diff --git a/packages/backend/contracts/coinbase/Coinbase.sol b/packages/backend/contracts/coinbase/Coinbase.sol index 52d44a4..428fcff 100644 --- a/packages/backend/contracts/coinbase/Coinbase.sol +++ b/packages/backend/contracts/coinbase/Coinbase.sol @@ -3,30 +3,23 @@ pragma solidity 0.8.24; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "../modules/sht-module/SHTModule.sol"; import "../project-funding/ProjectFunding.sol"; -/** - * @title Coinbase - * @dev This contract is used to start the ICO for housing projects. - */ +/// @title Coinbase +/// @dev This contract is used to start the ICO for housing projects. contract Coinbase is Ownable, SHTModule { - using SafeMath for uint256; - constructor() ERC20("SmartHousingToken", "SHT") { _mint(address(this), SHT.MAX_SUPPLY); } - /** - * @dev Starts the ICO by initializing the first housing project. - * @param projectFundingAddr Address of the ProjectFunding contract. - * @param smartHousingAddress Address of the SmartHousing contract. - * @param fundingToken Address of the funding token (ERC20). - * @param fundingGoal The funding goal for the new project. - * @param fundingDeadline The deadline for the project funding. - */ + /// @dev Starts the ICO by initializing the first housing project. + /// @param projectFundingAddr Address of the ProjectFunding contract. + /// @param smartHousingAddress Address of the SmartHousing contract. + /// @param fundingToken Address of the funding token (ERC20). + /// @param fundingGoal The funding goal for the new project. + /// @param fundingDeadline The deadline for the project funding. function startICO( string memory name, string memory symbol, @@ -35,38 +28,34 @@ contract Coinbase is Ownable, SHTModule { address fundingToken, uint256 fundingGoal, uint256 fundingDeadline - ) external onlyOwner { + ) external onlyOwner returns (address) { ERC20TokenPayment memory icoPayment = _makeSHTPayment(SHT.ICO_FUNDS); + // Directly approve the ProjectFunding contract to spend the ICO funds _approve(address(this), projectFundingAddr, icoPayment.amount); - ProjectFunding(projectFundingAddr).initFirstProject( - icoPayment, - name, - symbol, - smartHousingAddress, - fundingToken, - fundingGoal, - fundingDeadline - ); + return + ProjectFunding(projectFundingAddr).initFirstProject( + icoPayment, + name, + symbol, + smartHousingAddress, + fundingToken, + fundingGoal, + fundingDeadline + ); } - /** - * @dev Dispatches ecosystem funds if not already dispatched to SmartHousing contract. - * @param smartHousingAddr The address of the SmartHousing contract. - */ + /// @dev Dispatches ecosystem funds if not already dispatched to SmartHousing contract. + /// @param smartHousingAddr The address of the SmartHousing contract. function feedSmartHousing(address smartHousingAddr) external onlyOwner { - ERC20TokenPayment memory feedPayment = _makeSHTPayment( - SHT.ECOSYSTEM_DISTRIBUTION_FUNDS - ); + uint256 feedAmount = SHT.ECOSYSTEM_DISTRIBUTION_FUNDS; + require(balanceOf(address(this)) >= feedAmount, "Already dispatched"); - // Ensure data integrity - require( - balanceOf(address(this)) >= feedPayment.amount, - "Already dispatched" - ); + ERC20TokenPayment memory feedPayment = _makeSHTPayment(feedAmount); - _approve(address(this), smartHousingAddr, feedPayment.amount); + // Directly approve the SmartHousing contract to spend the ecosystem funds + _approve(address(this), smartHousingAddr, feedAmount); ISmartHousing(smartHousingAddr).setUpSHT(feedPayment); } diff --git a/packages/backend/contracts/housing-project/CallsSmartHousing.sol b/packages/backend/contracts/housing-project/CallsSmartHousing.sol index 218f15b..73f1807 100644 --- a/packages/backend/contracts/housing-project/CallsSmartHousing.sol +++ b/packages/backend/contracts/housing-project/CallsSmartHousing.sol @@ -1,11 +1,11 @@ -// SPDX-License-Identifier: SEE LICENSE IN LICENSE +// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import "../main/Interface.sol"; abstract contract CallsSmartHousing { /// @notice The address of the main SmartHousing contract. - address immutable smartHousingAddr; + address public immutable smartHousingAddr; constructor(address smartHousingAddr_) { smartHousingAddr = smartHousingAddr_; @@ -14,9 +14,9 @@ abstract contract CallsSmartHousing { /// @dev Gets the referrer address for a given original owner. /// @param userAddr The original owner of the token. /// @return The referrer address. - function getReferrer( + function _getReferrer( address userAddr - ) internal view returns (uint, address) { + ) internal view returns (uint256, address) { return IUserModule(smartHousingAddr).getReferrer(userAddr); } } diff --git a/packages/backend/contracts/housing-project/HousingProject.sol b/packages/backend/contracts/housing-project/HousingProject.sol index e6f9cc4..e829c1c 100644 --- a/packages/backend/contracts/housing-project/HousingProject.sol +++ b/packages/backend/contracts/housing-project/HousingProject.sol @@ -1,40 +1,141 @@ -// SPDX-License-Identifier: SEE LICENSE IN LICENSE +// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import "@openzeppelin/contracts/access/Ownable.sol"; import "./RentsModule.sol"; +import "./CallsSmartHousing.sol"; /// @title HousingProject Contract /// @notice Represents a unique real estate project within the SmartHousing ecosystem. -/// @dev This contract inherits from RentsModule and HousingSFT. -contract HousingProject is RentsModule, Ownable { +/// @dev This contract inherits from RentsModule and Ownable for management functions. +contract HousingProject is RentsModule, Ownable, CallsSmartHousing { + using RewardShares for rewardshares; + using TokenPayments for ERC20TokenPayment; + + // State Variables + uint256 public rewardsReserve; + uint256 public facilityManagementFunds; + + // Constants + uint256 public constant REWARD_PERCENT = 75; + uint256 public constant ECOSYSTEM_PERCENT = 18; + uint256 public constant FACILITY_PERCENT = 7; + + HousingSFT public immutable projectSFT; + ERC20Burnable public immutable housingToken; + /// @notice Initializes the HousingProject contract. /// @param smartHousingAddr The address of the main SmartHousing contract. + /// @param housingTokenAddr Coinbase contraact address + /// @param name The name of the HousingSFT token. + /// @param symbol The symbol of the HousingSFT token. constructor( string memory name, string memory symbol, - address smartHousingAddr + address smartHousingAddr, + address housingTokenAddr ) CallsSmartHousing(smartHousingAddr) { projectSFT = new HousingSFT(name, symbol); + + // Initialize the housing token + housingToken = ERC20Burnable(housingTokenAddr); } - event TokenIssued(address tokenAddress, string name, uint256 amountRaised); + /// @notice Receives rent payments, calculates, and distributes rewards. + /// @param rentPayment The details of the rent payment. + function receiveRent(ERC20TokenPayment calldata rentPayment) external { + uint256 rentAmount = rentPayment.amount; + require(rentAmount > 0, "RentsModule: Insufficient amount"); + require( + rentPayment.token == housingToken, + "RentsModule: Invalid token" + ); - function setTokenDetails( - uint256 amountRaised, - address housingTokenAddr - ) external onlyOwner { - require(address(housingToken) == address(0), "Token details set already"); + rentPayment.receiveERC20(); - housingToken = ERC20Burnable(housingTokenAddr); + uint256 rentReward = (rentAmount * REWARD_PERCENT) / 100; + uint256 ecosystemReward = (rentAmount * ECOSYSTEM_PERCENT) / 100; + uint256 facilityReward = (rentAmount * FACILITY_PERCENT) / 100; - projectSFT.setAmountRaised(amountRaised); - string memory name = projectSFT.name(); + // Update rewards and reserve + rewardPerShare += + (rentReward * DIVISION_SAFETY_CONST) / + projectSFT.getMaxSupply(); + rewardsReserve += rentReward; + facilityManagementFunds += facilityReward; - emit TokenIssued(address(projectSFT), name, amountRaised); + // Burn ecosystem reward and notify SmartHousing contract + housingToken.burn(ecosystemReward); + ISmartHousing(smartHousingAddr).addProjectRent(rentAmount); } - function getMaxSupply() public view returns (uint256) { + /// @notice Claims rent rewards for a given token and updates attributes. + /// @param nonce The nonce of the token to claim rewards for. + /// @return attr The updated HousingAttributes. + /// @return rewardShares The computed reward shares. + /// @return newNonce The new nonce after updating the token. + function claimRentReward( + uint256 nonce + ) + external + returns ( + HousingAttributes memory attr, + rewardshares memory rewardShares, + uint256 newNonce + ) + { + address caller = msg.sender; + uint256 currentRPS = rewardPerShare; + + attr = projectSFT.getUserSFT(caller, nonce); + rewardShares = _computeRewardShares(attr); + + uint256 totalReward = rewardShares.total(); + if (totalReward == 0) { + return (attr, rewardShares, nonce); + } + + require( + rewardsReserve >= totalReward, + "RentsModule: Insufficient rewards reserve" + ); + rewardsReserve -= totalReward; + + (, address referrer) = _getReferrer(attr.originalOwner); + if (rewardShares.referrerValue > 0) { + if (referrer != address(0)) { + housingToken.transfer(referrer, rewardShares.referrerValue); + } else { + housingToken.burn(rewardShares.referrerValue); + } + } + + attr.rewardsPerShare = currentRPS; + + newNonce = projectSFT.update( + caller, + nonce, + projectSFT.balanceOf(caller, nonce), + abi.encode(attr) + ); + + housingToken.transfer(caller, rewardShares.userValue); + + return (attr, rewardShares, newNonce); + } + + /// @notice Returns the maximum supply of the HousingSFT token. + /// @return The maximum supply of the HousingSFT token. + function getMaxSupply() external view returns (uint256) { return projectSFT.getMaxSupply(); } + + /// @notice Calculates the amount of rent claimable for a given token. + /// @param attr The attributes of the token. + /// @return The amount of rent claimable. + function rentClaimable( + HousingAttributes memory attr + ) public view returns (uint256) { + return _computeRewardShares(attr).userValue; + } } diff --git a/packages/backend/contracts/housing-project/HousingSFT.sol b/packages/backend/contracts/housing-project/HousingSFT.sol index ebf6940..c45b7f3 100644 --- a/packages/backend/contracts/housing-project/HousingSFT.sol +++ b/packages/backend/contracts/housing-project/HousingSFT.sol @@ -1,8 +1,9 @@ -// SPDX-License-Identifier: SEE LICENSE IN LICENSE +// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; import "../modules/SFT.sol"; @@ -17,6 +18,7 @@ struct HousingAttributes { /// @dev This contract will be inherited by the HousingProject contract. contract HousingSFT is SFT { using EnumerableSet for EnumerableSet.UintSet; + using Address for address; struct HousingSFTBalance { uint256 nonce; @@ -24,9 +26,7 @@ contract HousingSFT is SFT { HousingAttributes attributes; } - // FIXME this value should be unique to each contract, should depend on - // the total amount expected to raise as it determines the amount of SFTs to - // be minted for investors + /// @notice Maximum supply of tokens for this housing project. uint256 public constant MAX_SUPPLY = 1_000_000; /// @notice The amount of fungible tokens collected from investors to finance the development of this housing project. @@ -35,15 +35,20 @@ contract HousingSFT is SFT { /// @notice The current amount out of the `MAX_SUPPLY` of tokens minted. uint256 public totalSupply; + /// @param name_ Name of the SFT. + /// @param symbol_ Symbol of the SFT. constructor( string memory name_, string memory symbol_ ) SFT(name_, symbol_) {} - function setAmountRaised(uint256 amountRaised_) external onlyOwner { + /// @notice Sets the amount raised for the housing project. + /// @param amountRaised_ The amount raised during the token sale. + function setAmountRaised(uint256 amountRaised_) external canMint { amountRaised = amountRaised_; } + /// @dev Modifier to ensure only the SFT owner (i.e., the owner of the owner of this contract, which is the ProjectFunding Contract) can mint new tokens. modifier canMint() { address sftOwner = owner(); @@ -58,30 +63,23 @@ contract HousingSFT is SFT { /// @notice Mints SFT tokens for a depositor based on the amount of deposit. /// @param depositAmt The amount of fungible token deposited. /// @param depositor The address of the depositor. + /// @return The ID of the newly minted SFT. function mintSFT( uint256 depositAmt, - address depositor, - uint256 amount_raised + address depositor ) external canMint returns (uint256) { - // TODO remove after demo due to not beign able to move blocks in public networks - { - amountRaised = amount_raised; - } - - uint256 totalDeposits = amountRaised; uint256 maxShares = MAX_SUPPLY; + require(amountRaised > 0, "HousingSFT: No deposits recorded"); - require(totalDeposits > 0, "HousingSFT: No deposits recorded"); - - uint256 mintShare = (depositAmt * maxShares) / totalDeposits; - require(mintShare > 0, "HousingSFT: Computed token shares is invalid"); + uint256 mintShare = (depositAmt * maxShares) / amountRaised; + require(mintShare > 0, "HousingSFT: Computed token shares invalid"); totalSupply += mintShare; require(totalSupply <= MAX_SUPPLY, "HousingSFT: Max supply exceeded"); bytes memory attributes = abi.encode( HousingAttributes({ - rewardsPerShare: 0, // Should be 0 since they have never claimed any rent rewards + rewardsPerShare: 0, // Initial rewards per share originalOwner: depositor, tokenWeight: mintShare }) @@ -90,9 +88,10 @@ contract HousingSFT is SFT { return _mint(depositor, mintShare, attributes, ""); } - /// @notice Checks if an address owns this HousingSFT and returns the attributes. + /// @notice Retrieves the SFT attributes for a given owner and nonce. /// @param owner The address to check the balance of. - /// @return `HousingAttributes` if the owner has a positive balance of the token, panics otherwise. + /// @param nonce The specific nonce to check. + /// @return The attributes associated with the specified SFT. function getUserSFT( address owner, uint256 nonce @@ -105,10 +104,15 @@ contract HousingSFT is SFT { return abi.decode(getRawTokenAttributes(nonce), (HousingAttributes)); } + /// @notice Returns the maximum supply of the HousingSFT tokens. + /// @return The maximum supply of tokens. function getMaxSupply() public pure returns (uint256) { return MAX_SUPPLY; } + /// @notice Returns the SFT balance of a user including detailed attributes. + /// @param user The address of the user to check. + /// @return An array of `HousingSFTBalance` containing the user's balance details. function sftBalance( address user ) public view returns (HousingSFTBalance[] memory) { @@ -130,6 +134,8 @@ contract HousingSFT is SFT { return balance; } + /// @notice Retrieves the token details including name, symbol, and max supply. + /// @return A tuple containing the token's name, symbol, and max supply. function tokenDetails() public view diff --git a/packages/backend/contracts/housing-project/NewHousingProjectLib.sol b/packages/backend/contracts/housing-project/NewHousingProjectLib.sol index d380c83..9567db1 100644 --- a/packages/backend/contracts/housing-project/NewHousingProjectLib.sol +++ b/packages/backend/contracts/housing-project/NewHousingProjectLib.sol @@ -1,14 +1,24 @@ -// SPDX-License-Identifier: SEE LICENSE IN LICENSE +// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import { HousingProject } from "./HousingProject.sol"; +/// @title NewHousingProject Library +/// @notice This library provides a function to deploy new HousingProject contracts. +/// @dev This is a lightweight library intended for contract creation and can be expanded with additional functionality. library NewHousingProject { - function create( + /// @notice Deploys a new instance of the HousingProject contract. + /// @param name The name of the HousingProject token. + /// @param symbol The symbol of the HousingProject token. + /// @param coinbase Coinbase contraact address + /// @param smartHousingAddr The address of the SmartHousing contract that will own the new HousingProject. + /// @return The address of the newly created HousingProject contract. + function deployHousingProject( string memory name, string memory symbol, - address smartHousingAddr + address smartHousingAddr, + address coinbase ) external returns (HousingProject) { - return new HousingProject(name, symbol, smartHousingAddr); + return new HousingProject(name, symbol, smartHousingAddr, coinbase); } } diff --git a/packages/backend/contracts/housing-project/RentsModule.sol b/packages/backend/contracts/housing-project/RentsModule.sol index 32b3d62..7f45c23 100644 --- a/packages/backend/contracts/housing-project/RentsModule.sol +++ b/packages/backend/contracts/housing-project/RentsModule.sol @@ -3,118 +3,21 @@ pragma solidity 0.8.24; import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; - import "./HousingSFT.sol"; import "./RewardSharing.sol"; import "../lib/TokenPayments.sol"; -import "./CallsSmartHousing.sol"; /// @title Rents Module -/// @notice Handles rent payments, reward calculations, and distribution for Housing projects. +/// @notice Manages rent payments, reward calculations, and distribution for housing projects. /// @dev This abstract contract should be inherited by the HousingProject contract. -abstract contract RentsModule is CallsSmartHousing { - using TokenPayments for ERC20TokenPayment; - using RewardShares for rewardshares; - +abstract contract RentsModule { + // State Variables uint256 public rewardPerShare; - uint256 public rewardsReserve; - uint256 public facilityManagementFunds; - - ERC20Burnable public housingToken; - HousingSFT public projectSFT; - - uint256 private constant REWARD_PERCENT = 75; - uint256 private constant ECOSYSTEM_PERCENT = 18; - uint256 private constant FACILITY_PERCENT = 7; - - /// @notice Receives rent payments and distributes rewards. - /// @param rentPayment The details of the rent payment. - function receiveRent(ERC20TokenPayment calldata rentPayment) external { - uint256 rentAmount = rentPayment.amount; - require(rentAmount > 0, "RentsModule: Insufficient rent amount"); - require( - rentPayment.token == housingToken, - "RentsModule: Invalid rent payment token" - ); - - rentPayment.receiveERC20(); - - uint256 rentReward = (rentAmount * REWARD_PERCENT) / 100; - uint256 ecosystemReward = (rentAmount * ECOSYSTEM_PERCENT) / 100; - uint256 facilityReward = (rentAmount * FACILITY_PERCENT) / 100; - - rewardPerShare += - (rentReward * DIVISION_SAFETY_CONST) / - projectSFT.getMaxSupply(); - rewardsReserve += rentReward; - facilityManagementFunds += facilityReward; - - housingToken.burn(ecosystemReward); - ISmartHousing(smartHousingAddr).addProjectRent(rentAmount); - } - - /// @notice Claims rent rewards for a given token. - /// @return attr The updated HousingAttributes. - function claimRentReward( - uint256 nonce - ) - external - returns ( - HousingAttributes memory attr, - rewardshares memory rewardShares, - uint256 newNonce - ) - { - address caller = msg.sender; - uint256 currentRPS = rewardPerShare; - - attr = projectSFT.getUserSFT(caller, nonce); - rewardShares = computeRewardShares(attr); - - uint256 totalReward = rewardShares.total(); - if (totalReward == 0) { - return (attr, rewardShares, nonce); - } - - require(rewardsReserve >= totalReward, "Computed rewards too large"); - rewardsReserve -= totalReward; - (, address referrer) = getReferrer(attr.originalOwner); - if (rewardShares.referrerValue > 0) { - if (referrer != address(0)) { - housingToken.transfer(referrer, rewardShares.referrerValue); - } else { - housingToken.burn(rewardShares.referrerValue); - } - } - - attr.rewardsPerShare = currentRPS; - - newNonce = projectSFT.update( - caller, - nonce, - projectSFT.balanceOf(caller, nonce), - abi.encode(attr) - ); - - housingToken.transfer(caller, rewardShares.userValue); - - return (attr, rewardShares, newNonce); - } - - /// @notice Computes the amount of rent claimable for a given token. - /// @param attr The attributes of the token. - /// @return The amount of rent claimable. - function rentClaimable( - HousingAttributes memory attr - ) public view returns (uint256) { - return computeRewardShares(attr).userValue; - } - - /// @dev Computes the reward shares for a given token. + /// @dev Computes the reward shares for a given token based on its attributes. /// @param attr The attributes of the token. - /// @return The computed RewardShares. - function computeRewardShares( + /// @return rewardShares The computed RewardShares. + function _computeRewardShares( HousingAttributes memory attr ) internal view returns (rewardshares memory) { uint256 currentRPS = rewardPerShare; @@ -122,7 +25,36 @@ abstract contract RentsModule is CallsSmartHousing { return rewardshares({ userValue: 0, referrerValue: 0 }); } - uint256 reward = computeReward(attr, currentRPS); - return splitReward(reward); + uint256 reward = _computeReward(attr, currentRPS); + return _splitReward(reward); + } + + /// @dev Calculates the reward for a given token based on its attributes and current reward per share. + /// @param attr The attributes of the token. + /// @param currentRPS The current reward per share. + /// @return The computed reward. + function _computeReward( + HousingAttributes memory attr, + uint256 currentRPS + ) internal pure returns (uint256) { + return + ((currentRPS - attr.rewardsPerShare) * attr.tokenWeight) / + DIVISION_SAFETY_CONST; + } + + /// @dev Splits the computed reward into user and referrer shares. + /// @param reward The total computed reward. + /// @return rewardShares The split reward shares. + function _splitReward( + uint256 reward + ) internal pure returns (rewardshares memory) { + uint256 referrerShare = (reward * 30) / 100_00; + uint256 userShare = reward - referrerShare; + + return + rewardshares({ + userValue: userShare, + referrerValue: referrerShare + }); } } diff --git a/packages/backend/contracts/housing-project/RewardSharing.sol b/packages/backend/contracts/housing-project/RewardSharing.sol index ee8d5db..0420dd3 100644 --- a/packages/backend/contracts/housing-project/RewardSharing.sol +++ b/packages/backend/contracts/housing-project/RewardSharing.sol @@ -1,32 +1,48 @@ -// SPDX-License-Identifier: SEE LICENSE IN LICENSE +// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import "./HousingSFT.sol"; +// Constants uint256 constant DIVISION_SAFETY_CONST = 1_000_000_000_000_000_000; +// Structs struct rewardshares { uint256 userValue; uint256 referrerValue; } +// Library for managing reward shares library RewardShares { + /// @notice Calculates the total reward value (user + referrer). + /// @param self The rewardshares struct containing user and referrer values. + /// @return The total reward value. function total(rewardshares memory self) internal pure returns (uint256) { return self.userValue + self.referrerValue; } } +// Utility functions + +/// @notice Splits a reward amount into user and referrer shares. +/// @param reward The total reward amount to be split. +/// @return The rewardshares struct with user and referrer values. function splitReward(uint256 reward) pure returns (rewardshares memory) { - uint256 referrerValue = (reward * 6_66) / 100_00; // would amount to approximately 5% of grand total + uint256 referrerValue = (reward * 666) / 10000; // Approximately 6.66% of the total reward uint256 userValue = reward - referrerValue; return rewardshares(userValue, referrerValue); } +/// @notice Computes the reward for a given token based on its attributes and the current reward per share. +/// @param attr The attributes of the token. +/// @param contractRPS The current reward per share. +/// @return The computed reward amount. function computeReward( HousingAttributes memory attr, uint256 contractRPS ) pure returns (uint256) { + // Return 0 if the current reward per share is less than or equal to the token's recorded reward per share if (contractRPS <= attr.rewardsPerShare) { return 0; } diff --git a/packages/backend/contracts/lib/EpochsAndPeriods.sol b/packages/backend/contracts/lib/EpochsAndPeriods.sol index 0c6964b..ad6ecaa 100644 --- a/packages/backend/contracts/lib/EpochsAndPeriods.sol +++ b/packages/backend/contracts/lib/EpochsAndPeriods.sol @@ -2,23 +2,28 @@ pragma solidity 0.8.24; /// @title Epochs and Periods Management Library -/// @notice This library provides functions to manage and calculate epochs and periods based on a genesis timestamp and an epoch length. +/// @notice Provides functions to manage and calculate epochs and periods based on a genesis timestamp and epoch length. /// @dev The epoch length is specified in seconds, and the period is calculated as 30 epochs. library EpochsAndPeriods { + // Struct to store epoch management parameters struct Storage { - uint256 genesis; - uint256 epochLength; + uint256 genesis; // The genesis timestamp + uint256 epochLength; // Length of each epoch in seconds } + // Initialization Functions + /// @notice Initializes the storage with the current timestamp as the genesis and sets the epoch length. /// @param self The storage struct to initialize. - /// @param _epochLength The length of an epoch in seconds. This determines how long each epoch lasts. + /// @param _epochLength The length of an epoch in seconds. /// @dev This function should be called in the contract constructor to set the initial genesis timestamp and epoch length. function initialize(Storage storage self, uint256 _epochLength) internal { self.genesis = block.timestamp; self.epochLength = _epochLength; } + // View Functions + /// @notice Returns the current epoch based on the genesis timestamp and epoch length. /// @param self The storage struct containing the genesis timestamp and epoch length. /// @return The current epoch number. diff --git a/packages/backend/contracts/lib/LkSHTAttributes.sol b/packages/backend/contracts/lib/LkSHTAttributes.sol index 162973b..69c9586 100644 --- a/packages/backend/contracts/lib/LkSHTAttributes.sol +++ b/packages/backend/contracts/lib/LkSHTAttributes.sol @@ -2,31 +2,34 @@ pragma solidity 0.8.24; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -/** - * @title LkSHTAttributes - * @dev Library for handling attributes and unlocking of the Locked SmartHousing Token. - */ + + /// @title LkSHTAttributes + /// @dev Library for handling attributes and unlocking of the Locked SmartHousing Token (LkSHT). + library LkSHTAttributes { using SafeMath for uint256; - // TODO use this for mainnet uint256 constant LOCK_DURATION = 3 * 365 days; // 3 years - uint256 constant LOCK_DURATION = 5 hours; + // Constants + // Duration for which tokens are locked (e.g., 3 years in production, 3 weeks for testing) + uint256 constant LOCK_DURATION = 3 weeks; + // Struct to represent attributes of Locked SmartHousing Tokens struct Attributes { - uint256 initialAmount; - uint256 amount; - uint256 startTimestamp; - uint256 endTimestamp; + uint256 initialAmount; // Initial amount of tokens locked + uint256 amount; // Remaining amount of tokens locked + uint256 startTimestamp; // Timestamp when the lock started + uint256 endTimestamp; // Timestamp when the lock ends } - /** - * @dev Creates new attributes for a Locked SmartHousing Token. - * @param startTimestamp The start time of the lock. - * @param amount The amount of SmartHousing Tokens locked. - * @return attributes The initialized attributes. - */ + // Initialization Functions + + + /// @dev Creates new attributes for a Locked SmartHousing Token. + /// @param startTimestamp The start time of the lock. + /// @param amount The amount of SmartHousing Tokens locked. + /// @return attributes The initialized attributes. + function newAttributes( uint256 startTimestamp, uint256 amount @@ -40,11 +43,14 @@ library LkSHTAttributes { }); } - /** - * @dev Calculates and deducts the unlocked amount based on the elapsed time. - * @param self The attributes to update. - * @return unlockedAmount The amount of tokens unlocked. - */ + // View Functions + + + /// @dev Calculates and deducts the unlocked amount based on the elapsed time. + /// @param self The attributes to update. + /// @return unlockedAmount The amount of tokens unlocked. + /// @return newSelf The updated attributes with the deducted amount. + function unlockMatured( Attributes memory self ) @@ -59,11 +65,11 @@ library LkSHTAttributes { newSelf = self; } - /** - * @dev Calculates the elapsed time since the lock started. - * @param self The attributes to use. - * @return elapsedTime The elapsed time in seconds. - */ + + /// @dev Calculates the elapsed time since the lock started. + /// @param self The attributes to use. + /// @return elapsedTime The elapsed time in seconds. + function elapsedTime( Attributes memory self ) internal view returns (uint256) { diff --git a/packages/backend/contracts/lib/ProjectStorage.sol b/packages/backend/contracts/lib/ProjectStorage.sol index 08c0e8d..a544bf6 100644 --- a/packages/backend/contracts/lib/ProjectStorage.sol +++ b/packages/backend/contracts/lib/ProjectStorage.sol @@ -5,29 +5,40 @@ import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./TokenPayments.sol"; +import { HousingSFT } from "../housing-project/HousingSFT.sol"; +/// @title ProjectStorage +/// @dev Library for managing project data, funding, and deposit retrieval. library ProjectStorage { using SafeMath for uint256; using TokenPayments for TokenPayment; using ProjectStorage for Data; + // Enum representing the status of a project enum Status { - FundingPeriod, - Successful, - Failed + FundingPeriod, // Project is currently in the funding period + Successful, // Project has met its funding goal + Failed // Project has failed to meet its funding goal } + // Struct to hold project data struct Data { uint256 id; // Unique identifier for the project - address tokenAddress; + address tokenAddress; // Address of the token associated with the project address projectAddress; // Address of the deployed HousingProject contract uint256 fundingGoal; // Target funding amount for the project uint256 fundingDeadline; // Deadline timestamp for the project funding address fundingToken; // Address of the ERC20 token used for funding uint256 collectedFunds; // Amount of funds collected for the project + uint256 minDeposit; // Least amount of funding to receive } - function status(Data storage self) internal view returns (Status) { + // View Functions + + /// @dev Returns the current status of the project based on collected funds and deadline. + /// @param self The memory struct containing project data. + /// @return The status of the project. + function status(Data memory self) internal view returns (Status) { if (self.collectedFunds >= self.fundingGoal) { return Status.Successful; } else if (block.timestamp < self.fundingDeadline) { @@ -37,6 +48,18 @@ library ProjectStorage { } } + // Initialization Functions + + /// @dev Creates and initializes a new project. + /// @param projects The mapping of project IDs to project data. + /// @param projectsId The mapping of project addresses to project IDs. + /// @param projectCount The current number of projects. + /// @param fundingGoal The target funding amount. + /// @param fundingDeadline The deadline for funding. + /// @param fundingToken The address of the ERC20 token used for funding. + /// @param projectAddress The address of the HousingProject contract. + /// @param tokenAddress The address of the token associated with the project. + /// @return newProjectData The newly created project data. function createNew( mapping(uint256 => Data) storage projects, mapping(address => uint256) storage projectsId, @@ -55,6 +78,8 @@ library ProjectStorage { uint256 newId = projectCount.add(1); + uint256 tokenMaxSupply = HousingSFT(tokenAddress).getMaxSupply(); + Data memory newProjectData = Data({ id: newId, projectAddress: projectAddress, @@ -62,7 +87,8 @@ library ProjectStorage { fundingDeadline: fundingDeadline, fundingToken: fundingToken, collectedFunds: 0, - tokenAddress: tokenAddress + tokenAddress: tokenAddress, + minDeposit: fundingGoal / tokenMaxSupply }); projects[newId] = newProjectData; @@ -71,17 +97,29 @@ library ProjectStorage { return newProjectData; } + // Funding Functions + + /// @dev Funds a project with tokens. + /// @param projects The mapping of project IDs to project data. + /// @param usersDeposit The mapping of depositor addresses to their deposit amounts. + /// @param projectId The ID of the project to fund. + /// @param depositor The address of the person funding the project. + /// @param payment The details of the token payment. function fund( mapping(uint256 => Data) storage projects, mapping(address => uint256) storage usersDeposit, uint256 projectId, address depositor, TokenPayment calldata payment - ) internal { - require(payment.amount > 0, "Invalid funding amount"); - + ) internal returns (uint256) { Data storage project = projects[projectId]; + require( + payment.amount >= project.minDeposit && + payment.amount <= project.fundingGoal, + "Invalid funding amount" + ); + require( project.status() == Status.FundingPeriod, "Cannot fund project after deadline" @@ -90,37 +128,42 @@ library ProjectStorage { address(payment.token) == project.fundingToken, "Wrong token payment" ); + payment.receiveToken(); project.collectedFunds = project.collectedFunds.add(payment.amount); usersDeposit[depositor] = usersDeposit[depositor].add(payment.amount); + + return project.collectedFunds; } - /** - * @dev Retrieves and updates the user's deposit for a specific project. - * @param projectId The ID of the project to retrieve the deposit for. - * @param depositor The address of the depositor. - * @return (ProjectStorage.Data, uint256) The project data and deposit amount. - */ + // Deposit Functions + + /// @dev Retrieves and updates the user's deposit for a specific project. + /// @param projects The mapping of project IDs to project data. + /// @param usersDeposit The mapping of depositor addresses to their deposit amounts. + /// @param projectId The ID of the project to retrieve the deposit for. + /// @param depositor The address of the depositor. + /// @return project The project data. + /// @return depositAmount The amount of deposit for the user. + function takeDeposit( mapping(uint256 => Data) storage projects, mapping(address => uint256) storage usersDeposit, uint256 projectId, address depositor - ) internal returns (ProjectStorage.Data memory, uint256) { - ProjectStorage.Data storage project = projects[projectId]; + ) internal returns (Data memory project, uint256 depositAmount) { + project = projects[projectId]; require(project.id != 0, "Invalid project ID"); require( project.status() == Status.Successful, "Project not yet successful" ); - uint256 depositAmount = usersDeposit[depositor]; + depositAmount = usersDeposit[depositor]; require(depositAmount > 0, "No deposit found"); // Update the deposit amount to zero usersDeposit[depositor] = 0; - - return (project, depositAmount); } } diff --git a/packages/backend/contracts/lib/TokenPayments.sol b/packages/backend/contracts/lib/TokenPayments.sol index a19f724..b217409 100644 --- a/packages/backend/contracts/lib/TokenPayments.sol +++ b/packages/backend/contracts/lib/TokenPayments.sol @@ -48,7 +48,7 @@ library TokenPayments { from == msg.sender, "can receive native payment only from caller" ); - + // Nothing to do again since the VM will handle balance movements } else if (payment.nonce == 0) { IERC20(payment.token).transferFrom( diff --git a/packages/backend/contracts/main/HST.sol b/packages/backend/contracts/main/HST.sol index b8c369a..1d80cb7 100644 --- a/packages/backend/contracts/main/HST.sol +++ b/packages/backend/contracts/main/HST.sol @@ -5,7 +5,6 @@ import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; -import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import { TokenPayment } from "../lib/TokenPayments.sol"; import { SFT } from "../modules/SFT.sol"; @@ -46,6 +45,15 @@ contract HousingStakingToken is SFT { constructor() SFT("Housing Staking Token", "HST") {} + /// @notice Mints a new Housing Staking Token (HST) with specified attributes. + /// @param projectTokens Array of project tokens associated with the HST. + /// @param projectsShareCheckpoint The checkpoint for project share calculations. + /// @param shtRewardPerShare The reward per share of SHT. + /// @param lkDuration Duration of the lock in epochs. + /// @param shtAmount Amount of SHT to be associated with the token. + /// @param lkShtNonces Array of nonces associated with locked SHT. + /// @param caller Address of the caller requesting the minting. + /// @return attr The attributes associated with the minted token. function mint( TokenPayment[] calldata projectTokens, uint256 projectsShareCheckpoint, @@ -62,10 +70,11 @@ contract HousingStakingToken is SFT { ); require(shtAmount > 0 || lkShtNonces.length > 0, "Must send SHT"); + uint256 projectTokenCount = projectTokens.length; require( projectTokenCount > 0 && projectTokenCount <= 10, - "Must send project tokens of approved number" + "Must send approved number of project tokens" ); uint256 stakeWeight = shtAmount.mul(lkDuration); @@ -85,6 +94,9 @@ contract HousingStakingToken is SFT { emit MintHstToken(caller, nonce, attr); } + /// @notice Retrieves the balance of HST tokens for a specified user. + /// @param user Address of the user whose balance is to be retrieved. + /// @return balance Array of HSTBalance representing the user's HST holdings. function sftBalance( address user ) public view returns (HSTBalance[] memory) { diff --git a/packages/backend/contracts/main/Interface.sol b/packages/backend/contracts/main/Interface.sol index ed8427b..12755be 100644 --- a/packages/backend/contracts/main/Interface.sol +++ b/packages/backend/contracts/main/Interface.sol @@ -3,19 +3,36 @@ pragma solidity 0.8.24; import "../lib/TokenPayments.sol"; +/// @title SmartHousing Interface +/// @notice Interface for interacting with the SmartHousing contract. interface ISmartHousing { + /// @notice Adds rent payment to the project. + /// @param amount The amount of rent to add. function addProjectRent(uint256 amount) external; + /// @notice Creates a referral ID via a proxy. + /// @param userAddr The address of the user. + /// @param referrerId The ID of the referrer. + /// @return The newly created referral ID. function createRefIDViaProxy( address userAddr, uint256 referrerId ) external returns (uint256); + /// @notice Adds a new project to the SmartHousing system. + /// @param projectAddress The address of the new project. function addProject(address projectAddress) external; + /// @notice Sets up the SmartHousingToken (SHT) using the provided payment details. + /// @param payment The payment details for setting up SHT. function setUpSHT(ERC20TokenPayment calldata payment) external; } +/// @title User Module Interface +/// @notice Interface for interacting with the user module to retrieve referrer information. interface IUserModule { - function getReferrer(address user) external view returns (uint, address); + /// @notice Retrieves the referrer information for a given user. + /// @param user The address of the user. + /// @return A tuple containing the referrer ID and the referrer address. + function getReferrer(address user) external view returns (uint256, address); } diff --git a/packages/backend/contracts/main/SmartHousing.sol b/packages/backend/contracts/main/SmartHousing.sol index 219dceb..8e5fffd 100644 --- a/packages/backend/contracts/main/SmartHousing.sol +++ b/packages/backend/contracts/main/SmartHousing.sol @@ -6,31 +6,21 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; - import "../lib/TokenPayments.sol"; import "../modules/sht-module/SHT.sol"; import "../project-funding/ProjectFunding.sol"; - import "./Interface.sol"; import "./User.sol"; - import { Distribution } from "./distribution/Storage.sol"; import { EpochsAndPeriods } from "../lib/EpochsAndPeriods.sol"; import { HousingStakingToken, NewHousingStakingToken, MIN_EPOCHS_LOCK, MAX_EPOCHS_LOCK, HstAttributes } from "./HST.sol"; - import { HousingProject } from "../housing-project/HousingProject.sol"; import { rewardshares } from "../housing-project/RewardSharing.sol"; import { LkSHT } from "../modules/LockedSmartHousingToken.sol"; -import { ProjectFunding } from "../project-funding/ProjectFunding.sol"; /// @title SmartHousing -/// @notice SmartHousing leverages blockchain technology to revolutionize real estate investment and development by enabling the tokenization of properties. -/// @dev This contract allows for fractional ownership and ease of investment. -/// This innovative approach addresses the high costs and limited access to real estate investments in Abuja, Nigeria, making the market more inclusive and accessible. -/// By selling tokens, SmartHousing provides developers with immediate access to liquid funds, ensuring the timely and quality completion of affordable development projects. -/// The SmartHousing Contract is the main contract for the SmartHousing ecosystem. -/// This contract owns and deploys HousingProject contracts, which will represent the properties owned and managed by the SmartHousing project. -/// The management of ecosystem users will also be done in this contract. +/// @notice SmartHousing enables real estate tokenization for fractional ownership and investment. +/// @dev Main contract for the SmartHousing ecosystem. Manages HousingProjects, users, and staking. contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { using TokenPayments for ERC20TokenPayment; using Distribution for Distribution.Storage; @@ -39,38 +29,42 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { using TokenPayments for TokenPayment; using SafeMath for uint256; + // Contract addresses and instances address public projectFundingAddress; address public coinbaseAddress; address public shtTokenAddress; HousingStakingToken public hst; LkSHT public lkSht; + // Storage for distribution and epochs Distribution.Storage public distributionStorage; EpochsAndPeriods.Storage public epochsAndPeriodsStorage; + // Permission management enum Permissions { NONE, HOUSING_PROJECT } - mapping(address => Permissions) public permissions; - EnumerableSet.AddressSet private _projectsToken; // Enumerable list of project addresses + EnumerableSet.AddressSet private _projectsToken; // List of project SFT addresses + /// @notice Constructor to initialize SmartHousing. + /// @param coinbase Address of the coinbase. + /// @param projectFunding Address of the ProjectFunding contract. constructor(address coinbase, address projectFunding) { coinbaseAddress = coinbase; projectFundingAddress = projectFunding; hst = NewHousingStakingToken.create(); lkSht = ProjectFunding(projectFundingAddress).lkSht(); - // TODO set this from env vars - // TODO use this for mainnet epochsAndPeriodsStorage.initialize(24); // One epoch will span 24 seconds - epochsAndPeriodsStorage.initialize(1); // One epoch will span 1 second + // Initialize epochs and periods (24 hours for mainnet, 30 minutes for testing) + epochsAndPeriodsStorage.initialize(30 minutes); } - /// @notice Register a new user via proxy or get the referral ID if already registered. - /// @param userAddr The address of the user. - /// @param referrerId The ID of the referrer. - /// @return The ID of the registered user. + /// @notice Register a new user or get the referral ID if already registered. + /// @param userAddr Address of the user. + /// @param referrerId Referral ID of the referrer. + /// @return User ID. function createRefIDViaProxy( address userAddr, uint256 referrerId @@ -78,40 +72,31 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { return _createOrGetUserId(userAddr, referrerId); } + /// @notice Setup SHT token and distribute funds. + /// @param payment Token payment details for SHT setup. function setUpSHT(ERC20TokenPayment calldata payment) external { - require( - msg.sender == coinbaseAddress, - "Caller is not the coinbase address" - ); - - // Ensure that the SHT token has not been set already - require(shtTokenAddress == address(0), "SHT token already set"); + require(msg.sender == coinbaseAddress, "Unauthorized"); + require(shtTokenAddress == address(0), "SHT already set"); shtTokenAddress = address(payment.token); - - // Verify that the correct amount of SHT has been sent require( payment.amount == SHT.ECOSYSTEM_DISTRIBUTION_FUNDS, - "Must send all ecosystem funds" + "Incorrect SHT amount" ); payment.accept(); - // Set the total funds in distribution storage distributionStorage.setTotalFunds( epochsAndPeriodsStorage, payment.amount ); } - /// @notice Adds a new project and sets its permissions. - /// @param projectAddress The address of the new project. + /// @notice Add a new project and set its permissions. + /// @param projectAddress Address of the new project. function addProject(address projectAddress) external onlyProjectFunding { _setPermissions(projectAddress, Permissions.HOUSING_PROJECT); HousingProject project = HousingProject(projectAddress); - address projectSFTaddress = address( - HousingProject(projectAddress).projectSFT() - ); - - _projectsToken.add(projectSFTaddress); // Register the project's SFT address + address projectSFTaddress = address(project.projectSFT()); + _projectsToken.add(projectSFTaddress); distributionStorage.addProject( projectAddress, @@ -120,14 +105,17 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { ); } - /// @notice Adds rent to a project and updates the distribution storage. - /// @dev projectAddress is the msg.msg.sender which must be a recognised HousingProject contract - /// @param amount The amount of rent received. + /// @notice Add rent to a project and update distribution storage. + /// @param amount Amount of rent received. function addProjectRent(uint256 amount) external onlyHousingProject { address projectAddress = msg.sender; distributionStorage.addProjectRent(projectAddress, amount); } + /// @notice Stake tokens for rewards. + /// @param stakingTokens Array of token payments for staking. + /// @param epochsLock Lock period in epochs. + /// @param referrerId Referral ID of the referrer. function stake( TokenPayment[] calldata stakingTokens, uint256 epochsLock, @@ -137,13 +125,9 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { epochsLock >= MIN_EPOCHS_LOCK && epochsLock <= MAX_EPOCHS_LOCK, "Invalid epochs lock period" ); - address caller = msg.sender; - // Try create ID _createOrGetUserId(caller, referrerId); - - // Generate rewards before staking distributionStorage.generateRewards(epochsAndPeriodsStorage); HstAttributes memory newAttr = _mintHstToken( @@ -151,49 +135,45 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { distributionStorage.projectsStakingRewards.checkpoint, distributionStorage.shtRewardPerShare, epochsLock, - shtTokenAddress, - address(ProjectFunding(projectFundingAddress).lkSht()) + address(lkSht) ); distributionStorage.enterStaking(newAttr.stakeWeight); } + /// @notice Get the current epoch. + /// @return Current epoch number. function currentEpoch() public view returns (uint256) { return epochsAndPeriodsStorage.currentEpoch(); } - function currentPeriod() internal view returns (uint256) { - return epochsAndPeriodsStorage.currentPeriod(); - } - + /// @notice Check if a user can claim rewards. + /// @param user Address of the user. + /// @param tokenNonce Nonce of the token. + /// @return True if the user can claim rewards, otherwise false. function userCanClaim( address user, uint256 tokenNonce ) public view returns (bool) { bool hasSft = hst.hasSFT(user, tokenNonce); - if (!hasSft) { - // User can't claim reward of token they don't own - return false; - } + if (!hasSft) return false; - // hstAttr.shtRewardPerShare and distributionStorage.shtRewardPerShare could be equal - // becasue of recent rewards genrated, so we check if rewards can be generated, - // if yes, then user can potential claim rewards bool rewardsCanBeGenerated = distributionStorage .lastFundsDispatchEpoch < currentEpoch(); - if (rewardsCanBeGenerated) { - return true; - } + if (rewardsCanBeGenerated) return true; HstAttributes memory hstAttr = abi.decode( hst.getRawTokenAttributes(tokenNonce), (HstAttributes) ); - return hstAttr.shtRewardPerShare < distributionStorage.shtRewardPerShare; } + /// @notice Claim rewards and update token attributes. + /// @param hstNonce Nonce of the HST token. + /// @param referrerId Referral ID of the referrer. + /// @return newHstNonce New HST nonce. function claimRewards( uint256 hstNonce, uint256 referrerId @@ -202,11 +182,9 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { _createOrGetUserId(caller, referrerId); uint256 callerHstBal = hst.balanceOf(caller, hstNonce); - - require(callerHstBal > 0, "Caller does not own the hst token"); + require(callerHstBal > 0, "No HST token balance at nonce"); distributionStorage.generateRewards(epochsAndPeriodsStorage); - (uint256 claimedSHT, HstAttributes memory hstAttr) = distributionStorage .claimRewards( abi.decode(hst.getRawTokenAttributes(hstNonce), (HstAttributes)) @@ -245,12 +223,9 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { ); ERC20Burnable shtToken = ERC20Burnable(shtTokenAddress); - if (claimedSHT > 0) { uint256 referrerValue = claimedSHT.mul(25).div(1000); claimedSHT = claimedSHT.sub(referrerValue); - - // Do referrer operations (, address referrerAddr) = getReferrer(caller); if (referrerAddr != address(0)) { shtToken.transfer(referrerAddr, referrerValue); @@ -262,26 +237,32 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { shtToken.transfer(caller, claimedSHT.add(rentRewards)); } + /// @notice Get project distribution details. + /// @param project Address of the project. + /// @return Project distribution data. function projectDets( address project ) public view returns (Distribution.ProjectDistributionData memory) { return distributionStorage.projectDets[project]; } + /// @notice Get the list of project tokens. + /// @return Array of project token addresses. function projectsToken() public view returns (address[] memory) { return _projectsToken.values(); } - /// @notice Sets the permissions for a given address. - /// @param addr The address to set permissions for. - /// @param perm The permissions to set. + // Internal functions + + /// @notice Set permissions for an address. + /// @param addr Address to set permissions for. + /// @param perm Permissions to set. function _setPermissions(address addr, Permissions perm) internal { permissions[addr] = perm; } function _prepareProjectTokensAndLkShtNonces( TokenPayment[] calldata payments, - address shtAddress, address lkShtAddress ) internal @@ -297,7 +278,7 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { for (uint256 i = 0; i < payments.length; i++) { TokenPayment memory payment = payments[i]; - if (payment.token == shtAddress) { + if (payment.token == shtTokenAddress) { // Do nothing } else if (payment.token == lkShtAddress) { lkShtNoncesCount++; @@ -312,14 +293,19 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { lkShtNonces = new uint256[](lkShtNoncesCount); } + /// @notice Prepare project tokens and LkSHT for staking. + /// @param payments Array of tokens to prepare. + /// @param epochsLock Number of epochs to lock. + /// @param projectsShareCheckpoint Number of epochs to lock. + /// @param lkShtAddress Address of the LkSHT token. + /// @return Attributes of the new HST token. function _mintHstToken( TokenPayment[] calldata payments, uint256 projectsShareCheckpoint, uint256 shtRewardPerShare, - uint256 lkDuration, - address shtAddress, + uint256 epochsLock, address lkShtAddress - ) internal returns (HstAttributes memory attr) { + ) internal returns (HstAttributes memory) { address caller = msg.sender; uint256 projectTokenCount = 0; @@ -329,11 +315,7 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { ( TokenPayment[] memory projectTokens, uint256[] memory lkShtNonces - ) = _prepareProjectTokensAndLkShtNonces( - payments, - shtAddress, - lkShtAddress - ); + ) = _prepareProjectTokensAndLkShtNonces(payments, lkShtAddress); require( (projectTokens.length + lkShtNonces.length) < 10, "Max SFT tokens exceeded" @@ -342,7 +324,7 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { for (uint256 i = 0; i < payments.length; i++) { TokenPayment memory payment = payments[i]; - if (payment.token == shtAddress) { + if (payment.token == shtTokenAddress) { shtAmount = shtAmount.add(payment.amount); } else if (payment.token == lkShtAddress) { uint256 lkShtBal = lkSht.balanceOf(caller, payment.nonce); @@ -369,25 +351,26 @@ contract SmartHousing is ISmartHousing, Ownable, UserModule, ERC1155Holder { projectTokens, projectsShareCheckpoint, shtRewardPerShare, - lkDuration, + epochsLock, shtAmount, lkShtNonces, caller ); } + // Modifiers + + /// @notice Modifier to check if caller is authorized to interact with the contract. modifier onlyProjectFunding() { - require( - msg.sender == projectFundingAddress, - "Caller is not the project funder" - ); + require(msg.sender == projectFundingAddress, "Not authorized"); _; } + /// @notice Modifier to check if caller is a housing project. modifier onlyHousingProject() { require( permissions[msg.sender] == Permissions.HOUSING_PROJECT, - "Caller is not an accepted housing project" + "Not authorized" ); _; } diff --git a/packages/backend/contracts/main/User.sol b/packages/backend/contracts/main/User.sol index 1682b8f..e3b72fb 100644 --- a/packages/backend/contracts/main/User.sol +++ b/packages/backend/contracts/main/User.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: SEE LICENSE IN LICENSE +// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import "./Interface.sol"; @@ -47,12 +47,18 @@ abstract contract UserModule is IUserModule { referrerAddress = userIdToAddress[referrerId]; } + /// @notice Gets the user ID for a given address. + /// @param userAddress The address of the user. + /// @return userId The ID of the user. function getUserId( address userAddress ) external view returns (uint256 userId) { return users[userAddress].id; } + /// @notice Retrieves the referrals of a user. + /// @param userAddress The address of the user. + /// @return referrals An array of `ReferralInfo` structs representing the user's referrals. function getReferrals( address userAddress ) external view returns (ReferralInfo[] memory) { @@ -78,10 +84,14 @@ abstract contract UserModule is IUserModule { address userAddr, uint256 referrerId ) internal returns (uint256) { - if (users[userAddr].id != 0) { - return users[userAddr].id; + User storage user = users[userAddr]; + + // If user already exists, return the existing ID + if (user.id != 0) { + return user.id; } + // Increment user count and assign new user ID userCount++; users[userAddr] = User({ id: userCount, @@ -91,6 +101,7 @@ abstract contract UserModule is IUserModule { }); userIdToAddress[userCount] = userAddr; + // Add user to referrer's referrals list, if applicable if ( referrerId != 0 && referrerId != userCount && diff --git a/packages/backend/contracts/main/distribution/Storage.sol b/packages/backend/contracts/main/distribution/Storage.sol index 0060b01..bf07271 100644 --- a/packages/backend/contracts/main/distribution/Storage.sol +++ b/packages/backend/contracts/main/distribution/Storage.sol @@ -95,22 +95,20 @@ library Distribution { address projectAddress, uint256 amount ) internal { - // Update the total received rents across all projects - self.projectsTotalReceivedRents += amount; + self.projectsTotalReceivedRents = self.projectsTotalReceivedRents.add( + amount + ); - // Retrieve or initialize project-specific data ProjectDistributionData storage projectData = self.projectDets[ projectAddress ]; - // If `maxShares` is not set, initialize it with the maximum supply from the HousingProject contract if (projectData.maxShares == 0) { projectData.maxShares = HousingProject(projectAddress) .getMaxSupply(); } - // Add the received rent amount to the project's accumulated rents - projectData.receivedRents += amount; + projectData.receivedRents = projectData.receivedRents.add(amount); } function addProject( @@ -123,7 +121,7 @@ library Distribution { self.projectSftToProjectAddress[projectSFTaddress] = projectAddress; } - /// @notice Generates rewards for the current epoch. + /// @notice Generates rewards for the epochs that have elapsed. /// @param self The storage struct for the `Distribution` contract. function generateRewards( Storage storage self, @@ -142,12 +140,12 @@ library Distribution { toDispatch ); - // Take staking value + // Take stakers value uint256 stakingRewards = entitiesValue.staking; entitiesValue.staking = 0; self.entityFunds.add(entitiesValue); - uint256 shtStakersShare = stakingRewards.mul(7).div(10); // 70% goes to SHT stakers + uint256 shtStakersShare = stakingRewards.mul(7).div(10); // 70% to SHT stakers uint256 totalShtWeight = self.shtTotalStakeWeight; if (totalShtWeight > 0) { @@ -173,7 +171,6 @@ library Distribution { ) internal returns (uint256, HstAttributes memory) { uint256 shtClaimed = 0; - // Claim PT rewards uint256 ptRewardCheckpoint = self.projectsStakingRewards.checkpoint; if (ptRewardCheckpoint > 0) { for (uint256 i = 0; i < attr.projectTokens.length; i++) { @@ -196,7 +193,6 @@ library Distribution { .sub(shtClaimed); } - // Claim SHT rewards uint256 shtRPS = self.shtRewardPerShare; if (shtRPS > 0 && attr.shtRewardPerShare < shtRPS) { uint256 shtReward = shtRPS @@ -207,11 +203,9 @@ library Distribution { shtClaimed = self.shtStakingRewards; } self.shtStakingRewards = self.shtStakingRewards.sub(shtReward); - shtClaimed = shtClaimed.add(shtReward); } - // Update claim parameters attr.shtRewardPerShare = shtRPS; attr.projectsShareCheckpoint = ptRewardCheckpoint; @@ -232,7 +226,7 @@ library Distribution { ) internal view returns (uint256 reward) { if ( stakingCheckPoint >= tokenCheckPoint || - self.projectsTotalReceivedRents <= 0 + self.projectsTotalReceivedRents == 0 ) { return 0; } @@ -246,7 +240,7 @@ library Distribution { ); ProjectDistributionData storage projectData = self.projectDets[ - self.projectSftToProjectAddress[tokenPayment.token] + projectAddress ]; require( tokenPayment.amount <= projectData.maxShares, @@ -254,7 +248,6 @@ library Distribution { ); uint256 shareIncrease = tokenCheckPoint.sub(stakingCheckPoint); - // Project's allocation is dynamic, as rents received chages uint256 projectAllocation = shareIncrease .mul(projectData.receivedRents) .div(self.projectsTotalReceivedRents); diff --git a/packages/backend/contracts/modules/LockedSmartHousingToken.sol b/packages/backend/contracts/modules/LockedSmartHousingToken.sol index 67a903c..185a593 100644 --- a/packages/backend/contracts/modules/LockedSmartHousingToken.sol +++ b/packages/backend/contracts/modules/LockedSmartHousingToken.sol @@ -15,11 +15,9 @@ library NewLkSHT { } } -/** - * @title LockedSmartHousingToken - * @dev SFT token that locks SmartHousing Tokens (SHT) during ICO. - * Allows transfers only to whitelisted addresses. - */ +/// @title LockedSmartHousingToken +/// @dev SFT token that locks SmartHousing Tokens (SHT) during ICO. +/// Allows transfers only to whitelisted addresses. contract LkSHT is SFT { using SafeMath for uint256; using TokenPayments for ERC20TokenPayment; @@ -30,15 +28,21 @@ contract LkSHT is SFT { LkSHTAttributes.Attributes attributes; } + /// @dev Record the block timestamp when the contract is deployed uint256 immutable startTimestamp = block.timestamp; + /// @dev Constructor to initialize the token with name and symbol constructor( string memory name_, string memory symbol_ ) SFT(name_, symbol_) {} + /// @dev Event emitted when tokens are minted event TokensMinted(address indexed to, uint256 amount); + /// @dev Returns the balance of the user along with attributes + /// @param user The address of the user. + /// @return Array of LkSHTBalance containing nonce, amount, and attributes function sftBalance( address user ) public view returns (LkSHTBalance[] memory) { @@ -61,12 +65,12 @@ contract LkSHT is SFT { return balance; } - /** - * @dev Mints new Locked SmartHousing Tokens (LkSHT) by locking SHT. - * @param amount The amount of SHT to lock. - * @param to The address to mint the tokens to. - */ + /// @dev Mints new Locked SmartHousing Tokens (LkSHT) by locking SHT. + /// @param amount The amount of SHT to lock. + /// @param to The address to mint the tokens to. function mint(uint256 amount, address to) external onlyOwner { + require(amount > 0, "Amount must be greater than 0"); + bytes memory attributes = abi.encode( LkSHTAttributes.newAttributes(startTimestamp, amount) ); diff --git a/packages/backend/contracts/modules/SFT.sol b/packages/backend/contracts/modules/SFT.sol index 850b753..4b16a10 100644 --- a/packages/backend/contracts/modules/SFT.sol +++ b/packages/backend/contracts/modules/SFT.sol @@ -6,8 +6,8 @@ import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; -// TODO I think we should create a standard of this -abstract contract SFT is ERC1155, Ownable { +// TODO: Consider creating a standard for this +contract SFT is ERC1155, Ownable { using Counters for Counters.Counter; using EnumerableSet for EnumerableSet.UintSet; @@ -32,7 +32,7 @@ abstract contract SFT is ERC1155, Ownable { _symbol = symbol_; } - // Private function to mint new tokens + /// @dev Internal function to mint new tokens with attributes and store the nonce. function _mint( address to, uint256 amount, @@ -54,36 +54,51 @@ abstract contract SFT is ERC1155, Ownable { return nonce; } + /// @dev Returns the name of the token. function name() public view returns (string memory) { return _name; } + /// @dev Returns the symbol of the token. function symbol() public view returns (string memory) { return _symbol; } + /// @dev Returns the token name and symbol. function tokenInfo() public view returns (string memory, string memory) { return (_name, _symbol); } - // Function to get token attributes by nonce + /// @dev Returns raw token attributes by nonce. + /// @param nonce The nonce of the token. + /// @return Attributes in bytes. function getRawTokenAttributes( uint256 nonce ) public view returns (bytes memory) { return _tokenAttributes[nonce]; } - // Function to get list of nonces owned by an address + /// @dev Returns the list of nonces owned by an address. + /// @param owner The address of the token owner. + /// @return Array of nonces. function getNonces(address owner) public view returns (uint256[] memory) { return _addressToNonces[owner].values(); } + /// @dev Checks if the address owns a specific nonce. + /// @param owner The address of the token owner. + /// @param nonce The nonce to check. + /// @return True if the address owns the nonce, otherwise false. function hasSFT(address owner, uint256 nonce) public view returns (bool) { return _addressToNonces[owner].contains(nonce); } - /// Burns all the NFT balance of user at nonce, creates new with balance and attributes - /// Returns new nonce + /// @dev Burns the tokens of a specific nonce and mints new tokens with updated attributes. + /// @param user The address of the token holder. + /// @param nonce The nonce of the token to update. + /// @param amount The amount of tokens to mint. + /// @param attr The new attributes to assign. + /// @return The new nonce for the minted tokens. function update( address user, uint256 nonce, @@ -94,6 +109,9 @@ abstract contract SFT is ERC1155, Ownable { return _mint(user, amount, attr, ""); } + /// @dev Returns the balance of the user with their token attributes. + /// @param user The address of the user. + /// @return Array of SftBalance containing nonce, amount, and attributes. function _sftBalance( address user ) internal view returns (SftBalance[] memory) { @@ -115,7 +133,13 @@ abstract contract SFT is ERC1155, Ownable { return balance; } - // Override _beforeTokenTransfer to handle address-to-nonce mapping + /// @dev Override _beforeTokenTransfer to handle address-to-nonce mapping. + /// @param operator The address performing the transfer. + /// @param from The address sending tokens. + /// @param to The address receiving tokens. + /// @param ids The token IDs being transferred. + /// @param amounts The amounts of tokens being transferred. + /// @param data Additional data. function _beforeTokenTransfer( address operator, address from, diff --git a/packages/backend/contracts/modules/sht-module/Economics.sol b/packages/backend/contracts/modules/sht-module/Economics.sol index 0439c0e..ef153e1 100644 --- a/packages/backend/contracts/modules/sht-module/Economics.sol +++ b/packages/backend/contracts/modules/sht-module/Economics.sol @@ -32,30 +32,41 @@ library Emission { int256 private constant DECAY_RATE = 9998e14; // 0.9998 with 18 decimals int256 private constant E0 = 2729727036845720116116; // initial emission + /// @notice Computes emission at a specific epoch + /// @param epoch The epoch to compute emission for + /// @return Emission value at the given epoch function atEpoch(uint256 epoch) internal pure returns (uint256) { int256 decayFactor = PRBMathSD59x18.pow(DECAY_RATE, toInt256(epoch)); return toUint256((E0 * decayFactor) / 1e18); } - /// @notice Computes E0 * ​​(0.9998^epochStart − 0.9998^epochEnd​) + /// @notice Computes E0 * (0.9998^epochStart − 0.9998^epochEnd) / ln(0.9998) /// @param epochStart the starting epoch /// @param epochEnd the end epoch + /// @return Total emission through the epoch range function throughEpochRange( uint256 epochStart, uint256 epochEnd ) internal pure returns (uint256) { require(epochEnd > epochStart, "Invalid epoch range"); - int256 startFactor = PRBMathSD59x18.pow( - DECAY_RATE, - toInt256(epochStart) - ); - int256 endFactor = PRBMathSD59x18.pow(DECAY_RATE, toInt256(epochEnd)); + int256 startFactor = epochDecayFactor(epochStart); + int256 endFactor = epochDecayFactor(epochEnd); - int256 totalEmission = (E0 * (endFactor - startFactor)) / + int256 totalEmission = (E0 * (startFactor - endFactor)) / DECAY_RATE.ln(); - return toUint256(totalEmission); + // return the absolute value of totalEmission as uint256 + return toUint256(totalEmission * -1); + } + + function epochDecayFactor(uint256 epoch) private pure returns (int256) { + return + PRBMathSD59x18.pow( + DECAY_RATE, + // Extrapolate epoch to size with decimal places of DECAY_RATE + toInt256(epoch) * 1e18 + ); } } @@ -78,6 +89,9 @@ library Entities { uint256 lpAndListing; } + /// @notice Allocates total value based on predefined ratios. + /// @param totalValue The total value to be allocated. + /// @return Allocated values for each category. function fromTotalValue( uint256 totalValue ) internal pure returns (Value memory) { @@ -105,6 +119,9 @@ library Entities { }); } + /// @notice Computes the total value from individual allocations. + /// @param value The `Value` struct containing allocations. + /// @return The total value. function total(Value memory value) internal pure returns (uint256) { return value.team + @@ -115,6 +132,9 @@ library Entities { value.lpAndListing; } + /// @notice Adds another `Value` struct to the current one. + /// @param self The current `Value` struct. + /// @param rhs The `Value` struct to add. function add(Value storage self, Value memory rhs) internal { self.team += rhs.team; self.protocol += rhs.protocol; diff --git a/packages/backend/contracts/modules/sht-module/SHT.sol b/packages/backend/contracts/modules/sht-module/SHT.sol index 191ef36..aee902e 100644 --- a/packages/backend/contracts/modules/sht-module/SHT.sol +++ b/packages/backend/contracts/modules/sht-module/SHT.sol @@ -1,12 +1,23 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.24; +/// @title SHT Library +/// @notice Contains constants related to the Smart Housing Token (SHT) library SHT { + /// @dev Number of decimal places for the token uint256 public constant DECIMALS = 18; + + /// @dev 1 unit of token in its smallest unit, considering DECIMALS uint256 public constant ONE = 10 ** DECIMALS; + + /// @dev Maximum supply of the SHT token uint256 public constant MAX_SUPPLY = 21_000_000 * ONE; + + /// @dev Funds allocated for ecosystem distribution uint256 public constant ECOSYSTEM_DISTRIBUTION_FUNDS = (13_650_000 * ONE) + 2_248_573_618_499_339; + + /// @dev Funds allocated for ICO (Initial Coin Offering) uint256 public constant ICO_FUNDS = MAX_SUPPLY - ECOSYSTEM_DISTRIBUTION_FUNDS; } diff --git a/packages/backend/contracts/modules/sht-module/SHTModule.sol b/packages/backend/contracts/modules/sht-module/SHTModule.sol index 59f898f..723da27 100644 --- a/packages/backend/contracts/modules/sht-module/SHTModule.sol +++ b/packages/backend/contracts/modules/sht-module/SHTModule.sol @@ -7,21 +7,19 @@ import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import "../../lib/TokenPayments.sol"; import "./SHT.sol"; -/** - * @title SHTModule - * @dev This contract manages the Smart Housing Token (SHT) within the platform. - * It includes functionalities for making payments in SHT and querying the SHT token ID. - */ +/// @title SHTModule +/// @dev This contract manages the Smart Housing Token (SHT) within the platform. +/// It includes functionalities for making payments in SHT and querying the SHT token ID. + abstract contract SHTModule is ERC20, ERC20Burnable { function decimals() public pure override returns (uint8) { return uint8(SHT.DECIMALS); } - /** - * @dev Makes an ERC20TokenPayment struct in SHT for and amount. - * @param shtAmount Amount of SHT to be sent. - * @return payment ERC20TokenPayment struct representing the payment. - */ + /// @dev Makes an ERC20TokenPayment struct in SHT for and amount. + /// @param shtAmount Amount of SHT to be sent. + /// @return payment ERC20TokenPayment struct representing the payment. + function _makeSHTPayment( uint256 shtAmount ) internal view returns (ERC20TokenPayment memory) { diff --git a/packages/backend/contracts/project-funding/ProjectFunding.sol b/packages/backend/contracts/project-funding/ProjectFunding.sol index dbac5db..cc352fe 100644 --- a/packages/backend/contracts/project-funding/ProjectFunding.sol +++ b/packages/backend/contracts/project-funding/ProjectFunding.sol @@ -18,33 +18,25 @@ import { HousingSFT } from "../housing-project/HousingSFT.sol"; import { TokenPayment } from "../lib/TokenPayments.sol"; import { NewHousingProject, HousingProject } from "../housing-project/NewHousingProjectLib.sol"; -/** - * @title ProjectFunding - * @dev This contract is used for initializing and deploying housing projects. - * It allows the deployment of a new housing project and manages project data. - */ +/// @title ProjectFunding +/// @dev Manages and deploys housing projects, handles funding, and distributes tokens. contract ProjectFunding is Ownable { using SafeMath for uint256; using ProjectStorage for mapping(uint256 => ProjectStorage.Data); using ProjectStorage for ProjectStorage.Data; using LkSHTAttributes for LkSHTAttributes.Attributes; - address public coinbase; // Address authorized to initialize the first project, also the housingToken + // State variables + address public coinbase; // Address authorized to initialize the first project address public smartHousingAddress; // Address of the SmartHousing contract - mapping(uint256 => ProjectStorage.Data) public projects; // Mapping of project ID to ProjectData mapping(address => uint256) public projectsId; // Mapping of project address to project ID uint256 public projectCount; // Counter for the total number of projects - - mapping(uint256 => mapping(address => uint256)) public usersProjectDeposit; - + mapping(uint256 => mapping(address => uint256)) public usersProjectDeposit; // User deposits per project IERC20 public housingToken; // Token used for funding projects - LkSHT public lkSht; // The locked version + LkSHT public lkSht; // Instance of the locked SmartHousing Token (LkSHT) - /** - * @dev Emitted when a new project is deployed. - * @param projectAddress Address of the newly deployed HousingProject contract. - */ + // Events event ProjectDeployed(address indexed projectAddress); event ProjectFunded( uint256 indexed projectId, @@ -57,31 +49,30 @@ contract ProjectFunding is Ownable { uint256 amount ); - /** - * @param _coinbase Address authorized to initialize the first project. - */ + /// @param _coinbase Address authorized to initialize the first project constructor(address _coinbase) { coinbase = _coinbase; lkSht = NewLkSHT.create(); } - /** - * @dev Internal function to deploy a new HousingProject contract. - * @param fundingToken Address of the ERC20 token used for funding. - * @param fundingGoal The funding goal for the new project. - * @param fundingDeadline The deadline for the project funding. - */ + /// @dev Internal function to deploy a new HousingProject contract + /// @param name Name of the project + /// @param symbol Symbol of the project + /// @param fundingToken Address of the ERC20 token used for funding + /// @param fundingGoal The funding goal for the new project + /// @param fundingDeadline The deadline for the project funding function _deployProject( string memory name, string memory symbol, address fundingToken, uint256 fundingGoal, uint256 fundingDeadline - ) internal { - HousingProject newProject = NewHousingProject.create( + ) internal returns (address) { + HousingProject newProject = NewHousingProject.deployHousingProject( name, symbol, - smartHousingAddress + smartHousingAddress, + coinbase ); ProjectStorage.Data memory projectData = projects.createNew( projectsId, @@ -95,18 +86,19 @@ contract ProjectFunding is Ownable { projectCount = projectData.id; emit ProjectDeployed(projectData.projectAddress); + + return projectData.projectAddress; } - /** - * @dev Initializes the first project. - * This function must be called by the coinbase address and can only be called once. - * It sets up the token and deploys the first project. - * @param shtPayment Payment details for the Smart Housing Token (SHT). - * @param smartHousingAddress_ Address of the Smart Housing contract. - * @param fundingToken Address of the ERC20 token used for funding. - * @param fundingGoal The funding goal for the new project. - * @param fundingDeadline The deadline for the project funding. - */ + /// @dev Initializes the first project + /// This function must be called by the coinbase address and can only be called once + /// @param shtPayment Payment details for the Smart Housing Token (SHT) + /// @param name Name of the first project + /// @param symbol Symbol of the first project + /// @param smartHousingAddress_ Address of the Smart Housing contract + /// @param fundingToken Address of the ERC20 token used for funding + /// @param fundingGoal The funding goal for the new project + /// @param fundingDeadline The deadline for the project funding function initFirstProject( ERC20TokenPayment calldata shtPayment, string memory name, @@ -115,7 +107,7 @@ contract ProjectFunding is Ownable { address fundingToken, uint256 fundingGoal, uint256 fundingDeadline - ) external { + ) external returns (address) { require(msg.sender == coinbase, "Caller is not the coinbase"); require(projectCount == 0, "Project already initialized"); @@ -124,38 +116,44 @@ contract ProjectFunding is Ownable { smartHousingAddress = smartHousingAddress_; - _deployProject( - name, - symbol, - fundingToken, - fundingGoal, - fundingDeadline - ); + return + _deployProject( + name, + symbol, + fundingToken, + fundingGoal, + fundingDeadline + ); } - /** - * @dev Deploys a new project. - * This function can be called multiple times to deploy additional projects. - * @param fundingToken Address of the ERC20 token used for funding. - * @param fundingGoal The funding goal for the new project. - * @param fundingDeadline The deadline for the project funding. - */ + /// @dev Deploys a new project + /// This function can be called multiple times to deploy additional projects + /// @param name Name of the project + /// @param symbol Symbol of the project + /// @param fundingToken Address of the ERC20 token used for funding + /// @param fundingGoal The funding goal for the new project + /// @param fundingDeadline The deadline for the project funding function deployProject( string memory name, string memory symbol, address fundingToken, uint256 fundingGoal, uint256 fundingDeadline - ) public onlyOwner { - _deployProject( - name, - symbol, - fundingToken, - fundingGoal, - fundingDeadline - ); + ) public onlyOwner returns (address) { + return + _deployProject( + name, + symbol, + fundingToken, + fundingGoal, + fundingDeadline + ); } + /// @dev Allows users to fund a project + /// @param depositPayment Payment details for the funding + /// @param projectId ID of the project to fund + /// @param referrerId ID of the referrer (if applicable) function fundProject( TokenPayment calldata depositPayment, uint256 projectId, @@ -175,37 +173,32 @@ contract ProjectFunding is Ownable { ); // Update project funding - projects.fund( + uint256 totalCollected = projects.fund( usersProjectDeposit[projectId], projectId, depositor, depositPayment ); + // Set the amount raised in the project SFT + HousingSFT projectSFT = HousingSFT( + getProjectData(projectId).tokenAddress + ); + projectSFT.setAmountRaised(totalCollected); + emit ProjectFunded(projectId, depositor, depositPayment); } - function setProjectToken(uint256 projectId) external onlyOwner { + /// @dev Sets the project once funding is successful + /// @param projectId ID of the project + function addProjectToEcosystem(uint256 projectId) external onlyOwner { ProjectStorage.Data storage project = projects[projectId]; - // TODO Add this after demo - // require( - // project.status() == ProjectStorage.Status.Successful, - // "Project Funding not yet successful" - // ); - ISmartHousing(smartHousingAddress).addProject(project.projectAddress); - - HousingProject(project.projectAddress).setTokenDetails( - project.collectedFunds, - coinbase - ); } - /** - * @dev Claims project tokens for a given project ID. - * @param projectId The ID of the project to claim tokens from. - */ + /// @dev Claims project tokens for a given project ID + /// @param projectId ID of the project to claim tokens from function claimProjectTokens(uint256 projectId) external { address depositor = msg.sender; @@ -213,11 +206,7 @@ contract ProjectFunding is Ownable { (ProjectStorage.Data memory project, uint256 depositAmount) = projects .takeDeposit(usersProjectDeposit[projectId], projectId, depositor); - HousingSFT(project.tokenAddress).mintSFT( - depositAmount, - depositor, - project.collectedFunds - ); + HousingSFT(project.tokenAddress).mintSFT(depositAmount, depositor); // Mint LkSHT tokens if the project ID is 1 if (project.id == 1) { @@ -231,6 +220,9 @@ contract ProjectFunding is Ownable { emit ProjectTokensClaimed(depositor, projectId, depositAmount); } + /// @dev Unlocks SHT tokens by updating the nonce and transferring unlocked tokens to the user + /// @param nonce Nonce of the LkSHT token to unlock + /// @return newNonce New nonce for the updated LkSHT token function unlockSHT(uint256 nonce) external returns (uint256 newNonce) { address caller = msg.sender; @@ -259,10 +251,8 @@ contract ProjectFunding is Ownable { } } - /** - * @dev Returns an array of all project IDs and their associated data. - * @return projectList An array of tuples containing project details. - */ + /// @dev Returns an array of all project IDs and their associated data + /// @return projectList An array of tuples containing project details function allProjects() public view returns (ProjectStorage.Data[] memory) { ProjectStorage.Data[] memory projectList = new ProjectStorage.Data[]( projectCount @@ -275,53 +265,29 @@ contract ProjectFunding is Ownable { return projectList; } - /** - * @dev Returns the address of the HousingProject contract for a given project ID. - * @param projectId The ID of the project. - * @return projectAddress The address of the HousingProject contract. - */ + /// @dev Returns the address of the HousingProject contract for a given project ID + /// @param projectId ID of the project + /// @return projectAddress Address of the HousingProject contract function getProjectAddress( uint256 projectId - ) external view returns (address projectAddress) { - ProjectStorage.Data storage project = projects[projectId]; - return project.projectAddress; + ) public view returns (address projectAddress) { + require( + projectId > 0 && projectId <= projectCount, + "Invalid project ID" + ); + projectAddress = projects[projectId].projectAddress; } - /** - * @dev Returns the details of a project by its ID. - * @param projectId The ID of the project. - * @return id The project ID. - * @return fundingGoal The funding goal of the project. - * @return fundingDeadline The deadline for the project funding. - * @return fundingToken The address of the ERC20 token used for funding. - * @return projectAddress The address of the HousingProject contract. - * @return status The funding status of the project. - * @return collectedFunds The amount of funds collected. - */ + /// @dev Returns detailed information about a project by its ID + /// @param projectId ID of the project + /// @return projectData Project data struct function getProjectData( uint256 projectId - ) - external - view - returns ( - uint256 id, - uint256 fundingGoal, - uint256 fundingDeadline, - address fundingToken, - address projectAddress, - uint8 status, - uint256 collectedFunds - ) - { - ProjectStorage.Data storage project = projects[projectId]; - return ( - project.id, - project.fundingGoal, - project.fundingDeadline, - project.fundingToken, - project.projectAddress, - uint8(project.status()), - project.collectedFunds + ) public view returns (ProjectStorage.Data memory projectData) { + require( + projectId > 0 && projectId <= projectCount, + "Invalid project ID" ); + projectData = projects[projectId]; } } diff --git a/packages/backend/contracts/test-artifacts/CoinbaseMock.sol b/packages/backend/contracts/test-artifacts/CoinbaseMock.sol new file mode 100644 index 0000000..9abc2bf --- /dev/null +++ b/packages/backend/contracts/test-artifacts/CoinbaseMock.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import "../coinbase/Coinbase.sol"; +import "./MintableERC20.sol"; + +contract CoinbaseMock is Coinbase { + function mint(address to, uint256 amt) external onlyOwner { + _mint(to, amt); + } +} diff --git a/packages/backend/deploy/100_deploy_project_template.ts b/packages/backend/deploy/100_deploy_project_template.ts index 93f62ab..21b5c95 100644 --- a/packages/backend/deploy/100_deploy_project_template.ts +++ b/packages/backend/deploy/100_deploy_project_template.ts @@ -34,13 +34,13 @@ const deployHousingProject: DeployFunction = async function (hre: HardhatRuntime ); // TODO idealy, this is to be done after successful funding, but it will be teadious // to simulate this in demo, hence we do this here with contract modificatino also - await projectFunding.setProjectToken(1n); + await projectFunding.addProjectToEcosystem(1n); // Done to have the abis in front end await hre.deployments.deploy("HousingProject", { from: deployer, - args: ["", "", ZeroAddress], + args: ["", "", ZeroAddress, ZeroAddress], }); await hre.deployments.deploy("HousingStakingToken", { from: deployer, diff --git a/packages/backend/deployments/opbnb/Coinbase.json b/packages/backend/deployments/opbnb/Coinbase.json index 22ba8f1..51c2281 100644 --- a/packages/backend/deployments/opbnb/Coinbase.json +++ b/packages/backend/deployments/opbnb/Coinbase.json @@ -464,7 +464,7 @@ "args": [], "numDeployments": 2, "solcInputHash": "3f7696dcd180eba0f188ae64ff117803", - "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burnFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"smartHousingAddr\",\"type\":\"address\"}],\"name\":\"feedSmartHousing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"projectFundingAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"smartHousingAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fundingToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fundingGoal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingDeadline\",\"type\":\"uint256\"}],\"name\":\"startICO\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract is used to start the ICO for housing projects.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"See {IERC20-allowance}.\"},\"approve(address,uint256)\":{\"details\":\"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.\"},\"balanceOf(address)\":{\"details\":\"See {IERC20-balanceOf}.\"},\"burn(uint256)\":{\"details\":\"Destroys `amount` tokens from the caller. See {ERC20-_burn}.\"},\"burnFrom(address,uint256)\":{\"details\":\"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`.\"},\"decimals()\":{\"details\":\"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}.\"},\"decreaseAllowance(address,uint256)\":{\"details\":\"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`.\"},\"feedSmartHousing(address)\":{\"details\":\"Dispatches ecosystem funds if not already dispatched to SmartHousing contract.\",\"params\":{\"smartHousingAddr\":\"The address of the SmartHousing contract.\"}},\"increaseAllowance(address,uint256)\":{\"details\":\"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.\"},\"name()\":{\"details\":\"Returns the name of the token.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"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.\"},\"startICO(string,string,address,address,address,uint256,uint256)\":{\"details\":\"Starts the ICO by initializing the first housing project.\",\"params\":{\"fundingDeadline\":\"The deadline for the project funding.\",\"fundingGoal\":\"The funding goal for the new project.\",\"fundingToken\":\"Address of the funding token (ERC20).\",\"projectFundingAddr\":\"Address of the ProjectFunding contract.\",\"smartHousingAddress\":\"Address of the SmartHousing contract.\"}},\"symbol()\":{\"details\":\"Returns the symbol of the token, usually a shorter version of the name.\"},\"totalSupply()\":{\"details\":\"See {IERC20-totalSupply}.\"},\"transfer(address,uint256)\":{\"details\":\"See {IERC20-transfer}. Requirements: - `to` cannot be the zero address. - the caller must have a balance of at least `amount`.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"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`.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"Coinbase\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/coinbase/Coinbase.sol\":\"Coinbase\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../token/ERC20/IERC20.sol\\\";\\n\",\"keccak256\":\"0x6ebf1944ab804b8660eb6fc52f9fe84588cee01c2566a69023e59497e7d27f45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0xd917747dc87f189c6779b894f367a028f9dca4be930283cccec8f312966af820\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n // decrementing then incrementing.\\n _balances[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n unchecked {\\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n _balances[account] += amount;\\n }\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n // Overflow not possible: amount <= accountBalance <= totalSupply.\\n _totalSupply -= amount;\\n }\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x4ffc0547c02ad22925310c585c0f166f8759e2648a09e9b489100c42f15dd98d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../ERC20.sol\\\";\\nimport \\\"../../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\\n * tokens and those that they have an allowance for, in a way that can be\\n * recognized off-chain (via event analysis).\\n */\\nabstract contract ERC20Burnable is Context, ERC20 {\\n /**\\n * @dev Destroys `amount` tokens from the caller.\\n *\\n * See {ERC20-_burn}.\\n */\\n function burn(uint256 amount) public virtual {\\n _burn(_msgSender(), amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, deducting from the caller's\\n * allowance.\\n *\\n * See {ERC20-_burn} and {ERC20-allowance}.\\n *\\n * Requirements:\\n *\\n * - the caller must have allowance for ``accounts``'s tokens of at least\\n * `amount`.\\n */\\n function burnFrom(address account, uint256 amount) public virtual {\\n _spendAllowance(account, _msgSender(), amount);\\n _burn(account, amount);\\n }\\n}\\n\",\"keccak256\":\"0x0d19410453cda55960a818e02bd7c18952a5c8fe7a3036e81f0d599f34487a7b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf96f969e24029d43d0df89e59d365f277021dac62b48e1c1e3ebe0acdd7f1ca1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Counters.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Counters\\n * @author Matt Condon (@shrugs)\\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\\n *\\n * Include with `using Counters for Counters.Counter;`\\n */\\nlibrary Counters {\\n struct Counter {\\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\\n // this feature: see https://github.com/ethereum/solidity/issues/4637\\n uint256 _value; // default: 0\\n }\\n\\n function current(Counter storage counter) internal view returns (uint256) {\\n return counter._value;\\n }\\n\\n function increment(Counter storage counter) internal {\\n unchecked {\\n counter._value += 1;\\n }\\n }\\n\\n function decrement(Counter storage counter) internal {\\n uint256 value = counter._value;\\n require(value > 0, \\\"Counter: decrement overflow\\\");\\n unchecked {\\n counter._value = value - 1;\\n }\\n }\\n\\n function reset(Counter storage counter) internal {\\n counter._value = 0;\\n }\\n}\\n\",\"keccak256\":\"0xf0018c2440fbe238dd3a8732fa8e17a0f9dce84d31451dc8a32f6d62b349c9f1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0f633a0223d9a1dcccfcf38a64c9de0874dfcbfac0c6941ccf074d63a2ce0e1e\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * ```\\n * contract Example {\\n * // Add the library methods\\n * using EnumerableSet for EnumerableSet.AddressSet;\\n *\\n * // Declare a set state variable\\n * EnumerableSet.AddressSet private mySet;\\n * }\\n * ```\\n *\\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\\n * and `uint256` (`UintSet`) are supported.\\n *\\n * [WARNING]\\n * ====\\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\\n * unusable.\\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\\n *\\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\\n * array of EnumerableSet.\\n * ====\\n */\\nlibrary EnumerableSet {\\n // To implement this library for multiple types with as little code\\n // repetition as possible, we write it in terms of a generic Set type with\\n // bytes32 values.\\n // The Set implementation uses private functions, and user-facing\\n // implementations (such as AddressSet) are just wrappers around the\\n // underlying Set.\\n // This means that we can only create new EnumerableSets for types that fit\\n // in bytes32.\\n\\n struct Set {\\n // Storage of set values\\n bytes32[] _values;\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(bytes32 => uint256) _indexes;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function _add(Set storage set, bytes32 value) private returns (bool) {\\n if (!_contains(set, value)) {\\n set._values.push(value);\\n // The value is stored at length-1, but we add 1 to all indexes\\n // and use 0 as a sentinel value\\n set._indexes[value] = set._values.length;\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function _remove(Set storage set, bytes32 value) private returns (bool) {\\n // We read and store the value's index to prevent multiple reads from the same storage slot\\n uint256 valueIndex = set._indexes[value];\\n\\n if (valueIndex != 0) {\\n // Equivalent to contains(set, value)\\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\\n // the array, and then remove the last element (sometimes called as 'swap and pop').\\n // This modifies the order of the array, as noted in {at}.\\n\\n uint256 toDeleteIndex = valueIndex - 1;\\n uint256 lastIndex = set._values.length - 1;\\n\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set._values[lastIndex];\\n\\n // Move the last value to the index where the value to delete is\\n set._values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\\n }\\n\\n // Delete the slot where the moved value was stored\\n set._values.pop();\\n\\n // Delete the index for the deleted slot\\n delete set._indexes[value];\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\\n return set._indexes[value] != 0;\\n }\\n\\n /**\\n * @dev Returns the number of values on the set. O(1).\\n */\\n function _length(Set storage set) private view returns (uint256) {\\n return set._values.length;\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\\n return set._values[index];\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function _values(Set storage set) private view returns (bytes32[] memory) {\\n return set._values;\\n }\\n\\n // Bytes32Set\\n\\n struct Bytes32Set {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _add(set._inner, value);\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _remove(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return _contains(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return _at(set._inner, index);\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n bytes32[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // AddressSet\\n\\n struct AddressSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n return _add(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n return _remove(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\\n return address(uint160(uint256(_at(set._inner, index))));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(AddressSet storage set) internal view returns (address[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n address[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // UintSet\\n\\n struct UintSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(UintSet storage set, uint256 value) internal returns (bool) {\\n return _add(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\\n return _remove(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(UintSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\\n return uint256(_at(set._inner, index));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(UintSet storage set) internal view returns (uint256[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n uint256[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xc3ff3f5c4584e1d9a483ad7ced51ab64523201f4e3d3c65293e4ca8aeb77a961\",\"license\":\"MIT\"},\"contracts/coinbase/Coinbase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\nimport \\\"../modules/sht-module/SHTModule.sol\\\";\\nimport \\\"../project-funding/ProjectFunding.sol\\\";\\n\\n/**\\n * @title Coinbase\\n * @dev This contract is used to start the ICO for housing projects.\\n */\\ncontract Coinbase is Ownable, SHTModule {\\n\\tusing SafeMath for uint256;\\n\\n\\tconstructor() ERC20(\\\"SmartHousingToken\\\", \\\"SHT\\\") {\\n\\t\\t_mint(address(this), SHT.MAX_SUPPLY);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Starts the ICO by initializing the first housing project.\\n\\t * @param projectFundingAddr Address of the ProjectFunding contract.\\n\\t * @param smartHousingAddress Address of the SmartHousing contract.\\n\\t * @param fundingToken Address of the funding token (ERC20).\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction startICO(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress projectFundingAddr,\\n\\t\\taddress smartHousingAddress,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) external onlyOwner {\\n\\t\\tERC20TokenPayment memory icoPayment = _makeSHTPayment(SHT.ICO_FUNDS);\\n\\n\\t\\t_approve(address(this), projectFundingAddr, icoPayment.amount);\\n\\n\\t\\tProjectFunding(projectFundingAddr).initFirstProject(\\n\\t\\t\\ticoPayment,\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tsmartHousingAddress,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Dispatches ecosystem funds if not already dispatched to SmartHousing contract.\\n\\t * @param smartHousingAddr The address of the SmartHousing contract.\\n\\t */\\n\\tfunction feedSmartHousing(address smartHousingAddr) external onlyOwner {\\n\\t\\tERC20TokenPayment memory feedPayment = _makeSHTPayment(\\n\\t\\t\\tSHT.ECOSYSTEM_DISTRIBUTION_FUNDS\\n\\t\\t);\\n\\n\\t\\t// Ensure data integrity\\n\\t\\trequire(\\n\\t\\t\\tbalanceOf(address(this)) >= feedPayment.amount,\\n\\t\\t\\t\\\"Already dispatched\\\"\\n\\t\\t);\\n\\n\\t\\t_approve(address(this), smartHousingAddr, feedPayment.amount);\\n\\n\\t\\tISmartHousing(smartHousingAddr).setUpSHT(feedPayment);\\n\\t}\\n}\\n\",\"keccak256\":\"0x369b329420f100bd15dac5f7d5745276baaf58ca62b8e843d29df3c9e8259d16\",\"license\":\"MIT\"},\"contracts/housing-project/CallsSmartHousing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nabstract contract CallsSmartHousing {\\n\\t/// @notice The address of the main SmartHousing contract.\\n\\taddress immutable smartHousingAddr;\\n\\n\\tconstructor(address smartHousingAddr_) {\\n\\t\\tsmartHousingAddr = smartHousingAddr_;\\n\\t}\\n\\n\\t/// @dev Gets the referrer address for a given original owner.\\n\\t/// @param userAddr The original owner of the token.\\n\\t/// @return The referrer address.\\n\\tfunction getReferrer(\\n\\t\\taddress userAddr\\n\\t) internal view returns (uint, address) {\\n\\t\\treturn IUserModule(smartHousingAddr).getReferrer(userAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0xd2ded3c751d669f079d12e7381e586b747cb9ae1b6d9bd4dbd87fc9db3b0371c\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingProject.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"./RentsModule.sol\\\";\\n\\n/// @title HousingProject Contract\\n/// @notice Represents a unique real estate project within the SmartHousing ecosystem.\\n/// @dev This contract inherits from RentsModule and HousingSFT.\\ncontract HousingProject is RentsModule, Ownable {\\n\\t/// @notice Initializes the HousingProject contract.\\n\\t/// @param smartHousingAddr The address of the main SmartHousing contract.\\n\\tconstructor(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) CallsSmartHousing(smartHousingAddr) {\\n\\t\\tprojectSFT = new HousingSFT(name, symbol);\\n\\t}\\n\\n\\tevent TokenIssued(address tokenAddress, string name, uint256 amountRaised);\\n\\n\\tfunction setTokenDetails(\\n\\t\\tuint256 amountRaised,\\n\\t\\taddress housingTokenAddr\\n\\t) external onlyOwner {\\n\\t\\trequire(amountRaised == 0, \\\"Token details set already\\\");\\n\\n\\t\\thousingToken = ERC20Burnable(housingTokenAddr);\\n\\n\\t\\tprojectSFT.setAmountRaised(amountRaised);\\n\\t\\tstring memory name = projectSFT.name();\\n\\n\\t\\temit TokenIssued(address(projectSFT), name, amountRaised);\\n\\t}\\n\\n\\tfunction getMaxSupply() public view returns (uint256) {\\n\\t\\treturn projectSFT.getMaxSupply();\\n\\t}\\n}\\n\",\"keccak256\":\"0x159e6b338c47a2dacbec1254f582826b5584c338919e6e6908aba986f9a98350\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingSFT.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\n\\nimport \\\"../modules/SFT.sol\\\";\\n\\nstruct HousingAttributes {\\n\\tuint256 rewardsPerShare;\\n\\taddress originalOwner;\\n\\tuint256 tokenWeight;\\n}\\n\\n/// @title Housing SFT\\n/// @notice This contract represents a semi-fungible token (SFT) for housing projects.\\n/// @dev This contract will be inherited by the HousingProject contract.\\ncontract HousingSFT is SFT {\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct HousingSFTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tHousingAttributes attributes;\\n\\t}\\n\\n\\t// FIXME this value should be unique to each contract, should depend on\\n\\t// the total amount expected to raise as it determines the amount of SFTs to\\n\\t// be minted for investors\\n\\tuint256 public constant MAX_SUPPLY = 1_000_000;\\n\\n\\t/// @notice The amount of fungible tokens collected from investors to finance the development of this housing project.\\n\\tuint256 public amountRaised;\\n\\n\\t/// @notice The current amount out of the `MAX_SUPPLY` of tokens minted.\\n\\tuint256 public totalSupply;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tfunction setAmountRaised(uint256 amountRaised_) external onlyOwner {\\n\\t\\tamountRaised = amountRaised_;\\n\\t}\\n\\n\\tmodifier canMint() {\\n\\t\\taddress sftOwner = owner();\\n\\n\\t\\trequire(\\n\\t\\t\\tOwnable(sftOwner).owner() == _msgSender(),\\n\\t\\t\\t\\\"not allowed to mint\\\"\\n\\t\\t);\\n\\n\\t\\t_;\\n\\t}\\n\\n\\t/// @notice Mints SFT tokens for a depositor based on the amount of deposit.\\n\\t/// @param depositAmt The amount of fungible token deposited.\\n\\t/// @param depositor The address of the depositor.\\n\\tfunction mintSFT(\\n\\t\\tuint256 depositAmt,\\n\\t\\taddress depositor,\\n\\t\\tuint256 amount_raised\\n\\t) external canMint returns (uint256) {\\n\\t\\t// TODO remove after demo due to not beign able to move blocks in public networks\\n\\t\\t{\\n\\t\\t\\tamountRaised = amount_raised;\\n\\t\\t}\\n\\n\\t\\tuint256 totalDeposits = amountRaised;\\n\\t\\tuint256 maxShares = MAX_SUPPLY;\\n\\n\\t\\trequire(totalDeposits > 0, \\\"HousingSFT: No deposits recorded\\\");\\n\\n\\t\\tuint256 mintShare = (depositAmt * maxShares) / totalDeposits;\\n\\t\\trequire(mintShare > 0, \\\"HousingSFT: Computed token shares is invalid\\\");\\n\\n\\t\\ttotalSupply += mintShare;\\n\\t\\trequire(totalSupply <= MAX_SUPPLY, \\\"HousingSFT: Max supply exceeded\\\");\\n\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tHousingAttributes({\\n\\t\\t\\t\\trewardsPerShare: 0, // Should be 0 since they have never claimed any rent rewards\\n\\t\\t\\t\\toriginalOwner: depositor,\\n\\t\\t\\t\\ttokenWeight: mintShare\\n\\t\\t\\t})\\n\\t\\t);\\n\\n\\t\\treturn _mint(depositor, mintShare, attributes, \\\"\\\");\\n\\t}\\n\\n\\t/// @notice Checks if an address owns this HousingSFT and returns the attributes.\\n\\t/// @param owner The address to check the balance of.\\n\\t/// @return `HousingAttributes` if the owner has a positive balance of the token, panics otherwise.\\n\\tfunction getUserSFT(\\n\\t\\taddress owner,\\n\\t\\tuint256 nonce\\n\\t) public view returns (HousingAttributes memory) {\\n\\t\\trequire(\\n\\t\\t\\thasSFT(owner, nonce),\\n\\t\\t\\t\\\"HouisingSFT: No tokens found for user at nonce\\\"\\n\\t\\t);\\n\\n\\t\\treturn abi.decode(getRawTokenAttributes(nonce), (HousingAttributes));\\n\\t}\\n\\n\\tfunction getMaxSupply() public pure returns (uint256) {\\n\\t\\treturn MAX_SUPPLY;\\n\\t}\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (HousingSFTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tHousingSFTBalance[] memory balance = new HousingSFTBalance[](\\n\\t\\t\\t_sftBals.length\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = HousingSFTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(_sftBal.attributes, (HousingAttributes))\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\tfunction tokenDetails()\\n\\t\\tpublic\\n\\t\\tview\\n\\t\\treturns (string memory, string memory, uint256)\\n\\t{\\n\\t\\treturn (name(), symbol(), getMaxSupply());\\n\\t}\\n}\\n\",\"keccak256\":\"0x8fbbe8d670bc777eed8587d0a8b11acf1d7b40b9ae631fee4abc929f4275c160\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/NewHousingProjectLib.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport { HousingProject } from \\\"./HousingProject.sol\\\";\\n\\nlibrary NewHousingProject {\\n\\tfunction create(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) external returns (HousingProject) {\\n\\t\\treturn new HousingProject(name, symbol, smartHousingAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0x0ad286112bdc35e59e9424ffda000b7b6b582e228cca1cafc2b9cab28193628f\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/RentsModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\\\";\\n\\nimport \\\"./HousingSFT.sol\\\";\\nimport \\\"./RewardSharing.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"./CallsSmartHousing.sol\\\";\\n\\n/// @title Rents Module\\n/// @notice Handles rent payments, reward calculations, and distribution for Housing projects.\\n/// @dev This abstract contract should be inherited by the HousingProject contract.\\nabstract contract RentsModule is CallsSmartHousing {\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\tusing RewardShares for rewardshares;\\n\\n\\tuint256 public rewardPerShare;\\n\\tuint256 public rewardsReserve;\\n\\tuint256 public facilityManagementFunds;\\n\\n\\tERC20Burnable housingToken;\\n\\tHousingSFT public projectSFT;\\n\\n\\t/// @notice Receives rent payments and distributes rewards.\\n\\t/// @param rentPayment The details of the rent payment.\\n\\tfunction receiveRent(ERC20TokenPayment calldata rentPayment) external {\\n\\t\\t// TODO set the appropriate rent per Project\\n\\t\\trequire(\\n\\t\\t\\trentPayment.amount > 0,\\n\\t\\t\\t\\\"RentsModule: Insufficient rent amount\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\trentPayment.token == housingToken,\\n\\t\\t\\t\\\"RentsModule: Invalid rent payment token\\\"\\n\\t\\t);\\n\\t\\trentPayment.receiveERC20();\\n\\n\\t\\tuint256 rentReward = (rentPayment.amount * 75) / 100;\\n\\t\\tuint256 ecosystemReward = (rentPayment.amount * 18) / 100;\\n\\t\\tuint256 facilityReward = (rentPayment.amount * 7) / 100;\\n\\n\\t\\tuint256 allShares = projectSFT.getMaxSupply();\\n\\t\\tuint256 rpsIncrease = (rentReward * DIVISION_SAFETY_CONST) / allShares;\\n\\n\\t\\trewardPerShare += rpsIncrease;\\n\\t\\trewardsReserve += rentReward;\\n\\t\\tfacilityManagementFunds += facilityReward;\\n\\n\\t\\thousingToken.burn(ecosystemReward);\\n\\t\\tISmartHousing(smartHousingAddr).addProjectRent(rentPayment.amount);\\n\\t}\\n\\n\\t/// @notice Claims rent rewards for a given token.\\n\\t/// @return The updated HousingAttributes.\\n\\tfunction claimRentReward(\\n\\t\\tuint256 nonce\\n\\t) external returns (HousingAttributes memory, rewardshares memory) {\\n\\t\\taddress caller = msg.sender;\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tHousingAttributes memory attr = projectSFT.getUserSFT(caller, nonce);\\n\\t\\trewardshares memory rewardShares = computeRewardShares(attr);\\n\\t\\tuint256 totalReward = rewardShares.total();\\n\\n\\t\\tif (totalReward == 0) {\\n\\t\\t\\t// Fail silently\\n\\t\\t\\treturn (attr, rewardShares);\\n\\t\\t}\\n\\n\\t\\trequire(rewardsReserve >= totalReward, \\\"Computed rewards too large\\\");\\n\\n\\t\\trewardsReserve -= totalReward;\\n\\n\\t\\t// We use original owner since we are certain they are registered\\n\\t\\t(, address referrer) = getReferrer(attr.originalOwner);\\n\\t\\tif (rewardShares.referrerValue > 0) {\\n\\t\\t\\tif (referrer != address(0)) {\\n\\t\\t\\t\\thousingToken.transfer(referrer, rewardShares.referrerValue); // Send to referrer\\n\\t\\t\\t} else {\\n\\t\\t\\t\\thousingToken.burn(rewardShares.referrerValue); // Burn to add to ecosystem reward\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tattr.rewardsPerShare = currentRPS;\\n\\n\\t\\tprojectSFT.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tprojectSFT.balanceOf(caller, nonce),\\n\\t\\t\\tabi.encode(attr)\\n\\t\\t);\\n\\n\\t\\thousingToken.transfer(caller, rewardShares.userValue); // Send to user\\n\\n\\t\\treturn (attr, rewardShares);\\n\\t}\\n\\n\\t/// @notice Computes the amount of rent claimable for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The amount of rent claimable.\\n\\tfunction rentClaimable(\\n\\t\\tHousingAttributes memory attr\\n\\t) public view returns (uint256) {\\n\\t\\treturn computeRewardShares(attr).userValue;\\n\\t}\\n\\n\\t/// @dev Computes the reward shares for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The computed RewardShares.\\n\\tfunction computeRewardShares(\\n\\t\\tHousingAttributes memory attr\\n\\t) internal view returns (rewardshares memory) {\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tif (currentRPS == 0 || attr.rewardsPerShare >= currentRPS) {\\n\\t\\t\\treturn rewardshares({ userValue: 0, referrerValue: 0 });\\n\\t\\t}\\n\\n\\t\\tuint256 reward = computeReward(attr, currentRPS);\\n\\n\\t\\treturn splitReward(reward);\\n\\t}\\n}\\n\",\"keccak256\":\"0xe97c64b7d4f5a945493aa8492c4412248f60ec1e6e8cd74e3f805e40cc672768\",\"license\":\"MIT\"},\"contracts/housing-project/RewardSharing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"./HousingSFT.sol\\\";\\n\\nuint256 constant DIVISION_SAFETY_CONST = 1_000_000_000_000_000_000;\\n\\nstruct rewardshares {\\n\\tuint256 userValue;\\n\\tuint256 referrerValue;\\n}\\n\\nlibrary RewardShares {\\n\\tfunction total(rewardshares memory self) internal pure returns (uint256) {\\n\\t\\treturn self.userValue + self.referrerValue;\\n\\t}\\n}\\n\\nfunction splitReward(uint256 reward) pure returns (rewardshares memory) {\\n\\tuint256 referrerValue = (reward * 6_66) / 100_00; // would amount to approximately 5% of grand total\\n\\tuint256 userValue = reward - referrerValue;\\n\\n\\treturn rewardshares(userValue, referrerValue);\\n}\\n\\nfunction computeReward(\\n\\tHousingAttributes memory attr,\\n\\tuint256 contractRPS\\n) pure returns (uint256) {\\n\\tif (contractRPS <= attr.rewardsPerShare) {\\n\\t\\treturn 0;\\n\\t}\\n\\n\\treturn\\n\\t\\t((contractRPS - attr.rewardsPerShare) * attr.tokenWeight) /\\n\\t\\tDIVISION_SAFETY_CONST;\\n}\\n\",\"keccak256\":\"0x9f07d2b3ee49b91e12ad7ce9ba248ab7dd30bc2efc4238a594e681d3f0348e54\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/lib/LkSHTAttributes.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title LkSHTAttributes\\n * @dev Library for handling attributes and unlocking of the Locked SmartHousing Token.\\n */\\nlibrary LkSHTAttributes {\\n\\tusing SafeMath for uint256;\\n\\n\\t// TODO use this for mainnet uint256 constant LOCK_DURATION = 3 * 365 days; // 3 years\\n\\tuint256 constant LOCK_DURATION = 5 hours;\\n\\n\\tstruct Attributes {\\n\\t\\tuint256 initialAmount;\\n\\t\\tuint256 amount;\\n\\t\\tuint256 startTimestamp;\\n\\t\\tuint256 endTimestamp;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Creates new attributes for a Locked SmartHousing Token.\\n\\t * @param startTimestamp The start time of the lock.\\n\\t * @param amount The amount of SmartHousing Tokens locked.\\n\\t * @return attributes The initialized attributes.\\n\\t */\\n\\tfunction newAttributes(\\n\\t\\tuint256 startTimestamp,\\n\\t\\tuint256 amount\\n\\t) internal pure returns (Attributes memory) {\\n\\t\\treturn\\n\\t\\t\\tAttributes({\\n\\t\\t\\t\\tinitialAmount: amount,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tstartTimestamp: startTimestamp,\\n\\t\\t\\t\\tendTimestamp: startTimestamp.add(LOCK_DURATION)\\n\\t\\t\\t});\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calculates and deducts the unlocked amount based on the elapsed time.\\n\\t * @param self The attributes to update.\\n\\t * @return unlockedAmount The amount of tokens unlocked.\\n\\t */\\n\\tfunction unlockMatured(\\n\\t\\tAttributes memory self\\n\\t)\\n\\t\\tinternal\\n\\t\\tview\\n\\t\\treturns (uint256 unlockedAmount, Attributes memory newSelf)\\n\\t{\\n\\t\\tuint256 elapsed = elapsedTime(self);\\n\\t\\tunlockedAmount = self.amount.mul(elapsed).div(LOCK_DURATION);\\n\\n\\t\\tself.amount = self.amount.sub(unlockedAmount);\\n\\t\\tnewSelf = self;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calculates the elapsed time since the lock started.\\n\\t * @param self The attributes to use.\\n\\t * @return elapsedTime The elapsed time in seconds.\\n\\t */\\n\\tfunction elapsedTime(\\n\\t\\tAttributes memory self\\n\\t) internal view returns (uint256) {\\n\\t\\tuint256 currentTime = block.timestamp;\\n\\t\\tif (currentTime >= self.endTimestamp) {\\n\\t\\t\\treturn LOCK_DURATION;\\n\\t\\t} else {\\n\\t\\t\\treturn currentTime.sub(self.startTimestamp);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0xbaf851bef9603c72b3cce96d93f8f243f36187d31c8c94233101d802b9ae129d\",\"license\":\"MIT\"},\"contracts/lib/ProjectStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport \\\"./TokenPayments.sol\\\";\\n\\nlibrary ProjectStorage {\\n\\tusing SafeMath for uint256;\\n\\tusing TokenPayments for TokenPayment;\\n\\tusing ProjectStorage for Data;\\n\\n\\tenum Status {\\n\\t\\tFundingPeriod,\\n\\t\\tSuccessful,\\n\\t\\tFailed\\n\\t}\\n\\n\\tstruct Data {\\n\\t\\tuint256 id; // Unique identifier for the project\\n\\t\\taddress tokenAddress;\\n\\t\\taddress projectAddress; // Address of the deployed HousingProject contract\\n\\t\\tuint256 fundingGoal; // Target funding amount for the project\\n\\t\\tuint256 fundingDeadline; // Deadline timestamp for the project funding\\n\\t\\taddress fundingToken; // Address of the ERC20 token used for funding\\n\\t\\tuint256 collectedFunds; // Amount of funds collected for the project\\n\\t}\\n\\n\\tfunction status(Data storage self) internal view returns (Status) {\\n\\t\\tif (self.collectedFunds >= self.fundingGoal) {\\n\\t\\t\\treturn Status.Successful;\\n\\t\\t} else if (block.timestamp < self.fundingDeadline) {\\n\\t\\t\\treturn Status.FundingPeriod;\\n\\t\\t} else {\\n\\t\\t\\treturn Status.Failed;\\n\\t\\t}\\n\\t}\\n\\n\\tfunction createNew(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage projectsId,\\n\\t\\tuint256 projectCount,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline,\\n\\t\\taddress fundingToken,\\n\\t\\taddress projectAddress,\\n\\t\\taddress tokenAddress\\n\\t) internal returns (Data memory) {\\n\\t\\trequire(fundingGoal > 0, \\\"Funding goal must be more than 0\\\");\\n\\t\\trequire(\\n\\t\\t\\tfundingDeadline > block.timestamp,\\n\\t\\t\\t\\\"Deadline can't be in the past\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 newId = projectCount.add(1);\\n\\n\\t\\tData memory newProjectData = Data({\\n\\t\\t\\tid: newId,\\n\\t\\t\\tprojectAddress: projectAddress,\\n\\t\\t\\tfundingGoal: fundingGoal,\\n\\t\\t\\tfundingDeadline: fundingDeadline,\\n\\t\\t\\tfundingToken: fundingToken,\\n\\t\\t\\tcollectedFunds: 0,\\n\\t\\t\\ttokenAddress: tokenAddress\\n\\t\\t});\\n\\n\\t\\tprojects[newId] = newProjectData;\\n\\t\\tprojectsId[newProjectData.projectAddress] = newProjectData.id;\\n\\n\\t\\treturn newProjectData;\\n\\t}\\n\\n\\tfunction fund(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage usersDeposit,\\n\\t\\tuint256 projectId,\\n\\t\\taddress depositor,\\n\\t\\tTokenPayment calldata payment\\n\\t) internal {\\n\\t\\trequire(payment.amount > 0, \\\"Invalid funding amount\\\");\\n\\n\\t\\tData storage project = projects[projectId];\\n\\n\\t\\trequire(\\n\\t\\t\\tproject.status() == Status.FundingPeriod,\\n\\t\\t\\t\\\"Cannot fund project after deadline\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\taddress(payment.token) == project.fundingToken,\\n\\t\\t\\t\\\"Wrong token payment\\\"\\n\\t\\t);\\n\\t\\tpayment.receiveToken();\\n\\n\\t\\tproject.collectedFunds = project.collectedFunds.add(payment.amount);\\n\\t\\tusersDeposit[depositor] = usersDeposit[depositor].add(payment.amount);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Retrieves and updates the user's deposit for a specific project.\\n\\t * @param projectId The ID of the project to retrieve the deposit for.\\n\\t * @param depositor The address of the depositor.\\n\\t * @return (ProjectStorage.Data, uint256) The project data and deposit amount.\\n\\t */\\n\\tfunction takeDeposit(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage usersDeposit,\\n\\t\\tuint256 projectId,\\n\\t\\taddress depositor\\n\\t) internal returns (ProjectStorage.Data memory, uint256) {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\trequire(project.id != 0, \\\"Invalid project ID\\\");\\n\\t\\trequire(\\n\\t\\t\\tproject.status() == Status.Successful,\\n\\t\\t\\t\\\"Project not yet successful\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 depositAmount = usersDeposit[depositor];\\n\\t\\trequire(depositAmount > 0, \\\"No deposit found\\\");\\n\\n\\t\\t// Update the deposit amount to zero\\n\\t\\tusersDeposit[depositor] = 0;\\n\\n\\t\\treturn (project, depositAmount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x652aab2dc03764c430b91f35e908430208d6a1bd27a4cc8060adb1ec7f249ad5\",\"license\":\"MIT\"},\"contracts/lib/TokenPayments.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/interfaces/IERC20.sol\\\";\\nimport { SFT } from \\\"../modules/SFT.sol\\\";\\n\\nstruct ERC20TokenPayment {\\n\\tIERC20 token;\\n\\tuint256 amount;\\n}\\n\\nstruct TokenPayment {\\n\\taddress token;\\n\\tuint256 amount;\\n\\tuint256 nonce;\\n}\\n\\nlibrary TokenPayments {\\n\\tfunction accept(ERC20TokenPayment calldata self) internal {\\n\\t\\tTokenPayments.receiveERC20(self, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(ERC20TokenPayment calldata payment) internal {\\n\\t\\tTokenPayments.receiveERC20(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(\\n\\t\\tERC20TokenPayment calldata payment,\\n\\t\\taddress from\\n\\t) internal {\\n\\t\\tpayment.token.transferFrom(from, address(this), payment.amount);\\n\\t}\\n\\n\\t// Receives both Native, SFTs and ERC20; ERC20 have nonce as 0, Native coins have address 0 as token value\\n\\tfunction receiveToken(TokenPayment memory payment) internal {\\n\\t\\treceiveToken(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveToken(TokenPayment memory payment, address from) internal {\\n\\t\\tif (payment.token == address(0)) {\\n\\t\\t\\t// Native payment\\n\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tpayment.amount == msg.value,\\n\\t\\t\\t\\t\\\"expected payment amount must equal sent amount\\\"\\n\\t\\t\\t);\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tfrom == msg.sender,\\n\\t\\t\\t\\t\\\"can receive native payment only from caller\\\"\\n\\t\\t\\t);\\n\\t\\t\\t\\n\\t\\t\\t// Nothing to do again since the VM will handle balance movements\\n\\t\\t} else if (payment.nonce == 0) {\\n\\t\\t\\tIERC20(payment.token).transferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.amount\\n\\t\\t\\t);\\n\\t\\t} else {\\n\\t\\t\\tSFT(payment.token).safeTransferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.nonce,\\n\\t\\t\\t\\tpayment.amount,\\n\\t\\t\\t\\t\\\"\\\"\\n\\t\\t\\t);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x06bd73e8da1bde18d9aaf6d4b6a1bdec6e0718af6354fe2d7ce87251d6fd1ac5\",\"license\":\"MIT\"},\"contracts/main/Interface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"../lib/TokenPayments.sol\\\";\\n\\ninterface ISmartHousing {\\n\\tfunction addProjectRent(uint256 amount) external;\\n\\n\\tfunction createRefIDViaProxy(\\n\\t\\taddress userAddr,\\n\\t\\tuint256 referrerId\\n\\t) external returns (uint256);\\n\\n\\tfunction addProject(address projectAddress) external;\\n\\n\\tfunction setUpSHT(ERC20TokenPayment calldata payment) external;\\n}\\n\\ninterface IUserModule {\\n\\tfunction getReferrer(address user) external view returns (uint, address);\\n}\\n\",\"keccak256\":\"0x066719eed5c5ff2394d78ce027aada5a8555713c9f4abf8b5135975981ba9989\",\"license\":\"MIT\"},\"contracts/modules/LockedSmartHousingToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport \\\"../lib/LkSHTAttributes.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"../modules/SFT.sol\\\";\\n\\nlibrary NewLkSHT {\\n\\tfunction create() external returns (LkSHT) {\\n\\t\\treturn new LkSHT(\\\"Locked Housing Token\\\", \\\"LkSHT\\\");\\n\\t}\\n}\\n\\n/**\\n * @title LockedSmartHousingToken\\n * @dev SFT token that locks SmartHousing Tokens (SHT) during ICO.\\n * Allows transfers only to whitelisted addresses.\\n */\\ncontract LkSHT is SFT {\\n\\tusing SafeMath for uint256;\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\n\\tstruct LkSHTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tLkSHTAttributes.Attributes attributes;\\n\\t}\\n\\n\\tuint256 immutable startTimestamp = block.timestamp;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tevent TokensMinted(address indexed to, uint256 amount);\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (LkSHTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tLkSHTBalance[] memory balance = new LkSHTBalance[](_sftBals.length);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = LkSHTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(\\n\\t\\t\\t\\t\\t_sftBal.attributes,\\n\\t\\t\\t\\t\\t(LkSHTAttributes.Attributes)\\n\\t\\t\\t\\t)\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Mints new Locked SmartHousing Tokens (LkSHT) by locking SHT.\\n\\t * @param amount The amount of SHT to lock.\\n\\t * @param to The address to mint the tokens to.\\n\\t */\\n\\tfunction mint(uint256 amount, address to) external onlyOwner {\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tLkSHTAttributes.newAttributes(startTimestamp, amount)\\n\\t\\t);\\n\\n\\t\\tsuper._mint(to, amount, attributes, \\\"LockedSmartHousingToken\\\");\\n\\n\\t\\temit TokensMinted(to, amount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x33e840a42e8bab335538d2ab9a8973c97423b17caac5fd50a802b53f6db7357d\",\"license\":\"MIT\"},\"contracts/modules/SFT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Counters.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n// TODO I think we should create a standard of this\\nabstract contract SFT is ERC1155, Ownable {\\n\\tusing Counters for Counters.Counter;\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct SftBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tbytes attributes;\\n\\t}\\n\\n\\tCounters.Counter private _nonceCounter;\\n\\tstring private _name;\\n\\tstring private _symbol;\\n\\n\\t// Mapping from nonce to token attributes as bytes\\n\\tmapping(uint256 => bytes) private _tokenAttributes;\\n\\n\\t// Mapping from address to list of owned token nonces\\n\\tmapping(address => EnumerableSet.UintSet) private _addressToNonces;\\n\\n\\tconstructor(string memory name_, string memory symbol_) ERC1155(\\\"\\\") {\\n\\t\\t_name = name_;\\n\\t\\t_symbol = symbol_;\\n\\t}\\n\\n\\t// Private function to mint new tokens\\n\\tfunction _mint(\\n\\t\\taddress to,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attributes,\\n\\t\\tbytes memory data\\n\\t) internal returns (uint256) {\\n\\t\\t_nonceCounter.increment();\\n\\t\\tuint256 nonce = _nonceCounter.current();\\n\\n\\t\\t// Store the attributes\\n\\t\\t_tokenAttributes[nonce] = attributes;\\n\\n\\t\\t// Mint the token with the nonce as its ID\\n\\t\\tsuper._mint(to, nonce, amount, data);\\n\\n\\t\\t// Track the nonce for the address\\n\\t\\t_addressToNonces[to].add(nonce);\\n\\n\\t\\treturn nonce;\\n\\t}\\n\\n\\tfunction name() public view returns (string memory) {\\n\\t\\treturn _name;\\n\\t}\\n\\n\\tfunction symbol() public view returns (string memory) {\\n\\t\\treturn _symbol;\\n\\t}\\n\\n\\tfunction tokenInfo() public view returns (string memory, string memory) {\\n\\t\\treturn (_name, _symbol);\\n\\t}\\n\\n\\t// Function to get token attributes by nonce\\n\\tfunction getRawTokenAttributes(\\n\\t\\tuint256 nonce\\n\\t) public view returns (bytes memory) {\\n\\t\\treturn _tokenAttributes[nonce];\\n\\t}\\n\\n\\t// Function to get list of nonces owned by an address\\n\\tfunction getNonces(address owner) public view returns (uint256[] memory) {\\n\\t\\treturn _addressToNonces[owner].values();\\n\\t}\\n\\n\\tfunction hasSFT(address owner, uint256 nonce) public view returns (bool) {\\n\\t\\treturn _addressToNonces[owner].contains(nonce);\\n\\t}\\n\\n\\t/// Burns all the NFT balance of user at nonce, creates new with balance and attributes\\n\\tfunction update(\\n\\t\\taddress user,\\n\\t\\tuint256 nonce,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attr\\n\\t) external onlyOwner {\\n\\t\\t_burn(user, nonce, amount);\\n\\t\\t_mint(user, amount, attr, \\\"\\\");\\n\\t}\\n\\n\\tfunction _sftBalance(\\n\\t\\taddress user\\n\\t) internal view returns (SftBalance[] memory) {\\n\\t\\tuint256[] memory nonces = getNonces(user);\\n\\t\\tSftBalance[] memory balance = new SftBalance[](nonces.length);\\n\\n\\t\\tfor (uint256 i; i < nonces.length; i++) {\\n\\t\\t\\tuint256 nonce = nonces[i];\\n\\t\\t\\tbytes memory attributes = _tokenAttributes[nonce];\\n\\t\\t\\tuint256 amount = balanceOf(user, nonce);\\n\\n\\t\\t\\tbalance[i] = SftBalance({\\n\\t\\t\\t\\tnonce: nonce,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tattributes: attributes\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t// Override _beforeTokenTransfer to handle address-to-nonce mapping\\n\\tfunction _beforeTokenTransfer(\\n\\t\\taddress operator,\\n\\t\\taddress from,\\n\\t\\taddress to,\\n\\t\\tuint256[] memory ids,\\n\\t\\tuint256[] memory amounts,\\n\\t\\tbytes memory data\\n\\t) internal virtual override {\\n\\t\\tsuper._beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[from].remove(ids[i]);\\n\\t\\t}\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[to].add(ids[i]);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x8098c36137bbb9a342d16fd64f7d57c03a77841a872dd44641b9db1623a699aa\",\"license\":\"MIT\"},\"contracts/modules/sht-module/SHT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nlibrary SHT {\\n\\tuint256 public constant DECIMALS = 18;\\n\\tuint256 public constant ONE = 10 ** DECIMALS;\\n\\tuint256 public constant MAX_SUPPLY = 21_000_000 * ONE;\\n\\tuint256 public constant ECOSYSTEM_DISTRIBUTION_FUNDS =\\n\\t\\t(13_650_000 * ONE) + 2_248_573_618_499_339;\\n\\tuint256 public constant ICO_FUNDS =\\n\\t\\tMAX_SUPPLY - ECOSYSTEM_DISTRIBUTION_FUNDS;\\n}\\n\",\"keccak256\":\"0x66b511a7932bd0f6ceea118f9440cac3a6fd470d11e4d7fa337de8b178627dd7\",\"license\":\"MIT\"},\"contracts/modules/sht-module/SHTModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\\\";\\n\\nimport \\\"../../lib/TokenPayments.sol\\\";\\nimport \\\"./SHT.sol\\\";\\n\\n/**\\n * @title SHTModule\\n * @dev This contract manages the Smart Housing Token (SHT) within the platform.\\n * It includes functionalities for making payments in SHT and querying the SHT token ID.\\n */\\nabstract contract SHTModule is ERC20, ERC20Burnable {\\n\\tfunction decimals() public pure override returns (uint8) {\\n\\t\\treturn uint8(SHT.DECIMALS);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Makes an ERC20TokenPayment struct in SHT for and amount.\\n\\t * @param shtAmount Amount of SHT to be sent.\\n\\t * @return payment ERC20TokenPayment struct representing the payment.\\n\\t */\\n\\tfunction _makeSHTPayment(\\n\\t\\tuint256 shtAmount\\n\\t) internal view returns (ERC20TokenPayment memory) {\\n\\t\\treturn ERC20TokenPayment(IERC20(address(this)), shtAmount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x7d10eb1cf870d02c54a9db9fbbd7f0813a94197398a9fb13bdf51143941910e2\",\"license\":\"MIT\"},\"contracts/project-funding/ProjectFunding.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\\\";\\n\\nimport \\\"../lib/ProjectStorage.sol\\\";\\nimport \\\"../lib/LkSHTAttributes.sol\\\";\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nimport \\\"../modules/LockedSmartHousingToken.sol\\\";\\nimport \\\"../modules/sht-module/SHT.sol\\\";\\n\\nimport { HousingSFT } from \\\"../housing-project/HousingSFT.sol\\\";\\nimport { TokenPayment } from \\\"../lib/TokenPayments.sol\\\";\\nimport { NewHousingProject, HousingProject } from \\\"../housing-project/NewHousingProjectLib.sol\\\";\\n\\n/**\\n * @title ProjectFunding\\n * @dev This contract is used for initializing and deploying housing projects.\\n * It allows the deployment of a new housing project and manages project data.\\n */\\ncontract ProjectFunding is Ownable {\\n\\tusing SafeMath for uint256;\\n\\tusing ProjectStorage for mapping(uint256 => ProjectStorage.Data);\\n\\tusing ProjectStorage for ProjectStorage.Data;\\n\\tusing LkSHTAttributes for LkSHTAttributes.Attributes;\\n\\n\\taddress public coinbase; // Address authorized to initialize the first project, also the housingToken\\n\\taddress public smartHousingAddress; // Address of the SmartHousing contract\\n\\n\\tmapping(uint256 => ProjectStorage.Data) public projects; // Mapping of project ID to ProjectData\\n\\tmapping(address => uint256) public projectsId; // Mapping of project address to project ID\\n\\tuint256 public projectCount; // Counter for the total number of projects\\n\\n\\tmapping(uint256 => mapping(address => uint256)) public usersProjectDeposit;\\n\\n\\tIERC20 public housingToken; // Token used for funding projects\\n\\tLkSHT public lkSht; // The locked version\\n\\n\\t/**\\n\\t * @dev Emitted when a new project is deployed.\\n\\t * @param projectAddress Address of the newly deployed HousingProject contract.\\n\\t */\\n\\tevent ProjectDeployed(address indexed projectAddress);\\n\\tevent ProjectFunded(\\n\\t\\tuint256 indexed projectId,\\n\\t\\taddress indexed depositor,\\n\\t\\tTokenPayment payment\\n\\t);\\n\\tevent ProjectTokensClaimed(\\n\\t\\taddress indexed depositor,\\n\\t\\tuint256 projectId,\\n\\t\\tuint256 amount\\n\\t);\\n\\n\\t/**\\n\\t * @param _coinbase Address authorized to initialize the first project.\\n\\t */\\n\\tconstructor(address _coinbase) {\\n\\t\\tcoinbase = _coinbase;\\n\\t\\tlkSht = NewLkSHT.create();\\n\\t}\\n\\n\\t/**\\n\\t * @dev Internal function to deploy a new HousingProject contract.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction _deployProject(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) internal {\\n\\t\\tHousingProject newProject = NewHousingProject.create(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tsmartHousingAddress\\n\\t\\t);\\n\\t\\tProjectStorage.Data memory projectData = projects.createNew(\\n\\t\\t\\tprojectsId,\\n\\t\\t\\tprojectCount,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\taddress(newProject),\\n\\t\\t\\taddress(newProject.projectSFT())\\n\\t\\t);\\n\\t\\tprojectCount = projectData.id;\\n\\n\\t\\temit ProjectDeployed(projectData.projectAddress);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Initializes the first project.\\n\\t * This function must be called by the coinbase address and can only be called once.\\n\\t * It sets up the token and deploys the first project.\\n\\t * @param shtPayment Payment details for the Smart Housing Token (SHT).\\n\\t * @param smartHousingAddress_ Address of the Smart Housing contract.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction initFirstProject(\\n\\t\\tERC20TokenPayment calldata shtPayment,\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddress_,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) external {\\n\\t\\trequire(msg.sender == coinbase, \\\"Caller is not the coinbase\\\");\\n\\t\\trequire(projectCount == 0, \\\"Project already initialized\\\");\\n\\n\\t\\tTokenPayments.receiveERC20(shtPayment);\\n\\t\\thousingToken = shtPayment.token;\\n\\n\\t\\tsmartHousingAddress = smartHousingAddress_;\\n\\n\\t\\t_deployProject(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Deploys a new project.\\n\\t * This function can be called multiple times to deploy additional projects.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction deployProject(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) public onlyOwner {\\n\\t\\t_deployProject(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\tfunction fundProject(\\n\\t\\tTokenPayment calldata depositPayment,\\n\\t\\tuint256 projectId,\\n\\t\\tuint256 referrerId\\n\\t) external payable {\\n\\t\\trequire(\\n\\t\\t\\tprojectId > 0 && projectId <= projectCount,\\n\\t\\t\\t\\\"Invalid project ID\\\"\\n\\t\\t);\\n\\n\\t\\taddress depositor = msg.sender;\\n\\n\\t\\t// Register user with referrer (if needed)\\n\\t\\tISmartHousing(smartHousingAddress).createRefIDViaProxy(\\n\\t\\t\\tdepositor,\\n\\t\\t\\treferrerId\\n\\t\\t);\\n\\n\\t\\t// Update project funding\\n\\t\\tprojects.fund(\\n\\t\\t\\tusersProjectDeposit[projectId],\\n\\t\\t\\tprojectId,\\n\\t\\t\\tdepositor,\\n\\t\\t\\tdepositPayment\\n\\t\\t);\\n\\n\\t\\temit ProjectFunded(projectId, depositor, depositPayment);\\n\\t}\\n\\n\\tfunction setProjectToken(uint256 projectId) external onlyOwner {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\n\\t\\t// TODO Add this after demo\\n\\t\\t// require(\\n\\t\\t// \\tproject.status() == ProjectStorage.Status.Successful,\\n\\t\\t// \\t\\\"Project Funding not yet successful\\\"\\n\\t\\t// );\\n\\n\\t\\tISmartHousing(smartHousingAddress).addProject(project.projectAddress);\\n\\n\\t\\tHousingProject(project.projectAddress).setTokenDetails(\\n\\t\\t\\tproject.collectedFunds,\\n\\t\\t\\tcoinbase\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Claims project tokens for a given project ID.\\n\\t * @param projectId The ID of the project to claim tokens from.\\n\\t */\\n\\tfunction claimProjectTokens(uint256 projectId) external {\\n\\t\\taddress depositor = msg.sender;\\n\\n\\t\\t// Retrieve the project and deposit amount\\n\\t\\t(ProjectStorage.Data memory project, uint256 depositAmount) = projects\\n\\t\\t\\t.takeDeposit(usersProjectDeposit[projectId], projectId, depositor);\\n\\n\\t\\tHousingSFT(project.tokenAddress).mintSFT(\\n\\t\\t\\tdepositAmount,\\n\\t\\t\\tdepositor,\\n\\t\\t\\tproject.collectedFunds\\n\\t\\t);\\n\\n\\t\\t// Mint LkSHT tokens if the project ID is 1\\n\\t\\tif (project.id == 1) {\\n\\t\\t\\tuint256 shtAmount = depositAmount.mul(SHT.ICO_FUNDS).div(\\n\\t\\t\\t\\tproject.collectedFunds\\n\\t\\t\\t);\\n\\n\\t\\t\\tlkSht.mint(shtAmount, depositor);\\n\\t\\t}\\n\\n\\t\\temit ProjectTokensClaimed(depositor, projectId, depositAmount);\\n\\t}\\n\\n\\tfunction unlockSHT(uint256 nonce) external {\\n\\t\\taddress caller = msg.sender;\\n\\n\\t\\tuint256 lkShtBal = lkSht.balanceOf(caller, nonce);\\n\\t\\trequire(lkShtBal > 0, \\\"ProjectFunding: Nothing to unlock\\\");\\n\\n\\t\\tLkSHTAttributes.Attributes memory attr = abi.decode(\\n\\t\\t\\tlkSht.getRawTokenAttributes(nonce),\\n\\t\\t\\t(LkSHTAttributes.Attributes)\\n\\t\\t);\\n\\t\\t(\\n\\t\\t\\tuint256 totalUnlockedAmount,\\n\\t\\t\\tLkSHTAttributes.Attributes memory newAttr\\n\\t\\t) = attr.unlockMatured();\\n\\n\\t\\tlkSht.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tlkShtBal.sub(totalUnlockedAmount),\\n\\t\\t\\tabi.encode(newAttr)\\n\\t\\t);\\n\\n\\t\\t// Transfer the total unlocked SHT tokens to the user's address\\n\\t\\tif (totalUnlockedAmount > 0) {\\n\\t\\t\\thousingToken.transfer(caller, totalUnlockedAmount);\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns an array of all project IDs and their associated data.\\n\\t * @return projectList An array of tuples containing project details.\\n\\t */\\n\\tfunction allProjects() public view returns (ProjectStorage.Data[] memory) {\\n\\t\\tProjectStorage.Data[] memory projectList = new ProjectStorage.Data[](\\n\\t\\t\\tprojectCount\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i = 1; i <= projectCount; i++) {\\n\\t\\t\\tprojectList[i - 1] = projects[i];\\n\\t\\t}\\n\\n\\t\\treturn projectList;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns the address of the HousingProject contract for a given project ID.\\n\\t * @param projectId The ID of the project.\\n\\t * @return projectAddress The address of the HousingProject contract.\\n\\t */\\n\\tfunction getProjectAddress(\\n\\t\\tuint256 projectId\\n\\t) external view returns (address projectAddress) {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\treturn project.projectAddress;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns the details of a project by its ID.\\n\\t * @param projectId The ID of the project.\\n\\t * @return id The project ID.\\n\\t * @return fundingGoal The funding goal of the project.\\n\\t * @return fundingDeadline The deadline for the project funding.\\n\\t * @return fundingToken The address of the ERC20 token used for funding.\\n\\t * @return projectAddress The address of the HousingProject contract.\\n\\t * @return status The funding status of the project.\\n\\t * @return collectedFunds The amount of funds collected.\\n\\t */\\n\\tfunction getProjectData(\\n\\t\\tuint256 projectId\\n\\t)\\n\\t\\texternal\\n\\t\\tview\\n\\t\\treturns (\\n\\t\\t\\tuint256 id,\\n\\t\\t\\tuint256 fundingGoal,\\n\\t\\t\\tuint256 fundingDeadline,\\n\\t\\t\\taddress fundingToken,\\n\\t\\t\\taddress projectAddress,\\n\\t\\t\\tuint8 status,\\n\\t\\t\\tuint256 collectedFunds\\n\\t\\t)\\n\\t{\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\treturn (\\n\\t\\t\\tproject.id,\\n\\t\\t\\tproject.fundingGoal,\\n\\t\\t\\tproject.fundingDeadline,\\n\\t\\t\\tproject.fundingToken,\\n\\t\\t\\tproject.projectAddress,\\n\\t\\t\\tuint8(project.status()),\\n\\t\\t\\tproject.collectedFunds\\n\\t\\t);\\n\\t}\\n}\\n\",\"keccak256\":\"0xba3518a6288e777e4b2b51d944cbc298200458d0f09f3c5b701f52547991a4e1\",\"license\":\"MIT\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burnFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"smartHousingAddr\",\"type\":\"address\"}],\"name\":\"feedSmartHousing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"projectFundingAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"smartHousingAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fundingToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fundingGoal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingDeadline\",\"type\":\"uint256\"}],\"name\":\"startICO\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract is used to start the ICO for housing projects.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"See {IERC20-allowance}.\"},\"approve(address,uint256)\":{\"details\":\"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.\"},\"balanceOf(address)\":{\"details\":\"See {IERC20-balanceOf}.\"},\"burn(uint256)\":{\"details\":\"Destroys `amount` tokens from the caller. See {ERC20-_burn}.\"},\"burnFrom(address,uint256)\":{\"details\":\"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`.\"},\"decimals()\":{\"details\":\"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}.\"},\"decreaseAllowance(address,uint256)\":{\"details\":\"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`.\"},\"feedSmartHousing(address)\":{\"details\":\"Dispatches ecosystem funds if not already dispatched to SmartHousing contract.\",\"params\":{\"smartHousingAddr\":\"The address of the SmartHousing contract.\"}},\"increaseAllowance(address,uint256)\":{\"details\":\"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.\"},\"name()\":{\"details\":\"Returns the name of the token.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"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.\"},\"startICO(string,string,address,address,address,uint256,uint256)\":{\"details\":\"Starts the ICO by initializing the first housing project.\",\"params\":{\"fundingDeadline\":\"The deadline for the project funding.\",\"fundingGoal\":\"The funding goal for the new project.\",\"fundingToken\":\"Address of the funding token (ERC20).\",\"projectFundingAddr\":\"Address of the ProjectFunding contract.\",\"smartHousingAddress\":\"Address of the SmartHousing contract.\"}},\"symbol()\":{\"details\":\"Returns the symbol of the token, usually a shorter version of the name.\"},\"totalSupply()\":{\"details\":\"See {IERC20-totalSupply}.\"},\"transfer(address,uint256)\":{\"details\":\"See {IERC20-transfer}. Requirements: - `to` cannot be the zero address. - the caller must have a balance of at least `amount`.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"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`.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"Coinbase\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/coinbase/Coinbase.sol\":\"Coinbase\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../token/ERC20/IERC20.sol\\\";\\n\",\"keccak256\":\"0x6ebf1944ab804b8660eb6fc52f9fe84588cee01c2566a69023e59497e7d27f45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0xd917747dc87f189c6779b894f367a028f9dca4be930283cccec8f312966af820\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n // decrementing then incrementing.\\n _balances[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n unchecked {\\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n _balances[account] += amount;\\n }\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n // Overflow not possible: amount <= accountBalance <= totalSupply.\\n _totalSupply -= amount;\\n }\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x4ffc0547c02ad22925310c585c0f166f8759e2648a09e9b489100c42f15dd98d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../ERC20.sol\\\";\\nimport \\\"../../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\\n * tokens and those that they have an allowance for, in a way that can be\\n * recognized off-chain (via event analysis).\\n */\\nabstract contract ERC20Burnable is Context, ERC20 {\\n /**\\n * @dev Destroys `amount` tokens from the caller.\\n *\\n * See {ERC20-_burn}.\\n */\\n function burn(uint256 amount) public virtual {\\n _burn(_msgSender(), amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, deducting from the caller's\\n * allowance.\\n *\\n * See {ERC20-_burn} and {ERC20-allowance}.\\n *\\n * Requirements:\\n *\\n * - the caller must have allowance for ``accounts``'s tokens of at least\\n * `amount`.\\n */\\n function burnFrom(address account, uint256 amount) public virtual {\\n _spendAllowance(account, _msgSender(), amount);\\n _burn(account, amount);\\n }\\n}\\n\",\"keccak256\":\"0x0d19410453cda55960a818e02bd7c18952a5c8fe7a3036e81f0d599f34487a7b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf96f969e24029d43d0df89e59d365f277021dac62b48e1c1e3ebe0acdd7f1ca1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Counters.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Counters\\n * @author Matt Condon (@shrugs)\\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\\n *\\n * Include with `using Counters for Counters.Counter;`\\n */\\nlibrary Counters {\\n struct Counter {\\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\\n // this feature: see https://github.com/ethereum/solidity/issues/4637\\n uint256 _value; // default: 0\\n }\\n\\n function current(Counter storage counter) internal view returns (uint256) {\\n return counter._value;\\n }\\n\\n function increment(Counter storage counter) internal {\\n unchecked {\\n counter._value += 1;\\n }\\n }\\n\\n function decrement(Counter storage counter) internal {\\n uint256 value = counter._value;\\n require(value > 0, \\\"Counter: decrement overflow\\\");\\n unchecked {\\n counter._value = value - 1;\\n }\\n }\\n\\n function reset(Counter storage counter) internal {\\n counter._value = 0;\\n }\\n}\\n\",\"keccak256\":\"0xf0018c2440fbe238dd3a8732fa8e17a0f9dce84d31451dc8a32f6d62b349c9f1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0f633a0223d9a1dcccfcf38a64c9de0874dfcbfac0c6941ccf074d63a2ce0e1e\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * ```\\n * contract Example {\\n * // Add the library methods\\n * using EnumerableSet for EnumerableSet.AddressSet;\\n *\\n * // Declare a set state variable\\n * EnumerableSet.AddressSet private mySet;\\n * }\\n * ```\\n *\\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\\n * and `uint256` (`UintSet`) are supported.\\n *\\n * [WARNING]\\n * ====\\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\\n * unusable.\\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\\n *\\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\\n * array of EnumerableSet.\\n * ====\\n */\\nlibrary EnumerableSet {\\n // To implement this library for multiple types with as little code\\n // repetition as possible, we write it in terms of a generic Set type with\\n // bytes32 values.\\n // The Set implementation uses private functions, and user-facing\\n // implementations (such as AddressSet) are just wrappers around the\\n // underlying Set.\\n // This means that we can only create new EnumerableSets for types that fit\\n // in bytes32.\\n\\n struct Set {\\n // Storage of set values\\n bytes32[] _values;\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(bytes32 => uint256) _indexes;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function _add(Set storage set, bytes32 value) private returns (bool) {\\n if (!_contains(set, value)) {\\n set._values.push(value);\\n // The value is stored at length-1, but we add 1 to all indexes\\n // and use 0 as a sentinel value\\n set._indexes[value] = set._values.length;\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function _remove(Set storage set, bytes32 value) private returns (bool) {\\n // We read and store the value's index to prevent multiple reads from the same storage slot\\n uint256 valueIndex = set._indexes[value];\\n\\n if (valueIndex != 0) {\\n // Equivalent to contains(set, value)\\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\\n // the array, and then remove the last element (sometimes called as 'swap and pop').\\n // This modifies the order of the array, as noted in {at}.\\n\\n uint256 toDeleteIndex = valueIndex - 1;\\n uint256 lastIndex = set._values.length - 1;\\n\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set._values[lastIndex];\\n\\n // Move the last value to the index where the value to delete is\\n set._values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\\n }\\n\\n // Delete the slot where the moved value was stored\\n set._values.pop();\\n\\n // Delete the index for the deleted slot\\n delete set._indexes[value];\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\\n return set._indexes[value] != 0;\\n }\\n\\n /**\\n * @dev Returns the number of values on the set. O(1).\\n */\\n function _length(Set storage set) private view returns (uint256) {\\n return set._values.length;\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\\n return set._values[index];\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function _values(Set storage set) private view returns (bytes32[] memory) {\\n return set._values;\\n }\\n\\n // Bytes32Set\\n\\n struct Bytes32Set {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _add(set._inner, value);\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _remove(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return _contains(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return _at(set._inner, index);\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n bytes32[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // AddressSet\\n\\n struct AddressSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n return _add(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n return _remove(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\\n return address(uint160(uint256(_at(set._inner, index))));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(AddressSet storage set) internal view returns (address[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n address[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // UintSet\\n\\n struct UintSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(UintSet storage set, uint256 value) internal returns (bool) {\\n return _add(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\\n return _remove(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(UintSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\\n return uint256(_at(set._inner, index));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(UintSet storage set) internal view returns (uint256[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n uint256[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xc3ff3f5c4584e1d9a483ad7ced51ab64523201f4e3d3c65293e4ca8aeb77a961\",\"license\":\"MIT\"},\"contracts/coinbase/Coinbase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\nimport \\\"../modules/sht-module/SHTModule.sol\\\";\\nimport \\\"../project-funding/ProjectFunding.sol\\\";\\n\\n/**\\n * @title Coinbase\\n * @dev This contract is used to start the ICO for housing projects.\\n */\\ncontract Coinbase is Ownable, SHTModule {\\n\\tusing SafeMath for uint256;\\n\\n\\tconstructor() ERC20(\\\"SmartHousingToken\\\", \\\"SHT\\\") {\\n\\t\\t_mint(address(this), SHT.MAX_SUPPLY);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Starts the ICO by initializing the first housing project.\\n\\t * @param projectFundingAddr Address of the ProjectFunding contract.\\n\\t * @param smartHousingAddress Address of the SmartHousing contract.\\n\\t * @param fundingToken Address of the funding token (ERC20).\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction startICO(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress projectFundingAddr,\\n\\t\\taddress smartHousingAddress,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) external onlyOwner {\\n\\t\\tERC20TokenPayment memory icoPayment = _makeSHTPayment(SHT.ICO_FUNDS);\\n\\n\\t\\t_approve(address(this), projectFundingAddr, icoPayment.amount);\\n\\n\\t\\tProjectFunding(projectFundingAddr).initFirstProject(\\n\\t\\t\\ticoPayment,\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tsmartHousingAddress,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Dispatches ecosystem funds if not already dispatched to SmartHousing contract.\\n\\t * @param smartHousingAddr The address of the SmartHousing contract.\\n\\t */\\n\\tfunction feedSmartHousing(address smartHousingAddr) external onlyOwner {\\n\\t\\tERC20TokenPayment memory feedPayment = _makeSHTPayment(\\n\\t\\t\\tSHT.ECOSYSTEM_DISTRIBUTION_FUNDS\\n\\t\\t);\\n\\n\\t\\t// Ensure data integrity\\n\\t\\trequire(\\n\\t\\t\\tbalanceOf(address(this)) >= feedPayment.amount,\\n\\t\\t\\t\\\"Already dispatched\\\"\\n\\t\\t);\\n\\n\\t\\t_approve(address(this), smartHousingAddr, feedPayment.amount);\\n\\n\\t\\tISmartHousing(smartHousingAddr).setUpSHT(feedPayment);\\n\\t}\\n}\\n\",\"keccak256\":\"0x369b329420f100bd15dac5f7d5745276baaf58ca62b8e843d29df3c9e8259d16\",\"license\":\"MIT\"},\"contracts/housing-project/CallsSmartHousing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nabstract contract CallsSmartHousing {\\n\\t/// @notice The address of the main SmartHousing contract.\\n\\taddress immutable smartHousingAddr;\\n\\n\\tconstructor(address smartHousingAddr_) {\\n\\t\\tsmartHousingAddr = smartHousingAddr_;\\n\\t}\\n\\n\\t/// @dev Gets the referrer address for a given original owner.\\n\\t/// @param userAddr The original owner of the token.\\n\\t/// @return The referrer address.\\n\\tfunction getReferrer(\\n\\t\\taddress userAddr\\n\\t) internal view returns (uint, address) {\\n\\t\\treturn IUserModule(smartHousingAddr).getReferrer(userAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0xd2ded3c751d669f079d12e7381e586b747cb9ae1b6d9bd4dbd87fc9db3b0371c\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingProject.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"./RentsModule.sol\\\";\\n\\n/// @title HousingProject Contract\\n/// @notice Represents a unique real estate project within the SmartHousing ecosystem.\\n/// @dev This contract inherits from RentsModule and HousingSFT.\\ncontract HousingProject is RentsModule, Ownable {\\n\\t/// @notice Initializes the HousingProject contract.\\n\\t/// @param smartHousingAddr The address of the main SmartHousing contract.\\n\\tconstructor(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) CallsSmartHousing(smartHousingAddr) {\\n\\t\\tprojectSFT = new HousingSFT(name, symbol);\\n\\t}\\n\\n\\tevent TokenIssued(address tokenAddress, string name, uint256 amountRaised);\\n\\n\\tfunction setTokenDetails(\\n\\t\\tuint256 amountRaised,\\n\\t\\taddress housingTokenAddr\\n\\t) external onlyOwner {\\n\\t\\trequire(amountRaised == 0, \\\"Token details set already\\\");\\n\\n\\t\\thousingToken = ERC20Burnable(housingTokenAddr);\\n\\n\\t\\tprojectSFT.setAmountRaised(amountRaised);\\n\\t\\tstring memory name = projectSFT.name();\\n\\n\\t\\temit TokenIssued(address(projectSFT), name, amountRaised);\\n\\t}\\n\\n\\tfunction getMaxSupply() public view returns (uint256) {\\n\\t\\treturn projectSFT.getMaxSupply();\\n\\t}\\n}\\n\",\"keccak256\":\"0x159e6b338c47a2dacbec1254f582826b5584c338919e6e6908aba986f9a98350\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingSFT.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\n\\nimport \\\"../modules/SFT.sol\\\";\\n\\nstruct HousingAttributes {\\n\\tuint256 rewardsPerShare;\\n\\taddress originalOwner;\\n\\tuint256 tokenWeight;\\n}\\n\\n/// @title Housing SFT\\n/// @notice This contract represents a semi-fungible token (SFT) for housing projects.\\n/// @dev This contract will be inherited by the HousingProject contract.\\ncontract HousingSFT is SFT {\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct HousingSFTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tHousingAttributes attributes;\\n\\t}\\n\\n\\t// FIXME this value should be unique to each contract, should depend on\\n\\t// the total amount expected to raise as it determines the amount of SFTs to\\n\\t// be minted for investors\\n\\tuint256 public constant MAX_SUPPLY = 1_000_000;\\n\\n\\t/// @notice The amount of fungible tokens collected from investors to finance the development of this housing project.\\n\\tuint256 public amountRaised;\\n\\n\\t/// @notice The current amount out of the `MAX_SUPPLY` of tokens minted.\\n\\tuint256 public totalSupply;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tfunction setAmountRaised(uint256 amountRaised_) external onlyOwner {\\n\\t\\tamountRaised = amountRaised_;\\n\\t}\\n\\n\\tmodifier canMint() {\\n\\t\\taddress sftOwner = owner();\\n\\n\\t\\trequire(\\n\\t\\t\\tOwnable(sftOwner).owner() == _msgSender(),\\n\\t\\t\\t\\\"not allowed to mint\\\"\\n\\t\\t);\\n\\n\\t\\t_;\\n\\t}\\n\\n\\t/// @notice Mints SFT tokens for a depositor based on the amount of deposit.\\n\\t/// @param depositAmt The amount of fungible token deposited.\\n\\t/// @param depositor The address of the depositor.\\n\\tfunction mintSFT(\\n\\t\\tuint256 depositAmt,\\n\\t\\taddress depositor,\\n\\t\\tuint256 amount_raised\\n\\t) external canMint returns (uint256) {\\n\\t\\t// TODO remove after demo due to not beign able to move blocks in public networks\\n\\t\\t{\\n\\t\\t\\tamountRaised = amount_raised;\\n\\t\\t}\\n\\n\\t\\tuint256 totalDeposits = amountRaised;\\n\\t\\tuint256 maxShares = MAX_SUPPLY;\\n\\n\\t\\trequire(totalDeposits > 0, \\\"HousingSFT: No deposits recorded\\\");\\n\\n\\t\\tuint256 mintShare = (depositAmt * maxShares) / totalDeposits;\\n\\t\\trequire(mintShare > 0, \\\"HousingSFT: Computed token shares is invalid\\\");\\n\\n\\t\\ttotalSupply += mintShare;\\n\\t\\trequire(totalSupply <= MAX_SUPPLY, \\\"HousingSFT: Max supply exceeded\\\");\\n\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tHousingAttributes({\\n\\t\\t\\t\\trewardsPerShare: 0, // Should be 0 since they have never claimed any rent rewards\\n\\t\\t\\t\\toriginalOwner: depositor,\\n\\t\\t\\t\\ttokenWeight: mintShare\\n\\t\\t\\t})\\n\\t\\t);\\n\\n\\t\\treturn _mint(depositor, mintShare, attributes, \\\"\\\");\\n\\t}\\n\\n\\t/// @notice Checks if an address owns this HousingSFT and returns the attributes.\\n\\t/// @param owner The address to check the balance of.\\n\\t/// @return `HousingAttributes` if the owner has a positive balance of the token, panics otherwise.\\n\\tfunction getUserSFT(\\n\\t\\taddress owner,\\n\\t\\tuint256 nonce\\n\\t) public view returns (HousingAttributes memory) {\\n\\t\\trequire(\\n\\t\\t\\thasSFT(owner, nonce),\\n\\t\\t\\t\\\"HouisingSFT: No tokens found for user at nonce\\\"\\n\\t\\t);\\n\\n\\t\\treturn abi.decode(getRawTokenAttributes(nonce), (HousingAttributes));\\n\\t}\\n\\n\\tfunction getMaxSupply() public pure returns (uint256) {\\n\\t\\treturn MAX_SUPPLY;\\n\\t}\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (HousingSFTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tHousingSFTBalance[] memory balance = new HousingSFTBalance[](\\n\\t\\t\\t_sftBals.length\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = HousingSFTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(_sftBal.attributes, (HousingAttributes))\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\tfunction tokenDetails()\\n\\t\\tpublic\\n\\t\\tview\\n\\t\\treturns (string memory, string memory, uint256)\\n\\t{\\n\\t\\treturn (name(), symbol(), getMaxSupply());\\n\\t}\\n}\\n\",\"keccak256\":\"0x8fbbe8d670bc777eed8587d0a8b11acf1d7b40b9ae631fee4abc929f4275c160\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/NewHousingProjectLib.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport { HousingProject } from \\\"./HousingProject.sol\\\";\\n\\nlibrary NewHousingProject {\\n\\tfunction create(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) external returns (HousingProject) {\\n\\t\\treturn new HousingProject(name, symbol, smartHousingAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0x0ad286112bdc35e59e9424ffda000b7b6b582e228cca1cafc2b9cab28193628f\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/RentsModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\\\";\\n\\nimport \\\"./HousingSFT.sol\\\";\\nimport \\\"./RewardSharing.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"./CallsSmartHousing.sol\\\";\\n\\n/// @title Rents Module\\n/// @notice Handles rent payments, reward calculations, and distribution for Housing projects.\\n/// @dev This abstract contract should be inherited by the HousingProject contract.\\nabstract contract RentsModule is CallsSmartHousing {\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\tusing RewardShares for rewardshares;\\n\\n\\tuint256 public rewardPerShare;\\n\\tuint256 public rewardsReserve;\\n\\tuint256 public facilityManagementFunds;\\n\\n\\tERC20Burnable housingToken;\\n\\tHousingSFT public projectSFT;\\n\\n\\t/// @notice Receives rent payments and distributes rewards.\\n\\t/// @param rentPayment The details of the rent payment.\\n\\tfunction receiveRent(ERC20TokenPayment calldata rentPayment) external {\\n\\t\\t// TODO set the appropriate rent per Project\\n\\t\\trequire(\\n\\t\\t\\trentPayment.amount > 0,\\n\\t\\t\\t\\\"RentsModule: Insufficient amount\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\trentPayment.token == housingToken,\\n\\t\\t\\t\\\"RentsModule: Invalid rent payment token\\\"\\n\\t\\t);\\n\\t\\trentPayment.receiveERC20();\\n\\n\\t\\tuint256 rentReward = (rentPayment.amount * 75) / 100;\\n\\t\\tuint256 ecosystemReward = (rentPayment.amount * 18) / 100;\\n\\t\\tuint256 facilityReward = (rentPayment.amount * 7) / 100;\\n\\n\\t\\tuint256 allShares = projectSFT.getMaxSupply();\\n\\t\\tuint256 rpsIncrease = (rentReward * DIVISION_SAFETY_CONST) / allShares;\\n\\n\\t\\trewardPerShare += rpsIncrease;\\n\\t\\trewardsReserve += rentReward;\\n\\t\\tfacilityManagementFunds += facilityReward;\\n\\n\\t\\thousingToken.burn(ecosystemReward);\\n\\t\\tISmartHousing(smartHousingAddr).addProjectRent(rentPayment.amount);\\n\\t}\\n\\n\\t/// @notice Claims rent rewards for a given token.\\n\\t/// @return The updated HousingAttributes.\\n\\tfunction claimRentReward(\\n\\t\\tuint256 nonce\\n\\t) external returns (HousingAttributes memory, rewardshares memory) {\\n\\t\\taddress caller = msg.sender;\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tHousingAttributes memory attr = projectSFT.getUserSFT(caller, nonce);\\n\\t\\trewardshares memory rewardShares = computeRewardShares(attr);\\n\\t\\tuint256 totalReward = rewardShares.total();\\n\\n\\t\\tif (totalReward == 0) {\\n\\t\\t\\t// Fail silently\\n\\t\\t\\treturn (attr, rewardShares);\\n\\t\\t}\\n\\n\\t\\trequire(rewardsReserve >= totalReward, \\\"Computed rewards too large\\\");\\n\\n\\t\\trewardsReserve -= totalReward;\\n\\n\\t\\t// We use original owner since we are certain they are registered\\n\\t\\t(, address referrer) = getReferrer(attr.originalOwner);\\n\\t\\tif (rewardShares.referrerValue > 0) {\\n\\t\\t\\tif (referrer != address(0)) {\\n\\t\\t\\t\\thousingToken.transfer(referrer, rewardShares.referrerValue); // Send to referrer\\n\\t\\t\\t} else {\\n\\t\\t\\t\\thousingToken.burn(rewardShares.referrerValue); // Burn to add to ecosystem reward\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tattr.rewardsPerShare = currentRPS;\\n\\n\\t\\tprojectSFT.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tprojectSFT.balanceOf(caller, nonce),\\n\\t\\t\\tabi.encode(attr)\\n\\t\\t);\\n\\n\\t\\thousingToken.transfer(caller, rewardShares.userValue); // Send to user\\n\\n\\t\\treturn (attr, rewardShares);\\n\\t}\\n\\n\\t/// @notice Computes the amount of rent claimable for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The amount of rent claimable.\\n\\tfunction rentClaimable(\\n\\t\\tHousingAttributes memory attr\\n\\t) public view returns (uint256) {\\n\\t\\treturn computeRewardShares(attr).userValue;\\n\\t}\\n\\n\\t/// @dev Computes the reward shares for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The computed RewardShares.\\n\\tfunction computeRewardShares(\\n\\t\\tHousingAttributes memory attr\\n\\t) internal view returns (rewardshares memory) {\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tif (currentRPS == 0 || attr.rewardsPerShare >= currentRPS) {\\n\\t\\t\\treturn rewardshares({ userValue: 0, referrerValue: 0 });\\n\\t\\t}\\n\\n\\t\\tuint256 reward = computeReward(attr, currentRPS);\\n\\n\\t\\treturn splitReward(reward);\\n\\t}\\n}\\n\",\"keccak256\":\"0xe97c64b7d4f5a945493aa8492c4412248f60ec1e6e8cd74e3f805e40cc672768\",\"license\":\"MIT\"},\"contracts/housing-project/RewardSharing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"./HousingSFT.sol\\\";\\n\\nuint256 constant DIVISION_SAFETY_CONST = 1_000_000_000_000_000_000;\\n\\nstruct rewardshares {\\n\\tuint256 userValue;\\n\\tuint256 referrerValue;\\n}\\n\\nlibrary RewardShares {\\n\\tfunction total(rewardshares memory self) internal pure returns (uint256) {\\n\\t\\treturn self.userValue + self.referrerValue;\\n\\t}\\n}\\n\\nfunction splitReward(uint256 reward) pure returns (rewardshares memory) {\\n\\tuint256 referrerValue = (reward * 6_66) / 100_00; // would amount to approximately 5% of grand total\\n\\tuint256 userValue = reward - referrerValue;\\n\\n\\treturn rewardshares(userValue, referrerValue);\\n}\\n\\nfunction computeReward(\\n\\tHousingAttributes memory attr,\\n\\tuint256 contractRPS\\n) pure returns (uint256) {\\n\\tif (contractRPS <= attr.rewardsPerShare) {\\n\\t\\treturn 0;\\n\\t}\\n\\n\\treturn\\n\\t\\t((contractRPS - attr.rewardsPerShare) * attr.tokenWeight) /\\n\\t\\tDIVISION_SAFETY_CONST;\\n}\\n\",\"keccak256\":\"0x9f07d2b3ee49b91e12ad7ce9ba248ab7dd30bc2efc4238a594e681d3f0348e54\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/lib/LkSHTAttributes.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title LkSHTAttributes\\n * @dev Library for handling attributes and unlocking of the Locked SmartHousing Token.\\n */\\nlibrary LkSHTAttributes {\\n\\tusing SafeMath for uint256;\\n\\n\\t// TODO use this for mainnet uint256 constant LOCK_DURATION = 3 * 365 days; // 3 years\\n\\tuint256 constant LOCK_DURATION = 5 hours;\\n\\n\\tstruct Attributes {\\n\\t\\tuint256 initialAmount;\\n\\t\\tuint256 amount;\\n\\t\\tuint256 startTimestamp;\\n\\t\\tuint256 endTimestamp;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Creates new attributes for a Locked SmartHousing Token.\\n\\t * @param startTimestamp The start time of the lock.\\n\\t * @param amount The amount of SmartHousing Tokens locked.\\n\\t * @return attributes The initialized attributes.\\n\\t */\\n\\tfunction newAttributes(\\n\\t\\tuint256 startTimestamp,\\n\\t\\tuint256 amount\\n\\t) internal pure returns (Attributes memory) {\\n\\t\\treturn\\n\\t\\t\\tAttributes({\\n\\t\\t\\t\\tinitialAmount: amount,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tstartTimestamp: startTimestamp,\\n\\t\\t\\t\\tendTimestamp: startTimestamp.add(LOCK_DURATION)\\n\\t\\t\\t});\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calculates and deducts the unlocked amount based on the elapsed time.\\n\\t * @param self The attributes to update.\\n\\t * @return unlockedAmount The amount of tokens unlocked.\\n\\t */\\n\\tfunction unlockMatured(\\n\\t\\tAttributes memory self\\n\\t)\\n\\t\\tinternal\\n\\t\\tview\\n\\t\\treturns (uint256 unlockedAmount, Attributes memory newSelf)\\n\\t{\\n\\t\\tuint256 elapsed = elapsedTime(self);\\n\\t\\tunlockedAmount = self.amount.mul(elapsed).div(LOCK_DURATION);\\n\\n\\t\\tself.amount = self.amount.sub(unlockedAmount);\\n\\t\\tnewSelf = self;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calculates the elapsed time since the lock started.\\n\\t * @param self The attributes to use.\\n\\t * @return elapsedTime The elapsed time in seconds.\\n\\t */\\n\\tfunction elapsedTime(\\n\\t\\tAttributes memory self\\n\\t) internal view returns (uint256) {\\n\\t\\tuint256 currentTime = block.timestamp;\\n\\t\\tif (currentTime >= self.endTimestamp) {\\n\\t\\t\\treturn LOCK_DURATION;\\n\\t\\t} else {\\n\\t\\t\\treturn currentTime.sub(self.startTimestamp);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0xbaf851bef9603c72b3cce96d93f8f243f36187d31c8c94233101d802b9ae129d\",\"license\":\"MIT\"},\"contracts/lib/ProjectStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport \\\"./TokenPayments.sol\\\";\\n\\nlibrary ProjectStorage {\\n\\tusing SafeMath for uint256;\\n\\tusing TokenPayments for TokenPayment;\\n\\tusing ProjectStorage for Data;\\n\\n\\tenum Status {\\n\\t\\tFundingPeriod,\\n\\t\\tSuccessful,\\n\\t\\tFailed\\n\\t}\\n\\n\\tstruct Data {\\n\\t\\tuint256 id; // Unique identifier for the project\\n\\t\\taddress tokenAddress;\\n\\t\\taddress projectAddress; // Address of the deployed HousingProject contract\\n\\t\\tuint256 fundingGoal; // Target funding amount for the project\\n\\t\\tuint256 fundingDeadline; // Deadline timestamp for the project funding\\n\\t\\taddress fundingToken; // Address of the ERC20 token used for funding\\n\\t\\tuint256 collectedFunds; // Amount of funds collected for the project\\n\\t}\\n\\n\\tfunction status(Data storage self) internal view returns (Status) {\\n\\t\\tif (self.collectedFunds >= self.fundingGoal) {\\n\\t\\t\\treturn Status.Successful;\\n\\t\\t} else if (block.timestamp < self.fundingDeadline) {\\n\\t\\t\\treturn Status.FundingPeriod;\\n\\t\\t} else {\\n\\t\\t\\treturn Status.Failed;\\n\\t\\t}\\n\\t}\\n\\n\\tfunction createNew(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage projectsId,\\n\\t\\tuint256 projectCount,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline,\\n\\t\\taddress fundingToken,\\n\\t\\taddress projectAddress,\\n\\t\\taddress tokenAddress\\n\\t) internal returns (Data memory) {\\n\\t\\trequire(fundingGoal > 0, \\\"Funding goal must be more than 0\\\");\\n\\t\\trequire(\\n\\t\\t\\tfundingDeadline > block.timestamp,\\n\\t\\t\\t\\\"Deadline can't be in the past\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 newId = projectCount.add(1);\\n\\n\\t\\tData memory newProjectData = Data({\\n\\t\\t\\tid: newId,\\n\\t\\t\\tprojectAddress: projectAddress,\\n\\t\\t\\tfundingGoal: fundingGoal,\\n\\t\\t\\tfundingDeadline: fundingDeadline,\\n\\t\\t\\tfundingToken: fundingToken,\\n\\t\\t\\tcollectedFunds: 0,\\n\\t\\t\\ttokenAddress: tokenAddress\\n\\t\\t});\\n\\n\\t\\tprojects[newId] = newProjectData;\\n\\t\\tprojectsId[newProjectData.projectAddress] = newProjectData.id;\\n\\n\\t\\treturn newProjectData;\\n\\t}\\n\\n\\tfunction fund(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage usersDeposit,\\n\\t\\tuint256 projectId,\\n\\t\\taddress depositor,\\n\\t\\tTokenPayment calldata payment\\n\\t) internal {\\n\\t\\trequire(payment.amount > 0, \\\"Invalid funding amount\\\");\\n\\n\\t\\tData storage project = projects[projectId];\\n\\n\\t\\trequire(\\n\\t\\t\\tproject.status() == Status.FundingPeriod,\\n\\t\\t\\t\\\"Cannot fund project after deadline\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\taddress(payment.token) == project.fundingToken,\\n\\t\\t\\t\\\"Wrong token payment\\\"\\n\\t\\t);\\n\\t\\tpayment.receiveToken();\\n\\n\\t\\tproject.collectedFunds = project.collectedFunds.add(payment.amount);\\n\\t\\tusersDeposit[depositor] = usersDeposit[depositor].add(payment.amount);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Retrieves and updates the user's deposit for a specific project.\\n\\t * @param projectId The ID of the project to retrieve the deposit for.\\n\\t * @param depositor The address of the depositor.\\n\\t * @return (ProjectStorage.Data, uint256) The project data and deposit amount.\\n\\t */\\n\\tfunction takeDeposit(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage usersDeposit,\\n\\t\\tuint256 projectId,\\n\\t\\taddress depositor\\n\\t) internal returns (ProjectStorage.Data memory, uint256) {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\trequire(project.id != 0, \\\"Invalid project ID\\\");\\n\\t\\trequire(\\n\\t\\t\\tproject.status() == Status.Successful,\\n\\t\\t\\t\\\"Project not yet successful\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 depositAmount = usersDeposit[depositor];\\n\\t\\trequire(depositAmount > 0, \\\"No deposit found\\\");\\n\\n\\t\\t// Update the deposit amount to zero\\n\\t\\tusersDeposit[depositor] = 0;\\n\\n\\t\\treturn (project, depositAmount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x652aab2dc03764c430b91f35e908430208d6a1bd27a4cc8060adb1ec7f249ad5\",\"license\":\"MIT\"},\"contracts/lib/TokenPayments.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/interfaces/IERC20.sol\\\";\\nimport { SFT } from \\\"../modules/SFT.sol\\\";\\n\\nstruct ERC20TokenPayment {\\n\\tIERC20 token;\\n\\tuint256 amount;\\n}\\n\\nstruct TokenPayment {\\n\\taddress token;\\n\\tuint256 amount;\\n\\tuint256 nonce;\\n}\\n\\nlibrary TokenPayments {\\n\\tfunction accept(ERC20TokenPayment calldata self) internal {\\n\\t\\tTokenPayments.receiveERC20(self, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(ERC20TokenPayment calldata payment) internal {\\n\\t\\tTokenPayments.receiveERC20(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(\\n\\t\\tERC20TokenPayment calldata payment,\\n\\t\\taddress from\\n\\t) internal {\\n\\t\\tpayment.token.transferFrom(from, address(this), payment.amount);\\n\\t}\\n\\n\\t// Receives both Native, SFTs and ERC20; ERC20 have nonce as 0, Native coins have address 0 as token value\\n\\tfunction receiveToken(TokenPayment memory payment) internal {\\n\\t\\treceiveToken(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveToken(TokenPayment memory payment, address from) internal {\\n\\t\\tif (payment.token == address(0)) {\\n\\t\\t\\t// Native payment\\n\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tpayment.amount == msg.value,\\n\\t\\t\\t\\t\\\"expected payment amount must equal sent amount\\\"\\n\\t\\t\\t);\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tfrom == msg.sender,\\n\\t\\t\\t\\t\\\"can receive native payment only from caller\\\"\\n\\t\\t\\t);\\n\\t\\t\\t\\n\\t\\t\\t// Nothing to do again since the VM will handle balance movements\\n\\t\\t} else if (payment.nonce == 0) {\\n\\t\\t\\tIERC20(payment.token).transferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.amount\\n\\t\\t\\t);\\n\\t\\t} else {\\n\\t\\t\\tSFT(payment.token).safeTransferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.nonce,\\n\\t\\t\\t\\tpayment.amount,\\n\\t\\t\\t\\t\\\"\\\"\\n\\t\\t\\t);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x06bd73e8da1bde18d9aaf6d4b6a1bdec6e0718af6354fe2d7ce87251d6fd1ac5\",\"license\":\"MIT\"},\"contracts/main/Interface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"../lib/TokenPayments.sol\\\";\\n\\ninterface ISmartHousing {\\n\\tfunction addProjectRent(uint256 amount) external;\\n\\n\\tfunction createRefIDViaProxy(\\n\\t\\taddress userAddr,\\n\\t\\tuint256 referrerId\\n\\t) external returns (uint256);\\n\\n\\tfunction addProject(address projectAddress) external;\\n\\n\\tfunction setUpSHT(ERC20TokenPayment calldata payment) external;\\n}\\n\\ninterface IUserModule {\\n\\tfunction getReferrer(address user) external view returns (uint, address);\\n}\\n\",\"keccak256\":\"0x066719eed5c5ff2394d78ce027aada5a8555713c9f4abf8b5135975981ba9989\",\"license\":\"MIT\"},\"contracts/modules/LockedSmartHousingToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport \\\"../lib/LkSHTAttributes.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"../modules/SFT.sol\\\";\\n\\nlibrary NewLkSHT {\\n\\tfunction create() external returns (LkSHT) {\\n\\t\\treturn new LkSHT(\\\"Locked Housing Token\\\", \\\"LkSHT\\\");\\n\\t}\\n}\\n\\n/**\\n * @title LockedSmartHousingToken\\n * @dev SFT token that locks SmartHousing Tokens (SHT) during ICO.\\n * Allows transfers only to whitelisted addresses.\\n */\\ncontract LkSHT is SFT {\\n\\tusing SafeMath for uint256;\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\n\\tstruct LkSHTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tLkSHTAttributes.Attributes attributes;\\n\\t}\\n\\n\\tuint256 immutable startTimestamp = block.timestamp;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tevent TokensMinted(address indexed to, uint256 amount);\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (LkSHTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tLkSHTBalance[] memory balance = new LkSHTBalance[](_sftBals.length);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = LkSHTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(\\n\\t\\t\\t\\t\\t_sftBal.attributes,\\n\\t\\t\\t\\t\\t(LkSHTAttributes.Attributes)\\n\\t\\t\\t\\t)\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Mints new Locked SmartHousing Tokens (LkSHT) by locking SHT.\\n\\t * @param amount The amount of SHT to lock.\\n\\t * @param to The address to mint the tokens to.\\n\\t */\\n\\tfunction mint(uint256 amount, address to) external onlyOwner {\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tLkSHTAttributes.newAttributes(startTimestamp, amount)\\n\\t\\t);\\n\\n\\t\\tsuper._mint(to, amount, attributes, \\\"LockedSmartHousingToken\\\");\\n\\n\\t\\temit TokensMinted(to, amount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x33e840a42e8bab335538d2ab9a8973c97423b17caac5fd50a802b53f6db7357d\",\"license\":\"MIT\"},\"contracts/modules/SFT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Counters.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n// TODO I think we should create a standard of this\\nabstract contract SFT is ERC1155, Ownable {\\n\\tusing Counters for Counters.Counter;\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct SftBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tbytes attributes;\\n\\t}\\n\\n\\tCounters.Counter private _nonceCounter;\\n\\tstring private _name;\\n\\tstring private _symbol;\\n\\n\\t// Mapping from nonce to token attributes as bytes\\n\\tmapping(uint256 => bytes) private _tokenAttributes;\\n\\n\\t// Mapping from address to list of owned token nonces\\n\\tmapping(address => EnumerableSet.UintSet) private _addressToNonces;\\n\\n\\tconstructor(string memory name_, string memory symbol_) ERC1155(\\\"\\\") {\\n\\t\\t_name = name_;\\n\\t\\t_symbol = symbol_;\\n\\t}\\n\\n\\t// Private function to mint new tokens\\n\\tfunction _mint(\\n\\t\\taddress to,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attributes,\\n\\t\\tbytes memory data\\n\\t) internal returns (uint256) {\\n\\t\\t_nonceCounter.increment();\\n\\t\\tuint256 nonce = _nonceCounter.current();\\n\\n\\t\\t// Store the attributes\\n\\t\\t_tokenAttributes[nonce] = attributes;\\n\\n\\t\\t// Mint the token with the nonce as its ID\\n\\t\\tsuper._mint(to, nonce, amount, data);\\n\\n\\t\\t// Track the nonce for the address\\n\\t\\t_addressToNonces[to].add(nonce);\\n\\n\\t\\treturn nonce;\\n\\t}\\n\\n\\tfunction name() public view returns (string memory) {\\n\\t\\treturn _name;\\n\\t}\\n\\n\\tfunction symbol() public view returns (string memory) {\\n\\t\\treturn _symbol;\\n\\t}\\n\\n\\tfunction tokenInfo() public view returns (string memory, string memory) {\\n\\t\\treturn (_name, _symbol);\\n\\t}\\n\\n\\t// Function to get token attributes by nonce\\n\\tfunction getRawTokenAttributes(\\n\\t\\tuint256 nonce\\n\\t) public view returns (bytes memory) {\\n\\t\\treturn _tokenAttributes[nonce];\\n\\t}\\n\\n\\t// Function to get list of nonces owned by an address\\n\\tfunction getNonces(address owner) public view returns (uint256[] memory) {\\n\\t\\treturn _addressToNonces[owner].values();\\n\\t}\\n\\n\\tfunction hasSFT(address owner, uint256 nonce) public view returns (bool) {\\n\\t\\treturn _addressToNonces[owner].contains(nonce);\\n\\t}\\n\\n\\t/// Burns all the NFT balance of user at nonce, creates new with balance and attributes\\n\\tfunction update(\\n\\t\\taddress user,\\n\\t\\tuint256 nonce,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attr\\n\\t) external onlyOwner {\\n\\t\\t_burn(user, nonce, amount);\\n\\t\\t_mint(user, amount, attr, \\\"\\\");\\n\\t}\\n\\n\\tfunction _sftBalance(\\n\\t\\taddress user\\n\\t) internal view returns (SftBalance[] memory) {\\n\\t\\tuint256[] memory nonces = getNonces(user);\\n\\t\\tSftBalance[] memory balance = new SftBalance[](nonces.length);\\n\\n\\t\\tfor (uint256 i; i < nonces.length; i++) {\\n\\t\\t\\tuint256 nonce = nonces[i];\\n\\t\\t\\tbytes memory attributes = _tokenAttributes[nonce];\\n\\t\\t\\tuint256 amount = balanceOf(user, nonce);\\n\\n\\t\\t\\tbalance[i] = SftBalance({\\n\\t\\t\\t\\tnonce: nonce,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tattributes: attributes\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t// Override _beforeTokenTransfer to handle address-to-nonce mapping\\n\\tfunction _beforeTokenTransfer(\\n\\t\\taddress operator,\\n\\t\\taddress from,\\n\\t\\taddress to,\\n\\t\\tuint256[] memory ids,\\n\\t\\tuint256[] memory amounts,\\n\\t\\tbytes memory data\\n\\t) internal virtual override {\\n\\t\\tsuper._beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[from].remove(ids[i]);\\n\\t\\t}\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[to].add(ids[i]);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x8098c36137bbb9a342d16fd64f7d57c03a77841a872dd44641b9db1623a699aa\",\"license\":\"MIT\"},\"contracts/modules/sht-module/SHT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nlibrary SHT {\\n\\tuint256 public constant DECIMALS = 18;\\n\\tuint256 public constant ONE = 10 ** DECIMALS;\\n\\tuint256 public constant MAX_SUPPLY = 21_000_000 * ONE;\\n\\tuint256 public constant ECOSYSTEM_DISTRIBUTION_FUNDS =\\n\\t\\t(13_650_000 * ONE) + 2_248_573_618_499_339;\\n\\tuint256 public constant ICO_FUNDS =\\n\\t\\tMAX_SUPPLY - ECOSYSTEM_DISTRIBUTION_FUNDS;\\n}\\n\",\"keccak256\":\"0x66b511a7932bd0f6ceea118f9440cac3a6fd470d11e4d7fa337de8b178627dd7\",\"license\":\"MIT\"},\"contracts/modules/sht-module/SHTModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\\\";\\n\\nimport \\\"../../lib/TokenPayments.sol\\\";\\nimport \\\"./SHT.sol\\\";\\n\\n/**\\n * @title SHTModule\\n * @dev This contract manages the Smart Housing Token (SHT) within the platform.\\n * It includes functionalities for making payments in SHT and querying the SHT token ID.\\n */\\nabstract contract SHTModule is ERC20, ERC20Burnable {\\n\\tfunction decimals() public pure override returns (uint8) {\\n\\t\\treturn uint8(SHT.DECIMALS);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Makes an ERC20TokenPayment struct in SHT for and amount.\\n\\t * @param shtAmount Amount of SHT to be sent.\\n\\t * @return payment ERC20TokenPayment struct representing the payment.\\n\\t */\\n\\tfunction _makeSHTPayment(\\n\\t\\tuint256 shtAmount\\n\\t) internal view returns (ERC20TokenPayment memory) {\\n\\t\\treturn ERC20TokenPayment(IERC20(address(this)), shtAmount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x7d10eb1cf870d02c54a9db9fbbd7f0813a94197398a9fb13bdf51143941910e2\",\"license\":\"MIT\"},\"contracts/project-funding/ProjectFunding.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\\\";\\n\\nimport \\\"../lib/ProjectStorage.sol\\\";\\nimport \\\"../lib/LkSHTAttributes.sol\\\";\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nimport \\\"../modules/LockedSmartHousingToken.sol\\\";\\nimport \\\"../modules/sht-module/SHT.sol\\\";\\n\\nimport { HousingSFT } from \\\"../housing-project/HousingSFT.sol\\\";\\nimport { TokenPayment } from \\\"../lib/TokenPayments.sol\\\";\\nimport { NewHousingProject, HousingProject } from \\\"../housing-project/NewHousingProjectLib.sol\\\";\\n\\n/**\\n * @title ProjectFunding\\n * @dev This contract is used for initializing and deploying housing projects.\\n * It allows the deployment of a new housing project and manages project data.\\n */\\ncontract ProjectFunding is Ownable {\\n\\tusing SafeMath for uint256;\\n\\tusing ProjectStorage for mapping(uint256 => ProjectStorage.Data);\\n\\tusing ProjectStorage for ProjectStorage.Data;\\n\\tusing LkSHTAttributes for LkSHTAttributes.Attributes;\\n\\n\\taddress public coinbase; // Address authorized to initialize the first project, also the housingToken\\n\\taddress public smartHousingAddress; // Address of the SmartHousing contract\\n\\n\\tmapping(uint256 => ProjectStorage.Data) public projects; // Mapping of project ID to ProjectData\\n\\tmapping(address => uint256) public projectsId; // Mapping of project address to project ID\\n\\tuint256 public projectCount; // Counter for the total number of projects\\n\\n\\tmapping(uint256 => mapping(address => uint256)) public usersProjectDeposit;\\n\\n\\tIERC20 public housingToken; // Token used for funding projects\\n\\tLkSHT public lkSht; // The locked version\\n\\n\\t/**\\n\\t * @dev Emitted when a new project is deployed.\\n\\t * @param projectAddress Address of the newly deployed HousingProject contract.\\n\\t */\\n\\tevent ProjectDeployed(address indexed projectAddress);\\n\\tevent ProjectFunded(\\n\\t\\tuint256 indexed projectId,\\n\\t\\taddress indexed depositor,\\n\\t\\tTokenPayment payment\\n\\t);\\n\\tevent ProjectTokensClaimed(\\n\\t\\taddress indexed depositor,\\n\\t\\tuint256 projectId,\\n\\t\\tuint256 amount\\n\\t);\\n\\n\\t/**\\n\\t * @param _coinbase Address authorized to initialize the first project.\\n\\t */\\n\\tconstructor(address _coinbase) {\\n\\t\\tcoinbase = _coinbase;\\n\\t\\tlkSht = NewLkSHT.create();\\n\\t}\\n\\n\\t/**\\n\\t * @dev Internal function to deploy a new HousingProject contract.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction _deployProject(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) internal {\\n\\t\\tHousingProject newProject = NewHousingProject.create(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tsmartHousingAddress\\n\\t\\t);\\n\\t\\tProjectStorage.Data memory projectData = projects.createNew(\\n\\t\\t\\tprojectsId,\\n\\t\\t\\tprojectCount,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\taddress(newProject),\\n\\t\\t\\taddress(newProject.projectSFT())\\n\\t\\t);\\n\\t\\tprojectCount = projectData.id;\\n\\n\\t\\temit ProjectDeployed(projectData.projectAddress);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Initializes the first project.\\n\\t * This function must be called by the coinbase address and can only be called once.\\n\\t * It sets up the token and deploys the first project.\\n\\t * @param shtPayment Payment details for the Smart Housing Token (SHT).\\n\\t * @param smartHousingAddress_ Address of the Smart Housing contract.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction initFirstProject(\\n\\t\\tERC20TokenPayment calldata shtPayment,\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddress_,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) external {\\n\\t\\trequire(msg.sender == coinbase, \\\"Caller is not the coinbase\\\");\\n\\t\\trequire(projectCount == 0, \\\"Project already initialized\\\");\\n\\n\\t\\tTokenPayments.receiveERC20(shtPayment);\\n\\t\\thousingToken = shtPayment.token;\\n\\n\\t\\tsmartHousingAddress = smartHousingAddress_;\\n\\n\\t\\t_deployProject(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Deploys a new project.\\n\\t * This function can be called multiple times to deploy additional projects.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction deployProject(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) public onlyOwner {\\n\\t\\t_deployProject(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\tfunction fundProject(\\n\\t\\tTokenPayment calldata depositPayment,\\n\\t\\tuint256 projectId,\\n\\t\\tuint256 referrerId\\n\\t) external payable {\\n\\t\\trequire(\\n\\t\\t\\tprojectId > 0 && projectId <= projectCount,\\n\\t\\t\\t\\\"Invalid project ID\\\"\\n\\t\\t);\\n\\n\\t\\taddress depositor = msg.sender;\\n\\n\\t\\t// Register user with referrer (if needed)\\n\\t\\tISmartHousing(smartHousingAddress).createRefIDViaProxy(\\n\\t\\t\\tdepositor,\\n\\t\\t\\treferrerId\\n\\t\\t);\\n\\n\\t\\t// Update project funding\\n\\t\\tprojects.fund(\\n\\t\\t\\tusersProjectDeposit[projectId],\\n\\t\\t\\tprojectId,\\n\\t\\t\\tdepositor,\\n\\t\\t\\tdepositPayment\\n\\t\\t);\\n\\n\\t\\temit ProjectFunded(projectId, depositor, depositPayment);\\n\\t}\\n\\n\\tfunction addProjectToEcosystem(uint256 projectId) external onlyOwner {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\n\\t\\t// TODO Add this after demo\\n\\t\\t// require(\\n\\t\\t// \\tproject.status() == ProjectStorage.Status.Successful,\\n\\t\\t// \\t\\\"Project Funding not yet successful\\\"\\n\\t\\t// );\\n\\n\\t\\tISmartHousing(smartHousingAddress).addProject(project.projectAddress);\\n\\n\\t\\tHousingProject(project.projectAddress).setTokenDetails(\\n\\t\\t\\tproject.collectedFunds,\\n\\t\\t\\tcoinbase\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Claims project tokens for a given project ID.\\n\\t * @param projectId The ID of the project to claim tokens from.\\n\\t */\\n\\tfunction claimProjectTokens(uint256 projectId) external {\\n\\t\\taddress depositor = msg.sender;\\n\\n\\t\\t// Retrieve the project and deposit amount\\n\\t\\t(ProjectStorage.Data memory project, uint256 depositAmount) = projects\\n\\t\\t\\t.takeDeposit(usersProjectDeposit[projectId], projectId, depositor);\\n\\n\\t\\tHousingSFT(project.tokenAddress).mintSFT(\\n\\t\\t\\tdepositAmount,\\n\\t\\t\\tdepositor,\\n\\t\\t\\tproject.collectedFunds\\n\\t\\t);\\n\\n\\t\\t// Mint LkSHT tokens if the project ID is 1\\n\\t\\tif (project.id == 1) {\\n\\t\\t\\tuint256 shtAmount = depositAmount.mul(SHT.ICO_FUNDS).div(\\n\\t\\t\\t\\tproject.collectedFunds\\n\\t\\t\\t);\\n\\n\\t\\t\\tlkSht.mint(shtAmount, depositor);\\n\\t\\t}\\n\\n\\t\\temit ProjectTokensClaimed(depositor, projectId, depositAmount);\\n\\t}\\n\\n\\tfunction unlockSHT(uint256 nonce) external {\\n\\t\\taddress caller = msg.sender;\\n\\n\\t\\tuint256 lkShtBal = lkSht.balanceOf(caller, nonce);\\n\\t\\trequire(lkShtBal > 0, \\\"ProjectFunding: Nothing to unlock\\\");\\n\\n\\t\\tLkSHTAttributes.Attributes memory attr = abi.decode(\\n\\t\\t\\tlkSht.getRawTokenAttributes(nonce),\\n\\t\\t\\t(LkSHTAttributes.Attributes)\\n\\t\\t);\\n\\t\\t(\\n\\t\\t\\tuint256 totalUnlockedAmount,\\n\\t\\t\\tLkSHTAttributes.Attributes memory newAttr\\n\\t\\t) = attr.unlockMatured();\\n\\n\\t\\tlkSht.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tlkShtBal.sub(totalUnlockedAmount),\\n\\t\\t\\tabi.encode(newAttr)\\n\\t\\t);\\n\\n\\t\\t// Transfer the total unlocked SHT tokens to the user's address\\n\\t\\tif (totalUnlockedAmount > 0) {\\n\\t\\t\\thousingToken.transfer(caller, totalUnlockedAmount);\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns an array of all project IDs and their associated data.\\n\\t * @return projectList An array of tuples containing project details.\\n\\t */\\n\\tfunction allProjects() public view returns (ProjectStorage.Data[] memory) {\\n\\t\\tProjectStorage.Data[] memory projectList = new ProjectStorage.Data[](\\n\\t\\t\\tprojectCount\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i = 1; i <= projectCount; i++) {\\n\\t\\t\\tprojectList[i - 1] = projects[i];\\n\\t\\t}\\n\\n\\t\\treturn projectList;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns the address of the HousingProject contract for a given project ID.\\n\\t * @param projectId The ID of the project.\\n\\t * @return projectAddress The address of the HousingProject contract.\\n\\t */\\n\\tfunction getProjectAddress(\\n\\t\\tuint256 projectId\\n\\t) external view returns (address projectAddress) {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\treturn project.projectAddress;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns the details of a project by its ID.\\n\\t * @param projectId The ID of the project.\\n\\t * @return id The project ID.\\n\\t * @return fundingGoal The funding goal of the project.\\n\\t * @return fundingDeadline The deadline for the project funding.\\n\\t * @return fundingToken The address of the ERC20 token used for funding.\\n\\t * @return projectAddress The address of the HousingProject contract.\\n\\t * @return status The funding status of the project.\\n\\t * @return collectedFunds The amount of funds collected.\\n\\t */\\n\\tfunction getProjectData(\\n\\t\\tuint256 projectId\\n\\t)\\n\\t\\texternal\\n\\t\\tview\\n\\t\\treturns (\\n\\t\\t\\tuint256 id,\\n\\t\\t\\tuint256 fundingGoal,\\n\\t\\t\\tuint256 fundingDeadline,\\n\\t\\t\\taddress fundingToken,\\n\\t\\t\\taddress projectAddress,\\n\\t\\t\\tuint8 status,\\n\\t\\t\\tuint256 collectedFunds\\n\\t\\t)\\n\\t{\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\treturn (\\n\\t\\t\\tproject.id,\\n\\t\\t\\tproject.fundingGoal,\\n\\t\\t\\tproject.fundingDeadline,\\n\\t\\t\\tproject.fundingToken,\\n\\t\\t\\tproject.projectAddress,\\n\\t\\t\\tuint8(project.status()),\\n\\t\\t\\tproject.collectedFunds\\n\\t\\t);\\n\\t}\\n}\\n\",\"keccak256\":\"0xba3518a6288e777e4b2b51d944cbc298200458d0f09f3c5b701f52547991a4e1\",\"license\":\"MIT\"}},\"version\":1}", "bytecode": "0x60803462000411576001600160401b039060409080820183811182821017620003fb5782526011815260207029b6b0b93a2437bab9b4b733aa37b5b2b760791b8183015282519083820182811086821117620003fb57845260038083526214d21560ea1b8284015260008054336001600160a01b0319821681178355929591949192906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08680a3815190878211620003e7576004978854926001948585811c95168015620003dc575b87861014620002e9578190601f9586811162000389575b508790868311600114620003265789926200031a575b5050600019828a1b1c191690851b1789555b8151908111620003075760059182548581811c91168015620002fc575b87821014620002e95790818584931162000298575b5086908583116001146200023557889262000229575b505060001982891b1c191690841b1790555b3015620001e8575083546a115eec47f6cf7e3500000094858201809211620001d55755308084529082528483208054850190558451938452927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9190a3516110529081620004178239f35b634e487b7160e01b855260118852602485fd5b866064918488519262461bcd60e51b845283015260248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152fd5b01519050388062000158565b8489528789208794509190601f1984168a5b8a82821062000281575050841162000268575b505050811b0190556200016a565b0151600019838b1b60f8161c191690553880806200025a565b8385015186558a9790950194938401930162000247565b90915083885286882085808501861c820192898610620002df575b9188918695949301871c01915b828110620002d057505062000142565b8a8155859450889101620002c0565b92508192620002b3565b634e487b7160e01b885260228b52602488fd5b90607f16906200012d565b634e487b7160e01b865260418952602486fd5b015190503880620000fe565b8c8a52888a208894509190601f1984168b5b8b82821062000372575050841162000359575b505050811b01895562000110565b0151600019838c1b60f8161c191690553880806200034b565b8385015186558b9790950194938401930162000338565b9091508b89528789208680850160051c8201928a8610620003d2575b918991869594930160051c01915b828110620003c3575050620000e8565b8b8155859450899101620003b3565b92508192620003a5565b94607f1694620000d1565b634e487b7160e01b85526041600452602485fd5b634e487b7160e01b600052604160045260246000fd5b600080fdfe6080604081815260048036101561001557600080fd5b600092833560e01c90816306fdde031461098957508063095ea7b31461095f57806318160ddd1461094057806323b872dd14610903578063313ce567146108e7578063395093511461088057806342966c68146108625780634c7360471461061457806370a08231146105dc578063715018a61461058257806379cc67901461054f5780638da5cb5b1461052757806395d89b411461040a578063a457c2d714610364578063a9059cbb14610333578063d1223fc91461020a578063dd62ed3e146101b85763f2fde38b146100e957600080fd5b346101b45760203660031901126101b457610102610abf565b9061010b610fc4565b6001600160a01b03918216928315610162575050600054826bffffffffffffffffffffffff60a01b821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8280fd5b5050346102065780600319360112610206576020916101d5610abf565b826101de610ada565b6001600160a01b03928316845260028652922091166000908152908352819020549051908152f35b5080fd5b5082903461020657602036600319011261020657610226610abf565b9261022f610fc4565b60006020825161023e81610b1a565b828152015280519161024f83610b1a565b30835260208301946a0b4a7ffb9b9d8947082f0b86523085526001602052828520548651116102fb576102858596518230610baf565b6001600160a01b031692833b156102f7578251632fd2b55f60e01b815281516001600160a01b031692810192835260209182015191909201529183908390604490829084905af19081156102ee57506102db5750f35b6102e490610af0565b6102eb5780f35b80fd5b513d84823e3d90fd5b8480fd5b506020606492519162461bcd60e51b83528201526012602482015271105b1c9958591e48191a5cdc185d18da195960721b6044820152fd5b50503461020657806003193601126102065760209061035d610353610abf565b6024359033610d49565b5160018152f35b5082346102eb57826003193601126102eb5761037e610abf565b91836024359233815260026020522060018060a01b0384166000526020528360002054908282106103b95760208561035d8585038733610baf565b608490602086519162461bcd60e51b8352820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152fd5b5091346102eb57806003193601126102eb57815191816005549260018460011c916001861695861561051d575b602096878510811461050a578899509688969785829a5291826000146104e3575050600114610487575b5050506104839291610474910385610b36565b51928284938452830190610a7f565b0390f35b9190869350600583527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db05b8284106104cb5750505082010181610474610483610461565b8054848a0186015288955087949093019281016104b2565b60ff19168782015293151560051b8601909301935084925061047491506104839050610461565b634e487b7160e01b835260228a52602483fd5b92607f1692610437565b505034610206578160031936011261020657905490516001600160a01b039091168152602090f35b505034610206573660031901126102eb5761057f61056b610abf565b6024359061057a823383610cb1565b610eb9565b80f35b83346102eb57806003193601126102eb5761059b610fc4565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5050346102065760203660031901126102065760209181906001600160a01b03610604610abf565b1681526001845220549051908152f35b50919034610206576003199060e0368301126101b45767ffffffffffffffff9184358381116102f75761064a9036908701610b58565b926024359081116102f7576106629036908701610b58565b906001600160a01b03604435818116929083900361085e57606435978289168099036107bf576084359283168093036107bf5761069d610fc4565b8551986106a98a610b1a565b888a52886020809b01528651936106bf85610b1a565b3085526a06146c4c5b31f4edf7d0f59a8b8187015230156108105786156107c3578a9b7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92588929c9a9b9c308c52600281528c8c20848d528152828d8d20558c519283523092a3853b156107bf576107878894610765986107788c519d8e9b8c9a8b99630fe744bb60e31b8b528a01906020809160018060a01b0381511684520151910152565b6101006044890152610104880190610a7f565b91868303016064870152610a7f565b91608484015260a483015260a43560c483015260c43560e483015203925af19081156102ee57506107b6575080f35b61057f90610af0565b8780fd5b836084918a519162461bcd60e51b8352820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152fd5b836084918a519162461bcd60e51b83528201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152fd5b8680fd5b8382346102065760203660031901126102065761057f903533610eb9565b5091346102eb57816003193601126102eb5761089a610abf565b338252600260209081528383206001600160a01b03831684529052828220546024358101929083106108d45760208461035d858533610baf565b634e487b7160e01b815260118552602490fd5b5050346102065781600319360112610206576020905160128152f35b5050346102065760603660031901126102065760209061035d610924610abf565b61092c610ada565b6044359161093b833383610cb1565b610d49565b5050346102065781600319360112610206576020906003549051908152f35b50503461020657806003193601126102065760209061035d61097f610abf565b6024359033610baf565b90508383346102065781600319360112610206578184549260018460011c9160018616958615610a75575b602096878510811461050a579087899a92868b999a9b529182600014610a4b5750506001146109f0575b858861048389610474848a0385610b36565b815286935091907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b828410610a335750505082010181610474610483886109de565b8054848a018601528895508794909301928101610a19565b60ff19168882015294151560051b87019094019450859350610474925061048391508990506109de565b92607f16926109b4565b919082519283825260005b848110610aab575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201610a8a565b600435906001600160a01b0382168203610ad557565b600080fd5b602435906001600160a01b0382168203610ad557565b67ffffffffffffffff8111610b0457604052565b634e487b7160e01b600052604160045260246000fd5b6040810190811067ffffffffffffffff821117610b0457604052565b90601f8019910116810190811067ffffffffffffffff821117610b0457604052565b81601f82011215610ad55780359067ffffffffffffffff8211610b045760405192610b8d601f8401601f191660200185610b36565b82845260208383010111610ad557816000926020809301838601378301015290565b6001600160a01b03908116918215610c605716918215610c105760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260028252604060002085600052825280604060002055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b9060018060a01b0380831660005260026020526040600020908216600052602052604060002054926000198403610ce9575b50505050565b808410610d0457610cfb930391610baf565b38808080610ce3565b60405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606490fd5b6001600160a01b03908116918215610e665716918215610e155760008281526001602052604081205491808310610dc157604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef95876020965260018652038282205586815220818154019055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fd5b6001600160a01b03168015610f755780600052600160205260406000205491808310610f25576020817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92600095858752600184520360408620558060035403600355604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608490fd5b6000546001600160a01b03163303610fd857565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fdfea2646970667358221220a6d519663faca84e69e27b918299ef46f9acf768b82b3a1340a082a6a0ef648964736f6c63430008180033", "deployedBytecode": "0x6080604081815260048036101561001557600080fd5b600092833560e01c90816306fdde031461098957508063095ea7b31461095f57806318160ddd1461094057806323b872dd14610903578063313ce567146108e7578063395093511461088057806342966c68146108625780634c7360471461061457806370a08231146105dc578063715018a61461058257806379cc67901461054f5780638da5cb5b1461052757806395d89b411461040a578063a457c2d714610364578063a9059cbb14610333578063d1223fc91461020a578063dd62ed3e146101b85763f2fde38b146100e957600080fd5b346101b45760203660031901126101b457610102610abf565b9061010b610fc4565b6001600160a01b03918216928315610162575050600054826bffffffffffffffffffffffff60a01b821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8280fd5b5050346102065780600319360112610206576020916101d5610abf565b826101de610ada565b6001600160a01b03928316845260028652922091166000908152908352819020549051908152f35b5080fd5b5082903461020657602036600319011261020657610226610abf565b9261022f610fc4565b60006020825161023e81610b1a565b828152015280519161024f83610b1a565b30835260208301946a0b4a7ffb9b9d8947082f0b86523085526001602052828520548651116102fb576102858596518230610baf565b6001600160a01b031692833b156102f7578251632fd2b55f60e01b815281516001600160a01b031692810192835260209182015191909201529183908390604490829084905af19081156102ee57506102db5750f35b6102e490610af0565b6102eb5780f35b80fd5b513d84823e3d90fd5b8480fd5b506020606492519162461bcd60e51b83528201526012602482015271105b1c9958591e48191a5cdc185d18da195960721b6044820152fd5b50503461020657806003193601126102065760209061035d610353610abf565b6024359033610d49565b5160018152f35b5082346102eb57826003193601126102eb5761037e610abf565b91836024359233815260026020522060018060a01b0384166000526020528360002054908282106103b95760208561035d8585038733610baf565b608490602086519162461bcd60e51b8352820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152fd5b5091346102eb57806003193601126102eb57815191816005549260018460011c916001861695861561051d575b602096878510811461050a578899509688969785829a5291826000146104e3575050600114610487575b5050506104839291610474910385610b36565b51928284938452830190610a7f565b0390f35b9190869350600583527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db05b8284106104cb5750505082010181610474610483610461565b8054848a0186015288955087949093019281016104b2565b60ff19168782015293151560051b8601909301935084925061047491506104839050610461565b634e487b7160e01b835260228a52602483fd5b92607f1692610437565b505034610206578160031936011261020657905490516001600160a01b039091168152602090f35b505034610206573660031901126102eb5761057f61056b610abf565b6024359061057a823383610cb1565b610eb9565b80f35b83346102eb57806003193601126102eb5761059b610fc4565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5050346102065760203660031901126102065760209181906001600160a01b03610604610abf565b1681526001845220549051908152f35b50919034610206576003199060e0368301126101b45767ffffffffffffffff9184358381116102f75761064a9036908701610b58565b926024359081116102f7576106629036908701610b58565b906001600160a01b03604435818116929083900361085e57606435978289168099036107bf576084359283168093036107bf5761069d610fc4565b8551986106a98a610b1a565b888a52886020809b01528651936106bf85610b1a565b3085526a06146c4c5b31f4edf7d0f59a8b8187015230156108105786156107c3578a9b7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92588929c9a9b9c308c52600281528c8c20848d528152828d8d20558c519283523092a3853b156107bf576107878894610765986107788c519d8e9b8c9a8b99630fe744bb60e31b8b528a01906020809160018060a01b0381511684520151910152565b6101006044890152610104880190610a7f565b91868303016064870152610a7f565b91608484015260a483015260a43560c483015260c43560e483015203925af19081156102ee57506107b6575080f35b61057f90610af0565b8780fd5b836084918a519162461bcd60e51b8352820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152fd5b836084918a519162461bcd60e51b83528201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152fd5b8680fd5b8382346102065760203660031901126102065761057f903533610eb9565b5091346102eb57816003193601126102eb5761089a610abf565b338252600260209081528383206001600160a01b03831684529052828220546024358101929083106108d45760208461035d858533610baf565b634e487b7160e01b815260118552602490fd5b5050346102065781600319360112610206576020905160128152f35b5050346102065760603660031901126102065760209061035d610924610abf565b61092c610ada565b6044359161093b833383610cb1565b610d49565b5050346102065781600319360112610206576020906003549051908152f35b50503461020657806003193601126102065760209061035d61097f610abf565b6024359033610baf565b90508383346102065781600319360112610206578184549260018460011c9160018616958615610a75575b602096878510811461050a579087899a92868b999a9b529182600014610a4b5750506001146109f0575b858861048389610474848a0385610b36565b815286935091907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b828410610a335750505082010181610474610483886109de565b8054848a018601528895508794909301928101610a19565b60ff19168882015294151560051b87019094019450859350610474925061048391508990506109de565b92607f16926109b4565b919082519283825260005b848110610aab575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201610a8a565b600435906001600160a01b0382168203610ad557565b600080fd5b602435906001600160a01b0382168203610ad557565b67ffffffffffffffff8111610b0457604052565b634e487b7160e01b600052604160045260246000fd5b6040810190811067ffffffffffffffff821117610b0457604052565b90601f8019910116810190811067ffffffffffffffff821117610b0457604052565b81601f82011215610ad55780359067ffffffffffffffff8211610b045760405192610b8d601f8401601f191660200185610b36565b82845260208383010111610ad557816000926020809301838601378301015290565b6001600160a01b03908116918215610c605716918215610c105760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260028252604060002085600052825280604060002055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b9060018060a01b0380831660005260026020526040600020908216600052602052604060002054926000198403610ce9575b50505050565b808410610d0457610cfb930391610baf565b38808080610ce3565b60405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606490fd5b6001600160a01b03908116918215610e665716918215610e155760008281526001602052604081205491808310610dc157604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef95876020965260018652038282205586815220818154019055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fd5b6001600160a01b03168015610f755780600052600160205260406000205491808310610f25576020817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92600095858752600184520360408620558060035403600355604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608490fd5b6000546001600160a01b03163303610fd857565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fdfea2646970667358221220a6d519663faca84e69e27b918299ef46f9acf768b82b3a1340a082a6a0ef648964736f6c63430008180033", "devdoc": { diff --git a/packages/backend/deployments/opbnb/HousingProject.json b/packages/backend/deployments/opbnb/HousingProject.json index ab89975..4abd1ab 100644 --- a/packages/backend/deployments/opbnb/HousingProject.json +++ b/packages/backend/deployments/opbnb/HousingProject.json @@ -349,7 +349,7 @@ ], "numDeployments": 1, "solcInputHash": "a3834a2f81eba945e2e32ba65dfaced7", - "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"smartHousingAddr\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountRaised\",\"type\":\"uint256\"}],\"name\":\"TokenIssued\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"claimRentReward\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"rewardsPerShare\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originalOwner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenWeight\",\"type\":\"uint256\"}],\"internalType\":\"struct HousingAttributes\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"userValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"referrerValue\",\"type\":\"uint256\"}],\"internalType\":\"struct rewardshares\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"facilityManagementFunds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getMaxSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"projectSFT\",\"outputs\":[{\"internalType\":\"contract HousingSFT\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ERC20TokenPayment\",\"name\":\"rentPayment\",\"type\":\"tuple\"}],\"name\":\"receiveRent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"rewardsPerShare\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originalOwner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenWeight\",\"type\":\"uint256\"}],\"internalType\":\"struct HousingAttributes\",\"name\":\"attr\",\"type\":\"tuple\"}],\"name\":\"rentClaimable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardPerShare\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardsReserve\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amountRaised\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"housingTokenAddr\",\"type\":\"address\"}],\"name\":\"setTokenDetails\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract inherits from RentsModule and HousingSFT.\",\"kind\":\"dev\",\"methods\":{\"claimRentReward(uint256)\":{\"returns\":{\"_0\":\"The updated HousingAttributes.\"}},\"constructor\":{\"params\":{\"smartHousingAddr\":\"The address of the main SmartHousing contract.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"receiveRent((address,uint256))\":{\"params\":{\"rentPayment\":\"The details of the rent payment.\"}},\"renounceOwnership()\":{\"details\":\"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.\"},\"rentClaimable((uint256,address,uint256))\":{\"params\":{\"attr\":\"The attributes of the token.\"},\"returns\":{\"_0\":\"The amount of rent claimable.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"HousingProject Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimRentReward(uint256)\":{\"notice\":\"Claims rent rewards for a given token.\"},\"constructor\":{\"notice\":\"Initializes the HousingProject contract.\"},\"receiveRent((address,uint256))\":{\"notice\":\"Receives rent payments and distributes rewards.\"},\"rentClaimable((uint256,address,uint256))\":{\"notice\":\"Computes the amount of rent claimable for a given token.\"}},\"notice\":\"Represents a unique real estate project within the SmartHousing ecosystem.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/housing-project/HousingProject.sol\":\"HousingProject\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../token/ERC20/IERC20.sol\\\";\\n\",\"keccak256\":\"0x6ebf1944ab804b8660eb6fc52f9fe84588cee01c2566a69023e59497e7d27f45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0xd917747dc87f189c6779b894f367a028f9dca4be930283cccec8f312966af820\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n // decrementing then incrementing.\\n _balances[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n unchecked {\\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n _balances[account] += amount;\\n }\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n // Overflow not possible: amount <= accountBalance <= totalSupply.\\n _totalSupply -= amount;\\n }\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x4ffc0547c02ad22925310c585c0f166f8759e2648a09e9b489100c42f15dd98d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../ERC20.sol\\\";\\nimport \\\"../../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\\n * tokens and those that they have an allowance for, in a way that can be\\n * recognized off-chain (via event analysis).\\n */\\nabstract contract ERC20Burnable is Context, ERC20 {\\n /**\\n * @dev Destroys `amount` tokens from the caller.\\n *\\n * See {ERC20-_burn}.\\n */\\n function burn(uint256 amount) public virtual {\\n _burn(_msgSender(), amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, deducting from the caller's\\n * allowance.\\n *\\n * See {ERC20-_burn} and {ERC20-allowance}.\\n *\\n * Requirements:\\n *\\n * - the caller must have allowance for ``accounts``'s tokens of at least\\n * `amount`.\\n */\\n function burnFrom(address account, uint256 amount) public virtual {\\n _spendAllowance(account, _msgSender(), amount);\\n _burn(account, amount);\\n }\\n}\\n\",\"keccak256\":\"0x0d19410453cda55960a818e02bd7c18952a5c8fe7a3036e81f0d599f34487a7b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf96f969e24029d43d0df89e59d365f277021dac62b48e1c1e3ebe0acdd7f1ca1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Counters.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Counters\\n * @author Matt Condon (@shrugs)\\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\\n *\\n * Include with `using Counters for Counters.Counter;`\\n */\\nlibrary Counters {\\n struct Counter {\\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\\n // this feature: see https://github.com/ethereum/solidity/issues/4637\\n uint256 _value; // default: 0\\n }\\n\\n function current(Counter storage counter) internal view returns (uint256) {\\n return counter._value;\\n }\\n\\n function increment(Counter storage counter) internal {\\n unchecked {\\n counter._value += 1;\\n }\\n }\\n\\n function decrement(Counter storage counter) internal {\\n uint256 value = counter._value;\\n require(value > 0, \\\"Counter: decrement overflow\\\");\\n unchecked {\\n counter._value = value - 1;\\n }\\n }\\n\\n function reset(Counter storage counter) internal {\\n counter._value = 0;\\n }\\n}\\n\",\"keccak256\":\"0xf0018c2440fbe238dd3a8732fa8e17a0f9dce84d31451dc8a32f6d62b349c9f1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * ```\\n * contract Example {\\n * // Add the library methods\\n * using EnumerableSet for EnumerableSet.AddressSet;\\n *\\n * // Declare a set state variable\\n * EnumerableSet.AddressSet private mySet;\\n * }\\n * ```\\n *\\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\\n * and `uint256` (`UintSet`) are supported.\\n *\\n * [WARNING]\\n * ====\\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\\n * unusable.\\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\\n *\\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\\n * array of EnumerableSet.\\n * ====\\n */\\nlibrary EnumerableSet {\\n // To implement this library for multiple types with as little code\\n // repetition as possible, we write it in terms of a generic Set type with\\n // bytes32 values.\\n // The Set implementation uses private functions, and user-facing\\n // implementations (such as AddressSet) are just wrappers around the\\n // underlying Set.\\n // This means that we can only create new EnumerableSets for types that fit\\n // in bytes32.\\n\\n struct Set {\\n // Storage of set values\\n bytes32[] _values;\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(bytes32 => uint256) _indexes;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function _add(Set storage set, bytes32 value) private returns (bool) {\\n if (!_contains(set, value)) {\\n set._values.push(value);\\n // The value is stored at length-1, but we add 1 to all indexes\\n // and use 0 as a sentinel value\\n set._indexes[value] = set._values.length;\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function _remove(Set storage set, bytes32 value) private returns (bool) {\\n // We read and store the value's index to prevent multiple reads from the same storage slot\\n uint256 valueIndex = set._indexes[value];\\n\\n if (valueIndex != 0) {\\n // Equivalent to contains(set, value)\\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\\n // the array, and then remove the last element (sometimes called as 'swap and pop').\\n // This modifies the order of the array, as noted in {at}.\\n\\n uint256 toDeleteIndex = valueIndex - 1;\\n uint256 lastIndex = set._values.length - 1;\\n\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set._values[lastIndex];\\n\\n // Move the last value to the index where the value to delete is\\n set._values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\\n }\\n\\n // Delete the slot where the moved value was stored\\n set._values.pop();\\n\\n // Delete the index for the deleted slot\\n delete set._indexes[value];\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\\n return set._indexes[value] != 0;\\n }\\n\\n /**\\n * @dev Returns the number of values on the set. O(1).\\n */\\n function _length(Set storage set) private view returns (uint256) {\\n return set._values.length;\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\\n return set._values[index];\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function _values(Set storage set) private view returns (bytes32[] memory) {\\n return set._values;\\n }\\n\\n // Bytes32Set\\n\\n struct Bytes32Set {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _add(set._inner, value);\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _remove(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return _contains(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return _at(set._inner, index);\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n bytes32[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // AddressSet\\n\\n struct AddressSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n return _add(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n return _remove(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\\n return address(uint160(uint256(_at(set._inner, index))));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(AddressSet storage set) internal view returns (address[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n address[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // UintSet\\n\\n struct UintSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(UintSet storage set, uint256 value) internal returns (bool) {\\n return _add(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\\n return _remove(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(UintSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\\n return uint256(_at(set._inner, index));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(UintSet storage set) internal view returns (uint256[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n uint256[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xc3ff3f5c4584e1d9a483ad7ced51ab64523201f4e3d3c65293e4ca8aeb77a961\",\"license\":\"MIT\"},\"contracts/housing-project/CallsSmartHousing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nabstract contract CallsSmartHousing {\\n\\t/// @notice The address of the main SmartHousing contract.\\n\\taddress immutable smartHousingAddr;\\n\\n\\tconstructor(address smartHousingAddr_) {\\n\\t\\tsmartHousingAddr = smartHousingAddr_;\\n\\t}\\n\\n\\t/// @dev Gets the referrer address for a given original owner.\\n\\t/// @param userAddr The original owner of the token.\\n\\t/// @return The referrer address.\\n\\tfunction getReferrer(\\n\\t\\taddress userAddr\\n\\t) internal view returns (uint, address) {\\n\\t\\treturn IUserModule(smartHousingAddr).getReferrer(userAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0xd2ded3c751d669f079d12e7381e586b747cb9ae1b6d9bd4dbd87fc9db3b0371c\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingProject.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"./RentsModule.sol\\\";\\n\\n/// @title HousingProject Contract\\n/// @notice Represents a unique real estate project within the SmartHousing ecosystem.\\n/// @dev This contract inherits from RentsModule and HousingSFT.\\ncontract HousingProject is RentsModule, Ownable {\\n\\t/// @notice Initializes the HousingProject contract.\\n\\t/// @param smartHousingAddr The address of the main SmartHousing contract.\\n\\tconstructor(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) CallsSmartHousing(smartHousingAddr) {\\n\\t\\tprojectSFT = new HousingSFT(name, symbol);\\n\\t}\\n\\n\\tevent TokenIssued(address tokenAddress, string name, uint256 amountRaised);\\n\\n\\tfunction setTokenDetails(\\n\\t\\tuint256 amountRaised,\\n\\t\\taddress housingTokenAddr\\n\\t) external onlyOwner {\\n\\t\\trequire(amountRaised == 0, \\\"Token details set already\\\");\\n\\n\\t\\thousingToken = ERC20Burnable(housingTokenAddr);\\n\\n\\t\\tprojectSFT.setAmountRaised(amountRaised);\\n\\t\\tstring memory name = projectSFT.name();\\n\\n\\t\\temit TokenIssued(address(projectSFT), name, amountRaised);\\n\\t}\\n\\n\\tfunction getMaxSupply() public view returns (uint256) {\\n\\t\\treturn projectSFT.getMaxSupply();\\n\\t}\\n}\\n\",\"keccak256\":\"0x159e6b338c47a2dacbec1254f582826b5584c338919e6e6908aba986f9a98350\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingSFT.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\n\\nimport \\\"../modules/SFT.sol\\\";\\n\\nstruct HousingAttributes {\\n\\tuint256 rewardsPerShare;\\n\\taddress originalOwner;\\n\\tuint256 tokenWeight;\\n}\\n\\n/// @title Housing SFT\\n/// @notice This contract represents a semi-fungible token (SFT) for housing projects.\\n/// @dev This contract will be inherited by the HousingProject contract.\\ncontract HousingSFT is SFT {\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct HousingSFTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tHousingAttributes attributes;\\n\\t}\\n\\n\\t// FIXME this value should be unique to each contract, should depend on\\n\\t// the total amount expected to raise as it determines the amount of SFTs to\\n\\t// be minted for investors\\n\\tuint256 public constant MAX_SUPPLY = 1_000_000;\\n\\n\\t/// @notice The amount of fungible tokens collected from investors to finance the development of this housing project.\\n\\tuint256 public amountRaised;\\n\\n\\t/// @notice The current amount out of the `MAX_SUPPLY` of tokens minted.\\n\\tuint256 public totalSupply;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tfunction setAmountRaised(uint256 amountRaised_) external onlyOwner {\\n\\t\\tamountRaised = amountRaised_;\\n\\t}\\n\\n\\tmodifier canMint() {\\n\\t\\taddress sftOwner = owner();\\n\\n\\t\\trequire(\\n\\t\\t\\tOwnable(sftOwner).owner() == _msgSender(),\\n\\t\\t\\t\\\"not allowed to mint\\\"\\n\\t\\t);\\n\\n\\t\\t_;\\n\\t}\\n\\n\\t/// @notice Mints SFT tokens for a depositor based on the amount of deposit.\\n\\t/// @param depositAmt The amount of fungible token deposited.\\n\\t/// @param depositor The address of the depositor.\\n\\tfunction mintSFT(\\n\\t\\tuint256 depositAmt,\\n\\t\\taddress depositor,\\n\\t\\tuint256 amount_raised\\n\\t) external canMint returns (uint256) {\\n\\t\\t// TODO remove after demo due to not beign able to move blocks in public networks\\n\\t\\t{\\n\\t\\t\\tamountRaised = amount_raised;\\n\\t\\t}\\n\\n\\t\\tuint256 totalDeposits = amountRaised;\\n\\t\\tuint256 maxShares = MAX_SUPPLY;\\n\\n\\t\\trequire(totalDeposits > 0, \\\"HousingSFT: No deposits recorded\\\");\\n\\n\\t\\tuint256 mintShare = (depositAmt * maxShares) / totalDeposits;\\n\\t\\trequire(mintShare > 0, \\\"HousingSFT: Computed token shares is invalid\\\");\\n\\n\\t\\ttotalSupply += mintShare;\\n\\t\\trequire(totalSupply <= MAX_SUPPLY, \\\"HousingSFT: Max supply exceeded\\\");\\n\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tHousingAttributes({\\n\\t\\t\\t\\trewardsPerShare: 0, // Should be 0 since they have never claimed any rent rewards\\n\\t\\t\\t\\toriginalOwner: depositor,\\n\\t\\t\\t\\ttokenWeight: mintShare\\n\\t\\t\\t})\\n\\t\\t);\\n\\n\\t\\treturn _mint(depositor, mintShare, attributes, \\\"\\\");\\n\\t}\\n\\n\\t/// @notice Checks if an address owns this HousingSFT and returns the attributes.\\n\\t/// @param owner The address to check the balance of.\\n\\t/// @return `HousingAttributes` if the owner has a positive balance of the token, panics otherwise.\\n\\tfunction getUserSFT(\\n\\t\\taddress owner,\\n\\t\\tuint256 nonce\\n\\t) public view returns (HousingAttributes memory) {\\n\\t\\trequire(\\n\\t\\t\\thasSFT(owner, nonce),\\n\\t\\t\\t\\\"HouisingSFT: No tokens found for user at nonce\\\"\\n\\t\\t);\\n\\n\\t\\treturn abi.decode(getRawTokenAttributes(nonce), (HousingAttributes));\\n\\t}\\n\\n\\tfunction getMaxSupply() public pure returns (uint256) {\\n\\t\\treturn MAX_SUPPLY;\\n\\t}\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (HousingSFTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tHousingSFTBalance[] memory balance = new HousingSFTBalance[](\\n\\t\\t\\t_sftBals.length\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = HousingSFTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(_sftBal.attributes, (HousingAttributes))\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\tfunction tokenDetails()\\n\\t\\tpublic\\n\\t\\tview\\n\\t\\treturns (string memory, string memory, uint256)\\n\\t{\\n\\t\\treturn (name(), symbol(), getMaxSupply());\\n\\t}\\n}\\n\",\"keccak256\":\"0x8fbbe8d670bc777eed8587d0a8b11acf1d7b40b9ae631fee4abc929f4275c160\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/RentsModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\\\";\\n\\nimport \\\"./HousingSFT.sol\\\";\\nimport \\\"./RewardSharing.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"./CallsSmartHousing.sol\\\";\\n\\n/// @title Rents Module\\n/// @notice Handles rent payments, reward calculations, and distribution for Housing projects.\\n/// @dev This abstract contract should be inherited by the HousingProject contract.\\nabstract contract RentsModule is CallsSmartHousing {\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\tusing RewardShares for rewardshares;\\n\\n\\tuint256 public rewardPerShare;\\n\\tuint256 public rewardsReserve;\\n\\tuint256 public facilityManagementFunds;\\n\\n\\tERC20Burnable housingToken;\\n\\tHousingSFT public projectSFT;\\n\\n\\t/// @notice Receives rent payments and distributes rewards.\\n\\t/// @param rentPayment The details of the rent payment.\\n\\tfunction receiveRent(ERC20TokenPayment calldata rentPayment) external {\\n\\t\\t// TODO set the appropriate rent per Project\\n\\t\\trequire(\\n\\t\\t\\trentPayment.amount > 0,\\n\\t\\t\\t\\\"RentsModule: Insufficient rent amount\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\trentPayment.token == housingToken,\\n\\t\\t\\t\\\"RentsModule: Invalid rent payment token\\\"\\n\\t\\t);\\n\\t\\trentPayment.receiveERC20();\\n\\n\\t\\tuint256 rentReward = (rentPayment.amount * 75) / 100;\\n\\t\\tuint256 ecosystemReward = (rentPayment.amount * 18) / 100;\\n\\t\\tuint256 facilityReward = (rentPayment.amount * 7) / 100;\\n\\n\\t\\tuint256 allShares = projectSFT.getMaxSupply();\\n\\t\\tuint256 rpsIncrease = (rentReward * DIVISION_SAFETY_CONST) / allShares;\\n\\n\\t\\trewardPerShare += rpsIncrease;\\n\\t\\trewardsReserve += rentReward;\\n\\t\\tfacilityManagementFunds += facilityReward;\\n\\n\\t\\thousingToken.burn(ecosystemReward);\\n\\t\\tISmartHousing(smartHousingAddr).addProjectRent(rentPayment.amount);\\n\\t}\\n\\n\\t/// @notice Claims rent rewards for a given token.\\n\\t/// @return The updated HousingAttributes.\\n\\tfunction claimRentReward(\\n\\t\\tuint256 nonce\\n\\t) external returns (HousingAttributes memory, rewardshares memory) {\\n\\t\\taddress caller = msg.sender;\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tHousingAttributes memory attr = projectSFT.getUserSFT(caller, nonce);\\n\\t\\trewardshares memory rewardShares = computeRewardShares(attr);\\n\\t\\tuint256 totalReward = rewardShares.total();\\n\\n\\t\\tif (totalReward == 0) {\\n\\t\\t\\t// Fail silently\\n\\t\\t\\treturn (attr, rewardShares);\\n\\t\\t}\\n\\n\\t\\trequire(rewardsReserve >= totalReward, \\\"Computed rewards too large\\\");\\n\\n\\t\\trewardsReserve -= totalReward;\\n\\n\\t\\t// We use original owner since we are certain they are registered\\n\\t\\t(, address referrer) = getReferrer(attr.originalOwner);\\n\\t\\tif (rewardShares.referrerValue > 0) {\\n\\t\\t\\tif (referrer != address(0)) {\\n\\t\\t\\t\\thousingToken.transfer(referrer, rewardShares.referrerValue); // Send to referrer\\n\\t\\t\\t} else {\\n\\t\\t\\t\\thousingToken.burn(rewardShares.referrerValue); // Burn to add to ecosystem reward\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tattr.rewardsPerShare = currentRPS;\\n\\n\\t\\tprojectSFT.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tprojectSFT.balanceOf(caller, nonce),\\n\\t\\t\\tabi.encode(attr)\\n\\t\\t);\\n\\n\\t\\thousingToken.transfer(caller, rewardShares.userValue); // Send to user\\n\\n\\t\\treturn (attr, rewardShares);\\n\\t}\\n\\n\\t/// @notice Computes the amount of rent claimable for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The amount of rent claimable.\\n\\tfunction rentClaimable(\\n\\t\\tHousingAttributes memory attr\\n\\t) public view returns (uint256) {\\n\\t\\treturn computeRewardShares(attr).userValue;\\n\\t}\\n\\n\\t/// @dev Computes the reward shares for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The computed RewardShares.\\n\\tfunction computeRewardShares(\\n\\t\\tHousingAttributes memory attr\\n\\t) internal view returns (rewardshares memory) {\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tif (currentRPS == 0 || attr.rewardsPerShare >= currentRPS) {\\n\\t\\t\\treturn rewardshares({ userValue: 0, referrerValue: 0 });\\n\\t\\t}\\n\\n\\t\\tuint256 reward = computeReward(attr, currentRPS);\\n\\n\\t\\treturn splitReward(reward);\\n\\t}\\n}\\n\",\"keccak256\":\"0xe97c64b7d4f5a945493aa8492c4412248f60ec1e6e8cd74e3f805e40cc672768\",\"license\":\"MIT\"},\"contracts/housing-project/RewardSharing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"./HousingSFT.sol\\\";\\n\\nuint256 constant DIVISION_SAFETY_CONST = 1_000_000_000_000_000_000;\\n\\nstruct rewardshares {\\n\\tuint256 userValue;\\n\\tuint256 referrerValue;\\n}\\n\\nlibrary RewardShares {\\n\\tfunction total(rewardshares memory self) internal pure returns (uint256) {\\n\\t\\treturn self.userValue + self.referrerValue;\\n\\t}\\n}\\n\\nfunction splitReward(uint256 reward) pure returns (rewardshares memory) {\\n\\tuint256 referrerValue = (reward * 6_66) / 100_00; // would amount to approximately 5% of grand total\\n\\tuint256 userValue = reward - referrerValue;\\n\\n\\treturn rewardshares(userValue, referrerValue);\\n}\\n\\nfunction computeReward(\\n\\tHousingAttributes memory attr,\\n\\tuint256 contractRPS\\n) pure returns (uint256) {\\n\\tif (contractRPS <= attr.rewardsPerShare) {\\n\\t\\treturn 0;\\n\\t}\\n\\n\\treturn\\n\\t\\t((contractRPS - attr.rewardsPerShare) * attr.tokenWeight) /\\n\\t\\tDIVISION_SAFETY_CONST;\\n}\\n\",\"keccak256\":\"0x9f07d2b3ee49b91e12ad7ce9ba248ab7dd30bc2efc4238a594e681d3f0348e54\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/lib/TokenPayments.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/interfaces/IERC20.sol\\\";\\nimport { SFT } from \\\"../modules/SFT.sol\\\";\\n\\nstruct ERC20TokenPayment {\\n\\tIERC20 token;\\n\\tuint256 amount;\\n}\\n\\nstruct TokenPayment {\\n\\taddress token;\\n\\tuint256 amount;\\n\\tuint256 nonce;\\n}\\n\\nlibrary TokenPayments {\\n\\tfunction accept(ERC20TokenPayment calldata self) internal {\\n\\t\\tTokenPayments.receiveERC20(self, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(ERC20TokenPayment calldata payment) internal {\\n\\t\\tTokenPayments.receiveERC20(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(\\n\\t\\tERC20TokenPayment calldata payment,\\n\\t\\taddress from\\n\\t) internal {\\n\\t\\tpayment.token.transferFrom(from, address(this), payment.amount);\\n\\t}\\n\\n\\t// Receives both Native, SFTs and ERC20; ERC20 have nonce as 0, Native coins have address 0 as token value\\n\\tfunction receiveToken(TokenPayment memory payment) internal {\\n\\t\\treceiveToken(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveToken(TokenPayment memory payment, address from) internal {\\n\\t\\tif (payment.token == address(0)) {\\n\\t\\t\\t// Native payment\\n\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tpayment.amount == msg.value,\\n\\t\\t\\t\\t\\\"expected payment amount must equal sent amount\\\"\\n\\t\\t\\t);\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tfrom == msg.sender,\\n\\t\\t\\t\\t\\\"can receive native payment only from caller\\\"\\n\\t\\t\\t);\\n\\t\\t\\t\\n\\t\\t\\t// Nothing to do again since the VM will handle balance movements\\n\\t\\t} else if (payment.nonce == 0) {\\n\\t\\t\\tIERC20(payment.token).transferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.amount\\n\\t\\t\\t);\\n\\t\\t} else {\\n\\t\\t\\tSFT(payment.token).safeTransferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.nonce,\\n\\t\\t\\t\\tpayment.amount,\\n\\t\\t\\t\\t\\\"\\\"\\n\\t\\t\\t);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x06bd73e8da1bde18d9aaf6d4b6a1bdec6e0718af6354fe2d7ce87251d6fd1ac5\",\"license\":\"MIT\"},\"contracts/main/Interface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"../lib/TokenPayments.sol\\\";\\n\\ninterface ISmartHousing {\\n\\tfunction addProjectRent(uint256 amount) external;\\n\\n\\tfunction createRefIDViaProxy(\\n\\t\\taddress userAddr,\\n\\t\\tuint256 referrerId\\n\\t) external returns (uint256);\\n\\n\\tfunction addProject(address projectAddress) external;\\n\\n\\tfunction setUpSHT(ERC20TokenPayment calldata payment) external;\\n}\\n\\ninterface IUserModule {\\n\\tfunction getReferrer(address user) external view returns (uint, address);\\n}\\n\",\"keccak256\":\"0x066719eed5c5ff2394d78ce027aada5a8555713c9f4abf8b5135975981ba9989\",\"license\":\"MIT\"},\"contracts/modules/SFT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Counters.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n// TODO I think we should create a standard of this\\nabstract contract SFT is ERC1155, Ownable {\\n\\tusing Counters for Counters.Counter;\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct SftBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tbytes attributes;\\n\\t}\\n\\n\\tCounters.Counter private _nonceCounter;\\n\\tstring private _name;\\n\\tstring private _symbol;\\n\\n\\t// Mapping from nonce to token attributes as bytes\\n\\tmapping(uint256 => bytes) private _tokenAttributes;\\n\\n\\t// Mapping from address to list of owned token nonces\\n\\tmapping(address => EnumerableSet.UintSet) private _addressToNonces;\\n\\n\\tconstructor(string memory name_, string memory symbol_) ERC1155(\\\"\\\") {\\n\\t\\t_name = name_;\\n\\t\\t_symbol = symbol_;\\n\\t}\\n\\n\\t// Private function to mint new tokens\\n\\tfunction _mint(\\n\\t\\taddress to,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attributes,\\n\\t\\tbytes memory data\\n\\t) internal returns (uint256) {\\n\\t\\t_nonceCounter.increment();\\n\\t\\tuint256 nonce = _nonceCounter.current();\\n\\n\\t\\t// Store the attributes\\n\\t\\t_tokenAttributes[nonce] = attributes;\\n\\n\\t\\t// Mint the token with the nonce as its ID\\n\\t\\tsuper._mint(to, nonce, amount, data);\\n\\n\\t\\t// Track the nonce for the address\\n\\t\\t_addressToNonces[to].add(nonce);\\n\\n\\t\\treturn nonce;\\n\\t}\\n\\n\\tfunction name() public view returns (string memory) {\\n\\t\\treturn _name;\\n\\t}\\n\\n\\tfunction symbol() public view returns (string memory) {\\n\\t\\treturn _symbol;\\n\\t}\\n\\n\\tfunction tokenInfo() public view returns (string memory, string memory) {\\n\\t\\treturn (_name, _symbol);\\n\\t}\\n\\n\\t// Function to get token attributes by nonce\\n\\tfunction getRawTokenAttributes(\\n\\t\\tuint256 nonce\\n\\t) public view returns (bytes memory) {\\n\\t\\treturn _tokenAttributes[nonce];\\n\\t}\\n\\n\\t// Function to get list of nonces owned by an address\\n\\tfunction getNonces(address owner) public view returns (uint256[] memory) {\\n\\t\\treturn _addressToNonces[owner].values();\\n\\t}\\n\\n\\tfunction hasSFT(address owner, uint256 nonce) public view returns (bool) {\\n\\t\\treturn _addressToNonces[owner].contains(nonce);\\n\\t}\\n\\n\\t/// Burns all the NFT balance of user at nonce, creates new with balance and attributes\\n\\tfunction update(\\n\\t\\taddress user,\\n\\t\\tuint256 nonce,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attr\\n\\t) external onlyOwner {\\n\\t\\t_burn(user, nonce, amount);\\n\\t\\t_mint(user, amount, attr, \\\"\\\");\\n\\t}\\n\\n\\tfunction _sftBalance(\\n\\t\\taddress user\\n\\t) internal view returns (SftBalance[] memory) {\\n\\t\\tuint256[] memory nonces = getNonces(user);\\n\\t\\tSftBalance[] memory balance = new SftBalance[](nonces.length);\\n\\n\\t\\tfor (uint256 i; i < nonces.length; i++) {\\n\\t\\t\\tuint256 nonce = nonces[i];\\n\\t\\t\\tbytes memory attributes = _tokenAttributes[nonce];\\n\\t\\t\\tuint256 amount = balanceOf(user, nonce);\\n\\n\\t\\t\\tbalance[i] = SftBalance({\\n\\t\\t\\t\\tnonce: nonce,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tattributes: attributes\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t// Override _beforeTokenTransfer to handle address-to-nonce mapping\\n\\tfunction _beforeTokenTransfer(\\n\\t\\taddress operator,\\n\\t\\taddress from,\\n\\t\\taddress to,\\n\\t\\tuint256[] memory ids,\\n\\t\\tuint256[] memory amounts,\\n\\t\\tbytes memory data\\n\\t) internal virtual override {\\n\\t\\tsuper._beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[from].remove(ids[i]);\\n\\t\\t}\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[to].add(ids[i]);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x8098c36137bbb9a342d16fd64f7d57c03a77841a872dd44641b9db1623a699aa\",\"license\":\"MIT\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"smartHousingAddr\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountRaised\",\"type\":\"uint256\"}],\"name\":\"TokenIssued\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"claimRentReward\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"rewardsPerShare\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originalOwner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenWeight\",\"type\":\"uint256\"}],\"internalType\":\"struct HousingAttributes\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"userValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"referrerValue\",\"type\":\"uint256\"}],\"internalType\":\"struct rewardshares\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"facilityManagementFunds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getMaxSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"projectSFT\",\"outputs\":[{\"internalType\":\"contract HousingSFT\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ERC20TokenPayment\",\"name\":\"rentPayment\",\"type\":\"tuple\"}],\"name\":\"receiveRent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"rewardsPerShare\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originalOwner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenWeight\",\"type\":\"uint256\"}],\"internalType\":\"struct HousingAttributes\",\"name\":\"attr\",\"type\":\"tuple\"}],\"name\":\"rentClaimable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardPerShare\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardsReserve\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amountRaised\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"housingTokenAddr\",\"type\":\"address\"}],\"name\":\"setTokenDetails\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract inherits from RentsModule and HousingSFT.\",\"kind\":\"dev\",\"methods\":{\"claimRentReward(uint256)\":{\"returns\":{\"_0\":\"The updated HousingAttributes.\"}},\"constructor\":{\"params\":{\"smartHousingAddr\":\"The address of the main SmartHousing contract.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"receiveRent((address,uint256))\":{\"params\":{\"rentPayment\":\"The details of the rent payment.\"}},\"renounceOwnership()\":{\"details\":\"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.\"},\"rentClaimable((uint256,address,uint256))\":{\"params\":{\"attr\":\"The attributes of the token.\"},\"returns\":{\"_0\":\"The amount of rent claimable.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"HousingProject Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimRentReward(uint256)\":{\"notice\":\"Claims rent rewards for a given token.\"},\"constructor\":{\"notice\":\"Initializes the HousingProject contract.\"},\"receiveRent((address,uint256))\":{\"notice\":\"Receives rent payments and distributes rewards.\"},\"rentClaimable((uint256,address,uint256))\":{\"notice\":\"Computes the amount of rent claimable for a given token.\"}},\"notice\":\"Represents a unique real estate project within the SmartHousing ecosystem.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/housing-project/HousingProject.sol\":\"HousingProject\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../token/ERC20/IERC20.sol\\\";\\n\",\"keccak256\":\"0x6ebf1944ab804b8660eb6fc52f9fe84588cee01c2566a69023e59497e7d27f45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0xd917747dc87f189c6779b894f367a028f9dca4be930283cccec8f312966af820\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n // decrementing then incrementing.\\n _balances[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n unchecked {\\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n _balances[account] += amount;\\n }\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n // Overflow not possible: amount <= accountBalance <= totalSupply.\\n _totalSupply -= amount;\\n }\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x4ffc0547c02ad22925310c585c0f166f8759e2648a09e9b489100c42f15dd98d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../ERC20.sol\\\";\\nimport \\\"../../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\\n * tokens and those that they have an allowance for, in a way that can be\\n * recognized off-chain (via event analysis).\\n */\\nabstract contract ERC20Burnable is Context, ERC20 {\\n /**\\n * @dev Destroys `amount` tokens from the caller.\\n *\\n * See {ERC20-_burn}.\\n */\\n function burn(uint256 amount) public virtual {\\n _burn(_msgSender(), amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, deducting from the caller's\\n * allowance.\\n *\\n * See {ERC20-_burn} and {ERC20-allowance}.\\n *\\n * Requirements:\\n *\\n * - the caller must have allowance for ``accounts``'s tokens of at least\\n * `amount`.\\n */\\n function burnFrom(address account, uint256 amount) public virtual {\\n _spendAllowance(account, _msgSender(), amount);\\n _burn(account, amount);\\n }\\n}\\n\",\"keccak256\":\"0x0d19410453cda55960a818e02bd7c18952a5c8fe7a3036e81f0d599f34487a7b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf96f969e24029d43d0df89e59d365f277021dac62b48e1c1e3ebe0acdd7f1ca1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Counters.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Counters\\n * @author Matt Condon (@shrugs)\\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\\n *\\n * Include with `using Counters for Counters.Counter;`\\n */\\nlibrary Counters {\\n struct Counter {\\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\\n // this feature: see https://github.com/ethereum/solidity/issues/4637\\n uint256 _value; // default: 0\\n }\\n\\n function current(Counter storage counter) internal view returns (uint256) {\\n return counter._value;\\n }\\n\\n function increment(Counter storage counter) internal {\\n unchecked {\\n counter._value += 1;\\n }\\n }\\n\\n function decrement(Counter storage counter) internal {\\n uint256 value = counter._value;\\n require(value > 0, \\\"Counter: decrement overflow\\\");\\n unchecked {\\n counter._value = value - 1;\\n }\\n }\\n\\n function reset(Counter storage counter) internal {\\n counter._value = 0;\\n }\\n}\\n\",\"keccak256\":\"0xf0018c2440fbe238dd3a8732fa8e17a0f9dce84d31451dc8a32f6d62b349c9f1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * ```\\n * contract Example {\\n * // Add the library methods\\n * using EnumerableSet for EnumerableSet.AddressSet;\\n *\\n * // Declare a set state variable\\n * EnumerableSet.AddressSet private mySet;\\n * }\\n * ```\\n *\\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\\n * and `uint256` (`UintSet`) are supported.\\n *\\n * [WARNING]\\n * ====\\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\\n * unusable.\\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\\n *\\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\\n * array of EnumerableSet.\\n * ====\\n */\\nlibrary EnumerableSet {\\n // To implement this library for multiple types with as little code\\n // repetition as possible, we write it in terms of a generic Set type with\\n // bytes32 values.\\n // The Set implementation uses private functions, and user-facing\\n // implementations (such as AddressSet) are just wrappers around the\\n // underlying Set.\\n // This means that we can only create new EnumerableSets for types that fit\\n // in bytes32.\\n\\n struct Set {\\n // Storage of set values\\n bytes32[] _values;\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(bytes32 => uint256) _indexes;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function _add(Set storage set, bytes32 value) private returns (bool) {\\n if (!_contains(set, value)) {\\n set._values.push(value);\\n // The value is stored at length-1, but we add 1 to all indexes\\n // and use 0 as a sentinel value\\n set._indexes[value] = set._values.length;\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function _remove(Set storage set, bytes32 value) private returns (bool) {\\n // We read and store the value's index to prevent multiple reads from the same storage slot\\n uint256 valueIndex = set._indexes[value];\\n\\n if (valueIndex != 0) {\\n // Equivalent to contains(set, value)\\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\\n // the array, and then remove the last element (sometimes called as 'swap and pop').\\n // This modifies the order of the array, as noted in {at}.\\n\\n uint256 toDeleteIndex = valueIndex - 1;\\n uint256 lastIndex = set._values.length - 1;\\n\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set._values[lastIndex];\\n\\n // Move the last value to the index where the value to delete is\\n set._values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\\n }\\n\\n // Delete the slot where the moved value was stored\\n set._values.pop();\\n\\n // Delete the index for the deleted slot\\n delete set._indexes[value];\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\\n return set._indexes[value] != 0;\\n }\\n\\n /**\\n * @dev Returns the number of values on the set. O(1).\\n */\\n function _length(Set storage set) private view returns (uint256) {\\n return set._values.length;\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\\n return set._values[index];\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function _values(Set storage set) private view returns (bytes32[] memory) {\\n return set._values;\\n }\\n\\n // Bytes32Set\\n\\n struct Bytes32Set {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _add(set._inner, value);\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _remove(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return _contains(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return _at(set._inner, index);\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n bytes32[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // AddressSet\\n\\n struct AddressSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n return _add(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n return _remove(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\\n return address(uint160(uint256(_at(set._inner, index))));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(AddressSet storage set) internal view returns (address[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n address[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // UintSet\\n\\n struct UintSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(UintSet storage set, uint256 value) internal returns (bool) {\\n return _add(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\\n return _remove(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(UintSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\\n return uint256(_at(set._inner, index));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(UintSet storage set) internal view returns (uint256[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n uint256[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xc3ff3f5c4584e1d9a483ad7ced51ab64523201f4e3d3c65293e4ca8aeb77a961\",\"license\":\"MIT\"},\"contracts/housing-project/CallsSmartHousing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nabstract contract CallsSmartHousing {\\n\\t/// @notice The address of the main SmartHousing contract.\\n\\taddress immutable smartHousingAddr;\\n\\n\\tconstructor(address smartHousingAddr_) {\\n\\t\\tsmartHousingAddr = smartHousingAddr_;\\n\\t}\\n\\n\\t/// @dev Gets the referrer address for a given original owner.\\n\\t/// @param userAddr The original owner of the token.\\n\\t/// @return The referrer address.\\n\\tfunction getReferrer(\\n\\t\\taddress userAddr\\n\\t) internal view returns (uint, address) {\\n\\t\\treturn IUserModule(smartHousingAddr).getReferrer(userAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0xd2ded3c751d669f079d12e7381e586b747cb9ae1b6d9bd4dbd87fc9db3b0371c\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingProject.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"./RentsModule.sol\\\";\\n\\n/// @title HousingProject Contract\\n/// @notice Represents a unique real estate project within the SmartHousing ecosystem.\\n/// @dev This contract inherits from RentsModule and HousingSFT.\\ncontract HousingProject is RentsModule, Ownable {\\n\\t/// @notice Initializes the HousingProject contract.\\n\\t/// @param smartHousingAddr The address of the main SmartHousing contract.\\n\\tconstructor(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) CallsSmartHousing(smartHousingAddr) {\\n\\t\\tprojectSFT = new HousingSFT(name, symbol);\\n\\t}\\n\\n\\tevent TokenIssued(address tokenAddress, string name, uint256 amountRaised);\\n\\n\\tfunction setTokenDetails(\\n\\t\\tuint256 amountRaised,\\n\\t\\taddress housingTokenAddr\\n\\t) external onlyOwner {\\n\\t\\trequire(amountRaised == 0, \\\"Token details set already\\\");\\n\\n\\t\\thousingToken = ERC20Burnable(housingTokenAddr);\\n\\n\\t\\tprojectSFT.setAmountRaised(amountRaised);\\n\\t\\tstring memory name = projectSFT.name();\\n\\n\\t\\temit TokenIssued(address(projectSFT), name, amountRaised);\\n\\t}\\n\\n\\tfunction getMaxSupply() public view returns (uint256) {\\n\\t\\treturn projectSFT.getMaxSupply();\\n\\t}\\n}\\n\",\"keccak256\":\"0x159e6b338c47a2dacbec1254f582826b5584c338919e6e6908aba986f9a98350\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingSFT.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\n\\nimport \\\"../modules/SFT.sol\\\";\\n\\nstruct HousingAttributes {\\n\\tuint256 rewardsPerShare;\\n\\taddress originalOwner;\\n\\tuint256 tokenWeight;\\n}\\n\\n/// @title Housing SFT\\n/// @notice This contract represents a semi-fungible token (SFT) for housing projects.\\n/// @dev This contract will be inherited by the HousingProject contract.\\ncontract HousingSFT is SFT {\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct HousingSFTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tHousingAttributes attributes;\\n\\t}\\n\\n\\t// FIXME this value should be unique to each contract, should depend on\\n\\t// the total amount expected to raise as it determines the amount of SFTs to\\n\\t// be minted for investors\\n\\tuint256 public constant MAX_SUPPLY = 1_000_000;\\n\\n\\t/// @notice The amount of fungible tokens collected from investors to finance the development of this housing project.\\n\\tuint256 public amountRaised;\\n\\n\\t/// @notice The current amount out of the `MAX_SUPPLY` of tokens minted.\\n\\tuint256 public totalSupply;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tfunction setAmountRaised(uint256 amountRaised_) external onlyOwner {\\n\\t\\tamountRaised = amountRaised_;\\n\\t}\\n\\n\\tmodifier canMint() {\\n\\t\\taddress sftOwner = owner();\\n\\n\\t\\trequire(\\n\\t\\t\\tOwnable(sftOwner).owner() == _msgSender(),\\n\\t\\t\\t\\\"not allowed to mint\\\"\\n\\t\\t);\\n\\n\\t\\t_;\\n\\t}\\n\\n\\t/// @notice Mints SFT tokens for a depositor based on the amount of deposit.\\n\\t/// @param depositAmt The amount of fungible token deposited.\\n\\t/// @param depositor The address of the depositor.\\n\\tfunction mintSFT(\\n\\t\\tuint256 depositAmt,\\n\\t\\taddress depositor,\\n\\t\\tuint256 amount_raised\\n\\t) external canMint returns (uint256) {\\n\\t\\t// TODO remove after demo due to not beign able to move blocks in public networks\\n\\t\\t{\\n\\t\\t\\tamountRaised = amount_raised;\\n\\t\\t}\\n\\n\\t\\tuint256 totalDeposits = amountRaised;\\n\\t\\tuint256 maxShares = MAX_SUPPLY;\\n\\n\\t\\trequire(totalDeposits > 0, \\\"HousingSFT: No deposits recorded\\\");\\n\\n\\t\\tuint256 mintShare = (depositAmt * maxShares) / totalDeposits;\\n\\t\\trequire(mintShare > 0, \\\"HousingSFT: Computed token shares is invalid\\\");\\n\\n\\t\\ttotalSupply += mintShare;\\n\\t\\trequire(totalSupply <= MAX_SUPPLY, \\\"HousingSFT: Max supply exceeded\\\");\\n\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tHousingAttributes({\\n\\t\\t\\t\\trewardsPerShare: 0, // Should be 0 since they have never claimed any rent rewards\\n\\t\\t\\t\\toriginalOwner: depositor,\\n\\t\\t\\t\\ttokenWeight: mintShare\\n\\t\\t\\t})\\n\\t\\t);\\n\\n\\t\\treturn _mint(depositor, mintShare, attributes, \\\"\\\");\\n\\t}\\n\\n\\t/// @notice Checks if an address owns this HousingSFT and returns the attributes.\\n\\t/// @param owner The address to check the balance of.\\n\\t/// @return `HousingAttributes` if the owner has a positive balance of the token, panics otherwise.\\n\\tfunction getUserSFT(\\n\\t\\taddress owner,\\n\\t\\tuint256 nonce\\n\\t) public view returns (HousingAttributes memory) {\\n\\t\\trequire(\\n\\t\\t\\thasSFT(owner, nonce),\\n\\t\\t\\t\\\"HouisingSFT: No tokens found for user at nonce\\\"\\n\\t\\t);\\n\\n\\t\\treturn abi.decode(getRawTokenAttributes(nonce), (HousingAttributes));\\n\\t}\\n\\n\\tfunction getMaxSupply() public pure returns (uint256) {\\n\\t\\treturn MAX_SUPPLY;\\n\\t}\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (HousingSFTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tHousingSFTBalance[] memory balance = new HousingSFTBalance[](\\n\\t\\t\\t_sftBals.length\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = HousingSFTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(_sftBal.attributes, (HousingAttributes))\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\tfunction tokenDetails()\\n\\t\\tpublic\\n\\t\\tview\\n\\t\\treturns (string memory, string memory, uint256)\\n\\t{\\n\\t\\treturn (name(), symbol(), getMaxSupply());\\n\\t}\\n}\\n\",\"keccak256\":\"0x8fbbe8d670bc777eed8587d0a8b11acf1d7b40b9ae631fee4abc929f4275c160\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/RentsModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\\\";\\n\\nimport \\\"./HousingSFT.sol\\\";\\nimport \\\"./RewardSharing.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"./CallsSmartHousing.sol\\\";\\n\\n/// @title Rents Module\\n/// @notice Handles rent payments, reward calculations, and distribution for Housing projects.\\n/// @dev This abstract contract should be inherited by the HousingProject contract.\\nabstract contract RentsModule is CallsSmartHousing {\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\tusing RewardShares for rewardshares;\\n\\n\\tuint256 public rewardPerShare;\\n\\tuint256 public rewardsReserve;\\n\\tuint256 public facilityManagementFunds;\\n\\n\\tERC20Burnable housingToken;\\n\\tHousingSFT public projectSFT;\\n\\n\\t/// @notice Receives rent payments and distributes rewards.\\n\\t/// @param rentPayment The details of the rent payment.\\n\\tfunction receiveRent(ERC20TokenPayment calldata rentPayment) external {\\n\\t\\t// TODO set the appropriate rent per Project\\n\\t\\trequire(\\n\\t\\t\\trentPayment.amount > 0,\\n\\t\\t\\t\\\"RentsModule: Insufficient amount\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\trentPayment.token == housingToken,\\n\\t\\t\\t\\\"RentsModule: Invalid rent payment token\\\"\\n\\t\\t);\\n\\t\\trentPayment.receiveERC20();\\n\\n\\t\\tuint256 rentReward = (rentPayment.amount * 75) / 100;\\n\\t\\tuint256 ecosystemReward = (rentPayment.amount * 18) / 100;\\n\\t\\tuint256 facilityReward = (rentPayment.amount * 7) / 100;\\n\\n\\t\\tuint256 allShares = projectSFT.getMaxSupply();\\n\\t\\tuint256 rpsIncrease = (rentReward * DIVISION_SAFETY_CONST) / allShares;\\n\\n\\t\\trewardPerShare += rpsIncrease;\\n\\t\\trewardsReserve += rentReward;\\n\\t\\tfacilityManagementFunds += facilityReward;\\n\\n\\t\\thousingToken.burn(ecosystemReward);\\n\\t\\tISmartHousing(smartHousingAddr).addProjectRent(rentPayment.amount);\\n\\t}\\n\\n\\t/// @notice Claims rent rewards for a given token.\\n\\t/// @return The updated HousingAttributes.\\n\\tfunction claimRentReward(\\n\\t\\tuint256 nonce\\n\\t) external returns (HousingAttributes memory, rewardshares memory) {\\n\\t\\taddress caller = msg.sender;\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tHousingAttributes memory attr = projectSFT.getUserSFT(caller, nonce);\\n\\t\\trewardshares memory rewardShares = computeRewardShares(attr);\\n\\t\\tuint256 totalReward = rewardShares.total();\\n\\n\\t\\tif (totalReward == 0) {\\n\\t\\t\\t// Fail silently\\n\\t\\t\\treturn (attr, rewardShares);\\n\\t\\t}\\n\\n\\t\\trequire(rewardsReserve >= totalReward, \\\"Computed rewards too large\\\");\\n\\n\\t\\trewardsReserve -= totalReward;\\n\\n\\t\\t// We use original owner since we are certain they are registered\\n\\t\\t(, address referrer) = getReferrer(attr.originalOwner);\\n\\t\\tif (rewardShares.referrerValue > 0) {\\n\\t\\t\\tif (referrer != address(0)) {\\n\\t\\t\\t\\thousingToken.transfer(referrer, rewardShares.referrerValue); // Send to referrer\\n\\t\\t\\t} else {\\n\\t\\t\\t\\thousingToken.burn(rewardShares.referrerValue); // Burn to add to ecosystem reward\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tattr.rewardsPerShare = currentRPS;\\n\\n\\t\\tprojectSFT.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tprojectSFT.balanceOf(caller, nonce),\\n\\t\\t\\tabi.encode(attr)\\n\\t\\t);\\n\\n\\t\\thousingToken.transfer(caller, rewardShares.userValue); // Send to user\\n\\n\\t\\treturn (attr, rewardShares);\\n\\t}\\n\\n\\t/// @notice Computes the amount of rent claimable for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The amount of rent claimable.\\n\\tfunction rentClaimable(\\n\\t\\tHousingAttributes memory attr\\n\\t) public view returns (uint256) {\\n\\t\\treturn computeRewardShares(attr).userValue;\\n\\t}\\n\\n\\t/// @dev Computes the reward shares for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The computed RewardShares.\\n\\tfunction computeRewardShares(\\n\\t\\tHousingAttributes memory attr\\n\\t) internal view returns (rewardshares memory) {\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tif (currentRPS == 0 || attr.rewardsPerShare >= currentRPS) {\\n\\t\\t\\treturn rewardshares({ userValue: 0, referrerValue: 0 });\\n\\t\\t}\\n\\n\\t\\tuint256 reward = computeReward(attr, currentRPS);\\n\\n\\t\\treturn splitReward(reward);\\n\\t}\\n}\\n\",\"keccak256\":\"0xe97c64b7d4f5a945493aa8492c4412248f60ec1e6e8cd74e3f805e40cc672768\",\"license\":\"MIT\"},\"contracts/housing-project/RewardSharing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"./HousingSFT.sol\\\";\\n\\nuint256 constant DIVISION_SAFETY_CONST = 1_000_000_000_000_000_000;\\n\\nstruct rewardshares {\\n\\tuint256 userValue;\\n\\tuint256 referrerValue;\\n}\\n\\nlibrary RewardShares {\\n\\tfunction total(rewardshares memory self) internal pure returns (uint256) {\\n\\t\\treturn self.userValue + self.referrerValue;\\n\\t}\\n}\\n\\nfunction splitReward(uint256 reward) pure returns (rewardshares memory) {\\n\\tuint256 referrerValue = (reward * 6_66) / 100_00; // would amount to approximately 5% of grand total\\n\\tuint256 userValue = reward - referrerValue;\\n\\n\\treturn rewardshares(userValue, referrerValue);\\n}\\n\\nfunction computeReward(\\n\\tHousingAttributes memory attr,\\n\\tuint256 contractRPS\\n) pure returns (uint256) {\\n\\tif (contractRPS <= attr.rewardsPerShare) {\\n\\t\\treturn 0;\\n\\t}\\n\\n\\treturn\\n\\t\\t((contractRPS - attr.rewardsPerShare) * attr.tokenWeight) /\\n\\t\\tDIVISION_SAFETY_CONST;\\n}\\n\",\"keccak256\":\"0x9f07d2b3ee49b91e12ad7ce9ba248ab7dd30bc2efc4238a594e681d3f0348e54\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/lib/TokenPayments.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/interfaces/IERC20.sol\\\";\\nimport { SFT } from \\\"../modules/SFT.sol\\\";\\n\\nstruct ERC20TokenPayment {\\n\\tIERC20 token;\\n\\tuint256 amount;\\n}\\n\\nstruct TokenPayment {\\n\\taddress token;\\n\\tuint256 amount;\\n\\tuint256 nonce;\\n}\\n\\nlibrary TokenPayments {\\n\\tfunction accept(ERC20TokenPayment calldata self) internal {\\n\\t\\tTokenPayments.receiveERC20(self, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(ERC20TokenPayment calldata payment) internal {\\n\\t\\tTokenPayments.receiveERC20(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(\\n\\t\\tERC20TokenPayment calldata payment,\\n\\t\\taddress from\\n\\t) internal {\\n\\t\\tpayment.token.transferFrom(from, address(this), payment.amount);\\n\\t}\\n\\n\\t// Receives both Native, SFTs and ERC20; ERC20 have nonce as 0, Native coins have address 0 as token value\\n\\tfunction receiveToken(TokenPayment memory payment) internal {\\n\\t\\treceiveToken(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveToken(TokenPayment memory payment, address from) internal {\\n\\t\\tif (payment.token == address(0)) {\\n\\t\\t\\t// Native payment\\n\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tpayment.amount == msg.value,\\n\\t\\t\\t\\t\\\"expected payment amount must equal sent amount\\\"\\n\\t\\t\\t);\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tfrom == msg.sender,\\n\\t\\t\\t\\t\\\"can receive native payment only from caller\\\"\\n\\t\\t\\t);\\n\\t\\t\\t\\n\\t\\t\\t// Nothing to do again since the VM will handle balance movements\\n\\t\\t} else if (payment.nonce == 0) {\\n\\t\\t\\tIERC20(payment.token).transferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.amount\\n\\t\\t\\t);\\n\\t\\t} else {\\n\\t\\t\\tSFT(payment.token).safeTransferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.nonce,\\n\\t\\t\\t\\tpayment.amount,\\n\\t\\t\\t\\t\\\"\\\"\\n\\t\\t\\t);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x06bd73e8da1bde18d9aaf6d4b6a1bdec6e0718af6354fe2d7ce87251d6fd1ac5\",\"license\":\"MIT\"},\"contracts/main/Interface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"../lib/TokenPayments.sol\\\";\\n\\ninterface ISmartHousing {\\n\\tfunction addProjectRent(uint256 amount) external;\\n\\n\\tfunction createRefIDViaProxy(\\n\\t\\taddress userAddr,\\n\\t\\tuint256 referrerId\\n\\t) external returns (uint256);\\n\\n\\tfunction addProject(address projectAddress) external;\\n\\n\\tfunction setUpSHT(ERC20TokenPayment calldata payment) external;\\n}\\n\\ninterface IUserModule {\\n\\tfunction getReferrer(address user) external view returns (uint, address);\\n}\\n\",\"keccak256\":\"0x066719eed5c5ff2394d78ce027aada5a8555713c9f4abf8b5135975981ba9989\",\"license\":\"MIT\"},\"contracts/modules/SFT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Counters.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n// TODO I think we should create a standard of this\\nabstract contract SFT is ERC1155, Ownable {\\n\\tusing Counters for Counters.Counter;\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct SftBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tbytes attributes;\\n\\t}\\n\\n\\tCounters.Counter private _nonceCounter;\\n\\tstring private _name;\\n\\tstring private _symbol;\\n\\n\\t// Mapping from nonce to token attributes as bytes\\n\\tmapping(uint256 => bytes) private _tokenAttributes;\\n\\n\\t// Mapping from address to list of owned token nonces\\n\\tmapping(address => EnumerableSet.UintSet) private _addressToNonces;\\n\\n\\tconstructor(string memory name_, string memory symbol_) ERC1155(\\\"\\\") {\\n\\t\\t_name = name_;\\n\\t\\t_symbol = symbol_;\\n\\t}\\n\\n\\t// Private function to mint new tokens\\n\\tfunction _mint(\\n\\t\\taddress to,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attributes,\\n\\t\\tbytes memory data\\n\\t) internal returns (uint256) {\\n\\t\\t_nonceCounter.increment();\\n\\t\\tuint256 nonce = _nonceCounter.current();\\n\\n\\t\\t// Store the attributes\\n\\t\\t_tokenAttributes[nonce] = attributes;\\n\\n\\t\\t// Mint the token with the nonce as its ID\\n\\t\\tsuper._mint(to, nonce, amount, data);\\n\\n\\t\\t// Track the nonce for the address\\n\\t\\t_addressToNonces[to].add(nonce);\\n\\n\\t\\treturn nonce;\\n\\t}\\n\\n\\tfunction name() public view returns (string memory) {\\n\\t\\treturn _name;\\n\\t}\\n\\n\\tfunction symbol() public view returns (string memory) {\\n\\t\\treturn _symbol;\\n\\t}\\n\\n\\tfunction tokenInfo() public view returns (string memory, string memory) {\\n\\t\\treturn (_name, _symbol);\\n\\t}\\n\\n\\t// Function to get token attributes by nonce\\n\\tfunction getRawTokenAttributes(\\n\\t\\tuint256 nonce\\n\\t) public view returns (bytes memory) {\\n\\t\\treturn _tokenAttributes[nonce];\\n\\t}\\n\\n\\t// Function to get list of nonces owned by an address\\n\\tfunction getNonces(address owner) public view returns (uint256[] memory) {\\n\\t\\treturn _addressToNonces[owner].values();\\n\\t}\\n\\n\\tfunction hasSFT(address owner, uint256 nonce) public view returns (bool) {\\n\\t\\treturn _addressToNonces[owner].contains(nonce);\\n\\t}\\n\\n\\t/// Burns all the NFT balance of user at nonce, creates new with balance and attributes\\n\\tfunction update(\\n\\t\\taddress user,\\n\\t\\tuint256 nonce,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attr\\n\\t) external onlyOwner {\\n\\t\\t_burn(user, nonce, amount);\\n\\t\\t_mint(user, amount, attr, \\\"\\\");\\n\\t}\\n\\n\\tfunction _sftBalance(\\n\\t\\taddress user\\n\\t) internal view returns (SftBalance[] memory) {\\n\\t\\tuint256[] memory nonces = getNonces(user);\\n\\t\\tSftBalance[] memory balance = new SftBalance[](nonces.length);\\n\\n\\t\\tfor (uint256 i; i < nonces.length; i++) {\\n\\t\\t\\tuint256 nonce = nonces[i];\\n\\t\\t\\tbytes memory attributes = _tokenAttributes[nonce];\\n\\t\\t\\tuint256 amount = balanceOf(user, nonce);\\n\\n\\t\\t\\tbalance[i] = SftBalance({\\n\\t\\t\\t\\tnonce: nonce,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tattributes: attributes\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t// Override _beforeTokenTransfer to handle address-to-nonce mapping\\n\\tfunction _beforeTokenTransfer(\\n\\t\\taddress operator,\\n\\t\\taddress from,\\n\\t\\taddress to,\\n\\t\\tuint256[] memory ids,\\n\\t\\tuint256[] memory amounts,\\n\\t\\tbytes memory data\\n\\t) internal virtual override {\\n\\t\\tsuper._beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[from].remove(ids[i]);\\n\\t\\t}\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[to].add(ids[i]);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x8098c36137bbb9a342d16fd64f7d57c03a77841a872dd44641b9db1623a699aa\",\"license\":\"MIT\"}},\"version\":1}", "bytecode": "0x604060a08152346200015e5762003cf4803803806200001e8162000163565b92833981016060828203126200015e5781516001600160401b03908181116200015e57826200004f918501620001c4565b9160208401518281116200015e5785916200006c918601620001c4565b9301516001600160a01b03929083811681036200015e576080526005549160018060a01b0319943386851617600555865192600094863391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08780a3612a0c848101938411858510176200014a5791620000fb8594926200010a94620012e887398a84528a8401906200021b565b9160208184039101526200021b565b039082f09081156200013f575016906004541617600455516110a590816200024382396080518181816106550152610b650152f35b8451903d90823e3d90fd5b634e487b7160e01b86526041600452602486fd5b600080fd5b6040519190601f01601f191682016001600160401b038111838210176200018957604052565b634e487b7160e01b600052604160045260246000fd5b60005b838110620001b35750506000910152565b8181015183820152602001620001a2565b81601f820112156200015e5780516001600160401b0381116200018957620001f6601f8201601f191660200162000163565b92818452602082840101116200015e576200021891602080850191016200019f565b90565b9060209162000236815180928185528580860191016200019f565b601f01601f191601019056fe608060408181526004918236101561001657600080fd5b600092833560e01c91826321aca2ed146108f657508163446a2ec8146108d95781634c0f38c21461084a5781635ad08fea146104f4578163715018a6146104965781637361991514610276578163800151521461024e5781638da5cb5b14610225578163c4152bab14610206578163f2fde38b1461012c578163f59002e3146100ca575063faf36a4b146100a957600080fd5b346100c657816003193601126100c6576020906002549051908152f35b5080fd5b828434610129576020366003190112610129575060206101196100ef60a09435610a92565b9351815181526020808301516001600160a01b031690820152604091820151918101919091529290565b8051606084015201516080820152f35b80fd5b91905034610202576020366003190112610202576001600160a01b038235818116939192908490036101fd57610160610fd5565b83156101ab575050600554826bffffffffffffffffffffffff60a01b821617600555167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b600080fd5b8280fd5b5050346100c657816003193601126100c6576020906001549051908152f35b5050346100c657816003193601126100c65760055490516001600160a01b039091168152602090f35b9050346102025782600319360112610202575490516001600160a01b03909116815260209150f35b9050346102025781600319360112610202578035916102936109c2565b61029b610fd5565b8361045357600380546001600160a01b0319166001600160a01b03928316179055825485908216803b156100c657818091602486518094819363ee83ef1b60e01b83528b8b8401525af1801561044957610431575b5050825416908051936306fdde0360e01b855285858581865afa938415610427578694610361575b507f2f495db1d0882db23f97f363d216ccfe2aaed3fdfceb88feb921954e49569bd7945061035782519485948552606060208601526060850190610a34565b918301520390a180f35b9093503d8087873e61037381876109a0565b85019060208683031261040857855167ffffffffffffffff9687821161042357019082601f8301121561041f57815196871161040c57508251916103c1601f8801601f1916602001846109a0565b86835260208783010111610408577f2f495db1d0882db23f97f363d216ccfe2aaed3fdfceb88feb921954e49569bd7956104019160208085019101610a11565b9238610318565b8680fd5b634e487b7160e01b885260419052602487fd5b8780fd5b8880fd5b82513d88823e3d90fd5b61043a90610970565b6104455784386102f0565b8480fd5b84513d84823e3d90fd5b815162461bcd60e51b8152602081850152601960248201527f546f6b656e2064657461696c732073657420616c7265616479000000000000006044820152606490fd5b83346101295780600319360112610129576104af610fd5565b600580546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b8383346100c657806003193601126100c65760249081359384156107fb5761051a6109d8565b6003546001600160a01b039691908716908716036107a95785859661053d6109d8565b168451906323b872dd60e01b8252338583015230878301528360448301528160648160209b8c945af1801561079f57610772575b50604b8202828104604b03610760576064900496601283029783890460120361074e57600784029184830460070361073c578581858254168951928380926326079c6160e11b82525afa918215610732578a92610704575b5050670de0b6b3a76400008083029083820414831517156106f25781156106e057606492610601610617959361060b93048c546109ee565b8b556001546109ee565b600155046002546109ee565b600255806003541696873b156104085760648688928388519b8c948593630852cd8d60e31b855204898401525af180156106d6576106c2575b8596507f00000000000000000000000000000000000000000000000000000000000000001693843b156106be5785928385519687948593630cac2b0960e11b85528401525af19081156106b557506106a55750f35b6106ae90610970565b6101295780f35b513d84823e3d90fd5b8580fd5b9490956106ce90610970565b938590610650565b84513d88823e3d90fd5b634e487b7160e01b8a5260128752888afd5b634e487b7160e01b8a5260118752888afd5b90809250813d831161072b575b61071b81836109a0565b8101031261042357518a806105c9565b503d610711565b88513d8c823e3d90fd5b634e487b7160e01b8952601186528789fd5b634e487b7160e01b8852601185528688fd5b634e487b7160e01b8752601184528587fd5b61079190883d8a11610798575b61078981836109a0565b810190610a7a565b5087610571565b503d61077f565b85513d89823e3d90fd5b506027836020608494519362461bcd60e51b85528401528201527f52656e74734d6f64756c653a20496e76616c69642072656e74207061796d656e6044820152663a103a37b5b2b760c91b6064820152fd5b6025836020608494519362461bcd60e51b85528401528201527f52656e74734d6f64756c653a20496e73756666696369656e742072656e7420616044820152641b5bdd5b9d60da1b6064820152fd5b91905034610202578260031936011261020257815481516326079c6160e11b81529260209184919082906001600160a01b03165afa9182156108cf578392610897575b6020838351908152f35b9091506020813d6020116108c7575b816108b3602093836109a0565b81010312610202576020925051903861088d565b3d91506108a6565b81513d85823e3d90fd5b5050346100c657816003193601126100c657602091549051908152f35b838286346101295760603660031901126101295750826109369161091b60209561093e565b3581526109266109c2565b8482015260443583820152610f1a565b519051908152f35b6060810190811067ffffffffffffffff82111761095a57604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff811161095a57604052565b6040810190811067ffffffffffffffff82111761095a57604052565b90601f8019910116810190811067ffffffffffffffff82111761095a57604052565b602435906001600160a01b03821682036101fd57565b6004356001600160a01b03811681036101fd5790565b919082018092116109fb57565b634e487b7160e01b600052601160045260246000fd5b60005b838110610a245750506000910152565b8181015183820152602001610a14565b90602091610a4d81518092818552858086019101610a11565b601f01601f1916010190565b51906001600160a01b03821682036101fd57565b919082039182116109fb57565b908160209103126101fd575180151581036101fd5790565b906000604092835190610aa48261093e565b82825282856020938285820152015282828651610ac081610984565b828152015282546004805487516316e8334960e21b81523381840152602481018590529297929591906001600160a01b03906060908890604490829085165afa968715610d0c578397610ec1575b50610b1887610f1a565b988951610b2a888c01918251906109ee565b8015610eb457600154818110610e715790610b4491610a6d565b600155888801518651634a9fefc760e01b81529084168582015286816024817f000000000000000000000000000000000000000000000000000000000000000088165afa908115610e67579089918791610e2d575b5082519283610d62575b5050509088525081548451627eeac760e11b81523381850190815260208101889052918316918890829081906040010381855afa908115610d58578591610d2b575b50855189518982019081526020808c01516001600160a01b0316908201526040808c01519101529060608252608082019782891067ffffffffffffffff8a1117610d1657888852833b1561040857636c49c79360e11b895233608484015260a483015260c4820152608060e48201528491879182908490607f1990610c6e610104820182610a34565b0301925af18015610d0c5790869291610cf0575b6003548a51865163a9059cbb60e01b8152339481019485526020850191909152965086928390036040019183918691165af1918215610ce6575050610cc8575b50509190565b81610cde92903d106107985761078981836109a0565b503880610cc2565b51903d90823e3d90fd5b915091610cfe819495610970565b610202578392918591610c82565b84513d85823e3d90fd5b604186634e487b7160e01b6000525260246000fd5b90508781813d8311610d51575b610d4281836109a0565b810103126101fd575138610be5565b503d610d38565b86513d87823e3d90fd5b81861615610ddc576003549051895163a9059cbb60e01b81526001600160a01b039390931688840190815260208101919091529193508391829003604001908290899088165af18015610d5857610dbf575b505b38878180610ba3565b610dd590883d8a116107985761078981836109a0565b5038610db4565b505050826003541690813b156106be5785916024839289519485938492630852cd8d60e31b84528a8401525af18015610d5857610e1a575b50610db6565b610e2690949194610970565b9238610e14565b809250888092503d8311610e60575b610e4681836109a0565b810103126106be57610e5a89809201610a59565b38610b99565b503d610e3c565b87513d88823e3d90fd5b875162461bcd60e51b81528087018b9052601a60248201527f436f6d7075746564207265776172647320746f6f206c617267650000000000006044820152606490fd5b5050505050505050509190565b9096506060813d606011610f12575b81610edd606093836109a0565b810103126102025783805191610ef28361093e565b80518352610f01888201610a59565b888401520151848201529538610b0e565b3d9150610ed0565b602090604051610f2981610984565b60009281848093520152815480158015610fca575b610fb057610f4b9161102d565b90806020604051610f5b81610984565b828152015261029a90818302918383041483151715610f9c5750612710610f8491048092610a6d565b9060405191610f9283610984565b8252602082015290565b634e487b7160e01b81526011600452602490fd5b505060405190610fbf82610984565b808252602082015290565b508082511015610f3e565b6005546001600160a01b03163303610fe957565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b90815190818111156110675760409161104591610a6d565b910151908181029181830414901517156109fb57670de0b6b3a7640000900490565b50505060009056fea26469706673582212208f96dc3d1eefbf0c5a2e1c80fada8ccb233c10abf25e4575a551b2a71ed8244964736f6c634300081800336080604052346200040c5762002a0c803803806200001d8162000411565b9283398101906040818303126200040c5780516001600160401b0391908281116200040c57836200005091830162000437565b90602093848201518481116200040c576200006c920162000437565b6040519084820182811085821117620003f6576040526000809252600254906001928383811c93168015620003eb575b87841014620003d757601f92838111620003a9575b50600281905560038054336001600160a01b0319821681178355919691906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08480a38051878111620003955760059182548781811c911680156200038a575b8b821014620003765790818784931162000325575b508a90878311600114620002c1578592620002b5575b505060001982891b1c191690861b1781555b8251968711620002a157600654908582811c9216801562000296575b8983101462000282578482116200023b575b505086928611600114620001cd579495508592919083620001c1575b50501b92600019911b1c1916176006555b6040516125629081620004aa8239f35b015193503880620001a0565b6006815286812093969394938691601f198316915b8983831062000220575050501062000205575b50505050811b01600655620001b1565b01519060f884600019921b161c1916905538808080620001f5565b858701518955909701969485019488935090810190620001e2565b600683528883209085808a01821c8301938b8b1062000278575b01901c019085905b8281106200026c575062000184565b8381550185906200025d565b9350829362000255565b634e487b7160e01b83526022600452602483fd5b91607f169162000172565b634e487b7160e01b82526041600452602482fd5b01519050388062000144565b8486528b86208994509190601f198416878e5b8282106200030d5750508411620002f4575b505050811b01815562000156565b0151600019838b1b60f8161c19169055388080620002e6565b8385015186558c979095019493840193018e620002d4565b9091508385528a852087808501861c8201928d86106200036c575b918a918695949301871c01915b8281106200035d5750506200012e565b8781558594508a91016200034d565b9250819262000340565b634e487b7160e01b85526022600452602485fd5b90607f169062000119565b634e487b7160e01b83526041600452602483fd5b600282528484898420920160051c8201915b828110620003cb575050620000b1565b838155018590620003bb565b634e487b7160e01b81526022600452602490fd5b92607f16926200009c565b634e487b7160e01b600052604160045260246000fd5b600080fd5b6040519190601f01601f191682016001600160401b03811183821017620003f657604052565b919080601f840112156200040c5782516001600160401b038111620003f6576020906200046d601f8201601f1916830162000411565b928184528282870101116200040c5760005b8181106200049557508260009394955001015290565b85810183015184820184015282016200047f56fe6040608081526004908136101561001557600080fd5b600091823560e01c8062fdd58e1461181657806301ffc9a7146117a957806306fdde03146117845780630e89341c1461169957806318160ddd1461167a5780632eb2c2d6146112fa57806332cb6b0c146112dc5780634c0f38c2146112dc5780634e1273f4146111495780634fa3d25d146110f55780635124ae951461106f5780635ba0cd2414610f5e5780636addb66314610f08578063715018a614610ea85780637b3e5e7b14610e895780637c89f5df14610e565780638da5cb5b14610e2d57806395d89b4114610df2578063a22cb46514610d11578063a42accea14610a8e578063d6abe11014610a1c578063d8938f261461080b578063da96192114610569578063e985e9c51461051b578063ee83ef1b146104f5578063f242432a146102175763f2fde38b1461014957600080fd5b346102135760203660031901126102135761016261183f565b9061016b611e89565b6001600160a01b039182169283156101c1575050600354826bffffffffffffffffffffffff60a01b821617600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8280fd5b5090346102135760a03660031901126102135761023261183f565b9061023b61185a565b9160443593606435936084356001600160401b0381116104f1576102629036908401611994565b6001600160a01b039384169390929033851480156104d2575b61028490611cb5565b821692610292841515611dd0565b61029b8861237c565b966102a58161237c565b50895b88518110156102da57600190878c5260086020526102d3898d206102cc838d611d18565b519061243c565b50016102a8565b50909192939497895b885181101561031557600190878c52600860205261030e898d20610307838d611d18565b51906123c9565b50016102e3565b5091949296509296818952602097898952868a20828b52895284878b205461033f82821015611e2a565b848c528b8b52888c20848d528b5203878b2055828a52898952868a20848b528952868a2061036e868254611dad565b905583828851858152878c8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628a3392a43b6103aa578880f35b918697989596949391868a946103f38a519788968795869463f23a6e6160e01b9c8d8752339087015260248601526044850152606484015260a0608484015260a4830190611870565b03925af18391816104a3575b506104685750505061040f612298565b6308c379a014610437575b5162461bcd60e51b815291508190610433908201612327565b0390fd5b61043f6122b6565b8061044a575061041a565b610433915193849362461bcd60e51b85528401526024830190611870565b9194506001600160e01b03199091160361048a57505038808080808080808880f35b5162461bcd60e51b81529150819061043390820161224f565b6104c4919250873d89116104cb575b6104bc81836118fc565b81019061222f565b90386103ff565b503d6104b2565b5084895260016020908152868a20338b5290528589205460ff1661027b565b8780fd5b83823461051757602036600319011261051757610510611e89565b3560095580f35b5080fd5b50503461051757806003193601126105175760ff8160209361053b61183f565b61054361185a565b6001600160a01b0391821683526001875283832091168252855220549151911615158152f35b509190346105175760603660031901126105175782359161058861185a565b6003548351638da5cb5b60e01b81526020956001600160a01b03939092909160443591889082908b90829089165afa9081156108015786916107c8575b50843391160361078f5780600955801561074e57620f4240928381029080820485149015171561073b57049182156106e35761060383600a54611dad565b80600a55116106a057845192610618846118b0565b848452811686840152818584015261065185519387850190604080918051845260018060a01b0360208201511660208501520151910152565b6060835260808301938385106001600160401b0386111761068d578596975084610686965261067f856118e1565b8452611ee1565b9051908152f35b634e487b7160e01b815260418852602490fd5b845162461bcd60e51b8152808801879052601f60248201527f486f7573696e675346543a204d617820737570706c79206578636565646564006044820152606490fd5b855162461bcd60e51b8152808901889052602c60248201527f486f7573696e675346543a20436f6d707574656420746f6b656e20736861726560448201526b1cc81a5cc81a5b9d985b1a5960a21b6064820152608490fd5b634e487b7160e01b865260118952602486fd5b606488888089519262461bcd60e51b845283015260248201527f486f7573696e675346543a204e6f206465706f73697473207265636f726465646044820152fd5b855162461bcd60e51b815280890188905260136024820152721b9bdd08185b1b1bddd959081d1bc81b5a5b9d606a1b6044820152606490fd5b90508781813d83116107fa575b6107df81836118fc565b810103126107f6576107f090611d61565b386105c5565b8580fd5b503d6107d5565b87513d88823e3d90fd5b508290346105175760803660031901126105175761082761183f565b9160243592604435926064356001600160401b038111610a185761084e9036908301611994565b91610857611e89565b6001600160a01b0381169283156109c9576108718761237c565b9561087b8161237c565b50858951610888816118e1565b52855b87518110156108b65760019086885260086020526108af8b89206102cc838c611d18565b500161088b565b509193909296855b87518110156108e95760019087805260086020526108e28b8920610307838c611d18565b50016108be565b5080865260208681528987208388528152898720548a98508985821061097a5750918488999492818a95846109769c528683528787208688528352038686205585519283528201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62843392a4858151610962816118e1565b52519261096e846118e1565b858452611ee1565b5080f35b895162461bcd60e51b81529081018390526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152608490fd5b875162461bcd60e51b8152602081850152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b8380fd5b5050346105175781600319360112610517578051610a7891610a4882610a4181611add565b03836118fc565b620f4240610a868251610a6581610a5e81611b91565b03826118fc565b8351958695606087526060870190611870565b908582036020870152611870565b918301520390f35b5050346105175760208060031936011261021357610aaa61183f565b6001600160a01b03811684526008825282842083518154808252918652838620818501969194939192835b818110610cfd57505050610aef84610b16969703856118fc565b835193610afb8561191d565b94610b08885196876118fc565b808652601f1996879161191d565b0184845b828110610cd657505050825b8151811015610b945780610b3c60019284611d18565b5180865260078752610a5e610b588b88208c5192838092611c1f565b610b628287611a1e565b8b5192610b6e846118b0565b8352888301528a820152610b828289611d18565b52610b8d8188611d18565b5001610b26565b5050509291805192610bbd610ba88561191d565b94610bb5885196876118fc565b80865261191d565b0182855b828110610ca957505050835b8151811015610c335780610be360019284611d18565b51805190610c008987830151920151878082518301019101611d75565b90895192610c0d846118b0565b83528683015288820152610c218287611d18565b52610c2c8186611d18565b5001610bcd565b505091835192808401908085528351809252808686019401925b828110610c5a5785850386f35b909192938260a0600192610c9d8a895180518452858101518685015201518b830190604080918051845260018060a01b0360208201511660208501520151910152565b01950193929101610c4d565b8751610cb4816118b0565b8781528783820152610cc4611d42565b89820152828288010152018390610bc1565b8951610ce1816118b0565b868152868382015260608b82015282828a010152018590610b1a565b825489529785019760019283019201610ad5565b509034610213578060031936011261021357610d2b61183f565b9060243591821515809303610dee576001600160a01b031692338414610d9a5750338452600160205280842083855260205280842060ff1981541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b6020608492519162461bcd60e51b8352820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152fd5b8480fd5b5050346105175781600319360112610517578051610e2991610e1782610a4181611b91565b51918291602083526020830190611870565b0390f35b50503461051757816003193601126105175760035490516001600160a01b039091168152602090f35b50346102135760203660031901126102135790610e1781610e2994610a4194358152600760205220825193848092611c1f565b5050346105175781600319360112610517576020906009549051908152f35b8334610f055780600319360112610f0557610ec1611e89565b600380546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b828434610f055780600319360112610f055750805190610f2b82610a4181611add565b610e298151610f3d81610a5e81611b91565b610f508351948486958652850190611870565b908382036020850152611870565b50829034610517578260031936011261051757610f7961183f565b9060243591610f86611d42565b5060018060a01b031683526008602052610fb28285852060019160005201602052604060002054151590565b1561101557606084611013610feb610a5e610fdc8489898152600760205220855192838092611c1f565b60208082518301019101611d75565b9151825181526020808401516001600160a01b03169082015260409283015192810192909252565bf35b608490602085519162461bcd60e51b8352820152602e60248201527f486f756973696e675346543a204e6f20746f6b656e7320666f756e6420666f7260448201526d2075736572206174206e6f6e636560901b6064820152fd5b5050346105175760209081600319360112610213576001600160a01b0361109461183f565b16835260088252808320815190819485928583549182815201928252858220915b868282106110de578590610e29886110cf848903856118fc565b519282849384528301906119ea565b8354855288955090930192600192830192016110b5565b505034610517578060031936011261051757602091611140906001600160a01b0361111e61183f565b1681526008845282602435912060019160005201602052604060002054151590565b90519015158152f35b503461021357816003193601126102135780356001600160401b03808211610dee5736602383011215610dee5781830135906111848261191d565b92611191865194856118fc565b82845260209260248486019160051b830101913683116112d857602401905b8282106112b5575050506024359081116107f6576111d19036908501611934565b92825184510361126257508151946111e88661191d565b956111f5865197886118fc565b808752611204601f199161191d565b0136838801375b82518110156112505760019061123f6001600160a01b0361122c8387611d18565b51166112388388611d18565b5190611a1e565b6112498289611d18565b520161120b565b845182815280610e29818501896119ea565b60849185519162461bcd60e51b8352820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152fd5b81356001600160a01b03811681036112d45781529084019084016111b0565b8980fd5b8880fd5b50503461051757816003193601126105175760209051620f42408152f35b509034610213576003199060a036830112610a185761131761183f565b9361132061185a565b92604435946001600160401b0395868111610a18576113429036908301611934565b94606435878111610dee5761135a9036908401611934565b96608435908111610dee576113729036908401611994565b6001600160a01b0398891698909190338a14801561165b575b61139490611cb5565b8751895103611607578116916113ab831515611dd0565b855b88518110156113d8576001908b885260086020526113d18989206102cc838d611d18565b50016113ad565b5091939897909297855b885181101561140d576001908688526008602052611406898920610307838d611d18565b50016113e2565b5092989790969197855b8351811015611494578061142d60019286611d18565b51611438828c611d18565b5190808a526020908a82528b8b20898c528252828c8c8b828220549261146085851015611e2a565b858352828752822091528452038c8c20558a528981528a8a2090898b525261148c8a8a20918254611dad565b905501611417565b50949897909692959784878a518b81527f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb6114d18d8301886119ea565b918083036020820152806114e633948b6119ea565b0390a43b6114f2578880f35b8798969751948593849363bc197c8160e01b98898652338c87015260248601526044850160a0905260a48501611527916119ea565b8285820301606486015261153a916119ea565b9083820301608484015261154d91611870565b0381865a94602095f18391816115e6575b506115c65750505061156e612298565b6308c379a014611592575b905162461bcd60e51b8152908190610433908201612327565b61159a6122b6565b806115a55750611579565b610433906020935193849362461bcd60e51b85528401526024830190611870565b9193916001600160e01b0319160361048a57505038808080808080808880f35b61160091925060203d6020116104cb576104bc81836118fc565b903861155e565b865162461bcd60e51b8152602081860152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608490fd5b508986526001602090815287872033885290528686205460ff1661138b565b505034610517578160031936011261051757602090600a549051908152f35b5050346105175760209081600319360112610213578051838194906002546116c081611aa3565b918285526001918760018216918260001461175d575050600114611701575b505050610e2992916116f29103856118fc565b51928284938452830190611870565b9190869350600283527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b82841061174557505050820101816116f2610e296116df565b8054848a01860152889550879490930192810161172c565b60ff19168782015293151560051b860190930193508492506116f29150610e2990506116df565b5050346105175781600319360112610517578051610e2991610e1782610a4181611add565b503461021357602036600319011261021357359063ffffffff60e01b82168092036102135760209250636cdb3d1360e11b8214918215611805575b82156117f4575b50519015158152f35b6301ffc9a760e01b149150386117eb565b6303a24d0760e21b811492506117e4565b50503461051757806003193601126105175760209061068661183661183f565b60243590611a1e565b600435906001600160a01b038216820361185557565b600080fd5b602435906001600160a01b038216820361185557565b919082519283825260005b84811061189c575050826000602080949584010152601f8019910116010190565b60208183018101518483018201520161187b565b606081019081106001600160401b038211176118cb57604052565b634e487b7160e01b600052604160045260246000fd5b602081019081106001600160401b038211176118cb57604052565b90601f801991011681019081106001600160401b038211176118cb57604052565b6001600160401b0381116118cb5760051b60200190565b9080601f8301121561185557602090823561194e8161191d565b9361195c60405195866118fc565b81855260208086019260051b82010192831161185557602001905b828210611985575050505090565b81358152908301908301611977565b81601f82011215611855578035906001600160401b0382116118cb57604051926119c8601f8401601f1916602001856118fc565b8284526020838301011161185557816000926020809301838601378301015290565b90815180825260208080930193019160005b828110611a0a575050505090565b8351855293810193928101926001016119fc565b6001600160a01b0316908115611a4b57600052600060205260406000209060005260205260406000205490565b60405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b6064820152608490fd5b90600182811c92168015611ad3575b6020831014611abd57565b634e487b7160e01b600052602260045260246000fd5b91607f1691611ab2565b60055460009291611aed82611aa3565b80825291602090600190818116908115611b6c5750600114611b10575b50505050565b9293945060056000527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0926000935b858510611b59575050506020925001019038808080611b0a565b8054858501840152938201938101611b3f565b92505050602093945060ff929192191683830152151560051b01019038808080611b0a565b60065460009291611ba182611aa3565b80825291602090600190818116908115611b6c5750600114611bc35750505050565b9293945060066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f926000935b858510611c0c575050506020925001019038808080611b0a565b8054858501840152938201938101611bf2565b805460009392611c2e82611aa3565b91828252602093600191600181169081600014611c965750600114611c55575b5050505050565b90939495506000929192528360002092846000945b838610611c8257505050500101903880808080611c4e565b805485870183015294019385908201611c6a565b60ff19168685015250505090151560051b010191503880808080611c4e565b15611cbc57565b60405162461bcd60e51b815260206004820152602e60248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201526d195c881bdc88185c1c1c9bdd995960921b6064820152608490fd5b8051821015611d2c5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b60405190611d4f826118b0565b60006040838281528260208201520152565b51906001600160a01b038216820361185557565b90816060910312611855576040805191611d8e836118b0565b80518352611d9e60208201611d61565b60208401520151604082015290565b91908201809211611dba57565b634e487b7160e01b600052601160045260246000fd5b15611dd757565b60405162461bcd60e51b815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604482015264647265737360d81b6064820152608490fd5b15611e3157565b60405162461bcd60e51b815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201526939103a3930b739b332b960b11b6064820152608490fd5b6003546001600160a01b03163303611e9d57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b92909260016004818154019586825560009487865260209460078652604097888820908051906001600160401b03821161221c578190611f218454611aa3565b601f81116121cc575b508990601f831160011461216d578b92612162575b5050600019600383901b1c191690871b1790555b6001600160a01b03811694851561211557611f6d8a61237c565b611f768561237c565b508189815b6120e6575b509089915b6120b6575b5050508887528686528787208588528652878720611fa9848254611dad565b9055848789518b815285898201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628b3392a43b611ffb575b50505082526008905220611ff79082906123c9565b5090565b8461204191889a97959499969a518093819263f23a6e6160e01b968784528d33908501528960248501528a6044850152606484015260a0608484015260a4830190611870565b038187875af1849181612097575b5061205f5788888861040f612298565b63ffffffff60e0999598939496991b160361207e575060088286611fe2565b845162461bcd60e51b815290819061043390820161224f565b6120af9192508a3d8c116104cb576104bc81836118fc565b903861204f565b80518210156120e157828092898c5260088b526120d98d8d206103078386611d18565b500191611f85565b611f8a565b82518110156121105781908b805260088b526121088d8d206102cc8387611d18565b500181611f7b565b611f80565b885162461bcd60e51b8152808601889052602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608490fd5b015190503880611f3f565b848c528a8c208a94509190601f1984168d5b8d8282106121b6575050841161219d575b505050811b019055611f53565b015160001960f88460031b161c19169055388080612190565b8385015186558d9790950194938401930161217f565b909150838b52898b20601f840160051c8101918b8510612212575b84939291601f8c920160051c01915b828110612204575050611f2a565b8d81558594508b91016121f6565b90915081906121e7565b634e487b7160e01b8a526041875260248afd5b9081602091031261185557516001600160e01b0319811681036118555790565b60809060208152602860208201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b60608201520190565b60009060033d116122a557565b905060046000803e60005160e01c90565b600060443d1061231357604051600319913d83016004833e81516001600160401b03918282113d6024840111176123165781840194855193841161231e573d850101602084870101116123165750612313929101602001906118fc565b90565b949350505050565b50949350505050565b60809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356040820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b60608201520190565b60405190604082018281106001600160401b038211176118cb5760405260018252602082016020368237825115611d2c575290565b8054821015611d2c5760005260206000200190600090565b600082815260018201602052604090205461243557805490680100000000000000008210156118cb578261241e6124078460018096018555846123b1565b819391549060031b91821b91600019901b19161790565b905580549260005201602052604060002055600190565b5050600090565b906001820190600092818452826020526040842054908115156000146125255760001991808301818111612511578254908482019182116124fd578082036124c8575b505050805480156124b45782019161249783836123b1565b909182549160031b1b191690555582526020526040812055600190565b634e487b7160e01b86526031600452602486fd5b6124e86124d861240793866123b1565b90549060031b1c928392866123b1565b9055865284602052604086205538808061247f565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b87526011600452602487fd5b505050509056fea26469706673582212202d137cb3efc170b68d45dbf888164a01949016ba15b678c4c36cc54b57e0424364736f6c63430008180033", "deployedBytecode": "0x608060408181526004918236101561001657600080fd5b600092833560e01c91826321aca2ed146108f657508163446a2ec8146108d95781634c0f38c21461084a5781635ad08fea146104f4578163715018a6146104965781637361991514610276578163800151521461024e5781638da5cb5b14610225578163c4152bab14610206578163f2fde38b1461012c578163f59002e3146100ca575063faf36a4b146100a957600080fd5b346100c657816003193601126100c6576020906002549051908152f35b5080fd5b828434610129576020366003190112610129575060206101196100ef60a09435610a92565b9351815181526020808301516001600160a01b031690820152604091820151918101919091529290565b8051606084015201516080820152f35b80fd5b91905034610202576020366003190112610202576001600160a01b038235818116939192908490036101fd57610160610fd5565b83156101ab575050600554826bffffffffffffffffffffffff60a01b821617600555167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b600080fd5b8280fd5b5050346100c657816003193601126100c6576020906001549051908152f35b5050346100c657816003193601126100c65760055490516001600160a01b039091168152602090f35b9050346102025782600319360112610202575490516001600160a01b03909116815260209150f35b9050346102025781600319360112610202578035916102936109c2565b61029b610fd5565b8361045357600380546001600160a01b0319166001600160a01b03928316179055825485908216803b156100c657818091602486518094819363ee83ef1b60e01b83528b8b8401525af1801561044957610431575b5050825416908051936306fdde0360e01b855285858581865afa938415610427578694610361575b507f2f495db1d0882db23f97f363d216ccfe2aaed3fdfceb88feb921954e49569bd7945061035782519485948552606060208601526060850190610a34565b918301520390a180f35b9093503d8087873e61037381876109a0565b85019060208683031261040857855167ffffffffffffffff9687821161042357019082601f8301121561041f57815196871161040c57508251916103c1601f8801601f1916602001846109a0565b86835260208783010111610408577f2f495db1d0882db23f97f363d216ccfe2aaed3fdfceb88feb921954e49569bd7956104019160208085019101610a11565b9238610318565b8680fd5b634e487b7160e01b885260419052602487fd5b8780fd5b8880fd5b82513d88823e3d90fd5b61043a90610970565b6104455784386102f0565b8480fd5b84513d84823e3d90fd5b815162461bcd60e51b8152602081850152601960248201527f546f6b656e2064657461696c732073657420616c7265616479000000000000006044820152606490fd5b83346101295780600319360112610129576104af610fd5565b600580546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b8383346100c657806003193601126100c65760249081359384156107fb5761051a6109d8565b6003546001600160a01b039691908716908716036107a95785859661053d6109d8565b168451906323b872dd60e01b8252338583015230878301528360448301528160648160209b8c945af1801561079f57610772575b50604b8202828104604b03610760576064900496601283029783890460120361074e57600784029184830460070361073c578581858254168951928380926326079c6160e11b82525afa918215610732578a92610704575b5050670de0b6b3a76400008083029083820414831517156106f25781156106e057606492610601610617959361060b93048c546109ee565b8b556001546109ee565b600155046002546109ee565b600255806003541696873b156104085760648688928388519b8c948593630852cd8d60e31b855204898401525af180156106d6576106c2575b8596507f00000000000000000000000000000000000000000000000000000000000000001693843b156106be5785928385519687948593630cac2b0960e11b85528401525af19081156106b557506106a55750f35b6106ae90610970565b6101295780f35b513d84823e3d90fd5b8580fd5b9490956106ce90610970565b938590610650565b84513d88823e3d90fd5b634e487b7160e01b8a5260128752888afd5b634e487b7160e01b8a5260118752888afd5b90809250813d831161072b575b61071b81836109a0565b8101031261042357518a806105c9565b503d610711565b88513d8c823e3d90fd5b634e487b7160e01b8952601186528789fd5b634e487b7160e01b8852601185528688fd5b634e487b7160e01b8752601184528587fd5b61079190883d8a11610798575b61078981836109a0565b810190610a7a565b5087610571565b503d61077f565b85513d89823e3d90fd5b506027836020608494519362461bcd60e51b85528401528201527f52656e74734d6f64756c653a20496e76616c69642072656e74207061796d656e6044820152663a103a37b5b2b760c91b6064820152fd5b6025836020608494519362461bcd60e51b85528401528201527f52656e74734d6f64756c653a20496e73756666696369656e742072656e7420616044820152641b5bdd5b9d60da1b6064820152fd5b91905034610202578260031936011261020257815481516326079c6160e11b81529260209184919082906001600160a01b03165afa9182156108cf578392610897575b6020838351908152f35b9091506020813d6020116108c7575b816108b3602093836109a0565b81010312610202576020925051903861088d565b3d91506108a6565b81513d85823e3d90fd5b5050346100c657816003193601126100c657602091549051908152f35b838286346101295760603660031901126101295750826109369161091b60209561093e565b3581526109266109c2565b8482015260443583820152610f1a565b519051908152f35b6060810190811067ffffffffffffffff82111761095a57604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff811161095a57604052565b6040810190811067ffffffffffffffff82111761095a57604052565b90601f8019910116810190811067ffffffffffffffff82111761095a57604052565b602435906001600160a01b03821682036101fd57565b6004356001600160a01b03811681036101fd5790565b919082018092116109fb57565b634e487b7160e01b600052601160045260246000fd5b60005b838110610a245750506000910152565b8181015183820152602001610a14565b90602091610a4d81518092818552858086019101610a11565b601f01601f1916010190565b51906001600160a01b03821682036101fd57565b919082039182116109fb57565b908160209103126101fd575180151581036101fd5790565b906000604092835190610aa48261093e565b82825282856020938285820152015282828651610ac081610984565b828152015282546004805487516316e8334960e21b81523381840152602481018590529297929591906001600160a01b03906060908890604490829085165afa968715610d0c578397610ec1575b50610b1887610f1a565b988951610b2a888c01918251906109ee565b8015610eb457600154818110610e715790610b4491610a6d565b600155888801518651634a9fefc760e01b81529084168582015286816024817f000000000000000000000000000000000000000000000000000000000000000088165afa908115610e67579089918791610e2d575b5082519283610d62575b5050509088525081548451627eeac760e11b81523381850190815260208101889052918316918890829081906040010381855afa908115610d58578591610d2b575b50855189518982019081526020808c01516001600160a01b0316908201526040808c01519101529060608252608082019782891067ffffffffffffffff8a1117610d1657888852833b1561040857636c49c79360e11b895233608484015260a483015260c4820152608060e48201528491879182908490607f1990610c6e610104820182610a34565b0301925af18015610d0c5790869291610cf0575b6003548a51865163a9059cbb60e01b8152339481019485526020850191909152965086928390036040019183918691165af1918215610ce6575050610cc8575b50509190565b81610cde92903d106107985761078981836109a0565b503880610cc2565b51903d90823e3d90fd5b915091610cfe819495610970565b610202578392918591610c82565b84513d85823e3d90fd5b604186634e487b7160e01b6000525260246000fd5b90508781813d8311610d51575b610d4281836109a0565b810103126101fd575138610be5565b503d610d38565b86513d87823e3d90fd5b81861615610ddc576003549051895163a9059cbb60e01b81526001600160a01b039390931688840190815260208101919091529193508391829003604001908290899088165af18015610d5857610dbf575b505b38878180610ba3565b610dd590883d8a116107985761078981836109a0565b5038610db4565b505050826003541690813b156106be5785916024839289519485938492630852cd8d60e31b84528a8401525af18015610d5857610e1a575b50610db6565b610e2690949194610970565b9238610e14565b809250888092503d8311610e60575b610e4681836109a0565b810103126106be57610e5a89809201610a59565b38610b99565b503d610e3c565b87513d88823e3d90fd5b875162461bcd60e51b81528087018b9052601a60248201527f436f6d7075746564207265776172647320746f6f206c617267650000000000006044820152606490fd5b5050505050505050509190565b9096506060813d606011610f12575b81610edd606093836109a0565b810103126102025783805191610ef28361093e565b80518352610f01888201610a59565b888401520151848201529538610b0e565b3d9150610ed0565b602090604051610f2981610984565b60009281848093520152815480158015610fca575b610fb057610f4b9161102d565b90806020604051610f5b81610984565b828152015261029a90818302918383041483151715610f9c5750612710610f8491048092610a6d565b9060405191610f9283610984565b8252602082015290565b634e487b7160e01b81526011600452602490fd5b505060405190610fbf82610984565b808252602082015290565b508082511015610f3e565b6005546001600160a01b03163303610fe957565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b90815190818111156110675760409161104591610a6d565b910151908181029181830414901517156109fb57670de0b6b3a7640000900490565b50505060009056fea26469706673582212208f96dc3d1eefbf0c5a2e1c80fada8ccb233c10abf25e4575a551b2a71ed8244964736f6c63430008180033", "devdoc": { diff --git a/packages/backend/deployments/opbnb/ProjectFunding.json b/packages/backend/deployments/opbnb/ProjectFunding.json index 9d1169a..7647007 100644 --- a/packages/backend/deployments/opbnb/ProjectFunding.json +++ b/packages/backend/deployments/opbnb/ProjectFunding.json @@ -518,7 +518,7 @@ "type": "uint256" } ], - "name": "setProjectToken", + "name": "addProjectToEcosystem", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -637,7 +637,7 @@ ], "numDeployments": 3, "solcInputHash": "3f7696dcd180eba0f188ae64ff117803", - "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_coinbase\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"projectAddress\",\"type\":\"address\"}],\"name\":\"ProjectDeployed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"struct TokenPayment\",\"name\":\"payment\",\"type\":\"tuple\"}],\"name\":\"ProjectFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProjectTokensClaimed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"allProjects\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"projectAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fundingGoal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingDeadline\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"fundingToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"collectedFunds\",\"type\":\"uint256\"}],\"internalType\":\"struct ProjectStorage.Data[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"}],\"name\":\"claimProjectTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"coinbase\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"fundingToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fundingGoal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingDeadline\",\"type\":\"uint256\"}],\"name\":\"deployProject\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct TokenPayment\",\"name\":\"depositPayment\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"name\":\"fundProject\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"}],\"name\":\"getProjectAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"projectAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"}],\"name\":\"getProjectData\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingGoal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingDeadline\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"fundingToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"projectAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"collectedFunds\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"housingToken\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ERC20TokenPayment\",\"name\":\"shtPayment\",\"type\":\"tuple\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"smartHousingAddress_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fundingToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fundingGoal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingDeadline\",\"type\":\"uint256\"}],\"name\":\"initFirstProject\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lkSht\",\"outputs\":[{\"internalType\":\"contract LkSHT\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"projectCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"projects\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"projectAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fundingGoal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingDeadline\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"fundingToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"collectedFunds\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"projectsId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"}],\"name\":\"setProjectToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"smartHousingAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"unlockSHT\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"usersProjectDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract is used for initializing and deploying housing projects. It allows the deployment of a new housing project and manages project data.\",\"events\":{\"ProjectDeployed(address)\":{\"details\":\"Emitted when a new project is deployed.\",\"params\":{\"projectAddress\":\"Address of the newly deployed HousingProject contract.\"}}},\"kind\":\"dev\",\"methods\":{\"allProjects()\":{\"details\":\"Returns an array of all project IDs and their associated data.\",\"returns\":{\"_0\":\"projectList An array of tuples containing project details.\"}},\"claimProjectTokens(uint256)\":{\"details\":\"Claims project tokens for a given project ID.\",\"params\":{\"projectId\":\"The ID of the project to claim tokens from.\"}},\"constructor\":{\"params\":{\"_coinbase\":\"Address authorized to initialize the first project.\"}},\"deployProject(string,string,address,uint256,uint256)\":{\"details\":\"Deploys a new project. This function can be called multiple times to deploy additional projects.\",\"params\":{\"fundingDeadline\":\"The deadline for the project funding.\",\"fundingGoal\":\"The funding goal for the new project.\",\"fundingToken\":\"Address of the ERC20 token used for funding.\"}},\"getProjectAddress(uint256)\":{\"details\":\"Returns the address of the HousingProject contract for a given project ID.\",\"params\":{\"projectId\":\"The ID of the project.\"},\"returns\":{\"projectAddress\":\"The address of the HousingProject contract.\"}},\"getProjectData(uint256)\":{\"details\":\"Returns the details of a project by its ID.\",\"params\":{\"projectId\":\"The ID of the project.\"},\"returns\":{\"collectedFunds\":\"The amount of funds collected.\",\"fundingDeadline\":\"The deadline for the project funding.\",\"fundingGoal\":\"The funding goal of the project.\",\"fundingToken\":\"The address of the ERC20 token used for funding.\",\"id\":\"The project ID.\",\"projectAddress\":\"The address of the HousingProject contract.\",\"status\":\"The funding status of the project.\"}},\"initFirstProject((address,uint256),string,string,address,address,uint256,uint256)\":{\"details\":\"Initializes the first project. This function must be called by the coinbase address and can only be called once. It sets up the token and deploys the first project.\",\"params\":{\"fundingDeadline\":\"The deadline for the project funding.\",\"fundingGoal\":\"The funding goal for the new project.\",\"fundingToken\":\"Address of the ERC20 token used for funding.\",\"shtPayment\":\"Payment details for the Smart Housing Token (SHT).\",\"smartHousingAddress_\":\"Address of the Smart Housing contract.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"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.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"ProjectFunding\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/project-funding/ProjectFunding.sol\":\"ProjectFunding\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../token/ERC20/IERC20.sol\\\";\\n\",\"keccak256\":\"0x6ebf1944ab804b8660eb6fc52f9fe84588cee01c2566a69023e59497e7d27f45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0xd917747dc87f189c6779b894f367a028f9dca4be930283cccec8f312966af820\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n // decrementing then incrementing.\\n _balances[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n unchecked {\\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n _balances[account] += amount;\\n }\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n // Overflow not possible: amount <= accountBalance <= totalSupply.\\n _totalSupply -= amount;\\n }\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x4ffc0547c02ad22925310c585c0f166f8759e2648a09e9b489100c42f15dd98d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../ERC20.sol\\\";\\nimport \\\"../../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\\n * tokens and those that they have an allowance for, in a way that can be\\n * recognized off-chain (via event analysis).\\n */\\nabstract contract ERC20Burnable is Context, ERC20 {\\n /**\\n * @dev Destroys `amount` tokens from the caller.\\n *\\n * See {ERC20-_burn}.\\n */\\n function burn(uint256 amount) public virtual {\\n _burn(_msgSender(), amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, deducting from the caller's\\n * allowance.\\n *\\n * See {ERC20-_burn} and {ERC20-allowance}.\\n *\\n * Requirements:\\n *\\n * - the caller must have allowance for ``accounts``'s tokens of at least\\n * `amount`.\\n */\\n function burnFrom(address account, uint256 amount) public virtual {\\n _spendAllowance(account, _msgSender(), amount);\\n _burn(account, amount);\\n }\\n}\\n\",\"keccak256\":\"0x0d19410453cda55960a818e02bd7c18952a5c8fe7a3036e81f0d599f34487a7b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf96f969e24029d43d0df89e59d365f277021dac62b48e1c1e3ebe0acdd7f1ca1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Counters.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Counters\\n * @author Matt Condon (@shrugs)\\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\\n *\\n * Include with `using Counters for Counters.Counter;`\\n */\\nlibrary Counters {\\n struct Counter {\\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\\n // this feature: see https://github.com/ethereum/solidity/issues/4637\\n uint256 _value; // default: 0\\n }\\n\\n function current(Counter storage counter) internal view returns (uint256) {\\n return counter._value;\\n }\\n\\n function increment(Counter storage counter) internal {\\n unchecked {\\n counter._value += 1;\\n }\\n }\\n\\n function decrement(Counter storage counter) internal {\\n uint256 value = counter._value;\\n require(value > 0, \\\"Counter: decrement overflow\\\");\\n unchecked {\\n counter._value = value - 1;\\n }\\n }\\n\\n function reset(Counter storage counter) internal {\\n counter._value = 0;\\n }\\n}\\n\",\"keccak256\":\"0xf0018c2440fbe238dd3a8732fa8e17a0f9dce84d31451dc8a32f6d62b349c9f1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0f633a0223d9a1dcccfcf38a64c9de0874dfcbfac0c6941ccf074d63a2ce0e1e\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * ```\\n * contract Example {\\n * // Add the library methods\\n * using EnumerableSet for EnumerableSet.AddressSet;\\n *\\n * // Declare a set state variable\\n * EnumerableSet.AddressSet private mySet;\\n * }\\n * ```\\n *\\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\\n * and `uint256` (`UintSet`) are supported.\\n *\\n * [WARNING]\\n * ====\\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\\n * unusable.\\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\\n *\\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\\n * array of EnumerableSet.\\n * ====\\n */\\nlibrary EnumerableSet {\\n // To implement this library for multiple types with as little code\\n // repetition as possible, we write it in terms of a generic Set type with\\n // bytes32 values.\\n // The Set implementation uses private functions, and user-facing\\n // implementations (such as AddressSet) are just wrappers around the\\n // underlying Set.\\n // This means that we can only create new EnumerableSets for types that fit\\n // in bytes32.\\n\\n struct Set {\\n // Storage of set values\\n bytes32[] _values;\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(bytes32 => uint256) _indexes;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function _add(Set storage set, bytes32 value) private returns (bool) {\\n if (!_contains(set, value)) {\\n set._values.push(value);\\n // The value is stored at length-1, but we add 1 to all indexes\\n // and use 0 as a sentinel value\\n set._indexes[value] = set._values.length;\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function _remove(Set storage set, bytes32 value) private returns (bool) {\\n // We read and store the value's index to prevent multiple reads from the same storage slot\\n uint256 valueIndex = set._indexes[value];\\n\\n if (valueIndex != 0) {\\n // Equivalent to contains(set, value)\\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\\n // the array, and then remove the last element (sometimes called as 'swap and pop').\\n // This modifies the order of the array, as noted in {at}.\\n\\n uint256 toDeleteIndex = valueIndex - 1;\\n uint256 lastIndex = set._values.length - 1;\\n\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set._values[lastIndex];\\n\\n // Move the last value to the index where the value to delete is\\n set._values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\\n }\\n\\n // Delete the slot where the moved value was stored\\n set._values.pop();\\n\\n // Delete the index for the deleted slot\\n delete set._indexes[value];\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\\n return set._indexes[value] != 0;\\n }\\n\\n /**\\n * @dev Returns the number of values on the set. O(1).\\n */\\n function _length(Set storage set) private view returns (uint256) {\\n return set._values.length;\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\\n return set._values[index];\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function _values(Set storage set) private view returns (bytes32[] memory) {\\n return set._values;\\n }\\n\\n // Bytes32Set\\n\\n struct Bytes32Set {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _add(set._inner, value);\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _remove(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return _contains(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return _at(set._inner, index);\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n bytes32[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // AddressSet\\n\\n struct AddressSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n return _add(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n return _remove(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\\n return address(uint160(uint256(_at(set._inner, index))));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(AddressSet storage set) internal view returns (address[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n address[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // UintSet\\n\\n struct UintSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(UintSet storage set, uint256 value) internal returns (bool) {\\n return _add(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\\n return _remove(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(UintSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\\n return uint256(_at(set._inner, index));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(UintSet storage set) internal view returns (uint256[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n uint256[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xc3ff3f5c4584e1d9a483ad7ced51ab64523201f4e3d3c65293e4ca8aeb77a961\",\"license\":\"MIT\"},\"contracts/housing-project/CallsSmartHousing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nabstract contract CallsSmartHousing {\\n\\t/// @notice The address of the main SmartHousing contract.\\n\\taddress immutable smartHousingAddr;\\n\\n\\tconstructor(address smartHousingAddr_) {\\n\\t\\tsmartHousingAddr = smartHousingAddr_;\\n\\t}\\n\\n\\t/// @dev Gets the referrer address for a given original owner.\\n\\t/// @param userAddr The original owner of the token.\\n\\t/// @return The referrer address.\\n\\tfunction getReferrer(\\n\\t\\taddress userAddr\\n\\t) internal view returns (uint, address) {\\n\\t\\treturn IUserModule(smartHousingAddr).getReferrer(userAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0xd2ded3c751d669f079d12e7381e586b747cb9ae1b6d9bd4dbd87fc9db3b0371c\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingProject.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"./RentsModule.sol\\\";\\n\\n/// @title HousingProject Contract\\n/// @notice Represents a unique real estate project within the SmartHousing ecosystem.\\n/// @dev This contract inherits from RentsModule and HousingSFT.\\ncontract HousingProject is RentsModule, Ownable {\\n\\t/// @notice Initializes the HousingProject contract.\\n\\t/// @param smartHousingAddr The address of the main SmartHousing contract.\\n\\tconstructor(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) CallsSmartHousing(smartHousingAddr) {\\n\\t\\tprojectSFT = new HousingSFT(name, symbol);\\n\\t}\\n\\n\\tevent TokenIssued(address tokenAddress, string name, uint256 amountRaised);\\n\\n\\tfunction setTokenDetails(\\n\\t\\tuint256 amountRaised,\\n\\t\\taddress housingTokenAddr\\n\\t) external onlyOwner {\\n\\t\\trequire(amountRaised == 0, \\\"Token details set already\\\");\\n\\n\\t\\thousingToken = ERC20Burnable(housingTokenAddr);\\n\\n\\t\\tprojectSFT.setAmountRaised(amountRaised);\\n\\t\\tstring memory name = projectSFT.name();\\n\\n\\t\\temit TokenIssued(address(projectSFT), name, amountRaised);\\n\\t}\\n\\n\\tfunction getMaxSupply() public view returns (uint256) {\\n\\t\\treturn projectSFT.getMaxSupply();\\n\\t}\\n}\\n\",\"keccak256\":\"0x159e6b338c47a2dacbec1254f582826b5584c338919e6e6908aba986f9a98350\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingSFT.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\n\\nimport \\\"../modules/SFT.sol\\\";\\n\\nstruct HousingAttributes {\\n\\tuint256 rewardsPerShare;\\n\\taddress originalOwner;\\n\\tuint256 tokenWeight;\\n}\\n\\n/// @title Housing SFT\\n/// @notice This contract represents a semi-fungible token (SFT) for housing projects.\\n/// @dev This contract will be inherited by the HousingProject contract.\\ncontract HousingSFT is SFT {\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct HousingSFTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tHousingAttributes attributes;\\n\\t}\\n\\n\\t// FIXME this value should be unique to each contract, should depend on\\n\\t// the total amount expected to raise as it determines the amount of SFTs to\\n\\t// be minted for investors\\n\\tuint256 public constant MAX_SUPPLY = 1_000_000;\\n\\n\\t/// @notice The amount of fungible tokens collected from investors to finance the development of this housing project.\\n\\tuint256 public amountRaised;\\n\\n\\t/// @notice The current amount out of the `MAX_SUPPLY` of tokens minted.\\n\\tuint256 public totalSupply;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tfunction setAmountRaised(uint256 amountRaised_) external onlyOwner {\\n\\t\\tamountRaised = amountRaised_;\\n\\t}\\n\\n\\tmodifier canMint() {\\n\\t\\taddress sftOwner = owner();\\n\\n\\t\\trequire(\\n\\t\\t\\tOwnable(sftOwner).owner() == _msgSender(),\\n\\t\\t\\t\\\"not allowed to mint\\\"\\n\\t\\t);\\n\\n\\t\\t_;\\n\\t}\\n\\n\\t/// @notice Mints SFT tokens for a depositor based on the amount of deposit.\\n\\t/// @param depositAmt The amount of fungible token deposited.\\n\\t/// @param depositor The address of the depositor.\\n\\tfunction mintSFT(\\n\\t\\tuint256 depositAmt,\\n\\t\\taddress depositor,\\n\\t\\tuint256 amount_raised\\n\\t) external canMint returns (uint256) {\\n\\t\\t// TODO remove after demo due to not beign able to move blocks in public networks\\n\\t\\t{\\n\\t\\t\\tamountRaised = amount_raised;\\n\\t\\t}\\n\\n\\t\\tuint256 totalDeposits = amountRaised;\\n\\t\\tuint256 maxShares = MAX_SUPPLY;\\n\\n\\t\\trequire(totalDeposits > 0, \\\"HousingSFT: No deposits recorded\\\");\\n\\n\\t\\tuint256 mintShare = (depositAmt * maxShares) / totalDeposits;\\n\\t\\trequire(mintShare > 0, \\\"HousingSFT: Computed token shares is invalid\\\");\\n\\n\\t\\ttotalSupply += mintShare;\\n\\t\\trequire(totalSupply <= MAX_SUPPLY, \\\"HousingSFT: Max supply exceeded\\\");\\n\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tHousingAttributes({\\n\\t\\t\\t\\trewardsPerShare: 0, // Should be 0 since they have never claimed any rent rewards\\n\\t\\t\\t\\toriginalOwner: depositor,\\n\\t\\t\\t\\ttokenWeight: mintShare\\n\\t\\t\\t})\\n\\t\\t);\\n\\n\\t\\treturn _mint(depositor, mintShare, attributes, \\\"\\\");\\n\\t}\\n\\n\\t/// @notice Checks if an address owns this HousingSFT and returns the attributes.\\n\\t/// @param owner The address to check the balance of.\\n\\t/// @return `HousingAttributes` if the owner has a positive balance of the token, panics otherwise.\\n\\tfunction getUserSFT(\\n\\t\\taddress owner,\\n\\t\\tuint256 nonce\\n\\t) public view returns (HousingAttributes memory) {\\n\\t\\trequire(\\n\\t\\t\\thasSFT(owner, nonce),\\n\\t\\t\\t\\\"HouisingSFT: No tokens found for user at nonce\\\"\\n\\t\\t);\\n\\n\\t\\treturn abi.decode(getRawTokenAttributes(nonce), (HousingAttributes));\\n\\t}\\n\\n\\tfunction getMaxSupply() public pure returns (uint256) {\\n\\t\\treturn MAX_SUPPLY;\\n\\t}\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (HousingSFTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tHousingSFTBalance[] memory balance = new HousingSFTBalance[](\\n\\t\\t\\t_sftBals.length\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = HousingSFTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(_sftBal.attributes, (HousingAttributes))\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\tfunction tokenDetails()\\n\\t\\tpublic\\n\\t\\tview\\n\\t\\treturns (string memory, string memory, uint256)\\n\\t{\\n\\t\\treturn (name(), symbol(), getMaxSupply());\\n\\t}\\n}\\n\",\"keccak256\":\"0x8fbbe8d670bc777eed8587d0a8b11acf1d7b40b9ae631fee4abc929f4275c160\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/NewHousingProjectLib.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport { HousingProject } from \\\"./HousingProject.sol\\\";\\n\\nlibrary NewHousingProject {\\n\\tfunction create(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) external returns (HousingProject) {\\n\\t\\treturn new HousingProject(name, symbol, smartHousingAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0x0ad286112bdc35e59e9424ffda000b7b6b582e228cca1cafc2b9cab28193628f\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/RentsModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\\\";\\n\\nimport \\\"./HousingSFT.sol\\\";\\nimport \\\"./RewardSharing.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"./CallsSmartHousing.sol\\\";\\n\\n/// @title Rents Module\\n/// @notice Handles rent payments, reward calculations, and distribution for Housing projects.\\n/// @dev This abstract contract should be inherited by the HousingProject contract.\\nabstract contract RentsModule is CallsSmartHousing {\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\tusing RewardShares for rewardshares;\\n\\n\\tuint256 public rewardPerShare;\\n\\tuint256 public rewardsReserve;\\n\\tuint256 public facilityManagementFunds;\\n\\n\\tERC20Burnable housingToken;\\n\\tHousingSFT public projectSFT;\\n\\n\\t/// @notice Receives rent payments and distributes rewards.\\n\\t/// @param rentPayment The details of the rent payment.\\n\\tfunction receiveRent(ERC20TokenPayment calldata rentPayment) external {\\n\\t\\t// TODO set the appropriate rent per Project\\n\\t\\trequire(\\n\\t\\t\\trentPayment.amount > 0,\\n\\t\\t\\t\\\"RentsModule: Insufficient rent amount\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\trentPayment.token == housingToken,\\n\\t\\t\\t\\\"RentsModule: Invalid rent payment token\\\"\\n\\t\\t);\\n\\t\\trentPayment.receiveERC20();\\n\\n\\t\\tuint256 rentReward = (rentPayment.amount * 75) / 100;\\n\\t\\tuint256 ecosystemReward = (rentPayment.amount * 18) / 100;\\n\\t\\tuint256 facilityReward = (rentPayment.amount * 7) / 100;\\n\\n\\t\\tuint256 allShares = projectSFT.getMaxSupply();\\n\\t\\tuint256 rpsIncrease = (rentReward * DIVISION_SAFETY_CONST) / allShares;\\n\\n\\t\\trewardPerShare += rpsIncrease;\\n\\t\\trewardsReserve += rentReward;\\n\\t\\tfacilityManagementFunds += facilityReward;\\n\\n\\t\\thousingToken.burn(ecosystemReward);\\n\\t\\tISmartHousing(smartHousingAddr).addProjectRent(rentPayment.amount);\\n\\t}\\n\\n\\t/// @notice Claims rent rewards for a given token.\\n\\t/// @return The updated HousingAttributes.\\n\\tfunction claimRentReward(\\n\\t\\tuint256 nonce\\n\\t) external returns (HousingAttributes memory, rewardshares memory) {\\n\\t\\taddress caller = msg.sender;\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tHousingAttributes memory attr = projectSFT.getUserSFT(caller, nonce);\\n\\t\\trewardshares memory rewardShares = computeRewardShares(attr);\\n\\t\\tuint256 totalReward = rewardShares.total();\\n\\n\\t\\tif (totalReward == 0) {\\n\\t\\t\\t// Fail silently\\n\\t\\t\\treturn (attr, rewardShares);\\n\\t\\t}\\n\\n\\t\\trequire(rewardsReserve >= totalReward, \\\"Computed rewards too large\\\");\\n\\n\\t\\trewardsReserve -= totalReward;\\n\\n\\t\\t// We use original owner since we are certain they are registered\\n\\t\\t(, address referrer) = getReferrer(attr.originalOwner);\\n\\t\\tif (rewardShares.referrerValue > 0) {\\n\\t\\t\\tif (referrer != address(0)) {\\n\\t\\t\\t\\thousingToken.transfer(referrer, rewardShares.referrerValue); // Send to referrer\\n\\t\\t\\t} else {\\n\\t\\t\\t\\thousingToken.burn(rewardShares.referrerValue); // Burn to add to ecosystem reward\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tattr.rewardsPerShare = currentRPS;\\n\\n\\t\\tprojectSFT.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tprojectSFT.balanceOf(caller, nonce),\\n\\t\\t\\tabi.encode(attr)\\n\\t\\t);\\n\\n\\t\\thousingToken.transfer(caller, rewardShares.userValue); // Send to user\\n\\n\\t\\treturn (attr, rewardShares);\\n\\t}\\n\\n\\t/// @notice Computes the amount of rent claimable for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The amount of rent claimable.\\n\\tfunction rentClaimable(\\n\\t\\tHousingAttributes memory attr\\n\\t) public view returns (uint256) {\\n\\t\\treturn computeRewardShares(attr).userValue;\\n\\t}\\n\\n\\t/// @dev Computes the reward shares for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The computed RewardShares.\\n\\tfunction computeRewardShares(\\n\\t\\tHousingAttributes memory attr\\n\\t) internal view returns (rewardshares memory) {\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tif (currentRPS == 0 || attr.rewardsPerShare >= currentRPS) {\\n\\t\\t\\treturn rewardshares({ userValue: 0, referrerValue: 0 });\\n\\t\\t}\\n\\n\\t\\tuint256 reward = computeReward(attr, currentRPS);\\n\\n\\t\\treturn splitReward(reward);\\n\\t}\\n}\\n\",\"keccak256\":\"0xe97c64b7d4f5a945493aa8492c4412248f60ec1e6e8cd74e3f805e40cc672768\",\"license\":\"MIT\"},\"contracts/housing-project/RewardSharing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"./HousingSFT.sol\\\";\\n\\nuint256 constant DIVISION_SAFETY_CONST = 1_000_000_000_000_000_000;\\n\\nstruct rewardshares {\\n\\tuint256 userValue;\\n\\tuint256 referrerValue;\\n}\\n\\nlibrary RewardShares {\\n\\tfunction total(rewardshares memory self) internal pure returns (uint256) {\\n\\t\\treturn self.userValue + self.referrerValue;\\n\\t}\\n}\\n\\nfunction splitReward(uint256 reward) pure returns (rewardshares memory) {\\n\\tuint256 referrerValue = (reward * 6_66) / 100_00; // would amount to approximately 5% of grand total\\n\\tuint256 userValue = reward - referrerValue;\\n\\n\\treturn rewardshares(userValue, referrerValue);\\n}\\n\\nfunction computeReward(\\n\\tHousingAttributes memory attr,\\n\\tuint256 contractRPS\\n) pure returns (uint256) {\\n\\tif (contractRPS <= attr.rewardsPerShare) {\\n\\t\\treturn 0;\\n\\t}\\n\\n\\treturn\\n\\t\\t((contractRPS - attr.rewardsPerShare) * attr.tokenWeight) /\\n\\t\\tDIVISION_SAFETY_CONST;\\n}\\n\",\"keccak256\":\"0x9f07d2b3ee49b91e12ad7ce9ba248ab7dd30bc2efc4238a594e681d3f0348e54\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/lib/LkSHTAttributes.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title LkSHTAttributes\\n * @dev Library for handling attributes and unlocking of the Locked SmartHousing Token.\\n */\\nlibrary LkSHTAttributes {\\n\\tusing SafeMath for uint256;\\n\\n\\t// TODO use this for mainnet uint256 constant LOCK_DURATION = 3 * 365 days; // 3 years\\n\\tuint256 constant LOCK_DURATION = 5 hours;\\n\\n\\tstruct Attributes {\\n\\t\\tuint256 initialAmount;\\n\\t\\tuint256 amount;\\n\\t\\tuint256 startTimestamp;\\n\\t\\tuint256 endTimestamp;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Creates new attributes for a Locked SmartHousing Token.\\n\\t * @param startTimestamp The start time of the lock.\\n\\t * @param amount The amount of SmartHousing Tokens locked.\\n\\t * @return attributes The initialized attributes.\\n\\t */\\n\\tfunction newAttributes(\\n\\t\\tuint256 startTimestamp,\\n\\t\\tuint256 amount\\n\\t) internal pure returns (Attributes memory) {\\n\\t\\treturn\\n\\t\\t\\tAttributes({\\n\\t\\t\\t\\tinitialAmount: amount,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tstartTimestamp: startTimestamp,\\n\\t\\t\\t\\tendTimestamp: startTimestamp.add(LOCK_DURATION)\\n\\t\\t\\t});\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calculates and deducts the unlocked amount based on the elapsed time.\\n\\t * @param self The attributes to update.\\n\\t * @return unlockedAmount The amount of tokens unlocked.\\n\\t */\\n\\tfunction unlockMatured(\\n\\t\\tAttributes memory self\\n\\t)\\n\\t\\tinternal\\n\\t\\tview\\n\\t\\treturns (uint256 unlockedAmount, Attributes memory newSelf)\\n\\t{\\n\\t\\tuint256 elapsed = elapsedTime(self);\\n\\t\\tunlockedAmount = self.amount.mul(elapsed).div(LOCK_DURATION);\\n\\n\\t\\tself.amount = self.amount.sub(unlockedAmount);\\n\\t\\tnewSelf = self;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calculates the elapsed time since the lock started.\\n\\t * @param self The attributes to use.\\n\\t * @return elapsedTime The elapsed time in seconds.\\n\\t */\\n\\tfunction elapsedTime(\\n\\t\\tAttributes memory self\\n\\t) internal view returns (uint256) {\\n\\t\\tuint256 currentTime = block.timestamp;\\n\\t\\tif (currentTime >= self.endTimestamp) {\\n\\t\\t\\treturn LOCK_DURATION;\\n\\t\\t} else {\\n\\t\\t\\treturn currentTime.sub(self.startTimestamp);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0xbaf851bef9603c72b3cce96d93f8f243f36187d31c8c94233101d802b9ae129d\",\"license\":\"MIT\"},\"contracts/lib/ProjectStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport \\\"./TokenPayments.sol\\\";\\n\\nlibrary ProjectStorage {\\n\\tusing SafeMath for uint256;\\n\\tusing TokenPayments for TokenPayment;\\n\\tusing ProjectStorage for Data;\\n\\n\\tenum Status {\\n\\t\\tFundingPeriod,\\n\\t\\tSuccessful,\\n\\t\\tFailed\\n\\t}\\n\\n\\tstruct Data {\\n\\t\\tuint256 id; // Unique identifier for the project\\n\\t\\taddress tokenAddress;\\n\\t\\taddress projectAddress; // Address of the deployed HousingProject contract\\n\\t\\tuint256 fundingGoal; // Target funding amount for the project\\n\\t\\tuint256 fundingDeadline; // Deadline timestamp for the project funding\\n\\t\\taddress fundingToken; // Address of the ERC20 token used for funding\\n\\t\\tuint256 collectedFunds; // Amount of funds collected for the project\\n\\t}\\n\\n\\tfunction status(Data storage self) internal view returns (Status) {\\n\\t\\tif (self.collectedFunds >= self.fundingGoal) {\\n\\t\\t\\treturn Status.Successful;\\n\\t\\t} else if (block.timestamp < self.fundingDeadline) {\\n\\t\\t\\treturn Status.FundingPeriod;\\n\\t\\t} else {\\n\\t\\t\\treturn Status.Failed;\\n\\t\\t}\\n\\t}\\n\\n\\tfunction createNew(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage projectsId,\\n\\t\\tuint256 projectCount,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline,\\n\\t\\taddress fundingToken,\\n\\t\\taddress projectAddress,\\n\\t\\taddress tokenAddress\\n\\t) internal returns (Data memory) {\\n\\t\\trequire(fundingGoal > 0, \\\"Funding goal must be more than 0\\\");\\n\\t\\trequire(\\n\\t\\t\\tfundingDeadline > block.timestamp,\\n\\t\\t\\t\\\"Deadline can't be in the past\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 newId = projectCount.add(1);\\n\\n\\t\\tData memory newProjectData = Data({\\n\\t\\t\\tid: newId,\\n\\t\\t\\tprojectAddress: projectAddress,\\n\\t\\t\\tfundingGoal: fundingGoal,\\n\\t\\t\\tfundingDeadline: fundingDeadline,\\n\\t\\t\\tfundingToken: fundingToken,\\n\\t\\t\\tcollectedFunds: 0,\\n\\t\\t\\ttokenAddress: tokenAddress\\n\\t\\t});\\n\\n\\t\\tprojects[newId] = newProjectData;\\n\\t\\tprojectsId[newProjectData.projectAddress] = newProjectData.id;\\n\\n\\t\\treturn newProjectData;\\n\\t}\\n\\n\\tfunction fund(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage usersDeposit,\\n\\t\\tuint256 projectId,\\n\\t\\taddress depositor,\\n\\t\\tTokenPayment calldata payment\\n\\t) internal {\\n\\t\\trequire(payment.amount > 0, \\\"Invalid funding amount\\\");\\n\\n\\t\\tData storage project = projects[projectId];\\n\\n\\t\\trequire(\\n\\t\\t\\tproject.status() == Status.FundingPeriod,\\n\\t\\t\\t\\\"Cannot fund project after deadline\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\taddress(payment.token) == project.fundingToken,\\n\\t\\t\\t\\\"Wrong token payment\\\"\\n\\t\\t);\\n\\t\\tpayment.receiveToken();\\n\\n\\t\\tproject.collectedFunds = project.collectedFunds.add(payment.amount);\\n\\t\\tusersDeposit[depositor] = usersDeposit[depositor].add(payment.amount);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Retrieves and updates the user's deposit for a specific project.\\n\\t * @param projectId The ID of the project to retrieve the deposit for.\\n\\t * @param depositor The address of the depositor.\\n\\t * @return (ProjectStorage.Data, uint256) The project data and deposit amount.\\n\\t */\\n\\tfunction takeDeposit(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage usersDeposit,\\n\\t\\tuint256 projectId,\\n\\t\\taddress depositor\\n\\t) internal returns (ProjectStorage.Data memory, uint256) {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\trequire(project.id != 0, \\\"Invalid project ID\\\");\\n\\t\\trequire(\\n\\t\\t\\tproject.status() == Status.Successful,\\n\\t\\t\\t\\\"Project not yet successful\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 depositAmount = usersDeposit[depositor];\\n\\t\\trequire(depositAmount > 0, \\\"No deposit found\\\");\\n\\n\\t\\t// Update the deposit amount to zero\\n\\t\\tusersDeposit[depositor] = 0;\\n\\n\\t\\treturn (project, depositAmount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x652aab2dc03764c430b91f35e908430208d6a1bd27a4cc8060adb1ec7f249ad5\",\"license\":\"MIT\"},\"contracts/lib/TokenPayments.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/interfaces/IERC20.sol\\\";\\nimport { SFT } from \\\"../modules/SFT.sol\\\";\\n\\nstruct ERC20TokenPayment {\\n\\tIERC20 token;\\n\\tuint256 amount;\\n}\\n\\nstruct TokenPayment {\\n\\taddress token;\\n\\tuint256 amount;\\n\\tuint256 nonce;\\n}\\n\\nlibrary TokenPayments {\\n\\tfunction accept(ERC20TokenPayment calldata self) internal {\\n\\t\\tTokenPayments.receiveERC20(self, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(ERC20TokenPayment calldata payment) internal {\\n\\t\\tTokenPayments.receiveERC20(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(\\n\\t\\tERC20TokenPayment calldata payment,\\n\\t\\taddress from\\n\\t) internal {\\n\\t\\tpayment.token.transferFrom(from, address(this), payment.amount);\\n\\t}\\n\\n\\t// Receives both Native, SFTs and ERC20; ERC20 have nonce as 0, Native coins have address 0 as token value\\n\\tfunction receiveToken(TokenPayment memory payment) internal {\\n\\t\\treceiveToken(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveToken(TokenPayment memory payment, address from) internal {\\n\\t\\tif (payment.token == address(0)) {\\n\\t\\t\\t// Native payment\\n\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tpayment.amount == msg.value,\\n\\t\\t\\t\\t\\\"expected payment amount must equal sent amount\\\"\\n\\t\\t\\t);\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tfrom == msg.sender,\\n\\t\\t\\t\\t\\\"can receive native payment only from caller\\\"\\n\\t\\t\\t);\\n\\t\\t\\t\\n\\t\\t\\t// Nothing to do again since the VM will handle balance movements\\n\\t\\t} else if (payment.nonce == 0) {\\n\\t\\t\\tIERC20(payment.token).transferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.amount\\n\\t\\t\\t);\\n\\t\\t} else {\\n\\t\\t\\tSFT(payment.token).safeTransferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.nonce,\\n\\t\\t\\t\\tpayment.amount,\\n\\t\\t\\t\\t\\\"\\\"\\n\\t\\t\\t);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x06bd73e8da1bde18d9aaf6d4b6a1bdec6e0718af6354fe2d7ce87251d6fd1ac5\",\"license\":\"MIT\"},\"contracts/main/Interface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"../lib/TokenPayments.sol\\\";\\n\\ninterface ISmartHousing {\\n\\tfunction addProjectRent(uint256 amount) external;\\n\\n\\tfunction createRefIDViaProxy(\\n\\t\\taddress userAddr,\\n\\t\\tuint256 referrerId\\n\\t) external returns (uint256);\\n\\n\\tfunction addProject(address projectAddress) external;\\n\\n\\tfunction setUpSHT(ERC20TokenPayment calldata payment) external;\\n}\\n\\ninterface IUserModule {\\n\\tfunction getReferrer(address user) external view returns (uint, address);\\n}\\n\",\"keccak256\":\"0x066719eed5c5ff2394d78ce027aada5a8555713c9f4abf8b5135975981ba9989\",\"license\":\"MIT\"},\"contracts/modules/LockedSmartHousingToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport \\\"../lib/LkSHTAttributes.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"../modules/SFT.sol\\\";\\n\\nlibrary NewLkSHT {\\n\\tfunction create() external returns (LkSHT) {\\n\\t\\treturn new LkSHT(\\\"Locked Housing Token\\\", \\\"LkSHT\\\");\\n\\t}\\n}\\n\\n/**\\n * @title LockedSmartHousingToken\\n * @dev SFT token that locks SmartHousing Tokens (SHT) during ICO.\\n * Allows transfers only to whitelisted addresses.\\n */\\ncontract LkSHT is SFT {\\n\\tusing SafeMath for uint256;\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\n\\tstruct LkSHTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tLkSHTAttributes.Attributes attributes;\\n\\t}\\n\\n\\tuint256 immutable startTimestamp = block.timestamp;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tevent TokensMinted(address indexed to, uint256 amount);\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (LkSHTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tLkSHTBalance[] memory balance = new LkSHTBalance[](_sftBals.length);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = LkSHTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(\\n\\t\\t\\t\\t\\t_sftBal.attributes,\\n\\t\\t\\t\\t\\t(LkSHTAttributes.Attributes)\\n\\t\\t\\t\\t)\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Mints new Locked SmartHousing Tokens (LkSHT) by locking SHT.\\n\\t * @param amount The amount of SHT to lock.\\n\\t * @param to The address to mint the tokens to.\\n\\t */\\n\\tfunction mint(uint256 amount, address to) external onlyOwner {\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tLkSHTAttributes.newAttributes(startTimestamp, amount)\\n\\t\\t);\\n\\n\\t\\tsuper._mint(to, amount, attributes, \\\"LockedSmartHousingToken\\\");\\n\\n\\t\\temit TokensMinted(to, amount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x33e840a42e8bab335538d2ab9a8973c97423b17caac5fd50a802b53f6db7357d\",\"license\":\"MIT\"},\"contracts/modules/SFT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Counters.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n// TODO I think we should create a standard of this\\nabstract contract SFT is ERC1155, Ownable {\\n\\tusing Counters for Counters.Counter;\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct SftBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tbytes attributes;\\n\\t}\\n\\n\\tCounters.Counter private _nonceCounter;\\n\\tstring private _name;\\n\\tstring private _symbol;\\n\\n\\t// Mapping from nonce to token attributes as bytes\\n\\tmapping(uint256 => bytes) private _tokenAttributes;\\n\\n\\t// Mapping from address to list of owned token nonces\\n\\tmapping(address => EnumerableSet.UintSet) private _addressToNonces;\\n\\n\\tconstructor(string memory name_, string memory symbol_) ERC1155(\\\"\\\") {\\n\\t\\t_name = name_;\\n\\t\\t_symbol = symbol_;\\n\\t}\\n\\n\\t// Private function to mint new tokens\\n\\tfunction _mint(\\n\\t\\taddress to,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attributes,\\n\\t\\tbytes memory data\\n\\t) internal returns (uint256) {\\n\\t\\t_nonceCounter.increment();\\n\\t\\tuint256 nonce = _nonceCounter.current();\\n\\n\\t\\t// Store the attributes\\n\\t\\t_tokenAttributes[nonce] = attributes;\\n\\n\\t\\t// Mint the token with the nonce as its ID\\n\\t\\tsuper._mint(to, nonce, amount, data);\\n\\n\\t\\t// Track the nonce for the address\\n\\t\\t_addressToNonces[to].add(nonce);\\n\\n\\t\\treturn nonce;\\n\\t}\\n\\n\\tfunction name() public view returns (string memory) {\\n\\t\\treturn _name;\\n\\t}\\n\\n\\tfunction symbol() public view returns (string memory) {\\n\\t\\treturn _symbol;\\n\\t}\\n\\n\\tfunction tokenInfo() public view returns (string memory, string memory) {\\n\\t\\treturn (_name, _symbol);\\n\\t}\\n\\n\\t// Function to get token attributes by nonce\\n\\tfunction getRawTokenAttributes(\\n\\t\\tuint256 nonce\\n\\t) public view returns (bytes memory) {\\n\\t\\treturn _tokenAttributes[nonce];\\n\\t}\\n\\n\\t// Function to get list of nonces owned by an address\\n\\tfunction getNonces(address owner) public view returns (uint256[] memory) {\\n\\t\\treturn _addressToNonces[owner].values();\\n\\t}\\n\\n\\tfunction hasSFT(address owner, uint256 nonce) public view returns (bool) {\\n\\t\\treturn _addressToNonces[owner].contains(nonce);\\n\\t}\\n\\n\\t/// Burns all the NFT balance of user at nonce, creates new with balance and attributes\\n\\tfunction update(\\n\\t\\taddress user,\\n\\t\\tuint256 nonce,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attr\\n\\t) external onlyOwner {\\n\\t\\t_burn(user, nonce, amount);\\n\\t\\t_mint(user, amount, attr, \\\"\\\");\\n\\t}\\n\\n\\tfunction _sftBalance(\\n\\t\\taddress user\\n\\t) internal view returns (SftBalance[] memory) {\\n\\t\\tuint256[] memory nonces = getNonces(user);\\n\\t\\tSftBalance[] memory balance = new SftBalance[](nonces.length);\\n\\n\\t\\tfor (uint256 i; i < nonces.length; i++) {\\n\\t\\t\\tuint256 nonce = nonces[i];\\n\\t\\t\\tbytes memory attributes = _tokenAttributes[nonce];\\n\\t\\t\\tuint256 amount = balanceOf(user, nonce);\\n\\n\\t\\t\\tbalance[i] = SftBalance({\\n\\t\\t\\t\\tnonce: nonce,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tattributes: attributes\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t// Override _beforeTokenTransfer to handle address-to-nonce mapping\\n\\tfunction _beforeTokenTransfer(\\n\\t\\taddress operator,\\n\\t\\taddress from,\\n\\t\\taddress to,\\n\\t\\tuint256[] memory ids,\\n\\t\\tuint256[] memory amounts,\\n\\t\\tbytes memory data\\n\\t) internal virtual override {\\n\\t\\tsuper._beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[from].remove(ids[i]);\\n\\t\\t}\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[to].add(ids[i]);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x8098c36137bbb9a342d16fd64f7d57c03a77841a872dd44641b9db1623a699aa\",\"license\":\"MIT\"},\"contracts/modules/sht-module/SHT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nlibrary SHT {\\n\\tuint256 public constant DECIMALS = 18;\\n\\tuint256 public constant ONE = 10 ** DECIMALS;\\n\\tuint256 public constant MAX_SUPPLY = 21_000_000 * ONE;\\n\\tuint256 public constant ECOSYSTEM_DISTRIBUTION_FUNDS =\\n\\t\\t(13_650_000 * ONE) + 2_248_573_618_499_339;\\n\\tuint256 public constant ICO_FUNDS =\\n\\t\\tMAX_SUPPLY - ECOSYSTEM_DISTRIBUTION_FUNDS;\\n}\\n\",\"keccak256\":\"0x66b511a7932bd0f6ceea118f9440cac3a6fd470d11e4d7fa337de8b178627dd7\",\"license\":\"MIT\"},\"contracts/project-funding/ProjectFunding.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\\\";\\n\\nimport \\\"../lib/ProjectStorage.sol\\\";\\nimport \\\"../lib/LkSHTAttributes.sol\\\";\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nimport \\\"../modules/LockedSmartHousingToken.sol\\\";\\nimport \\\"../modules/sht-module/SHT.sol\\\";\\n\\nimport { HousingSFT } from \\\"../housing-project/HousingSFT.sol\\\";\\nimport { TokenPayment } from \\\"../lib/TokenPayments.sol\\\";\\nimport { NewHousingProject, HousingProject } from \\\"../housing-project/NewHousingProjectLib.sol\\\";\\n\\n/**\\n * @title ProjectFunding\\n * @dev This contract is used for initializing and deploying housing projects.\\n * It allows the deployment of a new housing project and manages project data.\\n */\\ncontract ProjectFunding is Ownable {\\n\\tusing SafeMath for uint256;\\n\\tusing ProjectStorage for mapping(uint256 => ProjectStorage.Data);\\n\\tusing ProjectStorage for ProjectStorage.Data;\\n\\tusing LkSHTAttributes for LkSHTAttributes.Attributes;\\n\\n\\taddress public coinbase; // Address authorized to initialize the first project, also the housingToken\\n\\taddress public smartHousingAddress; // Address of the SmartHousing contract\\n\\n\\tmapping(uint256 => ProjectStorage.Data) public projects; // Mapping of project ID to ProjectData\\n\\tmapping(address => uint256) public projectsId; // Mapping of project address to project ID\\n\\tuint256 public projectCount; // Counter for the total number of projects\\n\\n\\tmapping(uint256 => mapping(address => uint256)) public usersProjectDeposit;\\n\\n\\tIERC20 public housingToken; // Token used for funding projects\\n\\tLkSHT public lkSht; // The locked version\\n\\n\\t/**\\n\\t * @dev Emitted when a new project is deployed.\\n\\t * @param projectAddress Address of the newly deployed HousingProject contract.\\n\\t */\\n\\tevent ProjectDeployed(address indexed projectAddress);\\n\\tevent ProjectFunded(\\n\\t\\tuint256 indexed projectId,\\n\\t\\taddress indexed depositor,\\n\\t\\tTokenPayment payment\\n\\t);\\n\\tevent ProjectTokensClaimed(\\n\\t\\taddress indexed depositor,\\n\\t\\tuint256 projectId,\\n\\t\\tuint256 amount\\n\\t);\\n\\n\\t/**\\n\\t * @param _coinbase Address authorized to initialize the first project.\\n\\t */\\n\\tconstructor(address _coinbase) {\\n\\t\\tcoinbase = _coinbase;\\n\\t\\tlkSht = NewLkSHT.create();\\n\\t}\\n\\n\\t/**\\n\\t * @dev Internal function to deploy a new HousingProject contract.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction _deployProject(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) internal {\\n\\t\\tHousingProject newProject = NewHousingProject.create(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tsmartHousingAddress\\n\\t\\t);\\n\\t\\tProjectStorage.Data memory projectData = projects.createNew(\\n\\t\\t\\tprojectsId,\\n\\t\\t\\tprojectCount,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\taddress(newProject),\\n\\t\\t\\taddress(newProject.projectSFT())\\n\\t\\t);\\n\\t\\tprojectCount = projectData.id;\\n\\n\\t\\temit ProjectDeployed(projectData.projectAddress);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Initializes the first project.\\n\\t * This function must be called by the coinbase address and can only be called once.\\n\\t * It sets up the token and deploys the first project.\\n\\t * @param shtPayment Payment details for the Smart Housing Token (SHT).\\n\\t * @param smartHousingAddress_ Address of the Smart Housing contract.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction initFirstProject(\\n\\t\\tERC20TokenPayment calldata shtPayment,\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddress_,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) external {\\n\\t\\trequire(msg.sender == coinbase, \\\"Caller is not the coinbase\\\");\\n\\t\\trequire(projectCount == 0, \\\"Project already initialized\\\");\\n\\n\\t\\tTokenPayments.receiveERC20(shtPayment);\\n\\t\\thousingToken = shtPayment.token;\\n\\n\\t\\tsmartHousingAddress = smartHousingAddress_;\\n\\n\\t\\t_deployProject(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Deploys a new project.\\n\\t * This function can be called multiple times to deploy additional projects.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction deployProject(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) public onlyOwner {\\n\\t\\t_deployProject(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\tfunction fundProject(\\n\\t\\tTokenPayment calldata depositPayment,\\n\\t\\tuint256 projectId,\\n\\t\\tuint256 referrerId\\n\\t) external payable {\\n\\t\\trequire(\\n\\t\\t\\tprojectId > 0 && projectId <= projectCount,\\n\\t\\t\\t\\\"Invalid project ID\\\"\\n\\t\\t);\\n\\n\\t\\taddress depositor = msg.sender;\\n\\n\\t\\t// Register user with referrer (if needed)\\n\\t\\tISmartHousing(smartHousingAddress).createRefIDViaProxy(\\n\\t\\t\\tdepositor,\\n\\t\\t\\treferrerId\\n\\t\\t);\\n\\n\\t\\t// Update project funding\\n\\t\\tprojects.fund(\\n\\t\\t\\tusersProjectDeposit[projectId],\\n\\t\\t\\tprojectId,\\n\\t\\t\\tdepositor,\\n\\t\\t\\tdepositPayment\\n\\t\\t);\\n\\n\\t\\temit ProjectFunded(projectId, depositor, depositPayment);\\n\\t}\\n\\n\\tfunction setProjectToken(uint256 projectId) external onlyOwner {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\n\\t\\t// TODO Add this after demo\\n\\t\\t// require(\\n\\t\\t// \\tproject.status() == ProjectStorage.Status.Successful,\\n\\t\\t// \\t\\\"Project Funding not yet successful\\\"\\n\\t\\t// );\\n\\n\\t\\tISmartHousing(smartHousingAddress).addProject(project.projectAddress);\\n\\n\\t\\tHousingProject(project.projectAddress).setTokenDetails(\\n\\t\\t\\tproject.collectedFunds,\\n\\t\\t\\tcoinbase\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Claims project tokens for a given project ID.\\n\\t * @param projectId The ID of the project to claim tokens from.\\n\\t */\\n\\tfunction claimProjectTokens(uint256 projectId) external {\\n\\t\\taddress depositor = msg.sender;\\n\\n\\t\\t// Retrieve the project and deposit amount\\n\\t\\t(ProjectStorage.Data memory project, uint256 depositAmount) = projects\\n\\t\\t\\t.takeDeposit(usersProjectDeposit[projectId], projectId, depositor);\\n\\n\\t\\tHousingSFT(project.tokenAddress).mintSFT(\\n\\t\\t\\tdepositAmount,\\n\\t\\t\\tdepositor,\\n\\t\\t\\tproject.collectedFunds\\n\\t\\t);\\n\\n\\t\\t// Mint LkSHT tokens if the project ID is 1\\n\\t\\tif (project.id == 1) {\\n\\t\\t\\tuint256 shtAmount = depositAmount.mul(SHT.ICO_FUNDS).div(\\n\\t\\t\\t\\tproject.collectedFunds\\n\\t\\t\\t);\\n\\n\\t\\t\\tlkSht.mint(shtAmount, depositor);\\n\\t\\t}\\n\\n\\t\\temit ProjectTokensClaimed(depositor, projectId, depositAmount);\\n\\t}\\n\\n\\tfunction unlockSHT(uint256 nonce) external {\\n\\t\\taddress caller = msg.sender;\\n\\n\\t\\tuint256 lkShtBal = lkSht.balanceOf(caller, nonce);\\n\\t\\trequire(lkShtBal > 0, \\\"ProjectFunding: Nothing to unlock\\\");\\n\\n\\t\\tLkSHTAttributes.Attributes memory attr = abi.decode(\\n\\t\\t\\tlkSht.getRawTokenAttributes(nonce),\\n\\t\\t\\t(LkSHTAttributes.Attributes)\\n\\t\\t);\\n\\t\\t(\\n\\t\\t\\tuint256 totalUnlockedAmount,\\n\\t\\t\\tLkSHTAttributes.Attributes memory newAttr\\n\\t\\t) = attr.unlockMatured();\\n\\n\\t\\tlkSht.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tlkShtBal.sub(totalUnlockedAmount),\\n\\t\\t\\tabi.encode(newAttr)\\n\\t\\t);\\n\\n\\t\\t// Transfer the total unlocked SHT tokens to the user's address\\n\\t\\tif (totalUnlockedAmount > 0) {\\n\\t\\t\\thousingToken.transfer(caller, totalUnlockedAmount);\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns an array of all project IDs and their associated data.\\n\\t * @return projectList An array of tuples containing project details.\\n\\t */\\n\\tfunction allProjects() public view returns (ProjectStorage.Data[] memory) {\\n\\t\\tProjectStorage.Data[] memory projectList = new ProjectStorage.Data[](\\n\\t\\t\\tprojectCount\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i = 1; i <= projectCount; i++) {\\n\\t\\t\\tprojectList[i - 1] = projects[i];\\n\\t\\t}\\n\\n\\t\\treturn projectList;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns the address of the HousingProject contract for a given project ID.\\n\\t * @param projectId The ID of the project.\\n\\t * @return projectAddress The address of the HousingProject contract.\\n\\t */\\n\\tfunction getProjectAddress(\\n\\t\\tuint256 projectId\\n\\t) external view returns (address projectAddress) {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\treturn project.projectAddress;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns the details of a project by its ID.\\n\\t * @param projectId The ID of the project.\\n\\t * @return id The project ID.\\n\\t * @return fundingGoal The funding goal of the project.\\n\\t * @return fundingDeadline The deadline for the project funding.\\n\\t * @return fundingToken The address of the ERC20 token used for funding.\\n\\t * @return projectAddress The address of the HousingProject contract.\\n\\t * @return status The funding status of the project.\\n\\t * @return collectedFunds The amount of funds collected.\\n\\t */\\n\\tfunction getProjectData(\\n\\t\\tuint256 projectId\\n\\t)\\n\\t\\texternal\\n\\t\\tview\\n\\t\\treturns (\\n\\t\\t\\tuint256 id,\\n\\t\\t\\tuint256 fundingGoal,\\n\\t\\t\\tuint256 fundingDeadline,\\n\\t\\t\\taddress fundingToken,\\n\\t\\t\\taddress projectAddress,\\n\\t\\t\\tuint8 status,\\n\\t\\t\\tuint256 collectedFunds\\n\\t\\t)\\n\\t{\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\treturn (\\n\\t\\t\\tproject.id,\\n\\t\\t\\tproject.fundingGoal,\\n\\t\\t\\tproject.fundingDeadline,\\n\\t\\t\\tproject.fundingToken,\\n\\t\\t\\tproject.projectAddress,\\n\\t\\t\\tuint8(project.status()),\\n\\t\\t\\tproject.collectedFunds\\n\\t\\t);\\n\\t}\\n}\\n\",\"keccak256\":\"0xba3518a6288e777e4b2b51d944cbc298200458d0f09f3c5b701f52547991a4e1\",\"license\":\"MIT\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_coinbase\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"projectAddress\",\"type\":\"address\"}],\"name\":\"ProjectDeployed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"struct TokenPayment\",\"name\":\"payment\",\"type\":\"tuple\"}],\"name\":\"ProjectFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProjectTokensClaimed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"allProjects\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"projectAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fundingGoal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingDeadline\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"fundingToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"collectedFunds\",\"type\":\"uint256\"}],\"internalType\":\"struct ProjectStorage.Data[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"}],\"name\":\"claimProjectTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"coinbase\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"fundingToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fundingGoal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingDeadline\",\"type\":\"uint256\"}],\"name\":\"deployProject\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct TokenPayment\",\"name\":\"depositPayment\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"name\":\"fundProject\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"}],\"name\":\"getProjectAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"projectAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"}],\"name\":\"getProjectData\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingGoal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingDeadline\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"fundingToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"projectAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"collectedFunds\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"housingToken\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ERC20TokenPayment\",\"name\":\"shtPayment\",\"type\":\"tuple\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"smartHousingAddress_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fundingToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fundingGoal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingDeadline\",\"type\":\"uint256\"}],\"name\":\"initFirstProject\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lkSht\",\"outputs\":[{\"internalType\":\"contract LkSHT\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"projectCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"projects\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"projectAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fundingGoal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fundingDeadline\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"fundingToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"collectedFunds\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"projectsId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"}],\"name\":\"addProjectToEcosystem\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"smartHousingAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"unlockSHT\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"usersProjectDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract is used for initializing and deploying housing projects. It allows the deployment of a new housing project and manages project data.\",\"events\":{\"ProjectDeployed(address)\":{\"details\":\"Emitted when a new project is deployed.\",\"params\":{\"projectAddress\":\"Address of the newly deployed HousingProject contract.\"}}},\"kind\":\"dev\",\"methods\":{\"allProjects()\":{\"details\":\"Returns an array of all project IDs and their associated data.\",\"returns\":{\"_0\":\"projectList An array of tuples containing project details.\"}},\"claimProjectTokens(uint256)\":{\"details\":\"Claims project tokens for a given project ID.\",\"params\":{\"projectId\":\"The ID of the project to claim tokens from.\"}},\"constructor\":{\"params\":{\"_coinbase\":\"Address authorized to initialize the first project.\"}},\"deployProject(string,string,address,uint256,uint256)\":{\"details\":\"Deploys a new project. This function can be called multiple times to deploy additional projects.\",\"params\":{\"fundingDeadline\":\"The deadline for the project funding.\",\"fundingGoal\":\"The funding goal for the new project.\",\"fundingToken\":\"Address of the ERC20 token used for funding.\"}},\"getProjectAddress(uint256)\":{\"details\":\"Returns the address of the HousingProject contract for a given project ID.\",\"params\":{\"projectId\":\"The ID of the project.\"},\"returns\":{\"projectAddress\":\"The address of the HousingProject contract.\"}},\"getProjectData(uint256)\":{\"details\":\"Returns the details of a project by its ID.\",\"params\":{\"projectId\":\"The ID of the project.\"},\"returns\":{\"collectedFunds\":\"The amount of funds collected.\",\"fundingDeadline\":\"The deadline for the project funding.\",\"fundingGoal\":\"The funding goal of the project.\",\"fundingToken\":\"The address of the ERC20 token used for funding.\",\"id\":\"The project ID.\",\"projectAddress\":\"The address of the HousingProject contract.\",\"status\":\"The funding status of the project.\"}},\"initFirstProject((address,uint256),string,string,address,address,uint256,uint256)\":{\"details\":\"Initializes the first project. This function must be called by the coinbase address and can only be called once. It sets up the token and deploys the first project.\",\"params\":{\"fundingDeadline\":\"The deadline for the project funding.\",\"fundingGoal\":\"The funding goal for the new project.\",\"fundingToken\":\"Address of the ERC20 token used for funding.\",\"shtPayment\":\"Payment details for the Smart Housing Token (SHT).\",\"smartHousingAddress_\":\"Address of the Smart Housing contract.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"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.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"ProjectFunding\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/project-funding/ProjectFunding.sol\":\"ProjectFunding\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../token/ERC20/IERC20.sol\\\";\\n\",\"keccak256\":\"0x6ebf1944ab804b8660eb6fc52f9fe84588cee01c2566a69023e59497e7d27f45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0xd917747dc87f189c6779b894f367a028f9dca4be930283cccec8f312966af820\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n // decrementing then incrementing.\\n _balances[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n unchecked {\\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n _balances[account] += amount;\\n }\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n // Overflow not possible: amount <= accountBalance <= totalSupply.\\n _totalSupply -= amount;\\n }\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x4ffc0547c02ad22925310c585c0f166f8759e2648a09e9b489100c42f15dd98d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../ERC20.sol\\\";\\nimport \\\"../../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\\n * tokens and those that they have an allowance for, in a way that can be\\n * recognized off-chain (via event analysis).\\n */\\nabstract contract ERC20Burnable is Context, ERC20 {\\n /**\\n * @dev Destroys `amount` tokens from the caller.\\n *\\n * See {ERC20-_burn}.\\n */\\n function burn(uint256 amount) public virtual {\\n _burn(_msgSender(), amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, deducting from the caller's\\n * allowance.\\n *\\n * See {ERC20-_burn} and {ERC20-allowance}.\\n *\\n * Requirements:\\n *\\n * - the caller must have allowance for ``accounts``'s tokens of at least\\n * `amount`.\\n */\\n function burnFrom(address account, uint256 amount) public virtual {\\n _spendAllowance(account, _msgSender(), amount);\\n _burn(account, amount);\\n }\\n}\\n\",\"keccak256\":\"0x0d19410453cda55960a818e02bd7c18952a5c8fe7a3036e81f0d599f34487a7b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf96f969e24029d43d0df89e59d365f277021dac62b48e1c1e3ebe0acdd7f1ca1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Counters.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Counters\\n * @author Matt Condon (@shrugs)\\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\\n *\\n * Include with `using Counters for Counters.Counter;`\\n */\\nlibrary Counters {\\n struct Counter {\\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\\n // this feature: see https://github.com/ethereum/solidity/issues/4637\\n uint256 _value; // default: 0\\n }\\n\\n function current(Counter storage counter) internal view returns (uint256) {\\n return counter._value;\\n }\\n\\n function increment(Counter storage counter) internal {\\n unchecked {\\n counter._value += 1;\\n }\\n }\\n\\n function decrement(Counter storage counter) internal {\\n uint256 value = counter._value;\\n require(value > 0, \\\"Counter: decrement overflow\\\");\\n unchecked {\\n counter._value = value - 1;\\n }\\n }\\n\\n function reset(Counter storage counter) internal {\\n counter._value = 0;\\n }\\n}\\n\",\"keccak256\":\"0xf0018c2440fbe238dd3a8732fa8e17a0f9dce84d31451dc8a32f6d62b349c9f1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0f633a0223d9a1dcccfcf38a64c9de0874dfcbfac0c6941ccf074d63a2ce0e1e\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * ```\\n * contract Example {\\n * // Add the library methods\\n * using EnumerableSet for EnumerableSet.AddressSet;\\n *\\n * // Declare a set state variable\\n * EnumerableSet.AddressSet private mySet;\\n * }\\n * ```\\n *\\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\\n * and `uint256` (`UintSet`) are supported.\\n *\\n * [WARNING]\\n * ====\\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\\n * unusable.\\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\\n *\\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\\n * array of EnumerableSet.\\n * ====\\n */\\nlibrary EnumerableSet {\\n // To implement this library for multiple types with as little code\\n // repetition as possible, we write it in terms of a generic Set type with\\n // bytes32 values.\\n // The Set implementation uses private functions, and user-facing\\n // implementations (such as AddressSet) are just wrappers around the\\n // underlying Set.\\n // This means that we can only create new EnumerableSets for types that fit\\n // in bytes32.\\n\\n struct Set {\\n // Storage of set values\\n bytes32[] _values;\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(bytes32 => uint256) _indexes;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function _add(Set storage set, bytes32 value) private returns (bool) {\\n if (!_contains(set, value)) {\\n set._values.push(value);\\n // The value is stored at length-1, but we add 1 to all indexes\\n // and use 0 as a sentinel value\\n set._indexes[value] = set._values.length;\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function _remove(Set storage set, bytes32 value) private returns (bool) {\\n // We read and store the value's index to prevent multiple reads from the same storage slot\\n uint256 valueIndex = set._indexes[value];\\n\\n if (valueIndex != 0) {\\n // Equivalent to contains(set, value)\\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\\n // the array, and then remove the last element (sometimes called as 'swap and pop').\\n // This modifies the order of the array, as noted in {at}.\\n\\n uint256 toDeleteIndex = valueIndex - 1;\\n uint256 lastIndex = set._values.length - 1;\\n\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set._values[lastIndex];\\n\\n // Move the last value to the index where the value to delete is\\n set._values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\\n }\\n\\n // Delete the slot where the moved value was stored\\n set._values.pop();\\n\\n // Delete the index for the deleted slot\\n delete set._indexes[value];\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\\n return set._indexes[value] != 0;\\n }\\n\\n /**\\n * @dev Returns the number of values on the set. O(1).\\n */\\n function _length(Set storage set) private view returns (uint256) {\\n return set._values.length;\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\\n return set._values[index];\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function _values(Set storage set) private view returns (bytes32[] memory) {\\n return set._values;\\n }\\n\\n // Bytes32Set\\n\\n struct Bytes32Set {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _add(set._inner, value);\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _remove(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return _contains(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return _at(set._inner, index);\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n bytes32[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // AddressSet\\n\\n struct AddressSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n return _add(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n return _remove(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\\n return address(uint160(uint256(_at(set._inner, index))));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(AddressSet storage set) internal view returns (address[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n address[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // UintSet\\n\\n struct UintSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(UintSet storage set, uint256 value) internal returns (bool) {\\n return _add(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\\n return _remove(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(UintSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\\n return uint256(_at(set._inner, index));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(UintSet storage set) internal view returns (uint256[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n uint256[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xc3ff3f5c4584e1d9a483ad7ced51ab64523201f4e3d3c65293e4ca8aeb77a961\",\"license\":\"MIT\"},\"contracts/housing-project/CallsSmartHousing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nabstract contract CallsSmartHousing {\\n\\t/// @notice The address of the main SmartHousing contract.\\n\\taddress immutable smartHousingAddr;\\n\\n\\tconstructor(address smartHousingAddr_) {\\n\\t\\tsmartHousingAddr = smartHousingAddr_;\\n\\t}\\n\\n\\t/// @dev Gets the referrer address for a given original owner.\\n\\t/// @param userAddr The original owner of the token.\\n\\t/// @return The referrer address.\\n\\tfunction getReferrer(\\n\\t\\taddress userAddr\\n\\t) internal view returns (uint, address) {\\n\\t\\treturn IUserModule(smartHousingAddr).getReferrer(userAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0xd2ded3c751d669f079d12e7381e586b747cb9ae1b6d9bd4dbd87fc9db3b0371c\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingProject.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"./RentsModule.sol\\\";\\n\\n/// @title HousingProject Contract\\n/// @notice Represents a unique real estate project within the SmartHousing ecosystem.\\n/// @dev This contract inherits from RentsModule and HousingSFT.\\ncontract HousingProject is RentsModule, Ownable {\\n\\t/// @notice Initializes the HousingProject contract.\\n\\t/// @param smartHousingAddr The address of the main SmartHousing contract.\\n\\tconstructor(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) CallsSmartHousing(smartHousingAddr) {\\n\\t\\tprojectSFT = new HousingSFT(name, symbol);\\n\\t}\\n\\n\\tevent TokenIssued(address tokenAddress, string name, uint256 amountRaised);\\n\\n\\tfunction setTokenDetails(\\n\\t\\tuint256 amountRaised,\\n\\t\\taddress housingTokenAddr\\n\\t) external onlyOwner {\\n\\t\\trequire(amountRaised == 0, \\\"Token details set already\\\");\\n\\n\\t\\thousingToken = ERC20Burnable(housingTokenAddr);\\n\\n\\t\\tprojectSFT.setAmountRaised(amountRaised);\\n\\t\\tstring memory name = projectSFT.name();\\n\\n\\t\\temit TokenIssued(address(projectSFT), name, amountRaised);\\n\\t}\\n\\n\\tfunction getMaxSupply() public view returns (uint256) {\\n\\t\\treturn projectSFT.getMaxSupply();\\n\\t}\\n}\\n\",\"keccak256\":\"0x159e6b338c47a2dacbec1254f582826b5584c338919e6e6908aba986f9a98350\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingSFT.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\n\\nimport \\\"../modules/SFT.sol\\\";\\n\\nstruct HousingAttributes {\\n\\tuint256 rewardsPerShare;\\n\\taddress originalOwner;\\n\\tuint256 tokenWeight;\\n}\\n\\n/// @title Housing SFT\\n/// @notice This contract represents a semi-fungible token (SFT) for housing projects.\\n/// @dev This contract will be inherited by the HousingProject contract.\\ncontract HousingSFT is SFT {\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct HousingSFTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tHousingAttributes attributes;\\n\\t}\\n\\n\\t// FIXME this value should be unique to each contract, should depend on\\n\\t// the total amount expected to raise as it determines the amount of SFTs to\\n\\t// be minted for investors\\n\\tuint256 public constant MAX_SUPPLY = 1_000_000;\\n\\n\\t/// @notice The amount of fungible tokens collected from investors to finance the development of this housing project.\\n\\tuint256 public amountRaised;\\n\\n\\t/// @notice The current amount out of the `MAX_SUPPLY` of tokens minted.\\n\\tuint256 public totalSupply;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tfunction setAmountRaised(uint256 amountRaised_) external onlyOwner {\\n\\t\\tamountRaised = amountRaised_;\\n\\t}\\n\\n\\tmodifier canMint() {\\n\\t\\taddress sftOwner = owner();\\n\\n\\t\\trequire(\\n\\t\\t\\tOwnable(sftOwner).owner() == _msgSender(),\\n\\t\\t\\t\\\"not allowed to mint\\\"\\n\\t\\t);\\n\\n\\t\\t_;\\n\\t}\\n\\n\\t/// @notice Mints SFT tokens for a depositor based on the amount of deposit.\\n\\t/// @param depositAmt The amount of fungible token deposited.\\n\\t/// @param depositor The address of the depositor.\\n\\tfunction mintSFT(\\n\\t\\tuint256 depositAmt,\\n\\t\\taddress depositor,\\n\\t\\tuint256 amount_raised\\n\\t) external canMint returns (uint256) {\\n\\t\\t// TODO remove after demo due to not beign able to move blocks in public networks\\n\\t\\t{\\n\\t\\t\\tamountRaised = amount_raised;\\n\\t\\t}\\n\\n\\t\\tuint256 totalDeposits = amountRaised;\\n\\t\\tuint256 maxShares = MAX_SUPPLY;\\n\\n\\t\\trequire(totalDeposits > 0, \\\"HousingSFT: No deposits recorded\\\");\\n\\n\\t\\tuint256 mintShare = (depositAmt * maxShares) / totalDeposits;\\n\\t\\trequire(mintShare > 0, \\\"HousingSFT: Computed token shares is invalid\\\");\\n\\n\\t\\ttotalSupply += mintShare;\\n\\t\\trequire(totalSupply <= MAX_SUPPLY, \\\"HousingSFT: Max supply exceeded\\\");\\n\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tHousingAttributes({\\n\\t\\t\\t\\trewardsPerShare: 0, // Should be 0 since they have never claimed any rent rewards\\n\\t\\t\\t\\toriginalOwner: depositor,\\n\\t\\t\\t\\ttokenWeight: mintShare\\n\\t\\t\\t})\\n\\t\\t);\\n\\n\\t\\treturn _mint(depositor, mintShare, attributes, \\\"\\\");\\n\\t}\\n\\n\\t/// @notice Checks if an address owns this HousingSFT and returns the attributes.\\n\\t/// @param owner The address to check the balance of.\\n\\t/// @return `HousingAttributes` if the owner has a positive balance of the token, panics otherwise.\\n\\tfunction getUserSFT(\\n\\t\\taddress owner,\\n\\t\\tuint256 nonce\\n\\t) public view returns (HousingAttributes memory) {\\n\\t\\trequire(\\n\\t\\t\\thasSFT(owner, nonce),\\n\\t\\t\\t\\\"HouisingSFT: No tokens found for user at nonce\\\"\\n\\t\\t);\\n\\n\\t\\treturn abi.decode(getRawTokenAttributes(nonce), (HousingAttributes));\\n\\t}\\n\\n\\tfunction getMaxSupply() public pure returns (uint256) {\\n\\t\\treturn MAX_SUPPLY;\\n\\t}\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (HousingSFTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tHousingSFTBalance[] memory balance = new HousingSFTBalance[](\\n\\t\\t\\t_sftBals.length\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = HousingSFTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(_sftBal.attributes, (HousingAttributes))\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\tfunction tokenDetails()\\n\\t\\tpublic\\n\\t\\tview\\n\\t\\treturns (string memory, string memory, uint256)\\n\\t{\\n\\t\\treturn (name(), symbol(), getMaxSupply());\\n\\t}\\n}\\n\",\"keccak256\":\"0x8fbbe8d670bc777eed8587d0a8b11acf1d7b40b9ae631fee4abc929f4275c160\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/NewHousingProjectLib.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport { HousingProject } from \\\"./HousingProject.sol\\\";\\n\\nlibrary NewHousingProject {\\n\\tfunction create(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) external returns (HousingProject) {\\n\\t\\treturn new HousingProject(name, symbol, smartHousingAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0x0ad286112bdc35e59e9424ffda000b7b6b582e228cca1cafc2b9cab28193628f\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/RentsModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\\\";\\n\\nimport \\\"./HousingSFT.sol\\\";\\nimport \\\"./RewardSharing.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"./CallsSmartHousing.sol\\\";\\n\\n/// @title Rents Module\\n/// @notice Handles rent payments, reward calculations, and distribution for Housing projects.\\n/// @dev This abstract contract should be inherited by the HousingProject contract.\\nabstract contract RentsModule is CallsSmartHousing {\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\tusing RewardShares for rewardshares;\\n\\n\\tuint256 public rewardPerShare;\\n\\tuint256 public rewardsReserve;\\n\\tuint256 public facilityManagementFunds;\\n\\n\\tERC20Burnable housingToken;\\n\\tHousingSFT public projectSFT;\\n\\n\\t/// @notice Receives rent payments and distributes rewards.\\n\\t/// @param rentPayment The details of the rent payment.\\n\\tfunction receiveRent(ERC20TokenPayment calldata rentPayment) external {\\n\\t\\t// TODO set the appropriate rent per Project\\n\\t\\trequire(\\n\\t\\t\\trentPayment.amount > 0,\\n\\t\\t\\t\\\"RentsModule: Insufficient amount\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\trentPayment.token == housingToken,\\n\\t\\t\\t\\\"RentsModule: Invalid rent payment token\\\"\\n\\t\\t);\\n\\t\\trentPayment.receiveERC20();\\n\\n\\t\\tuint256 rentReward = (rentPayment.amount * 75) / 100;\\n\\t\\tuint256 ecosystemReward = (rentPayment.amount * 18) / 100;\\n\\t\\tuint256 facilityReward = (rentPayment.amount * 7) / 100;\\n\\n\\t\\tuint256 allShares = projectSFT.getMaxSupply();\\n\\t\\tuint256 rpsIncrease = (rentReward * DIVISION_SAFETY_CONST) / allShares;\\n\\n\\t\\trewardPerShare += rpsIncrease;\\n\\t\\trewardsReserve += rentReward;\\n\\t\\tfacilityManagementFunds += facilityReward;\\n\\n\\t\\thousingToken.burn(ecosystemReward);\\n\\t\\tISmartHousing(smartHousingAddr).addProjectRent(rentPayment.amount);\\n\\t}\\n\\n\\t/// @notice Claims rent rewards for a given token.\\n\\t/// @return The updated HousingAttributes.\\n\\tfunction claimRentReward(\\n\\t\\tuint256 nonce\\n\\t) external returns (HousingAttributes memory, rewardshares memory) {\\n\\t\\taddress caller = msg.sender;\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tHousingAttributes memory attr = projectSFT.getUserSFT(caller, nonce);\\n\\t\\trewardshares memory rewardShares = computeRewardShares(attr);\\n\\t\\tuint256 totalReward = rewardShares.total();\\n\\n\\t\\tif (totalReward == 0) {\\n\\t\\t\\t// Fail silently\\n\\t\\t\\treturn (attr, rewardShares);\\n\\t\\t}\\n\\n\\t\\trequire(rewardsReserve >= totalReward, \\\"Computed rewards too large\\\");\\n\\n\\t\\trewardsReserve -= totalReward;\\n\\n\\t\\t// We use original owner since we are certain they are registered\\n\\t\\t(, address referrer) = getReferrer(attr.originalOwner);\\n\\t\\tif (rewardShares.referrerValue > 0) {\\n\\t\\t\\tif (referrer != address(0)) {\\n\\t\\t\\t\\thousingToken.transfer(referrer, rewardShares.referrerValue); // Send to referrer\\n\\t\\t\\t} else {\\n\\t\\t\\t\\thousingToken.burn(rewardShares.referrerValue); // Burn to add to ecosystem reward\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tattr.rewardsPerShare = currentRPS;\\n\\n\\t\\tprojectSFT.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tprojectSFT.balanceOf(caller, nonce),\\n\\t\\t\\tabi.encode(attr)\\n\\t\\t);\\n\\n\\t\\thousingToken.transfer(caller, rewardShares.userValue); // Send to user\\n\\n\\t\\treturn (attr, rewardShares);\\n\\t}\\n\\n\\t/// @notice Computes the amount of rent claimable for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The amount of rent claimable.\\n\\tfunction rentClaimable(\\n\\t\\tHousingAttributes memory attr\\n\\t) public view returns (uint256) {\\n\\t\\treturn computeRewardShares(attr).userValue;\\n\\t}\\n\\n\\t/// @dev Computes the reward shares for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The computed RewardShares.\\n\\tfunction computeRewardShares(\\n\\t\\tHousingAttributes memory attr\\n\\t) internal view returns (rewardshares memory) {\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tif (currentRPS == 0 || attr.rewardsPerShare >= currentRPS) {\\n\\t\\t\\treturn rewardshares({ userValue: 0, referrerValue: 0 });\\n\\t\\t}\\n\\n\\t\\tuint256 reward = computeReward(attr, currentRPS);\\n\\n\\t\\treturn splitReward(reward);\\n\\t}\\n}\\n\",\"keccak256\":\"0xe97c64b7d4f5a945493aa8492c4412248f60ec1e6e8cd74e3f805e40cc672768\",\"license\":\"MIT\"},\"contracts/housing-project/RewardSharing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"./HousingSFT.sol\\\";\\n\\nuint256 constant DIVISION_SAFETY_CONST = 1_000_000_000_000_000_000;\\n\\nstruct rewardshares {\\n\\tuint256 userValue;\\n\\tuint256 referrerValue;\\n}\\n\\nlibrary RewardShares {\\n\\tfunction total(rewardshares memory self) internal pure returns (uint256) {\\n\\t\\treturn self.userValue + self.referrerValue;\\n\\t}\\n}\\n\\nfunction splitReward(uint256 reward) pure returns (rewardshares memory) {\\n\\tuint256 referrerValue = (reward * 6_66) / 100_00; // would amount to approximately 5% of grand total\\n\\tuint256 userValue = reward - referrerValue;\\n\\n\\treturn rewardshares(userValue, referrerValue);\\n}\\n\\nfunction computeReward(\\n\\tHousingAttributes memory attr,\\n\\tuint256 contractRPS\\n) pure returns (uint256) {\\n\\tif (contractRPS <= attr.rewardsPerShare) {\\n\\t\\treturn 0;\\n\\t}\\n\\n\\treturn\\n\\t\\t((contractRPS - attr.rewardsPerShare) * attr.tokenWeight) /\\n\\t\\tDIVISION_SAFETY_CONST;\\n}\\n\",\"keccak256\":\"0x9f07d2b3ee49b91e12ad7ce9ba248ab7dd30bc2efc4238a594e681d3f0348e54\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/lib/LkSHTAttributes.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title LkSHTAttributes\\n * @dev Library for handling attributes and unlocking of the Locked SmartHousing Token.\\n */\\nlibrary LkSHTAttributes {\\n\\tusing SafeMath for uint256;\\n\\n\\t// TODO use this for mainnet uint256 constant LOCK_DURATION = 3 * 365 days; // 3 years\\n\\tuint256 constant LOCK_DURATION = 5 hours;\\n\\n\\tstruct Attributes {\\n\\t\\tuint256 initialAmount;\\n\\t\\tuint256 amount;\\n\\t\\tuint256 startTimestamp;\\n\\t\\tuint256 endTimestamp;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Creates new attributes for a Locked SmartHousing Token.\\n\\t * @param startTimestamp The start time of the lock.\\n\\t * @param amount The amount of SmartHousing Tokens locked.\\n\\t * @return attributes The initialized attributes.\\n\\t */\\n\\tfunction newAttributes(\\n\\t\\tuint256 startTimestamp,\\n\\t\\tuint256 amount\\n\\t) internal pure returns (Attributes memory) {\\n\\t\\treturn\\n\\t\\t\\tAttributes({\\n\\t\\t\\t\\tinitialAmount: amount,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tstartTimestamp: startTimestamp,\\n\\t\\t\\t\\tendTimestamp: startTimestamp.add(LOCK_DURATION)\\n\\t\\t\\t});\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calculates and deducts the unlocked amount based on the elapsed time.\\n\\t * @param self The attributes to update.\\n\\t * @return unlockedAmount The amount of tokens unlocked.\\n\\t */\\n\\tfunction unlockMatured(\\n\\t\\tAttributes memory self\\n\\t)\\n\\t\\tinternal\\n\\t\\tview\\n\\t\\treturns (uint256 unlockedAmount, Attributes memory newSelf)\\n\\t{\\n\\t\\tuint256 elapsed = elapsedTime(self);\\n\\t\\tunlockedAmount = self.amount.mul(elapsed).div(LOCK_DURATION);\\n\\n\\t\\tself.amount = self.amount.sub(unlockedAmount);\\n\\t\\tnewSelf = self;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calculates the elapsed time since the lock started.\\n\\t * @param self The attributes to use.\\n\\t * @return elapsedTime The elapsed time in seconds.\\n\\t */\\n\\tfunction elapsedTime(\\n\\t\\tAttributes memory self\\n\\t) internal view returns (uint256) {\\n\\t\\tuint256 currentTime = block.timestamp;\\n\\t\\tif (currentTime >= self.endTimestamp) {\\n\\t\\t\\treturn LOCK_DURATION;\\n\\t\\t} else {\\n\\t\\t\\treturn currentTime.sub(self.startTimestamp);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0xbaf851bef9603c72b3cce96d93f8f243f36187d31c8c94233101d802b9ae129d\",\"license\":\"MIT\"},\"contracts/lib/ProjectStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport \\\"./TokenPayments.sol\\\";\\n\\nlibrary ProjectStorage {\\n\\tusing SafeMath for uint256;\\n\\tusing TokenPayments for TokenPayment;\\n\\tusing ProjectStorage for Data;\\n\\n\\tenum Status {\\n\\t\\tFundingPeriod,\\n\\t\\tSuccessful,\\n\\t\\tFailed\\n\\t}\\n\\n\\tstruct Data {\\n\\t\\tuint256 id; // Unique identifier for the project\\n\\t\\taddress tokenAddress;\\n\\t\\taddress projectAddress; // Address of the deployed HousingProject contract\\n\\t\\tuint256 fundingGoal; // Target funding amount for the project\\n\\t\\tuint256 fundingDeadline; // Deadline timestamp for the project funding\\n\\t\\taddress fundingToken; // Address of the ERC20 token used for funding\\n\\t\\tuint256 collectedFunds; // Amount of funds collected for the project\\n\\t}\\n\\n\\tfunction status(Data storage self) internal view returns (Status) {\\n\\t\\tif (self.collectedFunds >= self.fundingGoal) {\\n\\t\\t\\treturn Status.Successful;\\n\\t\\t} else if (block.timestamp < self.fundingDeadline) {\\n\\t\\t\\treturn Status.FundingPeriod;\\n\\t\\t} else {\\n\\t\\t\\treturn Status.Failed;\\n\\t\\t}\\n\\t}\\n\\n\\tfunction createNew(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage projectsId,\\n\\t\\tuint256 projectCount,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline,\\n\\t\\taddress fundingToken,\\n\\t\\taddress projectAddress,\\n\\t\\taddress tokenAddress\\n\\t) internal returns (Data memory) {\\n\\t\\trequire(fundingGoal > 0, \\\"Funding goal must be more than 0\\\");\\n\\t\\trequire(\\n\\t\\t\\tfundingDeadline > block.timestamp,\\n\\t\\t\\t\\\"Deadline can't be in the past\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 newId = projectCount.add(1);\\n\\n\\t\\tData memory newProjectData = Data({\\n\\t\\t\\tid: newId,\\n\\t\\t\\tprojectAddress: projectAddress,\\n\\t\\t\\tfundingGoal: fundingGoal,\\n\\t\\t\\tfundingDeadline: fundingDeadline,\\n\\t\\t\\tfundingToken: fundingToken,\\n\\t\\t\\tcollectedFunds: 0,\\n\\t\\t\\ttokenAddress: tokenAddress\\n\\t\\t});\\n\\n\\t\\tprojects[newId] = newProjectData;\\n\\t\\tprojectsId[newProjectData.projectAddress] = newProjectData.id;\\n\\n\\t\\treturn newProjectData;\\n\\t}\\n\\n\\tfunction fund(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage usersDeposit,\\n\\t\\tuint256 projectId,\\n\\t\\taddress depositor,\\n\\t\\tTokenPayment calldata payment\\n\\t) internal {\\n\\t\\trequire(payment.amount > 0, \\\"Invalid funding amount\\\");\\n\\n\\t\\tData storage project = projects[projectId];\\n\\n\\t\\trequire(\\n\\t\\t\\tproject.status() == Status.FundingPeriod,\\n\\t\\t\\t\\\"Cannot fund project after deadline\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\taddress(payment.token) == project.fundingToken,\\n\\t\\t\\t\\\"Wrong token payment\\\"\\n\\t\\t);\\n\\t\\tpayment.receiveToken();\\n\\n\\t\\tproject.collectedFunds = project.collectedFunds.add(payment.amount);\\n\\t\\tusersDeposit[depositor] = usersDeposit[depositor].add(payment.amount);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Retrieves and updates the user's deposit for a specific project.\\n\\t * @param projectId The ID of the project to retrieve the deposit for.\\n\\t * @param depositor The address of the depositor.\\n\\t * @return (ProjectStorage.Data, uint256) The project data and deposit amount.\\n\\t */\\n\\tfunction takeDeposit(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage usersDeposit,\\n\\t\\tuint256 projectId,\\n\\t\\taddress depositor\\n\\t) internal returns (ProjectStorage.Data memory, uint256) {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\trequire(project.id != 0, \\\"Invalid project ID\\\");\\n\\t\\trequire(\\n\\t\\t\\tproject.status() == Status.Successful,\\n\\t\\t\\t\\\"Project not yet successful\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 depositAmount = usersDeposit[depositor];\\n\\t\\trequire(depositAmount > 0, \\\"No deposit found\\\");\\n\\n\\t\\t// Update the deposit amount to zero\\n\\t\\tusersDeposit[depositor] = 0;\\n\\n\\t\\treturn (project, depositAmount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x652aab2dc03764c430b91f35e908430208d6a1bd27a4cc8060adb1ec7f249ad5\",\"license\":\"MIT\"},\"contracts/lib/TokenPayments.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/interfaces/IERC20.sol\\\";\\nimport { SFT } from \\\"../modules/SFT.sol\\\";\\n\\nstruct ERC20TokenPayment {\\n\\tIERC20 token;\\n\\tuint256 amount;\\n}\\n\\nstruct TokenPayment {\\n\\taddress token;\\n\\tuint256 amount;\\n\\tuint256 nonce;\\n}\\n\\nlibrary TokenPayments {\\n\\tfunction accept(ERC20TokenPayment calldata self) internal {\\n\\t\\tTokenPayments.receiveERC20(self, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(ERC20TokenPayment calldata payment) internal {\\n\\t\\tTokenPayments.receiveERC20(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(\\n\\t\\tERC20TokenPayment calldata payment,\\n\\t\\taddress from\\n\\t) internal {\\n\\t\\tpayment.token.transferFrom(from, address(this), payment.amount);\\n\\t}\\n\\n\\t// Receives both Native, SFTs and ERC20; ERC20 have nonce as 0, Native coins have address 0 as token value\\n\\tfunction receiveToken(TokenPayment memory payment) internal {\\n\\t\\treceiveToken(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveToken(TokenPayment memory payment, address from) internal {\\n\\t\\tif (payment.token == address(0)) {\\n\\t\\t\\t// Native payment\\n\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tpayment.amount == msg.value,\\n\\t\\t\\t\\t\\\"expected payment amount must equal sent amount\\\"\\n\\t\\t\\t);\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tfrom == msg.sender,\\n\\t\\t\\t\\t\\\"can receive native payment only from caller\\\"\\n\\t\\t\\t);\\n\\t\\t\\t\\n\\t\\t\\t// Nothing to do again since the VM will handle balance movements\\n\\t\\t} else if (payment.nonce == 0) {\\n\\t\\t\\tIERC20(payment.token).transferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.amount\\n\\t\\t\\t);\\n\\t\\t} else {\\n\\t\\t\\tSFT(payment.token).safeTransferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.nonce,\\n\\t\\t\\t\\tpayment.amount,\\n\\t\\t\\t\\t\\\"\\\"\\n\\t\\t\\t);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x06bd73e8da1bde18d9aaf6d4b6a1bdec6e0718af6354fe2d7ce87251d6fd1ac5\",\"license\":\"MIT\"},\"contracts/main/Interface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"../lib/TokenPayments.sol\\\";\\n\\ninterface ISmartHousing {\\n\\tfunction addProjectRent(uint256 amount) external;\\n\\n\\tfunction createRefIDViaProxy(\\n\\t\\taddress userAddr,\\n\\t\\tuint256 referrerId\\n\\t) external returns (uint256);\\n\\n\\tfunction addProject(address projectAddress) external;\\n\\n\\tfunction setUpSHT(ERC20TokenPayment calldata payment) external;\\n}\\n\\ninterface IUserModule {\\n\\tfunction getReferrer(address user) external view returns (uint, address);\\n}\\n\",\"keccak256\":\"0x066719eed5c5ff2394d78ce027aada5a8555713c9f4abf8b5135975981ba9989\",\"license\":\"MIT\"},\"contracts/modules/LockedSmartHousingToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport \\\"../lib/LkSHTAttributes.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"../modules/SFT.sol\\\";\\n\\nlibrary NewLkSHT {\\n\\tfunction create() external returns (LkSHT) {\\n\\t\\treturn new LkSHT(\\\"Locked Housing Token\\\", \\\"LkSHT\\\");\\n\\t}\\n}\\n\\n/**\\n * @title LockedSmartHousingToken\\n * @dev SFT token that locks SmartHousing Tokens (SHT) during ICO.\\n * Allows transfers only to whitelisted addresses.\\n */\\ncontract LkSHT is SFT {\\n\\tusing SafeMath for uint256;\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\n\\tstruct LkSHTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tLkSHTAttributes.Attributes attributes;\\n\\t}\\n\\n\\tuint256 immutable startTimestamp = block.timestamp;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tevent TokensMinted(address indexed to, uint256 amount);\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (LkSHTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tLkSHTBalance[] memory balance = new LkSHTBalance[](_sftBals.length);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = LkSHTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(\\n\\t\\t\\t\\t\\t_sftBal.attributes,\\n\\t\\t\\t\\t\\t(LkSHTAttributes.Attributes)\\n\\t\\t\\t\\t)\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Mints new Locked SmartHousing Tokens (LkSHT) by locking SHT.\\n\\t * @param amount The amount of SHT to lock.\\n\\t * @param to The address to mint the tokens to.\\n\\t */\\n\\tfunction mint(uint256 amount, address to) external onlyOwner {\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tLkSHTAttributes.newAttributes(startTimestamp, amount)\\n\\t\\t);\\n\\n\\t\\tsuper._mint(to, amount, attributes, \\\"LockedSmartHousingToken\\\");\\n\\n\\t\\temit TokensMinted(to, amount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x33e840a42e8bab335538d2ab9a8973c97423b17caac5fd50a802b53f6db7357d\",\"license\":\"MIT\"},\"contracts/modules/SFT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Counters.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n// TODO I think we should create a standard of this\\nabstract contract SFT is ERC1155, Ownable {\\n\\tusing Counters for Counters.Counter;\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct SftBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tbytes attributes;\\n\\t}\\n\\n\\tCounters.Counter private _nonceCounter;\\n\\tstring private _name;\\n\\tstring private _symbol;\\n\\n\\t// Mapping from nonce to token attributes as bytes\\n\\tmapping(uint256 => bytes) private _tokenAttributes;\\n\\n\\t// Mapping from address to list of owned token nonces\\n\\tmapping(address => EnumerableSet.UintSet) private _addressToNonces;\\n\\n\\tconstructor(string memory name_, string memory symbol_) ERC1155(\\\"\\\") {\\n\\t\\t_name = name_;\\n\\t\\t_symbol = symbol_;\\n\\t}\\n\\n\\t// Private function to mint new tokens\\n\\tfunction _mint(\\n\\t\\taddress to,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attributes,\\n\\t\\tbytes memory data\\n\\t) internal returns (uint256) {\\n\\t\\t_nonceCounter.increment();\\n\\t\\tuint256 nonce = _nonceCounter.current();\\n\\n\\t\\t// Store the attributes\\n\\t\\t_tokenAttributes[nonce] = attributes;\\n\\n\\t\\t// Mint the token with the nonce as its ID\\n\\t\\tsuper._mint(to, nonce, amount, data);\\n\\n\\t\\t// Track the nonce for the address\\n\\t\\t_addressToNonces[to].add(nonce);\\n\\n\\t\\treturn nonce;\\n\\t}\\n\\n\\tfunction name() public view returns (string memory) {\\n\\t\\treturn _name;\\n\\t}\\n\\n\\tfunction symbol() public view returns (string memory) {\\n\\t\\treturn _symbol;\\n\\t}\\n\\n\\tfunction tokenInfo() public view returns (string memory, string memory) {\\n\\t\\treturn (_name, _symbol);\\n\\t}\\n\\n\\t// Function to get token attributes by nonce\\n\\tfunction getRawTokenAttributes(\\n\\t\\tuint256 nonce\\n\\t) public view returns (bytes memory) {\\n\\t\\treturn _tokenAttributes[nonce];\\n\\t}\\n\\n\\t// Function to get list of nonces owned by an address\\n\\tfunction getNonces(address owner) public view returns (uint256[] memory) {\\n\\t\\treturn _addressToNonces[owner].values();\\n\\t}\\n\\n\\tfunction hasSFT(address owner, uint256 nonce) public view returns (bool) {\\n\\t\\treturn _addressToNonces[owner].contains(nonce);\\n\\t}\\n\\n\\t/// Burns all the NFT balance of user at nonce, creates new with balance and attributes\\n\\tfunction update(\\n\\t\\taddress user,\\n\\t\\tuint256 nonce,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attr\\n\\t) external onlyOwner {\\n\\t\\t_burn(user, nonce, amount);\\n\\t\\t_mint(user, amount, attr, \\\"\\\");\\n\\t}\\n\\n\\tfunction _sftBalance(\\n\\t\\taddress user\\n\\t) internal view returns (SftBalance[] memory) {\\n\\t\\tuint256[] memory nonces = getNonces(user);\\n\\t\\tSftBalance[] memory balance = new SftBalance[](nonces.length);\\n\\n\\t\\tfor (uint256 i; i < nonces.length; i++) {\\n\\t\\t\\tuint256 nonce = nonces[i];\\n\\t\\t\\tbytes memory attributes = _tokenAttributes[nonce];\\n\\t\\t\\tuint256 amount = balanceOf(user, nonce);\\n\\n\\t\\t\\tbalance[i] = SftBalance({\\n\\t\\t\\t\\tnonce: nonce,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tattributes: attributes\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t// Override _beforeTokenTransfer to handle address-to-nonce mapping\\n\\tfunction _beforeTokenTransfer(\\n\\t\\taddress operator,\\n\\t\\taddress from,\\n\\t\\taddress to,\\n\\t\\tuint256[] memory ids,\\n\\t\\tuint256[] memory amounts,\\n\\t\\tbytes memory data\\n\\t) internal virtual override {\\n\\t\\tsuper._beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[from].remove(ids[i]);\\n\\t\\t}\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[to].add(ids[i]);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x8098c36137bbb9a342d16fd64f7d57c03a77841a872dd44641b9db1623a699aa\",\"license\":\"MIT\"},\"contracts/modules/sht-module/SHT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nlibrary SHT {\\n\\tuint256 public constant DECIMALS = 18;\\n\\tuint256 public constant ONE = 10 ** DECIMALS;\\n\\tuint256 public constant MAX_SUPPLY = 21_000_000 * ONE;\\n\\tuint256 public constant ECOSYSTEM_DISTRIBUTION_FUNDS =\\n\\t\\t(13_650_000 * ONE) + 2_248_573_618_499_339;\\n\\tuint256 public constant ICO_FUNDS =\\n\\t\\tMAX_SUPPLY - ECOSYSTEM_DISTRIBUTION_FUNDS;\\n}\\n\",\"keccak256\":\"0x66b511a7932bd0f6ceea118f9440cac3a6fd470d11e4d7fa337de8b178627dd7\",\"license\":\"MIT\"},\"contracts/project-funding/ProjectFunding.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\\\";\\n\\nimport \\\"../lib/ProjectStorage.sol\\\";\\nimport \\\"../lib/LkSHTAttributes.sol\\\";\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nimport \\\"../modules/LockedSmartHousingToken.sol\\\";\\nimport \\\"../modules/sht-module/SHT.sol\\\";\\n\\nimport { HousingSFT } from \\\"../housing-project/HousingSFT.sol\\\";\\nimport { TokenPayment } from \\\"../lib/TokenPayments.sol\\\";\\nimport { NewHousingProject, HousingProject } from \\\"../housing-project/NewHousingProjectLib.sol\\\";\\n\\n/**\\n * @title ProjectFunding\\n * @dev This contract is used for initializing and deploying housing projects.\\n * It allows the deployment of a new housing project and manages project data.\\n */\\ncontract ProjectFunding is Ownable {\\n\\tusing SafeMath for uint256;\\n\\tusing ProjectStorage for mapping(uint256 => ProjectStorage.Data);\\n\\tusing ProjectStorage for ProjectStorage.Data;\\n\\tusing LkSHTAttributes for LkSHTAttributes.Attributes;\\n\\n\\taddress public coinbase; // Address authorized to initialize the first project, also the housingToken\\n\\taddress public smartHousingAddress; // Address of the SmartHousing contract\\n\\n\\tmapping(uint256 => ProjectStorage.Data) public projects; // Mapping of project ID to ProjectData\\n\\tmapping(address => uint256) public projectsId; // Mapping of project address to project ID\\n\\tuint256 public projectCount; // Counter for the total number of projects\\n\\n\\tmapping(uint256 => mapping(address => uint256)) public usersProjectDeposit;\\n\\n\\tIERC20 public housingToken; // Token used for funding projects\\n\\tLkSHT public lkSht; // The locked version\\n\\n\\t/**\\n\\t * @dev Emitted when a new project is deployed.\\n\\t * @param projectAddress Address of the newly deployed HousingProject contract.\\n\\t */\\n\\tevent ProjectDeployed(address indexed projectAddress);\\n\\tevent ProjectFunded(\\n\\t\\tuint256 indexed projectId,\\n\\t\\taddress indexed depositor,\\n\\t\\tTokenPayment payment\\n\\t);\\n\\tevent ProjectTokensClaimed(\\n\\t\\taddress indexed depositor,\\n\\t\\tuint256 projectId,\\n\\t\\tuint256 amount\\n\\t);\\n\\n\\t/**\\n\\t * @param _coinbase Address authorized to initialize the first project.\\n\\t */\\n\\tconstructor(address _coinbase) {\\n\\t\\tcoinbase = _coinbase;\\n\\t\\tlkSht = NewLkSHT.create();\\n\\t}\\n\\n\\t/**\\n\\t * @dev Internal function to deploy a new HousingProject contract.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction _deployProject(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) internal {\\n\\t\\tHousingProject newProject = NewHousingProject.create(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tsmartHousingAddress\\n\\t\\t);\\n\\t\\tProjectStorage.Data memory projectData = projects.createNew(\\n\\t\\t\\tprojectsId,\\n\\t\\t\\tprojectCount,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\taddress(newProject),\\n\\t\\t\\taddress(newProject.projectSFT())\\n\\t\\t);\\n\\t\\tprojectCount = projectData.id;\\n\\n\\t\\temit ProjectDeployed(projectData.projectAddress);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Initializes the first project.\\n\\t * This function must be called by the coinbase address and can only be called once.\\n\\t * It sets up the token and deploys the first project.\\n\\t * @param shtPayment Payment details for the Smart Housing Token (SHT).\\n\\t * @param smartHousingAddress_ Address of the Smart Housing contract.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction initFirstProject(\\n\\t\\tERC20TokenPayment calldata shtPayment,\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddress_,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) external {\\n\\t\\trequire(msg.sender == coinbase, \\\"Caller is not the coinbase\\\");\\n\\t\\trequire(projectCount == 0, \\\"Project already initialized\\\");\\n\\n\\t\\tTokenPayments.receiveERC20(shtPayment);\\n\\t\\thousingToken = shtPayment.token;\\n\\n\\t\\tsmartHousingAddress = smartHousingAddress_;\\n\\n\\t\\t_deployProject(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Deploys a new project.\\n\\t * This function can be called multiple times to deploy additional projects.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction deployProject(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) public onlyOwner {\\n\\t\\t_deployProject(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\tfunction fundProject(\\n\\t\\tTokenPayment calldata depositPayment,\\n\\t\\tuint256 projectId,\\n\\t\\tuint256 referrerId\\n\\t) external payable {\\n\\t\\trequire(\\n\\t\\t\\tprojectId > 0 && projectId <= projectCount,\\n\\t\\t\\t\\\"Invalid project ID\\\"\\n\\t\\t);\\n\\n\\t\\taddress depositor = msg.sender;\\n\\n\\t\\t// Register user with referrer (if needed)\\n\\t\\tISmartHousing(smartHousingAddress).createRefIDViaProxy(\\n\\t\\t\\tdepositor,\\n\\t\\t\\treferrerId\\n\\t\\t);\\n\\n\\t\\t// Update project funding\\n\\t\\tprojects.fund(\\n\\t\\t\\tusersProjectDeposit[projectId],\\n\\t\\t\\tprojectId,\\n\\t\\t\\tdepositor,\\n\\t\\t\\tdepositPayment\\n\\t\\t);\\n\\n\\t\\temit ProjectFunded(projectId, depositor, depositPayment);\\n\\t}\\n\\n\\tfunction addProjectToEcosystem(uint256 projectId) external onlyOwner {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\n\\t\\t// TODO Add this after demo\\n\\t\\t// require(\\n\\t\\t// \\tproject.status() == ProjectStorage.Status.Successful,\\n\\t\\t// \\t\\\"Project Funding not yet successful\\\"\\n\\t\\t// );\\n\\n\\t\\tISmartHousing(smartHousingAddress).addProject(project.projectAddress);\\n\\n\\t\\tHousingProject(project.projectAddress).setTokenDetails(\\n\\t\\t\\tproject.collectedFunds,\\n\\t\\t\\tcoinbase\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Claims project tokens for a given project ID.\\n\\t * @param projectId The ID of the project to claim tokens from.\\n\\t */\\n\\tfunction claimProjectTokens(uint256 projectId) external {\\n\\t\\taddress depositor = msg.sender;\\n\\n\\t\\t// Retrieve the project and deposit amount\\n\\t\\t(ProjectStorage.Data memory project, uint256 depositAmount) = projects\\n\\t\\t\\t.takeDeposit(usersProjectDeposit[projectId], projectId, depositor);\\n\\n\\t\\tHousingSFT(project.tokenAddress).mintSFT(\\n\\t\\t\\tdepositAmount,\\n\\t\\t\\tdepositor,\\n\\t\\t\\tproject.collectedFunds\\n\\t\\t);\\n\\n\\t\\t// Mint LkSHT tokens if the project ID is 1\\n\\t\\tif (project.id == 1) {\\n\\t\\t\\tuint256 shtAmount = depositAmount.mul(SHT.ICO_FUNDS).div(\\n\\t\\t\\t\\tproject.collectedFunds\\n\\t\\t\\t);\\n\\n\\t\\t\\tlkSht.mint(shtAmount, depositor);\\n\\t\\t}\\n\\n\\t\\temit ProjectTokensClaimed(depositor, projectId, depositAmount);\\n\\t}\\n\\n\\tfunction unlockSHT(uint256 nonce) external {\\n\\t\\taddress caller = msg.sender;\\n\\n\\t\\tuint256 lkShtBal = lkSht.balanceOf(caller, nonce);\\n\\t\\trequire(lkShtBal > 0, \\\"ProjectFunding: Nothing to unlock\\\");\\n\\n\\t\\tLkSHTAttributes.Attributes memory attr = abi.decode(\\n\\t\\t\\tlkSht.getRawTokenAttributes(nonce),\\n\\t\\t\\t(LkSHTAttributes.Attributes)\\n\\t\\t);\\n\\t\\t(\\n\\t\\t\\tuint256 totalUnlockedAmount,\\n\\t\\t\\tLkSHTAttributes.Attributes memory newAttr\\n\\t\\t) = attr.unlockMatured();\\n\\n\\t\\tlkSht.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tlkShtBal.sub(totalUnlockedAmount),\\n\\t\\t\\tabi.encode(newAttr)\\n\\t\\t);\\n\\n\\t\\t// Transfer the total unlocked SHT tokens to the user's address\\n\\t\\tif (totalUnlockedAmount > 0) {\\n\\t\\t\\thousingToken.transfer(caller, totalUnlockedAmount);\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns an array of all project IDs and their associated data.\\n\\t * @return projectList An array of tuples containing project details.\\n\\t */\\n\\tfunction allProjects() public view returns (ProjectStorage.Data[] memory) {\\n\\t\\tProjectStorage.Data[] memory projectList = new ProjectStorage.Data[](\\n\\t\\t\\tprojectCount\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i = 1; i <= projectCount; i++) {\\n\\t\\t\\tprojectList[i - 1] = projects[i];\\n\\t\\t}\\n\\n\\t\\treturn projectList;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns the address of the HousingProject contract for a given project ID.\\n\\t * @param projectId The ID of the project.\\n\\t * @return projectAddress The address of the HousingProject contract.\\n\\t */\\n\\tfunction getProjectAddress(\\n\\t\\tuint256 projectId\\n\\t) external view returns (address projectAddress) {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\treturn project.projectAddress;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns the details of a project by its ID.\\n\\t * @param projectId The ID of the project.\\n\\t * @return id The project ID.\\n\\t * @return fundingGoal The funding goal of the project.\\n\\t * @return fundingDeadline The deadline for the project funding.\\n\\t * @return fundingToken The address of the ERC20 token used for funding.\\n\\t * @return projectAddress The address of the HousingProject contract.\\n\\t * @return status The funding status of the project.\\n\\t * @return collectedFunds The amount of funds collected.\\n\\t */\\n\\tfunction getProjectData(\\n\\t\\tuint256 projectId\\n\\t)\\n\\t\\texternal\\n\\t\\tview\\n\\t\\treturns (\\n\\t\\t\\tuint256 id,\\n\\t\\t\\tuint256 fundingGoal,\\n\\t\\t\\tuint256 fundingDeadline,\\n\\t\\t\\taddress fundingToken,\\n\\t\\t\\taddress projectAddress,\\n\\t\\t\\tuint8 status,\\n\\t\\t\\tuint256 collectedFunds\\n\\t\\t)\\n\\t{\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\treturn (\\n\\t\\t\\tproject.id,\\n\\t\\t\\tproject.fundingGoal,\\n\\t\\t\\tproject.fundingDeadline,\\n\\t\\t\\tproject.fundingToken,\\n\\t\\t\\tproject.projectAddress,\\n\\t\\t\\tuint8(project.status()),\\n\\t\\t\\tproject.collectedFunds\\n\\t\\t);\\n\\t}\\n}\\n\",\"keccak256\":\"0xba3518a6288e777e4b2b51d944cbc298200458d0f09f3c5b701f52547991a4e1\",\"license\":\"MIT\"}},\"version\":1}", "bytecode": "0x608080604052346200013d5760208162001bcf803803809162000023828562000142565b8339810103126200013d57516001600160a01b03808216918290036200013d57600080546001600160a01b0319808216339081178455604051919591939285167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08480a3846001541617600155633bf206a360e21b82526020826004817359c8DE4B52BD5217302BdD070190074B8ea165815af491821562000130578192620000e3575b505016906008541617600855604051611a5290816200017d8239f35b9091506020813d60201162000127575b81620001026020938362000142565b810103126200012357519082821682036200012057503880620000c7565b80fd5b5080fd5b3d9150620000f3565b50604051903d90823e3d90fd5b600080fd5b601f909101601f19168101906001600160401b038211908210176200016657604052565b634e487b7160e01b600052604160045260246000fdfe6080604081815260048036101561001557600080fd5b60009260e0843560e01c918263107046bd1461137c57508163208359481461133657816321eefb9a1461130c5781632adf13b2146111875750806336fbad26146111685780634ca3e9b8146111335780634fd42f3a14610d2b57806350e76c8e14610d0257806358f36c1314610c62578381635b02f18c14610b515750806360ae7c3b146108c1578063661962661461088c578063715018a61461082f5780637f3a25d8146106695780638da5cb5b146106415780639c9e07ba14610618578063a6ae0aac146105ef578063c366164214610254578063da5e19d6146101ce5763f2fde38b1461010457600080fd5b346101ca5760203660031901126101ca5761011d6113f1565b906101266116d7565b6001600160a01b03918216928315610178575050600054826001600160601b0360a01b821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8280fd5b8382346102505760a03660031901126102505767ffffffffffffffff813581811161024c5761020090369084016114a7565b9160243591821161024c57610217913691016114a7565b604435916001600160a01b038316830361024757610244926102376116d7565b608435926064359261172f565b80f35b600080fd5b8380fd5b5080fd5b50346101ca576020918260031936011261024c576008548151627eeac760e11b8152338185019081528435602082018190526001600160a01b03938416918790849081906040010381855afa9283156105e55788936105b6575b508215610569578451637c89f5df60e01b8152868101829052918883602481845afa92831561055f5789936104e0575b506080838051810103126104dc578551906102f882611431565b88840151825286840151938983019485526080606082015191898501928352015190606084019182528b60608c828c519161033283611431565b818352820152828c8201520152610348846119f9565b86518181029181830414901517156104c7576146506103769104809861036f828a5161153e565b895261153e565b95895194518c86015251898501525160608401525160808301526080825260a082019382851067ffffffffffffffff8611176104b25790849392918b958952813b156104a45785859384928296636c49c79360e11b85523360a484015260c483015260e48201526080610104820152609f19906103f7610124820182611670565b0301925af180156104a857610490575b505080610412578580f35b600754835163a9059cbb60e01b8152339581019586526020860192909252909385928592169082908890829060400103925af19081156104875750610459575b8080808580f35b8161047892903d10610480575b6104708183611469565b810190611695565b503880610452565b503d610466565b513d85823e3d90fd5b61049990611407565b6104a4578538610407565b8580fd5b85513d84823e3d90fd5b604189634e487b7160e01b6000525260246000fd5b60118b634e487b7160e01b6000525260246000fd5b8880fd5b9092503d808a833e6104f28183611469565b810190888183031261055b5780519067ffffffffffffffff8211610557570181601f8201121561055b5780516105278161148b565b9261053489519485611469565b8184528a828401011161055757610550918a808501910161164d565b91386102de565b8a80fd5b8980fd5b86513d8b823e3d90fd5b845162461bcd60e51b8152808701889052602160248201527f50726f6a65637446756e64696e673a204e6f7468696e6720746f20756e6c6f636044820152606b60f81b6064820152608490fd5b9092508681813d83116105de575b6105ce8183611469565b81010312610247575191386102ae565b503d6105c4565b85513d8a823e3d90fd5b50503461025057816003193601126102505760015490516001600160a01b039091168152602090f35b50503461025057816003193601126102505760075490516001600160a01b039091168152602090f35b505034610250578160031936011261025057905490516001600160a01b039091168152602090f35b50346101ca573660031901610100811261024c5782136101ca5767ffffffffffffffff60443581811161082b576106a390369084016114a7565b9060643590811161082b576106bb90369084016114a7565b916084356001600160a01b03818116918290036102475760a43592818416840361024757816001541633036107e8576005546107a5576020610734899284610701611637565b8b516323b872dd60e01b815233938101938452306020850152602435604085015295869492909116928492839160600190565b03925af1801561079b57610244975061077c575b50610751611637565b166001600160601b0360a01b90816007541617600755600254161760025560e4359260c4359261172f565b6107949060203d602011610480576104708183611469565b5038610748565b87513d8a823e3d90fd5b606490602088519162461bcd60e51b8352820152601b60248201527f50726f6a65637420616c726561647920696e697469616c697a656400000000006044820152fd5b606490602088519162461bcd60e51b8352820152601a60248201527f43616c6c6572206973206e6f742074686520636f696e626173650000000000006044820152fd5b8480fd5b83346108895780600319360112610889576108486116d7565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b50346101ca5760203660031901126101ca5760209282916001600160a01b036108b36113f1565b168252845220549051908152f35b5090346101ca576020908160031936011261024c5782359283855260068352818520906108ec611506565b5084865260038452828620610903815415156115e9565b61090c816116ad565b6003811015610b3e57600103610afb57336000528285528360002054928315610ac557906109459133600052865287856000205561158b565b60018060a01b039081868201511690888760c0830193606485518a51948593849263da96192160e01b84528c8c85015233602485015260448401525af18015610abb57908891610a92575b5050516001146109ce575b5050507f30ef556644d7bab0fb4b399fb53bd396fdd3faf30c1dc80bccca41f0155a42f39282519485528401523392a280f35b6a06146c4c5b31f4edf7d0f58402906a06146c4c5b31f4edf7d0f41985830401610a7d5751918215610a6857908893929160085416803b1561082b5786516394bf804d60e01b81529290910492820192835233602084015290918391839182908490829060400103925af18015610a5e57610a4a575b8061099b565b610a5390611407565b61082b578438610a44565b84513d84823e3d90fd5b601284634e487b7160e01b6000525260246000fd5b601184634e487b7160e01b6000525260246000fd5b813d8311610ab4575b610aa58183611469565b81010312610247578638610990565b503d610a9b565b87513d8c823e3d90fd5b845162461bcd60e51b8152808401879052601060248201526f139bc819195c1bdcda5d08199bdd5b9960821b6044820152606490fd5b835162461bcd60e51b8152808301869052601a60248201527f50726f6a656374206e6f7420796574207375636365737366756c0000000000006044820152606490fd5b634e487b7160e01b885260218352602488fd5b92905034610c5e576020366003190112610c5e57610b6d6116d7565b8135835260036020528083206002805490820180546001600160a01b039593928616908616813b15610c5a5787916024839288519485938492630f8ad6f360e31b84528a8401525af18015610c505786918891610c39575b50506006915416910154936001541690803b156104a4578351637361991560e01b81529283019485526001600160a01b03909116602085015290928491849182908490829060400103925af1908115610c305750610c205750f35b610c2990611407565b6108895780f35b513d84823e3d90fd5b610c44919250611407565b6104a457848638610bc5565b85513d89823e3d90fd5b8780fd5b5050fd5b5091903461025057602036600319011261025057823582526003602052808220918254926003810154928582015460018060a01b0391826005850154169260028501541693610cb0816116ad565b956003871015610cef5760e0898960ff8a8a8a8a8a60068b01549681519889526020890152870152606086015260808501521660a083015260c0820152f35b634e487b7160e01b815260218a52602490fd5b50503461025057816003193601126102505760085490516001600160a01b039091168152602090f35b509190366003190160a081126101ca576060136102505760643580151580611127575b610d57906115e9565b6002548251631f50820b60e21b815233868201908152608435602080830191909152966001600160a01b039593909291889183918290036040019082908a908a165af1801561111d579087916110f4575b5050828552600686528185209560249687359283156110b9578588526003835284882090610dd5826116ad565b60038110156110a75761105a57803588811680910361055b5788600584015416036110225785519960608b019a808c1067ffffffffffffffff8d1117611010578798999a9b88528b868c610e276113f1565b8085528285018b81526044359d86018e9052949082169384610f1a575050505050513403610ec15750506006905b01610e6184825461162a565b905533600052808252610e7883856000205461162a565b903360005282528360002055825195610e8f6113f1565b1686528501528301527f27b16580fa2ea712cc42940322bda733d5eda86b4e41a6a5cd8362adbb9d10cc60603393a380f35b865162461bcd60e51b8152918201859052602e908201527f6578706563746564207061796d656e7420616d6f756e74206d7573742065717560448201526d185b081cd95b9d08185b5bdd5b9d60921b6064820152608490fd5b909192958d9795949715600014610fa05750505191518a516323b872dd60e01b8152339481019485523060208601526040850191909152945084928390036060019183918f91165af18015610f96579060069291610f79575b50610e55565b610f8f90853d8711610480576104708183611469565b5038610f73565b86513d8c823e3d90fd5b94935094505050833b156101ca5760c490838a519586948593637921219560e11b8552339085015230908401528c60448401528a606484015260a060848401528160a48401525af18015610f9657610ffc575b50600690610e55565b986110096006929a611407565b9890610ff3565b50634e487b7160e01b8a526041825289fd5b855162461bcd60e51b81529081018490526013818b01527215dc9bdb99c81d1bdad95b881c185e5b595b9d606a1b6044820152606490fd5b855162461bcd60e51b81529081018490526022818b01527f43616e6e6f742066756e642070726f6a65637420616674657220646561646c696044820152616e6560f01b6064820152608490fd5b634e487b7160e01b8a52602182528a8afd5b845162461bcd60e51b81529081018390526016818a015275125b9d985b1a5908199d5b991a5b99c8185b5bdd5b9d60521b6044820152606490fd5b813d8311611116575b6111078183611469565b8101031261082b578538610da8565b503d6110fd565b83513d88823e3d90fd5b50600554811115610d4e565b50346101ca5760203660031901126101ca5735825260036020908152918190206002015490516001600160a01b039091168152f35b5050346102505781600319360112610250576020906005549051908152f35b9050838334610250578160031936011261025057919290600554936111ab856114ee565b946111b885519687611469565b8086526111c4816114ee565b60209190601f1901845b8181106112e757505060019460015b8281111561126c5750505084519481860192828752875180945282828801980194915b84831061120d5787890388f35b855180518a52808501516001600160a01b039081168b8701528183015181168b840152606080830151908c0152608080830151908c015260a080830151909116908b015260c090810151908a0152978101979483019491860191611200565b80869495989699979952600385528584206000198201908282116112d457906112976112a89261158b565b6112a1828b611561565b5288611561565b5060001981146112c157880197959796939294966111dd565b634e487b7160e01b845260118252602484fd5b634e487b7160e01b865260118452602486fd5b9280949795936112f8999799611506565b82828a0101520197959796939294966111ce565b5050503461025057816003193601126102505760025490516001600160a01b039091168152602090f35b5050346101ca57816003193601126101ca576024356001600160a01b038116919082900361024c5792829160209435825260068552828220908252845220549051908152f35b939150503461024c57602036600319011261024c578060e094833581526003602052209081549260018060a01b03918260018501541690836002860154169160066003870154948701549560058801541696015496885260208801528601526060850152608084015260a083015260c0820152f35b600435906001600160a01b038216820361024757565b67ffffffffffffffff811161141b57604052565b634e487b7160e01b600052604160045260246000fd5b6080810190811067ffffffffffffffff82111761141b57604052565b60e0810190811067ffffffffffffffff82111761141b57604052565b90601f8019910116810190811067ffffffffffffffff82111761141b57604052565b67ffffffffffffffff811161141b57601f01601f191660200190565b81601f82011215610247578035906114be8261148b565b926114cc6040519485611469565b8284526020838301011161024757816000926020809301838601378301015290565b67ffffffffffffffff811161141b5760051b60200190565b604051906115138261144d565b8160c06000918281528260208201528260408201528260608201528260808201528260a08201520152565b9190820391821161154b57565b634e487b7160e01b600052601160045260246000fd5b80518210156115755760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b906040516115988161144d565b8254815260018301546001600160a01b039081166020830152600284015481166040830152600384015460608301526004840154608083015260058401541660a082015260069092015460c0830152565b156115f057565b60405162461bcd60e51b8152602060048201526012602482015271125b9d985b1a59081c1c9bda9958dd08125160721b6044820152606490fd5b9190820180921161154b57565b6004356001600160a01b03811681036102475790565b60005b8381106116605750506000910152565b8181015183820152602001611650565b906020916116898151809281855285808601910161164d565b601f01601f1916010190565b90816020910312610247575180151581036102475790565b60068101546003820154116116c25750600190565b600401544210156116d257600090565b600290565b6000546001600160a01b031633036116eb57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b93929361177d60018060a01b039586600254169360409485519384926316a709c960e21b845261176b6004976060898701526064860190611670565b84810360031901602486015290611670565b906044830152816020948592038173f07cB2cc32Be71ee856cC3F15bFcD3Bc4cd6F7A35af49081156119ee576000916119b8575b506005548551634000a8a960e11b815296918916929184888781875afa9788156119ad57600098611973575b506117e6611506565b50821561193257428911156118ef57600182018092116118da578695949392916006918b9851996118168b61144d565b828b5289878c0191168152888b019b8c96875260608c0195865260808c019081528a60a08d019316835260c08c0193600085526000526003885289600020958c519b8c88558060018901945116936001600160601b0360a01b94858254161790556002880198511697888482541617905551600387015551888601558c60058601925116908254161790555191015560005252600020555160055551167fdea458b889f1ff572931e5a15c1d834f165099a5381b6b264683153e666b7ce8600080a2565b601186634e487b7160e01b6000525260246000fd5b865162461bcd60e51b8152808701869052601d60248201527f446561646c696e652063616e277420626520696e2074686520706173740000006044820152606490fd5b60648686808a519262461bcd60e51b845283015260248201527f46756e64696e6720676f616c206d757374206265206d6f7265207468616e20306044820152fd5b8581819a939a3d83116119a6575b61198b8183611469565b810103126102505751908a82168203610889575096386117dd565b503d611981565b87513d6000823e3d90fd5b8381813d83116119e7575b6119cd8183611469565b8101031261025057519088821682036108895750386117b1565b503d6119c3565b85513d6000823e3d90fd5b60608101514210611a0b575061465090565b6040611a199101514261153e565b9056fea26469706673582212202a8d5d04899a6dabf47da80e4ade015f320f10c138854b671ee856c44fcd801064736f6c63430008180033", "deployedBytecode": "0x6080604081815260048036101561001557600080fd5b60009260e0843560e01c918263107046bd1461137c57508163208359481461133657816321eefb9a1461130c5781632adf13b2146111875750806336fbad26146111685780634ca3e9b8146111335780634fd42f3a14610d2b57806350e76c8e14610d0257806358f36c1314610c62578381635b02f18c14610b515750806360ae7c3b146108c1578063661962661461088c578063715018a61461082f5780637f3a25d8146106695780638da5cb5b146106415780639c9e07ba14610618578063a6ae0aac146105ef578063c366164214610254578063da5e19d6146101ce5763f2fde38b1461010457600080fd5b346101ca5760203660031901126101ca5761011d6113f1565b906101266116d7565b6001600160a01b03918216928315610178575050600054826001600160601b0360a01b821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8280fd5b8382346102505760a03660031901126102505767ffffffffffffffff813581811161024c5761020090369084016114a7565b9160243591821161024c57610217913691016114a7565b604435916001600160a01b038316830361024757610244926102376116d7565b608435926064359261172f565b80f35b600080fd5b8380fd5b5080fd5b50346101ca576020918260031936011261024c576008548151627eeac760e11b8152338185019081528435602082018190526001600160a01b03938416918790849081906040010381855afa9283156105e55788936105b6575b508215610569578451637c89f5df60e01b8152868101829052918883602481845afa92831561055f5789936104e0575b506080838051810103126104dc578551906102f882611431565b88840151825286840151938983019485526080606082015191898501928352015190606084019182528b60608c828c519161033283611431565b818352820152828c8201520152610348846119f9565b86518181029181830414901517156104c7576146506103769104809861036f828a5161153e565b895261153e565b95895194518c86015251898501525160608401525160808301526080825260a082019382851067ffffffffffffffff8611176104b25790849392918b958952813b156104a45785859384928296636c49c79360e11b85523360a484015260c483015260e48201526080610104820152609f19906103f7610124820182611670565b0301925af180156104a857610490575b505080610412578580f35b600754835163a9059cbb60e01b8152339581019586526020860192909252909385928592169082908890829060400103925af19081156104875750610459575b8080808580f35b8161047892903d10610480575b6104708183611469565b810190611695565b503880610452565b503d610466565b513d85823e3d90fd5b61049990611407565b6104a4578538610407565b8580fd5b85513d84823e3d90fd5b604189634e487b7160e01b6000525260246000fd5b60118b634e487b7160e01b6000525260246000fd5b8880fd5b9092503d808a833e6104f28183611469565b810190888183031261055b5780519067ffffffffffffffff8211610557570181601f8201121561055b5780516105278161148b565b9261053489519485611469565b8184528a828401011161055757610550918a808501910161164d565b91386102de565b8a80fd5b8980fd5b86513d8b823e3d90fd5b845162461bcd60e51b8152808701889052602160248201527f50726f6a65637446756e64696e673a204e6f7468696e6720746f20756e6c6f636044820152606b60f81b6064820152608490fd5b9092508681813d83116105de575b6105ce8183611469565b81010312610247575191386102ae565b503d6105c4565b85513d8a823e3d90fd5b50503461025057816003193601126102505760015490516001600160a01b039091168152602090f35b50503461025057816003193601126102505760075490516001600160a01b039091168152602090f35b505034610250578160031936011261025057905490516001600160a01b039091168152602090f35b50346101ca573660031901610100811261024c5782136101ca5767ffffffffffffffff60443581811161082b576106a390369084016114a7565b9060643590811161082b576106bb90369084016114a7565b916084356001600160a01b03818116918290036102475760a43592818416840361024757816001541633036107e8576005546107a5576020610734899284610701611637565b8b516323b872dd60e01b815233938101938452306020850152602435604085015295869492909116928492839160600190565b03925af1801561079b57610244975061077c575b50610751611637565b166001600160601b0360a01b90816007541617600755600254161760025560e4359260c4359261172f565b6107949060203d602011610480576104708183611469565b5038610748565b87513d8a823e3d90fd5b606490602088519162461bcd60e51b8352820152601b60248201527f50726f6a65637420616c726561647920696e697469616c697a656400000000006044820152fd5b606490602088519162461bcd60e51b8352820152601a60248201527f43616c6c6572206973206e6f742074686520636f696e626173650000000000006044820152fd5b8480fd5b83346108895780600319360112610889576108486116d7565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b50346101ca5760203660031901126101ca5760209282916001600160a01b036108b36113f1565b168252845220549051908152f35b5090346101ca576020908160031936011261024c5782359283855260068352818520906108ec611506565b5084865260038452828620610903815415156115e9565b61090c816116ad565b6003811015610b3e57600103610afb57336000528285528360002054928315610ac557906109459133600052865287856000205561158b565b60018060a01b039081868201511690888760c0830193606485518a51948593849263da96192160e01b84528c8c85015233602485015260448401525af18015610abb57908891610a92575b5050516001146109ce575b5050507f30ef556644d7bab0fb4b399fb53bd396fdd3faf30c1dc80bccca41f0155a42f39282519485528401523392a280f35b6a06146c4c5b31f4edf7d0f58402906a06146c4c5b31f4edf7d0f41985830401610a7d5751918215610a6857908893929160085416803b1561082b5786516394bf804d60e01b81529290910492820192835233602084015290918391839182908490829060400103925af18015610a5e57610a4a575b8061099b565b610a5390611407565b61082b578438610a44565b84513d84823e3d90fd5b601284634e487b7160e01b6000525260246000fd5b601184634e487b7160e01b6000525260246000fd5b813d8311610ab4575b610aa58183611469565b81010312610247578638610990565b503d610a9b565b87513d8c823e3d90fd5b845162461bcd60e51b8152808401879052601060248201526f139bc819195c1bdcda5d08199bdd5b9960821b6044820152606490fd5b835162461bcd60e51b8152808301869052601a60248201527f50726f6a656374206e6f7420796574207375636365737366756c0000000000006044820152606490fd5b634e487b7160e01b885260218352602488fd5b92905034610c5e576020366003190112610c5e57610b6d6116d7565b8135835260036020528083206002805490820180546001600160a01b039593928616908616813b15610c5a5787916024839288519485938492630f8ad6f360e31b84528a8401525af18015610c505786918891610c39575b50506006915416910154936001541690803b156104a4578351637361991560e01b81529283019485526001600160a01b03909116602085015290928491849182908490829060400103925af1908115610c305750610c205750f35b610c2990611407565b6108895780f35b513d84823e3d90fd5b610c44919250611407565b6104a457848638610bc5565b85513d89823e3d90fd5b8780fd5b5050fd5b5091903461025057602036600319011261025057823582526003602052808220918254926003810154928582015460018060a01b0391826005850154169260028501541693610cb0816116ad565b956003871015610cef5760e0898960ff8a8a8a8a8a60068b01549681519889526020890152870152606086015260808501521660a083015260c0820152f35b634e487b7160e01b815260218a52602490fd5b50503461025057816003193601126102505760085490516001600160a01b039091168152602090f35b509190366003190160a081126101ca576060136102505760643580151580611127575b610d57906115e9565b6002548251631f50820b60e21b815233868201908152608435602080830191909152966001600160a01b039593909291889183918290036040019082908a908a165af1801561111d579087916110f4575b5050828552600686528185209560249687359283156110b9578588526003835284882090610dd5826116ad565b60038110156110a75761105a57803588811680910361055b5788600584015416036110225785519960608b019a808c1067ffffffffffffffff8d1117611010578798999a9b88528b868c610e276113f1565b8085528285018b81526044359d86018e9052949082169384610f1a575050505050513403610ec15750506006905b01610e6184825461162a565b905533600052808252610e7883856000205461162a565b903360005282528360002055825195610e8f6113f1565b1686528501528301527f27b16580fa2ea712cc42940322bda733d5eda86b4e41a6a5cd8362adbb9d10cc60603393a380f35b865162461bcd60e51b8152918201859052602e908201527f6578706563746564207061796d656e7420616d6f756e74206d7573742065717560448201526d185b081cd95b9d08185b5bdd5b9d60921b6064820152608490fd5b909192958d9795949715600014610fa05750505191518a516323b872dd60e01b8152339481019485523060208601526040850191909152945084928390036060019183918f91165af18015610f96579060069291610f79575b50610e55565b610f8f90853d8711610480576104708183611469565b5038610f73565b86513d8c823e3d90fd5b94935094505050833b156101ca5760c490838a519586948593637921219560e11b8552339085015230908401528c60448401528a606484015260a060848401528160a48401525af18015610f9657610ffc575b50600690610e55565b986110096006929a611407565b9890610ff3565b50634e487b7160e01b8a526041825289fd5b855162461bcd60e51b81529081018490526013818b01527215dc9bdb99c81d1bdad95b881c185e5b595b9d606a1b6044820152606490fd5b855162461bcd60e51b81529081018490526022818b01527f43616e6e6f742066756e642070726f6a65637420616674657220646561646c696044820152616e6560f01b6064820152608490fd5b634e487b7160e01b8a52602182528a8afd5b845162461bcd60e51b81529081018390526016818a015275125b9d985b1a5908199d5b991a5b99c8185b5bdd5b9d60521b6044820152606490fd5b813d8311611116575b6111078183611469565b8101031261082b578538610da8565b503d6110fd565b83513d88823e3d90fd5b50600554811115610d4e565b50346101ca5760203660031901126101ca5735825260036020908152918190206002015490516001600160a01b039091168152f35b5050346102505781600319360112610250576020906005549051908152f35b9050838334610250578160031936011261025057919290600554936111ab856114ee565b946111b885519687611469565b8086526111c4816114ee565b60209190601f1901845b8181106112e757505060019460015b8281111561126c5750505084519481860192828752875180945282828801980194915b84831061120d5787890388f35b855180518a52808501516001600160a01b039081168b8701528183015181168b840152606080830151908c0152608080830151908c015260a080830151909116908b015260c090810151908a0152978101979483019491860191611200565b80869495989699979952600385528584206000198201908282116112d457906112976112a89261158b565b6112a1828b611561565b5288611561565b5060001981146112c157880197959796939294966111dd565b634e487b7160e01b845260118252602484fd5b634e487b7160e01b865260118452602486fd5b9280949795936112f8999799611506565b82828a0101520197959796939294966111ce565b5050503461025057816003193601126102505760025490516001600160a01b039091168152602090f35b5050346101ca57816003193601126101ca576024356001600160a01b038116919082900361024c5792829160209435825260068552828220908252845220549051908152f35b939150503461024c57602036600319011261024c578060e094833581526003602052209081549260018060a01b03918260018501541690836002860154169160066003870154948701549560058801541696015496885260208801528601526060850152608084015260a083015260c0820152f35b600435906001600160a01b038216820361024757565b67ffffffffffffffff811161141b57604052565b634e487b7160e01b600052604160045260246000fd5b6080810190811067ffffffffffffffff82111761141b57604052565b60e0810190811067ffffffffffffffff82111761141b57604052565b90601f8019910116810190811067ffffffffffffffff82111761141b57604052565b67ffffffffffffffff811161141b57601f01601f191660200190565b81601f82011215610247578035906114be8261148b565b926114cc6040519485611469565b8284526020838301011161024757816000926020809301838601378301015290565b67ffffffffffffffff811161141b5760051b60200190565b604051906115138261144d565b8160c06000918281528260208201528260408201528260608201528260808201528260a08201520152565b9190820391821161154b57565b634e487b7160e01b600052601160045260246000fd5b80518210156115755760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b906040516115988161144d565b8254815260018301546001600160a01b039081166020830152600284015481166040830152600384015460608301526004840154608083015260058401541660a082015260069092015460c0830152565b156115f057565b60405162461bcd60e51b8152602060048201526012602482015271125b9d985b1a59081c1c9bda9958dd08125160721b6044820152606490fd5b9190820180921161154b57565b6004356001600160a01b03811681036102475790565b60005b8381106116605750506000910152565b8181015183820152602001611650565b906020916116898151809281855285808601910161164d565b601f01601f1916010190565b90816020910312610247575180151581036102475790565b60068101546003820154116116c25750600190565b600401544210156116d257600090565b600290565b6000546001600160a01b031633036116eb57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b93929361177d60018060a01b039586600254169360409485519384926316a709c960e21b845261176b6004976060898701526064860190611670565b84810360031901602486015290611670565b906044830152816020948592038173__$e813fe76784a54ae344e441c6251fea768$__5af49081156119ee576000916119b8575b506005548551634000a8a960e11b815296918916929184888781875afa9788156119ad57600098611973575b506117e6611506565b50821561193257428911156118ef57600182018092116118da578695949392916006918b9851996118168b61144d565b828b5289878c0191168152888b019b8c96875260608c0195865260808c019081528a60a08d019316835260c08c0193600085526000526003885289600020958c519b8c88558060018901945116936001600160601b0360a01b94858254161790556002880198511697888482541617905551600387015551888601558c60058601925116908254161790555191015560005252600020555160055551167fdea458b889f1ff572931e5a15c1d834f165099a5381b6b264683153e666b7ce8600080a2565b601186634e487b7160e01b6000525260246000fd5b865162461bcd60e51b8152808701869052601d60248201527f446561646c696e652063616e277420626520696e2074686520706173740000006044820152606490fd5b60648686808a519262461bcd60e51b845283015260248201527f46756e64696e6720676f616c206d757374206265206d6f7265207468616e20306044820152fd5b8581819a939a3d83116119a6575b61198b8183611469565b810103126102505751908a82168203610889575096386117dd565b503d611981565b87513d6000823e3d90fd5b8381813d83116119e7575b6119cd8183611469565b8101031261025057519088821682036108895750386117b1565b503d6119c3565b85513d6000823e3d90fd5b60608101514210611a0b575061465090565b6040611a199101514261153e565b9056fea26469706673582212202a8d5d04899a6dabf47da80e4ade015f320f10c138854b671ee856c44fcd801064736f6c63430008180033", "libraries": { diff --git a/packages/backend/deployments/opbnb/SmartHousing.json b/packages/backend/deployments/opbnb/SmartHousing.json index b6c7402..b2caf85 100644 --- a/packages/backend/deployments/opbnb/SmartHousing.json +++ b/packages/backend/deployments/opbnb/SmartHousing.json @@ -1397,7 +1397,7 @@ ], "numDeployments": 2, "solcInputHash": "3f7696dcd180eba0f188ae64ff117803", - "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"conibase\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"projectFunding\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"PRBMathUD60x18__Exp2InputTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"PRBMathUD60x18__LogInputTooSmall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"prod1\",\"type\":\"uint256\"}],\"name\":\"PRBMath__MulDivFixedPointOverflow\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"prod1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"name\":\"PRBMath__MulDivOverflow\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct TokenPayment[]\",\"name\":\"projectTokens\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"projectsShareCheckpoint\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtRewardPerShare\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stakeWeight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lkDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lkShtNonce\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"struct HstAttributes\",\"name\":\"attributes\",\"type\":\"tuple\"}],\"name\":\"MintHstToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"referralId\",\"type\":\"uint256\"}],\"name\":\"ReferralAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"userId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"name\":\"UserRegistered\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_EPOCHS_LOCK\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_EPOCHS_LOCK\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"projectAddress\",\"type\":\"address\"}],\"name\":\"addProject\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"addProjectRent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"hstTokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"name\":\"claimRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"coinbaseAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"name\":\"createRefID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"name\":\"createRefIDViaProxy\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"distributionStorage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"totalFunds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"genesisEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectsTotalReceivedRents\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lastFundsDispatchEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtTotalStakeWeight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtRewardPerShare\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtStakingRewards\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"toShare\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"checkpoint\",\"type\":\"uint256\"}],\"internalType\":\"struct ProjectStakingRewards.Value\",\"name\":\"projectsStakingRewards\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"team\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"protocol\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"growth\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"staking\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectsReserve\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lpAndListing\",\"type\":\"uint256\"}],\"internalType\":\"struct Entities.Value\",\"name\":\"entityFunds\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"epochsAndPeriodsStorage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"genesis\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"epochLength\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"getNonces\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"getRawTokenAttributes\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"}],\"name\":\"getReferrals\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"referralAddress\",\"type\":\"address\"}],\"internalType\":\"struct UserModule.ReferralInfo[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"}],\"name\":\"getReferrer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"referrerAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"}],\"name\":\"getUserId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"userId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"hasSFT\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hst\",\"outputs\":[{\"internalType\":\"contract HousingStakingToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct TokenPayment[]\",\"name\":\"projectTokens\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"projectsShareCheckpoint\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtRewardPerShare\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lkDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lkShtNonce\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct TokenPayment[]\",\"name\":\"projectTokens\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"projectsShareCheckpoint\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtRewardPerShare\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stakeWeight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lkDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lkShtNonce\",\"type\":\"uint256\"}],\"internalType\":\"struct HstAttributes\",\"name\":\"attr\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"permissions\",\"outputs\":[{\"internalType\":\"enum SmartHousing.Permissions\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"project\",\"type\":\"address\"}],\"name\":\"projectDets\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"maxShares\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"receivedRents\",\"type\":\"uint256\"}],\"internalType\":\"struct Distribution.ProjectDistributionData\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"projectFundingAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"projectsToken\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ERC20TokenPayment\",\"name\":\"payment\",\"type\":\"tuple\"}],\"name\":\"setUpSHT\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"shtTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct TokenPayment[]\",\"name\":\"stakingTokens\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"epochsLock\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"name\":\"stake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenInfo\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"attr\",\"type\":\"bytes\"}],\"name\":\"update\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"userCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"userIdToAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"users\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract allows for fractional ownership and ease of investment. This innovative approach addresses the high costs and limited access to real estate investments in Abuja, Nigeria, making the market more inclusive and accessible. By selling tokens, SmartHousing provides developers with immediate access to liquid funds, ensuring the timely and quality completion of affordable development projects. The SmartHousing Contract is the main contract for the SmartHousing ecosystem. This contract owns and deploys HousingProject contracts, which will represent the properties owned and managed by the SmartHousing project. The management of ecosystem users will also be done in this contract.\",\"events\":{\"ApprovalForAll(address,address,bool)\":{\"details\":\"Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`.\"},\"TransferBatch(address,address,address,uint256[],uint256[])\":{\"details\":\"Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all transfers.\"},\"TransferSingle(address,address,address,uint256,uint256)\":{\"details\":\"Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\"},\"URI(string,uint256)\":{\"details\":\"Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. If an {URI} event was emitted for `id`, the standard https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value returned by {IERC1155MetadataURI-uri}.\"}},\"kind\":\"dev\",\"methods\":{\"addProject(address)\":{\"params\":{\"projectAddress\":\"The address of the new project.\"}},\"addProjectRent(uint256)\":{\"details\":\"projectAddress is the msg.msg.sender which must be a recognised HousingProject contract\",\"params\":{\"amount\":\"The amount of rent received.\"}},\"balanceOf(address,uint256)\":{\"details\":\"See {IERC1155-balanceOf}. Requirements: - `account` cannot be the zero address.\"},\"balanceOfBatch(address[],uint256[])\":{\"details\":\"See {IERC1155-balanceOfBatch}. Requirements: - `accounts` and `ids` must have the same length.\"},\"createRefID(uint256)\":{\"params\":{\"referrerId\":\"The ID of the referrer.\"},\"returns\":{\"_0\":\"The ID of the registered user.\"}},\"createRefIDViaProxy(address,uint256)\":{\"params\":{\"referrerId\":\"The ID of the referrer.\",\"userAddr\":\"The address of the user.\"},\"returns\":{\"_0\":\"The ID of the registered user.\"}},\"getReferrer(address)\":{\"params\":{\"userAddress\":\"The address of the user.\"},\"returns\":{\"referrerAddress\":\"The address of the referrer, address(0) if none.\",\"referrerId\":\"The ID of the referrer, 0 if none.\"}},\"isApprovedForAll(address,address)\":{\"details\":\"See {IERC1155-isApprovedForAll}.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"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.\"},\"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\":{\"details\":\"See {IERC1155-safeBatchTransferFrom}.\"},\"safeTransferFrom(address,address,uint256,uint256,bytes)\":{\"details\":\"See {IERC1155-safeTransferFrom}.\"},\"setApprovalForAll(address,bool)\":{\"details\":\"See {IERC1155-setApprovalForAll}.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"uri(uint256)\":{\"details\":\"See {IERC1155MetadataURI-uri}. This implementation returns the same URI for *all* token types. It relies on the token type ID substitution mechanism https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. Clients calling this function must replace the `\\\\{id\\\\}` substring with the actual token type ID.\"}},\"title\":\"SmartHousing\",\"version\":1},\"userdoc\":{\"errors\":{\"PRBMathUD60x18__Exp2InputTooBig(uint256)\":[{\"notice\":\"Emitted when the input is greater than 192.\"}],\"PRBMathUD60x18__LogInputTooSmall(uint256)\":[{\"notice\":\"Emitted when the input is less than 1.\"}],\"PRBMath__MulDivFixedPointOverflow(uint256)\":[{\"notice\":\"Emitted when the result overflows uint256.\"}],\"PRBMath__MulDivOverflow(uint256,uint256)\":[{\"notice\":\"Emitted when the result overflows uint256.\"}]},\"kind\":\"user\",\"methods\":{\"addProject(address)\":{\"notice\":\"Adds a new project and sets its permissions.\"},\"addProjectRent(uint256)\":{\"notice\":\"Adds rent to a project and updates the distribution storage.\"},\"createRefID(uint256)\":{\"notice\":\"Register a new user or get the referral ID if already registered.\"},\"createRefIDViaProxy(address,uint256)\":{\"notice\":\"Register a new user via proxy or get the referral ID if already registered.\"},\"getReferrer(address)\":{\"notice\":\"Gets the referrer and referrer ID of a user.\"},\"update(address,uint256,uint256,bytes)\":{\"notice\":\"Burns all the NFT balance of user at nonce, creates new with balance and attributes\"}},\"notice\":\"SmartHousing leverages blockchain technology to revolutionize real estate investment and development by enabling the tokenization of properties.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/main/SmartHousing.sol\":\"SmartHousing\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../token/ERC20/IERC20.sol\\\";\\n\",\"keccak256\":\"0x6ebf1944ab804b8660eb6fc52f9fe84588cee01c2566a69023e59497e7d27f45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0xd917747dc87f189c6779b894f367a028f9dca4be930283cccec8f312966af820\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n // decrementing then incrementing.\\n _balances[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n unchecked {\\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n _balances[account] += amount;\\n }\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n // Overflow not possible: amount <= accountBalance <= totalSupply.\\n _totalSupply -= amount;\\n }\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x4ffc0547c02ad22925310c585c0f166f8759e2648a09e9b489100c42f15dd98d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../ERC20.sol\\\";\\nimport \\\"../../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\\n * tokens and those that they have an allowance for, in a way that can be\\n * recognized off-chain (via event analysis).\\n */\\nabstract contract ERC20Burnable is Context, ERC20 {\\n /**\\n * @dev Destroys `amount` tokens from the caller.\\n *\\n * See {ERC20-_burn}.\\n */\\n function burn(uint256 amount) public virtual {\\n _burn(_msgSender(), amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, deducting from the caller's\\n * allowance.\\n *\\n * See {ERC20-_burn} and {ERC20-allowance}.\\n *\\n * Requirements:\\n *\\n * - the caller must have allowance for ``accounts``'s tokens of at least\\n * `amount`.\\n */\\n function burnFrom(address account, uint256 amount) public virtual {\\n _spendAllowance(account, _msgSender(), amount);\\n _burn(account, amount);\\n }\\n}\\n\",\"keccak256\":\"0x0d19410453cda55960a818e02bd7c18952a5c8fe7a3036e81f0d599f34487a7b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf96f969e24029d43d0df89e59d365f277021dac62b48e1c1e3ebe0acdd7f1ca1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Counters.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Counters\\n * @author Matt Condon (@shrugs)\\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\\n *\\n * Include with `using Counters for Counters.Counter;`\\n */\\nlibrary Counters {\\n struct Counter {\\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\\n // this feature: see https://github.com/ethereum/solidity/issues/4637\\n uint256 _value; // default: 0\\n }\\n\\n function current(Counter storage counter) internal view returns (uint256) {\\n return counter._value;\\n }\\n\\n function increment(Counter storage counter) internal {\\n unchecked {\\n counter._value += 1;\\n }\\n }\\n\\n function decrement(Counter storage counter) internal {\\n uint256 value = counter._value;\\n require(value > 0, \\\"Counter: decrement overflow\\\");\\n unchecked {\\n counter._value = value - 1;\\n }\\n }\\n\\n function reset(Counter storage counter) internal {\\n counter._value = 0;\\n }\\n}\\n\",\"keccak256\":\"0xf0018c2440fbe238dd3a8732fa8e17a0f9dce84d31451dc8a32f6d62b349c9f1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0f633a0223d9a1dcccfcf38a64c9de0874dfcbfac0c6941ccf074d63a2ce0e1e\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * ```\\n * contract Example {\\n * // Add the library methods\\n * using EnumerableSet for EnumerableSet.AddressSet;\\n *\\n * // Declare a set state variable\\n * EnumerableSet.AddressSet private mySet;\\n * }\\n * ```\\n *\\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\\n * and `uint256` (`UintSet`) are supported.\\n *\\n * [WARNING]\\n * ====\\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\\n * unusable.\\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\\n *\\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\\n * array of EnumerableSet.\\n * ====\\n */\\nlibrary EnumerableSet {\\n // To implement this library for multiple types with as little code\\n // repetition as possible, we write it in terms of a generic Set type with\\n // bytes32 values.\\n // The Set implementation uses private functions, and user-facing\\n // implementations (such as AddressSet) are just wrappers around the\\n // underlying Set.\\n // This means that we can only create new EnumerableSets for types that fit\\n // in bytes32.\\n\\n struct Set {\\n // Storage of set values\\n bytes32[] _values;\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(bytes32 => uint256) _indexes;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function _add(Set storage set, bytes32 value) private returns (bool) {\\n if (!_contains(set, value)) {\\n set._values.push(value);\\n // The value is stored at length-1, but we add 1 to all indexes\\n // and use 0 as a sentinel value\\n set._indexes[value] = set._values.length;\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function _remove(Set storage set, bytes32 value) private returns (bool) {\\n // We read and store the value's index to prevent multiple reads from the same storage slot\\n uint256 valueIndex = set._indexes[value];\\n\\n if (valueIndex != 0) {\\n // Equivalent to contains(set, value)\\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\\n // the array, and then remove the last element (sometimes called as 'swap and pop').\\n // This modifies the order of the array, as noted in {at}.\\n\\n uint256 toDeleteIndex = valueIndex - 1;\\n uint256 lastIndex = set._values.length - 1;\\n\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set._values[lastIndex];\\n\\n // Move the last value to the index where the value to delete is\\n set._values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\\n }\\n\\n // Delete the slot where the moved value was stored\\n set._values.pop();\\n\\n // Delete the index for the deleted slot\\n delete set._indexes[value];\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\\n return set._indexes[value] != 0;\\n }\\n\\n /**\\n * @dev Returns the number of values on the set. O(1).\\n */\\n function _length(Set storage set) private view returns (uint256) {\\n return set._values.length;\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\\n return set._values[index];\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function _values(Set storage set) private view returns (bytes32[] memory) {\\n return set._values;\\n }\\n\\n // Bytes32Set\\n\\n struct Bytes32Set {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _add(set._inner, value);\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _remove(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return _contains(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return _at(set._inner, index);\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n bytes32[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // AddressSet\\n\\n struct AddressSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n return _add(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n return _remove(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\\n return address(uint160(uint256(_at(set._inner, index))));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(AddressSet storage set) internal view returns (address[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n address[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // UintSet\\n\\n struct UintSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(UintSet storage set, uint256 value) internal returns (bool) {\\n return _add(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\\n return _remove(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(UintSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\\n return uint256(_at(set._inner, index));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(UintSet storage set) internal view returns (uint256[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n uint256[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xc3ff3f5c4584e1d9a483ad7ced51ab64523201f4e3d3c65293e4ca8aeb77a961\",\"license\":\"MIT\"},\"contracts/housing-project/CallsSmartHousing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nabstract contract CallsSmartHousing {\\n\\t/// @notice The address of the main SmartHousing contract.\\n\\taddress immutable smartHousingAddr;\\n\\n\\tconstructor(address smartHousingAddr_) {\\n\\t\\tsmartHousingAddr = smartHousingAddr_;\\n\\t}\\n\\n\\t/// @dev Gets the referrer address for a given original owner.\\n\\t/// @param userAddr The original owner of the token.\\n\\t/// @return The referrer address.\\n\\tfunction getReferrer(\\n\\t\\taddress userAddr\\n\\t) internal view returns (uint, address) {\\n\\t\\treturn IUserModule(smartHousingAddr).getReferrer(userAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0xd2ded3c751d669f079d12e7381e586b747cb9ae1b6d9bd4dbd87fc9db3b0371c\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingProject.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"./RentsModule.sol\\\";\\n\\n/// @title HousingProject Contract\\n/// @notice Represents a unique real estate project within the SmartHousing ecosystem.\\n/// @dev This contract inherits from RentsModule and HousingSFT.\\ncontract HousingProject is RentsModule, Ownable {\\n\\t/// @notice Initializes the HousingProject contract.\\n\\t/// @param smartHousingAddr The address of the main SmartHousing contract.\\n\\tconstructor(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) CallsSmartHousing(smartHousingAddr) {\\n\\t\\tprojectSFT = new HousingSFT(name, symbol);\\n\\t}\\n\\n\\tevent TokenIssued(address tokenAddress, string name, uint256 amountRaised);\\n\\n\\tfunction setTokenDetails(\\n\\t\\tuint256 amountRaised,\\n\\t\\taddress housingTokenAddr\\n\\t) external onlyOwner {\\n\\t\\trequire(amountRaised == 0, \\\"Token details set already\\\");\\n\\n\\t\\thousingToken = ERC20Burnable(housingTokenAddr);\\n\\n\\t\\tprojectSFT.setAmountRaised(amountRaised);\\n\\t\\tstring memory name = projectSFT.name();\\n\\n\\t\\temit TokenIssued(address(projectSFT), name, amountRaised);\\n\\t}\\n\\n\\tfunction getMaxSupply() public view returns (uint256) {\\n\\t\\treturn projectSFT.getMaxSupply();\\n\\t}\\n}\\n\",\"keccak256\":\"0x159e6b338c47a2dacbec1254f582826b5584c338919e6e6908aba986f9a98350\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingSFT.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\n\\nimport \\\"../modules/SFT.sol\\\";\\n\\nstruct HousingAttributes {\\n\\tuint256 rewardsPerShare;\\n\\taddress originalOwner;\\n\\tuint256 tokenWeight;\\n}\\n\\n/// @title Housing SFT\\n/// @notice This contract represents a semi-fungible token (SFT) for housing projects.\\n/// @dev This contract will be inherited by the HousingProject contract.\\ncontract HousingSFT is SFT {\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct HousingSFTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tHousingAttributes attributes;\\n\\t}\\n\\n\\t// FIXME this value should be unique to each contract, should depend on\\n\\t// the total amount expected to raise as it determines the amount of SFTs to\\n\\t// be minted for investors\\n\\tuint256 public constant MAX_SUPPLY = 1_000_000;\\n\\n\\t/// @notice The amount of fungible tokens collected from investors to finance the development of this housing project.\\n\\tuint256 public amountRaised;\\n\\n\\t/// @notice The current amount out of the `MAX_SUPPLY` of tokens minted.\\n\\tuint256 public totalSupply;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tfunction setAmountRaised(uint256 amountRaised_) external onlyOwner {\\n\\t\\tamountRaised = amountRaised_;\\n\\t}\\n\\n\\tmodifier canMint() {\\n\\t\\taddress sftOwner = owner();\\n\\n\\t\\trequire(\\n\\t\\t\\tOwnable(sftOwner).owner() == _msgSender(),\\n\\t\\t\\t\\\"not allowed to mint\\\"\\n\\t\\t);\\n\\n\\t\\t_;\\n\\t}\\n\\n\\t/// @notice Mints SFT tokens for a depositor based on the amount of deposit.\\n\\t/// @param depositAmt The amount of fungible token deposited.\\n\\t/// @param depositor The address of the depositor.\\n\\tfunction mintSFT(\\n\\t\\tuint256 depositAmt,\\n\\t\\taddress depositor,\\n\\t\\tuint256 amount_raised\\n\\t) external canMint returns (uint256) {\\n\\t\\t// TODO remove after demo due to not beign able to move blocks in public networks\\n\\t\\t{\\n\\t\\t\\tamountRaised = amount_raised;\\n\\t\\t}\\n\\n\\t\\tuint256 totalDeposits = amountRaised;\\n\\t\\tuint256 maxShares = MAX_SUPPLY;\\n\\n\\t\\trequire(totalDeposits > 0, \\\"HousingSFT: No deposits recorded\\\");\\n\\n\\t\\tuint256 mintShare = (depositAmt * maxShares) / totalDeposits;\\n\\t\\trequire(mintShare > 0, \\\"HousingSFT: Computed token shares is invalid\\\");\\n\\n\\t\\ttotalSupply += mintShare;\\n\\t\\trequire(totalSupply <= MAX_SUPPLY, \\\"HousingSFT: Max supply exceeded\\\");\\n\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tHousingAttributes({\\n\\t\\t\\t\\trewardsPerShare: 0, // Should be 0 since they have never claimed any rent rewards\\n\\t\\t\\t\\toriginalOwner: depositor,\\n\\t\\t\\t\\ttokenWeight: mintShare\\n\\t\\t\\t})\\n\\t\\t);\\n\\n\\t\\treturn _mint(depositor, mintShare, attributes, \\\"\\\");\\n\\t}\\n\\n\\t/// @notice Checks if an address owns this HousingSFT and returns the attributes.\\n\\t/// @param owner The address to check the balance of.\\n\\t/// @return `HousingAttributes` if the owner has a positive balance of the token, panics otherwise.\\n\\tfunction getUserSFT(\\n\\t\\taddress owner,\\n\\t\\tuint256 nonce\\n\\t) public view returns (HousingAttributes memory) {\\n\\t\\trequire(\\n\\t\\t\\thasSFT(owner, nonce),\\n\\t\\t\\t\\\"HouisingSFT: No tokens found for user at nonce\\\"\\n\\t\\t);\\n\\n\\t\\treturn abi.decode(getRawTokenAttributes(nonce), (HousingAttributes));\\n\\t}\\n\\n\\tfunction getMaxSupply() public pure returns (uint256) {\\n\\t\\treturn MAX_SUPPLY;\\n\\t}\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (HousingSFTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tHousingSFTBalance[] memory balance = new HousingSFTBalance[](\\n\\t\\t\\t_sftBals.length\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = HousingSFTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(_sftBal.attributes, (HousingAttributes))\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\tfunction tokenDetails()\\n\\t\\tpublic\\n\\t\\tview\\n\\t\\treturns (string memory, string memory, uint256)\\n\\t{\\n\\t\\treturn (name(), symbol(), getMaxSupply());\\n\\t}\\n}\\n\",\"keccak256\":\"0x8fbbe8d670bc777eed8587d0a8b11acf1d7b40b9ae631fee4abc929f4275c160\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/NewHousingProjectLib.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport { HousingProject } from \\\"./HousingProject.sol\\\";\\n\\nlibrary NewHousingProject {\\n\\tfunction create(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) external returns (HousingProject) {\\n\\t\\treturn new HousingProject(name, symbol, smartHousingAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0x0ad286112bdc35e59e9424ffda000b7b6b582e228cca1cafc2b9cab28193628f\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/RentsModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\\\";\\n\\nimport \\\"./HousingSFT.sol\\\";\\nimport \\\"./RewardSharing.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"./CallsSmartHousing.sol\\\";\\n\\n/// @title Rents Module\\n/// @notice Handles rent payments, reward calculations, and distribution for Housing projects.\\n/// @dev This abstract contract should be inherited by the HousingProject contract.\\nabstract contract RentsModule is CallsSmartHousing {\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\tusing RewardShares for rewardshares;\\n\\n\\tuint256 public rewardPerShare;\\n\\tuint256 public rewardsReserve;\\n\\tuint256 public facilityManagementFunds;\\n\\n\\tERC20Burnable housingToken;\\n\\tHousingSFT public projectSFT;\\n\\n\\t/// @notice Receives rent payments and distributes rewards.\\n\\t/// @param rentPayment The details of the rent payment.\\n\\tfunction receiveRent(ERC20TokenPayment calldata rentPayment) external {\\n\\t\\t// TODO set the appropriate rent per Project\\n\\t\\trequire(\\n\\t\\t\\trentPayment.amount > 0,\\n\\t\\t\\t\\\"RentsModule: Insufficient rent amount\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\trentPayment.token == housingToken,\\n\\t\\t\\t\\\"RentsModule: Invalid rent payment token\\\"\\n\\t\\t);\\n\\t\\trentPayment.receiveERC20();\\n\\n\\t\\tuint256 rentReward = (rentPayment.amount * 75) / 100;\\n\\t\\tuint256 ecosystemReward = (rentPayment.amount * 18) / 100;\\n\\t\\tuint256 facilityReward = (rentPayment.amount * 7) / 100;\\n\\n\\t\\tuint256 allShares = projectSFT.getMaxSupply();\\n\\t\\tuint256 rpsIncrease = (rentReward * DIVISION_SAFETY_CONST) / allShares;\\n\\n\\t\\trewardPerShare += rpsIncrease;\\n\\t\\trewardsReserve += rentReward;\\n\\t\\tfacilityManagementFunds += facilityReward;\\n\\n\\t\\thousingToken.burn(ecosystemReward);\\n\\t\\tISmartHousing(smartHousingAddr).addProjectRent(rentPayment.amount);\\n\\t}\\n\\n\\t/// @notice Claims rent rewards for a given token.\\n\\t/// @return The updated HousingAttributes.\\n\\tfunction claimRentReward(\\n\\t\\tuint256 nonce\\n\\t) external returns (HousingAttributes memory, rewardshares memory) {\\n\\t\\taddress caller = msg.sender;\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tHousingAttributes memory attr = projectSFT.getUserSFT(caller, nonce);\\n\\t\\trewardshares memory rewardShares = computeRewardShares(attr);\\n\\t\\tuint256 totalReward = rewardShares.total();\\n\\n\\t\\tif (totalReward == 0) {\\n\\t\\t\\t// Fail silently\\n\\t\\t\\treturn (attr, rewardShares);\\n\\t\\t}\\n\\n\\t\\trequire(rewardsReserve >= totalReward, \\\"Computed rewards too large\\\");\\n\\n\\t\\trewardsReserve -= totalReward;\\n\\n\\t\\t// We use original owner since we are certain they are registered\\n\\t\\t(, address referrer) = getReferrer(attr.originalOwner);\\n\\t\\tif (rewardShares.referrerValue > 0) {\\n\\t\\t\\tif (referrer != address(0)) {\\n\\t\\t\\t\\thousingToken.transfer(referrer, rewardShares.referrerValue); // Send to referrer\\n\\t\\t\\t} else {\\n\\t\\t\\t\\thousingToken.burn(rewardShares.referrerValue); // Burn to add to ecosystem reward\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tattr.rewardsPerShare = currentRPS;\\n\\n\\t\\tprojectSFT.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tprojectSFT.balanceOf(caller, nonce),\\n\\t\\t\\tabi.encode(attr)\\n\\t\\t);\\n\\n\\t\\thousingToken.transfer(caller, rewardShares.userValue); // Send to user\\n\\n\\t\\treturn (attr, rewardShares);\\n\\t}\\n\\n\\t/// @notice Computes the amount of rent claimable for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The amount of rent claimable.\\n\\tfunction rentClaimable(\\n\\t\\tHousingAttributes memory attr\\n\\t) public view returns (uint256) {\\n\\t\\treturn computeRewardShares(attr).userValue;\\n\\t}\\n\\n\\t/// @dev Computes the reward shares for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The computed RewardShares.\\n\\tfunction computeRewardShares(\\n\\t\\tHousingAttributes memory attr\\n\\t) internal view returns (rewardshares memory) {\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tif (currentRPS == 0 || attr.rewardsPerShare >= currentRPS) {\\n\\t\\t\\treturn rewardshares({ userValue: 0, referrerValue: 0 });\\n\\t\\t}\\n\\n\\t\\tuint256 reward = computeReward(attr, currentRPS);\\n\\n\\t\\treturn splitReward(reward);\\n\\t}\\n}\\n\",\"keccak256\":\"0xe97c64b7d4f5a945493aa8492c4412248f60ec1e6e8cd74e3f805e40cc672768\",\"license\":\"MIT\"},\"contracts/housing-project/RewardSharing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"./HousingSFT.sol\\\";\\n\\nuint256 constant DIVISION_SAFETY_CONST = 1_000_000_000_000_000_000;\\n\\nstruct rewardshares {\\n\\tuint256 userValue;\\n\\tuint256 referrerValue;\\n}\\n\\nlibrary RewardShares {\\n\\tfunction total(rewardshares memory self) internal pure returns (uint256) {\\n\\t\\treturn self.userValue + self.referrerValue;\\n\\t}\\n}\\n\\nfunction splitReward(uint256 reward) pure returns (rewardshares memory) {\\n\\tuint256 referrerValue = (reward * 6_66) / 100_00; // would amount to approximately 5% of grand total\\n\\tuint256 userValue = reward - referrerValue;\\n\\n\\treturn rewardshares(userValue, referrerValue);\\n}\\n\\nfunction computeReward(\\n\\tHousingAttributes memory attr,\\n\\tuint256 contractRPS\\n) pure returns (uint256) {\\n\\tif (contractRPS <= attr.rewardsPerShare) {\\n\\t\\treturn 0;\\n\\t}\\n\\n\\treturn\\n\\t\\t((contractRPS - attr.rewardsPerShare) * attr.tokenWeight) /\\n\\t\\tDIVISION_SAFETY_CONST;\\n}\\n\",\"keccak256\":\"0x9f07d2b3ee49b91e12ad7ce9ba248ab7dd30bc2efc4238a594e681d3f0348e54\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/lib/EpochsAndPeriods.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\n/// @title Epochs and Periods Management Library\\n/// @notice This library provides functions to manage and calculate epochs and periods based on a genesis timestamp and an epoch length.\\n/// @dev The epoch length is specified in hours, and the period is calculated as 30 epochs.\\nlibrary EpochsAndPeriods {\\n\\tstruct Storage {\\n\\t\\tuint256 genesis;\\n\\t\\tuint256 epochLength;\\n\\t}\\n\\n\\t/// @notice Initializes the storage with the current timestamp as the genesis and sets the epoch length.\\n\\t/// @param self The storage struct to initialize.\\n\\t/// @param _epochLength The length of an epoch in hours. This determines how long each epoch lasts.\\n\\t/// @dev This function should be called in the contract constructor to set the initial genesis timestamp and epoch length.\\n\\tfunction initialize(Storage storage self, uint256 _epochLength) internal {\\n\\t\\tself.genesis = block.timestamp;\\n\\t\\tself.epochLength = _epochLength;\\n\\t}\\n\\n\\t/// @notice Returns the current epoch based on the genesis timestamp and epoch length.\\n\\t/// @param self The storage struct containing the genesis timestamp and epoch length.\\n\\t/// @return The current epoch number.\\n\\t/// @dev The epoch is calculated by dividing the time elapsed since genesis by the epoch length in seconds.\\n\\tfunction currentEpoch(\\n\\t\\tStorage storage self\\n\\t) internal view returns (uint256) {\\n\\t\\trequire(self.genesis > 0, \\\"Invalid genesis timestamp\\\");\\n\\t\\treturn (block.timestamp - self.genesis) / (self.epochLength * 60 * 60);\\n\\t}\\n\\n\\t/// @notice Returns the current period based on the current epoch.\\n\\t/// @param self The storage struct containing the genesis timestamp and epoch length.\\n\\t/// @return The current period number.\\n\\t/// @dev The period is calculated by dividing the current epoch by 30.\\n\\tfunction currentPeriod(\\n\\t\\tStorage storage self\\n\\t) internal view returns (uint256) {\\n\\t\\treturn currentEpoch(self) / 30;\\n\\t}\\n}\\n\",\"keccak256\":\"0x1f41385e5d5eb0a27b0b7262b8caf99e89806036a8fd6c512bc123e7eb1fbbbd\",\"license\":\"MIT\"},\"contracts/lib/LkSHTAttributes.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title LkSHTAttributes\\n * @dev Library for handling attributes and unlocking of the Locked SmartHousing Token.\\n */\\nlibrary LkSHTAttributes {\\n\\tusing SafeMath for uint256;\\n\\n\\t// TODO use this for mainnet uint256 constant LOCK_DURATION = 3 * 365 days; // 3 years\\n\\tuint256 constant LOCK_DURATION = 5 hours;\\n\\n\\tstruct Attributes {\\n\\t\\tuint256 initialAmount;\\n\\t\\tuint256 amount;\\n\\t\\tuint256 startTimestamp;\\n\\t\\tuint256 endTimestamp;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Creates new attributes for a Locked SmartHousing Token.\\n\\t * @param startTimestamp The start time of the lock.\\n\\t * @param amount The amount of SmartHousing Tokens locked.\\n\\t * @return attributes The initialized attributes.\\n\\t */\\n\\tfunction newAttributes(\\n\\t\\tuint256 startTimestamp,\\n\\t\\tuint256 amount\\n\\t) internal pure returns (Attributes memory) {\\n\\t\\treturn\\n\\t\\t\\tAttributes({\\n\\t\\t\\t\\tinitialAmount: amount,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tstartTimestamp: startTimestamp,\\n\\t\\t\\t\\tendTimestamp: startTimestamp.add(LOCK_DURATION)\\n\\t\\t\\t});\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calculates and deducts the unlocked amount based on the elapsed time.\\n\\t * @param self The attributes to update.\\n\\t * @return unlockedAmount The amount of tokens unlocked.\\n\\t */\\n\\tfunction unlockMatured(\\n\\t\\tAttributes memory self\\n\\t)\\n\\t\\tinternal\\n\\t\\tview\\n\\t\\treturns (uint256 unlockedAmount, Attributes memory newSelf)\\n\\t{\\n\\t\\tuint256 elapsed = elapsedTime(self);\\n\\t\\tunlockedAmount = self.amount.mul(elapsed).div(LOCK_DURATION);\\n\\n\\t\\tself.amount = self.amount.sub(unlockedAmount);\\n\\t\\tnewSelf = self;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calculates the elapsed time since the lock started.\\n\\t * @param self The attributes to use.\\n\\t * @return elapsedTime The elapsed time in seconds.\\n\\t */\\n\\tfunction elapsedTime(\\n\\t\\tAttributes memory self\\n\\t) internal view returns (uint256) {\\n\\t\\tuint256 currentTime = block.timestamp;\\n\\t\\tif (currentTime >= self.endTimestamp) {\\n\\t\\t\\treturn LOCK_DURATION;\\n\\t\\t} else {\\n\\t\\t\\treturn currentTime.sub(self.startTimestamp);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0xbaf851bef9603c72b3cce96d93f8f243f36187d31c8c94233101d802b9ae129d\",\"license\":\"MIT\"},\"contracts/lib/ProjectStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport \\\"./TokenPayments.sol\\\";\\n\\nlibrary ProjectStorage {\\n\\tusing SafeMath for uint256;\\n\\tusing TokenPayments for TokenPayment;\\n\\tusing ProjectStorage for Data;\\n\\n\\tenum Status {\\n\\t\\tFundingPeriod,\\n\\t\\tSuccessful,\\n\\t\\tFailed\\n\\t}\\n\\n\\tstruct Data {\\n\\t\\tuint256 id; // Unique identifier for the project\\n\\t\\taddress tokenAddress;\\n\\t\\taddress projectAddress; // Address of the deployed HousingProject contract\\n\\t\\tuint256 fundingGoal; // Target funding amount for the project\\n\\t\\tuint256 fundingDeadline; // Deadline timestamp for the project funding\\n\\t\\taddress fundingToken; // Address of the ERC20 token used for funding\\n\\t\\tuint256 collectedFunds; // Amount of funds collected for the project\\n\\t}\\n\\n\\tfunction status(Data storage self) internal view returns (Status) {\\n\\t\\tif (self.collectedFunds >= self.fundingGoal) {\\n\\t\\t\\treturn Status.Successful;\\n\\t\\t} else if (block.timestamp < self.fundingDeadline) {\\n\\t\\t\\treturn Status.FundingPeriod;\\n\\t\\t} else {\\n\\t\\t\\treturn Status.Failed;\\n\\t\\t}\\n\\t}\\n\\n\\tfunction createNew(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage projectsId,\\n\\t\\tuint256 projectCount,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline,\\n\\t\\taddress fundingToken,\\n\\t\\taddress projectAddress,\\n\\t\\taddress tokenAddress\\n\\t) internal returns (Data memory) {\\n\\t\\trequire(fundingGoal > 0, \\\"Funding goal must be more than 0\\\");\\n\\t\\trequire(\\n\\t\\t\\tfundingDeadline > block.timestamp,\\n\\t\\t\\t\\\"Deadline can't be in the past\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 newId = projectCount.add(1);\\n\\n\\t\\tData memory newProjectData = Data({\\n\\t\\t\\tid: newId,\\n\\t\\t\\tprojectAddress: projectAddress,\\n\\t\\t\\tfundingGoal: fundingGoal,\\n\\t\\t\\tfundingDeadline: fundingDeadline,\\n\\t\\t\\tfundingToken: fundingToken,\\n\\t\\t\\tcollectedFunds: 0,\\n\\t\\t\\ttokenAddress: tokenAddress\\n\\t\\t});\\n\\n\\t\\tprojects[newId] = newProjectData;\\n\\t\\tprojectsId[newProjectData.projectAddress] = newProjectData.id;\\n\\n\\t\\treturn newProjectData;\\n\\t}\\n\\n\\tfunction fund(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage usersDeposit,\\n\\t\\tuint256 projectId,\\n\\t\\taddress depositor,\\n\\t\\tTokenPayment calldata payment\\n\\t) internal {\\n\\t\\trequire(payment.amount > 0, \\\"Invalid funding amount\\\");\\n\\n\\t\\tData storage project = projects[projectId];\\n\\n\\t\\trequire(\\n\\t\\t\\tproject.status() == Status.FundingPeriod,\\n\\t\\t\\t\\\"Cannot fund project after deadline\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\taddress(payment.token) == project.fundingToken,\\n\\t\\t\\t\\\"Wrong token payment\\\"\\n\\t\\t);\\n\\t\\tpayment.receiveToken();\\n\\n\\t\\tproject.collectedFunds = project.collectedFunds.add(payment.amount);\\n\\t\\tusersDeposit[depositor] = usersDeposit[depositor].add(payment.amount);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Retrieves and updates the user's deposit for a specific project.\\n\\t * @param projectId The ID of the project to retrieve the deposit for.\\n\\t * @param depositor The address of the depositor.\\n\\t * @return (ProjectStorage.Data, uint256) The project data and deposit amount.\\n\\t */\\n\\tfunction takeDeposit(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage usersDeposit,\\n\\t\\tuint256 projectId,\\n\\t\\taddress depositor\\n\\t) internal returns (ProjectStorage.Data memory, uint256) {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\trequire(project.id != 0, \\\"Invalid project ID\\\");\\n\\t\\trequire(\\n\\t\\t\\tproject.status() == Status.Successful,\\n\\t\\t\\t\\\"Project not yet successful\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 depositAmount = usersDeposit[depositor];\\n\\t\\trequire(depositAmount > 0, \\\"No deposit found\\\");\\n\\n\\t\\t// Update the deposit amount to zero\\n\\t\\tusersDeposit[depositor] = 0;\\n\\n\\t\\treturn (project, depositAmount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x652aab2dc03764c430b91f35e908430208d6a1bd27a4cc8060adb1ec7f249ad5\",\"license\":\"MIT\"},\"contracts/lib/TokenPayments.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/interfaces/IERC20.sol\\\";\\nimport { SFT } from \\\"../modules/SFT.sol\\\";\\n\\nstruct ERC20TokenPayment {\\n\\tIERC20 token;\\n\\tuint256 amount;\\n}\\n\\nstruct TokenPayment {\\n\\taddress token;\\n\\tuint256 amount;\\n\\tuint256 nonce;\\n}\\n\\nlibrary TokenPayments {\\n\\tfunction accept(ERC20TokenPayment calldata self) internal {\\n\\t\\tTokenPayments.receiveERC20(self, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(ERC20TokenPayment calldata payment) internal {\\n\\t\\tTokenPayments.receiveERC20(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(\\n\\t\\tERC20TokenPayment calldata payment,\\n\\t\\taddress from\\n\\t) internal {\\n\\t\\tpayment.token.transferFrom(from, address(this), payment.amount);\\n\\t}\\n\\n\\t// Receives both Native, SFTs and ERC20; ERC20 have nonce as 0, Native coins have address 0 as token value\\n\\tfunction receiveToken(TokenPayment memory payment) internal {\\n\\t\\treceiveToken(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveToken(TokenPayment memory payment, address from) internal {\\n\\t\\tif (payment.token == address(0)) {\\n\\t\\t\\t// Native payment\\n\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tpayment.amount == msg.value,\\n\\t\\t\\t\\t\\\"expected payment amount must equal sent amount\\\"\\n\\t\\t\\t);\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tfrom == msg.sender,\\n\\t\\t\\t\\t\\\"can receive native payment only from caller\\\"\\n\\t\\t\\t);\\n\\t\\t\\t\\n\\t\\t\\t// Nothing to do again since the VM will handle balance movements\\n\\t\\t} else if (payment.nonce == 0) {\\n\\t\\t\\tIERC20(payment.token).transferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.amount\\n\\t\\t\\t);\\n\\t\\t} else {\\n\\t\\t\\tSFT(payment.token).safeTransferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.nonce,\\n\\t\\t\\t\\tpayment.amount,\\n\\t\\t\\t\\t\\\"\\\"\\n\\t\\t\\t);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x06bd73e8da1bde18d9aaf6d4b6a1bdec6e0718af6354fe2d7ce87251d6fd1ac5\",\"license\":\"MIT\"},\"contracts/main/HST.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\n\\nimport { TokenPayment } from \\\"../lib/TokenPayments.sol\\\";\\nimport { SFT } from \\\"../modules/SFT.sol\\\";\\n\\nlibrary NewHousingStakingToken {\\n\\tfunction create() external returns (HousingStakingToken) {\\n\\t\\treturn new HousingStakingToken();\\n\\t}\\n}\\n\\nstruct HstAttributes {\\n\\tTokenPayment[] projectTokens;\\n\\tuint256 projectsShareCheckpoint;\\n\\tuint256 shtRewardPerShare;\\n\\tuint256 shtAmount;\\n\\tuint256 stakeWeight;\\n\\tuint256 lkDuration;\\n\\tuint256 lkShtNonce;\\n}\\n\\ncontract HousingStakingToken is SFT {\\n\\tusing SafeMath for uint256;\\n\\n\\tuint256 public constant MIN_EPOCHS_LOCK = 180;\\n\\tuint256 public constant MAX_EPOCHS_LOCK = 1080;\\n\\n\\tevent MintHstToken(\\n\\t\\taddress indexed to,\\n\\t\\tuint256 nonce,\\n\\t\\tHstAttributes attributes\\n\\t);\\n\\n\\tconstructor() SFT(\\\"Housing Staking Token\\\", \\\"HST\\\") {}\\n\\n\\tfunction mint(\\n\\t\\tTokenPayment[] calldata projectTokens,\\n\\t\\tuint256 projectsShareCheckpoint,\\n\\t\\tuint256 shtRewardPerShare,\\n\\t\\tuint256 lkDuration,\\n\\t\\tuint256 shtAmount,\\n\\t\\tuint256 lkShtNonce\\n\\t) external onlyOwner returns (HstAttributes memory attr) {\\n\\t\\taddress caller = msg.sender;\\n\\n\\t\\t// Validate lock duration\\n\\t\\trequire(\\n\\t\\t\\tlkDuration >= MIN_EPOCHS_LOCK && lkDuration <= MAX_EPOCHS_LOCK,\\n\\t\\t\\t\\\"Invalid lock duration\\\"\\n\\t\\t);\\n\\n\\t\\trequire(shtAmount > 0 || lkShtNonce > 0, \\\"Must send SHT\\\");\\n\\t\\tuint256 projectTokenCount = projectTokens.length;\\n\\t\\trequire(\\n\\t\\t\\tprojectTokenCount > 0 && projectTokenCount <= 10,\\n\\t\\t\\t\\\"Must send project tokens of approved number\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 stakeWeight = shtAmount.mul(lkDuration);\\n\\t\\tattr = HstAttributes({\\n\\t\\t\\tprojectTokens: projectTokens,\\n\\t\\t\\tprojectsShareCheckpoint: projectsShareCheckpoint,\\n\\t\\t\\tshtRewardPerShare: shtRewardPerShare,\\n\\t\\t\\tshtAmount: shtAmount,\\n\\t\\t\\tstakeWeight: stakeWeight,\\n\\t\\t\\tlkDuration: lkDuration,\\n\\t\\t\\tlkShtNonce: lkShtNonce\\n\\t\\t});\\n\\n\\t\\t// Mint the HST token\\n\\t\\tuint256 nonce = _mint(caller, 1, abi.encode(attr), \\\"\\\");\\n\\n\\t\\temit MintHstToken(caller, nonce, attr);\\n\\t}\\n}\\n\",\"keccak256\":\"0x4f0e5e502fd02a59ed29b264e0894e4a79230d59a42e6f1fe389c5078d3f6d0d\",\"license\":\"MIT\"},\"contracts/main/Interface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"../lib/TokenPayments.sol\\\";\\n\\ninterface ISmartHousing {\\n\\tfunction addProjectRent(uint256 amount) external;\\n\\n\\tfunction createRefIDViaProxy(\\n\\t\\taddress userAddr,\\n\\t\\tuint256 referrerId\\n\\t) external returns (uint256);\\n\\n\\tfunction addProject(address projectAddress) external;\\n\\n\\tfunction setUpSHT(ERC20TokenPayment calldata payment) external;\\n}\\n\\ninterface IUserModule {\\n\\tfunction getReferrer(address user) external view returns (uint, address);\\n}\\n\",\"keccak256\":\"0x066719eed5c5ff2394d78ce027aada5a8555713c9f4abf8b5135975981ba9989\",\"license\":\"MIT\"},\"contracts/main/SmartHousing.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\\\";\\n\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"../modules/sht-module/SHT.sol\\\";\\nimport \\\"../project-funding/ProjectFunding.sol\\\";\\n\\nimport \\\"./Interface.sol\\\";\\nimport \\\"./User.sol\\\";\\n\\nimport { Distribution } from \\\"./distribution/Storage.sol\\\";\\nimport { EpochsAndPeriods } from \\\"../lib/EpochsAndPeriods.sol\\\";\\nimport { HousingStakingToken, NewHousingStakingToken, HstAttributes } from \\\"./HST.sol\\\";\\n\\nimport { HousingProject } from \\\"../housing-project/HousingProject.sol\\\";\\nimport { rewardshares } from \\\"../housing-project/RewardSharing.sol\\\";\\n\\n/// @title SmartHousing\\n/// @notice SmartHousing leverages blockchain technology to revolutionize real estate investment and development by enabling the tokenization of properties.\\n/// @dev This contract allows for fractional ownership and ease of investment.\\n/// This innovative approach addresses the high costs and limited access to real estate investments in Abuja, Nigeria, making the market more inclusive and accessible.\\n/// By selling tokens, SmartHousing provides developers with immediate access to liquid funds, ensuring the timely and quality completion of affordable development projects.\\n/// The SmartHousing Contract is the main contract for the SmartHousing ecosystem.\\n/// This contract owns and deploys HousingProject contracts, which will represent the properties owned and managed by the SmartHousing project.\\n/// The management of ecosystem users will also be done in this contract.\\ncontract SmartHousing is\\n\\tISmartHousing,\\n\\tOwnable,\\n\\tUserModule,\\n\\tHousingStakingToken\\n{\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\tusing Distribution for Distribution.Storage;\\n\\tusing EpochsAndPeriods for EpochsAndPeriods.Storage;\\n\\tusing EnumerableSet for EnumerableSet.AddressSet;\\n\\tusing TokenPayments for TokenPayment;\\n\\tusing SafeMath for uint256;\\n\\n\\taddress public projectFundingAddress;\\n\\taddress public coinbaseAddress;\\n\\taddress public shtTokenAddress;\\n\\tHousingStakingToken public hst;\\n\\n\\tDistribution.Storage public distributionStorage;\\n\\tEpochsAndPeriods.Storage public epochsAndPeriodsStorage;\\n\\n\\tenum Permissions {\\n\\t\\tNONE,\\n\\t\\tHOUSING_PROJECT\\n\\t}\\n\\n\\tmapping(address => Permissions) public permissions;\\n\\tEnumerableSet.AddressSet private _projectsToken; // Enumerable list of project addresses\\n\\n\\tconstructor(address conibase, address projectFunding) {\\n\\t\\tcoinbaseAddress = conibase;\\n\\t\\tprojectFundingAddress = projectFunding;\\n\\t\\thst = NewHousingStakingToken.create();\\n\\n\\t\\t// TODO use this for mainnet epochsAndPeriodsStorage.initialize(24); // One epoch will span 24 hours\\n\\t\\tepochsAndPeriodsStorage.initialize(1); // One epoch will span 1 hour\\n\\t}\\n\\n\\t/// @notice Register a new user via proxy or get the referral ID if already registered.\\n\\t/// @param userAddr The address of the user.\\n\\t/// @param referrerId The ID of the referrer.\\n\\t/// @return The ID of the registered user.\\n\\tfunction createRefIDViaProxy(\\n\\t\\taddress userAddr,\\n\\t\\tuint256 referrerId\\n\\t) external onlyProjectFunding returns (uint256) {\\n\\t\\treturn _createOrGetUserId(userAddr, referrerId);\\n\\t}\\n\\n\\tfunction setUpSHT(ERC20TokenPayment calldata payment) external {\\n\\t\\trequire(\\n\\t\\t\\tmsg.sender == coinbaseAddress,\\n\\t\\t\\t\\\"Caller is not the coinbase address\\\"\\n\\t\\t);\\n\\n\\t\\t// Ensure that the SHT token has not been set already\\n\\t\\trequire(shtTokenAddress == address(0), \\\"SHT token already set\\\");\\n\\t\\tshtTokenAddress = address(payment.token);\\n\\n\\t\\t// Verify that the correct amount of SHT has been sent\\n\\t\\trequire(\\n\\t\\t\\tpayment.amount == SHT.ECOSYSTEM_DISTRIBUTION_FUNDS,\\n\\t\\t\\t\\\"Must send all ecosystem funds\\\"\\n\\t\\t);\\n\\t\\tpayment.accept();\\n\\n\\t\\t// Set the total funds in distribution storage\\n\\t\\tdistributionStorage.setTotalFunds(\\n\\t\\t\\tepochsAndPeriodsStorage,\\n\\t\\t\\tpayment.amount\\n\\t\\t);\\n\\t}\\n\\n\\t/// @notice Adds a new project and sets its permissions.\\n\\t/// @param projectAddress The address of the new project.\\n\\tfunction addProject(address projectAddress) external onlyProjectFunding {\\n\\t\\t_setPermissions(projectAddress, Permissions.HOUSING_PROJECT);\\n\\t\\t_projectsToken.add(projectAddress); // Register the project address\\n\\t}\\n\\n\\t/// @notice Adds rent to a project and updates the distribution storage.\\n\\t/// @dev projectAddress is the msg.msg.sender which must be a recognised HousingProject contract\\n\\t/// @param amount The amount of rent received.\\n\\tfunction addProjectRent(uint256 amount) external onlyHousingProject {\\n\\t\\taddress projectAddress = msg.sender;\\n\\t\\tdistributionStorage.addProjectRent(projectAddress, amount);\\n\\t}\\n\\n\\tfunction stake(\\n\\t\\tTokenPayment[] calldata stakingTokens,\\n\\t\\tuint256 epochsLock,\\n\\t\\tuint256 referrerId\\n\\t) external payable {\\n\\t\\trequire(\\n\\t\\t\\tepochsLock >= MIN_EPOCHS_LOCK && epochsLock <= MAX_EPOCHS_LOCK,\\n\\t\\t\\t\\\"Invalid epochs lock period\\\"\\n\\t\\t);\\n\\n\\t\\taddress caller = msg.sender;\\n\\n\\t\\t// Try create ID\\n\\t\\t_createOrGetUserId(caller, referrerId);\\n\\n\\t\\t// Generate rewards before staking\\n\\t\\tdistributionStorage.generateRewards(epochsAndPeriodsStorage);\\n\\n\\t\\tHstAttributes memory newAttr = _mintHstToken(\\n\\t\\t\\tstakingTokens,\\n\\t\\t\\tdistributionStorage.projectsStakingRewards.checkpoint,\\n\\t\\t\\tdistributionStorage.shtRewardPerShare,\\n\\t\\t\\tepochsLock,\\n\\t\\t\\tshtTokenAddress,\\n\\t\\t\\taddress(ProjectFunding(projectFundingAddress).lkSht())\\n\\t\\t);\\n\\n\\t\\tdistributionStorage.enterStaking(newAttr.stakeWeight);\\n\\t}\\n\\n\\tfunction claimRewards(uint256 hstTokenId, uint256 referrerId) external {\\n\\t\\taddress caller = msg.sender;\\n\\t\\t_createOrGetUserId(caller, referrerId);\\n\\n\\t\\tuint256 callerHstBal = hst.balanceOf(caller, hstTokenId);\\n\\n\\t\\trequire(callerHstBal > 0, \\\"Caller does not own the hst token\\\");\\n\\n\\t\\tdistributionStorage.generateRewards(epochsAndPeriodsStorage);\\n\\n\\t\\t(uint256 claimedSHT, HstAttributes memory hstAttr) = distributionStorage\\n\\t\\t\\t.claimRewards(\\n\\t\\t\\t\\tabi.decode(getRawTokenAttributes(hstTokenId), (HstAttributes))\\n\\t\\t\\t);\\n\\t\\tuint256 rentRewards = 0;\\n\\n\\t\\t// Claim rent rewards from HousingProjects\\n\\t\\tfor (uint256 i = 0; i < hstAttr.projectTokens.length; i++) {\\n\\t\\t\\tTokenPayment memory projectToken = hstAttr.projectTokens[i];\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tprojectToken.token != address(0),\\n\\t\\t\\t\\t\\\"Invalid project address\\\"\\n\\t\\t\\t);\\n\\n\\t\\t\\t// Call the external contract's claimRentReward function\\n\\t\\t\\t(, rewardshares memory rewardShares) = HousingProject(\\n\\t\\t\\t\\tprojectToken.token\\n\\t\\t\\t).claimRentReward(projectToken.nonce);\\n\\n\\t\\t\\trentRewards = rentRewards.add(rewardShares.userValue);\\n\\t\\t}\\n\\n\\t\\t// Update the attributes in the hst token\\n\\t\\thst.update(caller, hstTokenId, callerHstBal, abi.encode(hstAttr));\\n\\n\\t\\tERC20Burnable shtToken = ERC20Burnable(shtTokenAddress);\\n\\n\\t\\tif (claimedSHT > 0) {\\n\\t\\t\\tuint256 referrerValue = claimedSHT.mul(25).div(1000);\\n\\t\\t\\tclaimedSHT = claimedSHT.sub(referrerValue);\\n\\n\\t\\t\\t// Do referrer operations\\n\\t\\t\\t(, address referrerAddr) = getReferrer(caller);\\n\\t\\t\\tif (referrerAddr != address(0)) {\\n\\t\\t\\t\\tshtToken.transfer(referrerAddr, referrerValue);\\n\\t\\t\\t} else {\\n\\t\\t\\t\\tshtToken.burn(referrerValue);\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tshtToken.transfer(caller, claimedSHT.add(rentRewards));\\n\\t}\\n\\n\\tfunction projectDets(\\n\\t\\taddress project\\n\\t) public view returns (Distribution.ProjectDistributionData memory) {\\n\\t\\treturn distributionStorage.projectDets[project];\\n\\t}\\n\\n\\tfunction projectsToken() public view returns (address[] memory) {\\n\\t\\treturn _projectsToken.values();\\n\\t}\\n\\n\\t/// @notice Sets the permissions for a given address.\\n\\t/// @param addr The address to set permissions for.\\n\\t/// @param perm The permissions to set.\\n\\tfunction _setPermissions(address addr, Permissions perm) internal {\\n\\t\\tpermissions[addr] = perm;\\n\\t}\\n\\n\\tfunction _mintHstToken(\\n\\t\\tTokenPayment[] calldata payments,\\n\\t\\tuint256 projectsShareCheckpoint,\\n\\t\\tuint256 shtRewardPerShare,\\n\\t\\tuint256 lkDuration,\\n\\t\\taddress shtAddress,\\n\\t\\taddress lkShtAddress\\n\\t) internal returns (HstAttributes memory attr) {\\n\\t\\taddress caller = msg.sender;\\n\\n\\t\\tuint256 maxProjectTokens = 10;\\n\\t\\tTokenPayment[] memory projectTokens = new TokenPayment[](\\n\\t\\t\\tmaxProjectTokens\\n\\t\\t);\\n\\t\\tuint256 projectTokenCount = 0;\\n\\t\\tuint256 shtAmount = 0;\\n\\t\\tuint256 lkShtNonce = 0;\\n\\n\\t\\tfor (uint256 i = 0; i < payments.length; i++) {\\n\\t\\t\\tTokenPayment memory payment = payments[i];\\n\\n\\t\\t\\tif (payment.token == shtAddress) {\\n\\t\\t\\t\\tshtAmount = payment.amount;\\n\\t\\t\\t} else if (payment.token == lkShtAddress) {\\n\\t\\t\\t\\tlkShtNonce = payment.nonce;\\n\\t\\t\\t} else if (_projectsToken.contains(payment.token)) {\\n\\t\\t\\t\\t// Validate that the payment is for an allowed project token\\n\\t\\t\\t\\trequire(\\n\\t\\t\\t\\t\\tprojectTokens.length < maxProjectTokens,\\n\\t\\t\\t\\t\\t\\\"Max project tokens exceeded\\\"\\n\\t\\t\\t\\t);\\n\\n\\t\\t\\t\\tprojectTokens[projectTokenCount] = payment;\\n\\t\\t\\t\\tprojectTokenCount++;\\n\\t\\t\\t} else {\\n\\t\\t\\t\\trevert(\\\"Invalid Sent Token\\\");\\n\\t\\t\\t}\\n\\n\\t\\t\\tpayment.receiveToken(caller);\\n\\t\\t}\\n\\n\\t\\treturn\\n\\t\\t\\thst.mint(\\n\\t\\t\\t\\tprojectTokens,\\n\\t\\t\\t\\tprojectsShareCheckpoint,\\n\\t\\t\\t\\tshtRewardPerShare,\\n\\t\\t\\t\\tlkDuration,\\n\\t\\t\\t\\tshtAmount,\\n\\t\\t\\t\\tlkShtNonce\\n\\t\\t\\t);\\n\\t}\\n\\n\\tmodifier onlyProjectFunding() {\\n\\t\\trequire(\\n\\t\\t\\tmsg.sender == projectFundingAddress,\\n\\t\\t\\t\\\"Caller is not the project funder\\\"\\n\\t\\t);\\n\\t\\t_;\\n\\t}\\n\\n\\tmodifier onlyHousingProject() {\\n\\t\\trequire(\\n\\t\\t\\tpermissions[msg.sender] == Permissions.HOUSING_PROJECT,\\n\\t\\t\\t\\\"Caller is not an accepted housing project\\\"\\n\\t\\t);\\n\\t\\t_;\\n\\t}\\n}\\n\",\"keccak256\":\"0xea1ab05257afd6f7fd39b3bc0208df82c9935977135cff846ccad9bd1f1bfd32\",\"license\":\"MIT\"},\"contracts/main/User.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"./Interface.sol\\\";\\n\\nabstract contract UserModule is IUserModule {\\n\\tstruct ReferralInfo {\\n\\t\\tuint256 id;\\n\\t\\taddress referralAddress;\\n\\t}\\n\\n\\tstruct User {\\n\\t\\tuint256 id;\\n\\t\\taddress addr;\\n\\t\\tuint256 referrerId;\\n\\t\\tuint256[] referrals;\\n\\t}\\n\\n\\tuint256 public userCount;\\n\\tmapping(address => User) public users;\\n\\tmapping(uint256 => address) public userIdToAddress;\\n\\n\\tevent UserRegistered(\\n\\t\\tuint256 userId,\\n\\t\\taddress userAddress,\\n\\t\\tuint256 referrerId\\n\\t);\\n\\tevent ReferralAdded(uint256 referrerId, uint256 referralId);\\n\\n\\t/// @notice Register a new user or get the referral ID if already registered.\\n\\t/// @param referrerId The ID of the referrer.\\n\\t/// @return The ID of the registered user.\\n\\tfunction createRefID(uint256 referrerId) external returns (uint256) {\\n\\t\\taddress userAddr = msg.sender;\\n\\t\\treturn _createOrGetUserId(userAddr, referrerId);\\n\\t}\\n\\n\\t/// @notice Gets the referrer and referrer ID of a user.\\n\\t/// @param userAddress The address of the user.\\n\\t/// @return referrerId The ID of the referrer, 0 if none.\\n\\t/// @return referrerAddress The address of the referrer, address(0) if none.\\n\\tfunction getReferrer(\\n\\t\\taddress userAddress\\n\\t) public view returns (uint256 referrerId, address referrerAddress) {\\n\\t\\tUser storage user = users[userAddress];\\n\\t\\treferrerId = user.referrerId;\\n\\t\\treferrerAddress = userIdToAddress[referrerId];\\n\\t}\\n\\n\\tfunction getUserId(\\n\\t\\taddress userAddress\\n\\t) external view returns (uint256 userId) {\\n\\t\\treturn users[userAddress].id;\\n\\t}\\n\\n\\tfunction getReferrals(\\n\\t\\taddress userAddress\\n\\t) external view returns (ReferralInfo[] memory) {\\n\\t\\tuint256[] memory referralIds = users[userAddress].referrals;\\n\\t\\tReferralInfo[] memory referrals = new ReferralInfo[](\\n\\t\\t\\treferralIds.length\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i = 0; i < referralIds.length; i++) {\\n\\t\\t\\tuint256 id = referralIds[i];\\n\\t\\t\\taddress refAddr = userIdToAddress[id];\\n\\t\\t\\treferrals[i] = ReferralInfo({ id: id, referralAddress: refAddr });\\n\\t\\t}\\n\\n\\t\\treturn referrals;\\n\\t}\\n\\n\\t/// @notice Internal function to create or get the user ID.\\n\\t/// @param userAddr The address of the user.\\n\\t/// @param referrerId The ID of the referrer.\\n\\t/// @return The ID of the user.\\n\\tfunction _createOrGetUserId(\\n\\t\\taddress userAddr,\\n\\t\\tuint256 referrerId\\n\\t) internal returns (uint256) {\\n\\t\\tif (users[userAddr].id != 0) {\\n\\t\\t\\treturn users[userAddr].id;\\n\\t\\t}\\n\\n\\t\\tuserCount++;\\n\\t\\tusers[userAddr] = User({\\n\\t\\t\\tid: userCount,\\n\\t\\t\\taddr: userAddr,\\n\\t\\t\\treferrerId: referrerId,\\n\\t\\t\\treferrals: new uint256[](0)\\n\\t\\t});\\n\\t\\tuserIdToAddress[userCount] = userAddr;\\n\\n\\t\\tif (\\n\\t\\t\\treferrerId != 0 &&\\n\\t\\t\\treferrerId != userCount &&\\n\\t\\t\\tuserIdToAddress[referrerId] != address(0)\\n\\t\\t) {\\n\\t\\t\\tusers[userIdToAddress[referrerId]].referrals.push(userCount);\\n\\t\\t\\temit ReferralAdded(referrerId, userCount);\\n\\t\\t}\\n\\n\\t\\temit UserRegistered(userCount, userAddr, referrerId);\\n\\t\\treturn userCount;\\n\\t}\\n}\\n\",\"keccak256\":\"0x206c6860f427559d04d53cac1b2e1481c8d23776afc6d54ac6ec7e76b11eb687\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/main/distribution/Storage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\nimport \\\"../../lib/EpochsAndPeriods.sol\\\";\\nimport \\\"../../housing-project/HousingProject.sol\\\";\\nimport \\\"../../modules/sht-module/Economics.sol\\\";\\nimport { HstAttributes } from \\\"../HST.sol\\\";\\n\\nlibrary ProjectStakingRewards {\\n\\tusing SafeMath for uint256;\\n\\n\\tstruct Value {\\n\\t\\tuint256 toShare;\\n\\t\\tuint256 checkpoint;\\n\\t}\\n\\n\\tfunction add(Value storage self, uint256 rhs) internal {\\n\\t\\tself.toShare = self.toShare.add(rhs);\\n\\t\\tself.checkpoint = self.checkpoint.add(rhs);\\n\\t}\\n\\n\\tfunction sub(Value storage self, uint256 rhs) internal {\\n\\t\\tself.toShare = self.toShare.sub(rhs);\\n\\t}\\n}\\n\\nlibrary Distribution {\\n\\tusing SafeMath for uint256;\\n\\tusing EpochsAndPeriods for EpochsAndPeriods.Storage;\\n\\tusing Entities for Entities.Value;\\n\\tusing ProjectStakingRewards for ProjectStakingRewards.Value;\\n\\n\\tstruct Storage {\\n\\t\\tuint256 totalFunds;\\n\\t\\tuint256 genesisEpoch;\\n\\t\\tuint256 projectsTotalReceivedRents;\\n\\t\\tmapping(address => ProjectDistributionData) projectDets;\\n\\t\\tuint256 lastFundsDispatchEpoch;\\n\\t\\tuint256 shtTotalStakeWeight;\\n\\t\\tuint256 shtRewardPerShare;\\n\\t\\tuint256 shtStakingRewards;\\n\\t\\tProjectStakingRewards.Value projectsStakingRewards;\\n\\t\\tEntities.Value entityFunds;\\n\\t}\\n\\n\\tstruct ProjectDistributionData {\\n\\t\\tuint256 maxShares;\\n\\t\\tuint256 receivedRents;\\n\\t}\\n\\n\\t/// @notice Sets the total funds and the genesis epoch. This can only be done once.\\n\\t/// @param self The storage struct to set the total funds and genesis epoch.\\n\\t/// @param amount The amount of total funds to set.\\n\\t/// @param epochsAndPeriods The storage struct for epoch and period management.\\n\\tfunction setTotalFunds(\\n\\t\\tStorage storage self,\\n\\t\\tEpochsAndPeriods.Storage storage epochsAndPeriods,\\n\\t\\tuint256 amount\\n\\t) internal {\\n\\t\\trequire(self.totalFunds == 0, \\\"Total funds already set\\\");\\n\\t\\tself.totalFunds = amount;\\n\\t\\tself.genesisEpoch = epochsAndPeriods.currentEpoch();\\n\\t}\\n\\n\\t/// @notice Returns the total funds.\\n\\t/// @param self The storage struct containing the total funds.\\n\\t/// @return The total funds.\\n\\tfunction getTotalFunds(\\n\\t\\tStorage storage self\\n\\t) internal view returns (uint256) {\\n\\t\\treturn self.totalFunds;\\n\\t}\\n\\n\\t/// @notice Returns the genesis epoch when the total funds were set.\\n\\t/// @param self The storage struct containing the genesis epoch.\\n\\t/// @return The genesis epoch.\\n\\tfunction getGenesisEpoch(\\n\\t\\tStorage storage self\\n\\t) internal view returns (uint256) {\\n\\t\\treturn self.genesisEpoch;\\n\\t}\\n\\n\\t/// @notice Adds the rent received for a project and updates the total received rents and project-specific data.\\n\\t/// @dev This function updates the total amount of rent received across all projects and updates the specific project data.\\n\\t/// If the `maxShares` for the project has not been set, it retrieves and sets it from the `HousingProject` contract.\\n\\t/// @param self The storage struct for the `Distribution` contract where project and rent data is stored.\\n\\t/// @param projectAddress The address of the project whose rent is being added.\\n\\t/// @param amount The amount of rent received to be added to the project and total received rents.\\n\\tfunction addProjectRent(\\n\\t\\tStorage storage self,\\n\\t\\taddress projectAddress,\\n\\t\\tuint256 amount\\n\\t) internal {\\n\\t\\t// Update the total received rents across all projects\\n\\t\\tself.projectsTotalReceivedRents += amount;\\n\\n\\t\\t// Retrieve or initialize project-specific data\\n\\t\\tProjectDistributionData storage projectData = self.projectDets[\\n\\t\\t\\tprojectAddress\\n\\t\\t];\\n\\n\\t\\t// If `maxShares` is not set, initialize it with the maximum supply from the HousingProject contract\\n\\t\\tif (projectData.maxShares == 0) {\\n\\t\\t\\tprojectData.maxShares = HousingProject(projectAddress)\\n\\t\\t\\t\\t.getMaxSupply();\\n\\t\\t}\\n\\n\\t\\t// Add the received rent amount to the project's accumulated rents\\n\\t\\tprojectData.receivedRents += amount;\\n\\t}\\n\\n\\t/// @notice Generates rewards for the current epoch.\\n\\t/// @param self The storage struct for the `Distribution` contract.\\n\\tfunction generateRewards(\\n\\t\\tStorage storage self,\\n\\t\\tEpochsAndPeriods.Storage storage epochsAndPeriods\\n\\t) internal {\\n\\t\\tuint256 currentEpoch = epochsAndPeriods.currentEpoch();\\n\\t\\tif (currentEpoch <= self.lastFundsDispatchEpoch) {\\n\\t\\t\\treturn;\\n\\t\\t}\\n\\n\\t\\tuint256 toDispatch = Emission.throughEpochRange(\\n\\t\\t\\tself.lastFundsDispatchEpoch,\\n\\t\\t\\tcurrentEpoch\\n\\t\\t);\\n\\t\\tEntities.Value memory entitiesValue = Entities.fromTotalValue(\\n\\t\\t\\ttoDispatch\\n\\t\\t);\\n\\n\\t\\t// Take staking value\\n\\t\\tuint256 stakingRewards = entitiesValue.staking;\\n\\t\\tentitiesValue.staking = 0;\\n\\t\\tself.entityFunds.add(entitiesValue);\\n\\n\\t\\tuint256 shtStakersShare = stakingRewards.mul(7).div(10); // 70% goes to SHT stakers\\n\\n\\t\\tuint256 totalShtWeight = self.shtTotalStakeWeight;\\n\\t\\tif (totalShtWeight > 0) {\\n\\t\\t\\tuint256 rpsIncrease = shtStakersShare\\n\\t\\t\\t\\t.mul(DIVISION_SAFETY_CONST)\\n\\t\\t\\t\\t.div(totalShtWeight);\\n\\t\\t\\tself.shtRewardPerShare = self.shtRewardPerShare.add(rpsIncrease);\\n\\t\\t}\\n\\n\\t\\tself.shtStakingRewards = self.shtStakingRewards.add(shtStakersShare);\\n\\t\\tself.projectsStakingRewards.add(stakingRewards.sub(shtStakersShare));\\n\\n\\t\\tself.lastFundsDispatchEpoch = currentEpoch;\\n\\t}\\n\\n\\t/// @notice Claims rewards for a given attribute.\\n\\t/// @param self The storage struct for the `Distribution` contract.\\n\\t/// @param attr The attributes struct for which rewards are being claimed.\\n\\t/// @return The total amount of rewards claimed.\\n\\tfunction claimRewards(\\n\\t\\tStorage storage self,\\n\\t\\tHstAttributes memory attr\\n\\t) internal returns (uint256, HstAttributes memory) {\\n\\t\\tuint256 shtClaimed = 0;\\n\\n\\t\\t// Claim PT rewards\\n\\t\\tuint256 ptRewardCheckpoint = self.projectsStakingRewards.checkpoint;\\n\\t\\tif (ptRewardCheckpoint > 0) {\\n\\t\\t\\tfor (uint256 i = 0; i < attr.projectTokens.length; i++) {\\n\\t\\t\\t\\tshtClaimed = shtClaimed.add(\\n\\t\\t\\t\\t\\tcomputeRewardForPT(\\n\\t\\t\\t\\t\\t\\tself,\\n\\t\\t\\t\\t\\t\\tattr.projectTokens[i],\\n\\t\\t\\t\\t\\t\\tattr.projectsShareCheckpoint,\\n\\t\\t\\t\\t\\t\\tptRewardCheckpoint\\n\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t);\\n\\t\\t\\t}\\n\\n\\t\\t\\tif (self.projectsStakingRewards.toShare < shtClaimed) {\\n\\t\\t\\t\\tshtClaimed = self.projectsStakingRewards.toShare;\\n\\t\\t\\t}\\n\\t\\t\\tself.projectsStakingRewards.toShare = self\\n\\t\\t\\t\\t.projectsStakingRewards\\n\\t\\t\\t\\t.toShare\\n\\t\\t\\t\\t.sub(shtClaimed);\\n\\t\\t}\\n\\n\\t\\t// Claim SHT rewards\\n\\t\\tuint256 shtRPS = self.shtRewardPerShare;\\n\\t\\tif (shtRPS > 0 && attr.shtRewardPerShare < shtRPS) {\\n\\t\\t\\tuint256 shtReward = (shtRPS.sub(attr.shtRewardPerShare))\\n\\t\\t\\t\\t.mul(attr.stakeWeight)\\n\\t\\t\\t\\t.div(DIVISION_SAFETY_CONST);\\n\\t\\t\\tif (self.shtStakingRewards < shtReward) {\\n\\t\\t\\t\\tshtClaimed = self.shtStakingRewards;\\n\\t\\t\\t}\\n\\t\\t\\tself.shtStakingRewards = self.shtStakingRewards.sub(shtReward);\\n\\n\\t\\t\\tshtClaimed = shtClaimed.add(shtReward);\\n\\t\\t}\\n\\n\\t\\t// Update claim parameters\\n\\t\\tattr.shtRewardPerShare = shtRPS;\\n\\t\\tattr.projectsShareCheckpoint = ptRewardCheckpoint;\\n\\n\\t\\treturn (shtClaimed, attr);\\n\\t}\\n\\n\\t/// @notice Computes the reward for a given PT (Housing Project Token).\\n\\t/// @param self The storage struct for the `Distribution` contract.\\n\\t/// @param tokenPayment The token payment of the housing project.\\n\\t/// @param stakingCheckPoint The previous checkpoint value.\\n\\t/// @param tokenCheckPoint The new checkpoint value.\\n\\t/// @return reward The computed reward for the given PT.\\n\\tfunction computeRewardForPT(\\n\\t\\tStorage storage self,\\n\\t\\tTokenPayment memory tokenPayment,\\n\\t\\tuint256 stakingCheckPoint,\\n\\t\\tuint256 tokenCheckPoint\\n\\t) internal view returns (uint256 reward) {\\n\\t\\tif (stakingCheckPoint >= tokenCheckPoint) {\\n\\t\\t\\treturn 0;\\n\\t\\t}\\n\\n\\t\\tProjectDistributionData storage projectData = self.projectDets[\\n\\t\\t\\ttokenPayment.token\\n\\t\\t];\\n\\t\\trequire(\\n\\t\\t\\ttokenPayment.amount <= projectData.maxShares,\\n\\t\\t\\t\\\"Project token amount too large\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 shareIncrease = tokenCheckPoint.sub(stakingCheckPoint);\\n\\t\\t// Project's allocation is dynamic, as rents received chages\\n\\t\\tuint256 projectAllocation = shareIncrease\\n\\t\\t\\t.mul(projectData.receivedRents)\\n\\t\\t\\t.div(self.projectsTotalReceivedRents);\\n\\n\\t\\treward = projectAllocation.mul(tokenPayment.amount).div(\\n\\t\\t\\tprojectData.maxShares\\n\\t\\t);\\n\\t}\\n\\n\\t/// @notice Enters staking for the given attributes.\\n\\t/// @param self The storage struct for the `Distribution` contract.\\n\\t/// @param stakeWeight The stake weight to be added.\\n\\tfunction enterStaking(Storage storage self, uint256 stakeWeight) internal {\\n\\t\\tself.shtTotalStakeWeight = self.shtTotalStakeWeight.add(stakeWeight);\\n\\t}\\n}\\n\",\"keccak256\":\"0x9fb3f9b3c9b1731783433460c46eacc05feeb3345cd9a175a65c7dacf01c46d6\",\"license\":\"MIT\"},\"contracts/modules/LockedSmartHousingToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport \\\"../lib/LkSHTAttributes.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"../modules/SFT.sol\\\";\\n\\nlibrary NewLkSHT {\\n\\tfunction create() external returns (LkSHT) {\\n\\t\\treturn new LkSHT(\\\"Locked Housing Token\\\", \\\"LkSHT\\\");\\n\\t}\\n}\\n\\n/**\\n * @title LockedSmartHousingToken\\n * @dev SFT token that locks SmartHousing Tokens (SHT) during ICO.\\n * Allows transfers only to whitelisted addresses.\\n */\\ncontract LkSHT is SFT {\\n\\tusing SafeMath for uint256;\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\n\\tstruct LkSHTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tLkSHTAttributes.Attributes attributes;\\n\\t}\\n\\n\\tuint256 immutable startTimestamp = block.timestamp;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tevent TokensMinted(address indexed to, uint256 amount);\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (LkSHTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tLkSHTBalance[] memory balance = new LkSHTBalance[](_sftBals.length);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = LkSHTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(\\n\\t\\t\\t\\t\\t_sftBal.attributes,\\n\\t\\t\\t\\t\\t(LkSHTAttributes.Attributes)\\n\\t\\t\\t\\t)\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Mints new Locked SmartHousing Tokens (LkSHT) by locking SHT.\\n\\t * @param amount The amount of SHT to lock.\\n\\t * @param to The address to mint the tokens to.\\n\\t */\\n\\tfunction mint(uint256 amount, address to) external onlyOwner {\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tLkSHTAttributes.newAttributes(startTimestamp, amount)\\n\\t\\t);\\n\\n\\t\\tsuper._mint(to, amount, attributes, \\\"LockedSmartHousingToken\\\");\\n\\n\\t\\temit TokensMinted(to, amount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x33e840a42e8bab335538d2ab9a8973c97423b17caac5fd50a802b53f6db7357d\",\"license\":\"MIT\"},\"contracts/modules/SFT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Counters.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n// TODO I think we should create a standard of this\\nabstract contract SFT is ERC1155, Ownable {\\n\\tusing Counters for Counters.Counter;\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct SftBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tbytes attributes;\\n\\t}\\n\\n\\tCounters.Counter private _nonceCounter;\\n\\tstring private _name;\\n\\tstring private _symbol;\\n\\n\\t// Mapping from nonce to token attributes as bytes\\n\\tmapping(uint256 => bytes) private _tokenAttributes;\\n\\n\\t// Mapping from address to list of owned token nonces\\n\\tmapping(address => EnumerableSet.UintSet) private _addressToNonces;\\n\\n\\tconstructor(string memory name_, string memory symbol_) ERC1155(\\\"\\\") {\\n\\t\\t_name = name_;\\n\\t\\t_symbol = symbol_;\\n\\t}\\n\\n\\t// Private function to mint new tokens\\n\\tfunction _mint(\\n\\t\\taddress to,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attributes,\\n\\t\\tbytes memory data\\n\\t) internal returns (uint256) {\\n\\t\\t_nonceCounter.increment();\\n\\t\\tuint256 nonce = _nonceCounter.current();\\n\\n\\t\\t// Store the attributes\\n\\t\\t_tokenAttributes[nonce] = attributes;\\n\\n\\t\\t// Mint the token with the nonce as its ID\\n\\t\\tsuper._mint(to, nonce, amount, data);\\n\\n\\t\\t// Track the nonce for the address\\n\\t\\t_addressToNonces[to].add(nonce);\\n\\n\\t\\treturn nonce;\\n\\t}\\n\\n\\tfunction name() public view returns (string memory) {\\n\\t\\treturn _name;\\n\\t}\\n\\n\\tfunction symbol() public view returns (string memory) {\\n\\t\\treturn _symbol;\\n\\t}\\n\\n\\tfunction tokenInfo() public view returns (string memory, string memory) {\\n\\t\\treturn (_name, _symbol);\\n\\t}\\n\\n\\t// Function to get token attributes by nonce\\n\\tfunction getRawTokenAttributes(\\n\\t\\tuint256 nonce\\n\\t) public view returns (bytes memory) {\\n\\t\\treturn _tokenAttributes[nonce];\\n\\t}\\n\\n\\t// Function to get list of nonces owned by an address\\n\\tfunction getNonces(address owner) public view returns (uint256[] memory) {\\n\\t\\treturn _addressToNonces[owner].values();\\n\\t}\\n\\n\\tfunction hasSFT(address owner, uint256 nonce) public view returns (bool) {\\n\\t\\treturn _addressToNonces[owner].contains(nonce);\\n\\t}\\n\\n\\t/// Burns all the NFT balance of user at nonce, creates new with balance and attributes\\n\\tfunction update(\\n\\t\\taddress user,\\n\\t\\tuint256 nonce,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attr\\n\\t) external onlyOwner {\\n\\t\\t_burn(user, nonce, amount);\\n\\t\\t_mint(user, amount, attr, \\\"\\\");\\n\\t}\\n\\n\\tfunction _sftBalance(\\n\\t\\taddress user\\n\\t) internal view returns (SftBalance[] memory) {\\n\\t\\tuint256[] memory nonces = getNonces(user);\\n\\t\\tSftBalance[] memory balance = new SftBalance[](nonces.length);\\n\\n\\t\\tfor (uint256 i; i < nonces.length; i++) {\\n\\t\\t\\tuint256 nonce = nonces[i];\\n\\t\\t\\tbytes memory attributes = _tokenAttributes[nonce];\\n\\t\\t\\tuint256 amount = balanceOf(user, nonce);\\n\\n\\t\\t\\tbalance[i] = SftBalance({\\n\\t\\t\\t\\tnonce: nonce,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tattributes: attributes\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t// Override _beforeTokenTransfer to handle address-to-nonce mapping\\n\\tfunction _beforeTokenTransfer(\\n\\t\\taddress operator,\\n\\t\\taddress from,\\n\\t\\taddress to,\\n\\t\\tuint256[] memory ids,\\n\\t\\tuint256[] memory amounts,\\n\\t\\tbytes memory data\\n\\t) internal virtual override {\\n\\t\\tsuper._beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[from].remove(ids[i]);\\n\\t\\t}\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[to].add(ids[i]);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x8098c36137bbb9a342d16fd64f7d57c03a77841a872dd44641b9db1623a699aa\",\"license\":\"MIT\"},\"contracts/modules/sht-module/Economics.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"prb-math/contracts/PRBMathUD60x18.sol\\\";\\n\\nlibrary Emission {\\n\\tusing PRBMathUD60x18 for uint256;\\n\\n\\tuint256 private constant DECAY_RATE = 9998e14; // 0.9998 with 18 decimals\\n\\tuint256 private constant E0 = 2729727036845720116116; // Example initial emission\\n\\n\\tfunction atEpoch(uint256 epoch) internal pure returns (uint256) {\\n\\t\\tuint256 decayFactor = PRBMathUD60x18.pow(DECAY_RATE, epoch);\\n\\t\\treturn E0.mul(decayFactor) / 1e18;\\n\\t}\\n\\n\\t/// @notice Computes E0 * \\u200b\\u200b(0.9998^epochStart \\u2212 0.9998^epochEnd\\u200b)\\n\\t/// @param epochStart the starting epoch\\n\\t/// @param epochEnd the end epoch\\n\\tfunction throughEpochRange(\\n\\t\\tuint256 epochStart,\\n\\t\\tuint256 epochEnd\\n\\t) internal pure returns (uint256) {\\n\\t\\trequire(epochEnd > epochStart, \\\"Invalid epoch range\\\");\\n\\n\\t\\tuint256 startFactor = PRBMathUD60x18.pow(DECAY_RATE, epochStart);\\n\\t\\tuint256 endFactor = PRBMathUD60x18.pow(DECAY_RATE, epochEnd);\\n\\n\\t\\tuint256 totalEmission = E0\\n\\t\\t\\t.mul(SafeMath.sub(startFactor, endFactor))\\n\\t\\t\\t.div(DECAY_RATE.ln());\\n\\t\\treturn totalEmission;\\n\\t}\\n}\\n\\nlibrary Entities {\\n\\tusing SafeMath for uint256;\\n\\n\\tuint32 public constant UNITY = 100_00;\\n\\n\\tuint32 public constant TEAM_AND_ADVISORS_RATIO = 23_05;\\n\\tuint32 public constant PROTOCOL_DEVELOPMENT_RATIO = 30_05;\\n\\tuint32 public constant GROWTH_RATIO = 15_35;\\n\\tuint32 public constant STAKING_RATIO = 16_55;\\n\\tuint32 public constant PROJECTS_RESERVE_RATIO = 8_00;\\n\\tuint32 public constant LP_AND_LISTINGS_RATIO = 7_00;\\n\\n\\tstruct Value {\\n\\t\\tuint256 team;\\n\\t\\tuint256 protocol;\\n\\t\\tuint256 growth;\\n\\t\\tuint256 staking;\\n\\t\\tuint256 projectsReserve;\\n\\t\\tuint256 lpAndListing;\\n\\t}\\n\\n\\tfunction fromTotalValue(\\n\\t\\tuint256 totalValue\\n\\t) internal pure returns (Value memory) {\\n\\t\\tuint256 othersTotal = totalValue\\n\\t\\t\\t.mul(UNITY - PROTOCOL_DEVELOPMENT_RATIO)\\n\\t\\t\\t.div(UNITY);\\n\\n\\t\\tuint256 team = othersTotal.mul(TEAM_AND_ADVISORS_RATIO).div(UNITY);\\n\\t\\tuint256 growth = othersTotal.mul(GROWTH_RATIO).div(UNITY);\\n\\t\\tuint256 staking = othersTotal.mul(STAKING_RATIO).div(UNITY);\\n\\t\\tuint256 projectsReserve = othersTotal.mul(PROJECTS_RESERVE_RATIO).div(\\n\\t\\t\\tUNITY\\n\\t\\t);\\n\\t\\tuint256 lpAndListing = othersTotal.mul(LP_AND_LISTINGS_RATIO).div(\\n\\t\\t\\tUNITY\\n\\t\\t);\\n\\n\\t\\tuint256 protocol = totalValue\\n\\t\\t\\t.sub(team)\\n\\t\\t\\t.sub(growth)\\n\\t\\t\\t.sub(staking)\\n\\t\\t\\t.sub(projectsReserve)\\n\\t\\t\\t.sub(lpAndListing);\\n\\n\\t\\treturn\\n\\t\\t\\tValue({\\n\\t\\t\\t\\tteam: team,\\n\\t\\t\\t\\tprotocol: protocol,\\n\\t\\t\\t\\tgrowth: growth,\\n\\t\\t\\t\\tstaking: staking,\\n\\t\\t\\t\\tprojectsReserve: projectsReserve,\\n\\t\\t\\t\\tlpAndListing: lpAndListing\\n\\t\\t\\t});\\n\\t}\\n\\n\\tfunction total(Value memory value) internal pure returns (uint256) {\\n\\t\\treturn\\n\\t\\t\\tvalue\\n\\t\\t\\t\\t.team\\n\\t\\t\\t\\t.add(value.protocol)\\n\\t\\t\\t\\t.add(value.growth)\\n\\t\\t\\t\\t.add(value.staking)\\n\\t\\t\\t\\t.add(value.projectsReserve)\\n\\t\\t\\t\\t.add(value.lpAndListing);\\n\\t}\\n\\n\\tfunction add(Value storage self, Value memory rhs) internal {\\n\\t\\tself.team = self.team.add(rhs.team);\\n\\t\\tself.protocol = self.protocol.add(rhs.protocol);\\n\\t\\tself.growth = self.growth.add(rhs.growth);\\n\\t\\tself.staking = self.staking.add(rhs.staking);\\n\\t\\tself.projectsReserve = self.projectsReserve.add(rhs.projectsReserve);\\n\\t\\tself.lpAndListing = self.lpAndListing.add(rhs.lpAndListing);\\n\\t}\\n}\\n\",\"keccak256\":\"0xeb86637b933f394907cff1d0a8cf706bd3f737a34d660d87feffbaee09de1c32\",\"license\":\"MIT\"},\"contracts/modules/sht-module/SHT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nlibrary SHT {\\n\\tuint256 public constant DECIMALS = 18;\\n\\tuint256 public constant ONE = 10 ** DECIMALS;\\n\\tuint256 public constant MAX_SUPPLY = 21_000_000 * ONE;\\n\\tuint256 public constant ECOSYSTEM_DISTRIBUTION_FUNDS =\\n\\t\\t(13_650_000 * ONE) + 2_248_573_618_499_339;\\n\\tuint256 public constant ICO_FUNDS =\\n\\t\\tMAX_SUPPLY - ECOSYSTEM_DISTRIBUTION_FUNDS;\\n}\\n\",\"keccak256\":\"0x66b511a7932bd0f6ceea118f9440cac3a6fd470d11e4d7fa337de8b178627dd7\",\"license\":\"MIT\"},\"contracts/project-funding/ProjectFunding.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\\\";\\n\\nimport \\\"../lib/ProjectStorage.sol\\\";\\nimport \\\"../lib/LkSHTAttributes.sol\\\";\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nimport \\\"../modules/LockedSmartHousingToken.sol\\\";\\nimport \\\"../modules/sht-module/SHT.sol\\\";\\n\\nimport { HousingSFT } from \\\"../housing-project/HousingSFT.sol\\\";\\nimport { TokenPayment } from \\\"../lib/TokenPayments.sol\\\";\\nimport { NewHousingProject, HousingProject } from \\\"../housing-project/NewHousingProjectLib.sol\\\";\\n\\n/**\\n * @title ProjectFunding\\n * @dev This contract is used for initializing and deploying housing projects.\\n * It allows the deployment of a new housing project and manages project data.\\n */\\ncontract ProjectFunding is Ownable {\\n\\tusing SafeMath for uint256;\\n\\tusing ProjectStorage for mapping(uint256 => ProjectStorage.Data);\\n\\tusing ProjectStorage for ProjectStorage.Data;\\n\\tusing LkSHTAttributes for LkSHTAttributes.Attributes;\\n\\n\\taddress public coinbase; // Address authorized to initialize the first project, also the housingToken\\n\\taddress public smartHousingAddress; // Address of the SmartHousing contract\\n\\n\\tmapping(uint256 => ProjectStorage.Data) public projects; // Mapping of project ID to ProjectData\\n\\tmapping(address => uint256) public projectsId; // Mapping of project address to project ID\\n\\tuint256 public projectCount; // Counter for the total number of projects\\n\\n\\tmapping(uint256 => mapping(address => uint256)) public usersProjectDeposit;\\n\\n\\tIERC20 public housingToken; // Token used for funding projects\\n\\tLkSHT public lkSht; // The locked version\\n\\n\\t/**\\n\\t * @dev Emitted when a new project is deployed.\\n\\t * @param projectAddress Address of the newly deployed HousingProject contract.\\n\\t */\\n\\tevent ProjectDeployed(address indexed projectAddress);\\n\\tevent ProjectFunded(\\n\\t\\tuint256 indexed projectId,\\n\\t\\taddress indexed depositor,\\n\\t\\tTokenPayment payment\\n\\t);\\n\\tevent ProjectTokensClaimed(\\n\\t\\taddress indexed depositor,\\n\\t\\tuint256 projectId,\\n\\t\\tuint256 amount\\n\\t);\\n\\n\\t/**\\n\\t * @param _coinbase Address authorized to initialize the first project.\\n\\t */\\n\\tconstructor(address _coinbase) {\\n\\t\\tcoinbase = _coinbase;\\n\\t\\tlkSht = NewLkSHT.create();\\n\\t}\\n\\n\\t/**\\n\\t * @dev Internal function to deploy a new HousingProject contract.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction _deployProject(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) internal {\\n\\t\\tHousingProject newProject = NewHousingProject.create(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tsmartHousingAddress\\n\\t\\t);\\n\\t\\tProjectStorage.Data memory projectData = projects.createNew(\\n\\t\\t\\tprojectsId,\\n\\t\\t\\tprojectCount,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\taddress(newProject),\\n\\t\\t\\taddress(newProject.projectSFT())\\n\\t\\t);\\n\\t\\tprojectCount = projectData.id;\\n\\n\\t\\temit ProjectDeployed(projectData.projectAddress);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Initializes the first project.\\n\\t * This function must be called by the coinbase address and can only be called once.\\n\\t * It sets up the token and deploys the first project.\\n\\t * @param shtPayment Payment details for the Smart Housing Token (SHT).\\n\\t * @param smartHousingAddress_ Address of the Smart Housing contract.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction initFirstProject(\\n\\t\\tERC20TokenPayment calldata shtPayment,\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddress_,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) external {\\n\\t\\trequire(msg.sender == coinbase, \\\"Caller is not the coinbase\\\");\\n\\t\\trequire(projectCount == 0, \\\"Project already initialized\\\");\\n\\n\\t\\tTokenPayments.receiveERC20(shtPayment);\\n\\t\\thousingToken = shtPayment.token;\\n\\n\\t\\tsmartHousingAddress = smartHousingAddress_;\\n\\n\\t\\t_deployProject(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Deploys a new project.\\n\\t * This function can be called multiple times to deploy additional projects.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction deployProject(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) public onlyOwner {\\n\\t\\t_deployProject(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\tfunction fundProject(\\n\\t\\tTokenPayment calldata depositPayment,\\n\\t\\tuint256 projectId,\\n\\t\\tuint256 referrerId\\n\\t) external payable {\\n\\t\\trequire(\\n\\t\\t\\tprojectId > 0 && projectId <= projectCount,\\n\\t\\t\\t\\\"Invalid project ID\\\"\\n\\t\\t);\\n\\n\\t\\taddress depositor = msg.sender;\\n\\n\\t\\t// Register user with referrer (if needed)\\n\\t\\tISmartHousing(smartHousingAddress).createRefIDViaProxy(\\n\\t\\t\\tdepositor,\\n\\t\\t\\treferrerId\\n\\t\\t);\\n\\n\\t\\t// Update project funding\\n\\t\\tprojects.fund(\\n\\t\\t\\tusersProjectDeposit[projectId],\\n\\t\\t\\tprojectId,\\n\\t\\t\\tdepositor,\\n\\t\\t\\tdepositPayment\\n\\t\\t);\\n\\n\\t\\temit ProjectFunded(projectId, depositor, depositPayment);\\n\\t}\\n\\n\\tfunction setProjectToken(uint256 projectId) external onlyOwner {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\n\\t\\t// TODO Add this after demo\\n\\t\\t// require(\\n\\t\\t// \\tproject.status() == ProjectStorage.Status.Successful,\\n\\t\\t// \\t\\\"Project Funding not yet successful\\\"\\n\\t\\t// );\\n\\n\\t\\tISmartHousing(smartHousingAddress).addProject(project.projectAddress);\\n\\n\\t\\tHousingProject(project.projectAddress).setTokenDetails(\\n\\t\\t\\tproject.collectedFunds,\\n\\t\\t\\tcoinbase\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Claims project tokens for a given project ID.\\n\\t * @param projectId The ID of the project to claim tokens from.\\n\\t */\\n\\tfunction claimProjectTokens(uint256 projectId) external {\\n\\t\\taddress depositor = msg.sender;\\n\\n\\t\\t// Retrieve the project and deposit amount\\n\\t\\t(ProjectStorage.Data memory project, uint256 depositAmount) = projects\\n\\t\\t\\t.takeDeposit(usersProjectDeposit[projectId], projectId, depositor);\\n\\n\\t\\tHousingSFT(project.tokenAddress).mintSFT(\\n\\t\\t\\tdepositAmount,\\n\\t\\t\\tdepositor,\\n\\t\\t\\tproject.collectedFunds\\n\\t\\t);\\n\\n\\t\\t// Mint LkSHT tokens if the project ID is 1\\n\\t\\tif (project.id == 1) {\\n\\t\\t\\tuint256 shtAmount = depositAmount.mul(SHT.ICO_FUNDS).div(\\n\\t\\t\\t\\tproject.collectedFunds\\n\\t\\t\\t);\\n\\n\\t\\t\\tlkSht.mint(shtAmount, depositor);\\n\\t\\t}\\n\\n\\t\\temit ProjectTokensClaimed(depositor, projectId, depositAmount);\\n\\t}\\n\\n\\tfunction unlockSHT(uint256 nonce) external {\\n\\t\\taddress caller = msg.sender;\\n\\n\\t\\tuint256 lkShtBal = lkSht.balanceOf(caller, nonce);\\n\\t\\trequire(lkShtBal > 0, \\\"ProjectFunding: Nothing to unlock\\\");\\n\\n\\t\\tLkSHTAttributes.Attributes memory attr = abi.decode(\\n\\t\\t\\tlkSht.getRawTokenAttributes(nonce),\\n\\t\\t\\t(LkSHTAttributes.Attributes)\\n\\t\\t);\\n\\t\\t(\\n\\t\\t\\tuint256 totalUnlockedAmount,\\n\\t\\t\\tLkSHTAttributes.Attributes memory newAttr\\n\\t\\t) = attr.unlockMatured();\\n\\n\\t\\tlkSht.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tlkShtBal.sub(totalUnlockedAmount),\\n\\t\\t\\tabi.encode(newAttr)\\n\\t\\t);\\n\\n\\t\\t// Transfer the total unlocked SHT tokens to the user's address\\n\\t\\tif (totalUnlockedAmount > 0) {\\n\\t\\t\\thousingToken.transfer(caller, totalUnlockedAmount);\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns an array of all project IDs and their associated data.\\n\\t * @return projectList An array of tuples containing project details.\\n\\t */\\n\\tfunction allProjects() public view returns (ProjectStorage.Data[] memory) {\\n\\t\\tProjectStorage.Data[] memory projectList = new ProjectStorage.Data[](\\n\\t\\t\\tprojectCount\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i = 1; i <= projectCount; i++) {\\n\\t\\t\\tprojectList[i - 1] = projects[i];\\n\\t\\t}\\n\\n\\t\\treturn projectList;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns the address of the HousingProject contract for a given project ID.\\n\\t * @param projectId The ID of the project.\\n\\t * @return projectAddress The address of the HousingProject contract.\\n\\t */\\n\\tfunction getProjectAddress(\\n\\t\\tuint256 projectId\\n\\t) external view returns (address projectAddress) {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\treturn project.projectAddress;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns the details of a project by its ID.\\n\\t * @param projectId The ID of the project.\\n\\t * @return id The project ID.\\n\\t * @return fundingGoal The funding goal of the project.\\n\\t * @return fundingDeadline The deadline for the project funding.\\n\\t * @return fundingToken The address of the ERC20 token used for funding.\\n\\t * @return projectAddress The address of the HousingProject contract.\\n\\t * @return status The funding status of the project.\\n\\t * @return collectedFunds The amount of funds collected.\\n\\t */\\n\\tfunction getProjectData(\\n\\t\\tuint256 projectId\\n\\t)\\n\\t\\texternal\\n\\t\\tview\\n\\t\\treturns (\\n\\t\\t\\tuint256 id,\\n\\t\\t\\tuint256 fundingGoal,\\n\\t\\t\\tuint256 fundingDeadline,\\n\\t\\t\\taddress fundingToken,\\n\\t\\t\\taddress projectAddress,\\n\\t\\t\\tuint8 status,\\n\\t\\t\\tuint256 collectedFunds\\n\\t\\t)\\n\\t{\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\treturn (\\n\\t\\t\\tproject.id,\\n\\t\\t\\tproject.fundingGoal,\\n\\t\\t\\tproject.fundingDeadline,\\n\\t\\t\\tproject.fundingToken,\\n\\t\\t\\tproject.projectAddress,\\n\\t\\t\\tuint8(project.status()),\\n\\t\\t\\tproject.collectedFunds\\n\\t\\t);\\n\\t}\\n}\\n\",\"keccak256\":\"0xba3518a6288e777e4b2b51d944cbc298200458d0f09f3c5b701f52547991a4e1\",\"license\":\"MIT\"},\"prb-math/contracts/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\\n\\n/// @notice Emitted when one of the inputs is type(int256).min.\\nerror PRBMath__MulDivSignedInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows int256.\\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is MIN_SD59x18.\\nerror PRBMathSD59x18__AbsInputTooSmall();\\n\\n/// @notice Emitted when ceiling a number overflows SD59x18.\\nerror PRBMathSD59x18__CeilOverflow(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__DivInputTooSmall();\\n\\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\\n\\n/// @notice Emitted when flooring a number underflows SD59x18.\\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\\n\\n/// @notice Emitted when the product of the inputs is negative.\\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\\n\\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\\n\\n/// @notice Emitted when the input is less than or equal to zero.\\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__MulInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is negative.\\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows SD59x18.\\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\\n\\n/// @notice Emitted when addition overflows UD60x18.\\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when ceiling a number overflows UD60x18.\\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\\n\\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when the input is less than 1.\\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows UD60x18.\\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\\n\\n/// @notice Emitted when subtraction underflows UD60x18.\\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\\n\\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\\nlibrary PRBMath {\\n /// STRUCTS ///\\n\\n struct SD59x18 {\\n int256 value;\\n }\\n\\n struct UD60x18 {\\n uint256 value;\\n }\\n\\n /// STORAGE ///\\n\\n /// @dev How many trailing decimals can be represented.\\n uint256 internal constant SCALE = 1e18;\\n\\n /// @dev Largest power of two divisor of SCALE.\\n uint256 internal constant SCALE_LPOTD = 262144;\\n\\n /// @dev SCALE inverted mod 2^256.\\n uint256 internal constant SCALE_INVERSE =\\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\\n\\n /// FUNCTIONS ///\\n\\n /// @notice Calculates the binary exponent of x using the binary fraction method.\\n /// @dev Has to use 192.64-bit fixed-point numbers.\\n /// See https://ethereum.stackexchange.com/a/96594/24693.\\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function exp2(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n // Start from 0.5 in the 192.64-bit fixed-point format.\\n result = 0x800000000000000000000000000000000000000000000000;\\n\\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\\n // because the initial result is 2^191 and all magic factors are less than 2^65.\\n if (x & 0x8000000000000000 > 0) {\\n result = (result * 0x16A09E667F3BCC909) >> 64;\\n }\\n if (x & 0x4000000000000000 > 0) {\\n result = (result * 0x1306FE0A31B7152DF) >> 64;\\n }\\n if (x & 0x2000000000000000 > 0) {\\n result = (result * 0x1172B83C7D517ADCE) >> 64;\\n }\\n if (x & 0x1000000000000000 > 0) {\\n result = (result * 0x10B5586CF9890F62A) >> 64;\\n }\\n if (x & 0x800000000000000 > 0) {\\n result = (result * 0x1059B0D31585743AE) >> 64;\\n }\\n if (x & 0x400000000000000 > 0) {\\n result = (result * 0x102C9A3E778060EE7) >> 64;\\n }\\n if (x & 0x200000000000000 > 0) {\\n result = (result * 0x10163DA9FB33356D8) >> 64;\\n }\\n if (x & 0x100000000000000 > 0) {\\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\\n }\\n if (x & 0x80000000000000 > 0) {\\n result = (result * 0x10058C86DA1C09EA2) >> 64;\\n }\\n if (x & 0x40000000000000 > 0) {\\n result = (result * 0x1002C605E2E8CEC50) >> 64;\\n }\\n if (x & 0x20000000000000 > 0) {\\n result = (result * 0x100162F3904051FA1) >> 64;\\n }\\n if (x & 0x10000000000000 > 0) {\\n result = (result * 0x1000B175EFFDC76BA) >> 64;\\n }\\n if (x & 0x8000000000000 > 0) {\\n result = (result * 0x100058BA01FB9F96D) >> 64;\\n }\\n if (x & 0x4000000000000 > 0) {\\n result = (result * 0x10002C5CC37DA9492) >> 64;\\n }\\n if (x & 0x2000000000000 > 0) {\\n result = (result * 0x1000162E525EE0547) >> 64;\\n }\\n if (x & 0x1000000000000 > 0) {\\n result = (result * 0x10000B17255775C04) >> 64;\\n }\\n if (x & 0x800000000000 > 0) {\\n result = (result * 0x1000058B91B5BC9AE) >> 64;\\n }\\n if (x & 0x400000000000 > 0) {\\n result = (result * 0x100002C5C89D5EC6D) >> 64;\\n }\\n if (x & 0x200000000000 > 0) {\\n result = (result * 0x10000162E43F4F831) >> 64;\\n }\\n if (x & 0x100000000000 > 0) {\\n result = (result * 0x100000B1721BCFC9A) >> 64;\\n }\\n if (x & 0x80000000000 > 0) {\\n result = (result * 0x10000058B90CF1E6E) >> 64;\\n }\\n if (x & 0x40000000000 > 0) {\\n result = (result * 0x1000002C5C863B73F) >> 64;\\n }\\n if (x & 0x20000000000 > 0) {\\n result = (result * 0x100000162E430E5A2) >> 64;\\n }\\n if (x & 0x10000000000 > 0) {\\n result = (result * 0x1000000B172183551) >> 64;\\n }\\n if (x & 0x8000000000 > 0) {\\n result = (result * 0x100000058B90C0B49) >> 64;\\n }\\n if (x & 0x4000000000 > 0) {\\n result = (result * 0x10000002C5C8601CC) >> 64;\\n }\\n if (x & 0x2000000000 > 0) {\\n result = (result * 0x1000000162E42FFF0) >> 64;\\n }\\n if (x & 0x1000000000 > 0) {\\n result = (result * 0x10000000B17217FBB) >> 64;\\n }\\n if (x & 0x800000000 > 0) {\\n result = (result * 0x1000000058B90BFCE) >> 64;\\n }\\n if (x & 0x400000000 > 0) {\\n result = (result * 0x100000002C5C85FE3) >> 64;\\n }\\n if (x & 0x200000000 > 0) {\\n result = (result * 0x10000000162E42FF1) >> 64;\\n }\\n if (x & 0x100000000 > 0) {\\n result = (result * 0x100000000B17217F8) >> 64;\\n }\\n if (x & 0x80000000 > 0) {\\n result = (result * 0x10000000058B90BFC) >> 64;\\n }\\n if (x & 0x40000000 > 0) {\\n result = (result * 0x1000000002C5C85FE) >> 64;\\n }\\n if (x & 0x20000000 > 0) {\\n result = (result * 0x100000000162E42FF) >> 64;\\n }\\n if (x & 0x10000000 > 0) {\\n result = (result * 0x1000000000B17217F) >> 64;\\n }\\n if (x & 0x8000000 > 0) {\\n result = (result * 0x100000000058B90C0) >> 64;\\n }\\n if (x & 0x4000000 > 0) {\\n result = (result * 0x10000000002C5C860) >> 64;\\n }\\n if (x & 0x2000000 > 0) {\\n result = (result * 0x1000000000162E430) >> 64;\\n }\\n if (x & 0x1000000 > 0) {\\n result = (result * 0x10000000000B17218) >> 64;\\n }\\n if (x & 0x800000 > 0) {\\n result = (result * 0x1000000000058B90C) >> 64;\\n }\\n if (x & 0x400000 > 0) {\\n result = (result * 0x100000000002C5C86) >> 64;\\n }\\n if (x & 0x200000 > 0) {\\n result = (result * 0x10000000000162E43) >> 64;\\n }\\n if (x & 0x100000 > 0) {\\n result = (result * 0x100000000000B1721) >> 64;\\n }\\n if (x & 0x80000 > 0) {\\n result = (result * 0x10000000000058B91) >> 64;\\n }\\n if (x & 0x40000 > 0) {\\n result = (result * 0x1000000000002C5C8) >> 64;\\n }\\n if (x & 0x20000 > 0) {\\n result = (result * 0x100000000000162E4) >> 64;\\n }\\n if (x & 0x10000 > 0) {\\n result = (result * 0x1000000000000B172) >> 64;\\n }\\n if (x & 0x8000 > 0) {\\n result = (result * 0x100000000000058B9) >> 64;\\n }\\n if (x & 0x4000 > 0) {\\n result = (result * 0x10000000000002C5D) >> 64;\\n }\\n if (x & 0x2000 > 0) {\\n result = (result * 0x1000000000000162E) >> 64;\\n }\\n if (x & 0x1000 > 0) {\\n result = (result * 0x10000000000000B17) >> 64;\\n }\\n if (x & 0x800 > 0) {\\n result = (result * 0x1000000000000058C) >> 64;\\n }\\n if (x & 0x400 > 0) {\\n result = (result * 0x100000000000002C6) >> 64;\\n }\\n if (x & 0x200 > 0) {\\n result = (result * 0x10000000000000163) >> 64;\\n }\\n if (x & 0x100 > 0) {\\n result = (result * 0x100000000000000B1) >> 64;\\n }\\n if (x & 0x80 > 0) {\\n result = (result * 0x10000000000000059) >> 64;\\n }\\n if (x & 0x40 > 0) {\\n result = (result * 0x1000000000000002C) >> 64;\\n }\\n if (x & 0x20 > 0) {\\n result = (result * 0x10000000000000016) >> 64;\\n }\\n if (x & 0x10 > 0) {\\n result = (result * 0x1000000000000000B) >> 64;\\n }\\n if (x & 0x8 > 0) {\\n result = (result * 0x10000000000000006) >> 64;\\n }\\n if (x & 0x4 > 0) {\\n result = (result * 0x10000000000000003) >> 64;\\n }\\n if (x & 0x2 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n if (x & 0x1 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n\\n // We're doing two things at the same time:\\n //\\n // 1. Multiply the result by 2^n + 1, where \\\"2^n\\\" is the integer part and the one is added to account for\\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\\n // rather than 192.\\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\\n //\\n // This works because 2^(191-ip) = 2^ip / 2^191, where \\\"ip\\\" is the integer part \\\"2^n\\\".\\n result *= SCALE;\\n result >>= (191 - (x >> 64));\\n }\\n }\\n\\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\\n /// @dev See the note on msb in the \\\"Find First Set\\\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\\n /// @param x The uint256 number for which to find the index of the most significant bit.\\n /// @return msb The index of the most significant bit as an uint256.\\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\\n if (x >= 2**128) {\\n x >>= 128;\\n msb += 128;\\n }\\n if (x >= 2**64) {\\n x >>= 64;\\n msb += 64;\\n }\\n if (x >= 2**32) {\\n x >>= 32;\\n msb += 32;\\n }\\n if (x >= 2**16) {\\n x >>= 16;\\n msb += 16;\\n }\\n if (x >= 2**8) {\\n x >>= 8;\\n msb += 8;\\n }\\n if (x >= 2**4) {\\n x >>= 4;\\n msb += 4;\\n }\\n if (x >= 2**2) {\\n x >>= 2;\\n msb += 2;\\n }\\n if (x >= 2**1) {\\n // No need to shift x any more.\\n msb += 1;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\\n ///\\n /// Requirements:\\n /// - The denominator cannot be zero.\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The multiplicand as an uint256.\\n /// @param y The multiplier as an uint256.\\n /// @param denominator The divisor as an uint256.\\n /// @return result The result as an uint256.\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n unchecked {\\n result = prod0 / denominator;\\n }\\n return result;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n if (prod1 >= denominator) {\\n revert PRBMath__MulDivOverflow(prod1, denominator);\\n }\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n unchecked {\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 lpotdod = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by lpotdod.\\n denominator := div(denominator, lpotdod)\\n\\n // Divide [prod1 prod0] by lpotdod.\\n prod0 := div(prod0, lpotdod)\\n\\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * lpotdod;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f71e18) with full precision.\\n ///\\n /// @dev Variant of \\\"mulDiv\\\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\\n /// being rounded to 1e-18. See \\\"Listing 6\\\" and text above it at https://accu.org/index.php/journals/1717.\\n ///\\n /// Requirements:\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - The body is purposely left uncommented; see the NatSpec comments in \\\"PRBMath.mulDiv\\\" to understand how this works.\\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\\n /// 1. x * y = type(uint256).max * SCALE\\n /// 2. (x * y) % SCALE >= SCALE / 2\\n ///\\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n uint256 prod0;\\n uint256 prod1;\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n if (prod1 >= SCALE) {\\n revert PRBMath__MulDivFixedPointOverflow(prod1);\\n }\\n\\n uint256 remainder;\\n uint256 roundUpUnit;\\n assembly {\\n remainder := mulmod(x, y, SCALE)\\n roundUpUnit := gt(remainder, 499999999999999999)\\n }\\n\\n if (prod1 == 0) {\\n unchecked {\\n result = (prod0 / SCALE) + roundUpUnit;\\n return result;\\n }\\n }\\n\\n assembly {\\n result := add(\\n mul(\\n or(\\n div(sub(prod0, remainder), SCALE_LPOTD),\\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\\n ),\\n SCALE_INVERSE\\n ),\\n roundUpUnit\\n )\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev An extension of \\\"mulDiv\\\" for signed numbers. Works by computing the signs and the absolute values separately.\\n ///\\n /// Requirements:\\n /// - None of the inputs can be type(int256).min.\\n /// - The result must fit within int256.\\n ///\\n /// @param x The multiplicand as an int256.\\n /// @param y The multiplier as an int256.\\n /// @param denominator The divisor as an int256.\\n /// @return result The result as an int256.\\n function mulDivSigned(\\n int256 x,\\n int256 y,\\n int256 denominator\\n ) internal pure returns (int256 result) {\\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\\n revert PRBMath__MulDivSignedInputTooSmall();\\n }\\n\\n // Get hold of the absolute values of x, y and the denominator.\\n uint256 ax;\\n uint256 ay;\\n uint256 ad;\\n unchecked {\\n ax = x < 0 ? uint256(-x) : uint256(x);\\n ay = y < 0 ? uint256(-y) : uint256(y);\\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\\n }\\n\\n // Compute the absolute value of (x*y)\\u00f7denominator. The result must fit within int256.\\n uint256 rAbs = mulDiv(ax, ay, ad);\\n if (rAbs > uint256(type(int256).max)) {\\n revert PRBMath__MulDivSignedOverflow(rAbs);\\n }\\n\\n // Get the signs of x, y and the denominator.\\n uint256 sx;\\n uint256 sy;\\n uint256 sd;\\n assembly {\\n sx := sgt(x, sub(0, 1))\\n sy := sgt(y, sub(0, 1))\\n sd := sgt(denominator, sub(0, 1))\\n }\\n\\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\\n // If yes, the result should be negative.\\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\\n }\\n\\n /// @notice Calculates the square root of x, rounding down.\\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The uint256 number for which to calculate the square root.\\n /// @return result The result as an uint256.\\n function sqrt(uint256 x) internal pure returns (uint256 result) {\\n if (x == 0) {\\n return 0;\\n }\\n\\n // Set the initial guess to the least power of two that is greater than or equal to sqrt(x).\\n uint256 xAux = uint256(x);\\n result = 1;\\n if (xAux >= 0x100000000000000000000000000000000) {\\n xAux >>= 128;\\n result <<= 64;\\n }\\n if (xAux >= 0x10000000000000000) {\\n xAux >>= 64;\\n result <<= 32;\\n }\\n if (xAux >= 0x100000000) {\\n xAux >>= 32;\\n result <<= 16;\\n }\\n if (xAux >= 0x10000) {\\n xAux >>= 16;\\n result <<= 8;\\n }\\n if (xAux >= 0x100) {\\n xAux >>= 8;\\n result <<= 4;\\n }\\n if (xAux >= 0x10) {\\n xAux >>= 4;\\n result <<= 2;\\n }\\n if (xAux >= 0x8) {\\n result <<= 1;\\n }\\n\\n // The operations can never overflow because the result is max 2^127 when it enters this block.\\n unchecked {\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1; // Seven iterations should be enough\\n uint256 roundedDownResult = x / result;\\n return result >= roundedDownResult ? roundedDownResult : result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xed164c95012964f5e125b5d2b2d00471a4bdee4def618cd1fcf341d196011b61\",\"license\":\"Unlicense\"},\"prb-math/contracts/PRBMathUD60x18.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\nimport \\\"./PRBMath.sol\\\";\\n\\n/// @title PRBMathUD60x18\\n/// @author Paul Razvan Berg\\n/// @notice Smart contract library for advanced fixed-point math that works with uint256 numbers considered to have 18\\n/// trailing decimals. We call this number representation unsigned 60.18-decimal fixed-point, since there can be up to 60\\n/// digits in the integer part and up to 18 decimals in the fractional part. The numbers are bound by the minimum and the\\n/// maximum values permitted by the Solidity type uint256.\\nlibrary PRBMathUD60x18 {\\n /// @dev Half the SCALE number.\\n uint256 internal constant HALF_SCALE = 5e17;\\n\\n /// @dev log2(e) as an unsigned 60.18-decimal fixed-point number.\\n uint256 internal constant LOG2_E = 1_442695040888963407;\\n\\n /// @dev The maximum value an unsigned 60.18-decimal fixed-point number can have.\\n uint256 internal constant MAX_UD60x18 =\\n 115792089237316195423570985008687907853269984665640564039457_584007913129639935;\\n\\n /// @dev The maximum whole value an unsigned 60.18-decimal fixed-point number can have.\\n uint256 internal constant MAX_WHOLE_UD60x18 =\\n 115792089237316195423570985008687907853269984665640564039457_000000000000000000;\\n\\n /// @dev How many trailing decimals can be represented.\\n uint256 internal constant SCALE = 1e18;\\n\\n /// @notice Calculates the arithmetic average of x and y, rounding down.\\n /// @param x The first operand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The second operand as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The arithmetic average as an unsigned 60.18-decimal fixed-point number.\\n function avg(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n // The operations can never overflow.\\n unchecked {\\n // The last operand checks if both x and y are odd and if that is the case, we add 1 to the result. We need\\n // to do this because if both numbers are odd, the 0.5 remainder gets truncated twice.\\n result = (x >> 1) + (y >> 1) + (x & y & 1);\\n }\\n }\\n\\n /// @notice Yields the least unsigned 60.18 decimal fixed-point number greater than or equal to x.\\n ///\\n /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.\\n /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.\\n ///\\n /// Requirements:\\n /// - x must be less than or equal to MAX_WHOLE_UD60x18.\\n ///\\n /// @param x The unsigned 60.18-decimal fixed-point number to ceil.\\n /// @param result The least integer greater than or equal to x, as an unsigned 60.18-decimal fixed-point number.\\n function ceil(uint256 x) internal pure returns (uint256 result) {\\n if (x > MAX_WHOLE_UD60x18) {\\n revert PRBMathUD60x18__CeilOverflow(x);\\n }\\n assembly {\\n // Equivalent to \\\"x % SCALE\\\" but faster.\\n let remainder := mod(x, SCALE)\\n\\n // Equivalent to \\\"SCALE - remainder\\\" but faster.\\n let delta := sub(SCALE, remainder)\\n\\n // Equivalent to \\\"x + delta * (remainder > 0 ? 1 : 0)\\\" but faster.\\n result := add(x, mul(delta, gt(remainder, 0)))\\n }\\n }\\n\\n /// @notice Divides two unsigned 60.18-decimal fixed-point numbers, returning a new unsigned 60.18-decimal fixed-point number.\\n ///\\n /// @dev Uses mulDiv to enable overflow-safe multiplication and division.\\n ///\\n /// Requirements:\\n /// - The denominator cannot be zero.\\n ///\\n /// @param x The numerator as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The denominator as an unsigned 60.18-decimal fixed-point number.\\n /// @param result The quotient as an unsigned 60.18-decimal fixed-point number.\\n function div(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n result = PRBMath.mulDiv(x, SCALE, y);\\n }\\n\\n /// @notice Returns Euler's number as an unsigned 60.18-decimal fixed-point number.\\n /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant).\\n function e() internal pure returns (uint256 result) {\\n result = 2_718281828459045235;\\n }\\n\\n /// @notice Calculates the natural exponent of x.\\n ///\\n /// @dev Based on the insight that e^x = 2^(x * log2(e)).\\n ///\\n /// Requirements:\\n /// - All from \\\"log2\\\".\\n /// - x must be less than 133.084258667509499441.\\n ///\\n /// @param x The exponent as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function exp(uint256 x) internal pure returns (uint256 result) {\\n // Without this check, the value passed to \\\"exp2\\\" would be greater than 192.\\n if (x >= 133_084258667509499441) {\\n revert PRBMathUD60x18__ExpInputTooBig(x);\\n }\\n\\n // Do the fixed-point multiplication inline to save gas.\\n unchecked {\\n uint256 doubleScaleProduct = x * LOG2_E;\\n result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE);\\n }\\n }\\n\\n /// @notice Calculates the binary exponent of x using the binary fraction method.\\n ///\\n /// @dev See https://ethereum.stackexchange.com/q/79903/24693.\\n ///\\n /// Requirements:\\n /// - x must be 192 or less.\\n /// - The result must fit within MAX_UD60x18.\\n ///\\n /// @param x The exponent as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function exp2(uint256 x) internal pure returns (uint256 result) {\\n // 2^192 doesn't fit within the 192.64-bit format used internally in this function.\\n if (x >= 192e18) {\\n revert PRBMathUD60x18__Exp2InputTooBig(x);\\n }\\n\\n unchecked {\\n // Convert x to the 192.64-bit fixed-point format.\\n uint256 x192x64 = (x << 64) / SCALE;\\n\\n // Pass x to the PRBMath.exp2 function, which uses the 192.64-bit fixed-point number representation.\\n result = PRBMath.exp2(x192x64);\\n }\\n }\\n\\n /// @notice Yields the greatest unsigned 60.18 decimal fixed-point number less than or equal to x.\\n /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.\\n /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.\\n /// @param x The unsigned 60.18-decimal fixed-point number to floor.\\n /// @param result The greatest integer less than or equal to x, as an unsigned 60.18-decimal fixed-point number.\\n function floor(uint256 x) internal pure returns (uint256 result) {\\n assembly {\\n // Equivalent to \\\"x % SCALE\\\" but faster.\\n let remainder := mod(x, SCALE)\\n\\n // Equivalent to \\\"x - remainder * (remainder > 0 ? 1 : 0)\\\" but faster.\\n result := sub(x, mul(remainder, gt(remainder, 0)))\\n }\\n }\\n\\n /// @notice Yields the excess beyond the floor of x.\\n /// @dev Based on the odd function definition https://en.wikipedia.org/wiki/Fractional_part.\\n /// @param x The unsigned 60.18-decimal fixed-point number to get the fractional part of.\\n /// @param result The fractional part of x as an unsigned 60.18-decimal fixed-point number.\\n function frac(uint256 x) internal pure returns (uint256 result) {\\n assembly {\\n result := mod(x, SCALE)\\n }\\n }\\n\\n /// @notice Converts a number from basic integer form to unsigned 60.18-decimal fixed-point representation.\\n ///\\n /// @dev Requirements:\\n /// - x must be less than or equal to MAX_UD60x18 divided by SCALE.\\n ///\\n /// @param x The basic integer to convert.\\n /// @param result The same number in unsigned 60.18-decimal fixed-point representation.\\n function fromUint(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n if (x > MAX_UD60x18 / SCALE) {\\n revert PRBMathUD60x18__FromUintOverflow(x);\\n }\\n result = x * SCALE;\\n }\\n }\\n\\n /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down.\\n ///\\n /// @dev Requirements:\\n /// - x * y must fit within MAX_UD60x18, lest it overflows.\\n ///\\n /// @param x The first operand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The second operand as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function gm(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n if (x == 0) {\\n return 0;\\n }\\n\\n unchecked {\\n // Checking for overflow this way is faster than letting Solidity do it.\\n uint256 xy = x * y;\\n if (xy / x != y) {\\n revert PRBMathUD60x18__GmOverflow(x, y);\\n }\\n\\n // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE\\n // during multiplication. See the comments within the \\\"sqrt\\\" function.\\n result = PRBMath.sqrt(xy);\\n }\\n }\\n\\n /// @notice Calculates 1 / x, rounding toward zero.\\n ///\\n /// @dev Requirements:\\n /// - x cannot be zero.\\n ///\\n /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the inverse.\\n /// @return result The inverse as an unsigned 60.18-decimal fixed-point number.\\n function inv(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n // 1e36 is SCALE * SCALE.\\n result = 1e36 / x;\\n }\\n }\\n\\n /// @notice Calculates the natural logarithm of x.\\n ///\\n /// @dev Based on the insight that ln(x) = log2(x) / log2(e).\\n ///\\n /// Requirements:\\n /// - All from \\\"log2\\\".\\n ///\\n /// Caveats:\\n /// - All from \\\"log2\\\".\\n /// - This doesn't return exactly 1 for 2.718281828459045235, for that we would need more fine-grained precision.\\n ///\\n /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the natural logarithm.\\n /// @return result The natural logarithm as an unsigned 60.18-decimal fixed-point number.\\n function ln(uint256 x) internal pure returns (uint256 result) {\\n // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x)\\n // can return is 196205294292027477728.\\n unchecked {\\n result = (log2(x) * SCALE) / LOG2_E;\\n }\\n }\\n\\n /// @notice Calculates the common logarithm of x.\\n ///\\n /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common\\n /// logarithm based on the insight that log10(x) = log2(x) / log2(10).\\n ///\\n /// Requirements:\\n /// - All from \\\"log2\\\".\\n ///\\n /// Caveats:\\n /// - All from \\\"log2\\\".\\n ///\\n /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the common logarithm.\\n /// @return result The common logarithm as an unsigned 60.18-decimal fixed-point number.\\n function log10(uint256 x) internal pure returns (uint256 result) {\\n if (x < SCALE) {\\n revert PRBMathUD60x18__LogInputTooSmall(x);\\n }\\n\\n // Note that the \\\"mul\\\" in this block is the assembly multiplication operation, not the \\\"mul\\\" function defined\\n // in this contract.\\n // prettier-ignore\\n assembly {\\n switch x\\n case 1 { result := mul(SCALE, sub(0, 18)) }\\n case 10 { result := mul(SCALE, sub(1, 18)) }\\n case 100 { result := mul(SCALE, sub(2, 18)) }\\n case 1000 { result := mul(SCALE, sub(3, 18)) }\\n case 10000 { result := mul(SCALE, sub(4, 18)) }\\n case 100000 { result := mul(SCALE, sub(5, 18)) }\\n case 1000000 { result := mul(SCALE, sub(6, 18)) }\\n case 10000000 { result := mul(SCALE, sub(7, 18)) }\\n case 100000000 { result := mul(SCALE, sub(8, 18)) }\\n case 1000000000 { result := mul(SCALE, sub(9, 18)) }\\n case 10000000000 { result := mul(SCALE, sub(10, 18)) }\\n case 100000000000 { result := mul(SCALE, sub(11, 18)) }\\n case 1000000000000 { result := mul(SCALE, sub(12, 18)) }\\n case 10000000000000 { result := mul(SCALE, sub(13, 18)) }\\n case 100000000000000 { result := mul(SCALE, sub(14, 18)) }\\n case 1000000000000000 { result := mul(SCALE, sub(15, 18)) }\\n case 10000000000000000 { result := mul(SCALE, sub(16, 18)) }\\n case 100000000000000000 { result := mul(SCALE, sub(17, 18)) }\\n case 1000000000000000000 { result := 0 }\\n case 10000000000000000000 { result := SCALE }\\n case 100000000000000000000 { result := mul(SCALE, 2) }\\n case 1000000000000000000000 { result := mul(SCALE, 3) }\\n case 10000000000000000000000 { result := mul(SCALE, 4) }\\n case 100000000000000000000000 { result := mul(SCALE, 5) }\\n case 1000000000000000000000000 { result := mul(SCALE, 6) }\\n case 10000000000000000000000000 { result := mul(SCALE, 7) }\\n case 100000000000000000000000000 { result := mul(SCALE, 8) }\\n case 1000000000000000000000000000 { result := mul(SCALE, 9) }\\n case 10000000000000000000000000000 { result := mul(SCALE, 10) }\\n case 100000000000000000000000000000 { result := mul(SCALE, 11) }\\n case 1000000000000000000000000000000 { result := mul(SCALE, 12) }\\n case 10000000000000000000000000000000 { result := mul(SCALE, 13) }\\n case 100000000000000000000000000000000 { result := mul(SCALE, 14) }\\n case 1000000000000000000000000000000000 { result := mul(SCALE, 15) }\\n case 10000000000000000000000000000000000 { result := mul(SCALE, 16) }\\n case 100000000000000000000000000000000000 { result := mul(SCALE, 17) }\\n case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) }\\n case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) }\\n case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) }\\n case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) }\\n case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) }\\n case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) }\\n case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) }\\n case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) }\\n case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) }\\n case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) }\\n case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) }\\n case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) }\\n case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) }\\n case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) }\\n case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) }\\n case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) }\\n case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) }\\n case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) }\\n case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) }\\n case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) }\\n case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) }\\n case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) }\\n case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) }\\n case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) }\\n case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) }\\n case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) }\\n case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) }\\n case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) }\\n case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) }\\n case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) }\\n case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) }\\n case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) }\\n case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) }\\n case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) }\\n case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) }\\n case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) }\\n case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) }\\n case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) }\\n case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) }\\n case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) }\\n case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) }\\n case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 59) }\\n default {\\n result := MAX_UD60x18\\n }\\n }\\n\\n if (result == MAX_UD60x18) {\\n // Do the fixed-point division inline to save gas. The denominator is log2(10).\\n unchecked {\\n result = (log2(x) * SCALE) / 3_321928094887362347;\\n }\\n }\\n }\\n\\n /// @notice Calculates the binary logarithm of x.\\n ///\\n /// @dev Based on the iterative approximation algorithm.\\n /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation\\n ///\\n /// Requirements:\\n /// - x must be greater than or equal to SCALE, otherwise the result would be negative.\\n ///\\n /// Caveats:\\n /// - The results are nor perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation.\\n ///\\n /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the binary logarithm.\\n /// @return result The binary logarithm as an unsigned 60.18-decimal fixed-point number.\\n function log2(uint256 x) internal pure returns (uint256 result) {\\n if (x < SCALE) {\\n revert PRBMathUD60x18__LogInputTooSmall(x);\\n }\\n unchecked {\\n // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).\\n uint256 n = PRBMath.mostSignificantBit(x / SCALE);\\n\\n // The integer part of the logarithm as an unsigned 60.18-decimal fixed-point number. The operation can't overflow\\n // because n is maximum 255 and SCALE is 1e18.\\n result = n * SCALE;\\n\\n // This is y = x * 2^(-n).\\n uint256 y = x >> n;\\n\\n // If y = 1, the fractional part is zero.\\n if (y == SCALE) {\\n return result;\\n }\\n\\n // Calculate the fractional part via the iterative approximation.\\n // The \\\"delta >>= 1\\\" part is equivalent to \\\"delta /= 2\\\", but shifting bits is faster.\\n for (uint256 delta = HALF_SCALE; delta > 0; delta >>= 1) {\\n y = (y * y) / SCALE;\\n\\n // Is y^2 > 2 and so in the range [2,4)?\\n if (y >= 2 * SCALE) {\\n // Add the 2^(-m) factor to the logarithm.\\n result += delta;\\n\\n // Corresponds to z/2 on Wikipedia.\\n y >>= 1;\\n }\\n }\\n }\\n }\\n\\n /// @notice Multiplies two unsigned 60.18-decimal fixed-point numbers together, returning a new unsigned 60.18-decimal\\n /// fixed-point number.\\n /// @dev See the documentation for the \\\"PRBMath.mulDivFixedPoint\\\" function.\\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The product as an unsigned 60.18-decimal fixed-point number.\\n function mul(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n result = PRBMath.mulDivFixedPoint(x, y);\\n }\\n\\n /// @notice Returns PI as an unsigned 60.18-decimal fixed-point number.\\n function pi() internal pure returns (uint256 result) {\\n result = 3_141592653589793238;\\n }\\n\\n /// @notice Raises x to the power of y.\\n ///\\n /// @dev Based on the insight that x^y = 2^(log2(x) * y).\\n ///\\n /// Requirements:\\n /// - All from \\\"exp2\\\", \\\"log2\\\" and \\\"mul\\\".\\n ///\\n /// Caveats:\\n /// - All from \\\"exp2\\\", \\\"log2\\\" and \\\"mul\\\".\\n /// - Assumes 0^0 is 1.\\n ///\\n /// @param x Number to raise to given power y, as an unsigned 60.18-decimal fixed-point number.\\n /// @param y Exponent to raise x to, as an unsigned 60.18-decimal fixed-point number.\\n /// @return result x raised to power y, as an unsigned 60.18-decimal fixed-point number.\\n function pow(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n if (x == 0) {\\n result = y == 0 ? SCALE : uint256(0);\\n } else {\\n result = exp2(mul(log2(x), y));\\n }\\n }\\n\\n /// @notice Raises x (unsigned 60.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the\\n /// famous algorithm \\\"exponentiation by squaring\\\".\\n ///\\n /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring\\n ///\\n /// Requirements:\\n /// - The result must fit within MAX_UD60x18.\\n ///\\n /// Caveats:\\n /// - All from \\\"mul\\\".\\n /// - Assumes 0^0 is 1.\\n ///\\n /// @param x The base as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The exponent as an uint256.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function powu(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n // Calculate the first iteration of the loop in advance.\\n result = y & 1 > 0 ? x : SCALE;\\n\\n // Equivalent to \\\"for(y /= 2; y > 0; y /= 2)\\\" but faster.\\n for (y >>= 1; y > 0; y >>= 1) {\\n x = PRBMath.mulDivFixedPoint(x, x);\\n\\n // Equivalent to \\\"y % 2 == 1\\\" but faster.\\n if (y & 1 > 0) {\\n result = PRBMath.mulDivFixedPoint(result, x);\\n }\\n }\\n }\\n\\n /// @notice Returns 1 as an unsigned 60.18-decimal fixed-point number.\\n function scale() internal pure returns (uint256 result) {\\n result = SCALE;\\n }\\n\\n /// @notice Calculates the square root of x, rounding down.\\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\\n ///\\n /// Requirements:\\n /// - x must be less than MAX_UD60x18 / SCALE.\\n ///\\n /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the square root.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point .\\n function sqrt(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n if (x > MAX_UD60x18 / SCALE) {\\n revert PRBMathUD60x18__SqrtOverflow(x);\\n }\\n // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two unsigned\\n // 60.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root).\\n result = PRBMath.sqrt(x * SCALE);\\n }\\n }\\n\\n /// @notice Converts a unsigned 60.18-decimal fixed-point number to basic integer form, rounding down in the process.\\n /// @param x The unsigned 60.18-decimal fixed-point number to convert.\\n /// @return result The same number in basic integer form.\\n function toUint(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n result = x / SCALE;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2180489de7680a79844dd5ef145f800e4f68e515e0e89409242f0187dbbd657b\",\"license\":\"Unlicense\"}},\"version\":1}", + "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"conibase\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"projectFunding\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"PRBMathUD60x18__Exp2InputTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"PRBMathUD60x18__LogInputTooSmall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"prod1\",\"type\":\"uint256\"}],\"name\":\"PRBMath__MulDivFixedPointOverflow\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"prod1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"name\":\"PRBMath__MulDivOverflow\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct TokenPayment[]\",\"name\":\"projectTokens\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"projectsShareCheckpoint\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtRewardPerShare\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stakeWeight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lkDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lkShtNonce\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"struct HstAttributes\",\"name\":\"attributes\",\"type\":\"tuple\"}],\"name\":\"MintHstToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"referralId\",\"type\":\"uint256\"}],\"name\":\"ReferralAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"userId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"name\":\"UserRegistered\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_EPOCHS_LOCK\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_EPOCHS_LOCK\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"projectAddress\",\"type\":\"address\"}],\"name\":\"addProject\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"addProjectRent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"hstTokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"name\":\"claimRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"coinbaseAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"name\":\"createRefID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"name\":\"createRefIDViaProxy\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"distributionStorage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"totalFunds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"genesisEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectsTotalReceivedRents\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lastFundsDispatchEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtTotalStakeWeight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtRewardPerShare\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtStakingRewards\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"toShare\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"checkpoint\",\"type\":\"uint256\"}],\"internalType\":\"struct ProjectStakingRewards.Value\",\"name\":\"projectsStakingRewards\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"team\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"protocol\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"growth\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"staking\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectsReserve\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lpAndListing\",\"type\":\"uint256\"}],\"internalType\":\"struct Entities.Value\",\"name\":\"entityFunds\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"epochsAndPeriodsStorage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"genesis\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"epochLength\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"getNonces\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"getRawTokenAttributes\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"}],\"name\":\"getReferrals\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"referralAddress\",\"type\":\"address\"}],\"internalType\":\"struct UserModule.ReferralInfo[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"}],\"name\":\"getReferrer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"referrerAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"}],\"name\":\"getUserId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"userId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"hasSFT\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hst\",\"outputs\":[{\"internalType\":\"contract HousingStakingToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct TokenPayment[]\",\"name\":\"projectTokens\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"projectsShareCheckpoint\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtRewardPerShare\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lkDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lkShtNonce\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct TokenPayment[]\",\"name\":\"projectTokens\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"projectsShareCheckpoint\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtRewardPerShare\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"shtAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stakeWeight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lkDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lkShtNonce\",\"type\":\"uint256\"}],\"internalType\":\"struct HstAttributes\",\"name\":\"attr\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"permissions\",\"outputs\":[{\"internalType\":\"enum SmartHousing.Permissions\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"project\",\"type\":\"address\"}],\"name\":\"projectDets\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"maxShares\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"receivedRents\",\"type\":\"uint256\"}],\"internalType\":\"struct Distribution.ProjectDistributionData\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"projectFundingAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"projectsToken\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ERC20TokenPayment\",\"name\":\"payment\",\"type\":\"tuple\"}],\"name\":\"setUpSHT\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"shtTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct TokenPayment[]\",\"name\":\"stakingTokens\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"epochsLock\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"name\":\"stake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenInfo\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"attr\",\"type\":\"bytes\"}],\"name\":\"update\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"userCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"userIdToAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"users\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"referrerId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract allows for fractional ownership and ease of investment. This innovative approach addresses the high costs and limited access to real estate investments in Abuja, Nigeria, making the market more inclusive and accessible. By selling tokens, SmartHousing provides developers with immediate access to liquid funds, ensuring the timely and quality completion of affordable development projects. The SmartHousing Contract is the main contract for the SmartHousing ecosystem. This contract owns and deploys HousingProject contracts, which will represent the properties owned and managed by the SmartHousing project. The management of ecosystem users will also be done in this contract.\",\"events\":{\"ApprovalForAll(address,address,bool)\":{\"details\":\"Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to `approved`.\"},\"TransferBatch(address,address,address,uint256[],uint256[])\":{\"details\":\"Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all transfers.\"},\"TransferSingle(address,address,address,uint256,uint256)\":{\"details\":\"Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\"},\"URI(string,uint256)\":{\"details\":\"Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. If an {URI} event was emitted for `id`, the standard https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value returned by {IERC1155MetadataURI-uri}.\"}},\"kind\":\"dev\",\"methods\":{\"addProject(address)\":{\"params\":{\"projectAddress\":\"The address of the new project.\"}},\"addProjectRent(uint256)\":{\"details\":\"projectAddress is the msg.msg.sender which must be a recognised HousingProject contract\",\"params\":{\"amount\":\"The amount of rent received.\"}},\"balanceOf(address,uint256)\":{\"details\":\"See {IERC1155-balanceOf}. Requirements: - `account` cannot be the zero address.\"},\"balanceOfBatch(address[],uint256[])\":{\"details\":\"See {IERC1155-balanceOfBatch}. Requirements: - `accounts` and `ids` must have the same length.\"},\"createRefID(uint256)\":{\"params\":{\"referrerId\":\"The ID of the referrer.\"},\"returns\":{\"_0\":\"The ID of the registered user.\"}},\"createRefIDViaProxy(address,uint256)\":{\"params\":{\"referrerId\":\"The ID of the referrer.\",\"userAddr\":\"The address of the user.\"},\"returns\":{\"_0\":\"The ID of the registered user.\"}},\"getReferrer(address)\":{\"params\":{\"userAddress\":\"The address of the user.\"},\"returns\":{\"referrerAddress\":\"The address of the referrer, address(0) if none.\",\"referrerId\":\"The ID of the referrer, 0 if none.\"}},\"isApprovedForAll(address,address)\":{\"details\":\"See {IERC1155-isApprovedForAll}.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"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.\"},\"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\":{\"details\":\"See {IERC1155-safeBatchTransferFrom}.\"},\"safeTransferFrom(address,address,uint256,uint256,bytes)\":{\"details\":\"See {IERC1155-safeTransferFrom}.\"},\"setApprovalForAll(address,bool)\":{\"details\":\"See {IERC1155-setApprovalForAll}.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"uri(uint256)\":{\"details\":\"See {IERC1155MetadataURI-uri}. This implementation returns the same URI for *all* token types. It relies on the token type ID substitution mechanism https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. Clients calling this function must replace the `\\\\{id\\\\}` substring with the actual token type ID.\"}},\"title\":\"SmartHousing\",\"version\":1},\"userdoc\":{\"errors\":{\"PRBMathUD60x18__Exp2InputTooBig(uint256)\":[{\"notice\":\"Emitted when the input is greater than 192.\"}],\"PRBMathUD60x18__LogInputTooSmall(uint256)\":[{\"notice\":\"Emitted when the input is less than 1.\"}],\"PRBMath__MulDivFixedPointOverflow(uint256)\":[{\"notice\":\"Emitted when the result overflows uint256.\"}],\"PRBMath__MulDivOverflow(uint256,uint256)\":[{\"notice\":\"Emitted when the result overflows uint256.\"}]},\"kind\":\"user\",\"methods\":{\"addProject(address)\":{\"notice\":\"Adds a new project and sets its permissions.\"},\"addProjectRent(uint256)\":{\"notice\":\"Adds rent to a project and updates the distribution storage.\"},\"createRefID(uint256)\":{\"notice\":\"Register a new user or get the referral ID if already registered.\"},\"createRefIDViaProxy(address,uint256)\":{\"notice\":\"Register a new user via proxy or get the referral ID if already registered.\"},\"getReferrer(address)\":{\"notice\":\"Gets the referrer and referrer ID of a user.\"},\"update(address,uint256,uint256,bytes)\":{\"notice\":\"Burns all the NFT balance of user at nonce, creates new with balance and attributes\"}},\"notice\":\"SmartHousing leverages blockchain technology to revolutionize real estate investment and development by enabling the tokenization of properties.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/main/SmartHousing.sol\":\"SmartHousing\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../token/ERC20/IERC20.sol\\\";\\n\",\"keccak256\":\"0x6ebf1944ab804b8660eb6fc52f9fe84588cee01c2566a69023e59497e7d27f45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC1155.sol\\\";\\nimport \\\"./IERC1155Receiver.sol\\\";\\nimport \\\"./extensions/IERC1155MetadataURI.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\nimport \\\"../../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the basic standard multi-token.\\n * See https://eips.ethereum.org/EIPS/eip-1155\\n * Originally based on code by Enjin: https://github.com/enjin/erc-1155\\n *\\n * _Available since v3.1._\\n */\\ncontract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {\\n using Address for address;\\n\\n // Mapping from token ID to account balances\\n mapping(uint256 => mapping(address => uint256)) private _balances;\\n\\n // Mapping from account to operator approvals\\n mapping(address => mapping(address => bool)) private _operatorApprovals;\\n\\n // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json\\n string private _uri;\\n\\n /**\\n * @dev See {_setURI}.\\n */\\n constructor(string memory uri_) {\\n _setURI(uri_);\\n }\\n\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n interfaceId == type(IERC1155).interfaceId ||\\n interfaceId == type(IERC1155MetadataURI).interfaceId ||\\n super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev See {IERC1155MetadataURI-uri}.\\n *\\n * This implementation returns the same URI for *all* token types. It relies\\n * on the token type ID substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * Clients calling this function must replace the `\\\\{id\\\\}` substring with the\\n * actual token type ID.\\n */\\n function uri(uint256) public view virtual override returns (string memory) {\\n return _uri;\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {\\n require(account != address(0), \\\"ERC1155: address zero is not a valid owner\\\");\\n return _balances[id][account];\\n }\\n\\n /**\\n * @dev See {IERC1155-balanceOfBatch}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n public\\n view\\n virtual\\n override\\n returns (uint256[] memory)\\n {\\n require(accounts.length == ids.length, \\\"ERC1155: accounts and ids length mismatch\\\");\\n\\n uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n for (uint256 i = 0; i < accounts.length; ++i) {\\n batchBalances[i] = balanceOf(accounts[i], ids[i]);\\n }\\n\\n return batchBalances;\\n }\\n\\n /**\\n * @dev See {IERC1155-setApprovalForAll}.\\n */\\n function setApprovalForAll(address operator, bool approved) public virtual override {\\n _setApprovalForAll(_msgSender(), operator, approved);\\n }\\n\\n /**\\n * @dev See {IERC1155-isApprovedForAll}.\\n */\\n function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {\\n return _operatorApprovals[account][operator];\\n }\\n\\n /**\\n * @dev See {IERC1155-safeTransferFrom}.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeTransferFrom(from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev See {IERC1155-safeBatchTransferFrom}.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) public virtual override {\\n require(\\n from == _msgSender() || isApprovedForAll(from, _msgSender()),\\n \\\"ERC1155: caller is not token owner or approved\\\"\\n );\\n _safeBatchTransferFrom(from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n\\n emit TransferSingle(operator, from, to, id, amount);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n require(to != address(0), \\\"ERC1155: transfer to the zero address\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; ++i) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: insufficient balance for transfer\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n _balances[id][to] += amount;\\n }\\n\\n emit TransferBatch(operator, from, to, ids, amounts);\\n\\n _afterTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Sets a new URI for all token types, by relying on the token type ID\\n * substitution mechanism\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].\\n *\\n * By this mechanism, any occurrence of the `\\\\{id\\\\}` substring in either the\\n * URI or any of the amounts in the JSON file at said URI will be replaced by\\n * clients with the token type ID.\\n *\\n * For example, the `https://token-cdn-domain/\\\\{id\\\\}.json` URI would be\\n * interpreted by clients as\\n * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`\\n * for token type ID 0x4cce0.\\n *\\n * See {uri}.\\n *\\n * Because these URIs cannot be meaningfully represented by the {URI} event,\\n * this function emits no events.\\n */\\n function _setURI(string memory newuri) internal virtual {\\n _uri = newuri;\\n }\\n\\n /**\\n * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function _mint(\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _balances[id][to] += amount;\\n emit TransferSingle(operator, address(0), to, id, amount);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function _mintBatch(\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {\\n require(to != address(0), \\\"ERC1155: mint to the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n _balances[ids[i]][to] += amounts[i];\\n }\\n\\n emit TransferBatch(operator, address(0), to, ids, amounts);\\n\\n _afterTokenTransfer(operator, address(0), to, ids, amounts, data);\\n\\n _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens of token type `id` from `from`\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `from` must have at least `amount` tokens of token type `id`.\\n */\\n function _burn(\\n address from,\\n uint256 id,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n\\n address operator = _msgSender();\\n uint256[] memory ids = _asSingletonArray(id);\\n uint256[] memory amounts = _asSingletonArray(amount);\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n\\n emit TransferSingle(operator, from, address(0), id, amount);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n */\\n function _burnBatch(\\n address from,\\n uint256[] memory ids,\\n uint256[] memory amounts\\n ) internal virtual {\\n require(from != address(0), \\\"ERC1155: burn from the zero address\\\");\\n require(ids.length == amounts.length, \\\"ERC1155: ids and amounts length mismatch\\\");\\n\\n address operator = _msgSender();\\n\\n _beforeTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint256 id = ids[i];\\n uint256 amount = amounts[i];\\n\\n uint256 fromBalance = _balances[id][from];\\n require(fromBalance >= amount, \\\"ERC1155: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[id][from] = fromBalance - amount;\\n }\\n }\\n\\n emit TransferBatch(operator, from, address(0), ids, amounts);\\n\\n _afterTokenTransfer(operator, from, address(0), ids, amounts, \\\"\\\");\\n }\\n\\n /**\\n * @dev Approve `operator` to operate on all of `owner` tokens\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function _setApprovalForAll(\\n address owner,\\n address operator,\\n bool approved\\n ) internal virtual {\\n require(owner != operator, \\\"ERC1155: setting approval status for self\\\");\\n _operatorApprovals[owner][operator] = approved;\\n emit ApprovalForAll(owner, operator, approved);\\n }\\n\\n /**\\n * @dev Hook that is called before any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `ids` and `amounts` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any token transfer. This includes minting\\n * and burning, as well as batched variants.\\n *\\n * The same hook is called on both single and batched variants. For single\\n * transfers, the length of the `id` and `amount` arrays will be 1.\\n *\\n * Calling conditions (for each `id` and `amount` pair):\\n *\\n * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * of token type `id` will be transferred to `to`.\\n * - When `from` is zero, `amount` tokens of token type `id` will be minted\\n * for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`\\n * will be burned.\\n * - `from` and `to` are never both zero.\\n * - `ids` and `amounts` have the same, non-zero length.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) internal virtual {}\\n\\n function _doSafeTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {\\n if (response != IERC1155Receiver.onERC1155Received.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _doSafeBatchTransferAcceptanceCheck(\\n address operator,\\n address from,\\n address to,\\n uint256[] memory ids,\\n uint256[] memory amounts,\\n bytes memory data\\n ) private {\\n if (to.isContract()) {\\n try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (\\n bytes4 response\\n ) {\\n if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {\\n revert(\\\"ERC1155: ERC1155Receiver rejected tokens\\\");\\n }\\n } catch Error(string memory reason) {\\n revert(reason);\\n } catch {\\n revert(\\\"ERC1155: transfer to non-ERC1155Receiver implementer\\\");\\n }\\n }\\n }\\n\\n function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {\\n uint256[] memory array = new uint256[](1);\\n array[0] = element;\\n\\n return array;\\n }\\n}\\n\",\"keccak256\":\"0xd917747dc87f189c6779b894f367a028f9dca4be930283cccec8f312966af820\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155 is IERC165 {\\n /**\\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\\n */\\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\\n\\n /**\\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\\n * transfers.\\n */\\n event TransferBatch(\\n address indexed operator,\\n address indexed from,\\n address indexed to,\\n uint256[] ids,\\n uint256[] values\\n );\\n\\n /**\\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\\n * `approved`.\\n */\\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\\n\\n /**\\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\\n *\\n * If an {URI} event was emitted for `id`, the standard\\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\\n * returned by {IERC1155MetadataURI-uri}.\\n */\\n event URI(string value, uint256 indexed id);\\n\\n /**\\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function balanceOf(address account, uint256 id) external view returns (uint256);\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\\n *\\n * Requirements:\\n *\\n * - `accounts` and `ids` must have the same length.\\n */\\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n external\\n view\\n returns (uint256[] memory);\\n\\n /**\\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\\n *\\n * Emits an {ApprovalForAll} event.\\n *\\n * Requirements:\\n *\\n * - `operator` cannot be the caller.\\n */\\n function setApprovalForAll(address operator, bool approved) external;\\n\\n /**\\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\\n *\\n * See {setApprovalForAll}.\\n */\\n function isApprovedForAll(address account, address operator) external view returns (bool);\\n\\n /**\\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\\n *\\n * Emits a {TransferSingle} event.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\\n * acceptance magic value.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n uint256 amount,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\\n *\\n * Emits a {TransferBatch} event.\\n *\\n * Requirements:\\n *\\n * - `ids` and `amounts` must have the same length.\\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\\n * acceptance magic value.\\n */\\n function safeBatchTransferFrom(\\n address from,\\n address to,\\n uint256[] calldata ids,\\n uint256[] calldata amounts,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x6392f2cfe3a5ee802227fe7a2dfd47096d881aec89bddd214b35c5b46d3cd941\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev _Available since v3.1._\\n */\\ninterface IERC1155Receiver is IERC165 {\\n /**\\n * @dev Handles the receipt of a single ERC1155 token type. This function is\\n * called at the end of a `safeTransferFrom` after the balance has been updated.\\n *\\n * NOTE: To accept the transfer, this must return\\n * `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n * (i.e. 0xf23a6e61, or its own function selector).\\n *\\n * @param operator The address which initiated the transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param id The ID of the token being transferred\\n * @param value The amount of tokens being transferred\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155Received(\\n address operator,\\n address from,\\n uint256 id,\\n uint256 value,\\n bytes calldata data\\n ) external returns (bytes4);\\n\\n /**\\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\\n * is called at the end of a `safeBatchTransferFrom` after the balances have\\n * been updated.\\n *\\n * NOTE: To accept the transfer(s), this must return\\n * `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n * (i.e. 0xbc197c81, or its own function selector).\\n *\\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\\n * @param from The address which previously owned the token\\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\\n * @param data Additional data with no specified format\\n * @return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` if transfer is allowed\\n */\\n function onERC1155BatchReceived(\\n address operator,\\n address from,\\n uint256[] calldata ids,\\n uint256[] calldata values,\\n bytes calldata data\\n ) external returns (bytes4);\\n}\\n\",\"keccak256\":\"0xeb373f1fdc7b755c6a750123a9b9e3a8a02c1470042fd6505d875000a80bde0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC1155.sol\\\";\\n\\n/**\\n * @dev Interface of the optional ERC1155MetadataExtension interface, as defined\\n * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].\\n *\\n * _Available since v3.1._\\n */\\ninterface IERC1155MetadataURI is IERC1155 {\\n /**\\n * @dev Returns the URI for token type `id`.\\n *\\n * If the `\\\\{id\\\\}` substring is present in the URI, it must be replaced by\\n * clients with the actual token type ID.\\n */\\n function uri(uint256 id) external view returns (string memory);\\n}\\n\",\"keccak256\":\"0xa66d18b9a85458d28fc3304717964502ae36f7f8a2ff35bc83f6f85d74b03574\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n // decrementing then incrementing.\\n _balances[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n unchecked {\\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n _balances[account] += amount;\\n }\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n // Overflow not possible: amount <= accountBalance <= totalSupply.\\n _totalSupply -= amount;\\n }\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x4ffc0547c02ad22925310c585c0f166f8759e2648a09e9b489100c42f15dd98d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../ERC20.sol\\\";\\nimport \\\"../../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\\n * tokens and those that they have an allowance for, in a way that can be\\n * recognized off-chain (via event analysis).\\n */\\nabstract contract ERC20Burnable is Context, ERC20 {\\n /**\\n * @dev Destroys `amount` tokens from the caller.\\n *\\n * See {ERC20-_burn}.\\n */\\n function burn(uint256 amount) public virtual {\\n _burn(_msgSender(), amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, deducting from the caller's\\n * allowance.\\n *\\n * See {ERC20-_burn} and {ERC20-allowance}.\\n *\\n * Requirements:\\n *\\n * - the caller must have allowance for ``accounts``'s tokens of at least\\n * `amount`.\\n */\\n function burnFrom(address account, uint256 amount) public virtual {\\n _spendAllowance(account, _msgSender(), amount);\\n _burn(account, amount);\\n }\\n}\\n\",\"keccak256\":\"0x0d19410453cda55960a818e02bd7c18952a5c8fe7a3036e81f0d599f34487a7b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf96f969e24029d43d0df89e59d365f277021dac62b48e1c1e3ebe0acdd7f1ca1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Counters.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Counters\\n * @author Matt Condon (@shrugs)\\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\\n *\\n * Include with `using Counters for Counters.Counter;`\\n */\\nlibrary Counters {\\n struct Counter {\\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\\n // this feature: see https://github.com/ethereum/solidity/issues/4637\\n uint256 _value; // default: 0\\n }\\n\\n function current(Counter storage counter) internal view returns (uint256) {\\n return counter._value;\\n }\\n\\n function increment(Counter storage counter) internal {\\n unchecked {\\n counter._value += 1;\\n }\\n }\\n\\n function decrement(Counter storage counter) internal {\\n uint256 value = counter._value;\\n require(value > 0, \\\"Counter: decrement overflow\\\");\\n unchecked {\\n counter._value = value - 1;\\n }\\n }\\n\\n function reset(Counter storage counter) internal {\\n counter._value = 0;\\n }\\n}\\n\",\"keccak256\":\"0xf0018c2440fbe238dd3a8732fa8e17a0f9dce84d31451dc8a32f6d62b349c9f1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0f633a0223d9a1dcccfcf38a64c9de0874dfcbfac0c6941ccf074d63a2ce0e1e\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * ```\\n * contract Example {\\n * // Add the library methods\\n * using EnumerableSet for EnumerableSet.AddressSet;\\n *\\n * // Declare a set state variable\\n * EnumerableSet.AddressSet private mySet;\\n * }\\n * ```\\n *\\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\\n * and `uint256` (`UintSet`) are supported.\\n *\\n * [WARNING]\\n * ====\\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\\n * unusable.\\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\\n *\\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\\n * array of EnumerableSet.\\n * ====\\n */\\nlibrary EnumerableSet {\\n // To implement this library for multiple types with as little code\\n // repetition as possible, we write it in terms of a generic Set type with\\n // bytes32 values.\\n // The Set implementation uses private functions, and user-facing\\n // implementations (such as AddressSet) are just wrappers around the\\n // underlying Set.\\n // This means that we can only create new EnumerableSets for types that fit\\n // in bytes32.\\n\\n struct Set {\\n // Storage of set values\\n bytes32[] _values;\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(bytes32 => uint256) _indexes;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function _add(Set storage set, bytes32 value) private returns (bool) {\\n if (!_contains(set, value)) {\\n set._values.push(value);\\n // The value is stored at length-1, but we add 1 to all indexes\\n // and use 0 as a sentinel value\\n set._indexes[value] = set._values.length;\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function _remove(Set storage set, bytes32 value) private returns (bool) {\\n // We read and store the value's index to prevent multiple reads from the same storage slot\\n uint256 valueIndex = set._indexes[value];\\n\\n if (valueIndex != 0) {\\n // Equivalent to contains(set, value)\\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\\n // the array, and then remove the last element (sometimes called as 'swap and pop').\\n // This modifies the order of the array, as noted in {at}.\\n\\n uint256 toDeleteIndex = valueIndex - 1;\\n uint256 lastIndex = set._values.length - 1;\\n\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set._values[lastIndex];\\n\\n // Move the last value to the index where the value to delete is\\n set._values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\\n }\\n\\n // Delete the slot where the moved value was stored\\n set._values.pop();\\n\\n // Delete the index for the deleted slot\\n delete set._indexes[value];\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\\n return set._indexes[value] != 0;\\n }\\n\\n /**\\n * @dev Returns the number of values on the set. O(1).\\n */\\n function _length(Set storage set) private view returns (uint256) {\\n return set._values.length;\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\\n return set._values[index];\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function _values(Set storage set) private view returns (bytes32[] memory) {\\n return set._values;\\n }\\n\\n // Bytes32Set\\n\\n struct Bytes32Set {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _add(set._inner, value);\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _remove(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return _contains(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return _at(set._inner, index);\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n bytes32[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // AddressSet\\n\\n struct AddressSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n return _add(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n return _remove(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\\n return address(uint160(uint256(_at(set._inner, index))));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(AddressSet storage set) internal view returns (address[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n address[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // UintSet\\n\\n struct UintSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(UintSet storage set, uint256 value) internal returns (bool) {\\n return _add(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\\n return _remove(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(UintSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\\n return uint256(_at(set._inner, index));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(UintSet storage set) internal view returns (uint256[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n uint256[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xc3ff3f5c4584e1d9a483ad7ced51ab64523201f4e3d3c65293e4ca8aeb77a961\",\"license\":\"MIT\"},\"contracts/housing-project/CallsSmartHousing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nabstract contract CallsSmartHousing {\\n\\t/// @notice The address of the main SmartHousing contract.\\n\\taddress immutable smartHousingAddr;\\n\\n\\tconstructor(address smartHousingAddr_) {\\n\\t\\tsmartHousingAddr = smartHousingAddr_;\\n\\t}\\n\\n\\t/// @dev Gets the referrer address for a given original owner.\\n\\t/// @param userAddr The original owner of the token.\\n\\t/// @return The referrer address.\\n\\tfunction getReferrer(\\n\\t\\taddress userAddr\\n\\t) internal view returns (uint, address) {\\n\\t\\treturn IUserModule(smartHousingAddr).getReferrer(userAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0xd2ded3c751d669f079d12e7381e586b747cb9ae1b6d9bd4dbd87fc9db3b0371c\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingProject.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"./RentsModule.sol\\\";\\n\\n/// @title HousingProject Contract\\n/// @notice Represents a unique real estate project within the SmartHousing ecosystem.\\n/// @dev This contract inherits from RentsModule and HousingSFT.\\ncontract HousingProject is RentsModule, Ownable {\\n\\t/// @notice Initializes the HousingProject contract.\\n\\t/// @param smartHousingAddr The address of the main SmartHousing contract.\\n\\tconstructor(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) CallsSmartHousing(smartHousingAddr) {\\n\\t\\tprojectSFT = new HousingSFT(name, symbol);\\n\\t}\\n\\n\\tevent TokenIssued(address tokenAddress, string name, uint256 amountRaised);\\n\\n\\tfunction setTokenDetails(\\n\\t\\tuint256 amountRaised,\\n\\t\\taddress housingTokenAddr\\n\\t) external onlyOwner {\\n\\t\\trequire(amountRaised == 0, \\\"Token details set already\\\");\\n\\n\\t\\thousingToken = ERC20Burnable(housingTokenAddr);\\n\\n\\t\\tprojectSFT.setAmountRaised(amountRaised);\\n\\t\\tstring memory name = projectSFT.name();\\n\\n\\t\\temit TokenIssued(address(projectSFT), name, amountRaised);\\n\\t}\\n\\n\\tfunction getMaxSupply() public view returns (uint256) {\\n\\t\\treturn projectSFT.getMaxSupply();\\n\\t}\\n}\\n\",\"keccak256\":\"0x159e6b338c47a2dacbec1254f582826b5584c338919e6e6908aba986f9a98350\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/HousingSFT.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\n\\nimport \\\"../modules/SFT.sol\\\";\\n\\nstruct HousingAttributes {\\n\\tuint256 rewardsPerShare;\\n\\taddress originalOwner;\\n\\tuint256 tokenWeight;\\n}\\n\\n/// @title Housing SFT\\n/// @notice This contract represents a semi-fungible token (SFT) for housing projects.\\n/// @dev This contract will be inherited by the HousingProject contract.\\ncontract HousingSFT is SFT {\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct HousingSFTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tHousingAttributes attributes;\\n\\t}\\n\\n\\t// FIXME this value should be unique to each contract, should depend on\\n\\t// the total amount expected to raise as it determines the amount of SFTs to\\n\\t// be minted for investors\\n\\tuint256 public constant MAX_SUPPLY = 1_000_000;\\n\\n\\t/// @notice The amount of fungible tokens collected from investors to finance the development of this housing project.\\n\\tuint256 public amountRaised;\\n\\n\\t/// @notice The current amount out of the `MAX_SUPPLY` of tokens minted.\\n\\tuint256 public totalSupply;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tfunction setAmountRaised(uint256 amountRaised_) external onlyOwner {\\n\\t\\tamountRaised = amountRaised_;\\n\\t}\\n\\n\\tmodifier canMint() {\\n\\t\\taddress sftOwner = owner();\\n\\n\\t\\trequire(\\n\\t\\t\\tOwnable(sftOwner).owner() == _msgSender(),\\n\\t\\t\\t\\\"not allowed to mint\\\"\\n\\t\\t);\\n\\n\\t\\t_;\\n\\t}\\n\\n\\t/// @notice Mints SFT tokens for a depositor based on the amount of deposit.\\n\\t/// @param depositAmt The amount of fungible token deposited.\\n\\t/// @param depositor The address of the depositor.\\n\\tfunction mintSFT(\\n\\t\\tuint256 depositAmt,\\n\\t\\taddress depositor,\\n\\t\\tuint256 amount_raised\\n\\t) external canMint returns (uint256) {\\n\\t\\t// TODO remove after demo due to not beign able to move blocks in public networks\\n\\t\\t{\\n\\t\\t\\tamountRaised = amount_raised;\\n\\t\\t}\\n\\n\\t\\tuint256 totalDeposits = amountRaised;\\n\\t\\tuint256 maxShares = MAX_SUPPLY;\\n\\n\\t\\trequire(totalDeposits > 0, \\\"HousingSFT: No deposits recorded\\\");\\n\\n\\t\\tuint256 mintShare = (depositAmt * maxShares) / totalDeposits;\\n\\t\\trequire(mintShare > 0, \\\"HousingSFT: Computed token shares is invalid\\\");\\n\\n\\t\\ttotalSupply += mintShare;\\n\\t\\trequire(totalSupply <= MAX_SUPPLY, \\\"HousingSFT: Max supply exceeded\\\");\\n\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tHousingAttributes({\\n\\t\\t\\t\\trewardsPerShare: 0, // Should be 0 since they have never claimed any rent rewards\\n\\t\\t\\t\\toriginalOwner: depositor,\\n\\t\\t\\t\\ttokenWeight: mintShare\\n\\t\\t\\t})\\n\\t\\t);\\n\\n\\t\\treturn _mint(depositor, mintShare, attributes, \\\"\\\");\\n\\t}\\n\\n\\t/// @notice Checks if an address owns this HousingSFT and returns the attributes.\\n\\t/// @param owner The address to check the balance of.\\n\\t/// @return `HousingAttributes` if the owner has a positive balance of the token, panics otherwise.\\n\\tfunction getUserSFT(\\n\\t\\taddress owner,\\n\\t\\tuint256 nonce\\n\\t) public view returns (HousingAttributes memory) {\\n\\t\\trequire(\\n\\t\\t\\thasSFT(owner, nonce),\\n\\t\\t\\t\\\"HouisingSFT: No tokens found for user at nonce\\\"\\n\\t\\t);\\n\\n\\t\\treturn abi.decode(getRawTokenAttributes(nonce), (HousingAttributes));\\n\\t}\\n\\n\\tfunction getMaxSupply() public pure returns (uint256) {\\n\\t\\treturn MAX_SUPPLY;\\n\\t}\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (HousingSFTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tHousingSFTBalance[] memory balance = new HousingSFTBalance[](\\n\\t\\t\\t_sftBals.length\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = HousingSFTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(_sftBal.attributes, (HousingAttributes))\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\tfunction tokenDetails()\\n\\t\\tpublic\\n\\t\\tview\\n\\t\\treturns (string memory, string memory, uint256)\\n\\t{\\n\\t\\treturn (name(), symbol(), getMaxSupply());\\n\\t}\\n}\\n\",\"keccak256\":\"0x8fbbe8d670bc777eed8587d0a8b11acf1d7b40b9ae631fee4abc929f4275c160\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/NewHousingProjectLib.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport { HousingProject } from \\\"./HousingProject.sol\\\";\\n\\nlibrary NewHousingProject {\\n\\tfunction create(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddr\\n\\t) external returns (HousingProject) {\\n\\t\\treturn new HousingProject(name, symbol, smartHousingAddr);\\n\\t}\\n}\\n\",\"keccak256\":\"0x0ad286112bdc35e59e9424ffda000b7b6b582e228cca1cafc2b9cab28193628f\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/housing-project/RentsModule.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\\\";\\n\\nimport \\\"./HousingSFT.sol\\\";\\nimport \\\"./RewardSharing.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"./CallsSmartHousing.sol\\\";\\n\\n/// @title Rents Module\\n/// @notice Handles rent payments, reward calculations, and distribution for Housing projects.\\n/// @dev This abstract contract should be inherited by the HousingProject contract.\\nabstract contract RentsModule is CallsSmartHousing {\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\tusing RewardShares for rewardshares;\\n\\n\\tuint256 public rewardPerShare;\\n\\tuint256 public rewardsReserve;\\n\\tuint256 public facilityManagementFunds;\\n\\n\\tERC20Burnable housingToken;\\n\\tHousingSFT public projectSFT;\\n\\n\\t/// @notice Receives rent payments and distributes rewards.\\n\\t/// @param rentPayment The details of the rent payment.\\n\\tfunction receiveRent(ERC20TokenPayment calldata rentPayment) external {\\n\\t\\t// TODO set the appropriate rent per Project\\n\\t\\trequire(\\n\\t\\t\\trentPayment.amount > 0,\\n\\t\\t\\t\\\"RentsModule: Insufficient amount\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\trentPayment.token == housingToken,\\n\\t\\t\\t\\\"RentsModule: Invalid rent payment token\\\"\\n\\t\\t);\\n\\t\\trentPayment.receiveERC20();\\n\\n\\t\\tuint256 rentReward = (rentPayment.amount * 75) / 100;\\n\\t\\tuint256 ecosystemReward = (rentPayment.amount * 18) / 100;\\n\\t\\tuint256 facilityReward = (rentPayment.amount * 7) / 100;\\n\\n\\t\\tuint256 allShares = projectSFT.getMaxSupply();\\n\\t\\tuint256 rpsIncrease = (rentReward * DIVISION_SAFETY_CONST) / allShares;\\n\\n\\t\\trewardPerShare += rpsIncrease;\\n\\t\\trewardsReserve += rentReward;\\n\\t\\tfacilityManagementFunds += facilityReward;\\n\\n\\t\\thousingToken.burn(ecosystemReward);\\n\\t\\tISmartHousing(smartHousingAddr).addProjectRent(rentPayment.amount);\\n\\t}\\n\\n\\t/// @notice Claims rent rewards for a given token.\\n\\t/// @return The updated HousingAttributes.\\n\\tfunction claimRentReward(\\n\\t\\tuint256 nonce\\n\\t) external returns (HousingAttributes memory, rewardshares memory) {\\n\\t\\taddress caller = msg.sender;\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tHousingAttributes memory attr = projectSFT.getUserSFT(caller, nonce);\\n\\t\\trewardshares memory rewardShares = computeRewardShares(attr);\\n\\t\\tuint256 totalReward = rewardShares.total();\\n\\n\\t\\tif (totalReward == 0) {\\n\\t\\t\\t// Fail silently\\n\\t\\t\\treturn (attr, rewardShares);\\n\\t\\t}\\n\\n\\t\\trequire(rewardsReserve >= totalReward, \\\"Computed rewards too large\\\");\\n\\n\\t\\trewardsReserve -= totalReward;\\n\\n\\t\\t// We use original owner since we are certain they are registered\\n\\t\\t(, address referrer) = getReferrer(attr.originalOwner);\\n\\t\\tif (rewardShares.referrerValue > 0) {\\n\\t\\t\\tif (referrer != address(0)) {\\n\\t\\t\\t\\thousingToken.transfer(referrer, rewardShares.referrerValue); // Send to referrer\\n\\t\\t\\t} else {\\n\\t\\t\\t\\thousingToken.burn(rewardShares.referrerValue); // Burn to add to ecosystem reward\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tattr.rewardsPerShare = currentRPS;\\n\\n\\t\\tprojectSFT.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tprojectSFT.balanceOf(caller, nonce),\\n\\t\\t\\tabi.encode(attr)\\n\\t\\t);\\n\\n\\t\\thousingToken.transfer(caller, rewardShares.userValue); // Send to user\\n\\n\\t\\treturn (attr, rewardShares);\\n\\t}\\n\\n\\t/// @notice Computes the amount of rent claimable for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The amount of rent claimable.\\n\\tfunction rentClaimable(\\n\\t\\tHousingAttributes memory attr\\n\\t) public view returns (uint256) {\\n\\t\\treturn computeRewardShares(attr).userValue;\\n\\t}\\n\\n\\t/// @dev Computes the reward shares for a given token.\\n\\t/// @param attr The attributes of the token.\\n\\t/// @return The computed RewardShares.\\n\\tfunction computeRewardShares(\\n\\t\\tHousingAttributes memory attr\\n\\t) internal view returns (rewardshares memory) {\\n\\t\\tuint256 currentRPS = rewardPerShare;\\n\\n\\t\\tif (currentRPS == 0 || attr.rewardsPerShare >= currentRPS) {\\n\\t\\t\\treturn rewardshares({ userValue: 0, referrerValue: 0 });\\n\\t\\t}\\n\\n\\t\\tuint256 reward = computeReward(attr, currentRPS);\\n\\n\\t\\treturn splitReward(reward);\\n\\t}\\n}\\n\",\"keccak256\":\"0xe97c64b7d4f5a945493aa8492c4412248f60ec1e6e8cd74e3f805e40cc672768\",\"license\":\"MIT\"},\"contracts/housing-project/RewardSharing.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"./HousingSFT.sol\\\";\\n\\nuint256 constant DIVISION_SAFETY_CONST = 1_000_000_000_000_000_000;\\n\\nstruct rewardshares {\\n\\tuint256 userValue;\\n\\tuint256 referrerValue;\\n}\\n\\nlibrary RewardShares {\\n\\tfunction total(rewardshares memory self) internal pure returns (uint256) {\\n\\t\\treturn self.userValue + self.referrerValue;\\n\\t}\\n}\\n\\nfunction splitReward(uint256 reward) pure returns (rewardshares memory) {\\n\\tuint256 referrerValue = (reward * 6_66) / 100_00; // would amount to approximately 5% of grand total\\n\\tuint256 userValue = reward - referrerValue;\\n\\n\\treturn rewardshares(userValue, referrerValue);\\n}\\n\\nfunction computeReward(\\n\\tHousingAttributes memory attr,\\n\\tuint256 contractRPS\\n) pure returns (uint256) {\\n\\tif (contractRPS <= attr.rewardsPerShare) {\\n\\t\\treturn 0;\\n\\t}\\n\\n\\treturn\\n\\t\\t((contractRPS - attr.rewardsPerShare) * attr.tokenWeight) /\\n\\t\\tDIVISION_SAFETY_CONST;\\n}\\n\",\"keccak256\":\"0x9f07d2b3ee49b91e12ad7ce9ba248ab7dd30bc2efc4238a594e681d3f0348e54\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/lib/EpochsAndPeriods.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\n/// @title Epochs and Periods Management Library\\n/// @notice This library provides functions to manage and calculate epochs and periods based on a genesis timestamp and an epoch length.\\n/// @dev The epoch length is specified in hours, and the period is calculated as 30 epochs.\\nlibrary EpochsAndPeriods {\\n\\tstruct Storage {\\n\\t\\tuint256 genesis;\\n\\t\\tuint256 epochLength;\\n\\t}\\n\\n\\t/// @notice Initializes the storage with the current timestamp as the genesis and sets the epoch length.\\n\\t/// @param self The storage struct to initialize.\\n\\t/// @param _epochLength The length of an epoch in hours. This determines how long each epoch lasts.\\n\\t/// @dev This function should be called in the contract constructor to set the initial genesis timestamp and epoch length.\\n\\tfunction initialize(Storage storage self, uint256 _epochLength) internal {\\n\\t\\tself.genesis = block.timestamp;\\n\\t\\tself.epochLength = _epochLength;\\n\\t}\\n\\n\\t/// @notice Returns the current epoch based on the genesis timestamp and epoch length.\\n\\t/// @param self The storage struct containing the genesis timestamp and epoch length.\\n\\t/// @return The current epoch number.\\n\\t/// @dev The epoch is calculated by dividing the time elapsed since genesis by the epoch length in seconds.\\n\\tfunction currentEpoch(\\n\\t\\tStorage storage self\\n\\t) internal view returns (uint256) {\\n\\t\\trequire(self.genesis > 0, \\\"Invalid genesis timestamp\\\");\\n\\t\\treturn (block.timestamp - self.genesis) / (self.epochLength * 60 * 60);\\n\\t}\\n\\n\\t/// @notice Returns the current period based on the current epoch.\\n\\t/// @param self The storage struct containing the genesis timestamp and epoch length.\\n\\t/// @return The current period number.\\n\\t/// @dev The period is calculated by dividing the current epoch by 30.\\n\\tfunction currentPeriod(\\n\\t\\tStorage storage self\\n\\t) internal view returns (uint256) {\\n\\t\\treturn currentEpoch(self) / 30;\\n\\t}\\n}\\n\",\"keccak256\":\"0x1f41385e5d5eb0a27b0b7262b8caf99e89806036a8fd6c512bc123e7eb1fbbbd\",\"license\":\"MIT\"},\"contracts/lib/LkSHTAttributes.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @title LkSHTAttributes\\n * @dev Library for handling attributes and unlocking of the Locked SmartHousing Token.\\n */\\nlibrary LkSHTAttributes {\\n\\tusing SafeMath for uint256;\\n\\n\\t// TODO use this for mainnet uint256 constant LOCK_DURATION = 3 * 365 days; // 3 years\\n\\tuint256 constant LOCK_DURATION = 5 hours;\\n\\n\\tstruct Attributes {\\n\\t\\tuint256 initialAmount;\\n\\t\\tuint256 amount;\\n\\t\\tuint256 startTimestamp;\\n\\t\\tuint256 endTimestamp;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Creates new attributes for a Locked SmartHousing Token.\\n\\t * @param startTimestamp The start time of the lock.\\n\\t * @param amount The amount of SmartHousing Tokens locked.\\n\\t * @return attributes The initialized attributes.\\n\\t */\\n\\tfunction newAttributes(\\n\\t\\tuint256 startTimestamp,\\n\\t\\tuint256 amount\\n\\t) internal pure returns (Attributes memory) {\\n\\t\\treturn\\n\\t\\t\\tAttributes({\\n\\t\\t\\t\\tinitialAmount: amount,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tstartTimestamp: startTimestamp,\\n\\t\\t\\t\\tendTimestamp: startTimestamp.add(LOCK_DURATION)\\n\\t\\t\\t});\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calculates and deducts the unlocked amount based on the elapsed time.\\n\\t * @param self The attributes to update.\\n\\t * @return unlockedAmount The amount of tokens unlocked.\\n\\t */\\n\\tfunction unlockMatured(\\n\\t\\tAttributes memory self\\n\\t)\\n\\t\\tinternal\\n\\t\\tview\\n\\t\\treturns (uint256 unlockedAmount, Attributes memory newSelf)\\n\\t{\\n\\t\\tuint256 elapsed = elapsedTime(self);\\n\\t\\tunlockedAmount = self.amount.mul(elapsed).div(LOCK_DURATION);\\n\\n\\t\\tself.amount = self.amount.sub(unlockedAmount);\\n\\t\\tnewSelf = self;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calculates the elapsed time since the lock started.\\n\\t * @param self The attributes to use.\\n\\t * @return elapsedTime The elapsed time in seconds.\\n\\t */\\n\\tfunction elapsedTime(\\n\\t\\tAttributes memory self\\n\\t) internal view returns (uint256) {\\n\\t\\tuint256 currentTime = block.timestamp;\\n\\t\\tif (currentTime >= self.endTimestamp) {\\n\\t\\t\\treturn LOCK_DURATION;\\n\\t\\t} else {\\n\\t\\t\\treturn currentTime.sub(self.startTimestamp);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0xbaf851bef9603c72b3cce96d93f8f243f36187d31c8c94233101d802b9ae129d\",\"license\":\"MIT\"},\"contracts/lib/ProjectStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport \\\"./TokenPayments.sol\\\";\\n\\nlibrary ProjectStorage {\\n\\tusing SafeMath for uint256;\\n\\tusing TokenPayments for TokenPayment;\\n\\tusing ProjectStorage for Data;\\n\\n\\tenum Status {\\n\\t\\tFundingPeriod,\\n\\t\\tSuccessful,\\n\\t\\tFailed\\n\\t}\\n\\n\\tstruct Data {\\n\\t\\tuint256 id; // Unique identifier for the project\\n\\t\\taddress tokenAddress;\\n\\t\\taddress projectAddress; // Address of the deployed HousingProject contract\\n\\t\\tuint256 fundingGoal; // Target funding amount for the project\\n\\t\\tuint256 fundingDeadline; // Deadline timestamp for the project funding\\n\\t\\taddress fundingToken; // Address of the ERC20 token used for funding\\n\\t\\tuint256 collectedFunds; // Amount of funds collected for the project\\n\\t}\\n\\n\\tfunction status(Data storage self) internal view returns (Status) {\\n\\t\\tif (self.collectedFunds >= self.fundingGoal) {\\n\\t\\t\\treturn Status.Successful;\\n\\t\\t} else if (block.timestamp < self.fundingDeadline) {\\n\\t\\t\\treturn Status.FundingPeriod;\\n\\t\\t} else {\\n\\t\\t\\treturn Status.Failed;\\n\\t\\t}\\n\\t}\\n\\n\\tfunction createNew(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage projectsId,\\n\\t\\tuint256 projectCount,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline,\\n\\t\\taddress fundingToken,\\n\\t\\taddress projectAddress,\\n\\t\\taddress tokenAddress\\n\\t) internal returns (Data memory) {\\n\\t\\trequire(fundingGoal > 0, \\\"Funding goal must be more than 0\\\");\\n\\t\\trequire(\\n\\t\\t\\tfundingDeadline > block.timestamp,\\n\\t\\t\\t\\\"Deadline can't be in the past\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 newId = projectCount.add(1);\\n\\n\\t\\tData memory newProjectData = Data({\\n\\t\\t\\tid: newId,\\n\\t\\t\\tprojectAddress: projectAddress,\\n\\t\\t\\tfundingGoal: fundingGoal,\\n\\t\\t\\tfundingDeadline: fundingDeadline,\\n\\t\\t\\tfundingToken: fundingToken,\\n\\t\\t\\tcollectedFunds: 0,\\n\\t\\t\\ttokenAddress: tokenAddress\\n\\t\\t});\\n\\n\\t\\tprojects[newId] = newProjectData;\\n\\t\\tprojectsId[newProjectData.projectAddress] = newProjectData.id;\\n\\n\\t\\treturn newProjectData;\\n\\t}\\n\\n\\tfunction fund(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage usersDeposit,\\n\\t\\tuint256 projectId,\\n\\t\\taddress depositor,\\n\\t\\tTokenPayment calldata payment\\n\\t) internal {\\n\\t\\trequire(payment.amount > 0, \\\"Invalid funding amount\\\");\\n\\n\\t\\tData storage project = projects[projectId];\\n\\n\\t\\trequire(\\n\\t\\t\\tproject.status() == Status.FundingPeriod,\\n\\t\\t\\t\\\"Cannot fund project after deadline\\\"\\n\\t\\t);\\n\\t\\trequire(\\n\\t\\t\\taddress(payment.token) == project.fundingToken,\\n\\t\\t\\t\\\"Wrong token payment\\\"\\n\\t\\t);\\n\\t\\tpayment.receiveToken();\\n\\n\\t\\tproject.collectedFunds = project.collectedFunds.add(payment.amount);\\n\\t\\tusersDeposit[depositor] = usersDeposit[depositor].add(payment.amount);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Retrieves and updates the user's deposit for a specific project.\\n\\t * @param projectId The ID of the project to retrieve the deposit for.\\n\\t * @param depositor The address of the depositor.\\n\\t * @return (ProjectStorage.Data, uint256) The project data and deposit amount.\\n\\t */\\n\\tfunction takeDeposit(\\n\\t\\tmapping(uint256 => Data) storage projects,\\n\\t\\tmapping(address => uint256) storage usersDeposit,\\n\\t\\tuint256 projectId,\\n\\t\\taddress depositor\\n\\t) internal returns (ProjectStorage.Data memory, uint256) {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\trequire(project.id != 0, \\\"Invalid project ID\\\");\\n\\t\\trequire(\\n\\t\\t\\tproject.status() == Status.Successful,\\n\\t\\t\\t\\\"Project not yet successful\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 depositAmount = usersDeposit[depositor];\\n\\t\\trequire(depositAmount > 0, \\\"No deposit found\\\");\\n\\n\\t\\t// Update the deposit amount to zero\\n\\t\\tusersDeposit[depositor] = 0;\\n\\n\\t\\treturn (project, depositAmount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x652aab2dc03764c430b91f35e908430208d6a1bd27a4cc8060adb1ec7f249ad5\",\"license\":\"MIT\"},\"contracts/lib/TokenPayments.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/interfaces/IERC20.sol\\\";\\nimport { SFT } from \\\"../modules/SFT.sol\\\";\\n\\nstruct ERC20TokenPayment {\\n\\tIERC20 token;\\n\\tuint256 amount;\\n}\\n\\nstruct TokenPayment {\\n\\taddress token;\\n\\tuint256 amount;\\n\\tuint256 nonce;\\n}\\n\\nlibrary TokenPayments {\\n\\tfunction accept(ERC20TokenPayment calldata self) internal {\\n\\t\\tTokenPayments.receiveERC20(self, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(ERC20TokenPayment calldata payment) internal {\\n\\t\\tTokenPayments.receiveERC20(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveERC20(\\n\\t\\tERC20TokenPayment calldata payment,\\n\\t\\taddress from\\n\\t) internal {\\n\\t\\tpayment.token.transferFrom(from, address(this), payment.amount);\\n\\t}\\n\\n\\t// Receives both Native, SFTs and ERC20; ERC20 have nonce as 0, Native coins have address 0 as token value\\n\\tfunction receiveToken(TokenPayment memory payment) internal {\\n\\t\\treceiveToken(payment, msg.sender);\\n\\t}\\n\\n\\tfunction receiveToken(TokenPayment memory payment, address from) internal {\\n\\t\\tif (payment.token == address(0)) {\\n\\t\\t\\t// Native payment\\n\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tpayment.amount == msg.value,\\n\\t\\t\\t\\t\\\"expected payment amount must equal sent amount\\\"\\n\\t\\t\\t);\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tfrom == msg.sender,\\n\\t\\t\\t\\t\\\"can receive native payment only from caller\\\"\\n\\t\\t\\t);\\n\\t\\t\\t\\n\\t\\t\\t// Nothing to do again since the VM will handle balance movements\\n\\t\\t} else if (payment.nonce == 0) {\\n\\t\\t\\tIERC20(payment.token).transferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.amount\\n\\t\\t\\t);\\n\\t\\t} else {\\n\\t\\t\\tSFT(payment.token).safeTransferFrom(\\n\\t\\t\\t\\tfrom,\\n\\t\\t\\t\\taddress(this),\\n\\t\\t\\t\\tpayment.nonce,\\n\\t\\t\\t\\tpayment.amount,\\n\\t\\t\\t\\t\\\"\\\"\\n\\t\\t\\t);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x06bd73e8da1bde18d9aaf6d4b6a1bdec6e0718af6354fe2d7ce87251d6fd1ac5\",\"license\":\"MIT\"},\"contracts/main/HST.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\n\\nimport { TokenPayment } from \\\"../lib/TokenPayments.sol\\\";\\nimport { SFT } from \\\"../modules/SFT.sol\\\";\\n\\nlibrary NewHousingStakingToken {\\n\\tfunction create() external returns (HousingStakingToken) {\\n\\t\\treturn new HousingStakingToken();\\n\\t}\\n}\\n\\nstruct HstAttributes {\\n\\tTokenPayment[] projectTokens;\\n\\tuint256 projectsShareCheckpoint;\\n\\tuint256 shtRewardPerShare;\\n\\tuint256 shtAmount;\\n\\tuint256 stakeWeight;\\n\\tuint256 lkDuration;\\n\\tuint256 lkShtNonce;\\n}\\n\\ncontract HousingStakingToken is SFT {\\n\\tusing SafeMath for uint256;\\n\\n\\tuint256 public constant MIN_EPOCHS_LOCK = 180;\\n\\tuint256 public constant MAX_EPOCHS_LOCK = 1080;\\n\\n\\tevent MintHstToken(\\n\\t\\taddress indexed to,\\n\\t\\tuint256 nonce,\\n\\t\\tHstAttributes attributes\\n\\t);\\n\\n\\tconstructor() SFT(\\\"Housing Staking Token\\\", \\\"HST\\\") {}\\n\\n\\tfunction mint(\\n\\t\\tTokenPayment[] calldata projectTokens,\\n\\t\\tuint256 projectsShareCheckpoint,\\n\\t\\tuint256 shtRewardPerShare,\\n\\t\\tuint256 lkDuration,\\n\\t\\tuint256 shtAmount,\\n\\t\\tuint256 lkShtNonce\\n\\t) external onlyOwner returns (HstAttributes memory attr) {\\n\\t\\taddress caller = msg.sender;\\n\\n\\t\\t// Validate lock duration\\n\\t\\trequire(\\n\\t\\t\\tlkDuration >= MIN_EPOCHS_LOCK && lkDuration <= MAX_EPOCHS_LOCK,\\n\\t\\t\\t\\\"Invalid lock duration\\\"\\n\\t\\t);\\n\\n\\t\\trequire(shtAmount > 0 || lkShtNonce > 0, \\\"Must send SHT\\\");\\n\\t\\tuint256 projectTokenCount = projectTokens.length;\\n\\t\\trequire(\\n\\t\\t\\tprojectTokenCount > 0 && projectTokenCount <= 10,\\n\\t\\t\\t\\\"Must send project tokens of approved number\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 stakeWeight = shtAmount.mul(lkDuration);\\n\\t\\tattr = HstAttributes({\\n\\t\\t\\tprojectTokens: projectTokens,\\n\\t\\t\\tprojectsShareCheckpoint: projectsShareCheckpoint,\\n\\t\\t\\tshtRewardPerShare: shtRewardPerShare,\\n\\t\\t\\tshtAmount: shtAmount,\\n\\t\\t\\tstakeWeight: stakeWeight,\\n\\t\\t\\tlkDuration: lkDuration,\\n\\t\\t\\tlkShtNonce: lkShtNonce\\n\\t\\t});\\n\\n\\t\\t// Mint the HST token\\n\\t\\tuint256 nonce = _mint(caller, 1, abi.encode(attr), \\\"\\\");\\n\\n\\t\\temit MintHstToken(caller, nonce, attr);\\n\\t}\\n}\\n\",\"keccak256\":\"0x4f0e5e502fd02a59ed29b264e0894e4a79230d59a42e6f1fe389c5078d3f6d0d\",\"license\":\"MIT\"},\"contracts/main/Interface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"../lib/TokenPayments.sol\\\";\\n\\ninterface ISmartHousing {\\n\\tfunction addProjectRent(uint256 amount) external;\\n\\n\\tfunction createRefIDViaProxy(\\n\\t\\taddress userAddr,\\n\\t\\tuint256 referrerId\\n\\t) external returns (uint256);\\n\\n\\tfunction addProject(address projectAddress) external;\\n\\n\\tfunction setUpSHT(ERC20TokenPayment calldata payment) external;\\n}\\n\\ninterface IUserModule {\\n\\tfunction getReferrer(address user) external view returns (uint, address);\\n}\\n\",\"keccak256\":\"0x066719eed5c5ff2394d78ce027aada5a8555713c9f4abf8b5135975981ba9989\",\"license\":\"MIT\"},\"contracts/main/SmartHousing.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\\\";\\n\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"../modules/sht-module/SHT.sol\\\";\\nimport \\\"../project-funding/ProjectFunding.sol\\\";\\n\\nimport \\\"./Interface.sol\\\";\\nimport \\\"./User.sol\\\";\\n\\nimport { Distribution } from \\\"./distribution/Storage.sol\\\";\\nimport { EpochsAndPeriods } from \\\"../lib/EpochsAndPeriods.sol\\\";\\nimport { HousingStakingToken, NewHousingStakingToken, HstAttributes } from \\\"./HST.sol\\\";\\n\\nimport { HousingProject } from \\\"../housing-project/HousingProject.sol\\\";\\nimport { rewardshares } from \\\"../housing-project/RewardSharing.sol\\\";\\n\\n/// @title SmartHousing\\n/// @notice SmartHousing leverages blockchain technology to revolutionize real estate investment and development by enabling the tokenization of properties.\\n/// @dev This contract allows for fractional ownership and ease of investment.\\n/// This innovative approach addresses the high costs and limited access to real estate investments in Abuja, Nigeria, making the market more inclusive and accessible.\\n/// By selling tokens, SmartHousing provides developers with immediate access to liquid funds, ensuring the timely and quality completion of affordable development projects.\\n/// The SmartHousing Contract is the main contract for the SmartHousing ecosystem.\\n/// This contract owns and deploys HousingProject contracts, which will represent the properties owned and managed by the SmartHousing project.\\n/// The management of ecosystem users will also be done in this contract.\\ncontract SmartHousing is\\n\\tISmartHousing,\\n\\tOwnable,\\n\\tUserModule,\\n\\tHousingStakingToken\\n{\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\tusing Distribution for Distribution.Storage;\\n\\tusing EpochsAndPeriods for EpochsAndPeriods.Storage;\\n\\tusing EnumerableSet for EnumerableSet.AddressSet;\\n\\tusing TokenPayments for TokenPayment;\\n\\tusing SafeMath for uint256;\\n\\n\\taddress public projectFundingAddress;\\n\\taddress public coinbaseAddress;\\n\\taddress public shtTokenAddress;\\n\\tHousingStakingToken public hst;\\n\\n\\tDistribution.Storage public distributionStorage;\\n\\tEpochsAndPeriods.Storage public epochsAndPeriodsStorage;\\n\\n\\tenum Permissions {\\n\\t\\tNONE,\\n\\t\\tHOUSING_PROJECT\\n\\t}\\n\\n\\tmapping(address => Permissions) public permissions;\\n\\tEnumerableSet.AddressSet private _projectsToken; // Enumerable list of project addresses\\n\\n\\tconstructor(address conibase, address projectFunding) {\\n\\t\\tcoinbaseAddress = conibase;\\n\\t\\tprojectFundingAddress = projectFunding;\\n\\t\\thst = NewHousingStakingToken.create();\\n\\n\\t\\t// TODO use this for mainnet epochsAndPeriodsStorage.initialize(24); // One epoch will span 24 hours\\n\\t\\tepochsAndPeriodsStorage.initialize(1); // One epoch will span 1 hour\\n\\t}\\n\\n\\t/// @notice Register a new user via proxy or get the referral ID if already registered.\\n\\t/// @param userAddr The address of the user.\\n\\t/// @param referrerId The ID of the referrer.\\n\\t/// @return The ID of the registered user.\\n\\tfunction createRefIDViaProxy(\\n\\t\\taddress userAddr,\\n\\t\\tuint256 referrerId\\n\\t) external onlyProjectFunding returns (uint256) {\\n\\t\\treturn _createOrGetUserId(userAddr, referrerId);\\n\\t}\\n\\n\\tfunction setUpSHT(ERC20TokenPayment calldata payment) external {\\n\\t\\trequire(\\n\\t\\t\\tmsg.sender == coinbaseAddress,\\n\\t\\t\\t\\\"Caller is not the coinbase address\\\"\\n\\t\\t);\\n\\n\\t\\t// Ensure that the SHT token has not been set already\\n\\t\\trequire(shtTokenAddress == address(0), \\\"SHT token already set\\\");\\n\\t\\tshtTokenAddress = address(payment.token);\\n\\n\\t\\t// Verify that the correct amount of SHT has been sent\\n\\t\\trequire(\\n\\t\\t\\tpayment.amount == SHT.ECOSYSTEM_DISTRIBUTION_FUNDS,\\n\\t\\t\\t\\\"Must send all ecosystem funds\\\"\\n\\t\\t);\\n\\t\\tpayment.accept();\\n\\n\\t\\t// Set the total funds in distribution storage\\n\\t\\tdistributionStorage.setTotalFunds(\\n\\t\\t\\tepochsAndPeriodsStorage,\\n\\t\\t\\tpayment.amount\\n\\t\\t);\\n\\t}\\n\\n\\t/// @notice Adds a new project and sets its permissions.\\n\\t/// @param projectAddress The address of the new project.\\n\\tfunction addProject(address projectAddress) external onlyProjectFunding {\\n\\t\\t_setPermissions(projectAddress, Permissions.HOUSING_PROJECT);\\n\\t\\t_projectsToken.add(projectAddress); // Register the project address\\n\\t}\\n\\n\\t/// @notice Adds rent to a project and updates the distribution storage.\\n\\t/// @dev projectAddress is the msg.msg.sender which must be a recognised HousingProject contract\\n\\t/// @param amount The amount of rent received.\\n\\tfunction addProjectRent(uint256 amount) external onlyHousingProject {\\n\\t\\taddress projectAddress = msg.sender;\\n\\t\\tdistributionStorage.addProjectRent(projectAddress, amount);\\n\\t}\\n\\n\\tfunction stake(\\n\\t\\tTokenPayment[] calldata stakingTokens,\\n\\t\\tuint256 epochsLock,\\n\\t\\tuint256 referrerId\\n\\t) external payable {\\n\\t\\trequire(\\n\\t\\t\\tepochsLock >= MIN_EPOCHS_LOCK && epochsLock <= MAX_EPOCHS_LOCK,\\n\\t\\t\\t\\\"Invalid epochs lock period\\\"\\n\\t\\t);\\n\\n\\t\\taddress caller = msg.sender;\\n\\n\\t\\t// Try create ID\\n\\t\\t_createOrGetUserId(caller, referrerId);\\n\\n\\t\\t// Generate rewards before staking\\n\\t\\tdistributionStorage.generateRewards(epochsAndPeriodsStorage);\\n\\n\\t\\tHstAttributes memory newAttr = _mintHstToken(\\n\\t\\t\\tstakingTokens,\\n\\t\\t\\tdistributionStorage.projectsStakingRewards.checkpoint,\\n\\t\\t\\tdistributionStorage.shtRewardPerShare,\\n\\t\\t\\tepochsLock,\\n\\t\\t\\tshtTokenAddress,\\n\\t\\t\\taddress(ProjectFunding(projectFundingAddress).lkSht())\\n\\t\\t);\\n\\n\\t\\tdistributionStorage.enterStaking(newAttr.stakeWeight);\\n\\t}\\n\\n\\tfunction claimRewards(uint256 hstTokenId, uint256 referrerId) external {\\n\\t\\taddress caller = msg.sender;\\n\\t\\t_createOrGetUserId(caller, referrerId);\\n\\n\\t\\tuint256 callerHstBal = hst.balanceOf(caller, hstTokenId);\\n\\n\\t\\trequire(callerHstBal > 0, \\\"Caller does not own the hst token\\\");\\n\\n\\t\\tdistributionStorage.generateRewards(epochsAndPeriodsStorage);\\n\\n\\t\\t(uint256 claimedSHT, HstAttributes memory hstAttr) = distributionStorage\\n\\t\\t\\t.claimRewards(\\n\\t\\t\\t\\tabi.decode(getRawTokenAttributes(hstTokenId), (HstAttributes))\\n\\t\\t\\t);\\n\\t\\tuint256 rentRewards = 0;\\n\\n\\t\\t// Claim rent rewards from HousingProjects\\n\\t\\tfor (uint256 i = 0; i < hstAttr.projectTokens.length; i++) {\\n\\t\\t\\tTokenPayment memory projectToken = hstAttr.projectTokens[i];\\n\\t\\t\\trequire(\\n\\t\\t\\t\\tprojectToken.token != address(0),\\n\\t\\t\\t\\t\\\"Invalid project address\\\"\\n\\t\\t\\t);\\n\\n\\t\\t\\t// Call the external contract's claimRentReward function\\n\\t\\t\\t(, rewardshares memory rewardShares) = HousingProject(\\n\\t\\t\\t\\tprojectToken.token\\n\\t\\t\\t).claimRentReward(projectToken.nonce);\\n\\n\\t\\t\\trentRewards = rentRewards.add(rewardShares.userValue);\\n\\t\\t}\\n\\n\\t\\t// Update the attributes in the hst token\\n\\t\\thst.update(caller, hstTokenId, callerHstBal, abi.encode(hstAttr));\\n\\n\\t\\tERC20Burnable shtToken = ERC20Burnable(shtTokenAddress);\\n\\n\\t\\tif (claimedSHT > 0) {\\n\\t\\t\\tuint256 referrerValue = claimedSHT.mul(25).div(1000);\\n\\t\\t\\tclaimedSHT = claimedSHT.sub(referrerValue);\\n\\n\\t\\t\\t// Do referrer operations\\n\\t\\t\\t(, address referrerAddr) = getReferrer(caller);\\n\\t\\t\\tif (referrerAddr != address(0)) {\\n\\t\\t\\t\\tshtToken.transfer(referrerAddr, referrerValue);\\n\\t\\t\\t} else {\\n\\t\\t\\t\\tshtToken.burn(referrerValue);\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tshtToken.transfer(caller, claimedSHT.add(rentRewards));\\n\\t}\\n\\n\\tfunction projectDets(\\n\\t\\taddress project\\n\\t) public view returns (Distribution.ProjectDistributionData memory) {\\n\\t\\treturn distributionStorage.projectDets[project];\\n\\t}\\n\\n\\tfunction projectsToken() public view returns (address[] memory) {\\n\\t\\treturn _projectsToken.values();\\n\\t}\\n\\n\\t/// @notice Sets the permissions for a given address.\\n\\t/// @param addr The address to set permissions for.\\n\\t/// @param perm The permissions to set.\\n\\tfunction _setPermissions(address addr, Permissions perm) internal {\\n\\t\\tpermissions[addr] = perm;\\n\\t}\\n\\n\\tfunction _mintHstToken(\\n\\t\\tTokenPayment[] calldata payments,\\n\\t\\tuint256 projectsShareCheckpoint,\\n\\t\\tuint256 shtRewardPerShare,\\n\\t\\tuint256 lkDuration,\\n\\t\\taddress shtAddress,\\n\\t\\taddress lkShtAddress\\n\\t) internal returns (HstAttributes memory attr) {\\n\\t\\taddress caller = msg.sender;\\n\\n\\t\\tuint256 maxProjectTokens = 10;\\n\\t\\tTokenPayment[] memory projectTokens = new TokenPayment[](\\n\\t\\t\\tmaxProjectTokens\\n\\t\\t);\\n\\t\\tuint256 projectTokenCount = 0;\\n\\t\\tuint256 shtAmount = 0;\\n\\t\\tuint256 lkShtNonce = 0;\\n\\n\\t\\tfor (uint256 i = 0; i < payments.length; i++) {\\n\\t\\t\\tTokenPayment memory payment = payments[i];\\n\\n\\t\\t\\tif (payment.token == shtAddress) {\\n\\t\\t\\t\\tshtAmount = payment.amount;\\n\\t\\t\\t} else if (payment.token == lkShtAddress) {\\n\\t\\t\\t\\tlkShtNonce = payment.nonce;\\n\\t\\t\\t} else if (_projectsToken.contains(payment.token)) {\\n\\t\\t\\t\\t// Validate that the payment is for an allowed project token\\n\\t\\t\\t\\trequire(\\n\\t\\t\\t\\t\\tprojectTokens.length < maxProjectTokens,\\n\\t\\t\\t\\t\\t\\\"Max project tokens exceeded\\\"\\n\\t\\t\\t\\t);\\n\\n\\t\\t\\t\\tprojectTokens[projectTokenCount] = payment;\\n\\t\\t\\t\\tprojectTokenCount++;\\n\\t\\t\\t} else {\\n\\t\\t\\t\\trevert(\\\"Invalid Sent Token\\\");\\n\\t\\t\\t}\\n\\n\\t\\t\\tpayment.receiveToken(caller);\\n\\t\\t}\\n\\n\\t\\treturn\\n\\t\\t\\thst.mint(\\n\\t\\t\\t\\tprojectTokens,\\n\\t\\t\\t\\tprojectsShareCheckpoint,\\n\\t\\t\\t\\tshtRewardPerShare,\\n\\t\\t\\t\\tlkDuration,\\n\\t\\t\\t\\tshtAmount,\\n\\t\\t\\t\\tlkShtNonce\\n\\t\\t\\t);\\n\\t}\\n\\n\\tmodifier onlyProjectFunding() {\\n\\t\\trequire(\\n\\t\\t\\tmsg.sender == projectFundingAddress,\\n\\t\\t\\t\\\"Caller is not the project funder\\\"\\n\\t\\t);\\n\\t\\t_;\\n\\t}\\n\\n\\tmodifier onlyHousingProject() {\\n\\t\\trequire(\\n\\t\\t\\tpermissions[msg.sender] == Permissions.HOUSING_PROJECT,\\n\\t\\t\\t\\\"Caller is not an accepted housing project\\\"\\n\\t\\t);\\n\\t\\t_;\\n\\t}\\n}\\n\",\"keccak256\":\"0xea1ab05257afd6f7fd39b3bc0208df82c9935977135cff846ccad9bd1f1bfd32\",\"license\":\"MIT\"},\"contracts/main/User.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity 0.8.24;\\n\\nimport \\\"./Interface.sol\\\";\\n\\nabstract contract UserModule is IUserModule {\\n\\tstruct ReferralInfo {\\n\\t\\tuint256 id;\\n\\t\\taddress referralAddress;\\n\\t}\\n\\n\\tstruct User {\\n\\t\\tuint256 id;\\n\\t\\taddress addr;\\n\\t\\tuint256 referrerId;\\n\\t\\tuint256[] referrals;\\n\\t}\\n\\n\\tuint256 public userCount;\\n\\tmapping(address => User) public users;\\n\\tmapping(uint256 => address) public userIdToAddress;\\n\\n\\tevent UserRegistered(\\n\\t\\tuint256 userId,\\n\\t\\taddress userAddress,\\n\\t\\tuint256 referrerId\\n\\t);\\n\\tevent ReferralAdded(uint256 referrerId, uint256 referralId);\\n\\n\\t/// @notice Register a new user or get the referral ID if already registered.\\n\\t/// @param referrerId The ID of the referrer.\\n\\t/// @return The ID of the registered user.\\n\\tfunction createRefID(uint256 referrerId) external returns (uint256) {\\n\\t\\taddress userAddr = msg.sender;\\n\\t\\treturn _createOrGetUserId(userAddr, referrerId);\\n\\t}\\n\\n\\t/// @notice Gets the referrer and referrer ID of a user.\\n\\t/// @param userAddress The address of the user.\\n\\t/// @return referrerId The ID of the referrer, 0 if none.\\n\\t/// @return referrerAddress The address of the referrer, address(0) if none.\\n\\tfunction getReferrer(\\n\\t\\taddress userAddress\\n\\t) public view returns (uint256 referrerId, address referrerAddress) {\\n\\t\\tUser storage user = users[userAddress];\\n\\t\\treferrerId = user.referrerId;\\n\\t\\treferrerAddress = userIdToAddress[referrerId];\\n\\t}\\n\\n\\tfunction getUserId(\\n\\t\\taddress userAddress\\n\\t) external view returns (uint256 userId) {\\n\\t\\treturn users[userAddress].id;\\n\\t}\\n\\n\\tfunction getReferrals(\\n\\t\\taddress userAddress\\n\\t) external view returns (ReferralInfo[] memory) {\\n\\t\\tuint256[] memory referralIds = users[userAddress].referrals;\\n\\t\\tReferralInfo[] memory referrals = new ReferralInfo[](\\n\\t\\t\\treferralIds.length\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i = 0; i < referralIds.length; i++) {\\n\\t\\t\\tuint256 id = referralIds[i];\\n\\t\\t\\taddress refAddr = userIdToAddress[id];\\n\\t\\t\\treferrals[i] = ReferralInfo({ id: id, referralAddress: refAddr });\\n\\t\\t}\\n\\n\\t\\treturn referrals;\\n\\t}\\n\\n\\t/// @notice Internal function to create or get the user ID.\\n\\t/// @param userAddr The address of the user.\\n\\t/// @param referrerId The ID of the referrer.\\n\\t/// @return The ID of the user.\\n\\tfunction _createOrGetUserId(\\n\\t\\taddress userAddr,\\n\\t\\tuint256 referrerId\\n\\t) internal returns (uint256) {\\n\\t\\tif (users[userAddr].id != 0) {\\n\\t\\t\\treturn users[userAddr].id;\\n\\t\\t}\\n\\n\\t\\tuserCount++;\\n\\t\\tusers[userAddr] = User({\\n\\t\\t\\tid: userCount,\\n\\t\\t\\taddr: userAddr,\\n\\t\\t\\treferrerId: referrerId,\\n\\t\\t\\treferrals: new uint256[](0)\\n\\t\\t});\\n\\t\\tuserIdToAddress[userCount] = userAddr;\\n\\n\\t\\tif (\\n\\t\\t\\treferrerId != 0 &&\\n\\t\\t\\treferrerId != userCount &&\\n\\t\\t\\tuserIdToAddress[referrerId] != address(0)\\n\\t\\t) {\\n\\t\\t\\tusers[userIdToAddress[referrerId]].referrals.push(userCount);\\n\\t\\t\\temit ReferralAdded(referrerId, userCount);\\n\\t\\t}\\n\\n\\t\\temit UserRegistered(userCount, userAddr, referrerId);\\n\\t\\treturn userCount;\\n\\t}\\n}\\n\",\"keccak256\":\"0x206c6860f427559d04d53cac1b2e1481c8d23776afc6d54ac6ec7e76b11eb687\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/main/distribution/Storage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\nimport \\\"../../lib/EpochsAndPeriods.sol\\\";\\nimport \\\"../../housing-project/HousingProject.sol\\\";\\nimport \\\"../../modules/sht-module/Economics.sol\\\";\\nimport { HstAttributes } from \\\"../HST.sol\\\";\\n\\nlibrary ProjectStakingRewards {\\n\\tusing SafeMath for uint256;\\n\\n\\tstruct Value {\\n\\t\\tuint256 toShare;\\n\\t\\tuint256 checkpoint;\\n\\t}\\n\\n\\tfunction add(Value storage self, uint256 rhs) internal {\\n\\t\\tself.toShare = self.toShare.add(rhs);\\n\\t\\tself.checkpoint = self.checkpoint.add(rhs);\\n\\t}\\n\\n\\tfunction sub(Value storage self, uint256 rhs) internal {\\n\\t\\tself.toShare = self.toShare.sub(rhs);\\n\\t}\\n}\\n\\nlibrary Distribution {\\n\\tusing SafeMath for uint256;\\n\\tusing EpochsAndPeriods for EpochsAndPeriods.Storage;\\n\\tusing Entities for Entities.Value;\\n\\tusing ProjectStakingRewards for ProjectStakingRewards.Value;\\n\\n\\tstruct Storage {\\n\\t\\tuint256 totalFunds;\\n\\t\\tuint256 genesisEpoch;\\n\\t\\tuint256 projectsTotalReceivedRents;\\n\\t\\tmapping(address => ProjectDistributionData) projectDets;\\n\\t\\tuint256 lastFundsDispatchEpoch;\\n\\t\\tuint256 shtTotalStakeWeight;\\n\\t\\tuint256 shtRewardPerShare;\\n\\t\\tuint256 shtStakingRewards;\\n\\t\\tProjectStakingRewards.Value projectsStakingRewards;\\n\\t\\tEntities.Value entityFunds;\\n\\t}\\n\\n\\tstruct ProjectDistributionData {\\n\\t\\tuint256 maxShares;\\n\\t\\tuint256 receivedRents;\\n\\t}\\n\\n\\t/// @notice Sets the total funds and the genesis epoch. This can only be done once.\\n\\t/// @param self The storage struct to set the total funds and genesis epoch.\\n\\t/// @param amount The amount of total funds to set.\\n\\t/// @param epochsAndPeriods The storage struct for epoch and period management.\\n\\tfunction setTotalFunds(\\n\\t\\tStorage storage self,\\n\\t\\tEpochsAndPeriods.Storage storage epochsAndPeriods,\\n\\t\\tuint256 amount\\n\\t) internal {\\n\\t\\trequire(self.totalFunds == 0, \\\"Total funds already set\\\");\\n\\t\\tself.totalFunds = amount;\\n\\t\\tself.genesisEpoch = epochsAndPeriods.currentEpoch();\\n\\t}\\n\\n\\t/// @notice Returns the total funds.\\n\\t/// @param self The storage struct containing the total funds.\\n\\t/// @return The total funds.\\n\\tfunction getTotalFunds(\\n\\t\\tStorage storage self\\n\\t) internal view returns (uint256) {\\n\\t\\treturn self.totalFunds;\\n\\t}\\n\\n\\t/// @notice Returns the genesis epoch when the total funds were set.\\n\\t/// @param self The storage struct containing the genesis epoch.\\n\\t/// @return The genesis epoch.\\n\\tfunction getGenesisEpoch(\\n\\t\\tStorage storage self\\n\\t) internal view returns (uint256) {\\n\\t\\treturn self.genesisEpoch;\\n\\t}\\n\\n\\t/// @notice Adds the rent received for a project and updates the total received rents and project-specific data.\\n\\t/// @dev This function updates the total amount of rent received across all projects and updates the specific project data.\\n\\t/// If the `maxShares` for the project has not been set, it retrieves and sets it from the `HousingProject` contract.\\n\\t/// @param self The storage struct for the `Distribution` contract where project and rent data is stored.\\n\\t/// @param projectAddress The address of the project whose rent is being added.\\n\\t/// @param amount The amount of rent received to be added to the project and total received rents.\\n\\tfunction addProjectRent(\\n\\t\\tStorage storage self,\\n\\t\\taddress projectAddress,\\n\\t\\tuint256 amount\\n\\t) internal {\\n\\t\\t// Update the total received rents across all projects\\n\\t\\tself.projectsTotalReceivedRents += amount;\\n\\n\\t\\t// Retrieve or initialize project-specific data\\n\\t\\tProjectDistributionData storage projectData = self.projectDets[\\n\\t\\t\\tprojectAddress\\n\\t\\t];\\n\\n\\t\\t// If `maxShares` is not set, initialize it with the maximum supply from the HousingProject contract\\n\\t\\tif (projectData.maxShares == 0) {\\n\\t\\t\\tprojectData.maxShares = HousingProject(projectAddress)\\n\\t\\t\\t\\t.getMaxSupply();\\n\\t\\t}\\n\\n\\t\\t// Add the received rent amount to the project's accumulated rents\\n\\t\\tprojectData.receivedRents += amount;\\n\\t}\\n\\n\\t/// @notice Generates rewards for the current epoch.\\n\\t/// @param self The storage struct for the `Distribution` contract.\\n\\tfunction generateRewards(\\n\\t\\tStorage storage self,\\n\\t\\tEpochsAndPeriods.Storage storage epochsAndPeriods\\n\\t) internal {\\n\\t\\tuint256 currentEpoch = epochsAndPeriods.currentEpoch();\\n\\t\\tif (currentEpoch <= self.lastFundsDispatchEpoch) {\\n\\t\\t\\treturn;\\n\\t\\t}\\n\\n\\t\\tuint256 toDispatch = Emission.throughEpochRange(\\n\\t\\t\\tself.lastFundsDispatchEpoch,\\n\\t\\t\\tcurrentEpoch\\n\\t\\t);\\n\\t\\tEntities.Value memory entitiesValue = Entities.fromTotalValue(\\n\\t\\t\\ttoDispatch\\n\\t\\t);\\n\\n\\t\\t// Take staking value\\n\\t\\tuint256 stakingRewards = entitiesValue.staking;\\n\\t\\tentitiesValue.staking = 0;\\n\\t\\tself.entityFunds.add(entitiesValue);\\n\\n\\t\\tuint256 shtStakersShare = stakingRewards.mul(7).div(10); // 70% goes to SHT stakers\\n\\n\\t\\tuint256 totalShtWeight = self.shtTotalStakeWeight;\\n\\t\\tif (totalShtWeight > 0) {\\n\\t\\t\\tuint256 rpsIncrease = shtStakersShare\\n\\t\\t\\t\\t.mul(DIVISION_SAFETY_CONST)\\n\\t\\t\\t\\t.div(totalShtWeight);\\n\\t\\t\\tself.shtRewardPerShare = self.shtRewardPerShare.add(rpsIncrease);\\n\\t\\t}\\n\\n\\t\\tself.shtStakingRewards = self.shtStakingRewards.add(shtStakersShare);\\n\\t\\tself.projectsStakingRewards.add(stakingRewards.sub(shtStakersShare));\\n\\n\\t\\tself.lastFundsDispatchEpoch = currentEpoch;\\n\\t}\\n\\n\\t/// @notice Claims rewards for a given attribute.\\n\\t/// @param self The storage struct for the `Distribution` contract.\\n\\t/// @param attr The attributes struct for which rewards are being claimed.\\n\\t/// @return The total amount of rewards claimed.\\n\\tfunction claimRewards(\\n\\t\\tStorage storage self,\\n\\t\\tHstAttributes memory attr\\n\\t) internal returns (uint256, HstAttributes memory) {\\n\\t\\tuint256 shtClaimed = 0;\\n\\n\\t\\t// Claim PT rewards\\n\\t\\tuint256 ptRewardCheckpoint = self.projectsStakingRewards.checkpoint;\\n\\t\\tif (ptRewardCheckpoint > 0) {\\n\\t\\t\\tfor (uint256 i = 0; i < attr.projectTokens.length; i++) {\\n\\t\\t\\t\\tshtClaimed = shtClaimed.add(\\n\\t\\t\\t\\t\\tcomputeRewardForPT(\\n\\t\\t\\t\\t\\t\\tself,\\n\\t\\t\\t\\t\\t\\tattr.projectTokens[i],\\n\\t\\t\\t\\t\\t\\tattr.projectsShareCheckpoint,\\n\\t\\t\\t\\t\\t\\tptRewardCheckpoint\\n\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t);\\n\\t\\t\\t}\\n\\n\\t\\t\\tif (self.projectsStakingRewards.toShare < shtClaimed) {\\n\\t\\t\\t\\tshtClaimed = self.projectsStakingRewards.toShare;\\n\\t\\t\\t}\\n\\t\\t\\tself.projectsStakingRewards.toShare = self\\n\\t\\t\\t\\t.projectsStakingRewards\\n\\t\\t\\t\\t.toShare\\n\\t\\t\\t\\t.sub(shtClaimed);\\n\\t\\t}\\n\\n\\t\\t// Claim SHT rewards\\n\\t\\tuint256 shtRPS = self.shtRewardPerShare;\\n\\t\\tif (shtRPS > 0 && attr.shtRewardPerShare < shtRPS) {\\n\\t\\t\\tuint256 shtReward = (shtRPS.sub(attr.shtRewardPerShare))\\n\\t\\t\\t\\t.mul(attr.stakeWeight)\\n\\t\\t\\t\\t.div(DIVISION_SAFETY_CONST);\\n\\t\\t\\tif (self.shtStakingRewards < shtReward) {\\n\\t\\t\\t\\tshtClaimed = self.shtStakingRewards;\\n\\t\\t\\t}\\n\\t\\t\\tself.shtStakingRewards = self.shtStakingRewards.sub(shtReward);\\n\\n\\t\\t\\tshtClaimed = shtClaimed.add(shtReward);\\n\\t\\t}\\n\\n\\t\\t// Update claim parameters\\n\\t\\tattr.shtRewardPerShare = shtRPS;\\n\\t\\tattr.projectsShareCheckpoint = ptRewardCheckpoint;\\n\\n\\t\\treturn (shtClaimed, attr);\\n\\t}\\n\\n\\t/// @notice Computes the reward for a given PT (Housing Project Token).\\n\\t/// @param self The storage struct for the `Distribution` contract.\\n\\t/// @param tokenPayment The token payment of the housing project.\\n\\t/// @param stakingCheckPoint The previous checkpoint value.\\n\\t/// @param tokenCheckPoint The new checkpoint value.\\n\\t/// @return reward The computed reward for the given PT.\\n\\tfunction computeRewardForPT(\\n\\t\\tStorage storage self,\\n\\t\\tTokenPayment memory tokenPayment,\\n\\t\\tuint256 stakingCheckPoint,\\n\\t\\tuint256 tokenCheckPoint\\n\\t) internal view returns (uint256 reward) {\\n\\t\\tif (stakingCheckPoint >= tokenCheckPoint) {\\n\\t\\t\\treturn 0;\\n\\t\\t}\\n\\n\\t\\tProjectDistributionData storage projectData = self.projectDets[\\n\\t\\t\\ttokenPayment.token\\n\\t\\t];\\n\\t\\trequire(\\n\\t\\t\\ttokenPayment.amount <= projectData.maxShares,\\n\\t\\t\\t\\\"Project token amount too large\\\"\\n\\t\\t);\\n\\n\\t\\tuint256 shareIncrease = tokenCheckPoint.sub(stakingCheckPoint);\\n\\t\\t// Project's allocation is dynamic, as rents received chages\\n\\t\\tuint256 projectAllocation = shareIncrease\\n\\t\\t\\t.mul(projectData.receivedRents)\\n\\t\\t\\t.div(self.projectsTotalReceivedRents);\\n\\n\\t\\treward = projectAllocation.mul(tokenPayment.amount).div(\\n\\t\\t\\tprojectData.maxShares\\n\\t\\t);\\n\\t}\\n\\n\\t/// @notice Enters staking for the given attributes.\\n\\t/// @param self The storage struct for the `Distribution` contract.\\n\\t/// @param stakeWeight The stake weight to be added.\\n\\tfunction enterStaking(Storage storage self, uint256 stakeWeight) internal {\\n\\t\\tself.shtTotalStakeWeight = self.shtTotalStakeWeight.add(stakeWeight);\\n\\t}\\n}\\n\",\"keccak256\":\"0x9fb3f9b3c9b1731783433460c46eacc05feeb3345cd9a175a65c7dacf01c46d6\",\"license\":\"MIT\"},\"contracts/modules/LockedSmartHousingToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\nimport \\\"../lib/LkSHTAttributes.sol\\\";\\nimport \\\"../lib/TokenPayments.sol\\\";\\nimport \\\"../modules/SFT.sol\\\";\\n\\nlibrary NewLkSHT {\\n\\tfunction create() external returns (LkSHT) {\\n\\t\\treturn new LkSHT(\\\"Locked Housing Token\\\", \\\"LkSHT\\\");\\n\\t}\\n}\\n\\n/**\\n * @title LockedSmartHousingToken\\n * @dev SFT token that locks SmartHousing Tokens (SHT) during ICO.\\n * Allows transfers only to whitelisted addresses.\\n */\\ncontract LkSHT is SFT {\\n\\tusing SafeMath for uint256;\\n\\tusing TokenPayments for ERC20TokenPayment;\\n\\n\\tstruct LkSHTBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tLkSHTAttributes.Attributes attributes;\\n\\t}\\n\\n\\tuint256 immutable startTimestamp = block.timestamp;\\n\\n\\tconstructor(\\n\\t\\tstring memory name_,\\n\\t\\tstring memory symbol_\\n\\t) SFT(name_, symbol_) {}\\n\\n\\tevent TokensMinted(address indexed to, uint256 amount);\\n\\n\\tfunction sftBalance(\\n\\t\\taddress user\\n\\t) public view returns (LkSHTBalance[] memory) {\\n\\t\\tSftBalance[] memory _sftBals = _sftBalance(user);\\n\\t\\tLkSHTBalance[] memory balance = new LkSHTBalance[](_sftBals.length);\\n\\n\\t\\tfor (uint256 i; i < _sftBals.length; i++) {\\n\\t\\t\\tSftBalance memory _sftBal = _sftBals[i];\\n\\n\\t\\t\\tbalance[i] = LkSHTBalance({\\n\\t\\t\\t\\tnonce: _sftBal.nonce,\\n\\t\\t\\t\\tamount: _sftBal.amount,\\n\\t\\t\\t\\tattributes: abi.decode(\\n\\t\\t\\t\\t\\t_sftBal.attributes,\\n\\t\\t\\t\\t\\t(LkSHTAttributes.Attributes)\\n\\t\\t\\t\\t)\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Mints new Locked SmartHousing Tokens (LkSHT) by locking SHT.\\n\\t * @param amount The amount of SHT to lock.\\n\\t * @param to The address to mint the tokens to.\\n\\t */\\n\\tfunction mint(uint256 amount, address to) external onlyOwner {\\n\\t\\tbytes memory attributes = abi.encode(\\n\\t\\t\\tLkSHTAttributes.newAttributes(startTimestamp, amount)\\n\\t\\t);\\n\\n\\t\\tsuper._mint(to, amount, attributes, \\\"LockedSmartHousingToken\\\");\\n\\n\\t\\temit TokensMinted(to, amount);\\n\\t}\\n}\\n\",\"keccak256\":\"0x33e840a42e8bab335538d2ab9a8973c97423b17caac5fd50a802b53f6db7357d\",\"license\":\"MIT\"},\"contracts/modules/SFT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Counters.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n// TODO I think we should create a standard of this\\nabstract contract SFT is ERC1155, Ownable {\\n\\tusing Counters for Counters.Counter;\\n\\tusing EnumerableSet for EnumerableSet.UintSet;\\n\\n\\tstruct SftBalance {\\n\\t\\tuint256 nonce;\\n\\t\\tuint256 amount;\\n\\t\\tbytes attributes;\\n\\t}\\n\\n\\tCounters.Counter private _nonceCounter;\\n\\tstring private _name;\\n\\tstring private _symbol;\\n\\n\\t// Mapping from nonce to token attributes as bytes\\n\\tmapping(uint256 => bytes) private _tokenAttributes;\\n\\n\\t// Mapping from address to list of owned token nonces\\n\\tmapping(address => EnumerableSet.UintSet) private _addressToNonces;\\n\\n\\tconstructor(string memory name_, string memory symbol_) ERC1155(\\\"\\\") {\\n\\t\\t_name = name_;\\n\\t\\t_symbol = symbol_;\\n\\t}\\n\\n\\t// Private function to mint new tokens\\n\\tfunction _mint(\\n\\t\\taddress to,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attributes,\\n\\t\\tbytes memory data\\n\\t) internal returns (uint256) {\\n\\t\\t_nonceCounter.increment();\\n\\t\\tuint256 nonce = _nonceCounter.current();\\n\\n\\t\\t// Store the attributes\\n\\t\\t_tokenAttributes[nonce] = attributes;\\n\\n\\t\\t// Mint the token with the nonce as its ID\\n\\t\\tsuper._mint(to, nonce, amount, data);\\n\\n\\t\\t// Track the nonce for the address\\n\\t\\t_addressToNonces[to].add(nonce);\\n\\n\\t\\treturn nonce;\\n\\t}\\n\\n\\tfunction name() public view returns (string memory) {\\n\\t\\treturn _name;\\n\\t}\\n\\n\\tfunction symbol() public view returns (string memory) {\\n\\t\\treturn _symbol;\\n\\t}\\n\\n\\tfunction tokenInfo() public view returns (string memory, string memory) {\\n\\t\\treturn (_name, _symbol);\\n\\t}\\n\\n\\t// Function to get token attributes by nonce\\n\\tfunction getRawTokenAttributes(\\n\\t\\tuint256 nonce\\n\\t) public view returns (bytes memory) {\\n\\t\\treturn _tokenAttributes[nonce];\\n\\t}\\n\\n\\t// Function to get list of nonces owned by an address\\n\\tfunction getNonces(address owner) public view returns (uint256[] memory) {\\n\\t\\treturn _addressToNonces[owner].values();\\n\\t}\\n\\n\\tfunction hasSFT(address owner, uint256 nonce) public view returns (bool) {\\n\\t\\treturn _addressToNonces[owner].contains(nonce);\\n\\t}\\n\\n\\t/// Burns all the NFT balance of user at nonce, creates new with balance and attributes\\n\\tfunction update(\\n\\t\\taddress user,\\n\\t\\tuint256 nonce,\\n\\t\\tuint256 amount,\\n\\t\\tbytes memory attr\\n\\t) external onlyOwner {\\n\\t\\t_burn(user, nonce, amount);\\n\\t\\t_mint(user, amount, attr, \\\"\\\");\\n\\t}\\n\\n\\tfunction _sftBalance(\\n\\t\\taddress user\\n\\t) internal view returns (SftBalance[] memory) {\\n\\t\\tuint256[] memory nonces = getNonces(user);\\n\\t\\tSftBalance[] memory balance = new SftBalance[](nonces.length);\\n\\n\\t\\tfor (uint256 i; i < nonces.length; i++) {\\n\\t\\t\\tuint256 nonce = nonces[i];\\n\\t\\t\\tbytes memory attributes = _tokenAttributes[nonce];\\n\\t\\t\\tuint256 amount = balanceOf(user, nonce);\\n\\n\\t\\t\\tbalance[i] = SftBalance({\\n\\t\\t\\t\\tnonce: nonce,\\n\\t\\t\\t\\tamount: amount,\\n\\t\\t\\t\\tattributes: attributes\\n\\t\\t\\t});\\n\\t\\t}\\n\\n\\t\\treturn balance;\\n\\t}\\n\\n\\t// Override _beforeTokenTransfer to handle address-to-nonce mapping\\n\\tfunction _beforeTokenTransfer(\\n\\t\\taddress operator,\\n\\t\\taddress from,\\n\\t\\taddress to,\\n\\t\\tuint256[] memory ids,\\n\\t\\tuint256[] memory amounts,\\n\\t\\tbytes memory data\\n\\t) internal virtual override {\\n\\t\\tsuper._beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[from].remove(ids[i]);\\n\\t\\t}\\n\\n\\t\\tfor (uint256 i = 0; i < ids.length; i++) {\\n\\t\\t\\t_addressToNonces[to].add(ids[i]);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x8098c36137bbb9a342d16fd64f7d57c03a77841a872dd44641b9db1623a699aa\",\"license\":\"MIT\"},\"contracts/modules/sht-module/Economics.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"prb-math/contracts/PRBMathUD60x18.sol\\\";\\n\\nlibrary Emission {\\n\\tusing PRBMathUD60x18 for uint256;\\n\\n\\tuint256 private constant DECAY_RATE = 9998e14; // 0.9998 with 18 decimals\\n\\tuint256 private constant E0 = 2729727036845720116116; // Example initial emission\\n\\n\\tfunction atEpoch(uint256 epoch) internal pure returns (uint256) {\\n\\t\\tuint256 decayFactor = PRBMathUD60x18.pow(DECAY_RATE, epoch);\\n\\t\\treturn E0.mul(decayFactor) / 1e18;\\n\\t}\\n\\n\\t/// @notice Computes E0 * \\u200b\\u200b(0.9998^epochStart \\u2212 0.9998^epochEnd\\u200b)\\n\\t/// @param epochStart the starting epoch\\n\\t/// @param epochEnd the end epoch\\n\\tfunction throughEpochRange(\\n\\t\\tuint256 epochStart,\\n\\t\\tuint256 epochEnd\\n\\t) internal pure returns (uint256) {\\n\\t\\trequire(epochEnd > epochStart, \\\"Invalid epoch range\\\");\\n\\n\\t\\tuint256 startFactor = PRBMathUD60x18.pow(DECAY_RATE, epochStart);\\n\\t\\tuint256 endFactor = PRBMathUD60x18.pow(DECAY_RATE, epochEnd);\\n\\n\\t\\tuint256 totalEmission = E0\\n\\t\\t\\t.mul(SafeMath.sub(startFactor, endFactor))\\n\\t\\t\\t.div(DECAY_RATE.ln());\\n\\t\\treturn totalEmission;\\n\\t}\\n}\\n\\nlibrary Entities {\\n\\tusing SafeMath for uint256;\\n\\n\\tuint32 public constant UNITY = 100_00;\\n\\n\\tuint32 public constant TEAM_AND_ADVISORS_RATIO = 23_05;\\n\\tuint32 public constant PROTOCOL_DEVELOPMENT_RATIO = 30_05;\\n\\tuint32 public constant GROWTH_RATIO = 15_35;\\n\\tuint32 public constant STAKING_RATIO = 16_55;\\n\\tuint32 public constant PROJECTS_RESERVE_RATIO = 8_00;\\n\\tuint32 public constant LP_AND_LISTINGS_RATIO = 7_00;\\n\\n\\tstruct Value {\\n\\t\\tuint256 team;\\n\\t\\tuint256 protocol;\\n\\t\\tuint256 growth;\\n\\t\\tuint256 staking;\\n\\t\\tuint256 projectsReserve;\\n\\t\\tuint256 lpAndListing;\\n\\t}\\n\\n\\tfunction fromTotalValue(\\n\\t\\tuint256 totalValue\\n\\t) internal pure returns (Value memory) {\\n\\t\\tuint256 othersTotal = totalValue\\n\\t\\t\\t.mul(UNITY - PROTOCOL_DEVELOPMENT_RATIO)\\n\\t\\t\\t.div(UNITY);\\n\\n\\t\\tuint256 team = othersTotal.mul(TEAM_AND_ADVISORS_RATIO).div(UNITY);\\n\\t\\tuint256 growth = othersTotal.mul(GROWTH_RATIO).div(UNITY);\\n\\t\\tuint256 staking = othersTotal.mul(STAKING_RATIO).div(UNITY);\\n\\t\\tuint256 projectsReserve = othersTotal.mul(PROJECTS_RESERVE_RATIO).div(\\n\\t\\t\\tUNITY\\n\\t\\t);\\n\\t\\tuint256 lpAndListing = othersTotal.mul(LP_AND_LISTINGS_RATIO).div(\\n\\t\\t\\tUNITY\\n\\t\\t);\\n\\n\\t\\tuint256 protocol = totalValue\\n\\t\\t\\t.sub(team)\\n\\t\\t\\t.sub(growth)\\n\\t\\t\\t.sub(staking)\\n\\t\\t\\t.sub(projectsReserve)\\n\\t\\t\\t.sub(lpAndListing);\\n\\n\\t\\treturn\\n\\t\\t\\tValue({\\n\\t\\t\\t\\tteam: team,\\n\\t\\t\\t\\tprotocol: protocol,\\n\\t\\t\\t\\tgrowth: growth,\\n\\t\\t\\t\\tstaking: staking,\\n\\t\\t\\t\\tprojectsReserve: projectsReserve,\\n\\t\\t\\t\\tlpAndListing: lpAndListing\\n\\t\\t\\t});\\n\\t}\\n\\n\\tfunction total(Value memory value) internal pure returns (uint256) {\\n\\t\\treturn\\n\\t\\t\\tvalue\\n\\t\\t\\t\\t.team\\n\\t\\t\\t\\t.add(value.protocol)\\n\\t\\t\\t\\t.add(value.growth)\\n\\t\\t\\t\\t.add(value.staking)\\n\\t\\t\\t\\t.add(value.projectsReserve)\\n\\t\\t\\t\\t.add(value.lpAndListing);\\n\\t}\\n\\n\\tfunction add(Value storage self, Value memory rhs) internal {\\n\\t\\tself.team = self.team.add(rhs.team);\\n\\t\\tself.protocol = self.protocol.add(rhs.protocol);\\n\\t\\tself.growth = self.growth.add(rhs.growth);\\n\\t\\tself.staking = self.staking.add(rhs.staking);\\n\\t\\tself.projectsReserve = self.projectsReserve.add(rhs.projectsReserve);\\n\\t\\tself.lpAndListing = self.lpAndListing.add(rhs.lpAndListing);\\n\\t}\\n}\\n\",\"keccak256\":\"0xeb86637b933f394907cff1d0a8cf706bd3f737a34d660d87feffbaee09de1c32\",\"license\":\"MIT\"},\"contracts/modules/sht-module/SHT.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nlibrary SHT {\\n\\tuint256 public constant DECIMALS = 18;\\n\\tuint256 public constant ONE = 10 ** DECIMALS;\\n\\tuint256 public constant MAX_SUPPLY = 21_000_000 * ONE;\\n\\tuint256 public constant ECOSYSTEM_DISTRIBUTION_FUNDS =\\n\\t\\t(13_650_000 * ONE) + 2_248_573_618_499_339;\\n\\tuint256 public constant ICO_FUNDS =\\n\\t\\tMAX_SUPPLY - ECOSYSTEM_DISTRIBUTION_FUNDS;\\n}\\n\",\"keccak256\":\"0x66b511a7932bd0f6ceea118f9440cac3a6fd470d11e4d7fa337de8b178627dd7\",\"license\":\"MIT\"},\"contracts/project-funding/ProjectFunding.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.24;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\\\";\\n\\nimport \\\"../lib/ProjectStorage.sol\\\";\\nimport \\\"../lib/LkSHTAttributes.sol\\\";\\n\\nimport \\\"../main/Interface.sol\\\";\\n\\nimport \\\"../modules/LockedSmartHousingToken.sol\\\";\\nimport \\\"../modules/sht-module/SHT.sol\\\";\\n\\nimport { HousingSFT } from \\\"../housing-project/HousingSFT.sol\\\";\\nimport { TokenPayment } from \\\"../lib/TokenPayments.sol\\\";\\nimport { NewHousingProject, HousingProject } from \\\"../housing-project/NewHousingProjectLib.sol\\\";\\n\\n/**\\n * @title ProjectFunding\\n * @dev This contract is used for initializing and deploying housing projects.\\n * It allows the deployment of a new housing project and manages project data.\\n */\\ncontract ProjectFunding is Ownable {\\n\\tusing SafeMath for uint256;\\n\\tusing ProjectStorage for mapping(uint256 => ProjectStorage.Data);\\n\\tusing ProjectStorage for ProjectStorage.Data;\\n\\tusing LkSHTAttributes for LkSHTAttributes.Attributes;\\n\\n\\taddress public coinbase; // Address authorized to initialize the first project, also the housingToken\\n\\taddress public smartHousingAddress; // Address of the SmartHousing contract\\n\\n\\tmapping(uint256 => ProjectStorage.Data) public projects; // Mapping of project ID to ProjectData\\n\\tmapping(address => uint256) public projectsId; // Mapping of project address to project ID\\n\\tuint256 public projectCount; // Counter for the total number of projects\\n\\n\\tmapping(uint256 => mapping(address => uint256)) public usersProjectDeposit;\\n\\n\\tIERC20 public housingToken; // Token used for funding projects\\n\\tLkSHT public lkSht; // The locked version\\n\\n\\t/**\\n\\t * @dev Emitted when a new project is deployed.\\n\\t * @param projectAddress Address of the newly deployed HousingProject contract.\\n\\t */\\n\\tevent ProjectDeployed(address indexed projectAddress);\\n\\tevent ProjectFunded(\\n\\t\\tuint256 indexed projectId,\\n\\t\\taddress indexed depositor,\\n\\t\\tTokenPayment payment\\n\\t);\\n\\tevent ProjectTokensClaimed(\\n\\t\\taddress indexed depositor,\\n\\t\\tuint256 projectId,\\n\\t\\tuint256 amount\\n\\t);\\n\\n\\t/**\\n\\t * @param _coinbase Address authorized to initialize the first project.\\n\\t */\\n\\tconstructor(address _coinbase) {\\n\\t\\tcoinbase = _coinbase;\\n\\t\\tlkSht = NewLkSHT.create();\\n\\t}\\n\\n\\t/**\\n\\t * @dev Internal function to deploy a new HousingProject contract.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction _deployProject(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) internal {\\n\\t\\tHousingProject newProject = NewHousingProject.create(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tsmartHousingAddress\\n\\t\\t);\\n\\t\\tProjectStorage.Data memory projectData = projects.createNew(\\n\\t\\t\\tprojectsId,\\n\\t\\t\\tprojectCount,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\taddress(newProject),\\n\\t\\t\\taddress(newProject.projectSFT())\\n\\t\\t);\\n\\t\\tprojectCount = projectData.id;\\n\\n\\t\\temit ProjectDeployed(projectData.projectAddress);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Initializes the first project.\\n\\t * This function must be called by the coinbase address and can only be called once.\\n\\t * It sets up the token and deploys the first project.\\n\\t * @param shtPayment Payment details for the Smart Housing Token (SHT).\\n\\t * @param smartHousingAddress_ Address of the Smart Housing contract.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction initFirstProject(\\n\\t\\tERC20TokenPayment calldata shtPayment,\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress smartHousingAddress_,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) external {\\n\\t\\trequire(msg.sender == coinbase, \\\"Caller is not the coinbase\\\");\\n\\t\\trequire(projectCount == 0, \\\"Project already initialized\\\");\\n\\n\\t\\tTokenPayments.receiveERC20(shtPayment);\\n\\t\\thousingToken = shtPayment.token;\\n\\n\\t\\tsmartHousingAddress = smartHousingAddress_;\\n\\n\\t\\t_deployProject(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Deploys a new project.\\n\\t * This function can be called multiple times to deploy additional projects.\\n\\t * @param fundingToken Address of the ERC20 token used for funding.\\n\\t * @param fundingGoal The funding goal for the new project.\\n\\t * @param fundingDeadline The deadline for the project funding.\\n\\t */\\n\\tfunction deployProject(\\n\\t\\tstring memory name,\\n\\t\\tstring memory symbol,\\n\\t\\taddress fundingToken,\\n\\t\\tuint256 fundingGoal,\\n\\t\\tuint256 fundingDeadline\\n\\t) public onlyOwner {\\n\\t\\t_deployProject(\\n\\t\\t\\tname,\\n\\t\\t\\tsymbol,\\n\\t\\t\\tfundingToken,\\n\\t\\t\\tfundingGoal,\\n\\t\\t\\tfundingDeadline\\n\\t\\t);\\n\\t}\\n\\n\\tfunction fundProject(\\n\\t\\tTokenPayment calldata depositPayment,\\n\\t\\tuint256 projectId,\\n\\t\\tuint256 referrerId\\n\\t) external payable {\\n\\t\\trequire(\\n\\t\\t\\tprojectId > 0 && projectId <= projectCount,\\n\\t\\t\\t\\\"Invalid project ID\\\"\\n\\t\\t);\\n\\n\\t\\taddress depositor = msg.sender;\\n\\n\\t\\t// Register user with referrer (if needed)\\n\\t\\tISmartHousing(smartHousingAddress).createRefIDViaProxy(\\n\\t\\t\\tdepositor,\\n\\t\\t\\treferrerId\\n\\t\\t);\\n\\n\\t\\t// Update project funding\\n\\t\\tprojects.fund(\\n\\t\\t\\tusersProjectDeposit[projectId],\\n\\t\\t\\tprojectId,\\n\\t\\t\\tdepositor,\\n\\t\\t\\tdepositPayment\\n\\t\\t);\\n\\n\\t\\temit ProjectFunded(projectId, depositor, depositPayment);\\n\\t}\\n\\n\\tfunction addProjectToEcosystem(uint256 projectId) external onlyOwner {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\n\\t\\t// TODO Add this after demo\\n\\t\\t// require(\\n\\t\\t// \\tproject.status() == ProjectStorage.Status.Successful,\\n\\t\\t// \\t\\\"Project Funding not yet successful\\\"\\n\\t\\t// );\\n\\n\\t\\tISmartHousing(smartHousingAddress).addProject(project.projectAddress);\\n\\n\\t\\tHousingProject(project.projectAddress).setTokenDetails(\\n\\t\\t\\tproject.collectedFunds,\\n\\t\\t\\tcoinbase\\n\\t\\t);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Claims project tokens for a given project ID.\\n\\t * @param projectId The ID of the project to claim tokens from.\\n\\t */\\n\\tfunction claimProjectTokens(uint256 projectId) external {\\n\\t\\taddress depositor = msg.sender;\\n\\n\\t\\t// Retrieve the project and deposit amount\\n\\t\\t(ProjectStorage.Data memory project, uint256 depositAmount) = projects\\n\\t\\t\\t.takeDeposit(usersProjectDeposit[projectId], projectId, depositor);\\n\\n\\t\\tHousingSFT(project.tokenAddress).mintSFT(\\n\\t\\t\\tdepositAmount,\\n\\t\\t\\tdepositor,\\n\\t\\t\\tproject.collectedFunds\\n\\t\\t);\\n\\n\\t\\t// Mint LkSHT tokens if the project ID is 1\\n\\t\\tif (project.id == 1) {\\n\\t\\t\\tuint256 shtAmount = depositAmount.mul(SHT.ICO_FUNDS).div(\\n\\t\\t\\t\\tproject.collectedFunds\\n\\t\\t\\t);\\n\\n\\t\\t\\tlkSht.mint(shtAmount, depositor);\\n\\t\\t}\\n\\n\\t\\temit ProjectTokensClaimed(depositor, projectId, depositAmount);\\n\\t}\\n\\n\\tfunction unlockSHT(uint256 nonce) external {\\n\\t\\taddress caller = msg.sender;\\n\\n\\t\\tuint256 lkShtBal = lkSht.balanceOf(caller, nonce);\\n\\t\\trequire(lkShtBal > 0, \\\"ProjectFunding: Nothing to unlock\\\");\\n\\n\\t\\tLkSHTAttributes.Attributes memory attr = abi.decode(\\n\\t\\t\\tlkSht.getRawTokenAttributes(nonce),\\n\\t\\t\\t(LkSHTAttributes.Attributes)\\n\\t\\t);\\n\\t\\t(\\n\\t\\t\\tuint256 totalUnlockedAmount,\\n\\t\\t\\tLkSHTAttributes.Attributes memory newAttr\\n\\t\\t) = attr.unlockMatured();\\n\\n\\t\\tlkSht.update(\\n\\t\\t\\tcaller,\\n\\t\\t\\tnonce,\\n\\t\\t\\tlkShtBal.sub(totalUnlockedAmount),\\n\\t\\t\\tabi.encode(newAttr)\\n\\t\\t);\\n\\n\\t\\t// Transfer the total unlocked SHT tokens to the user's address\\n\\t\\tif (totalUnlockedAmount > 0) {\\n\\t\\t\\thousingToken.transfer(caller, totalUnlockedAmount);\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns an array of all project IDs and their associated data.\\n\\t * @return projectList An array of tuples containing project details.\\n\\t */\\n\\tfunction allProjects() public view returns (ProjectStorage.Data[] memory) {\\n\\t\\tProjectStorage.Data[] memory projectList = new ProjectStorage.Data[](\\n\\t\\t\\tprojectCount\\n\\t\\t);\\n\\n\\t\\tfor (uint256 i = 1; i <= projectCount; i++) {\\n\\t\\t\\tprojectList[i - 1] = projects[i];\\n\\t\\t}\\n\\n\\t\\treturn projectList;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns the address of the HousingProject contract for a given project ID.\\n\\t * @param projectId The ID of the project.\\n\\t * @return projectAddress The address of the HousingProject contract.\\n\\t */\\n\\tfunction getProjectAddress(\\n\\t\\tuint256 projectId\\n\\t) external view returns (address projectAddress) {\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\treturn project.projectAddress;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Returns the details of a project by its ID.\\n\\t * @param projectId The ID of the project.\\n\\t * @return id The project ID.\\n\\t * @return fundingGoal The funding goal of the project.\\n\\t * @return fundingDeadline The deadline for the project funding.\\n\\t * @return fundingToken The address of the ERC20 token used for funding.\\n\\t * @return projectAddress The address of the HousingProject contract.\\n\\t * @return status The funding status of the project.\\n\\t * @return collectedFunds The amount of funds collected.\\n\\t */\\n\\tfunction getProjectData(\\n\\t\\tuint256 projectId\\n\\t)\\n\\t\\texternal\\n\\t\\tview\\n\\t\\treturns (\\n\\t\\t\\tuint256 id,\\n\\t\\t\\tuint256 fundingGoal,\\n\\t\\t\\tuint256 fundingDeadline,\\n\\t\\t\\taddress fundingToken,\\n\\t\\t\\taddress projectAddress,\\n\\t\\t\\tuint8 status,\\n\\t\\t\\tuint256 collectedFunds\\n\\t\\t)\\n\\t{\\n\\t\\tProjectStorage.Data storage project = projects[projectId];\\n\\t\\treturn (\\n\\t\\t\\tproject.id,\\n\\t\\t\\tproject.fundingGoal,\\n\\t\\t\\tproject.fundingDeadline,\\n\\t\\t\\tproject.fundingToken,\\n\\t\\t\\tproject.projectAddress,\\n\\t\\t\\tuint8(project.status()),\\n\\t\\t\\tproject.collectedFunds\\n\\t\\t);\\n\\t}\\n}\\n\",\"keccak256\":\"0xba3518a6288e777e4b2b51d944cbc298200458d0f09f3c5b701f52547991a4e1\",\"license\":\"MIT\"},\"prb-math/contracts/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\\n\\n/// @notice Emitted when one of the inputs is type(int256).min.\\nerror PRBMath__MulDivSignedInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows int256.\\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is MIN_SD59x18.\\nerror PRBMathSD59x18__AbsInputTooSmall();\\n\\n/// @notice Emitted when ceiling a number overflows SD59x18.\\nerror PRBMathSD59x18__CeilOverflow(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__DivInputTooSmall();\\n\\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\\n\\n/// @notice Emitted when flooring a number underflows SD59x18.\\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\\n\\n/// @notice Emitted when the product of the inputs is negative.\\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\\n\\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\\n\\n/// @notice Emitted when the input is less than or equal to zero.\\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__MulInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is negative.\\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows SD59x18.\\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\\n\\n/// @notice Emitted when addition overflows UD60x18.\\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when ceiling a number overflows UD60x18.\\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\\n\\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when the input is less than 1.\\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows UD60x18.\\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\\n\\n/// @notice Emitted when subtraction underflows UD60x18.\\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\\n\\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\\nlibrary PRBMath {\\n /// STRUCTS ///\\n\\n struct SD59x18 {\\n int256 value;\\n }\\n\\n struct UD60x18 {\\n uint256 value;\\n }\\n\\n /// STORAGE ///\\n\\n /// @dev How many trailing decimals can be represented.\\n uint256 internal constant SCALE = 1e18;\\n\\n /// @dev Largest power of two divisor of SCALE.\\n uint256 internal constant SCALE_LPOTD = 262144;\\n\\n /// @dev SCALE inverted mod 2^256.\\n uint256 internal constant SCALE_INVERSE =\\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\\n\\n /// FUNCTIONS ///\\n\\n /// @notice Calculates the binary exponent of x using the binary fraction method.\\n /// @dev Has to use 192.64-bit fixed-point numbers.\\n /// See https://ethereum.stackexchange.com/a/96594/24693.\\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function exp2(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n // Start from 0.5 in the 192.64-bit fixed-point format.\\n result = 0x800000000000000000000000000000000000000000000000;\\n\\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\\n // because the initial result is 2^191 and all magic factors are less than 2^65.\\n if (x & 0x8000000000000000 > 0) {\\n result = (result * 0x16A09E667F3BCC909) >> 64;\\n }\\n if (x & 0x4000000000000000 > 0) {\\n result = (result * 0x1306FE0A31B7152DF) >> 64;\\n }\\n if (x & 0x2000000000000000 > 0) {\\n result = (result * 0x1172B83C7D517ADCE) >> 64;\\n }\\n if (x & 0x1000000000000000 > 0) {\\n result = (result * 0x10B5586CF9890F62A) >> 64;\\n }\\n if (x & 0x800000000000000 > 0) {\\n result = (result * 0x1059B0D31585743AE) >> 64;\\n }\\n if (x & 0x400000000000000 > 0) {\\n result = (result * 0x102C9A3E778060EE7) >> 64;\\n }\\n if (x & 0x200000000000000 > 0) {\\n result = (result * 0x10163DA9FB33356D8) >> 64;\\n }\\n if (x & 0x100000000000000 > 0) {\\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\\n }\\n if (x & 0x80000000000000 > 0) {\\n result = (result * 0x10058C86DA1C09EA2) >> 64;\\n }\\n if (x & 0x40000000000000 > 0) {\\n result = (result * 0x1002C605E2E8CEC50) >> 64;\\n }\\n if (x & 0x20000000000000 > 0) {\\n result = (result * 0x100162F3904051FA1) >> 64;\\n }\\n if (x & 0x10000000000000 > 0) {\\n result = (result * 0x1000B175EFFDC76BA) >> 64;\\n }\\n if (x & 0x8000000000000 > 0) {\\n result = (result * 0x100058BA01FB9F96D) >> 64;\\n }\\n if (x & 0x4000000000000 > 0) {\\n result = (result * 0x10002C5CC37DA9492) >> 64;\\n }\\n if (x & 0x2000000000000 > 0) {\\n result = (result * 0x1000162E525EE0547) >> 64;\\n }\\n if (x & 0x1000000000000 > 0) {\\n result = (result * 0x10000B17255775C04) >> 64;\\n }\\n if (x & 0x800000000000 > 0) {\\n result = (result * 0x1000058B91B5BC9AE) >> 64;\\n }\\n if (x & 0x400000000000 > 0) {\\n result = (result * 0x100002C5C89D5EC6D) >> 64;\\n }\\n if (x & 0x200000000000 > 0) {\\n result = (result * 0x10000162E43F4F831) >> 64;\\n }\\n if (x & 0x100000000000 > 0) {\\n result = (result * 0x100000B1721BCFC9A) >> 64;\\n }\\n if (x & 0x80000000000 > 0) {\\n result = (result * 0x10000058B90CF1E6E) >> 64;\\n }\\n if (x & 0x40000000000 > 0) {\\n result = (result * 0x1000002C5C863B73F) >> 64;\\n }\\n if (x & 0x20000000000 > 0) {\\n result = (result * 0x100000162E430E5A2) >> 64;\\n }\\n if (x & 0x10000000000 > 0) {\\n result = (result * 0x1000000B172183551) >> 64;\\n }\\n if (x & 0x8000000000 > 0) {\\n result = (result * 0x100000058B90C0B49) >> 64;\\n }\\n if (x & 0x4000000000 > 0) {\\n result = (result * 0x10000002C5C8601CC) >> 64;\\n }\\n if (x & 0x2000000000 > 0) {\\n result = (result * 0x1000000162E42FFF0) >> 64;\\n }\\n if (x & 0x1000000000 > 0) {\\n result = (result * 0x10000000B17217FBB) >> 64;\\n }\\n if (x & 0x800000000 > 0) {\\n result = (result * 0x1000000058B90BFCE) >> 64;\\n }\\n if (x & 0x400000000 > 0) {\\n result = (result * 0x100000002C5C85FE3) >> 64;\\n }\\n if (x & 0x200000000 > 0) {\\n result = (result * 0x10000000162E42FF1) >> 64;\\n }\\n if (x & 0x100000000 > 0) {\\n result = (result * 0x100000000B17217F8) >> 64;\\n }\\n if (x & 0x80000000 > 0) {\\n result = (result * 0x10000000058B90BFC) >> 64;\\n }\\n if (x & 0x40000000 > 0) {\\n result = (result * 0x1000000002C5C85FE) >> 64;\\n }\\n if (x & 0x20000000 > 0) {\\n result = (result * 0x100000000162E42FF) >> 64;\\n }\\n if (x & 0x10000000 > 0) {\\n result = (result * 0x1000000000B17217F) >> 64;\\n }\\n if (x & 0x8000000 > 0) {\\n result = (result * 0x100000000058B90C0) >> 64;\\n }\\n if (x & 0x4000000 > 0) {\\n result = (result * 0x10000000002C5C860) >> 64;\\n }\\n if (x & 0x2000000 > 0) {\\n result = (result * 0x1000000000162E430) >> 64;\\n }\\n if (x & 0x1000000 > 0) {\\n result = (result * 0x10000000000B17218) >> 64;\\n }\\n if (x & 0x800000 > 0) {\\n result = (result * 0x1000000000058B90C) >> 64;\\n }\\n if (x & 0x400000 > 0) {\\n result = (result * 0x100000000002C5C86) >> 64;\\n }\\n if (x & 0x200000 > 0) {\\n result = (result * 0x10000000000162E43) >> 64;\\n }\\n if (x & 0x100000 > 0) {\\n result = (result * 0x100000000000B1721) >> 64;\\n }\\n if (x & 0x80000 > 0) {\\n result = (result * 0x10000000000058B91) >> 64;\\n }\\n if (x & 0x40000 > 0) {\\n result = (result * 0x1000000000002C5C8) >> 64;\\n }\\n if (x & 0x20000 > 0) {\\n result = (result * 0x100000000000162E4) >> 64;\\n }\\n if (x & 0x10000 > 0) {\\n result = (result * 0x1000000000000B172) >> 64;\\n }\\n if (x & 0x8000 > 0) {\\n result = (result * 0x100000000000058B9) >> 64;\\n }\\n if (x & 0x4000 > 0) {\\n result = (result * 0x10000000000002C5D) >> 64;\\n }\\n if (x & 0x2000 > 0) {\\n result = (result * 0x1000000000000162E) >> 64;\\n }\\n if (x & 0x1000 > 0) {\\n result = (result * 0x10000000000000B17) >> 64;\\n }\\n if (x & 0x800 > 0) {\\n result = (result * 0x1000000000000058C) >> 64;\\n }\\n if (x & 0x400 > 0) {\\n result = (result * 0x100000000000002C6) >> 64;\\n }\\n if (x & 0x200 > 0) {\\n result = (result * 0x10000000000000163) >> 64;\\n }\\n if (x & 0x100 > 0) {\\n result = (result * 0x100000000000000B1) >> 64;\\n }\\n if (x & 0x80 > 0) {\\n result = (result * 0x10000000000000059) >> 64;\\n }\\n if (x & 0x40 > 0) {\\n result = (result * 0x1000000000000002C) >> 64;\\n }\\n if (x & 0x20 > 0) {\\n result = (result * 0x10000000000000016) >> 64;\\n }\\n if (x & 0x10 > 0) {\\n result = (result * 0x1000000000000000B) >> 64;\\n }\\n if (x & 0x8 > 0) {\\n result = (result * 0x10000000000000006) >> 64;\\n }\\n if (x & 0x4 > 0) {\\n result = (result * 0x10000000000000003) >> 64;\\n }\\n if (x & 0x2 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n if (x & 0x1 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n\\n // We're doing two things at the same time:\\n //\\n // 1. Multiply the result by 2^n + 1, where \\\"2^n\\\" is the integer part and the one is added to account for\\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\\n // rather than 192.\\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\\n //\\n // This works because 2^(191-ip) = 2^ip / 2^191, where \\\"ip\\\" is the integer part \\\"2^n\\\".\\n result *= SCALE;\\n result >>= (191 - (x >> 64));\\n }\\n }\\n\\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\\n /// @dev See the note on msb in the \\\"Find First Set\\\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\\n /// @param x The uint256 number for which to find the index of the most significant bit.\\n /// @return msb The index of the most significant bit as an uint256.\\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\\n if (x >= 2**128) {\\n x >>= 128;\\n msb += 128;\\n }\\n if (x >= 2**64) {\\n x >>= 64;\\n msb += 64;\\n }\\n if (x >= 2**32) {\\n x >>= 32;\\n msb += 32;\\n }\\n if (x >= 2**16) {\\n x >>= 16;\\n msb += 16;\\n }\\n if (x >= 2**8) {\\n x >>= 8;\\n msb += 8;\\n }\\n if (x >= 2**4) {\\n x >>= 4;\\n msb += 4;\\n }\\n if (x >= 2**2) {\\n x >>= 2;\\n msb += 2;\\n }\\n if (x >= 2**1) {\\n // No need to shift x any more.\\n msb += 1;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\\n ///\\n /// Requirements:\\n /// - The denominator cannot be zero.\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The multiplicand as an uint256.\\n /// @param y The multiplier as an uint256.\\n /// @param denominator The divisor as an uint256.\\n /// @return result The result as an uint256.\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n unchecked {\\n result = prod0 / denominator;\\n }\\n return result;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n if (prod1 >= denominator) {\\n revert PRBMath__MulDivOverflow(prod1, denominator);\\n }\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n unchecked {\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 lpotdod = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by lpotdod.\\n denominator := div(denominator, lpotdod)\\n\\n // Divide [prod1 prod0] by lpotdod.\\n prod0 := div(prod0, lpotdod)\\n\\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * lpotdod;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f71e18) with full precision.\\n ///\\n /// @dev Variant of \\\"mulDiv\\\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\\n /// being rounded to 1e-18. See \\\"Listing 6\\\" and text above it at https://accu.org/index.php/journals/1717.\\n ///\\n /// Requirements:\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - The body is purposely left uncommented; see the NatSpec comments in \\\"PRBMath.mulDiv\\\" to understand how this works.\\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\\n /// 1. x * y = type(uint256).max * SCALE\\n /// 2. (x * y) % SCALE >= SCALE / 2\\n ///\\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n uint256 prod0;\\n uint256 prod1;\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n if (prod1 >= SCALE) {\\n revert PRBMath__MulDivFixedPointOverflow(prod1);\\n }\\n\\n uint256 remainder;\\n uint256 roundUpUnit;\\n assembly {\\n remainder := mulmod(x, y, SCALE)\\n roundUpUnit := gt(remainder, 499999999999999999)\\n }\\n\\n if (prod1 == 0) {\\n unchecked {\\n result = (prod0 / SCALE) + roundUpUnit;\\n return result;\\n }\\n }\\n\\n assembly {\\n result := add(\\n mul(\\n or(\\n div(sub(prod0, remainder), SCALE_LPOTD),\\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\\n ),\\n SCALE_INVERSE\\n ),\\n roundUpUnit\\n )\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev An extension of \\\"mulDiv\\\" for signed numbers. Works by computing the signs and the absolute values separately.\\n ///\\n /// Requirements:\\n /// - None of the inputs can be type(int256).min.\\n /// - The result must fit within int256.\\n ///\\n /// @param x The multiplicand as an int256.\\n /// @param y The multiplier as an int256.\\n /// @param denominator The divisor as an int256.\\n /// @return result The result as an int256.\\n function mulDivSigned(\\n int256 x,\\n int256 y,\\n int256 denominator\\n ) internal pure returns (int256 result) {\\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\\n revert PRBMath__MulDivSignedInputTooSmall();\\n }\\n\\n // Get hold of the absolute values of x, y and the denominator.\\n uint256 ax;\\n uint256 ay;\\n uint256 ad;\\n unchecked {\\n ax = x < 0 ? uint256(-x) : uint256(x);\\n ay = y < 0 ? uint256(-y) : uint256(y);\\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\\n }\\n\\n // Compute the absolute value of (x*y)\\u00f7denominator. The result must fit within int256.\\n uint256 rAbs = mulDiv(ax, ay, ad);\\n if (rAbs > uint256(type(int256).max)) {\\n revert PRBMath__MulDivSignedOverflow(rAbs);\\n }\\n\\n // Get the signs of x, y and the denominator.\\n uint256 sx;\\n uint256 sy;\\n uint256 sd;\\n assembly {\\n sx := sgt(x, sub(0, 1))\\n sy := sgt(y, sub(0, 1))\\n sd := sgt(denominator, sub(0, 1))\\n }\\n\\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\\n // If yes, the result should be negative.\\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\\n }\\n\\n /// @notice Calculates the square root of x, rounding down.\\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The uint256 number for which to calculate the square root.\\n /// @return result The result as an uint256.\\n function sqrt(uint256 x) internal pure returns (uint256 result) {\\n if (x == 0) {\\n return 0;\\n }\\n\\n // Set the initial guess to the least power of two that is greater than or equal to sqrt(x).\\n uint256 xAux = uint256(x);\\n result = 1;\\n if (xAux >= 0x100000000000000000000000000000000) {\\n xAux >>= 128;\\n result <<= 64;\\n }\\n if (xAux >= 0x10000000000000000) {\\n xAux >>= 64;\\n result <<= 32;\\n }\\n if (xAux >= 0x100000000) {\\n xAux >>= 32;\\n result <<= 16;\\n }\\n if (xAux >= 0x10000) {\\n xAux >>= 16;\\n result <<= 8;\\n }\\n if (xAux >= 0x100) {\\n xAux >>= 8;\\n result <<= 4;\\n }\\n if (xAux >= 0x10) {\\n xAux >>= 4;\\n result <<= 2;\\n }\\n if (xAux >= 0x8) {\\n result <<= 1;\\n }\\n\\n // The operations can never overflow because the result is max 2^127 when it enters this block.\\n unchecked {\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1; // Seven iterations should be enough\\n uint256 roundedDownResult = x / result;\\n return result >= roundedDownResult ? roundedDownResult : result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0xed164c95012964f5e125b5d2b2d00471a4bdee4def618cd1fcf341d196011b61\",\"license\":\"Unlicense\"},\"prb-math/contracts/PRBMathUD60x18.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\nimport \\\"./PRBMath.sol\\\";\\n\\n/// @title PRBMathUD60x18\\n/// @author Paul Razvan Berg\\n/// @notice Smart contract library for advanced fixed-point math that works with uint256 numbers considered to have 18\\n/// trailing decimals. We call this number representation unsigned 60.18-decimal fixed-point, since there can be up to 60\\n/// digits in the integer part and up to 18 decimals in the fractional part. The numbers are bound by the minimum and the\\n/// maximum values permitted by the Solidity type uint256.\\nlibrary PRBMathUD60x18 {\\n /// @dev Half the SCALE number.\\n uint256 internal constant HALF_SCALE = 5e17;\\n\\n /// @dev log2(e) as an unsigned 60.18-decimal fixed-point number.\\n uint256 internal constant LOG2_E = 1_442695040888963407;\\n\\n /// @dev The maximum value an unsigned 60.18-decimal fixed-point number can have.\\n uint256 internal constant MAX_UD60x18 =\\n 115792089237316195423570985008687907853269984665640564039457_584007913129639935;\\n\\n /// @dev The maximum whole value an unsigned 60.18-decimal fixed-point number can have.\\n uint256 internal constant MAX_WHOLE_UD60x18 =\\n 115792089237316195423570985008687907853269984665640564039457_000000000000000000;\\n\\n /// @dev How many trailing decimals can be represented.\\n uint256 internal constant SCALE = 1e18;\\n\\n /// @notice Calculates the arithmetic average of x and y, rounding down.\\n /// @param x The first operand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The second operand as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The arithmetic average as an unsigned 60.18-decimal fixed-point number.\\n function avg(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n // The operations can never overflow.\\n unchecked {\\n // The last operand checks if both x and y are odd and if that is the case, we add 1 to the result. We need\\n // to do this because if both numbers are odd, the 0.5 remainder gets truncated twice.\\n result = (x >> 1) + (y >> 1) + (x & y & 1);\\n }\\n }\\n\\n /// @notice Yields the least unsigned 60.18 decimal fixed-point number greater than or equal to x.\\n ///\\n /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.\\n /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.\\n ///\\n /// Requirements:\\n /// - x must be less than or equal to MAX_WHOLE_UD60x18.\\n ///\\n /// @param x The unsigned 60.18-decimal fixed-point number to ceil.\\n /// @param result The least integer greater than or equal to x, as an unsigned 60.18-decimal fixed-point number.\\n function ceil(uint256 x) internal pure returns (uint256 result) {\\n if (x > MAX_WHOLE_UD60x18) {\\n revert PRBMathUD60x18__CeilOverflow(x);\\n }\\n assembly {\\n // Equivalent to \\\"x % SCALE\\\" but faster.\\n let remainder := mod(x, SCALE)\\n\\n // Equivalent to \\\"SCALE - remainder\\\" but faster.\\n let delta := sub(SCALE, remainder)\\n\\n // Equivalent to \\\"x + delta * (remainder > 0 ? 1 : 0)\\\" but faster.\\n result := add(x, mul(delta, gt(remainder, 0)))\\n }\\n }\\n\\n /// @notice Divides two unsigned 60.18-decimal fixed-point numbers, returning a new unsigned 60.18-decimal fixed-point number.\\n ///\\n /// @dev Uses mulDiv to enable overflow-safe multiplication and division.\\n ///\\n /// Requirements:\\n /// - The denominator cannot be zero.\\n ///\\n /// @param x The numerator as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The denominator as an unsigned 60.18-decimal fixed-point number.\\n /// @param result The quotient as an unsigned 60.18-decimal fixed-point number.\\n function div(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n result = PRBMath.mulDiv(x, SCALE, y);\\n }\\n\\n /// @notice Returns Euler's number as an unsigned 60.18-decimal fixed-point number.\\n /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant).\\n function e() internal pure returns (uint256 result) {\\n result = 2_718281828459045235;\\n }\\n\\n /// @notice Calculates the natural exponent of x.\\n ///\\n /// @dev Based on the insight that e^x = 2^(x * log2(e)).\\n ///\\n /// Requirements:\\n /// - All from \\\"log2\\\".\\n /// - x must be less than 133.084258667509499441.\\n ///\\n /// @param x The exponent as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function exp(uint256 x) internal pure returns (uint256 result) {\\n // Without this check, the value passed to \\\"exp2\\\" would be greater than 192.\\n if (x >= 133_084258667509499441) {\\n revert PRBMathUD60x18__ExpInputTooBig(x);\\n }\\n\\n // Do the fixed-point multiplication inline to save gas.\\n unchecked {\\n uint256 doubleScaleProduct = x * LOG2_E;\\n result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE);\\n }\\n }\\n\\n /// @notice Calculates the binary exponent of x using the binary fraction method.\\n ///\\n /// @dev See https://ethereum.stackexchange.com/q/79903/24693.\\n ///\\n /// Requirements:\\n /// - x must be 192 or less.\\n /// - The result must fit within MAX_UD60x18.\\n ///\\n /// @param x The exponent as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function exp2(uint256 x) internal pure returns (uint256 result) {\\n // 2^192 doesn't fit within the 192.64-bit format used internally in this function.\\n if (x >= 192e18) {\\n revert PRBMathUD60x18__Exp2InputTooBig(x);\\n }\\n\\n unchecked {\\n // Convert x to the 192.64-bit fixed-point format.\\n uint256 x192x64 = (x << 64) / SCALE;\\n\\n // Pass x to the PRBMath.exp2 function, which uses the 192.64-bit fixed-point number representation.\\n result = PRBMath.exp2(x192x64);\\n }\\n }\\n\\n /// @notice Yields the greatest unsigned 60.18 decimal fixed-point number less than or equal to x.\\n /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.\\n /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.\\n /// @param x The unsigned 60.18-decimal fixed-point number to floor.\\n /// @param result The greatest integer less than or equal to x, as an unsigned 60.18-decimal fixed-point number.\\n function floor(uint256 x) internal pure returns (uint256 result) {\\n assembly {\\n // Equivalent to \\\"x % SCALE\\\" but faster.\\n let remainder := mod(x, SCALE)\\n\\n // Equivalent to \\\"x - remainder * (remainder > 0 ? 1 : 0)\\\" but faster.\\n result := sub(x, mul(remainder, gt(remainder, 0)))\\n }\\n }\\n\\n /// @notice Yields the excess beyond the floor of x.\\n /// @dev Based on the odd function definition https://en.wikipedia.org/wiki/Fractional_part.\\n /// @param x The unsigned 60.18-decimal fixed-point number to get the fractional part of.\\n /// @param result The fractional part of x as an unsigned 60.18-decimal fixed-point number.\\n function frac(uint256 x) internal pure returns (uint256 result) {\\n assembly {\\n result := mod(x, SCALE)\\n }\\n }\\n\\n /// @notice Converts a number from basic integer form to unsigned 60.18-decimal fixed-point representation.\\n ///\\n /// @dev Requirements:\\n /// - x must be less than or equal to MAX_UD60x18 divided by SCALE.\\n ///\\n /// @param x The basic integer to convert.\\n /// @param result The same number in unsigned 60.18-decimal fixed-point representation.\\n function fromUint(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n if (x > MAX_UD60x18 / SCALE) {\\n revert PRBMathUD60x18__FromUintOverflow(x);\\n }\\n result = x * SCALE;\\n }\\n }\\n\\n /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down.\\n ///\\n /// @dev Requirements:\\n /// - x * y must fit within MAX_UD60x18, lest it overflows.\\n ///\\n /// @param x The first operand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The second operand as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function gm(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n if (x == 0) {\\n return 0;\\n }\\n\\n unchecked {\\n // Checking for overflow this way is faster than letting Solidity do it.\\n uint256 xy = x * y;\\n if (xy / x != y) {\\n revert PRBMathUD60x18__GmOverflow(x, y);\\n }\\n\\n // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE\\n // during multiplication. See the comments within the \\\"sqrt\\\" function.\\n result = PRBMath.sqrt(xy);\\n }\\n }\\n\\n /// @notice Calculates 1 / x, rounding toward zero.\\n ///\\n /// @dev Requirements:\\n /// - x cannot be zero.\\n ///\\n /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the inverse.\\n /// @return result The inverse as an unsigned 60.18-decimal fixed-point number.\\n function inv(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n // 1e36 is SCALE * SCALE.\\n result = 1e36 / x;\\n }\\n }\\n\\n /// @notice Calculates the natural logarithm of x.\\n ///\\n /// @dev Based on the insight that ln(x) = log2(x) / log2(e).\\n ///\\n /// Requirements:\\n /// - All from \\\"log2\\\".\\n ///\\n /// Caveats:\\n /// - All from \\\"log2\\\".\\n /// - This doesn't return exactly 1 for 2.718281828459045235, for that we would need more fine-grained precision.\\n ///\\n /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the natural logarithm.\\n /// @return result The natural logarithm as an unsigned 60.18-decimal fixed-point number.\\n function ln(uint256 x) internal pure returns (uint256 result) {\\n // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x)\\n // can return is 196205294292027477728.\\n unchecked {\\n result = (log2(x) * SCALE) / LOG2_E;\\n }\\n }\\n\\n /// @notice Calculates the common logarithm of x.\\n ///\\n /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common\\n /// logarithm based on the insight that log10(x) = log2(x) / log2(10).\\n ///\\n /// Requirements:\\n /// - All from \\\"log2\\\".\\n ///\\n /// Caveats:\\n /// - All from \\\"log2\\\".\\n ///\\n /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the common logarithm.\\n /// @return result The common logarithm as an unsigned 60.18-decimal fixed-point number.\\n function log10(uint256 x) internal pure returns (uint256 result) {\\n if (x < SCALE) {\\n revert PRBMathUD60x18__LogInputTooSmall(x);\\n }\\n\\n // Note that the \\\"mul\\\" in this block is the assembly multiplication operation, not the \\\"mul\\\" function defined\\n // in this contract.\\n // prettier-ignore\\n assembly {\\n switch x\\n case 1 { result := mul(SCALE, sub(0, 18)) }\\n case 10 { result := mul(SCALE, sub(1, 18)) }\\n case 100 { result := mul(SCALE, sub(2, 18)) }\\n case 1000 { result := mul(SCALE, sub(3, 18)) }\\n case 10000 { result := mul(SCALE, sub(4, 18)) }\\n case 100000 { result := mul(SCALE, sub(5, 18)) }\\n case 1000000 { result := mul(SCALE, sub(6, 18)) }\\n case 10000000 { result := mul(SCALE, sub(7, 18)) }\\n case 100000000 { result := mul(SCALE, sub(8, 18)) }\\n case 1000000000 { result := mul(SCALE, sub(9, 18)) }\\n case 10000000000 { result := mul(SCALE, sub(10, 18)) }\\n case 100000000000 { result := mul(SCALE, sub(11, 18)) }\\n case 1000000000000 { result := mul(SCALE, sub(12, 18)) }\\n case 10000000000000 { result := mul(SCALE, sub(13, 18)) }\\n case 100000000000000 { result := mul(SCALE, sub(14, 18)) }\\n case 1000000000000000 { result := mul(SCALE, sub(15, 18)) }\\n case 10000000000000000 { result := mul(SCALE, sub(16, 18)) }\\n case 100000000000000000 { result := mul(SCALE, sub(17, 18)) }\\n case 1000000000000000000 { result := 0 }\\n case 10000000000000000000 { result := SCALE }\\n case 100000000000000000000 { result := mul(SCALE, 2) }\\n case 1000000000000000000000 { result := mul(SCALE, 3) }\\n case 10000000000000000000000 { result := mul(SCALE, 4) }\\n case 100000000000000000000000 { result := mul(SCALE, 5) }\\n case 1000000000000000000000000 { result := mul(SCALE, 6) }\\n case 10000000000000000000000000 { result := mul(SCALE, 7) }\\n case 100000000000000000000000000 { result := mul(SCALE, 8) }\\n case 1000000000000000000000000000 { result := mul(SCALE, 9) }\\n case 10000000000000000000000000000 { result := mul(SCALE, 10) }\\n case 100000000000000000000000000000 { result := mul(SCALE, 11) }\\n case 1000000000000000000000000000000 { result := mul(SCALE, 12) }\\n case 10000000000000000000000000000000 { result := mul(SCALE, 13) }\\n case 100000000000000000000000000000000 { result := mul(SCALE, 14) }\\n case 1000000000000000000000000000000000 { result := mul(SCALE, 15) }\\n case 10000000000000000000000000000000000 { result := mul(SCALE, 16) }\\n case 100000000000000000000000000000000000 { result := mul(SCALE, 17) }\\n case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) }\\n case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) }\\n case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) }\\n case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) }\\n case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) }\\n case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) }\\n case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) }\\n case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) }\\n case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) }\\n case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) }\\n case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) }\\n case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) }\\n case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) }\\n case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) }\\n case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) }\\n case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) }\\n case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) }\\n case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) }\\n case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) }\\n case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) }\\n case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) }\\n case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) }\\n case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) }\\n case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) }\\n case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) }\\n case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) }\\n case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) }\\n case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) }\\n case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) }\\n case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) }\\n case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) }\\n case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) }\\n case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) }\\n case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) }\\n case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) }\\n case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) }\\n case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) }\\n case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) }\\n case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) }\\n case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) }\\n case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) }\\n case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 59) }\\n default {\\n result := MAX_UD60x18\\n }\\n }\\n\\n if (result == MAX_UD60x18) {\\n // Do the fixed-point division inline to save gas. The denominator is log2(10).\\n unchecked {\\n result = (log2(x) * SCALE) / 3_321928094887362347;\\n }\\n }\\n }\\n\\n /// @notice Calculates the binary logarithm of x.\\n ///\\n /// @dev Based on the iterative approximation algorithm.\\n /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation\\n ///\\n /// Requirements:\\n /// - x must be greater than or equal to SCALE, otherwise the result would be negative.\\n ///\\n /// Caveats:\\n /// - The results are nor perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation.\\n ///\\n /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the binary logarithm.\\n /// @return result The binary logarithm as an unsigned 60.18-decimal fixed-point number.\\n function log2(uint256 x) internal pure returns (uint256 result) {\\n if (x < SCALE) {\\n revert PRBMathUD60x18__LogInputTooSmall(x);\\n }\\n unchecked {\\n // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).\\n uint256 n = PRBMath.mostSignificantBit(x / SCALE);\\n\\n // The integer part of the logarithm as an unsigned 60.18-decimal fixed-point number. The operation can't overflow\\n // because n is maximum 255 and SCALE is 1e18.\\n result = n * SCALE;\\n\\n // This is y = x * 2^(-n).\\n uint256 y = x >> n;\\n\\n // If y = 1, the fractional part is zero.\\n if (y == SCALE) {\\n return result;\\n }\\n\\n // Calculate the fractional part via the iterative approximation.\\n // The \\\"delta >>= 1\\\" part is equivalent to \\\"delta /= 2\\\", but shifting bits is faster.\\n for (uint256 delta = HALF_SCALE; delta > 0; delta >>= 1) {\\n y = (y * y) / SCALE;\\n\\n // Is y^2 > 2 and so in the range [2,4)?\\n if (y >= 2 * SCALE) {\\n // Add the 2^(-m) factor to the logarithm.\\n result += delta;\\n\\n // Corresponds to z/2 on Wikipedia.\\n y >>= 1;\\n }\\n }\\n }\\n }\\n\\n /// @notice Multiplies two unsigned 60.18-decimal fixed-point numbers together, returning a new unsigned 60.18-decimal\\n /// fixed-point number.\\n /// @dev See the documentation for the \\\"PRBMath.mulDivFixedPoint\\\" function.\\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The product as an unsigned 60.18-decimal fixed-point number.\\n function mul(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n result = PRBMath.mulDivFixedPoint(x, y);\\n }\\n\\n /// @notice Returns PI as an unsigned 60.18-decimal fixed-point number.\\n function pi() internal pure returns (uint256 result) {\\n result = 3_141592653589793238;\\n }\\n\\n /// @notice Raises x to the power of y.\\n ///\\n /// @dev Based on the insight that x^y = 2^(log2(x) * y).\\n ///\\n /// Requirements:\\n /// - All from \\\"exp2\\\", \\\"log2\\\" and \\\"mul\\\".\\n ///\\n /// Caveats:\\n /// - All from \\\"exp2\\\", \\\"log2\\\" and \\\"mul\\\".\\n /// - Assumes 0^0 is 1.\\n ///\\n /// @param x Number to raise to given power y, as an unsigned 60.18-decimal fixed-point number.\\n /// @param y Exponent to raise x to, as an unsigned 60.18-decimal fixed-point number.\\n /// @return result x raised to power y, as an unsigned 60.18-decimal fixed-point number.\\n function pow(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n if (x == 0) {\\n result = y == 0 ? SCALE : uint256(0);\\n } else {\\n result = exp2(mul(log2(x), y));\\n }\\n }\\n\\n /// @notice Raises x (unsigned 60.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the\\n /// famous algorithm \\\"exponentiation by squaring\\\".\\n ///\\n /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring\\n ///\\n /// Requirements:\\n /// - The result must fit within MAX_UD60x18.\\n ///\\n /// Caveats:\\n /// - All from \\\"mul\\\".\\n /// - Assumes 0^0 is 1.\\n ///\\n /// @param x The base as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The exponent as an uint256.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function powu(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n // Calculate the first iteration of the loop in advance.\\n result = y & 1 > 0 ? x : SCALE;\\n\\n // Equivalent to \\\"for(y /= 2; y > 0; y /= 2)\\\" but faster.\\n for (y >>= 1; y > 0; y >>= 1) {\\n x = PRBMath.mulDivFixedPoint(x, x);\\n\\n // Equivalent to \\\"y % 2 == 1\\\" but faster.\\n if (y & 1 > 0) {\\n result = PRBMath.mulDivFixedPoint(result, x);\\n }\\n }\\n }\\n\\n /// @notice Returns 1 as an unsigned 60.18-decimal fixed-point number.\\n function scale() internal pure returns (uint256 result) {\\n result = SCALE;\\n }\\n\\n /// @notice Calculates the square root of x, rounding down.\\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\\n ///\\n /// Requirements:\\n /// - x must be less than MAX_UD60x18 / SCALE.\\n ///\\n /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the square root.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point .\\n function sqrt(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n if (x > MAX_UD60x18 / SCALE) {\\n revert PRBMathUD60x18__SqrtOverflow(x);\\n }\\n // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two unsigned\\n // 60.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root).\\n result = PRBMath.sqrt(x * SCALE);\\n }\\n }\\n\\n /// @notice Converts a unsigned 60.18-decimal fixed-point number to basic integer form, rounding down in the process.\\n /// @param x The unsigned 60.18-decimal fixed-point number to convert.\\n /// @return result The same number in basic integer form.\\n function toUint(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n result = x / SCALE;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2180489de7680a79844dd5ef145f800e4f68e515e0e89409242f0187dbbd657b\",\"license\":\"Unlicense\"}},\"version\":1}", "bytecode": "0x6080604081815234620002e0578082620048bd803803809162000023828562000580565b833981010312620002e0576200004760206200003f84620005a4565b9301620005a4565b815192620000558462000564565b601584527f486f7573696e67205374616b696e6720546f6b656e000000000000000000000060208501528251936200008d8562000564565b60038552621214d560ea1b60208601528351602081019080821060018060401b03831117620003fd57600091865252600254600181811c9116801562000559575b6020821014620003dc57601f81116200050c575b5060006002556003543360018060a01b0319821617600355339060018060a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a38051906001600160401b038211620003fd5760085490600182811c9216801562000501575b6020831014620003dc5781601f8493116200049d575b50602090601f83116001146200041f5760009262000413575b50508160011b916000199060031b1c1916176008555b83516001600160401b038111620003fd57600954600181811c91168015620003f2575b6020821014620003dc57601f811162000372575b50602094601f82116001146200030557948192939495600092620002f9575b50508160011b916000199060031b1c1916176009555b600d80546001600160a01b039283166001600160a01b031991821617909155600c80549390921692169190911790558051633bf206a360e21b815260208160048173aCf3c12262CBD3e180C7A9F3BCBEA961D2b421985af4908115620002ee57600091620002a0575b50600f80546001600160a01b0319166001600160a01b0392909216919091179055426020556001602155516142e39081620005ba8239f35b90506020813d602011620002e5575b81620002be6020938362000580565b81010312620002e057516001600160a01b0381168103620002e0573862000268565b600080fd5b3d9150620002af565b82513d6000823e3d90fd5b015190503880620001e9565b601f19821695600960005260206000209160005b88811062000359575083600195969798106200033f575b505050811b01600955620001ff565b015160001960f88460031b161c1916905538808062000330565b9192602060018192868501518155019401920162000319565b60096000527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af601f830160051c81019160208410620003d1575b601f0160051c01905b818110620003c45750620001ca565b60008155600101620003b5565b9091508190620003ac565b634e487b7160e01b600052602260045260246000fd5b90607f1690620001b6565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017d565b6008600090815293506000805160206200489d83398151915291905b601f198416851062000481576001945083601f1981161062000467575b505050811b0160085562000193565b015160001960f88460031b161c1916905538808062000458565b818101518355602094850194600190930192909101906200043b565b60086000529091506000805160206200489d833981519152601f840160051c81019160208510620004f6575b90601f859493920160051c01905b818110620004e6575062000164565b60008155849350600101620004d7565b9091508190620004c9565b91607f16916200014e565b6002600052601f0160051c7f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace908101905b8181106200054c5750620000e2565b600081556001016200053d565b90607f1690620000ce565b604081019081106001600160401b03821117620003fd57604052565b601f909101601f19168101906001600160401b03821190821017620003fd57604052565b51906001600160a01b0382168203620002e05756fe6080604052600436101561001257600080fd5b6000803560e01c8062fdd58e146131ca57806301e882081461316f57806301ffc9a71461310057806306fdde03146130dc57806307973ccf146130be5780630e89341c14612fdc5780631958561214612ea757806325da499a14612e7e5780632b956ff714612e455780632eb2c2d614612b1d5780632fd2b55f1461287657806341a0894d146127055780634a9fefc7146126a15780634e1273f41461250c5780634fa3d25d146124b65780635124ae951461242f578063553c991214612406578063594dd43214611df9578063610bdf5d14611dd05780636addb66314611d77578063715018a614611d195780637c373a5014611c5c5780637c56b79814611c085780637c89f5df14611bd35780637d42082c14611b965780638b2ef8b114611b795780638da5cb5b14611b5057806395d89b4114611b11578063a22cb46514611a2d578063a476941c1461192b578063a87430ba146118c4578063af5ad2181461125a578063b169520114611227578063b81d481514611202578063c398bf3a146111da578063cbd91ab4146111be578063d73ca9d314610c0c578063d8938f26146106d0578063e985e9c51461067c578063f242432a14610352578063f2fde38b1461028c578063f7157af6146102205763fdc052a3146101f557600080fd5b3461021d578060031936011261021d57600e546040516001600160a01b039091168152602090f35b80fd5b503461021d57602036600319011261021d576040809161023e6131f2565b60006020845161024d81613277565b82815201526001600160a01b03168152601360205220815161026e81613277565b60206001835493848452015491019081528251918252516020820152f35b503461021d57602036600319011261021d576102a66131f2565b6102ae613e99565b6001600160a01b039081169081156102fe57600354826001600160601b0360a01b821617600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b503461021d5760a036600319011261021d5761036c6131f2565b9061037561320d565b60643591604435916084356001600160401b0381116106785761039c90369060040161338e565b6001600160a01b03958616959093903387148015610651575b6103be9061377d565b82166103cb811515613a22565b6103d482614198565b946103de87614198565b50845b865181101561041457600190898752600b60205261040d60408820610406838b613816565b51906141bd565b50016103e1565b509092969195845b865181101561044f57600190858752600b60205261044860408820610441838b613816565b5190614141565b500161041c565b509194509294808652602096868852604087208660005288528260406000205461047b82821015613a7c565b838952888a5260408920886000528a52036040600020558187528688526040872084600052885260406000206104b2848254613809565b90558386604051848152858b8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260403392a43b6104f0578580f35b916105369391600088946040519687958694859363f23a6e6160e01b9b8c865233600487015260248601526044850152606484015260a0608484015260a4830190613237565b03925af160009181610622575b506105ae5783610551613f11565b6308c379a014610579575b60405162461bcd60e51b81528061057560048201613fa0565b0390fd5b610581613f2f565b908161058d575061055c565b61057560405192839262461bcd60e51b845260048401526024830190613237565b9192506001600160e01b0319909116036105cc578038808080808580f35b60405162461bcd60e51b815260206004820152602860248201527f455243313135353a204552433131353552656365697665722072656a656374656044820152676420746f6b656e7360c01b6064820152608490fd5b610643919250853d871161064a575b61063b81836132f6565b810190613ef1565b9038610543565b503d610631565b50868452600160205260408420336000526020526103be60ff6040600020541690506103b5565b8280fd5b503461021d57604036600319011261021d576106966131f2565b60406106a061320d565b9260018060a01b0380931681526001602052209116600052602052602060ff604060002054166040519015158152f35b503461021d57608036600319011261021d576106ea6131f2565b604435916001600160401b0391602480359190606435858111610c085761071590369060040161338e565b9461071e613e99565b6001600160a01b038316938415610bb85761073881614198565b9761074281614198565b5086604051610750816132db565b52865b895181101561078057600190878952600b6020526107798b6104068360408d2092613816565b5001610753565b50909294919396865b89518110156107b657600190888052600b6020526107af8b6104418360408d2092613816565b5001610789565b508796959684875260209487865260408820856000528652604060002054848110610b69578490828a5289885260408a2087600052885203604060002055604051908152838682015287857fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62928360403392a487604051610836816132db565b5260405192610844846132db565b8884526001908160075401988960075589600052600a89526040600020918051918211610b54578190610877845461356b565b8b601f8211610b18575b50508a90601f8311600114610ab257600092610aa7575b5050600019600383901b1c191690831b1790558591905b6108b889614198565b6108c187614198565b506000825b610a64575b5081906000925b610a28575b505050600090888252818852604082208383528852604082206108fb878254613809565b905560405190898252868983015260403392a43b61092f575b8561092b86600b8787600052526040600020614141565b5080f35b8361097391604097969597518093819263f23a6e6160e01b9687845233600485015260008d850152896044850152606484015260a0608484015260a4830190613237565b03816000875af160009181610a09575b506109e8578686610992613f11565b6308c379a0146109b55760405162461bcd60e51b81528061057560048201613fa0565b6109bd613f2f565b806109c8575061055c565b6105759060405193849362461bcd60e51b85526004850152830190613237565b90919293955063ffffffff60e01b16036105cc57839290600b61092b610914565b610a21919250873d891161064a5761063b81836132f6565b9088610983565b9091938151851015610a5e578293948391600052600b8b52610a5260406000206104418386613816565b500191908894936108d2565b936108d7565b8293945081929151811015610a9b57819060008052600b8b52610a8f60406000206104068387613816565b500188949392916108c6565b889493509190916108cb565b015190508d80610898565b60008581528c8120879550929190601f198516908e5b828210610b015750508411610ae8575b505050811b0190559085916108af565b015160001960f88460031b161c191690558d8080610ad8565b83850151865589979095019493840193018e610ac8565b610b4391866000528160002090601f860160051c8201928610610b4a575b601f0160051c0190613aea565b8e8b610881565b9091508190610b36565b8c634e487b7160e01b60005260416004526000fd5b6084878b6040519162461bcd60e51b83526004830152808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152fd5b60405162461bcd60e51b8152602060048201526023818501527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b8480fd5b50606036600319011261021d576001600160401b0360043581811161067857610c39903690600401613418565b909160b46024351015806111b0575b1561116b57610c5960443533613b19565b50610c62613dbb565b601954926016549260018060a01b03600e5416906004602060018060a01b03600c541660405192838092632873b64760e11b82525afa90811561116057889161111a575b50610caf6139b0565b5060405194610160860190811186821017611104579188979491889693604052600a8452865b61014081106110ca57508687958894895b858110610e015750505050505060018060a01b03600f5416926040519687956315eb5a4360e31b875260c4870160c060048901528551809152602060e48901960190895b818110610db057505050928694919285938995602486015260448501526024356064850152608484015260a483015203925af1908115610da557610d7d916080918491610d83575b500151601554613809565b60155580f35b610d9f91503d8086833e610d9781836132f6565b81019061383e565b84610d72565b6040513d84823e3d90fd5b9294966020919496989a50829950610ded906001935190604060609260018060a01b03815116835260208101516020840152015160408201520190565b98019101908a989694928a98969492610d2a565b610e1c9b9a9192939495969897999b366060830285016139e9565b80519098906001600160a01b0316858103610fdf5750506020880151975b80516001600160a01b031680610eca5750602091925001513403610e6e576001905b01908b999a9896979594939291610ce6565b60405162461bcd60e51b815260206004820152602e60248201527f6578706563746564207061796d656e7420616d6f756e74206d7573742065717560448201526d185b081cd95b9d08185b5bdd5b9d60921b6064820152608490fd5b604082015180610f6157505080516020918201516040516323b872dd60e01b8152336004820152306024820152604481019190915293849160649183916001600160a01b03165af1918215610f5657600192610f27575b50610e5c565b610f489060203d602011610f4f575b610f4081836132f6565b81019061394d565b508d610f21565b503d610f36565b6040513d8f823e3d90fd5b90916020909493940151823b15610fdb5760c48492836040519586948593637921219560e11b85523360048601523060248601526044850152606484015260a060848401528160a48401525af18015610da557610fc3575b5050600190610e5c565b610fcc906132ad565b610fd7578b8d610fb9565b8b80fd5b8380fd5b989990986001600160a01b0388168103611000575050604089015198610e3a565b60009081526024602052604090205490999592501561109057600a8a51101561104b5761104582868f94611034908e613816565b5261103f818d613816565b50613adb565b94610e3a565b60405162461bcd60e51b815260206004820152601b60248201527f4d61782070726f6a65637420746f6b656e7320657863656564656400000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601260248201527124b73b30b634b21029b2b73a102a37b5b2b760711b6044820152606490fd5b60209192939594969897506040516110e181613292565b8a81528a838201528a604082015282828901015201908896979593949291610cd5565b634e487b7160e01b600052604160045260246000fd5b90506020813d602011611158575b81611135602093836132f6565b8101031261115457516001600160a01b03811681036111545738610ca6565b8780fd5b3d9150611128565b6040513d8a823e3d90fd5b60405162461bcd60e51b815260206004820152601a60248201527f496e76616c69642065706f636873206c6f636b20706572696f640000000000006044820152606490fd5b506104386024351115610c48565b503461021d578060031936011261021d57602060405160b48152f35b503461021d57602036600319011261021d5760206111fa60043533613b19565b604051908152f35b503461021d578060031936011261021d57604060205460215482519182526020820152f35b503461021d57602036600319011261021d57602090600435815260068252604060018060a01b0391205416604051908152f35b503461021d5760c036600319011261021d576004356001600160401b0381116118c05761128b903690600401613418565b906112946139b0565b5061129d613e99565b60b46064351015806118b2575b15611875576084351580159061186a575b15611835578115158061182a575b156117d1576112dc6064356084356137f6565b90604051926112ea846132c0565b6112f381613317565b9161130160405193846132f6565b818352602083019036606084028201116117cd5780915b60608402820183106117b057505050508252602435602083015260443560408301526084356060830152608082015260643560a082015260a43560c08201526040516020808201528061136e6040820184613448565b0392611382601f19948581018452836132f6565b6040519061138f826132db565b81526001918260075401948560075585600052600a6020526040600020918051916001600160401b0383116111045782916113ca855461356b565b601f811161177e575b50602091601f841160011461171d5750600092611712575b5050600019600383901b1c191690841b1790555b33156116c35761140e84614198565b60405161141a81613277565b8381526020810190602036833751156116ad57839052826000815b61165e575b50906000825b61162b575b50505083600052600060205260406000203360005260205260406000208054908382018092116116155755604051848152826020820152600033917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260403392a4333b611523575b61151f838533600052600b6020526114c9816040600020614141565b50604051908152604060208201527f4c04859a2c5c5d82310b4e9457a381ad4d4b599fdd102495d18131c90b2e4ea53391806115086040820186613448565b0390a2604051918291602083526020830190613448565b0390f35b6020611565916040518093819263f23a6e6160e01b9687845233600485015260006024850152896044850152606484015260a0608484015260a4830190613237565b03816000335af1600091816115f4575b506115dc57611582613f11565b6308c379a0146115a55760405162461bcd60e51b81528061057560048201613fa0565b6115ad613f2f565b806115b8575061055c565b60405162461bcd60e51b815260206004820152908190610575906024830190613237565b6001600160e01b031916036105cc5761151f386114ad565b61160e91925060203d60201161064a5761063b81836132f6565b9038611575565b634e487b7160e01b600052601160045260246000fd5b815181101561165957829033600052600b60205261165160406000206104418386613816565b500182611440565b611445565b82518110156116a85760008052600b60205281906116a07fdf7de25b7f1fd6d0b5205f0e18f1f35bd7b8d84cce336588d184533ce43a6f766104068387613816565b500181611435565b61143a565b634e487b7160e01b600052603260045260246000fd5b60405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608490fd5b0151905038806113eb565b879492919216918560005260206000209260005b8181106117665750841161174d575b505050811b0190556113ff565b015160001960f88460031b161c19169055388080611740565b82840151855589969094019360209384019301611731565b6117aa90866000526020600020601f860160051c81019160208710610b4a57601f0160051c0190613aea565b386113d3565b6060602081926117c036876139e9565b8152019301929050611318565b8680fd5b60405162461bcd60e51b815260206004820152602b60248201527f4d7573742073656e642070726f6a65637420746f6b656e73206f66206170707260448201526a37bb32b210373ab6b132b960a91b6064820152608490fd5b50600a8211156112c9565b60405162461bcd60e51b815260206004820152600d60248201526c135d5cdd081cd95b990814d215609a1b6044820152606490fd5b5060a43515156112bb565b60405162461bcd60e51b815260206004820152601560248201527424b73b30b634b2103637b1b590323ab930ba34b7b760591b6044820152606490fd5b5061043860643511156112aa565b5080fd5b503461021d57602036600319011261021d576001600160a01b0390604090826118eb6131f2565b1681526005602052209061151f6002835492600185015416930154604051938493846040919493926060820195825260018060a01b031660208201520152565b503461021d578060031936011261021d576010546011546012549060145491601554926016549360175460405161196181613277565b601854815260195491602082019283526040519760c089018981106001600160401b0382111761110457604052601a548952601b549460208a01958652601c549660408b01978852601d549860608c01998a52601e549a60808d019b8c528c601f549060a00152604051809e81526020015260408d015260608c015260808b015260a08a015260c08901525160e0880152516101008701528451610120870152516101408601525161016085015251610180840152516101a083015260a001516101c08201526101e090f35b503461021d57604036600319011261021d57611a476131f2565b60243590811515809203610678576001600160a01b031690338214611aba5733835260016020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b60405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608490fd5b503461021d578060031936011261021d5761151f604051611b3c81611b3581613659565b03826132f6565b604051918291602083526020830190613237565b503461021d578060031936011261021d576003546040516001600160a01b039091168152602090f35b503461021d578060031936011261021d5760206040516104388152f35b503461021d57604036600319011261021d5760206111fa611bb56131f2565b611bca60018060a01b03600c54163314613965565b60243590613b19565b503461021d57602036600319011261021d57611b35611b3c604061151f936004358152600a60205220604051928380926136e7565b503461021d57602036600319011261021d5761092b611c256131f2565b600c546001600160a01b039190611c3f9083163314613965565b16808352602260205260408320805460ff191660011790556140a9565b503461021d578060031936011261021d5760405180916023549081835260208093018092602383527fd57b2b5166478fd4318d2acc6cc2c704584312bdd8781b32d5d06abda57f423090835b818110611d055750505084611cbe9103856132f6565b60405193838594850191818652518092526040850193925b828110611ce557505050500390f35b83516001600160a01b031685528695509381019392810192600101611cd6565b825484529286019260019283019201611ca8565b503461021d578060031936011261021d57611d32613e99565b600380546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461021d578060031936011261021d57611dc2604051611d9b81611b35816135a5565b61151f604051611dae81611b3581613659565b604051938493604085526040850190613237565b908382036020850152613237565b503461021d578060031936011261021d57600f546040516001600160a01b039091168152602090f35b503461021d57604036600319011261021d57602490600435611e1c833533613b19565b50600f54604051627eeac760e11b81523360048201526024810183905292906020906001600160a01b039082908690604490829085165afa9485156121315783956123d7575b50841561238957611e71613dbb565b838352600a8252611e9f611b35611e9160408620604051928380926136e7565b83808251830101910161383e565b93611ea86139b0565b508360195480612314575b60165480151580612307575b6122ae575b60408801528487015280859786985b885180518b1015612027578a611ee891613816565b518681511615611fe35788816040898f94511691015160405193849163f59002e360e01b835260048301528160a09485945af1918215611fd8578a92611f41575b5050600191611f39915190613809565b990198611ed3565b81819293503d8411611fd1575b611f5881836132f6565b810103918212611fc957606091828112611fcd576040908151611f7a81613292565b83518152611f898c850161382a565b818d01528383015190830152605f190112611fc95791611f3991608060019460405192611fb584613277565b810151835201518a82015291819350611f29565b8980fd5b8a80fd5b503d611f4e565b6040513d8c823e3d90fd5b60405162461bcd60e51b8152600481018990526017818e01527f496e76616c69642070726f6a65637420616464726573730000000000000000006044820152606490fd5b5093908a959293986120519261205f85600f5416926040519586918c808401526040830190613448565b03601f1981018652856132f6565b813b15611fc9579089929183896120a260405197889687958694636c49c79360e11b86523360048701528501526044840152608060648401526084830190613237565b03925af180156122a357612290575b5080600e5416938715801561213c575b505050849550916120d86121029285969594613809565b60405163a9059cbb60e01b8152336004820152602481019190915293849283919082906044820190565b03925af1801561213157612114578280f35b8161212a92903d10610f4f57610f4081836132f6565b5081808280f35b6040513d85823e3d90fd5b9093919492506019880290888204601914171561227d579486976121676103e8839998048092613e8c565b336000908152600560209081526040808320600201548084526006909252909120549197916001600160a01b031691821615905061221b5760405163a9059cbb60e01b81526001600160a01b03919091166004820152602481019190915293508360448188865af1908115612210578694612102946120d8936121f3575b505b929495968194506120c1565b61220990873d8911610f4f57610f4081836132f6565b50896121e5565b6040513d87823e3d90fd5b509050823b15612279578590604051948591630852cd8d60e31b835260048301528183865af180156122105786938691612260575b50506120d89061210293946121e7565b61226c919294506132ad565b610fdb5784918488612250565b8580fd5b634e487b7160e01b875260116004528387fd5b61229c909691966132ad565b94876120b1565b6040513d89823e3d90fd5b916122f990670de0b6b3a76400006122d86122cd60408c015187613e8c565b60808c0151906137f6565b049060175490828083106122ff575b6122f19192613e8c565b601755613809565b91611ec4565b8291506122e7565b5080604089015110611ebf565b959094809893979294808301965b835180518c10156123585760019161234a8b6123418f61235095613816565b518c5190613ff5565b90613809565b9a0199612322565b509297919650949297939850601854828110612381575b8261237991613e8c565b601855611eb3565b91508161236f565b60405162461bcd60e51b8152600481018390526021818801527f43616c6c657220646f6573206e6f74206f776e207468652068737420746f6b656044820152603760f91b6064820152608490fd5b9094508181813d83116123ff575b6123ef81836132f6565b8101031261067857519338611e62565b503d6123e5565b503461021d578060031936011261021d57600d546040516001600160a01b039091168152602090f35b503461021d576020806003193601126118c0576001600160a01b036124526131f2565b168252600b81526040822091604051809384918482549182815201918452848420935b858282106124a05750505061248c925003836132f6565b61151f6040519282849384528301906133e4565b8554845260019586019588955093019201612475565b503461021d57604036600319011261021d57602090612502906001600160a01b036124df6131f2565b168152600b83526040602435912060019160005201602052604060002054151590565b6040519015158152f35b503461021d57604036600319011261021d576001600160401b0360043581811161067857366023820112156106785780600401359161254a83613317565b9161255860405193846132f6565b83835260209360248585019160051b830101913683116117cd576024869101915b8383106126895750505050602435908111610fdb5761259c90369060040161332e565b908051825103612632578051936125b285613317565b946125c060405196876132f6565b8086526125cf601f1991613317565b0136858701375b815181101561261b5760019061260a6001600160a01b036125f78386613816565b51166126038387613816565b51906134e6565b6126148288613816565b52016125d6565b50505061151f6040519282849384528301906133e4565b60405162461bcd60e51b815260048101849052602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152608490fd5b819061269484613223565b8152019101908590612579565b503461021d57602036600319011261021d5760406126f06126c06131f2565b9060018060a01b038092166000526005602052600260406000200154918260005260066020526040600020541690565b82519182526001600160a01b03166020820152f35b503461021d576020908160031936011261021d576001600160a01b03918261272b6131f2565b168252600581526003604083200191604051808484829654938481520190845284842092845b8682821061286057505050612768925003846132f6565b82519161278d61277784613317565b9361278560405195866132f6565b808552613317565b601f190181835b82811061283e57505050815b84518110156127f457806127b660019287613816565b518085526006845287604086205416604051916127d283613277565b8252848201526127e28287613816565b526127ed8186613816565b50016127a0565b5092506040519280840190808552835180925280604086019401925b82811061281d5785850386f35b83518051865282015187168583015260409094019392810192600101612810565b60405161284a81613277565b8581528583820152828288010152018290612794565b8554845260019586019589955093019201612751565b503461021d57604036600319011261021d57600d546001600160a01b03919082163303612acd57600e54828116612a9057826128b06137e0565b16906001600160601b0360a01b1617600e556024918235906a0b4a7ffb9b9d8947082f0b8203612a4c576128e26137e0565b6040516323b872dd60e01b8152336004820152306024820152604481018490526020939290918491839160649183918991165af18015612a4157612a24575b506010546129e05760105580549081156129a157506129409042613e8c565b60215490603c820291808304603c148115171561298d57610e100291808304603c149015171561297a579061297491613e6c565b60115580f35b5050634e487b7160e01b81526011600452fd5b5050634e487b7160e01b8252506011600452fd5b6064906019856040519262461bcd60e51b84526004840152820152780496e76616c69642067656e657369732074696d657374616d7603c1b6044820152fd5b60405162461bcd60e51b8152600481018390526017818601527f546f74616c2066756e647320616c7265616479207365740000000000000000006044820152606490fd5b612a3a90833d8511610f4f57610f4081836132f6565b5038612921565b6040513d86823e3d90fd5b60405162461bcd60e51b815260206004820152601d818601527f4d7573742073656e6420616c6c2065636f73797374656d2066756e64730000006044820152606490fd5b60405162461bcd60e51b815260206004820152601560248201527414d215081d1bdad95b88185b1c9958591e481cd95d605a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f43616c6c6572206973206e6f742074686520636f696e62617365206164647265604482015261737360f01b6064820152608490fd5b503461021d5760031960a0368201126118c057612b386131f2565b90612b4161320d565b916001600160401b039160443583811161227957612b6390369060040161332e565b926064358181116117cd57612b7c90369060040161332e565b906084359081116117cd57612b9590369060040161338e565b946001600160a01b03938416933385148015612e20575b612bb59061377d565b8551835103612dca57811691612bcc831515613a22565b875b8651811015612bfa57600190868a52600b602052612bf360408b20610406838b613816565b5001612bce565b509193909295875b8651811015612c2e57600190868a52600b602052612c2760408b20610441838b613816565b5001612c02565b50909295949194875b888451821015612cba575080612c4f60019286613816565b51612c5a828a613816565b5190808c526020908c82528c8960408220915282528c60408481832054612c8382821015613a7c565b8484528386528284208d85528652039120558c528b815260408c2090898d5252612cb260408c20918254613809565b905501612c37565b959050869186898388604051604081527f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb612cf8604083018c6133e4565b91808303602082015280612d0d33948c6133e4565b0390a43b612d185780f35b612d6895612d77612d5893602097604051998a988997889663bc197c8160e01b9e8f89523360048a0152602489015260a0604489015260a48801906133e4565b90848783030160648801526133e4565b91848303016084850152613237565b03925af1839181612da9575b50612d9057611582613f11565b6001600160e01b031916036105cc578180808080808680f35b612dc391925060203d60201161064a5761063b81836132f6565b9084612d83565b60405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608490fd5b50848852600160205260408820338952602052612bb560ff60408a2054169050612bac565b503461021d57602036600319011261021d576020906040906001600160a01b03612e6d6131f2565b168152600583522054604051908152f35b503461021d578060031936011261021d57600c546040516001600160a01b039091168152602090f35b503461021d576020806003193601126118c057600435903383526022815260ff6040842054166002811015612fc857600103612f7257612ee982601254613809565b601255338352601381526040832090815415612f15575b506001612f109101918254613809565b905580f35b6040516326079c6160e11b81528181600481335afa918215612210578592612f43575b505081556001612f00565b90809250813d8311612f6b575b612f5a81836132f6565b81010312610fdb5751816001612f38565b503d612f50565b6084906040519062461bcd60e51b82526004820152602960248201527f43616c6c6572206973206e6f7420616e20616363657074656420686f7573696e60448201526819c81c1c9bda9958dd60ba1b6064820152fd5b634e487b7160e01b84526021600452602484fd5b503461021d576020806003193601126118c0576040519182816002546130018161356b565b938484526001918660018216918260001461309c575050600114613042575b505061302e925003836132f6565b61151f604051928284938452830190613237565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061308457505061302e93508201013880613020565b8054838901850152879450869390920191810161306c565b925093505061302e94915060ff191682840152151560051b8201013880613020565b503461021d578060031936011261021d576020600454604051908152f35b503461021d578060031936011261021d5761151f604051611b3c81611b35816135a5565b503461021d57602036600319011261021d5760043563ffffffff60e01b81168091036118c057602090636cdb3d1360e11b811490811561315e575b811561314d575b506040519015158152f35b6301ffc9a760e01b14905082613142565b6303a24d0760e21b8114915061313b565b503461021d57602036600319011261021d576001600160a01b036131916131f2565b168152602260205260ff6040822054166040519060028110156131b657602092508152f35b634e487b7160e01b83526021600452602483fd5b503461021d57604036600319011261021d5760206111fa6131e96131f2565b602435906134e6565b600435906001600160a01b038216820361320857565b600080fd5b602435906001600160a01b038216820361320857565b35906001600160a01b038216820361320857565b919082519283825260005b848110613263575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201613242565b604081019081106001600160401b0382111761110457604052565b606081019081106001600160401b0382111761110457604052565b6001600160401b03811161110457604052565b60e081019081106001600160401b0382111761110457604052565b602081019081106001600160401b0382111761110457604052565b90601f801991011681019081106001600160401b0382111761110457604052565b6001600160401b0381116111045760051b60200190565b9080601f8301121561320857602090823561334881613317565b9361335660405195866132f6565b81855260208086019260051b82010192831161320857602001905b82821061337f575050505090565b81358152908301908301613371565b81601f82011215613208578035906001600160401b03821161110457604051926133c2601f8401601f1916602001856132f6565b8284526020838301011161320857816000926020809301838601378301015290565b90815180825260208080930193019160005b828110613404575050505090565b8351855293810193928101926001016133f6565b9181601f84011215613208578235916001600160401b038311613208576020808501946060850201011161320857565b9060e0810191805160e08352805180945261010083019360208092019160005b8281106134b1575050505060c081602082930151602085015260408101516040850152606081015160608501526080810151608085015260a081015160a0850152015191015290565b835180516001600160a01b03168852602080820151908901526040908101519088015260609096019592810192600101613468565b6001600160a01b031690811561351357600052600060205260406000209060005260205260406000205490565b60405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b6064820152608490fd5b90600182811c9216801561359b575b602083101461358557565b634e487b7160e01b600052602260045260246000fd5b91607f169161357a565b600854600092916135b58261356b565b8082529160209060019081811690811561363457506001146135d8575b50505050565b9293945060086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3926000935b8585106136215750505060209250010190388080806135d2565b8054858501840152938201938101613607565b92505050602093945060ff929192191683830152151560051b010190388080806135d2565b600954600092916136698261356b565b80825291602090600190818116908115613634575060011461368b5750505050565b9293945060096000527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af926000935b8585106136d45750505060209250010190388080806135d2565b80548585018401529382019381016136ba565b8054600093926136f68261356b565b9182825260209360019160018116908160001461375e575060011461371d575b5050505050565b90939495506000929192528360002092846000945b83861061374a57505050500101903880808080613716565b805485870183015294019385908201613732565b60ff19168685015250505090151560051b010191503880808080613716565b1561378457565b60405162461bcd60e51b815260206004820152602e60248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201526d195c881bdc88185c1c1c9bdd995960921b6064820152608490fd5b6004356001600160a01b03811681036132085790565b8181029291811591840414171561161557565b9190820180921161161557565b80518210156116ad5760209160051b010190565b51906001600160a01b038216820361320857565b919091602080828503126132085781516001600160401b039283821161320857019060e08286031261320857604090815193613879856132c0565b83519081116132085783019580601f880112156132085786519661389c88613317565b916138a9855193846132f6565b88835283830190846060809b0284010192818411613208578501915b83831061391057505050508460c0959697505280830151908501528082015190840152606081015160608401526080810151608084015260a081015160a0840152015160c082015290565b8a8383031261320857858b91885161392781613292565b6139308661382a565b81528286015183820152898601518a8201528152019201916138c5565b90816020910312613208575180151581036132085790565b1561396c57565b606460405162461bcd60e51b815260206004820152602060248201527f43616c6c6572206973206e6f74207468652070726f6a6563742066756e6465726044820152fd5b604051906139bd826132c0565b816060815260c06000918260208201528260408201528260608201528260808201528260a08201520152565b919082606091031261320857604051613a0181613292565b6040808294613a0f81613223565b8452602081013560208501520135910152565b15613a2957565b60405162461bcd60e51b815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604482015264647265737360d81b6064820152608490fd5b15613a8357565b60405162461bcd60e51b815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201526939103a3930b739b332b960b11b6064820152608490fd5b60001981146116155760010190565b818110613af5575050565b60008155600101613aea565b80548210156116ad5760005260206000200190600090565b91909160018060a01b0392838216916000838152602090600582526040948582205480613db15750600497613b4e8954613adb565b808a55875192613b5d846132db565b84845288516001600160401b03926080820184811183821017613d9d578b5281528681019282845260038b8301928b84526060810197885284895260058a528c8920905181556001938760018301975116966001600160601b0360a01b9788825416179055516002820155019551958651918211613d9d57600160401b96878311613d8a5789908254848455808510613d70575b5001908852888820885b838110613d5f5750505050508a548552600686528885209182541617905585151580613d54575b80613d43575b613c81575b5050955493518481526001600160a01b039092166020830152506040810191909152919250907fb58d46e66658e855773af8232237e606476d7f0ad98813c081b540e6f435ea3e9080606081015b0390a190565b8583528683205416825260058352600386832001885492815492831015613d30575095613c7b9381989993613d18613d01857fb58d46e66658e855773af8232237e606476d7f0ad98813c081b540e6f435ea3e9b60017fa8b1f3acfefae9dbf6c7ffd8c16eda5db6950c383b34ca999d98f9998721c50c98018155613b01565b819391549060031b91821b91600019901b19161790565b90558354825191888352820152a19594933880613c2d565b634e487b7160e01b815260418a52602490fd5b508583528087842054161515613c28565b508854861415613c22565b825182820155918a01918401613bfb565b838b52828b20613d84918101908601613aea565b38613bf1565b634e487b7160e01b895260418f52602489fd5b50634e487b7160e01b875260418d52602487fd5b9750505050505050565b6020548015613e2b57613dce9042613e8c565b602154603c810290808204603c148115171561161557610e100290808204603c149015171561161557613e0091613e6c565b6014541015613e2957604051633621413760e21b8152670de000cd866f80006004820152602490fd5b565b60405162461bcd60e51b81526020600482015260196024820152780496e76616c69642067656e657369732074696d657374616d7603c1b6044820152606490fd5b8115613e76570490565b634e487b7160e01b600052601260045260246000fd5b9190820391821161161557565b6003546001600160a01b03163303613ead57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b9081602091031261320857516001600160e01b0319811681036132085790565b60009060033d11613f1e57565b905060046000803e60005160e01c90565b600060443d10613f8c57604051600319913d83016004833e81516001600160401b03918282113d602484011117613f8f57818401948551938411613f97573d85010160208487010111613f8f5750613f8c929101602001906132f6565b90565b949350505050565b50949350505050565b60809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356040820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b60608201520190565b828210156140a15760018060a01b038151166000526013602052602060406000209101805192825480941161405c5761404661405793600161403d61404f94613f8c99613e8c565b910154906137f6565b60125490613e6c565b9051906137f6565b613e6c565b60405162461bcd60e51b815260206004820152601e60248201527f50726f6a65637420746f6b656e20616d6f756e7420746f6f206c6172676500006044820152606490fd5b505050600090565b60008181526024602052604081205461413c57602354600160401b8110156141285760018101806023558110156141145790826040927fd57b2b5166478fd4318d2acc6cc2c704584312bdd8781b32d5d06abda57f4230015560235492815260246020522055600190565b634e487b7160e01b82526032600452602482fd5b634e487b7160e01b82526041600452602482fd5b905090565b600082815260018201602052604090205461419157805490600160401b821015611104578261417a613d01846001809601855584613b01565b905580549260005201602052604060002055600190565b5050600090565b604051906141a582613277565b600182526020820160203682378251156116ad575290565b906001820190600092818452826020526040842054908115156000146142a657600019918083018181116142925782549084820191821161427e57808203614249575b50505080548015614235578201916142188383613b01565b909182549160031b1b191690555582526020526040812055600190565b634e487b7160e01b86526031600452602486fd5b614269614259613d019386613b01565b90549060031b1c92839286613b01565b90558652846020526040862055388080614200565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b87526011600452602487fd5b505050509056fea26469706673582212202db0ebe05d10699f2baac20251bd3cd600b477a8b6be65acb79b176d49b1e54164736f6c63430008180033f3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3", "deployedBytecode": "0x6080604052600436101561001257600080fd5b6000803560e01c8062fdd58e146131ca57806301e882081461316f57806301ffc9a71461310057806306fdde03146130dc57806307973ccf146130be5780630e89341c14612fdc5780631958561214612ea757806325da499a14612e7e5780632b956ff714612e455780632eb2c2d614612b1d5780632fd2b55f1461287657806341a0894d146127055780634a9fefc7146126a15780634e1273f41461250c5780634fa3d25d146124b65780635124ae951461242f578063553c991214612406578063594dd43214611df9578063610bdf5d14611dd05780636addb66314611d77578063715018a614611d195780637c373a5014611c5c5780637c56b79814611c085780637c89f5df14611bd35780637d42082c14611b965780638b2ef8b114611b795780638da5cb5b14611b5057806395d89b4114611b11578063a22cb46514611a2d578063a476941c1461192b578063a87430ba146118c4578063af5ad2181461125a578063b169520114611227578063b81d481514611202578063c398bf3a146111da578063cbd91ab4146111be578063d73ca9d314610c0c578063d8938f26146106d0578063e985e9c51461067c578063f242432a14610352578063f2fde38b1461028c578063f7157af6146102205763fdc052a3146101f557600080fd5b3461021d578060031936011261021d57600e546040516001600160a01b039091168152602090f35b80fd5b503461021d57602036600319011261021d576040809161023e6131f2565b60006020845161024d81613277565b82815201526001600160a01b03168152601360205220815161026e81613277565b60206001835493848452015491019081528251918252516020820152f35b503461021d57602036600319011261021d576102a66131f2565b6102ae613e99565b6001600160a01b039081169081156102fe57600354826001600160601b0360a01b821617600355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b503461021d5760a036600319011261021d5761036c6131f2565b9061037561320d565b60643591604435916084356001600160401b0381116106785761039c90369060040161338e565b6001600160a01b03958616959093903387148015610651575b6103be9061377d565b82166103cb811515613a22565b6103d482614198565b946103de87614198565b50845b865181101561041457600190898752600b60205261040d60408820610406838b613816565b51906141bd565b50016103e1565b509092969195845b865181101561044f57600190858752600b60205261044860408820610441838b613816565b5190614141565b500161041c565b509194509294808652602096868852604087208660005288528260406000205461047b82821015613a7c565b838952888a5260408920886000528a52036040600020558187528688526040872084600052885260406000206104b2848254613809565b90558386604051848152858b8201527fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260403392a43b6104f0578580f35b916105369391600088946040519687958694859363f23a6e6160e01b9b8c865233600487015260248601526044850152606484015260a0608484015260a4830190613237565b03925af160009181610622575b506105ae5783610551613f11565b6308c379a014610579575b60405162461bcd60e51b81528061057560048201613fa0565b0390fd5b610581613f2f565b908161058d575061055c565b61057560405192839262461bcd60e51b845260048401526024830190613237565b9192506001600160e01b0319909116036105cc578038808080808580f35b60405162461bcd60e51b815260206004820152602860248201527f455243313135353a204552433131353552656365697665722072656a656374656044820152676420746f6b656e7360c01b6064820152608490fd5b610643919250853d871161064a575b61063b81836132f6565b810190613ef1565b9038610543565b503d610631565b50868452600160205260408420336000526020526103be60ff6040600020541690506103b5565b8280fd5b503461021d57604036600319011261021d576106966131f2565b60406106a061320d565b9260018060a01b0380931681526001602052209116600052602052602060ff604060002054166040519015158152f35b503461021d57608036600319011261021d576106ea6131f2565b604435916001600160401b0391602480359190606435858111610c085761071590369060040161338e565b9461071e613e99565b6001600160a01b038316938415610bb85761073881614198565b9761074281614198565b5086604051610750816132db565b52865b895181101561078057600190878952600b6020526107798b6104068360408d2092613816565b5001610753565b50909294919396865b89518110156107b657600190888052600b6020526107af8b6104418360408d2092613816565b5001610789565b508796959684875260209487865260408820856000528652604060002054848110610b69578490828a5289885260408a2087600052885203604060002055604051908152838682015287857fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62928360403392a487604051610836816132db565b5260405192610844846132db565b8884526001908160075401988960075589600052600a89526040600020918051918211610b54578190610877845461356b565b8b601f8211610b18575b50508a90601f8311600114610ab257600092610aa7575b5050600019600383901b1c191690831b1790558591905b6108b889614198565b6108c187614198565b506000825b610a64575b5081906000925b610a28575b505050600090888252818852604082208383528852604082206108fb878254613809565b905560405190898252868983015260403392a43b61092f575b8561092b86600b8787600052526040600020614141565b5080f35b8361097391604097969597518093819263f23a6e6160e01b9687845233600485015260008d850152896044850152606484015260a0608484015260a4830190613237565b03816000875af160009181610a09575b506109e8578686610992613f11565b6308c379a0146109b55760405162461bcd60e51b81528061057560048201613fa0565b6109bd613f2f565b806109c8575061055c565b6105759060405193849362461bcd60e51b85526004850152830190613237565b90919293955063ffffffff60e01b16036105cc57839290600b61092b610914565b610a21919250873d891161064a5761063b81836132f6565b9088610983565b9091938151851015610a5e578293948391600052600b8b52610a5260406000206104418386613816565b500191908894936108d2565b936108d7565b8293945081929151811015610a9b57819060008052600b8b52610a8f60406000206104068387613816565b500188949392916108c6565b889493509190916108cb565b015190508d80610898565b60008581528c8120879550929190601f198516908e5b828210610b015750508411610ae8575b505050811b0190559085916108af565b015160001960f88460031b161c191690558d8080610ad8565b83850151865589979095019493840193018e610ac8565b610b4391866000528160002090601f860160051c8201928610610b4a575b601f0160051c0190613aea565b8e8b610881565b9091508190610b36565b8c634e487b7160e01b60005260416004526000fd5b6084878b6040519162461bcd60e51b83526004830152808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152fd5b60405162461bcd60e51b8152602060048201526023818501527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b8480fd5b50606036600319011261021d576001600160401b0360043581811161067857610c39903690600401613418565b909160b46024351015806111b0575b1561116b57610c5960443533613b19565b50610c62613dbb565b601954926016549260018060a01b03600e5416906004602060018060a01b03600c541660405192838092632873b64760e11b82525afa90811561116057889161111a575b50610caf6139b0565b5060405194610160860190811186821017611104579188979491889693604052600a8452865b61014081106110ca57508687958894895b858110610e015750505050505060018060a01b03600f5416926040519687956315eb5a4360e31b875260c4870160c060048901528551809152602060e48901960190895b818110610db057505050928694919285938995602486015260448501526024356064850152608484015260a483015203925af1908115610da557610d7d916080918491610d83575b500151601554613809565b60155580f35b610d9f91503d8086833e610d9781836132f6565b81019061383e565b84610d72565b6040513d84823e3d90fd5b9294966020919496989a50829950610ded906001935190604060609260018060a01b03815116835260208101516020840152015160408201520190565b98019101908a989694928a98969492610d2a565b610e1c9b9a9192939495969897999b366060830285016139e9565b80519098906001600160a01b0316858103610fdf5750506020880151975b80516001600160a01b031680610eca5750602091925001513403610e6e576001905b01908b999a9896979594939291610ce6565b60405162461bcd60e51b815260206004820152602e60248201527f6578706563746564207061796d656e7420616d6f756e74206d7573742065717560448201526d185b081cd95b9d08185b5bdd5b9d60921b6064820152608490fd5b604082015180610f6157505080516020918201516040516323b872dd60e01b8152336004820152306024820152604481019190915293849160649183916001600160a01b03165af1918215610f5657600192610f27575b50610e5c565b610f489060203d602011610f4f575b610f4081836132f6565b81019061394d565b508d610f21565b503d610f36565b6040513d8f823e3d90fd5b90916020909493940151823b15610fdb5760c48492836040519586948593637921219560e11b85523360048601523060248601526044850152606484015260a060848401528160a48401525af18015610da557610fc3575b5050600190610e5c565b610fcc906132ad565b610fd7578b8d610fb9565b8b80fd5b8380fd5b989990986001600160a01b0388168103611000575050604089015198610e3a565b60009081526024602052604090205490999592501561109057600a8a51101561104b5761104582868f94611034908e613816565b5261103f818d613816565b50613adb565b94610e3a565b60405162461bcd60e51b815260206004820152601b60248201527f4d61782070726f6a65637420746f6b656e7320657863656564656400000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601260248201527124b73b30b634b21029b2b73a102a37b5b2b760711b6044820152606490fd5b60209192939594969897506040516110e181613292565b8a81528a838201528a604082015282828901015201908896979593949291610cd5565b634e487b7160e01b600052604160045260246000fd5b90506020813d602011611158575b81611135602093836132f6565b8101031261115457516001600160a01b03811681036111545738610ca6565b8780fd5b3d9150611128565b6040513d8a823e3d90fd5b60405162461bcd60e51b815260206004820152601a60248201527f496e76616c69642065706f636873206c6f636b20706572696f640000000000006044820152606490fd5b506104386024351115610c48565b503461021d578060031936011261021d57602060405160b48152f35b503461021d57602036600319011261021d5760206111fa60043533613b19565b604051908152f35b503461021d578060031936011261021d57604060205460215482519182526020820152f35b503461021d57602036600319011261021d57602090600435815260068252604060018060a01b0391205416604051908152f35b503461021d5760c036600319011261021d576004356001600160401b0381116118c05761128b903690600401613418565b906112946139b0565b5061129d613e99565b60b46064351015806118b2575b15611875576084351580159061186a575b15611835578115158061182a575b156117d1576112dc6064356084356137f6565b90604051926112ea846132c0565b6112f381613317565b9161130160405193846132f6565b818352602083019036606084028201116117cd5780915b60608402820183106117b057505050508252602435602083015260443560408301526084356060830152608082015260643560a082015260a43560c08201526040516020808201528061136e6040820184613448565b0392611382601f19948581018452836132f6565b6040519061138f826132db565b81526001918260075401948560075585600052600a6020526040600020918051916001600160401b0383116111045782916113ca855461356b565b601f811161177e575b50602091601f841160011461171d5750600092611712575b5050600019600383901b1c191690841b1790555b33156116c35761140e84614198565b60405161141a81613277565b8381526020810190602036833751156116ad57839052826000815b61165e575b50906000825b61162b575b50505083600052600060205260406000203360005260205260406000208054908382018092116116155755604051848152826020820152600033917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260403392a4333b611523575b61151f838533600052600b6020526114c9816040600020614141565b50604051908152604060208201527f4c04859a2c5c5d82310b4e9457a381ad4d4b599fdd102495d18131c90b2e4ea53391806115086040820186613448565b0390a2604051918291602083526020830190613448565b0390f35b6020611565916040518093819263f23a6e6160e01b9687845233600485015260006024850152896044850152606484015260a0608484015260a4830190613237565b03816000335af1600091816115f4575b506115dc57611582613f11565b6308c379a0146115a55760405162461bcd60e51b81528061057560048201613fa0565b6115ad613f2f565b806115b8575061055c565b60405162461bcd60e51b815260206004820152908190610575906024830190613237565b6001600160e01b031916036105cc5761151f386114ad565b61160e91925060203d60201161064a5761063b81836132f6565b9038611575565b634e487b7160e01b600052601160045260246000fd5b815181101561165957829033600052600b60205261165160406000206104418386613816565b500182611440565b611445565b82518110156116a85760008052600b60205281906116a07fdf7de25b7f1fd6d0b5205f0e18f1f35bd7b8d84cce336588d184533ce43a6f766104068387613816565b500181611435565b61143a565b634e487b7160e01b600052603260045260246000fd5b60405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608490fd5b0151905038806113eb565b879492919216918560005260206000209260005b8181106117665750841161174d575b505050811b0190556113ff565b015160001960f88460031b161c19169055388080611740565b82840151855589969094019360209384019301611731565b6117aa90866000526020600020601f860160051c81019160208710610b4a57601f0160051c0190613aea565b386113d3565b6060602081926117c036876139e9565b8152019301929050611318565b8680fd5b60405162461bcd60e51b815260206004820152602b60248201527f4d7573742073656e642070726f6a65637420746f6b656e73206f66206170707260448201526a37bb32b210373ab6b132b960a91b6064820152608490fd5b50600a8211156112c9565b60405162461bcd60e51b815260206004820152600d60248201526c135d5cdd081cd95b990814d215609a1b6044820152606490fd5b5060a43515156112bb565b60405162461bcd60e51b815260206004820152601560248201527424b73b30b634b2103637b1b590323ab930ba34b7b760591b6044820152606490fd5b5061043860643511156112aa565b5080fd5b503461021d57602036600319011261021d576001600160a01b0390604090826118eb6131f2565b1681526005602052209061151f6002835492600185015416930154604051938493846040919493926060820195825260018060a01b031660208201520152565b503461021d578060031936011261021d576010546011546012549060145491601554926016549360175460405161196181613277565b601854815260195491602082019283526040519760c089018981106001600160401b0382111761110457604052601a548952601b549460208a01958652601c549660408b01978852601d549860608c01998a52601e549a60808d019b8c528c601f549060a00152604051809e81526020015260408d015260608c015260808b015260a08a015260c08901525160e0880152516101008701528451610120870152516101408601525161016085015251610180840152516101a083015260a001516101c08201526101e090f35b503461021d57604036600319011261021d57611a476131f2565b60243590811515809203610678576001600160a01b031690338214611aba5733835260016020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b60405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608490fd5b503461021d578060031936011261021d5761151f604051611b3c81611b3581613659565b03826132f6565b604051918291602083526020830190613237565b503461021d578060031936011261021d576003546040516001600160a01b039091168152602090f35b503461021d578060031936011261021d5760206040516104388152f35b503461021d57604036600319011261021d5760206111fa611bb56131f2565b611bca60018060a01b03600c54163314613965565b60243590613b19565b503461021d57602036600319011261021d57611b35611b3c604061151f936004358152600a60205220604051928380926136e7565b503461021d57602036600319011261021d5761092b611c256131f2565b600c546001600160a01b039190611c3f9083163314613965565b16808352602260205260408320805460ff191660011790556140a9565b503461021d578060031936011261021d5760405180916023549081835260208093018092602383527fd57b2b5166478fd4318d2acc6cc2c704584312bdd8781b32d5d06abda57f423090835b818110611d055750505084611cbe9103856132f6565b60405193838594850191818652518092526040850193925b828110611ce557505050500390f35b83516001600160a01b031685528695509381019392810192600101611cd6565b825484529286019260019283019201611ca8565b503461021d578060031936011261021d57611d32613e99565b600380546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461021d578060031936011261021d57611dc2604051611d9b81611b35816135a5565b61151f604051611dae81611b3581613659565b604051938493604085526040850190613237565b908382036020850152613237565b503461021d578060031936011261021d57600f546040516001600160a01b039091168152602090f35b503461021d57604036600319011261021d57602490600435611e1c833533613b19565b50600f54604051627eeac760e11b81523360048201526024810183905292906020906001600160a01b039082908690604490829085165afa9485156121315783956123d7575b50841561238957611e71613dbb565b838352600a8252611e9f611b35611e9160408620604051928380926136e7565b83808251830101910161383e565b93611ea86139b0565b508360195480612314575b60165480151580612307575b6122ae575b60408801528487015280859786985b885180518b1015612027578a611ee891613816565b518681511615611fe35788816040898f94511691015160405193849163f59002e360e01b835260048301528160a09485945af1918215611fd8578a92611f41575b5050600191611f39915190613809565b990198611ed3565b81819293503d8411611fd1575b611f5881836132f6565b810103918212611fc957606091828112611fcd576040908151611f7a81613292565b83518152611f898c850161382a565b818d01528383015190830152605f190112611fc95791611f3991608060019460405192611fb584613277565b810151835201518a82015291819350611f29565b8980fd5b8a80fd5b503d611f4e565b6040513d8c823e3d90fd5b60405162461bcd60e51b8152600481018990526017818e01527f496e76616c69642070726f6a65637420616464726573730000000000000000006044820152606490fd5b5093908a959293986120519261205f85600f5416926040519586918c808401526040830190613448565b03601f1981018652856132f6565b813b15611fc9579089929183896120a260405197889687958694636c49c79360e11b86523360048701528501526044840152608060648401526084830190613237565b03925af180156122a357612290575b5080600e5416938715801561213c575b505050849550916120d86121029285969594613809565b60405163a9059cbb60e01b8152336004820152602481019190915293849283919082906044820190565b03925af1801561213157612114578280f35b8161212a92903d10610f4f57610f4081836132f6565b5081808280f35b6040513d85823e3d90fd5b9093919492506019880290888204601914171561227d579486976121676103e8839998048092613e8c565b336000908152600560209081526040808320600201548084526006909252909120549197916001600160a01b031691821615905061221b5760405163a9059cbb60e01b81526001600160a01b03919091166004820152602481019190915293508360448188865af1908115612210578694612102946120d8936121f3575b505b929495968194506120c1565b61220990873d8911610f4f57610f4081836132f6565b50896121e5565b6040513d87823e3d90fd5b509050823b15612279578590604051948591630852cd8d60e31b835260048301528183865af180156122105786938691612260575b50506120d89061210293946121e7565b61226c919294506132ad565b610fdb5784918488612250565b8580fd5b634e487b7160e01b875260116004528387fd5b61229c909691966132ad565b94876120b1565b6040513d89823e3d90fd5b916122f990670de0b6b3a76400006122d86122cd60408c015187613e8c565b60808c0151906137f6565b049060175490828083106122ff575b6122f19192613e8c565b601755613809565b91611ec4565b8291506122e7565b5080604089015110611ebf565b959094809893979294808301965b835180518c10156123585760019161234a8b6123418f61235095613816565b518c5190613ff5565b90613809565b9a0199612322565b509297919650949297939850601854828110612381575b8261237991613e8c565b601855611eb3565b91508161236f565b60405162461bcd60e51b8152600481018390526021818801527f43616c6c657220646f6573206e6f74206f776e207468652068737420746f6b656044820152603760f91b6064820152608490fd5b9094508181813d83116123ff575b6123ef81836132f6565b8101031261067857519338611e62565b503d6123e5565b503461021d578060031936011261021d57600d546040516001600160a01b039091168152602090f35b503461021d576020806003193601126118c0576001600160a01b036124526131f2565b168252600b81526040822091604051809384918482549182815201918452848420935b858282106124a05750505061248c925003836132f6565b61151f6040519282849384528301906133e4565b8554845260019586019588955093019201612475565b503461021d57604036600319011261021d57602090612502906001600160a01b036124df6131f2565b168152600b83526040602435912060019160005201602052604060002054151590565b6040519015158152f35b503461021d57604036600319011261021d576001600160401b0360043581811161067857366023820112156106785780600401359161254a83613317565b9161255860405193846132f6565b83835260209360248585019160051b830101913683116117cd576024869101915b8383106126895750505050602435908111610fdb5761259c90369060040161332e565b908051825103612632578051936125b285613317565b946125c060405196876132f6565b8086526125cf601f1991613317565b0136858701375b815181101561261b5760019061260a6001600160a01b036125f78386613816565b51166126038387613816565b51906134e6565b6126148288613816565b52016125d6565b50505061151f6040519282849384528301906133e4565b60405162461bcd60e51b815260048101849052602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152608490fd5b819061269484613223565b8152019101908590612579565b503461021d57602036600319011261021d5760406126f06126c06131f2565b9060018060a01b038092166000526005602052600260406000200154918260005260066020526040600020541690565b82519182526001600160a01b03166020820152f35b503461021d576020908160031936011261021d576001600160a01b03918261272b6131f2565b168252600581526003604083200191604051808484829654938481520190845284842092845b8682821061286057505050612768925003846132f6565b82519161278d61277784613317565b9361278560405195866132f6565b808552613317565b601f190181835b82811061283e57505050815b84518110156127f457806127b660019287613816565b518085526006845287604086205416604051916127d283613277565b8252848201526127e28287613816565b526127ed8186613816565b50016127a0565b5092506040519280840190808552835180925280604086019401925b82811061281d5785850386f35b83518051865282015187168583015260409094019392810192600101612810565b60405161284a81613277565b8581528583820152828288010152018290612794565b8554845260019586019589955093019201612751565b503461021d57604036600319011261021d57600d546001600160a01b03919082163303612acd57600e54828116612a9057826128b06137e0565b16906001600160601b0360a01b1617600e556024918235906a0b4a7ffb9b9d8947082f0b8203612a4c576128e26137e0565b6040516323b872dd60e01b8152336004820152306024820152604481018490526020939290918491839160649183918991165af18015612a4157612a24575b506010546129e05760105580549081156129a157506129409042613e8c565b60215490603c820291808304603c148115171561298d57610e100291808304603c149015171561297a579061297491613e6c565b60115580f35b5050634e487b7160e01b81526011600452fd5b5050634e487b7160e01b8252506011600452fd5b6064906019856040519262461bcd60e51b84526004840152820152780496e76616c69642067656e657369732074696d657374616d7603c1b6044820152fd5b60405162461bcd60e51b8152600481018390526017818601527f546f74616c2066756e647320616c7265616479207365740000000000000000006044820152606490fd5b612a3a90833d8511610f4f57610f4081836132f6565b5038612921565b6040513d86823e3d90fd5b60405162461bcd60e51b815260206004820152601d818601527f4d7573742073656e6420616c6c2065636f73797374656d2066756e64730000006044820152606490fd5b60405162461bcd60e51b815260206004820152601560248201527414d215081d1bdad95b88185b1c9958591e481cd95d605a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f43616c6c6572206973206e6f742074686520636f696e62617365206164647265604482015261737360f01b6064820152608490fd5b503461021d5760031960a0368201126118c057612b386131f2565b90612b4161320d565b916001600160401b039160443583811161227957612b6390369060040161332e565b926064358181116117cd57612b7c90369060040161332e565b906084359081116117cd57612b9590369060040161338e565b946001600160a01b03938416933385148015612e20575b612bb59061377d565b8551835103612dca57811691612bcc831515613a22565b875b8651811015612bfa57600190868a52600b602052612bf360408b20610406838b613816565b5001612bce565b509193909295875b8651811015612c2e57600190868a52600b602052612c2760408b20610441838b613816565b5001612c02565b50909295949194875b888451821015612cba575080612c4f60019286613816565b51612c5a828a613816565b5190808c526020908c82528c8960408220915282528c60408481832054612c8382821015613a7c565b8484528386528284208d85528652039120558c528b815260408c2090898d5252612cb260408c20918254613809565b905501612c37565b959050869186898388604051604081527f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb612cf8604083018c6133e4565b91808303602082015280612d0d33948c6133e4565b0390a43b612d185780f35b612d6895612d77612d5893602097604051998a988997889663bc197c8160e01b9e8f89523360048a0152602489015260a0604489015260a48801906133e4565b90848783030160648801526133e4565b91848303016084850152613237565b03925af1839181612da9575b50612d9057611582613f11565b6001600160e01b031916036105cc578180808080808680f35b612dc391925060203d60201161064a5761063b81836132f6565b9084612d83565b60405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608490fd5b50848852600160205260408820338952602052612bb560ff60408a2054169050612bac565b503461021d57602036600319011261021d576020906040906001600160a01b03612e6d6131f2565b168152600583522054604051908152f35b503461021d578060031936011261021d57600c546040516001600160a01b039091168152602090f35b503461021d576020806003193601126118c057600435903383526022815260ff6040842054166002811015612fc857600103612f7257612ee982601254613809565b601255338352601381526040832090815415612f15575b506001612f109101918254613809565b905580f35b6040516326079c6160e11b81528181600481335afa918215612210578592612f43575b505081556001612f00565b90809250813d8311612f6b575b612f5a81836132f6565b81010312610fdb5751816001612f38565b503d612f50565b6084906040519062461bcd60e51b82526004820152602960248201527f43616c6c6572206973206e6f7420616e20616363657074656420686f7573696e60448201526819c81c1c9bda9958dd60ba1b6064820152fd5b634e487b7160e01b84526021600452602484fd5b503461021d576020806003193601126118c0576040519182816002546130018161356b565b938484526001918660018216918260001461309c575050600114613042575b505061302e925003836132f6565b61151f604051928284938452830190613237565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061308457505061302e93508201013880613020565b8054838901850152879450869390920191810161306c565b925093505061302e94915060ff191682840152151560051b8201013880613020565b503461021d578060031936011261021d576020600454604051908152f35b503461021d578060031936011261021d5761151f604051611b3c81611b35816135a5565b503461021d57602036600319011261021d5760043563ffffffff60e01b81168091036118c057602090636cdb3d1360e11b811490811561315e575b811561314d575b506040519015158152f35b6301ffc9a760e01b14905082613142565b6303a24d0760e21b8114915061313b565b503461021d57602036600319011261021d576001600160a01b036131916131f2565b168152602260205260ff6040822054166040519060028110156131b657602092508152f35b634e487b7160e01b83526021600452602483fd5b503461021d57604036600319011261021d5760206111fa6131e96131f2565b602435906134e6565b600435906001600160a01b038216820361320857565b600080fd5b602435906001600160a01b038216820361320857565b35906001600160a01b038216820361320857565b919082519283825260005b848110613263575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201613242565b604081019081106001600160401b0382111761110457604052565b606081019081106001600160401b0382111761110457604052565b6001600160401b03811161110457604052565b60e081019081106001600160401b0382111761110457604052565b602081019081106001600160401b0382111761110457604052565b90601f801991011681019081106001600160401b0382111761110457604052565b6001600160401b0381116111045760051b60200190565b9080601f8301121561320857602090823561334881613317565b9361335660405195866132f6565b81855260208086019260051b82010192831161320857602001905b82821061337f575050505090565b81358152908301908301613371565b81601f82011215613208578035906001600160401b03821161110457604051926133c2601f8401601f1916602001856132f6565b8284526020838301011161320857816000926020809301838601378301015290565b90815180825260208080930193019160005b828110613404575050505090565b8351855293810193928101926001016133f6565b9181601f84011215613208578235916001600160401b038311613208576020808501946060850201011161320857565b9060e0810191805160e08352805180945261010083019360208092019160005b8281106134b1575050505060c081602082930151602085015260408101516040850152606081015160608501526080810151608085015260a081015160a0850152015191015290565b835180516001600160a01b03168852602080820151908901526040908101519088015260609096019592810192600101613468565b6001600160a01b031690811561351357600052600060205260406000209060005260205260406000205490565b60405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b6064820152608490fd5b90600182811c9216801561359b575b602083101461358557565b634e487b7160e01b600052602260045260246000fd5b91607f169161357a565b600854600092916135b58261356b565b8082529160209060019081811690811561363457506001146135d8575b50505050565b9293945060086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3926000935b8585106136215750505060209250010190388080806135d2565b8054858501840152938201938101613607565b92505050602093945060ff929192191683830152151560051b010190388080806135d2565b600954600092916136698261356b565b80825291602090600190818116908115613634575060011461368b5750505050565b9293945060096000527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af926000935b8585106136d45750505060209250010190388080806135d2565b80548585018401529382019381016136ba565b8054600093926136f68261356b565b9182825260209360019160018116908160001461375e575060011461371d575b5050505050565b90939495506000929192528360002092846000945b83861061374a57505050500101903880808080613716565b805485870183015294019385908201613732565b60ff19168685015250505090151560051b010191503880808080613716565b1561378457565b60405162461bcd60e51b815260206004820152602e60248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201526d195c881bdc88185c1c1c9bdd995960921b6064820152608490fd5b6004356001600160a01b03811681036132085790565b8181029291811591840414171561161557565b9190820180921161161557565b80518210156116ad5760209160051b010190565b51906001600160a01b038216820361320857565b919091602080828503126132085781516001600160401b039283821161320857019060e08286031261320857604090815193613879856132c0565b83519081116132085783019580601f880112156132085786519661389c88613317565b916138a9855193846132f6565b88835283830190846060809b0284010192818411613208578501915b83831061391057505050508460c0959697505280830151908501528082015190840152606081015160608401526080810151608084015260a081015160a0840152015160c082015290565b8a8383031261320857858b91885161392781613292565b6139308661382a565b81528286015183820152898601518a8201528152019201916138c5565b90816020910312613208575180151581036132085790565b1561396c57565b606460405162461bcd60e51b815260206004820152602060248201527f43616c6c6572206973206e6f74207468652070726f6a6563742066756e6465726044820152fd5b604051906139bd826132c0565b816060815260c06000918260208201528260408201528260608201528260808201528260a08201520152565b919082606091031261320857604051613a0181613292565b6040808294613a0f81613223565b8452602081013560208501520135910152565b15613a2957565b60405162461bcd60e51b815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604482015264647265737360d81b6064820152608490fd5b15613a8357565b60405162461bcd60e51b815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201526939103a3930b739b332b960b11b6064820152608490fd5b60001981146116155760010190565b818110613af5575050565b60008155600101613aea565b80548210156116ad5760005260206000200190600090565b91909160018060a01b0392838216916000838152602090600582526040948582205480613db15750600497613b4e8954613adb565b808a55875192613b5d846132db565b84845288516001600160401b03926080820184811183821017613d9d578b5281528681019282845260038b8301928b84526060810197885284895260058a528c8920905181556001938760018301975116966001600160601b0360a01b9788825416179055516002820155019551958651918211613d9d57600160401b96878311613d8a5789908254848455808510613d70575b5001908852888820885b838110613d5f5750505050508a548552600686528885209182541617905585151580613d54575b80613d43575b613c81575b5050955493518481526001600160a01b039092166020830152506040810191909152919250907fb58d46e66658e855773af8232237e606476d7f0ad98813c081b540e6f435ea3e9080606081015b0390a190565b8583528683205416825260058352600386832001885492815492831015613d30575095613c7b9381989993613d18613d01857fb58d46e66658e855773af8232237e606476d7f0ad98813c081b540e6f435ea3e9b60017fa8b1f3acfefae9dbf6c7ffd8c16eda5db6950c383b34ca999d98f9998721c50c98018155613b01565b819391549060031b91821b91600019901b19161790565b90558354825191888352820152a19594933880613c2d565b634e487b7160e01b815260418a52602490fd5b508583528087842054161515613c28565b508854861415613c22565b825182820155918a01918401613bfb565b838b52828b20613d84918101908601613aea565b38613bf1565b634e487b7160e01b895260418f52602489fd5b50634e487b7160e01b875260418d52602487fd5b9750505050505050565b6020548015613e2b57613dce9042613e8c565b602154603c810290808204603c148115171561161557610e100290808204603c149015171561161557613e0091613e6c565b6014541015613e2957604051633621413760e21b8152670de000cd866f80006004820152602490fd5b565b60405162461bcd60e51b81526020600482015260196024820152780496e76616c69642067656e657369732074696d657374616d7603c1b6044820152606490fd5b8115613e76570490565b634e487b7160e01b600052601260045260246000fd5b9190820391821161161557565b6003546001600160a01b03163303613ead57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b9081602091031261320857516001600160e01b0319811681036132085790565b60009060033d11613f1e57565b905060046000803e60005160e01c90565b600060443d10613f8c57604051600319913d83016004833e81516001600160401b03918282113d602484011117613f8f57818401948551938411613f97573d85010160208487010111613f8f5750613f8c929101602001906132f6565b90565b949350505050565b50949350505050565b60809060208152603460208201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356040820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b60608201520190565b828210156140a15760018060a01b038151166000526013602052602060406000209101805192825480941161405c5761404661405793600161403d61404f94613f8c99613e8c565b910154906137f6565b60125490613e6c565b9051906137f6565b613e6c565b60405162461bcd60e51b815260206004820152601e60248201527f50726f6a65637420746f6b656e20616d6f756e7420746f6f206c6172676500006044820152606490fd5b505050600090565b60008181526024602052604081205461413c57602354600160401b8110156141285760018101806023558110156141145790826040927fd57b2b5166478fd4318d2acc6cc2c704584312bdd8781b32d5d06abda57f4230015560235492815260246020522055600190565b634e487b7160e01b82526032600452602482fd5b634e487b7160e01b82526041600452602482fd5b905090565b600082815260018201602052604090205461419157805490600160401b821015611104578261417a613d01846001809601855584613b01565b905580549260005201602052604060002055600190565b5050600090565b604051906141a582613277565b600182526020820160203682378251156116ad575290565b906001820190600092818452826020526040842054908115156000146142a657600019918083018181116142925782549084820191821161427e57808203614249575b50505080548015614235578201916142188383613b01565b909182549160031b1b191690555582526020526040812055600190565b634e487b7160e01b86526031600452602486fd5b614269614259613d019386613b01565b90549060031b1c92839286613b01565b90558652846020526040862055388080614200565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b87526011600452602487fd5b505050509056fea26469706673582212202db0ebe05d10699f2baac20251bd3cd600b477a8b6be65acb79b176d49b1e54164736f6c63430008180033", "libraries": { diff --git a/packages/backend/deployments/opbnb/solcInputs/3f7696dcd180eba0f188ae64ff117803.json b/packages/backend/deployments/opbnb/solcInputs/3f7696dcd180eba0f188ae64ff117803.json index 7cf425e..b48580b 100644 --- a/packages/backend/deployments/opbnb/solcInputs/3f7696dcd180eba0f188ae64ff117803.json +++ b/packages/backend/deployments/opbnb/solcInputs/3f7696dcd180eba0f188ae64ff117803.json @@ -68,7 +68,7 @@ "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity 0.8.24;\n\nimport { HousingProject } from \"./HousingProject.sol\";\n\nlibrary NewHousingProject {\n\tfunction create(\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress smartHousingAddr\n\t) external returns (HousingProject) {\n\t\treturn new HousingProject(name, symbol, smartHousingAddr);\n\t}\n}\n" }, "contracts/housing-project/RentsModule.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\n\nimport \"./HousingSFT.sol\";\nimport \"./RewardSharing.sol\";\nimport \"../lib/TokenPayments.sol\";\nimport \"./CallsSmartHousing.sol\";\n\n/// @title Rents Module\n/// @notice Handles rent payments, reward calculations, and distribution for Housing projects.\n/// @dev This abstract contract should be inherited by the HousingProject contract.\nabstract contract RentsModule is CallsSmartHousing {\n\tusing TokenPayments for ERC20TokenPayment;\n\tusing RewardShares for rewardshares;\n\n\tuint256 public rewardPerShare;\n\tuint256 public rewardsReserve;\n\tuint256 public facilityManagementFunds;\n\n\tERC20Burnable housingToken;\n\tHousingSFT public projectSFT;\n\n\t/// @notice Receives rent payments and distributes rewards.\n\t/// @param rentPayment The details of the rent payment.\n\tfunction receiveRent(ERC20TokenPayment calldata rentPayment) external {\n\t\t// TODO set the appropriate rent per Project\n\t\trequire(\n\t\t\trentPayment.amount > 0,\n\t\t\t\"RentsModule: Insufficient rent amount\"\n\t\t);\n\t\trequire(\n\t\t\trentPayment.token == housingToken,\n\t\t\t\"RentsModule: Invalid rent payment token\"\n\t\t);\n\t\trentPayment.receiveERC20();\n\n\t\tuint256 rentReward = (rentPayment.amount * 75) / 100;\n\t\tuint256 ecosystemReward = (rentPayment.amount * 18) / 100;\n\t\tuint256 facilityReward = (rentPayment.amount * 7) / 100;\n\n\t\tuint256 allShares = projectSFT.getMaxSupply();\n\t\tuint256 rpsIncrease = (rentReward * DIVISION_SAFETY_CONST) / allShares;\n\n\t\trewardPerShare += rpsIncrease;\n\t\trewardsReserve += rentReward;\n\t\tfacilityManagementFunds += facilityReward;\n\n\t\thousingToken.burn(ecosystemReward);\n\t\tISmartHousing(smartHousingAddr).addProjectRent(rentPayment.amount);\n\t}\n\n\t/// @notice Claims rent rewards for a given token.\n\t/// @return The updated HousingAttributes.\n\tfunction claimRentReward(\n\t\tuint256 nonce\n\t) external returns (HousingAttributes memory, rewardshares memory) {\n\t\taddress caller = msg.sender;\n\t\tuint256 currentRPS = rewardPerShare;\n\n\t\tHousingAttributes memory attr = projectSFT.getUserSFT(caller, nonce);\n\t\trewardshares memory rewardShares = computeRewardShares(attr);\n\t\tuint256 totalReward = rewardShares.total();\n\n\t\tif (totalReward == 0) {\n\t\t\t// Fail silently\n\t\t\treturn (attr, rewardShares);\n\t\t}\n\n\t\trequire(rewardsReserve >= totalReward, \"Computed rewards too large\");\n\n\t\trewardsReserve -= totalReward;\n\n\t\t// We use original owner since we are certain they are registered\n\t\t(, address referrer) = getReferrer(attr.originalOwner);\n\t\tif (rewardShares.referrerValue > 0) {\n\t\t\tif (referrer != address(0)) {\n\t\t\t\thousingToken.transfer(referrer, rewardShares.referrerValue); // Send to referrer\n\t\t\t} else {\n\t\t\t\thousingToken.burn(rewardShares.referrerValue); // Burn to add to ecosystem reward\n\t\t\t}\n\t\t}\n\n\t\tattr.rewardsPerShare = currentRPS;\n\n\t\tprojectSFT.update(\n\t\t\tcaller,\n\t\t\tnonce,\n\t\t\tprojectSFT.balanceOf(caller, nonce),\n\t\t\tabi.encode(attr)\n\t\t);\n\n\t\thousingToken.transfer(caller, rewardShares.userValue); // Send to user\n\n\t\treturn (attr, rewardShares);\n\t}\n\n\t/// @notice Computes the amount of rent claimable for a given token.\n\t/// @param attr The attributes of the token.\n\t/// @return The amount of rent claimable.\n\tfunction rentClaimable(\n\t\tHousingAttributes memory attr\n\t) public view returns (uint256) {\n\t\treturn computeRewardShares(attr).userValue;\n\t}\n\n\t/// @dev Computes the reward shares for a given token.\n\t/// @param attr The attributes of the token.\n\t/// @return The computed RewardShares.\n\tfunction computeRewardShares(\n\t\tHousingAttributes memory attr\n\t) internal view returns (rewardshares memory) {\n\t\tuint256 currentRPS = rewardPerShare;\n\n\t\tif (currentRPS == 0 || attr.rewardsPerShare >= currentRPS) {\n\t\t\treturn rewardshares({ userValue: 0, referrerValue: 0 });\n\t\t}\n\n\t\tuint256 reward = computeReward(attr, currentRPS);\n\n\t\treturn splitReward(reward);\n\t}\n}\n" + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\n\nimport \"./HousingSFT.sol\";\nimport \"./RewardSharing.sol\";\nimport \"../lib/TokenPayments.sol\";\nimport \"./CallsSmartHousing.sol\";\n\n/// @title Rents Module\n/// @notice Handles rent payments, reward calculations, and distribution for Housing projects.\n/// @dev This abstract contract should be inherited by the HousingProject contract.\nabstract contract RentsModule is CallsSmartHousing {\n\tusing TokenPayments for ERC20TokenPayment;\n\tusing RewardShares for rewardshares;\n\n\tuint256 public rewardPerShare;\n\tuint256 public rewardsReserve;\n\tuint256 public facilityManagementFunds;\n\n\tERC20Burnable housingToken;\n\tHousingSFT public projectSFT;\n\n\t/// @notice Receives rent payments and distributes rewards.\n\t/// @param rentPayment The details of the rent payment.\n\tfunction receiveRent(ERC20TokenPayment calldata rentPayment) external {\n\t\t// TODO set the appropriate rent per Project\n\t\trequire(\n\t\t\trentPayment.amount > 0,\n\t\t\t\"RentsModule: Insufficient amount\"\n\t\t);\n\t\trequire(\n\t\t\trentPayment.token == housingToken,\n\t\t\t\"RentsModule: Invalid rent payment token\"\n\t\t);\n\t\trentPayment.receiveERC20();\n\n\t\tuint256 rentReward = (rentPayment.amount * 75) / 100;\n\t\tuint256 ecosystemReward = (rentPayment.amount * 18) / 100;\n\t\tuint256 facilityReward = (rentPayment.amount * 7) / 100;\n\n\t\tuint256 allShares = projectSFT.getMaxSupply();\n\t\tuint256 rpsIncrease = (rentReward * DIVISION_SAFETY_CONST) / allShares;\n\n\t\trewardPerShare += rpsIncrease;\n\t\trewardsReserve += rentReward;\n\t\tfacilityManagementFunds += facilityReward;\n\n\t\thousingToken.burn(ecosystemReward);\n\t\tISmartHousing(smartHousingAddr).addProjectRent(rentPayment.amount);\n\t}\n\n\t/// @notice Claims rent rewards for a given token.\n\t/// @return The updated HousingAttributes.\n\tfunction claimRentReward(\n\t\tuint256 nonce\n\t) external returns (HousingAttributes memory, rewardshares memory) {\n\t\taddress caller = msg.sender;\n\t\tuint256 currentRPS = rewardPerShare;\n\n\t\tHousingAttributes memory attr = projectSFT.getUserSFT(caller, nonce);\n\t\trewardshares memory rewardShares = computeRewardShares(attr);\n\t\tuint256 totalReward = rewardShares.total();\n\n\t\tif (totalReward == 0) {\n\t\t\t// Fail silently\n\t\t\treturn (attr, rewardShares);\n\t\t}\n\n\t\trequire(rewardsReserve >= totalReward, \"Computed rewards too large\");\n\n\t\trewardsReserve -= totalReward;\n\n\t\t// We use original owner since we are certain they are registered\n\t\t(, address referrer) = getReferrer(attr.originalOwner);\n\t\tif (rewardShares.referrerValue > 0) {\n\t\t\tif (referrer != address(0)) {\n\t\t\t\thousingToken.transfer(referrer, rewardShares.referrerValue); // Send to referrer\n\t\t\t} else {\n\t\t\t\thousingToken.burn(rewardShares.referrerValue); // Burn to add to ecosystem reward\n\t\t\t}\n\t\t}\n\n\t\tattr.rewardsPerShare = currentRPS;\n\n\t\tprojectSFT.update(\n\t\t\tcaller,\n\t\t\tnonce,\n\t\t\tprojectSFT.balanceOf(caller, nonce),\n\t\t\tabi.encode(attr)\n\t\t);\n\n\t\thousingToken.transfer(caller, rewardShares.userValue); // Send to user\n\n\t\treturn (attr, rewardShares);\n\t}\n\n\t/// @notice Computes the amount of rent claimable for a given token.\n\t/// @param attr The attributes of the token.\n\t/// @return The amount of rent claimable.\n\tfunction rentClaimable(\n\t\tHousingAttributes memory attr\n\t) public view returns (uint256) {\n\t\treturn computeRewardShares(attr).userValue;\n\t}\n\n\t/// @dev Computes the reward shares for a given token.\n\t/// @param attr The attributes of the token.\n\t/// @return The computed RewardShares.\n\tfunction computeRewardShares(\n\t\tHousingAttributes memory attr\n\t) internal view returns (rewardshares memory) {\n\t\tuint256 currentRPS = rewardPerShare;\n\n\t\tif (currentRPS == 0 || attr.rewardsPerShare >= currentRPS) {\n\t\t\treturn rewardshares({ userValue: 0, referrerValue: 0 });\n\t\t}\n\n\t\tuint256 reward = computeReward(attr, currentRPS);\n\n\t\treturn splitReward(reward);\n\t}\n}\n" }, "contracts/housing-project/RewardSharing.sol": { "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity 0.8.24;\n\nimport \"./HousingSFT.sol\";\n\nuint256 constant DIVISION_SAFETY_CONST = 1_000_000_000_000_000_000;\n\nstruct rewardshares {\n\tuint256 userValue;\n\tuint256 referrerValue;\n}\n\nlibrary RewardShares {\n\tfunction total(rewardshares memory self) internal pure returns (uint256) {\n\t\treturn self.userValue + self.referrerValue;\n\t}\n}\n\nfunction splitReward(uint256 reward) pure returns (rewardshares memory) {\n\tuint256 referrerValue = (reward * 6_66) / 100_00; // would amount to approximately 5% of grand total\n\tuint256 userValue = reward - referrerValue;\n\n\treturn rewardshares(userValue, referrerValue);\n}\n\nfunction computeReward(\n\tHousingAttributes memory attr,\n\tuint256 contractRPS\n) pure returns (uint256) {\n\tif (contractRPS <= attr.rewardsPerShare) {\n\t\treturn 0;\n\t}\n\n\treturn\n\t\t((contractRPS - attr.rewardsPerShare) * attr.tokenWeight) /\n\t\tDIVISION_SAFETY_CONST;\n}\n" @@ -116,7 +116,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\n\nimport \"../../lib/TokenPayments.sol\";\nimport \"./SHT.sol\";\n\n/**\n * @title SHTModule\n * @dev This contract manages the Smart Housing Token (SHT) within the platform.\n * It includes functionalities for making payments in SHT and querying the SHT token ID.\n */\nabstract contract SHTModule is ERC20, ERC20Burnable {\n\tfunction decimals() public pure override returns (uint8) {\n\t\treturn uint8(SHT.DECIMALS);\n\t}\n\n\t/**\n\t * @dev Makes an ERC20TokenPayment struct in SHT for and amount.\n\t * @param shtAmount Amount of SHT to be sent.\n\t * @return payment ERC20TokenPayment struct representing the payment.\n\t */\n\tfunction _makeSHTPayment(\n\t\tuint256 shtAmount\n\t) internal view returns (ERC20TokenPayment memory) {\n\t\treturn ERC20TokenPayment(IERC20(address(this)), shtAmount);\n\t}\n}\n" }, "contracts/project-funding/ProjectFunding.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\";\n\nimport \"../lib/ProjectStorage.sol\";\nimport \"../lib/LkSHTAttributes.sol\";\n\nimport \"../main/Interface.sol\";\n\nimport \"../modules/LockedSmartHousingToken.sol\";\nimport \"../modules/sht-module/SHT.sol\";\n\nimport { HousingSFT } from \"../housing-project/HousingSFT.sol\";\nimport { TokenPayment } from \"../lib/TokenPayments.sol\";\nimport { NewHousingProject, HousingProject } from \"../housing-project/NewHousingProjectLib.sol\";\n\n/**\n * @title ProjectFunding\n * @dev This contract is used for initializing and deploying housing projects.\n * It allows the deployment of a new housing project and manages project data.\n */\ncontract ProjectFunding is Ownable {\n\tusing SafeMath for uint256;\n\tusing ProjectStorage for mapping(uint256 => ProjectStorage.Data);\n\tusing ProjectStorage for ProjectStorage.Data;\n\tusing LkSHTAttributes for LkSHTAttributes.Attributes;\n\n\taddress public coinbase; // Address authorized to initialize the first project, also the housingToken\n\taddress public smartHousingAddress; // Address of the SmartHousing contract\n\n\tmapping(uint256 => ProjectStorage.Data) public projects; // Mapping of project ID to ProjectData\n\tmapping(address => uint256) public projectsId; // Mapping of project address to project ID\n\tuint256 public projectCount; // Counter for the total number of projects\n\n\tmapping(uint256 => mapping(address => uint256)) public usersProjectDeposit;\n\n\tIERC20 public housingToken; // Token used for funding projects\n\tLkSHT public lkSht; // The locked version\n\n\t/**\n\t * @dev Emitted when a new project is deployed.\n\t * @param projectAddress Address of the newly deployed HousingProject contract.\n\t */\n\tevent ProjectDeployed(address indexed projectAddress);\n\tevent ProjectFunded(\n\t\tuint256 indexed projectId,\n\t\taddress indexed depositor,\n\t\tTokenPayment payment\n\t);\n\tevent ProjectTokensClaimed(\n\t\taddress indexed depositor,\n\t\tuint256 projectId,\n\t\tuint256 amount\n\t);\n\n\t/**\n\t * @param _coinbase Address authorized to initialize the first project.\n\t */\n\tconstructor(address _coinbase) {\n\t\tcoinbase = _coinbase;\n\t\tlkSht = NewLkSHT.create();\n\t}\n\n\t/**\n\t * @dev Internal function to deploy a new HousingProject contract.\n\t * @param fundingToken Address of the ERC20 token used for funding.\n\t * @param fundingGoal The funding goal for the new project.\n\t * @param fundingDeadline The deadline for the project funding.\n\t */\n\tfunction _deployProject(\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress fundingToken,\n\t\tuint256 fundingGoal,\n\t\tuint256 fundingDeadline\n\t) internal {\n\t\tHousingProject newProject = NewHousingProject.create(\n\t\t\tname,\n\t\t\tsymbol,\n\t\t\tsmartHousingAddress\n\t\t);\n\t\tProjectStorage.Data memory projectData = projects.createNew(\n\t\t\tprojectsId,\n\t\t\tprojectCount,\n\t\t\tfundingGoal,\n\t\t\tfundingDeadline,\n\t\t\tfundingToken,\n\t\t\taddress(newProject),\n\t\t\taddress(newProject.projectSFT())\n\t\t);\n\t\tprojectCount = projectData.id;\n\n\t\temit ProjectDeployed(projectData.projectAddress);\n\t}\n\n\t/**\n\t * @dev Initializes the first project.\n\t * This function must be called by the coinbase address and can only be called once.\n\t * It sets up the token and deploys the first project.\n\t * @param shtPayment Payment details for the Smart Housing Token (SHT).\n\t * @param smartHousingAddress_ Address of the Smart Housing contract.\n\t * @param fundingToken Address of the ERC20 token used for funding.\n\t * @param fundingGoal The funding goal for the new project.\n\t * @param fundingDeadline The deadline for the project funding.\n\t */\n\tfunction initFirstProject(\n\t\tERC20TokenPayment calldata shtPayment,\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress smartHousingAddress_,\n\t\taddress fundingToken,\n\t\tuint256 fundingGoal,\n\t\tuint256 fundingDeadline\n\t) external {\n\t\trequire(msg.sender == coinbase, \"Caller is not the coinbase\");\n\t\trequire(projectCount == 0, \"Project already initialized\");\n\n\t\tTokenPayments.receiveERC20(shtPayment);\n\t\thousingToken = shtPayment.token;\n\n\t\tsmartHousingAddress = smartHousingAddress_;\n\n\t\t_deployProject(\n\t\t\tname,\n\t\t\tsymbol,\n\t\t\tfundingToken,\n\t\t\tfundingGoal,\n\t\t\tfundingDeadline\n\t\t);\n\t}\n\n\t/**\n\t * @dev Deploys a new project.\n\t * This function can be called multiple times to deploy additional projects.\n\t * @param fundingToken Address of the ERC20 token used for funding.\n\t * @param fundingGoal The funding goal for the new project.\n\t * @param fundingDeadline The deadline for the project funding.\n\t */\n\tfunction deployProject(\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress fundingToken,\n\t\tuint256 fundingGoal,\n\t\tuint256 fundingDeadline\n\t) public onlyOwner {\n\t\t_deployProject(\n\t\t\tname,\n\t\t\tsymbol,\n\t\t\tfundingToken,\n\t\t\tfundingGoal,\n\t\t\tfundingDeadline\n\t\t);\n\t}\n\n\tfunction fundProject(\n\t\tTokenPayment calldata depositPayment,\n\t\tuint256 projectId,\n\t\tuint256 referrerId\n\t) external payable {\n\t\trequire(\n\t\t\tprojectId > 0 && projectId <= projectCount,\n\t\t\t\"Invalid project ID\"\n\t\t);\n\n\t\taddress depositor = msg.sender;\n\n\t\t// Register user with referrer (if needed)\n\t\tISmartHousing(smartHousingAddress).createRefIDViaProxy(\n\t\t\tdepositor,\n\t\t\treferrerId\n\t\t);\n\n\t\t// Update project funding\n\t\tprojects.fund(\n\t\t\tusersProjectDeposit[projectId],\n\t\t\tprojectId,\n\t\t\tdepositor,\n\t\t\tdepositPayment\n\t\t);\n\n\t\temit ProjectFunded(projectId, depositor, depositPayment);\n\t}\n\n\tfunction setProjectToken(uint256 projectId) external onlyOwner {\n\t\tProjectStorage.Data storage project = projects[projectId];\n\n\t\t// TODO Add this after demo\n\t\t// require(\n\t\t// \tproject.status() == ProjectStorage.Status.Successful,\n\t\t// \t\"Project Funding not yet successful\"\n\t\t// );\n\n\t\tISmartHousing(smartHousingAddress).addProject(project.projectAddress);\n\n\t\tHousingProject(project.projectAddress).setTokenDetails(\n\t\t\tproject.collectedFunds,\n\t\t\tcoinbase\n\t\t);\n\t}\n\n\t/**\n\t * @dev Claims project tokens for a given project ID.\n\t * @param projectId The ID of the project to claim tokens from.\n\t */\n\tfunction claimProjectTokens(uint256 projectId) external {\n\t\taddress depositor = msg.sender;\n\n\t\t// Retrieve the project and deposit amount\n\t\t(ProjectStorage.Data memory project, uint256 depositAmount) = projects\n\t\t\t.takeDeposit(usersProjectDeposit[projectId], projectId, depositor);\n\n\t\tHousingSFT(project.tokenAddress).mintSFT(\n\t\t\tdepositAmount,\n\t\t\tdepositor,\n\t\t\tproject.collectedFunds\n\t\t);\n\n\t\t// Mint LkSHT tokens if the project ID is 1\n\t\tif (project.id == 1) {\n\t\t\tuint256 shtAmount = depositAmount.mul(SHT.ICO_FUNDS).div(\n\t\t\t\tproject.collectedFunds\n\t\t\t);\n\n\t\t\tlkSht.mint(shtAmount, depositor);\n\t\t}\n\n\t\temit ProjectTokensClaimed(depositor, projectId, depositAmount);\n\t}\n\n\tfunction unlockSHT(uint256 nonce) external {\n\t\taddress caller = msg.sender;\n\n\t\tuint256 lkShtBal = lkSht.balanceOf(caller, nonce);\n\t\trequire(lkShtBal > 0, \"ProjectFunding: Nothing to unlock\");\n\n\t\tLkSHTAttributes.Attributes memory attr = abi.decode(\n\t\t\tlkSht.getRawTokenAttributes(nonce),\n\t\t\t(LkSHTAttributes.Attributes)\n\t\t);\n\t\t(\n\t\t\tuint256 totalUnlockedAmount,\n\t\t\tLkSHTAttributes.Attributes memory newAttr\n\t\t) = attr.unlockMatured();\n\n\t\tlkSht.update(\n\t\t\tcaller,\n\t\t\tnonce,\n\t\t\tlkShtBal.sub(totalUnlockedAmount),\n\t\t\tabi.encode(newAttr)\n\t\t);\n\n\t\t// Transfer the total unlocked SHT tokens to the user's address\n\t\tif (totalUnlockedAmount > 0) {\n\t\t\thousingToken.transfer(caller, totalUnlockedAmount);\n\t\t}\n\t}\n\n\t/**\n\t * @dev Returns an array of all project IDs and their associated data.\n\t * @return projectList An array of tuples containing project details.\n\t */\n\tfunction allProjects() public view returns (ProjectStorage.Data[] memory) {\n\t\tProjectStorage.Data[] memory projectList = new ProjectStorage.Data[](\n\t\t\tprojectCount\n\t\t);\n\n\t\tfor (uint256 i = 1; i <= projectCount; i++) {\n\t\t\tprojectList[i - 1] = projects[i];\n\t\t}\n\n\t\treturn projectList;\n\t}\n\n\t/**\n\t * @dev Returns the address of the HousingProject contract for a given project ID.\n\t * @param projectId The ID of the project.\n\t * @return projectAddress The address of the HousingProject contract.\n\t */\n\tfunction getProjectAddress(\n\t\tuint256 projectId\n\t) external view returns (address projectAddress) {\n\t\tProjectStorage.Data storage project = projects[projectId];\n\t\treturn project.projectAddress;\n\t}\n\n\t/**\n\t * @dev Returns the details of a project by its ID.\n\t * @param projectId The ID of the project.\n\t * @return id The project ID.\n\t * @return fundingGoal The funding goal of the project.\n\t * @return fundingDeadline The deadline for the project funding.\n\t * @return fundingToken The address of the ERC20 token used for funding.\n\t * @return projectAddress The address of the HousingProject contract.\n\t * @return status The funding status of the project.\n\t * @return collectedFunds The amount of funds collected.\n\t */\n\tfunction getProjectData(\n\t\tuint256 projectId\n\t)\n\t\texternal\n\t\tview\n\t\treturns (\n\t\t\tuint256 id,\n\t\t\tuint256 fundingGoal,\n\t\t\tuint256 fundingDeadline,\n\t\t\taddress fundingToken,\n\t\t\taddress projectAddress,\n\t\t\tuint8 status,\n\t\t\tuint256 collectedFunds\n\t\t)\n\t{\n\t\tProjectStorage.Data storage project = projects[projectId];\n\t\treturn (\n\t\t\tproject.id,\n\t\t\tproject.fundingGoal,\n\t\t\tproject.fundingDeadline,\n\t\t\tproject.fundingToken,\n\t\t\tproject.projectAddress,\n\t\t\tuint8(project.status()),\n\t\t\tproject.collectedFunds\n\t\t);\n\t}\n}\n" + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\";\n\nimport \"../lib/ProjectStorage.sol\";\nimport \"../lib/LkSHTAttributes.sol\";\n\nimport \"../main/Interface.sol\";\n\nimport \"../modules/LockedSmartHousingToken.sol\";\nimport \"../modules/sht-module/SHT.sol\";\n\nimport { HousingSFT } from \"../housing-project/HousingSFT.sol\";\nimport { TokenPayment } from \"../lib/TokenPayments.sol\";\nimport { NewHousingProject, HousingProject } from \"../housing-project/NewHousingProjectLib.sol\";\n\n/**\n * @title ProjectFunding\n * @dev This contract is used for initializing and deploying housing projects.\n * It allows the deployment of a new housing project and manages project data.\n */\ncontract ProjectFunding is Ownable {\n\tusing SafeMath for uint256;\n\tusing ProjectStorage for mapping(uint256 => ProjectStorage.Data);\n\tusing ProjectStorage for ProjectStorage.Data;\n\tusing LkSHTAttributes for LkSHTAttributes.Attributes;\n\n\taddress public coinbase; // Address authorized to initialize the first project, also the housingToken\n\taddress public smartHousingAddress; // Address of the SmartHousing contract\n\n\tmapping(uint256 => ProjectStorage.Data) public projects; // Mapping of project ID to ProjectData\n\tmapping(address => uint256) public projectsId; // Mapping of project address to project ID\n\tuint256 public projectCount; // Counter for the total number of projects\n\n\tmapping(uint256 => mapping(address => uint256)) public usersProjectDeposit;\n\n\tIERC20 public housingToken; // Token used for funding projects\n\tLkSHT public lkSht; // The locked version\n\n\t/**\n\t * @dev Emitted when a new project is deployed.\n\t * @param projectAddress Address of the newly deployed HousingProject contract.\n\t */\n\tevent ProjectDeployed(address indexed projectAddress);\n\tevent ProjectFunded(\n\t\tuint256 indexed projectId,\n\t\taddress indexed depositor,\n\t\tTokenPayment payment\n\t);\n\tevent ProjectTokensClaimed(\n\t\taddress indexed depositor,\n\t\tuint256 projectId,\n\t\tuint256 amount\n\t);\n\n\t/**\n\t * @param _coinbase Address authorized to initialize the first project.\n\t */\n\tconstructor(address _coinbase) {\n\t\tcoinbase = _coinbase;\n\t\tlkSht = NewLkSHT.create();\n\t}\n\n\t/**\n\t * @dev Internal function to deploy a new HousingProject contract.\n\t * @param fundingToken Address of the ERC20 token used for funding.\n\t * @param fundingGoal The funding goal for the new project.\n\t * @param fundingDeadline The deadline for the project funding.\n\t */\n\tfunction _deployProject(\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress fundingToken,\n\t\tuint256 fundingGoal,\n\t\tuint256 fundingDeadline\n\t) internal {\n\t\tHousingProject newProject = NewHousingProject.create(\n\t\t\tname,\n\t\t\tsymbol,\n\t\t\tsmartHousingAddress\n\t\t);\n\t\tProjectStorage.Data memory projectData = projects.createNew(\n\t\t\tprojectsId,\n\t\t\tprojectCount,\n\t\t\tfundingGoal,\n\t\t\tfundingDeadline,\n\t\t\tfundingToken,\n\t\t\taddress(newProject),\n\t\t\taddress(newProject.projectSFT())\n\t\t);\n\t\tprojectCount = projectData.id;\n\n\t\temit ProjectDeployed(projectData.projectAddress);\n\t}\n\n\t/**\n\t * @dev Initializes the first project.\n\t * This function must be called by the coinbase address and can only be called once.\n\t * It sets up the token and deploys the first project.\n\t * @param shtPayment Payment details for the Smart Housing Token (SHT).\n\t * @param smartHousingAddress_ Address of the Smart Housing contract.\n\t * @param fundingToken Address of the ERC20 token used for funding.\n\t * @param fundingGoal The funding goal for the new project.\n\t * @param fundingDeadline The deadline for the project funding.\n\t */\n\tfunction initFirstProject(\n\t\tERC20TokenPayment calldata shtPayment,\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress smartHousingAddress_,\n\t\taddress fundingToken,\n\t\tuint256 fundingGoal,\n\t\tuint256 fundingDeadline\n\t) external {\n\t\trequire(msg.sender == coinbase, \"Caller is not the coinbase\");\n\t\trequire(projectCount == 0, \"Project already initialized\");\n\n\t\tTokenPayments.receiveERC20(shtPayment);\n\t\thousingToken = shtPayment.token;\n\n\t\tsmartHousingAddress = smartHousingAddress_;\n\n\t\t_deployProject(\n\t\t\tname,\n\t\t\tsymbol,\n\t\t\tfundingToken,\n\t\t\tfundingGoal,\n\t\t\tfundingDeadline\n\t\t);\n\t}\n\n\t/**\n\t * @dev Deploys a new project.\n\t * This function can be called multiple times to deploy additional projects.\n\t * @param fundingToken Address of the ERC20 token used for funding.\n\t * @param fundingGoal The funding goal for the new project.\n\t * @param fundingDeadline The deadline for the project funding.\n\t */\n\tfunction deployProject(\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress fundingToken,\n\t\tuint256 fundingGoal,\n\t\tuint256 fundingDeadline\n\t) public onlyOwner {\n\t\t_deployProject(\n\t\t\tname,\n\t\t\tsymbol,\n\t\t\tfundingToken,\n\t\t\tfundingGoal,\n\t\t\tfundingDeadline\n\t\t);\n\t}\n\n\tfunction fundProject(\n\t\tTokenPayment calldata depositPayment,\n\t\tuint256 projectId,\n\t\tuint256 referrerId\n\t) external payable {\n\t\trequire(\n\t\t\tprojectId > 0 && projectId <= projectCount,\n\t\t\t\"Invalid project ID\"\n\t\t);\n\n\t\taddress depositor = msg.sender;\n\n\t\t// Register user with referrer (if needed)\n\t\tISmartHousing(smartHousingAddress).createRefIDViaProxy(\n\t\t\tdepositor,\n\t\t\treferrerId\n\t\t);\n\n\t\t// Update project funding\n\t\tprojects.fund(\n\t\t\tusersProjectDeposit[projectId],\n\t\t\tprojectId,\n\t\t\tdepositor,\n\t\t\tdepositPayment\n\t\t);\n\n\t\temit ProjectFunded(projectId, depositor, depositPayment);\n\t}\n\n\tfunction addProjectToEcosystem(uint256 projectId) external onlyOwner {\n\t\tProjectStorage.Data storage project = projects[projectId];\n\n\t\t// TODO Add this after demo\n\t\t// require(\n\t\t// \tproject.status() == ProjectStorage.Status.Successful,\n\t\t// \t\"Project Funding not yet successful\"\n\t\t// );\n\n\t\tISmartHousing(smartHousingAddress).addProject(project.projectAddress);\n\n\t\tHousingProject(project.projectAddress).setTokenDetails(\n\t\t\tproject.collectedFunds,\n\t\t\tcoinbase\n\t\t);\n\t}\n\n\t/**\n\t * @dev Claims project tokens for a given project ID.\n\t * @param projectId The ID of the project to claim tokens from.\n\t */\n\tfunction claimProjectTokens(uint256 projectId) external {\n\t\taddress depositor = msg.sender;\n\n\t\t// Retrieve the project and deposit amount\n\t\t(ProjectStorage.Data memory project, uint256 depositAmount) = projects\n\t\t\t.takeDeposit(usersProjectDeposit[projectId], projectId, depositor);\n\n\t\tHousingSFT(project.tokenAddress).mintSFT(\n\t\t\tdepositAmount,\n\t\t\tdepositor,\n\t\t\tproject.collectedFunds\n\t\t);\n\n\t\t// Mint LkSHT tokens if the project ID is 1\n\t\tif (project.id == 1) {\n\t\t\tuint256 shtAmount = depositAmount.mul(SHT.ICO_FUNDS).div(\n\t\t\t\tproject.collectedFunds\n\t\t\t);\n\n\t\t\tlkSht.mint(shtAmount, depositor);\n\t\t}\n\n\t\temit ProjectTokensClaimed(depositor, projectId, depositAmount);\n\t}\n\n\tfunction unlockSHT(uint256 nonce) external {\n\t\taddress caller = msg.sender;\n\n\t\tuint256 lkShtBal = lkSht.balanceOf(caller, nonce);\n\t\trequire(lkShtBal > 0, \"ProjectFunding: Nothing to unlock\");\n\n\t\tLkSHTAttributes.Attributes memory attr = abi.decode(\n\t\t\tlkSht.getRawTokenAttributes(nonce),\n\t\t\t(LkSHTAttributes.Attributes)\n\t\t);\n\t\t(\n\t\t\tuint256 totalUnlockedAmount,\n\t\t\tLkSHTAttributes.Attributes memory newAttr\n\t\t) = attr.unlockMatured();\n\n\t\tlkSht.update(\n\t\t\tcaller,\n\t\t\tnonce,\n\t\t\tlkShtBal.sub(totalUnlockedAmount),\n\t\t\tabi.encode(newAttr)\n\t\t);\n\n\t\t// Transfer the total unlocked SHT tokens to the user's address\n\t\tif (totalUnlockedAmount > 0) {\n\t\t\thousingToken.transfer(caller, totalUnlockedAmount);\n\t\t}\n\t}\n\n\t/**\n\t * @dev Returns an array of all project IDs and their associated data.\n\t * @return projectList An array of tuples containing project details.\n\t */\n\tfunction allProjects() public view returns (ProjectStorage.Data[] memory) {\n\t\tProjectStorage.Data[] memory projectList = new ProjectStorage.Data[](\n\t\t\tprojectCount\n\t\t);\n\n\t\tfor (uint256 i = 1; i <= projectCount; i++) {\n\t\t\tprojectList[i - 1] = projects[i];\n\t\t}\n\n\t\treturn projectList;\n\t}\n\n\t/**\n\t * @dev Returns the address of the HousingProject contract for a given project ID.\n\t * @param projectId The ID of the project.\n\t * @return projectAddress The address of the HousingProject contract.\n\t */\n\tfunction getProjectAddress(\n\t\tuint256 projectId\n\t) external view returns (address projectAddress) {\n\t\tProjectStorage.Data storage project = projects[projectId];\n\t\treturn project.projectAddress;\n\t}\n\n\t/**\n\t * @dev Returns the details of a project by its ID.\n\t * @param projectId The ID of the project.\n\t * @return id The project ID.\n\t * @return fundingGoal The funding goal of the project.\n\t * @return fundingDeadline The deadline for the project funding.\n\t * @return fundingToken The address of the ERC20 token used for funding.\n\t * @return projectAddress The address of the HousingProject contract.\n\t * @return status The funding status of the project.\n\t * @return collectedFunds The amount of funds collected.\n\t */\n\tfunction getProjectData(\n\t\tuint256 projectId\n\t)\n\t\texternal\n\t\tview\n\t\treturns (\n\t\t\tuint256 id,\n\t\t\tuint256 fundingGoal,\n\t\t\tuint256 fundingDeadline,\n\t\t\taddress fundingToken,\n\t\t\taddress projectAddress,\n\t\t\tuint8 status,\n\t\t\tuint256 collectedFunds\n\t\t)\n\t{\n\t\tProjectStorage.Data storage project = projects[projectId];\n\t\treturn (\n\t\t\tproject.id,\n\t\t\tproject.fundingGoal,\n\t\t\tproject.fundingDeadline,\n\t\t\tproject.fundingToken,\n\t\t\tproject.projectAddress,\n\t\t\tuint8(project.status()),\n\t\t\tproject.collectedFunds\n\t\t);\n\t}\n}\n" }, "prb-math/contracts/PRBMath.sol": { "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\n\n/// @notice Emitted when one of the inputs is type(int256).min.\nerror PRBMath__MulDivSignedInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows int256.\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is MIN_SD59x18.\nerror PRBMathSD59x18__AbsInputTooSmall();\n\n/// @notice Emitted when ceiling a number overflows SD59x18.\nerror PRBMathSD59x18__CeilOverflow(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__DivInputTooSmall();\n\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\n\n/// @notice Emitted when flooring a number underflows SD59x18.\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\n\n/// @notice Emitted when the product of the inputs is negative.\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\n\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\n\n/// @notice Emitted when the input is less than or equal to zero.\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__MulInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is negative.\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\n\n/// @notice Emitted when the calculating the square root overflows SD59x18.\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\n\n/// @notice Emitted when addition overflows UD60x18.\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when ceiling a number overflows UD60x18.\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\n\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when the input is less than 1.\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\n\n/// @notice Emitted when the calculating the square root overflows UD60x18.\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\n\n/// @notice Emitted when subtraction underflows UD60x18.\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\n\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\nlibrary PRBMath {\n /// STRUCTS ///\n\n struct SD59x18 {\n int256 value;\n }\n\n struct UD60x18 {\n uint256 value;\n }\n\n /// STORAGE ///\n\n /// @dev How many trailing decimals can be represented.\n uint256 internal constant SCALE = 1e18;\n\n /// @dev Largest power of two divisor of SCALE.\n uint256 internal constant SCALE_LPOTD = 262144;\n\n /// @dev SCALE inverted mod 2^256.\n uint256 internal constant SCALE_INVERSE =\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\n\n /// FUNCTIONS ///\n\n /// @notice Calculates the binary exponent of x using the binary fraction method.\n /// @dev Has to use 192.64-bit fixed-point numbers.\n /// See https://ethereum.stackexchange.com/a/96594/24693.\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n function exp2(uint256 x) internal pure returns (uint256 result) {\n unchecked {\n // Start from 0.5 in the 192.64-bit fixed-point format.\n result = 0x800000000000000000000000000000000000000000000000;\n\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\n // because the initial result is 2^191 and all magic factors are less than 2^65.\n if (x & 0x8000000000000000 > 0) {\n result = (result * 0x16A09E667F3BCC909) >> 64;\n }\n if (x & 0x4000000000000000 > 0) {\n result = (result * 0x1306FE0A31B7152DF) >> 64;\n }\n if (x & 0x2000000000000000 > 0) {\n result = (result * 0x1172B83C7D517ADCE) >> 64;\n }\n if (x & 0x1000000000000000 > 0) {\n result = (result * 0x10B5586CF9890F62A) >> 64;\n }\n if (x & 0x800000000000000 > 0) {\n result = (result * 0x1059B0D31585743AE) >> 64;\n }\n if (x & 0x400000000000000 > 0) {\n result = (result * 0x102C9A3E778060EE7) >> 64;\n }\n if (x & 0x200000000000000 > 0) {\n result = (result * 0x10163DA9FB33356D8) >> 64;\n }\n if (x & 0x100000000000000 > 0) {\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\n }\n if (x & 0x80000000000000 > 0) {\n result = (result * 0x10058C86DA1C09EA2) >> 64;\n }\n if (x & 0x40000000000000 > 0) {\n result = (result * 0x1002C605E2E8CEC50) >> 64;\n }\n if (x & 0x20000000000000 > 0) {\n result = (result * 0x100162F3904051FA1) >> 64;\n }\n if (x & 0x10000000000000 > 0) {\n result = (result * 0x1000B175EFFDC76BA) >> 64;\n }\n if (x & 0x8000000000000 > 0) {\n result = (result * 0x100058BA01FB9F96D) >> 64;\n }\n if (x & 0x4000000000000 > 0) {\n result = (result * 0x10002C5CC37DA9492) >> 64;\n }\n if (x & 0x2000000000000 > 0) {\n result = (result * 0x1000162E525EE0547) >> 64;\n }\n if (x & 0x1000000000000 > 0) {\n result = (result * 0x10000B17255775C04) >> 64;\n }\n if (x & 0x800000000000 > 0) {\n result = (result * 0x1000058B91B5BC9AE) >> 64;\n }\n if (x & 0x400000000000 > 0) {\n result = (result * 0x100002C5C89D5EC6D) >> 64;\n }\n if (x & 0x200000000000 > 0) {\n result = (result * 0x10000162E43F4F831) >> 64;\n }\n if (x & 0x100000000000 > 0) {\n result = (result * 0x100000B1721BCFC9A) >> 64;\n }\n if (x & 0x80000000000 > 0) {\n result = (result * 0x10000058B90CF1E6E) >> 64;\n }\n if (x & 0x40000000000 > 0) {\n result = (result * 0x1000002C5C863B73F) >> 64;\n }\n if (x & 0x20000000000 > 0) {\n result = (result * 0x100000162E430E5A2) >> 64;\n }\n if (x & 0x10000000000 > 0) {\n result = (result * 0x1000000B172183551) >> 64;\n }\n if (x & 0x8000000000 > 0) {\n result = (result * 0x100000058B90C0B49) >> 64;\n }\n if (x & 0x4000000000 > 0) {\n result = (result * 0x10000002C5C8601CC) >> 64;\n }\n if (x & 0x2000000000 > 0) {\n result = (result * 0x1000000162E42FFF0) >> 64;\n }\n if (x & 0x1000000000 > 0) {\n result = (result * 0x10000000B17217FBB) >> 64;\n }\n if (x & 0x800000000 > 0) {\n result = (result * 0x1000000058B90BFCE) >> 64;\n }\n if (x & 0x400000000 > 0) {\n result = (result * 0x100000002C5C85FE3) >> 64;\n }\n if (x & 0x200000000 > 0) {\n result = (result * 0x10000000162E42FF1) >> 64;\n }\n if (x & 0x100000000 > 0) {\n result = (result * 0x100000000B17217F8) >> 64;\n }\n if (x & 0x80000000 > 0) {\n result = (result * 0x10000000058B90BFC) >> 64;\n }\n if (x & 0x40000000 > 0) {\n result = (result * 0x1000000002C5C85FE) >> 64;\n }\n if (x & 0x20000000 > 0) {\n result = (result * 0x100000000162E42FF) >> 64;\n }\n if (x & 0x10000000 > 0) {\n result = (result * 0x1000000000B17217F) >> 64;\n }\n if (x & 0x8000000 > 0) {\n result = (result * 0x100000000058B90C0) >> 64;\n }\n if (x & 0x4000000 > 0) {\n result = (result * 0x10000000002C5C860) >> 64;\n }\n if (x & 0x2000000 > 0) {\n result = (result * 0x1000000000162E430) >> 64;\n }\n if (x & 0x1000000 > 0) {\n result = (result * 0x10000000000B17218) >> 64;\n }\n if (x & 0x800000 > 0) {\n result = (result * 0x1000000000058B90C) >> 64;\n }\n if (x & 0x400000 > 0) {\n result = (result * 0x100000000002C5C86) >> 64;\n }\n if (x & 0x200000 > 0) {\n result = (result * 0x10000000000162E43) >> 64;\n }\n if (x & 0x100000 > 0) {\n result = (result * 0x100000000000B1721) >> 64;\n }\n if (x & 0x80000 > 0) {\n result = (result * 0x10000000000058B91) >> 64;\n }\n if (x & 0x40000 > 0) {\n result = (result * 0x1000000000002C5C8) >> 64;\n }\n if (x & 0x20000 > 0) {\n result = (result * 0x100000000000162E4) >> 64;\n }\n if (x & 0x10000 > 0) {\n result = (result * 0x1000000000000B172) >> 64;\n }\n if (x & 0x8000 > 0) {\n result = (result * 0x100000000000058B9) >> 64;\n }\n if (x & 0x4000 > 0) {\n result = (result * 0x10000000000002C5D) >> 64;\n }\n if (x & 0x2000 > 0) {\n result = (result * 0x1000000000000162E) >> 64;\n }\n if (x & 0x1000 > 0) {\n result = (result * 0x10000000000000B17) >> 64;\n }\n if (x & 0x800 > 0) {\n result = (result * 0x1000000000000058C) >> 64;\n }\n if (x & 0x400 > 0) {\n result = (result * 0x100000000000002C6) >> 64;\n }\n if (x & 0x200 > 0) {\n result = (result * 0x10000000000000163) >> 64;\n }\n if (x & 0x100 > 0) {\n result = (result * 0x100000000000000B1) >> 64;\n }\n if (x & 0x80 > 0) {\n result = (result * 0x10000000000000059) >> 64;\n }\n if (x & 0x40 > 0) {\n result = (result * 0x1000000000000002C) >> 64;\n }\n if (x & 0x20 > 0) {\n result = (result * 0x10000000000000016) >> 64;\n }\n if (x & 0x10 > 0) {\n result = (result * 0x1000000000000000B) >> 64;\n }\n if (x & 0x8 > 0) {\n result = (result * 0x10000000000000006) >> 64;\n }\n if (x & 0x4 > 0) {\n result = (result * 0x10000000000000003) >> 64;\n }\n if (x & 0x2 > 0) {\n result = (result * 0x10000000000000001) >> 64;\n }\n if (x & 0x1 > 0) {\n result = (result * 0x10000000000000001) >> 64;\n }\n\n // We're doing two things at the same time:\n //\n // 1. Multiply the result by 2^n + 1, where \"2^n\" is the integer part and the one is added to account for\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\n // rather than 192.\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\n //\n // This works because 2^(191-ip) = 2^ip / 2^191, where \"ip\" is the integer part \"2^n\".\n result *= SCALE;\n result >>= (191 - (x >> 64));\n }\n }\n\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\n /// @dev See the note on msb in the \"Find First Set\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\n /// @param x The uint256 number for which to find the index of the most significant bit.\n /// @return msb The index of the most significant bit as an uint256.\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\n if (x >= 2**128) {\n x >>= 128;\n msb += 128;\n }\n if (x >= 2**64) {\n x >>= 64;\n msb += 64;\n }\n if (x >= 2**32) {\n x >>= 32;\n msb += 32;\n }\n if (x >= 2**16) {\n x >>= 16;\n msb += 16;\n }\n if (x >= 2**8) {\n x >>= 8;\n msb += 8;\n }\n if (x >= 2**4) {\n x >>= 4;\n msb += 4;\n }\n if (x >= 2**2) {\n x >>= 2;\n msb += 2;\n }\n if (x >= 2**1) {\n // No need to shift x any more.\n msb += 1;\n }\n }\n\n /// @notice Calculates floor(x*y÷denominator) with full precision.\n ///\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\n ///\n /// Requirements:\n /// - The denominator cannot be zero.\n /// - The result must fit within uint256.\n ///\n /// Caveats:\n /// - This function does not work with fixed-point numbers.\n ///\n /// @param x The multiplicand as an uint256.\n /// @param y The multiplier as an uint256.\n /// @param denominator The divisor as an uint256.\n /// @return result The result as an uint256.\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n unchecked {\n result = prod0 / denominator;\n }\n return result;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n if (prod1 >= denominator) {\n revert PRBMath__MulDivOverflow(prod1, denominator);\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n unchecked {\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 lpotdod = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by lpotdod.\n denominator := div(denominator, lpotdod)\n\n // Divide [prod1 prod0] by lpotdod.\n prod0 := div(prod0, lpotdod)\n\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * lpotdod;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /// @notice Calculates floor(x*y÷1e18) with full precision.\n ///\n /// @dev Variant of \"mulDiv\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\n /// being rounded to 1e-18. See \"Listing 6\" and text above it at https://accu.org/index.php/journals/1717.\n ///\n /// Requirements:\n /// - The result must fit within uint256.\n ///\n /// Caveats:\n /// - The body is purposely left uncommented; see the NatSpec comments in \"PRBMath.mulDiv\" to understand how this works.\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\n /// 1. x * y = type(uint256).max * SCALE\n /// 2. (x * y) % SCALE >= SCALE / 2\n ///\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\n uint256 prod0;\n uint256 prod1;\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n if (prod1 >= SCALE) {\n revert PRBMath__MulDivFixedPointOverflow(prod1);\n }\n\n uint256 remainder;\n uint256 roundUpUnit;\n assembly {\n remainder := mulmod(x, y, SCALE)\n roundUpUnit := gt(remainder, 499999999999999999)\n }\n\n if (prod1 == 0) {\n unchecked {\n result = (prod0 / SCALE) + roundUpUnit;\n return result;\n }\n }\n\n assembly {\n result := add(\n mul(\n or(\n div(sub(prod0, remainder), SCALE_LPOTD),\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\n ),\n SCALE_INVERSE\n ),\n roundUpUnit\n )\n }\n }\n\n /// @notice Calculates floor(x*y÷denominator) with full precision.\n ///\n /// @dev An extension of \"mulDiv\" for signed numbers. Works by computing the signs and the absolute values separately.\n ///\n /// Requirements:\n /// - None of the inputs can be type(int256).min.\n /// - The result must fit within int256.\n ///\n /// @param x The multiplicand as an int256.\n /// @param y The multiplier as an int256.\n /// @param denominator The divisor as an int256.\n /// @return result The result as an int256.\n function mulDivSigned(\n int256 x,\n int256 y,\n int256 denominator\n ) internal pure returns (int256 result) {\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\n revert PRBMath__MulDivSignedInputTooSmall();\n }\n\n // Get hold of the absolute values of x, y and the denominator.\n uint256 ax;\n uint256 ay;\n uint256 ad;\n unchecked {\n ax = x < 0 ? uint256(-x) : uint256(x);\n ay = y < 0 ? uint256(-y) : uint256(y);\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\n }\n\n // Compute the absolute value of (x*y)÷denominator. The result must fit within int256.\n uint256 rAbs = mulDiv(ax, ay, ad);\n if (rAbs > uint256(type(int256).max)) {\n revert PRBMath__MulDivSignedOverflow(rAbs);\n }\n\n // Get the signs of x, y and the denominator.\n uint256 sx;\n uint256 sy;\n uint256 sd;\n assembly {\n sx := sgt(x, sub(0, 1))\n sy := sgt(y, sub(0, 1))\n sd := sgt(denominator, sub(0, 1))\n }\n\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\n // If yes, the result should be negative.\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\n }\n\n /// @notice Calculates the square root of x, rounding down.\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n ///\n /// Caveats:\n /// - This function does not work with fixed-point numbers.\n ///\n /// @param x The uint256 number for which to calculate the square root.\n /// @return result The result as an uint256.\n function sqrt(uint256 x) internal pure returns (uint256 result) {\n if (x == 0) {\n return 0;\n }\n\n // Set the initial guess to the least power of two that is greater than or equal to sqrt(x).\n uint256 xAux = uint256(x);\n result = 1;\n if (xAux >= 0x100000000000000000000000000000000) {\n xAux >>= 128;\n result <<= 64;\n }\n if (xAux >= 0x10000000000000000) {\n xAux >>= 64;\n result <<= 32;\n }\n if (xAux >= 0x100000000) {\n xAux >>= 32;\n result <<= 16;\n }\n if (xAux >= 0x10000) {\n xAux >>= 16;\n result <<= 8;\n }\n if (xAux >= 0x100) {\n xAux >>= 8;\n result <<= 4;\n }\n if (xAux >= 0x10) {\n xAux >>= 4;\n result <<= 2;\n }\n if (xAux >= 0x8) {\n result <<= 1;\n }\n\n // The operations can never overflow because the result is max 2^127 when it enters this block.\n unchecked {\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1; // Seven iterations should be enough\n uint256 roundedDownResult = x / result;\n return result >= roundedDownResult ? roundedDownResult : result;\n }\n }\n}\n" diff --git a/packages/backend/deployments/opbnb/solcInputs/a3834a2f81eba945e2e32ba65dfaced7.json b/packages/backend/deployments/opbnb/solcInputs/a3834a2f81eba945e2e32ba65dfaced7.json index d869d41..4f61422 100644 --- a/packages/backend/deployments/opbnb/solcInputs/a3834a2f81eba945e2e32ba65dfaced7.json +++ b/packages/backend/deployments/opbnb/solcInputs/a3834a2f81eba945e2e32ba65dfaced7.json @@ -65,7 +65,7 @@ "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\n\nimport \"../modules/SFT.sol\";\n\nstruct HousingAttributes {\n\tuint256 rewardsPerShare;\n\taddress originalOwner;\n\tuint256 tokenWeight;\n}\n\n/// @title Housing SFT\n/// @notice This contract represents a semi-fungible token (SFT) for housing projects.\n/// @dev This contract will be inherited by the HousingProject contract.\ncontract HousingSFT is SFT {\n\tusing EnumerableSet for EnumerableSet.UintSet;\n\n\tstruct HousingSFTBalance {\n\t\tuint256 nonce;\n\t\tuint256 amount;\n\t\tHousingAttributes attributes;\n\t}\n\n\t// FIXME this value should be unique to each contract, should depend on\n\t// the total amount expected to raise as it determines the amount of SFTs to\n\t// be minted for investors\n\tuint256 public constant MAX_SUPPLY = 1_000_000;\n\n\t/// @notice The amount of fungible tokens collected from investors to finance the development of this housing project.\n\tuint256 public amountRaised;\n\n\t/// @notice The current amount out of the `MAX_SUPPLY` of tokens minted.\n\tuint256 public totalSupply;\n\n\tconstructor(\n\t\tstring memory name_,\n\t\tstring memory symbol_\n\t) SFT(name_, symbol_) {}\n\n\tfunction setAmountRaised(uint256 amountRaised_) external onlyOwner {\n\t\tamountRaised = amountRaised_;\n\t}\n\n\tmodifier canMint() {\n\t\taddress sftOwner = owner();\n\n\t\trequire(\n\t\t\tOwnable(sftOwner).owner() == _msgSender(),\n\t\t\t\"not allowed to mint\"\n\t\t);\n\n\t\t_;\n\t}\n\n\t/// @notice Mints SFT tokens for a depositor based on the amount of deposit.\n\t/// @param depositAmt The amount of fungible token deposited.\n\t/// @param depositor The address of the depositor.\n\tfunction mintSFT(\n\t\tuint256 depositAmt,\n\t\taddress depositor,\n\t\tuint256 amount_raised\n\t) external canMint returns (uint256) {\n\t\t// TODO remove after demo due to not beign able to move blocks in public networks\n\t\t{\n\t\t\tamountRaised = amount_raised;\n\t\t}\n\n\t\tuint256 totalDeposits = amountRaised;\n\t\tuint256 maxShares = MAX_SUPPLY;\n\n\t\trequire(totalDeposits > 0, \"HousingSFT: No deposits recorded\");\n\n\t\tuint256 mintShare = (depositAmt * maxShares) / totalDeposits;\n\t\trequire(mintShare > 0, \"HousingSFT: Computed token shares is invalid\");\n\n\t\ttotalSupply += mintShare;\n\t\trequire(totalSupply <= MAX_SUPPLY, \"HousingSFT: Max supply exceeded\");\n\n\t\tbytes memory attributes = abi.encode(\n\t\t\tHousingAttributes({\n\t\t\t\trewardsPerShare: 0, // Should be 0 since they have never claimed any rent rewards\n\t\t\t\toriginalOwner: depositor,\n\t\t\t\ttokenWeight: mintShare\n\t\t\t})\n\t\t);\n\n\t\treturn _mint(depositor, mintShare, attributes, \"\");\n\t}\n\n\t/// @notice Checks if an address owns this HousingSFT and returns the attributes.\n\t/// @param owner The address to check the balance of.\n\t/// @return `HousingAttributes` if the owner has a positive balance of the token, panics otherwise.\n\tfunction getUserSFT(\n\t\taddress owner,\n\t\tuint256 nonce\n\t) public view returns (HousingAttributes memory) {\n\t\trequire(\n\t\t\thasSFT(owner, nonce),\n\t\t\t\"HouisingSFT: No tokens found for user at nonce\"\n\t\t);\n\n\t\treturn abi.decode(getRawTokenAttributes(nonce), (HousingAttributes));\n\t}\n\n\tfunction getMaxSupply() public pure returns (uint256) {\n\t\treturn MAX_SUPPLY;\n\t}\n\n\tfunction sftBalance(\n\t\taddress user\n\t) public view returns (HousingSFTBalance[] memory) {\n\t\tSftBalance[] memory _sftBals = _sftBalance(user);\n\t\tHousingSFTBalance[] memory balance = new HousingSFTBalance[](\n\t\t\t_sftBals.length\n\t\t);\n\n\t\tfor (uint256 i; i < _sftBals.length; i++) {\n\t\t\tSftBalance memory _sftBal = _sftBals[i];\n\n\t\t\tbalance[i] = HousingSFTBalance({\n\t\t\t\tnonce: _sftBal.nonce,\n\t\t\t\tamount: _sftBal.amount,\n\t\t\t\tattributes: abi.decode(_sftBal.attributes, (HousingAttributes))\n\t\t\t});\n\t\t}\n\n\t\treturn balance;\n\t}\n\n\tfunction tokenDetails()\n\t\tpublic\n\t\tview\n\t\treturns (string memory, string memory, uint256)\n\t{\n\t\treturn (name(), symbol(), getMaxSupply());\n\t}\n}\n" }, "contracts/housing-project/RentsModule.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\n\nimport \"./HousingSFT.sol\";\nimport \"./RewardSharing.sol\";\nimport \"../lib/TokenPayments.sol\";\nimport \"./CallsSmartHousing.sol\";\n\n/// @title Rents Module\n/// @notice Handles rent payments, reward calculations, and distribution for Housing projects.\n/// @dev This abstract contract should be inherited by the HousingProject contract.\nabstract contract RentsModule is CallsSmartHousing {\n\tusing TokenPayments for ERC20TokenPayment;\n\tusing RewardShares for rewardshares;\n\n\tuint256 public rewardPerShare;\n\tuint256 public rewardsReserve;\n\tuint256 public facilityManagementFunds;\n\n\tERC20Burnable housingToken;\n\tHousingSFT public projectSFT;\n\n\t/// @notice Receives rent payments and distributes rewards.\n\t/// @param rentPayment The details of the rent payment.\n\tfunction receiveRent(ERC20TokenPayment calldata rentPayment) external {\n\t\t// TODO set the appropriate rent per Project\n\t\trequire(\n\t\t\trentPayment.amount > 0,\n\t\t\t\"RentsModule: Insufficient rent amount\"\n\t\t);\n\t\trequire(\n\t\t\trentPayment.token == housingToken,\n\t\t\t\"RentsModule: Invalid rent payment token\"\n\t\t);\n\t\trentPayment.receiveERC20();\n\n\t\tuint256 rentReward = (rentPayment.amount * 75) / 100;\n\t\tuint256 ecosystemReward = (rentPayment.amount * 18) / 100;\n\t\tuint256 facilityReward = (rentPayment.amount * 7) / 100;\n\n\t\tuint256 allShares = projectSFT.getMaxSupply();\n\t\tuint256 rpsIncrease = (rentReward * DIVISION_SAFETY_CONST) / allShares;\n\n\t\trewardPerShare += rpsIncrease;\n\t\trewardsReserve += rentReward;\n\t\tfacilityManagementFunds += facilityReward;\n\n\t\thousingToken.burn(ecosystemReward);\n\t\tISmartHousing(smartHousingAddr).addProjectRent(rentPayment.amount);\n\t}\n\n\t/// @notice Claims rent rewards for a given token.\n\t/// @return The updated HousingAttributes.\n\tfunction claimRentReward(\n\t\tuint256 nonce\n\t) external returns (HousingAttributes memory, rewardshares memory) {\n\t\taddress caller = msg.sender;\n\t\tuint256 currentRPS = rewardPerShare;\n\n\t\tHousingAttributes memory attr = projectSFT.getUserSFT(caller, nonce);\n\t\trewardshares memory rewardShares = computeRewardShares(attr);\n\t\tuint256 totalReward = rewardShares.total();\n\n\t\tif (totalReward == 0) {\n\t\t\t// Fail silently\n\t\t\treturn (attr, rewardShares);\n\t\t}\n\n\t\trequire(rewardsReserve >= totalReward, \"Computed rewards too large\");\n\n\t\trewardsReserve -= totalReward;\n\n\t\t// We use original owner since we are certain they are registered\n\t\t(, address referrer) = getReferrer(attr.originalOwner);\n\t\tif (rewardShares.referrerValue > 0) {\n\t\t\tif (referrer != address(0)) {\n\t\t\t\thousingToken.transfer(referrer, rewardShares.referrerValue); // Send to referrer\n\t\t\t} else {\n\t\t\t\thousingToken.burn(rewardShares.referrerValue); // Burn to add to ecosystem reward\n\t\t\t}\n\t\t}\n\n\t\tattr.rewardsPerShare = currentRPS;\n\n\t\tprojectSFT.update(\n\t\t\tcaller,\n\t\t\tnonce,\n\t\t\tprojectSFT.balanceOf(caller, nonce),\n\t\t\tabi.encode(attr)\n\t\t);\n\n\t\thousingToken.transfer(caller, rewardShares.userValue); // Send to user\n\n\t\treturn (attr, rewardShares);\n\t}\n\n\t/// @notice Computes the amount of rent claimable for a given token.\n\t/// @param attr The attributes of the token.\n\t/// @return The amount of rent claimable.\n\tfunction rentClaimable(\n\t\tHousingAttributes memory attr\n\t) public view returns (uint256) {\n\t\treturn computeRewardShares(attr).userValue;\n\t}\n\n\t/// @dev Computes the reward shares for a given token.\n\t/// @param attr The attributes of the token.\n\t/// @return The computed RewardShares.\n\tfunction computeRewardShares(\n\t\tHousingAttributes memory attr\n\t) internal view returns (rewardshares memory) {\n\t\tuint256 currentRPS = rewardPerShare;\n\n\t\tif (currentRPS == 0 || attr.rewardsPerShare >= currentRPS) {\n\t\t\treturn rewardshares({ userValue: 0, referrerValue: 0 });\n\t\t}\n\n\t\tuint256 reward = computeReward(attr, currentRPS);\n\n\t\treturn splitReward(reward);\n\t}\n}\n" + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/token/ERC1155/ERC1155.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\n\nimport \"./HousingSFT.sol\";\nimport \"./RewardSharing.sol\";\nimport \"../lib/TokenPayments.sol\";\nimport \"./CallsSmartHousing.sol\";\n\n/// @title Rents Module\n/// @notice Handles rent payments, reward calculations, and distribution for Housing projects.\n/// @dev This abstract contract should be inherited by the HousingProject contract.\nabstract contract RentsModule is CallsSmartHousing {\n\tusing TokenPayments for ERC20TokenPayment;\n\tusing RewardShares for rewardshares;\n\n\tuint256 public rewardPerShare;\n\tuint256 public rewardsReserve;\n\tuint256 public facilityManagementFunds;\n\n\tERC20Burnable housingToken;\n\tHousingSFT public projectSFT;\n\n\t/// @notice Receives rent payments and distributes rewards.\n\t/// @param rentPayment The details of the rent payment.\n\tfunction receiveRent(ERC20TokenPayment calldata rentPayment) external {\n\t\t// TODO set the appropriate rent per Project\n\t\trequire(\n\t\t\trentPayment.amount > 0,\n\t\t\t\"RentsModule: Insufficient amount\"\n\t\t);\n\t\trequire(\n\t\t\trentPayment.token == housingToken,\n\t\t\t\"RentsModule: Invalid rent payment token\"\n\t\t);\n\t\trentPayment.receiveERC20();\n\n\t\tuint256 rentReward = (rentPayment.amount * 75) / 100;\n\t\tuint256 ecosystemReward = (rentPayment.amount * 18) / 100;\n\t\tuint256 facilityReward = (rentPayment.amount * 7) / 100;\n\n\t\tuint256 allShares = projectSFT.getMaxSupply();\n\t\tuint256 rpsIncrease = (rentReward * DIVISION_SAFETY_CONST) / allShares;\n\n\t\trewardPerShare += rpsIncrease;\n\t\trewardsReserve += rentReward;\n\t\tfacilityManagementFunds += facilityReward;\n\n\t\thousingToken.burn(ecosystemReward);\n\t\tISmartHousing(smartHousingAddr).addProjectRent(rentPayment.amount);\n\t}\n\n\t/// @notice Claims rent rewards for a given token.\n\t/// @return The updated HousingAttributes.\n\tfunction claimRentReward(\n\t\tuint256 nonce\n\t) external returns (HousingAttributes memory, rewardshares memory) {\n\t\taddress caller = msg.sender;\n\t\tuint256 currentRPS = rewardPerShare;\n\n\t\tHousingAttributes memory attr = projectSFT.getUserSFT(caller, nonce);\n\t\trewardshares memory rewardShares = computeRewardShares(attr);\n\t\tuint256 totalReward = rewardShares.total();\n\n\t\tif (totalReward == 0) {\n\t\t\t// Fail silently\n\t\t\treturn (attr, rewardShares);\n\t\t}\n\n\t\trequire(rewardsReserve >= totalReward, \"Computed rewards too large\");\n\n\t\trewardsReserve -= totalReward;\n\n\t\t// We use original owner since we are certain they are registered\n\t\t(, address referrer) = getReferrer(attr.originalOwner);\n\t\tif (rewardShares.referrerValue > 0) {\n\t\t\tif (referrer != address(0)) {\n\t\t\t\thousingToken.transfer(referrer, rewardShares.referrerValue); // Send to referrer\n\t\t\t} else {\n\t\t\t\thousingToken.burn(rewardShares.referrerValue); // Burn to add to ecosystem reward\n\t\t\t}\n\t\t}\n\n\t\tattr.rewardsPerShare = currentRPS;\n\n\t\tprojectSFT.update(\n\t\t\tcaller,\n\t\t\tnonce,\n\t\t\tprojectSFT.balanceOf(caller, nonce),\n\t\t\tabi.encode(attr)\n\t\t);\n\n\t\thousingToken.transfer(caller, rewardShares.userValue); // Send to user\n\n\t\treturn (attr, rewardShares);\n\t}\n\n\t/// @notice Computes the amount of rent claimable for a given token.\n\t/// @param attr The attributes of the token.\n\t/// @return The amount of rent claimable.\n\tfunction rentClaimable(\n\t\tHousingAttributes memory attr\n\t) public view returns (uint256) {\n\t\treturn computeRewardShares(attr).userValue;\n\t}\n\n\t/// @dev Computes the reward shares for a given token.\n\t/// @param attr The attributes of the token.\n\t/// @return The computed RewardShares.\n\tfunction computeRewardShares(\n\t\tHousingAttributes memory attr\n\t) internal view returns (rewardshares memory) {\n\t\tuint256 currentRPS = rewardPerShare;\n\n\t\tif (currentRPS == 0 || attr.rewardsPerShare >= currentRPS) {\n\t\t\treturn rewardshares({ userValue: 0, referrerValue: 0 });\n\t\t}\n\n\t\tuint256 reward = computeReward(attr, currentRPS);\n\n\t\treturn splitReward(reward);\n\t}\n}\n" }, "contracts/housing-project/RewardSharing.sol": { "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity 0.8.24;\n\nimport \"./HousingSFT.sol\";\n\nuint256 constant DIVISION_SAFETY_CONST = 1_000_000_000_000_000_000;\n\nstruct rewardshares {\n\tuint256 userValue;\n\tuint256 referrerValue;\n}\n\nlibrary RewardShares {\n\tfunction total(rewardshares memory self) internal pure returns (uint256) {\n\t\treturn self.userValue + self.referrerValue;\n\t}\n}\n\nfunction splitReward(uint256 reward) pure returns (rewardshares memory) {\n\tuint256 referrerValue = (reward * 6_66) / 100_00; // would amount to approximately 5% of grand total\n\tuint256 userValue = reward - referrerValue;\n\n\treturn rewardshares(userValue, referrerValue);\n}\n\nfunction computeReward(\n\tHousingAttributes memory attr,\n\tuint256 contractRPS\n) pure returns (uint256) {\n\tif (contractRPS <= attr.rewardsPerShare) {\n\t\treturn 0;\n\t}\n\n\treturn\n\t\t((contractRPS - attr.rewardsPerShare) * attr.tokenWeight) /\n\t\tDIVISION_SAFETY_CONST;\n}\n" @@ -113,7 +113,7 @@ "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\n\nimport \"../../lib/TokenPayments.sol\";\nimport \"./SHT.sol\";\n\n/**\n * @title SHTModule\n * @dev This contract manages the Smart Housing Token (SHT) within the platform.\n * It includes functionalities for making payments in SHT and querying the SHT token ID.\n */\nabstract contract SHTModule is ERC20, ERC20Burnable {\n\tfunction decimals() public pure override returns (uint8) {\n\t\treturn uint8(SHT.DECIMALS);\n\t}\n\n\t/**\n\t * @dev Makes an ERC20TokenPayment struct in SHT for and amount.\n\t * @param shtAmount Amount of SHT to be sent.\n\t * @return payment ERC20TokenPayment struct representing the payment.\n\t */\n\tfunction _makeSHTPayment(\n\t\tuint256 shtAmount\n\t) internal view returns (ERC20TokenPayment memory) {\n\t\treturn ERC20TokenPayment(IERC20(address(this)), shtAmount);\n\t}\n}\n" }, "contracts/project-funding/ProjectFunding.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\";\n\nimport \"../lib/ProjectStorage.sol\";\nimport \"../lib/LkSHTAttributes.sol\";\n\nimport \"../main/Interface.sol\";\n\nimport \"../housing-project/HousingProject.sol\";\nimport \"../modules/LockedSmartHousingToken.sol\";\nimport \"../modules/sht-module/SHT.sol\";\n\nimport { TokenPayment } from \"../lib/TokenPayments.sol\";\n\n/**\n * @title ProjectFunding\n * @dev This contract is used for initializing and deploying housing projects.\n * It allows the deployment of a new housing project and manages project data.\n */\ncontract ProjectFunding is Ownable {\n\tusing SafeMath for uint256;\n\tusing ProjectStorage for mapping(uint256 => ProjectStorage.Data);\n\tusing ProjectStorage for ProjectStorage.Data;\n\tusing LkSHTAttributes for LkSHTAttributes.Attributes;\n\n\taddress public coinbase; // Address authorized to initialize the first project, also the housingToken\n\taddress public smartHousingAddress; // Address of the SmartHousing contract\n\n\tmapping(uint256 => ProjectStorage.Data) public projects; // Mapping of project ID to ProjectData\n\tmapping(address => uint256) public projectsId; // Mapping of project address to project ID\n\tuint256 public projectCount; // Counter for the total number of projects\n\n\tmapping(uint256 => mapping(address => uint256)) public usersProjectDeposit;\n\n\tIERC20 public housingToken; // Token used for funding projects\n\tLkSHT public lkSht; // The locked version\n\n\t/**\n\t * @dev Emitted when a new project is deployed.\n\t * @param projectAddress Address of the newly deployed HousingProject contract.\n\t */\n\tevent ProjectDeployed(address indexed projectAddress);\n\tevent ProjectFunded(\n\t\tuint256 indexed projectId,\n\t\taddress indexed depositor,\n\t\tTokenPayment payment\n\t);\n\tevent ProjectTokensClaimed(\n\t\taddress indexed depositor,\n\t\tuint256 projectId,\n\t\tuint256 amount\n\t);\n\n\t/**\n\t * @param _coinbase Address authorized to initialize the first project.\n\t */\n\tconstructor(address _coinbase) {\n\t\tcoinbase = _coinbase;\n\t\tlkSht = NewLkSHT.create();\n\t}\n\n\t/**\n\t * @dev Internal function to deploy a new HousingProject contract.\n\t * @param fundingToken Address of the ERC20 token used for funding.\n\t * @param fundingGoal The funding goal for the new project.\n\t * @param fundingDeadline The deadline for the project funding.\n\t */\n\tfunction _deployProject(\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress fundingToken,\n\t\tuint256 fundingGoal,\n\t\tuint256 fundingDeadline\n\t) internal {\n\t\tHousingProject newProject = new HousingProject(\n\t\t\tname,\n\t\t\tsymbol,\n\t\t\tsmartHousingAddress\n\t\t);\n\t\tProjectStorage.Data memory projectData = projects.createNew(\n\t\t\tprojectsId,\n\t\t\tprojectCount,\n\t\t\tfundingGoal,\n\t\t\tfundingDeadline,\n\t\t\tfundingToken,\n\t\t\taddress(newProject),\n\t\t\taddress(newProject.projectSFT())\n\t\t);\n\t\tprojectCount = projectData.id;\n\n\t\temit ProjectDeployed(projectData.projectAddress);\n\t}\n\n\t/**\n\t * @dev Initializes the first project.\n\t * This function must be called by the coinbase address and can only be called once.\n\t * It sets up the token and deploys the first project.\n\t * @param shtPayment Payment details for the Smart Housing Token (SHT).\n\t * @param smartHousingAddress_ Address of the Smart Housing contract.\n\t * @param fundingToken Address of the ERC20 token used for funding.\n\t * @param fundingGoal The funding goal for the new project.\n\t * @param fundingDeadline The deadline for the project funding.\n\t */\n\tfunction initFirstProject(\n\t\tERC20TokenPayment calldata shtPayment,\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress smartHousingAddress_,\n\t\taddress fundingToken,\n\t\tuint256 fundingGoal,\n\t\tuint256 fundingDeadline\n\t) external {\n\t\trequire(msg.sender == coinbase, \"Caller is not the coinbase\");\n\t\trequire(projectCount == 0, \"Project already initialized\");\n\n\t\tTokenPayments.receiveERC20(shtPayment);\n\t\thousingToken = shtPayment.token;\n\n\t\tsmartHousingAddress = smartHousingAddress_;\n\n\t\t_deployProject(\n\t\t\tname,\n\t\t\tsymbol,\n\t\t\tfundingToken,\n\t\t\tfundingGoal,\n\t\t\tfundingDeadline\n\t\t);\n\t}\n\n\t/**\n\t * @dev Deploys a new project.\n\t * This function can be called multiple times to deploy additional projects.\n\t * @param fundingToken Address of the ERC20 token used for funding.\n\t * @param fundingGoal The funding goal for the new project.\n\t * @param fundingDeadline The deadline for the project funding.\n\t */\n\tfunction deployProject(\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress fundingToken,\n\t\tuint256 fundingGoal,\n\t\tuint256 fundingDeadline\n\t) public onlyOwner {\n\t\t_deployProject(\n\t\t\tname,\n\t\t\tsymbol,\n\t\t\tfundingToken,\n\t\t\tfundingGoal,\n\t\t\tfundingDeadline\n\t\t);\n\t}\n\n\tfunction fundProject(\n\t\tTokenPayment calldata depositPayment,\n\t\tuint256 projectId,\n\t\tuint256 referrerId\n\t) external payable {\n\t\trequire(\n\t\t\tprojectId > 0 && projectId <= projectCount,\n\t\t\t\"Invalid project ID\"\n\t\t);\n\n\t\taddress depositor = msg.sender;\n\n\t\t// Register user with referrer (if needed)\n\t\tISmartHousing(smartHousingAddress).createRefIDViaProxy(\n\t\t\tdepositor,\n\t\t\treferrerId\n\t\t);\n\n\t\t// Update project funding\n\t\tprojects.fund(\n\t\t\tusersProjectDeposit[projectId],\n\t\t\tprojectId,\n\t\t\tdepositor,\n\t\t\tdepositPayment\n\t\t);\n\n\t\temit ProjectFunded(projectId, depositor, depositPayment);\n\t}\n\n\tfunction setProjectToken(uint256 projectId) external onlyOwner {\n\t\tProjectStorage.Data storage project = projects[projectId];\n\n\t\t// TODO Add this after demo\n\t\t// require(\n\t\t// \tproject.status() == ProjectStorage.Status.Successful,\n\t\t// \t\"Project Funding not yet successful\"\n\t\t// );\n\n\t\tISmartHousing(smartHousingAddress).addProject(project.projectAddress);\n\n\t\tHousingProject(project.projectAddress).setTokenDetails(\n\t\t\tproject.collectedFunds,\n\t\t\tcoinbase\n\t\t);\n\t}\n\n\t/**\n\t * @dev Claims project tokens for a given project ID.\n\t * @param projectId The ID of the project to claim tokens from.\n\t */\n\tfunction claimProjectTokens(uint256 projectId) external {\n\t\taddress depositor = msg.sender;\n\n\t\t// Retrieve the project and deposit amount\n\t\t(ProjectStorage.Data memory project, uint256 depositAmount) = projects\n\t\t\t.takeDeposit(usersProjectDeposit[projectId], projectId, depositor);\n\n\t\tHousingSFT(project.tokenAddress).mintSFT(\n\t\t\tdepositAmount,\n\t\t\tdepositor,\n\t\t\tproject.collectedFunds\n\t\t);\n\n\t\t// Mint LkSHT tokens if the project ID is 1\n\t\tif (project.id == 1) {\n\t\t\tuint256 shtAmount = depositAmount.mul(SHT.ICO_FUNDS).div(\n\t\t\t\tproject.collectedFunds\n\t\t\t);\n\n\t\t\tlkSht.mint(shtAmount, depositor);\n\t\t}\n\n\t\temit ProjectTokensClaimed(depositor, projectId, depositAmount);\n\t}\n\n\tfunction unlockSHT(uint256 nonce) external {\n\t\taddress caller = msg.sender;\n\n\t\tuint256 lkShtBal = lkSht.balanceOf(caller, nonce);\n\t\trequire(lkShtBal > 0, \"ProjectFunding: Nothing to unlock\");\n\n\t\tLkSHTAttributes.Attributes memory attr = abi.decode(\n\t\t\tlkSht.getRawTokenAttributes(nonce),\n\t\t\t(LkSHTAttributes.Attributes)\n\t\t);\n\t\t(\n\t\t\tuint256 totalUnlockedAmount,\n\t\t\tLkSHTAttributes.Attributes memory newAttr\n\t\t) = attr.unlockMatured();\n\n\t\tlkSht.update(\n\t\t\tcaller,\n\t\t\tnonce,\n\t\t\tlkShtBal.sub(totalUnlockedAmount),\n\t\t\tabi.encode(newAttr)\n\t\t);\n\n\t\t// Transfer the total unlocked SHT tokens to the user's address\n\t\tif (totalUnlockedAmount > 0) {\n\t\t\thousingToken.transfer(caller, totalUnlockedAmount);\n\t\t}\n\t}\n\n\t/**\n\t * @dev Returns an array of all project IDs and their associated data.\n\t * @return projectList An array of tuples containing project details.\n\t */\n\tfunction allProjects() public view returns (ProjectStorage.Data[] memory) {\n\t\tProjectStorage.Data[] memory projectList = new ProjectStorage.Data[](\n\t\t\tprojectCount\n\t\t);\n\n\t\tfor (uint256 i = 1; i <= projectCount; i++) {\n\t\t\tprojectList[i - 1] = projects[i];\n\t\t}\n\n\t\treturn projectList;\n\t}\n\n\t/**\n\t * @dev Returns the address of the HousingProject contract for a given project ID.\n\t * @param projectId The ID of the project.\n\t * @return projectAddress The address of the HousingProject contract.\n\t */\n\tfunction getProjectAddress(\n\t\tuint256 projectId\n\t) external view returns (address projectAddress) {\n\t\tProjectStorage.Data storage project = projects[projectId];\n\t\treturn project.projectAddress;\n\t}\n\n\t/**\n\t * @dev Returns the details of a project by its ID.\n\t * @param projectId The ID of the project.\n\t * @return id The project ID.\n\t * @return fundingGoal The funding goal of the project.\n\t * @return fundingDeadline The deadline for the project funding.\n\t * @return fundingToken The address of the ERC20 token used for funding.\n\t * @return projectAddress The address of the HousingProject contract.\n\t * @return status The funding status of the project.\n\t * @return collectedFunds The amount of funds collected.\n\t */\n\tfunction getProjectData(\n\t\tuint256 projectId\n\t)\n\t\texternal\n\t\tview\n\t\treturns (\n\t\t\tuint256 id,\n\t\t\tuint256 fundingGoal,\n\t\t\tuint256 fundingDeadline,\n\t\t\taddress fundingToken,\n\t\t\taddress projectAddress,\n\t\t\tuint8 status,\n\t\t\tuint256 collectedFunds\n\t\t)\n\t{\n\t\tProjectStorage.Data storage project = projects[projectId];\n\t\treturn (\n\t\t\tproject.id,\n\t\t\tproject.fundingGoal,\n\t\t\tproject.fundingDeadline,\n\t\t\tproject.fundingToken,\n\t\t\tproject.projectAddress,\n\t\t\tuint8(project.status()),\n\t\t\tproject.collectedFunds\n\t\t);\n\t}\n}\n" + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\";\n\nimport \"../lib/ProjectStorage.sol\";\nimport \"../lib/LkSHTAttributes.sol\";\n\nimport \"../main/Interface.sol\";\n\nimport \"../housing-project/HousingProject.sol\";\nimport \"../modules/LockedSmartHousingToken.sol\";\nimport \"../modules/sht-module/SHT.sol\";\n\nimport { TokenPayment } from \"../lib/TokenPayments.sol\";\n\n/**\n * @title ProjectFunding\n * @dev This contract is used for initializing and deploying housing projects.\n * It allows the deployment of a new housing project and manages project data.\n */\ncontract ProjectFunding is Ownable {\n\tusing SafeMath for uint256;\n\tusing ProjectStorage for mapping(uint256 => ProjectStorage.Data);\n\tusing ProjectStorage for ProjectStorage.Data;\n\tusing LkSHTAttributes for LkSHTAttributes.Attributes;\n\n\taddress public coinbase; // Address authorized to initialize the first project, also the housingToken\n\taddress public smartHousingAddress; // Address of the SmartHousing contract\n\n\tmapping(uint256 => ProjectStorage.Data) public projects; // Mapping of project ID to ProjectData\n\tmapping(address => uint256) public projectsId; // Mapping of project address to project ID\n\tuint256 public projectCount; // Counter for the total number of projects\n\n\tmapping(uint256 => mapping(address => uint256)) public usersProjectDeposit;\n\n\tIERC20 public housingToken; // Token used for funding projects\n\tLkSHT public lkSht; // The locked version\n\n\t/**\n\t * @dev Emitted when a new project is deployed.\n\t * @param projectAddress Address of the newly deployed HousingProject contract.\n\t */\n\tevent ProjectDeployed(address indexed projectAddress);\n\tevent ProjectFunded(\n\t\tuint256 indexed projectId,\n\t\taddress indexed depositor,\n\t\tTokenPayment payment\n\t);\n\tevent ProjectTokensClaimed(\n\t\taddress indexed depositor,\n\t\tuint256 projectId,\n\t\tuint256 amount\n\t);\n\n\t/**\n\t * @param _coinbase Address authorized to initialize the first project.\n\t */\n\tconstructor(address _coinbase) {\n\t\tcoinbase = _coinbase;\n\t\tlkSht = NewLkSHT.create();\n\t}\n\n\t/**\n\t * @dev Internal function to deploy a new HousingProject contract.\n\t * @param fundingToken Address of the ERC20 token used for funding.\n\t * @param fundingGoal The funding goal for the new project.\n\t * @param fundingDeadline The deadline for the project funding.\n\t */\n\tfunction _deployProject(\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress fundingToken,\n\t\tuint256 fundingGoal,\n\t\tuint256 fundingDeadline\n\t) internal {\n\t\tHousingProject newProject = new HousingProject(\n\t\t\tname,\n\t\t\tsymbol,\n\t\t\tsmartHousingAddress\n\t\t);\n\t\tProjectStorage.Data memory projectData = projects.createNew(\n\t\t\tprojectsId,\n\t\t\tprojectCount,\n\t\t\tfundingGoal,\n\t\t\tfundingDeadline,\n\t\t\tfundingToken,\n\t\t\taddress(newProject),\n\t\t\taddress(newProject.projectSFT())\n\t\t);\n\t\tprojectCount = projectData.id;\n\n\t\temit ProjectDeployed(projectData.projectAddress);\n\t}\n\n\t/**\n\t * @dev Initializes the first project.\n\t * This function must be called by the coinbase address and can only be called once.\n\t * It sets up the token and deploys the first project.\n\t * @param shtPayment Payment details for the Smart Housing Token (SHT).\n\t * @param smartHousingAddress_ Address of the Smart Housing contract.\n\t * @param fundingToken Address of the ERC20 token used for funding.\n\t * @param fundingGoal The funding goal for the new project.\n\t * @param fundingDeadline The deadline for the project funding.\n\t */\n\tfunction initFirstProject(\n\t\tERC20TokenPayment calldata shtPayment,\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress smartHousingAddress_,\n\t\taddress fundingToken,\n\t\tuint256 fundingGoal,\n\t\tuint256 fundingDeadline\n\t) external {\n\t\trequire(msg.sender == coinbase, \"Caller is not the coinbase\");\n\t\trequire(projectCount == 0, \"Project already initialized\");\n\n\t\tTokenPayments.receiveERC20(shtPayment);\n\t\thousingToken = shtPayment.token;\n\n\t\tsmartHousingAddress = smartHousingAddress_;\n\n\t\t_deployProject(\n\t\t\tname,\n\t\t\tsymbol,\n\t\t\tfundingToken,\n\t\t\tfundingGoal,\n\t\t\tfundingDeadline\n\t\t);\n\t}\n\n\t/**\n\t * @dev Deploys a new project.\n\t * This function can be called multiple times to deploy additional projects.\n\t * @param fundingToken Address of the ERC20 token used for funding.\n\t * @param fundingGoal The funding goal for the new project.\n\t * @param fundingDeadline The deadline for the project funding.\n\t */\n\tfunction deployProject(\n\t\tstring memory name,\n\t\tstring memory symbol,\n\t\taddress fundingToken,\n\t\tuint256 fundingGoal,\n\t\tuint256 fundingDeadline\n\t) public onlyOwner {\n\t\t_deployProject(\n\t\t\tname,\n\t\t\tsymbol,\n\t\t\tfundingToken,\n\t\t\tfundingGoal,\n\t\t\tfundingDeadline\n\t\t);\n\t}\n\n\tfunction fundProject(\n\t\tTokenPayment calldata depositPayment,\n\t\tuint256 projectId,\n\t\tuint256 referrerId\n\t) external payable {\n\t\trequire(\n\t\t\tprojectId > 0 && projectId <= projectCount,\n\t\t\t\"Invalid project ID\"\n\t\t);\n\n\t\taddress depositor = msg.sender;\n\n\t\t// Register user with referrer (if needed)\n\t\tISmartHousing(smartHousingAddress).createRefIDViaProxy(\n\t\t\tdepositor,\n\t\t\treferrerId\n\t\t);\n\n\t\t// Update project funding\n\t\tprojects.fund(\n\t\t\tusersProjectDeposit[projectId],\n\t\t\tprojectId,\n\t\t\tdepositor,\n\t\t\tdepositPayment\n\t\t);\n\n\t\temit ProjectFunded(projectId, depositor, depositPayment);\n\t}\n\n\tfunction addProjectToEcosystem(uint256 projectId) external onlyOwner {\n\t\tProjectStorage.Data storage project = projects[projectId];\n\n\t\t// TODO Add this after demo\n\t\t// require(\n\t\t// \tproject.status() == ProjectStorage.Status.Successful,\n\t\t// \t\"Project Funding not yet successful\"\n\t\t// );\n\n\t\tISmartHousing(smartHousingAddress).addProject(project.projectAddress);\n\n\t\tHousingProject(project.projectAddress).setTokenDetails(\n\t\t\tproject.collectedFunds,\n\t\t\tcoinbase\n\t\t);\n\t}\n\n\t/**\n\t * @dev Claims project tokens for a given project ID.\n\t * @param projectId The ID of the project to claim tokens from.\n\t */\n\tfunction claimProjectTokens(uint256 projectId) external {\n\t\taddress depositor = msg.sender;\n\n\t\t// Retrieve the project and deposit amount\n\t\t(ProjectStorage.Data memory project, uint256 depositAmount) = projects\n\t\t\t.takeDeposit(usersProjectDeposit[projectId], projectId, depositor);\n\n\t\tHousingSFT(project.tokenAddress).mintSFT(\n\t\t\tdepositAmount,\n\t\t\tdepositor,\n\t\t\tproject.collectedFunds\n\t\t);\n\n\t\t// Mint LkSHT tokens if the project ID is 1\n\t\tif (project.id == 1) {\n\t\t\tuint256 shtAmount = depositAmount.mul(SHT.ICO_FUNDS).div(\n\t\t\t\tproject.collectedFunds\n\t\t\t);\n\n\t\t\tlkSht.mint(shtAmount, depositor);\n\t\t}\n\n\t\temit ProjectTokensClaimed(depositor, projectId, depositAmount);\n\t}\n\n\tfunction unlockSHT(uint256 nonce) external {\n\t\taddress caller = msg.sender;\n\n\t\tuint256 lkShtBal = lkSht.balanceOf(caller, nonce);\n\t\trequire(lkShtBal > 0, \"ProjectFunding: Nothing to unlock\");\n\n\t\tLkSHTAttributes.Attributes memory attr = abi.decode(\n\t\t\tlkSht.getRawTokenAttributes(nonce),\n\t\t\t(LkSHTAttributes.Attributes)\n\t\t);\n\t\t(\n\t\t\tuint256 totalUnlockedAmount,\n\t\t\tLkSHTAttributes.Attributes memory newAttr\n\t\t) = attr.unlockMatured();\n\n\t\tlkSht.update(\n\t\t\tcaller,\n\t\t\tnonce,\n\t\t\tlkShtBal.sub(totalUnlockedAmount),\n\t\t\tabi.encode(newAttr)\n\t\t);\n\n\t\t// Transfer the total unlocked SHT tokens to the user's address\n\t\tif (totalUnlockedAmount > 0) {\n\t\t\thousingToken.transfer(caller, totalUnlockedAmount);\n\t\t}\n\t}\n\n\t/**\n\t * @dev Returns an array of all project IDs and their associated data.\n\t * @return projectList An array of tuples containing project details.\n\t */\n\tfunction allProjects() public view returns (ProjectStorage.Data[] memory) {\n\t\tProjectStorage.Data[] memory projectList = new ProjectStorage.Data[](\n\t\t\tprojectCount\n\t\t);\n\n\t\tfor (uint256 i = 1; i <= projectCount; i++) {\n\t\t\tprojectList[i - 1] = projects[i];\n\t\t}\n\n\t\treturn projectList;\n\t}\n\n\t/**\n\t * @dev Returns the address of the HousingProject contract for a given project ID.\n\t * @param projectId The ID of the project.\n\t * @return projectAddress The address of the HousingProject contract.\n\t */\n\tfunction getProjectAddress(\n\t\tuint256 projectId\n\t) external view returns (address projectAddress) {\n\t\tProjectStorage.Data storage project = projects[projectId];\n\t\treturn project.projectAddress;\n\t}\n\n\t/**\n\t * @dev Returns the details of a project by its ID.\n\t * @param projectId The ID of the project.\n\t * @return id The project ID.\n\t * @return fundingGoal The funding goal of the project.\n\t * @return fundingDeadline The deadline for the project funding.\n\t * @return fundingToken The address of the ERC20 token used for funding.\n\t * @return projectAddress The address of the HousingProject contract.\n\t * @return status The funding status of the project.\n\t * @return collectedFunds The amount of funds collected.\n\t */\n\tfunction getProjectData(\n\t\tuint256 projectId\n\t)\n\t\texternal\n\t\tview\n\t\treturns (\n\t\t\tuint256 id,\n\t\t\tuint256 fundingGoal,\n\t\t\tuint256 fundingDeadline,\n\t\t\taddress fundingToken,\n\t\t\taddress projectAddress,\n\t\t\tuint8 status,\n\t\t\tuint256 collectedFunds\n\t\t)\n\t{\n\t\tProjectStorage.Data storage project = projects[projectId];\n\t\treturn (\n\t\t\tproject.id,\n\t\t\tproject.fundingGoal,\n\t\t\tproject.fundingDeadline,\n\t\t\tproject.fundingToken,\n\t\t\tproject.projectAddress,\n\t\t\tuint8(project.status()),\n\t\t\tproject.collectedFunds\n\t\t);\n\t}\n}\n" }, "contracts/test-artifacts/MintableERC20.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\n\ncontract MintableERC20 is ERC20, Ownable, ERC20Burnable {\n\tconstructor(\n\t\tstring memory name_,\n\t\tstring memory symbol_\n\t) ERC20(name_, symbol_) {}\n\n\tfunction mint(address to, uint256 amt) external onlyOwner {\n\t\t_mint(to, amt);\n\t}\n}\n" diff --git a/packages/backend/package.json b/packages/backend/package.json index 42695b2..348e3ae 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -37,7 +37,7 @@ "@nomicfoundation/hardhat-verify": "~2.0.3", "@nomicfoundation/ignition-core": "^0.15.5", "@typechain/ethers-v5": "~10.1.0", - "@typechain/hardhat": "~9.1.0", + "@typechain/hardhat": "^9.1.0", "@types/eslint": "~8", "@types/mocha": "~9.1.1", "@types/prettier": "~2", @@ -49,9 +49,9 @@ "eslint-config-prettier": "~9.1.0", "eslint-plugin-prettier": "~5.1.3", "ethers": "~6.10.0", - "hardhat": "~2.19.4", - "hardhat-deploy": "~0.11.45", - "hardhat-deploy-ethers": "~0.4.1", + "hardhat": "^2.22.8", + "hardhat-deploy": "^0.12.4", + "hardhat-deploy-ethers": "^0.4.2", "hardhat-gas-reporter": "~1.0.9", "prettier": "~3.3.2", "solidity-coverage": "~0.8.5", diff --git a/packages/backend/scripts/deployHousingProject.ts b/packages/backend/scripts/deployHousingProject.ts index 561e14d..4e58a12 100644 --- a/packages/backend/scripts/deployHousingProject.ts +++ b/packages/backend/scripts/deployHousingProject.ts @@ -26,5 +26,5 @@ task("deployProject", "Deploys new Housing Project") // TODO idealy, this is to be done after successful funding, but it will be teadious // to simulate this in demo, hence we do this here with contract modificatino also - await projectFunding.setProjectToken(projectId); + await projectFunding.addProjectToEcosystem(projectId); }); diff --git a/packages/backend/test/Coinbase.ts b/packages/backend/test/Coinbase.ts index 5ae862a..674cb58 100644 --- a/packages/backend/test/Coinbase.ts +++ b/packages/backend/test/Coinbase.ts @@ -1,55 +1,44 @@ import { expect } from "chai"; import { ethers } from "hardhat"; import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; -import { token } from "../typechain-types/@openzeppelin/contracts"; +import { deployContractsFixtures } from "./deployContractsFixture"; describe("Coinbase", function () { - async function deployContractsFixture() { - const [owner, addr1, addr2, ...addrs] = await ethers.getSigners(); - - const FundingToken = await ethers.getContractFactory("MintableERC20"); - const fundingToken = await FundingToken.deploy("FundingToken", "FTK"); - - // Deploy Coinbase contract - const Coinbase = await ethers.getContractFactory("Coinbase"); - const coinbase = await Coinbase.deploy(); - - // Deploy ProjectFunding contract - const newLkSHTlib = await ethers.deployContract("NewLkSHT"); - const projectFunding = await ethers.deployContract("ProjectFunding", [coinbase], { - libraries: { NewLkSHT: await newLkSHTlib.getAddress() }, - }); - - // Deploy SmartHousing contract - const newHSTlib = await ethers.deployContract("NewHousingStakingToken"); - const smartHousing = await ethers.deployContract("SmartHousing", [coinbase, projectFunding], { - libraries: { NewHousingStakingToken: await newHSTlib.getAddress() }, - }); + async function deployFixture() { + const { otherUsers, ...fixtures } = await loadFixture(deployContractsFixtures); + const [addr1, addr2, ...addrs] = otherUsers; const SHT = await ethers.deployContract("SHT"); - return { coinbase, projectFunding, smartHousing, owner, addr1, addr2, addrs, fundingToken, SHT }; + return { ...fixtures, addr1, addr2, addrs, SHT }; } describe("Deployment", function () { it("should set the right initial values", async function () { - const { coinbase, owner } = await loadFixture(deployContractsFixture); + const { coinbase, owner } = await loadFixture(deployFixture); - expect(await coinbase.owner()).to.equal(owner); + expect(await coinbase.owner()).to.equal(owner.address); }); }); describe("startICO", function () { it("should initialize the first project correctly", async function () { - const { coinbase, projectFunding, smartHousing, SHT, fundingToken } = await loadFixture(deployContractsFixture); + const { coinbase, projectFunding, smartHousing, fundingToken, SHT } = await loadFixture(deployFixture); const fundingGoal = ethers.parseUnits("1000", 18); const fundingDeadline = Math.floor(Date.now() / 1000) + 86400; // Start ICO - await expect(coinbase.startICO(projectFunding, smartHousing, fundingToken, fundingGoal, fundingDeadline)).to.emit( - projectFunding, - "ProjectDeployed", - ); + await expect( + coinbase.startICO( + "TestProject", + "TP", + projectFunding, + smartHousing, + fundingToken, + fundingGoal, + fundingDeadline, + ), + ).to.emit(projectFunding, "ProjectDeployed"); // Check if the project was initialized correctly const projectData = await projectFunding.getProjectData(1); @@ -62,19 +51,21 @@ describe("Coinbase", function () { }); it("should revert if called by non-owner", async function () { - const { coinbase, projectFunding, smartHousing, addr1, fundingToken } = await loadFixture(deployContractsFixture); + const { coinbase, projectFunding, smartHousing, fundingToken, addr1 } = await loadFixture(deployFixture); const fundingGoal = ethers.parseUnits("1000", 18); const fundingDeadline = Math.floor(Date.now() / 1000) + 86400; await expect( - coinbase.connect(addr1).startICO(projectFunding, smartHousing, fundingToken, fundingGoal, fundingDeadline), + coinbase + .connect(addr1) + .startICO("TestProject", "TP", projectFunding, smartHousing, fundingToken, fundingGoal, fundingDeadline), ).to.be.revertedWith("Ownable: caller is not the owner"); }); }); describe("feedSmartHousing", function () { it("should dispatch ecosystem funds to SmartHousing contract correctly", async function () { - const { coinbase, smartHousing, SHT } = await loadFixture(deployContractsFixture); + const { coinbase, smartHousing, SHT } = await loadFixture(deployFixture); const amountToDispatch = await SHT.ECOSYSTEM_DISTRIBUTION_FUNDS(); @@ -86,7 +77,7 @@ describe("Coinbase", function () { }); it("should revert if not called by the owner", async function () { - const { coinbase, smartHousing, addr1 } = await loadFixture(deployContractsFixture); + const { coinbase, smartHousing, addr1 } = await loadFixture(deployFixture); await expect(coinbase.connect(addr1).feedSmartHousing(smartHousing)).to.be.revertedWith( "Ownable: caller is not the owner", @@ -94,7 +85,7 @@ describe("Coinbase", function () { }); it("should revert if funds are already dispatched", async function () { - const { coinbase, smartHousing } = await loadFixture(deployContractsFixture); + const { coinbase, smartHousing } = await loadFixture(deployFixture); // Dispatch the funds first time await coinbase.feedSmartHousing(smartHousing); diff --git a/packages/backend/test/HousingProject.ts b/packages/backend/test/HousingProject.ts index 7dfb1fd..6502c26 100644 --- a/packages/backend/test/HousingProject.ts +++ b/packages/backend/test/HousingProject.ts @@ -1,151 +1,286 @@ import { expect } from "chai"; import { ethers } from "hardhat"; -import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; -import { BigNumberish, parseEther, ZeroAddress } from "ethers"; +import { loadFixture, time } from "@nomicfoundation/hardhat-toolbox/network-helpers"; +import { BigNumberish, parseEther } from "ethers"; import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; +import { deployContractsFixtures } from "./deployContractsFixture"; describe("HousingProject", function () { - const amountRaised = parseEther((50_000_000).toString()); const name = "Incredible Block"; - const uri = "https://awesome.address.money/api/tokens/{projectName}/{tokenId}.json"; - - async function deployFixtures() { - const [owner, projectFunding, ...otherUsers] = await ethers.getSigners(); - const sht = await ethers.deployContract("MintableERC20", ["SmartHousingToken", "SHT"]); - const newHSTlib = await ethers.deployContract("NewHousingStakingToken"); - const smartHousing = await ethers.deployContract("SmartHousing", [ZeroAddress, projectFunding], { - libraries: { NewHousingStakingToken: await newHSTlib.getAddress() }, - }); + const symbol = "ICRB"; - const housingProject = await ethers.deployContract("HousingProject", [smartHousing]); - await housingProject.setTokenDetails(name, uri, amountRaised, sht); - await smartHousing.connect(projectFunding).addProject(housingProject); - - return { - housingProject, - otherUsers, - owner, - sht, - MAX_SUPPLY: await housingProject.MAX_SUPPLY(), - checkHousingTokenAttr: async ({ - expectedMintedAmt, - user, - expectedRPS, - nonce, - }: { - expectedMintedAmt: bigint; - user: HardhatEthersSigner; - expectedRPS: bigint; - nonce: bigint; - }) => { - const { rewardsPerShare, tokenWeight, originalOwner } = await housingProject.getUserSFT(user, nonce); - expect(rewardsPerShare).to.equal(expectedRPS); - expect(tokenWeight).to.equal(expectedMintedAmt); - expect(originalOwner).to.equal(user.address); - }, - }; - } - - describe("Deployment", function () { - it("deploys", async () => { - const { housingProject, owner } = await loadFixture(deployFixtures); - expect(await housingProject.name()).to.equal(name); - expect(await housingProject.amountRaised()).to.equal(amountRaised); - expect(await housingProject.totalSupply()).to.equal(0); - expect(await housingProject.balanceOf(owner, 1)).to.equal(0); - }); - }); + describe("HousingProject from ProjectFunding", function () { + async function housingProjectFixtures() { + const { otherUsers, initFirstProject, getHousingSFT, projectFunding, coinbase, ...fixtures } = + await loadFixture(deployContractsFixtures); + + const fundingGoal = parseEther("20"); + const fundingDeadline = (await time.latest()) + 100_000; + + await initFirstProject({ fundingDeadline, fundingGoal, name, symbol }); + const { projectAddress } = await projectFunding.getProjectData(1); + const housingProject = await ethers.getContractAt("HousingProject", projectAddress); + + const housingSFT = await getHousingSFT(housingProject); + + await projectFunding.addProjectToEcosystem(1); - describe("mintSFT", async () => { - it("mints housing SFT for depositor", async () => { - const { + return { + ...fixtures, + fundingDeadline, + fundingGoal, + otherUsers, + housingSFT, housingProject, - otherUsers: [someUser], - MAX_SUPPLY, - checkHousingTokenAttr, - } = await loadFixture(deployFixtures); + coinbase, + projectFunding, + MAX_SUPPLY: await housingSFT.MAX_SUPPLY(), + checkHousingTokenAttr: async ({ + expectedMintedAmt, + user, + expectedRPS, + nonce, + }: { + expectedMintedAmt: bigint; + user: HardhatEthersSigner; + expectedRPS: bigint; + nonce: bigint; + }) => { + const housingSFT = await getHousingSFT(housingProject); + const { rewardsPerShare, tokenWeight, originalOwner } = await housingSFT.getUserSFT(user, nonce); + expect(rewardsPerShare).to.equal(expectedRPS); + expect(tokenWeight).to.equal(expectedMintedAmt); + expect(originalOwner).to.equal(user.address); + }, + }; + } + + describe("Deployment", function () { + it("should deploy intial HousingProject contract with correct parameters", async () => { + const { initFirstProject, getHousingSFT, projectFunding } = await loadFixture(deployContractsFixtures); + + const fundingGoal = parseEther("20"); + const fundingDeadline = (await time.latest()) + 100_000; - // This guy is a whale, bought $5,000,000 worth of this project in IPO - const depositAmount = amountRaised / 10n; //10% - const expectedMintedAmt = MAX_SUPPLY / 10n; + await initFirstProject({ fundingDeadline, fundingGoal, name, symbol }); + const { projectAddress } = await projectFunding.getProjectData(1); - await housingProject.mintSFT(depositAmount, someUser); + const housingProject = await ethers.getContractAt("HousingProject", projectAddress); - expect(await housingProject.balanceOf(someUser, 1)).to.equal(expectedMintedAmt); + const housingSFT = await getHousingSFT(housingProject); - await checkHousingTokenAttr({ - user: someUser, - expectedMintedAmt, - expectedRPS: 0n, - nonce: 1n, + expect(await housingSFT.name()).to.equal(name); + expect(await housingSFT.amountRaised()).to.equal(0); + expect(await housingSFT.totalSupply()).to.equal(0); }); - // Minting more than allowed should throw an error - await expect(housingProject.mintSFT(amountRaised + 1n, someUser)).to.be.revertedWith( - "HousingSFT: Max supply exceeded", - ); + it("should deploy subsequent HousingProject contract with correct parameters", async () => { + const { getHousingSFT, projectFunding, fundingToken } = await loadFixture(deployContractsFixtures); + + const fundingGoal = parseEther("20"); + const fundingDeadline = (await time.latest()) + 100_000; + + await projectFunding.deployProject(name, symbol, fundingToken, fundingGoal, fundingDeadline); + const { projectAddress } = await projectFunding.getProjectData(1); + const housingProject = await ethers.getContractAt("HousingProject", projectAddress); + + const housingSFT = await getHousingSFT(housingProject); + + expect(await housingSFT.name()).to.equal(name); + expect(await housingSFT.amountRaised()).to.equal(0); + expect(await housingSFT.totalSupply()).to.equal(0); + }); }); - }); - describe("claimRentReward", function () { - it("can claim rent rewards after minting and receiving rent", async () => { - const { - housingProject, - otherUsers: [, tenant, investor], - sht, - checkHousingTokenAttr, - } = await loadFixture(deployFixtures); - - await housingProject.mintSFT(amountRaised / 100_000n, investor); - - // Pays rent for tenant - const payRent = async (rent: BigNumberish) => { - await sht.mint(tenant, rent); - await sht.connect(tenant).approve(housingProject, rent); - await housingProject.connect(tenant).receiveRent({ token: sht, amount: rent }); - }; - await payRent(parseEther("20")); + describe("receiveRent", function () { + it("should receive rent, calculate, and distribute rewards", async function () { + const { + housingProject, + coinbase, + otherUsers: [rentPayer], + } = await loadFixture(housingProjectFixtures); + + // Mint tokens to rent payer + const rentAmount = ethers.parseUnits("500", 18); + await coinbase.mint(rentPayer, rentAmount); + await coinbase.connect(rentPayer).approve(housingProject, rentAmount); - await checkHousingTokenAttr({ - user: investor, - expectedMintedAmt: 10n, - expectedRPS: 0n, - nonce: 1n, + // Capture initial state + const initialRewardsReserve = await housingProject.rewardsReserve(); + const initialFacilityManagementFunds = await housingProject.facilityManagementFunds(); + const initialTotalSupply = await coinbase.totalSupply(); + + // Receive rent + await housingProject.connect(rentPayer).receiveRent({ amount: rentAmount, token: coinbase }); + + // Calculate expected values + const rentReward = (rentAmount * 75n) / 100n; + const facilityReward = (rentAmount * 7n) / 100n; + const ecosystemReward = (rentAmount * 18n) / 100n; + + // Verify storage parameter updates + expect(await housingProject.rewardsReserve()).to.equal(initialRewardsReserve + rentReward); + expect(await housingProject.facilityManagementFunds()).to.equal( + initialFacilityManagementFunds + facilityReward, + ); + expect(await housingProject.rewardPerShare()).to.gt(0); + + // Verify ecosystem reward was burned + expect(await coinbase.totalSupply()).to.equal(initialTotalSupply - ecosystemReward); }); - await housingProject.connect(investor).claimRentReward(1n); + it("should revert if rent amount is insufficient", async function () { + const { + housingProject, + coinbase, + otherUsers: [rentPayer], + } = await loadFixture(housingProjectFixtures); + + // Mint a small amount of tokens to rent payer + const rentAmount = ethers.parseUnits("0", 18); + await coinbase.mint(rentPayer, rentAmount); + await coinbase.connect(rentPayer).approve(housingProject, rentAmount); - // Investor receives rent shares - expect(await sht.balanceOf(investor)).to.equal(140010000000000); - // Investor's token RPS increasses, gets 10 units of project - await checkHousingTokenAttr({ - user: investor, - expectedMintedAmt: 10n, - expectedRPS: 15000000000000000000000000000000n, - nonce: 1n, + // Attempt to receive rent with insufficient amount + await expect( + housingProject.connect(rentPayer).receiveRent({ amount: rentAmount, token: coinbase }), + ).to.be.revertedWith("RentsModule: Insufficient amount"); }); - // Claiming again without new rent does nothing - await housingProject.connect(investor).claimRentReward(1n); - await checkHousingTokenAttr({ - user: investor, - expectedMintedAmt: 10n, - expectedRPS: 15000000000000000000000000000000n, - nonce: 1n, + it("should revert if rent payment token is invalid", async function () { + const { + housingProject, + otherUsers: [rentPayer], + } = await loadFixture(housingProjectFixtures); + + // Mint tokens of a different token (invalid token) + const invalidToken = await ethers.getContractFactory("MintableERC20"); + const invalidERC20Token = await invalidToken.deploy("InvalidToken", "ITK"); + await invalidERC20Token.mint(rentPayer, ethers.parseUnits("500", 18)); + await invalidERC20Token.connect(rentPayer).approve(housingProject, ethers.parseUnits("500", 18)); + + // Attempt to receive rent with an invalid token + await expect( + housingProject + .connect(rentPayer) + .receiveRent({ amount: ethers.parseUnits("500", 18), token: invalidERC20Token }), + ).to.be.revertedWith("RentsModule: Invalid token"); + }); + }); + + describe("claimRentReward", function () { + async function claimRentRewardFixtures() { + const { + housingProject, + otherUsers: [, tenant, investor], + coinbase, + projectFunding, + fundingToken, + fundingGoal, + ...fixtures + } = await loadFixture(housingProjectFixtures); + + // Fund project and get project SFT + const investment = fundingGoal; + await fundingToken.mint(investor, investment); + await fundingToken.connect(investor).approve(projectFunding, investment); + + await projectFunding.connect(investor).fundProject( + { + token: fundingToken, + amount: investment, + nonce: 0, + }, + 1, + 0, + ); + + /** + * Pays rent for tenant + * */ + const payRent = async (rent: BigNumberish) => { + await coinbase.mint(tenant, rent); + await coinbase.connect(tenant).approve(housingProject, rent); + await housingProject.connect(tenant).receiveRent({ token: coinbase, amount: rent }); + }; + + return { ...fixtures, payRent, projectFunding, investor, coinbase, housingProject }; + } + it("should allow users to claim rent rewards after minting and receiving rent", async () => { + const { + housingSFT, + housingProject, + coinbase, + payRent, + fundingDeadline, + investor, + projectFunding, + checkHousingTokenAttr, + } = await loadFixture(claimRentRewardFixtures); + + await time.increaseTo(fundingDeadline + 1); + await projectFunding.connect(investor).claimProjectTokens(1); + + await payRent(parseEther("20")); + + let investorSFTNonce = 1n; + + await checkHousingTokenAttr({ + user: investor, + expectedMintedAmt: 1_000_000n, + expectedRPS: 0n, + nonce: investorSFTNonce, + }); + + // Capture initial state + const initialRewardsReserve = await housingProject.rewardsReserve(); + const initialCoinbaseBalance = await coinbase.balanceOf(investor); + + // Claim rent reward + await housingProject.connect(investor).claimRentReward(investorSFTNonce); + investorSFTNonce += 1n; + + // Verify rewards reserve is decremented + expect(await housingProject.rewardsReserve()).to.be.below(initialRewardsReserve); + + // Verify the investor's token attributes have been updated + await checkHousingTokenAttr({ + user: investor, + expectedMintedAmt: 1_000_000n, + expectedRPS: await housingProject.rewardPerShare(), + nonce: investorSFTNonce, + }); + + // Verify the investor's balance has increased + expect(await coinbase.balanceOf(investor)).to.be.above(initialCoinbaseBalance); + + // Verify nonce update + expect(await housingSFT.hasSFT(investor, investorSFTNonce)).to.equal(true); }); - // Claiming again with new rent - await payRent(parseEther("0.005")); - - await housingProject.connect(investor).claimRentReward(1n); - // Investor receives rent shares - expect(await sht.balanceOf(investor)).to.equal(140045002500000); - // Investor's token RPS increasses, gets 10 units of project - await checkHousingTokenAttr({ - user: investor, - expectedMintedAmt: 10n, - expectedRPS: 15003750000000000000000000000000n, - nonce: 1n, + describe("rentClaimable", function () { + it("should correctly calculate claimable rent rewards", async function () { + const { housingProject, investor, projectFunding, housingSFT, payRent } = + await loadFixture(claimRentRewardFixtures); + + const rentAmount = ethers.parseUnits("500", 18); + + await payRent(rentAmount); + + // Claiming SFT after rent was paid + await projectFunding.connect(investor).claimProjectTokens(1); + const { rewardsPerShare, originalOwner, tokenWeight } = await housingSFT.getUserSFT(investor, 1); + + // Check claimable rent rewards + const claimableRent = await housingProject.rentClaimable({ rewardsPerShare, tokenWeight, originalOwner }); + + // 70% + const investorsShare = (rentAmount * 75n) / 100n; + // Referrer gets 0.3% as there bonus + const expectedClaimableRent = (investorsShare * 99_70n) / 100_00n; + + expect(claimableRent).to.equal(expectedClaimableRent); + }); }); }); }); diff --git a/packages/backend/test/ProjectFunding.ts b/packages/backend/test/ProjectFunding.ts index bf53d02..3af34cf 100644 --- a/packages/backend/test/ProjectFunding.ts +++ b/packages/backend/test/ProjectFunding.ts @@ -2,49 +2,30 @@ import { expect } from "chai"; import { ethers } from "hardhat"; import { loadFixture, time } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { parseEther } from "ethers"; +import { deployContractsFixtures } from "./deployContractsFixture"; describe("ProjectFunding", function () { const fundingGoal = parseEther("1000"); const fundingDeadline = Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 7; // 1 week from now async function deployFixtures() { - const [owner, coinbase, otherUser] = await ethers.getSigners(); - const fundingToken = await ethers.deployContract("MintableERC20", ["FundingToken", "FTK"]); - const newLkSHTlib = await ethers.deployContract("NewLkSHT"); - const projectFunding = await ethers.deployContract("ProjectFunding", [coinbase], { - libraries: { NewLkSHT: await newLkSHTlib.getAddress() }, - }); - - const newHSTlib = await ethers.deployContract("NewHousingStakingToken"); - const smartHousing = await ethers.deployContract("SmartHousing", [coinbase, projectFunding], { - libraries: { NewHousingStakingToken: await newHSTlib.getAddress() }, - }); - - const LkSHT = await ethers.getContractAt("LkSHT", await projectFunding.lkSht()); - return { + const { projectFunding, fundingToken, - coinbase, + initFirstProject, + otherUsers: [, otherUser], + ...fixtures + } = await loadFixture(deployContractsFixtures); + const LkSHT = await ethers.getContractAt("LkSHT", await projectFunding.lkSht()); + + return { + ...fixtures, otherUser, - owner, - fundingGoal, - fundingDeadline, - smartHousing, + fundingToken, + projectFunding, LkSHT, initFirstProject: async () => { - await fundingToken.mint(coinbase, parseEther("1000")); // Mint tokens to the coinbase contract - await fundingToken.connect(coinbase).approve(projectFunding, parseEther("1000")); // Approve tokens - - return projectFunding.connect(coinbase).initFirstProject( - { - token: fundingToken, - amount: parseEther("1000"), - }, - smartHousing, - fundingToken, - fundingGoal, - fundingDeadline, - ); + return initFirstProject({ fundingDeadline, fundingGoal, name: "FirstProject", symbol: "FIRST" }); }, }; } @@ -58,8 +39,7 @@ describe("ProjectFunding", function () { describe("initFirstProject", function () { it("initializes the first project correctly", async () => { - const { projectFunding, fundingToken, initFirstProject, fundingGoal, fundingDeadline } = - await loadFixture(deployFixtures); + const { projectFunding, fundingToken, initFirstProject } = await loadFixture(deployFixtures); await expect(initFirstProject()).to.emit(projectFunding, "ProjectDeployed"); @@ -71,14 +51,15 @@ describe("ProjectFunding", function () { }); it("reverts if called by non-coinbase address", async () => { - const { projectFunding, otherUser, fundingToken, smartHousing, fundingGoal, fundingDeadline } = - await loadFixture(deployFixtures); + const { projectFunding, otherUser, fundingToken, smartHousing } = await loadFixture(deployFixtures); await expect( projectFunding.connect(otherUser).initFirstProject( { token: fundingToken, amount: parseEther("1000"), }, + "SomeName", + "TICKER", smartHousing, fundingToken, fundingGoal, @@ -96,15 +77,13 @@ describe("ProjectFunding", function () { describe("deployProject", function () { it("deploys a new project correctly", async () => { - const { projectFunding, fundingToken, initFirstProject, fundingGoal, fundingDeadline } = - await loadFixture(deployFixtures); + const { projectFunding, fundingToken, initFirstProject } = await loadFixture(deployFixtures); await initFirstProject(); - await expect(projectFunding.deployProject(fundingToken, fundingGoal, fundingDeadline)).to.emit( - projectFunding, - "ProjectDeployed", - ); + await expect( + projectFunding.deployProject("SomeProject", "SPT", fundingToken, fundingGoal, fundingDeadline), + ).to.emit(projectFunding, "ProjectDeployed"); const projectData = await projectFunding.projects(2); expect(projectData.fundingGoal).to.equal(fundingGoal); @@ -128,6 +107,7 @@ describe("ProjectFunding", function () { { token: fundingToken, amount: parseEther("500"), + nonce: 0, }, 1, 0, @@ -151,6 +131,7 @@ describe("ProjectFunding", function () { { token: fundingToken, amount: parseEther("500"), + nonce: 0, }, 99, 0, @@ -159,13 +140,12 @@ describe("ProjectFunding", function () { }); it("reverts if project funding period has ended", async () => { - const { projectFunding, fundingToken, initFirstProject, fundingGoal, otherUser } = - await loadFixture(deployFixtures); + const { projectFunding, fundingToken, initFirstProject, otherUser } = await loadFixture(deployFixtures); await initFirstProject(); const fundingDeadline = (await time.latest()) + 60 * 60 * 24; // 1 day into the future - await projectFunding.deployProject(fundingToken, fundingGoal, fundingDeadline); + await projectFunding.deployProject("SomeName", "TTTK", fundingToken, fundingGoal, fundingDeadline); await fundingToken.mint(otherUser, parseEther("500")); await fundingToken.connect(otherUser).approve(projectFunding, parseEther("500")); @@ -177,6 +157,7 @@ describe("ProjectFunding", function () { { token: fundingToken, amount: parseEther("500"), + nonce: 0, }, 2, 0, @@ -199,26 +180,29 @@ describe("ProjectFunding", function () { { token: fundingToken, amount: parseEther("500"), + nonce: 0, }, 1, 0, ); // Simulate project success - const [, fundingGoal] = await projectFunding.getProjectData(1); - await fundingToken.mint(owner, fundingGoal); - await fundingToken.connect(owner).approve(projectFunding, fundingGoal); + const { fundingGoal, collectedFunds } = await projectFunding.getProjectData(1); + const completeFund = fundingGoal - collectedFunds; + await fundingToken.mint(owner, completeFund); + await fundingToken.connect(owner).approve(projectFunding, completeFund); await projectFunding.connect(owner).fundProject( { token: fundingToken, - amount: fundingGoal, + amount: completeFund, + nonce: 0, }, 1, 0, ); await time.increaseTo(fundingDeadline + 1); - await projectFunding.setProjectToken(1, "UloAku", ""); + await projectFunding.addProjectToEcosystem(1); await expect(projectFunding.connect(otherUser).claimProjectTokens(1)).to.emit( projectFunding, @@ -241,6 +225,7 @@ describe("ProjectFunding", function () { { token: fundingToken, amount: parseEther("500"), + nonce: 0, }, 1, 0, diff --git a/packages/backend/test/SmartHousing.ts b/packages/backend/test/SmartHousing.ts index fb477ec..0787fd1 100644 --- a/packages/backend/test/SmartHousing.ts +++ b/packages/backend/test/SmartHousing.ts @@ -2,51 +2,19 @@ import { expect } from "chai"; import { ethers } from "hardhat"; import { loadFixture, time } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { parseEther } from "ethers"; +import { deployContractsFixtures } from "./deployContractsFixture"; describe("SmartHousing", function () { async function deployFixtures() { - const [owner, ...otherUsers] = await ethers.getSigners(); - const coinbase = owner; - - const newLkSHTlib = await ethers.deployContract("NewLkSHT"); - const newHousingProjectib = await ethers.deployContract("NewHousingProject"); - const projectFunding = await ethers.deployContract("ProjectFunding", [coinbase], { - libraries: { - NewLkSHT: await newLkSHTlib.getAddress(), - NewHousingProject: await newHousingProjectib.getAddress(), - }, - }); - - const newHSTlib = await ethers.deployContract("NewHousingStakingToken"); - const smartHousing = await ethers.deployContract("SmartHousing", [coinbase, projectFunding], { - libraries: { NewHousingStakingToken: await newHSTlib.getAddress() }, - }); + const { coinbase, smartHousing, ...fixtures } = await loadFixture(deployContractsFixtures); + const SHT = await ethers.deployContract("SHT"); return { - smartHousing, - owner, - projectFunding, + ...fixtures, coinbase, - otherUsers, - setUpSht: async () => { - const SHT = await ethers.deployContract("SHT"); - const SmartToken = await ethers.getContractFactory("MintableERC20"); - const sht = await SmartToken.connect(coinbase).deploy("SmartToken", "SHT"); - await sht.mint(coinbase, await SHT.MAX_SUPPLY()); - - // Prepare the payment - const payment = { - token: sht, - amount: await SHT.ECOSYSTEM_DISTRIBUTION_FUNDS(), - }; - - await payment.token.connect(coinbase).approve(smartHousing, payment.amount); - - // Set up SHT - await (await smartHousing.connect(coinbase).setUpSHT(payment)).wait(); - - return { sht, payment }; - }, + smartHousing, + SHT, + setUpSht: () => coinbase.feedSmartHousing(smartHousing), }; } @@ -62,16 +30,16 @@ describe("SmartHousing", function () { describe("SHT Setup", function () { it("Should set up SHT correctly if called by coinbase", async function () { - const { smartHousing, setUpSht } = await loadFixture(deployFixtures); + const { smartHousing, setUpSht, coinbase, SHT } = await loadFixture(deployFixtures); - const { payment } = await setUpSht(); + await setUpSht(); // Check if SHT token address is set - expect(await smartHousing.shtTokenAddress()).to.equal(await payment.token.getAddress()); + expect(await smartHousing.shtTokenAddress()).to.equal(coinbase); // Check if total funds are set in distribution storage - const [totalFunds] = await smartHousing.distributionStorage(); - expect(totalFunds).to.equal(payment.amount); + const { totalFunds } = await smartHousing.distributionStorage(); + expect(totalFunds).to.equal(await SHT.ECOSYSTEM_DISTRIBUTION_FUNDS()); }); it("Should revert if not called by coinbase", async function () { @@ -79,28 +47,17 @@ describe("SmartHousing", function () { const [nonCoinbase] = otherUsers; await expect(smartHousing.connect(nonCoinbase).setUpSHT({ token: coinbase, amount: 0 })).to.be.revertedWith( - "Caller is not the coinbase address", + "Unauthorized", ); }); it("Should revert if SHT token already set", async function () { - const { smartHousing, coinbase, setUpSht } = await loadFixture(deployFixtures); + const { coinbase, setUpSht, SHT } = await loadFixture(deployFixtures); - const { payment } = await setUpSht(); + await setUpSht(); + await coinbase.mint(coinbase, await SHT.ECOSYSTEM_DISTRIBUTION_FUNDS()); - await expect(smartHousing.connect(coinbase).setUpSHT(payment)).to.be.revertedWith("SHT token already set"); - }); - - it("Should revert if incorrect amount of SHT is sent", async function () { - const { smartHousing, coinbase } = await loadFixture(deployFixtures); - - await expect(smartHousing.connect(coinbase).setUpSHT({ token: coinbase, amount: 0 })).to.be.revertedWith( - "Must send all ecosystem funds", - ); - - await expect( - smartHousing.connect(coinbase).setUpSHT({ token: coinbase, amount: parseEther("1500") }), - ).to.be.revertedWith("Must send all ecosystem funds"); + await expect(setUpSht()).to.be.revertedWith("SHT already set"); }); }); @@ -109,130 +66,85 @@ describe("SmartHousing", function () { const { smartHousing, otherUsers } = await loadFixture(deployFixtures); const [project, nonFunder] = otherUsers; - await expect(smartHousing.connect(nonFunder).addProject(project)).to.be.revertedWith( - "Caller is not the project funder", - ); + await expect(smartHousing.connect(nonFunder).addProject(project)).to.be.revertedWith("Not authorized"); }); }); describe("Rent Management", function () { - // TODO we need way to make housingProject call addProjectRent - // it("Should add rent to a project and update distribution storage", async function () { - // const { smartHousing, projectFunding, housingProject, setUpSht } = await loadFixture(deployFixtures); - - // // Add the project - // await smartHousing.connect(projectFunding).addProject(housingProject); - - // // Set up SHT - // await setUpSht(); - - // // Add rent - // const rentAmount = parseEther("100"); - // await smartHousing.connect(housingProject).addProjectRent(rentAmount); - - // // Verify rent addition - // const projectData = await smartHousing.projectDets(housingProject); - // expect(projectData.receivedRents).to.equal(rentAmount); - // }); - it("Should revert if a non-HousingProject tries to add rent", async function () { const { smartHousing, otherUsers } = await loadFixture(deployFixtures); const [nonProject] = otherUsers; await expect(smartHousing.connect(nonProject).addProjectRent(parseEther("100"))).to.be.revertedWith( - "Caller is not an accepted housing project", + "Not authorized", ); }); }); describe("Staking", function () { - it("Should allow users to stake tokens", async function () { - const { smartHousing, otherUsers, setUpSht } = await loadFixture(deployFixtures); - const [user] = otherUsers; - const { sht } = await setUpSht(); - - const stakeAmount = parseEther("100"); - - await sht.connect(user).approve(await smartHousing.getAddress(), stakeAmount); - - const referrerId = 1; - await smartHousing.connect(user).stake([{ token: sht, amount: stakeAmount, nonce: 0n }], 24, referrerId); - - // Verify the staking - const userId = await smartHousing.getUserId(user); - expect(userId).to.equal(2); - - const userCanClaim = await smartHousing.userCanClaim(user, 1); - expect(userCanClaim).to.be.true; - }); - it("Should revert staking if the epochs lock period is invalid", async function () { - const { smartHousing, otherUsers, setUpSht } = await loadFixture(deployFixtures); - const [user] = otherUsers; - const { sht } = await setUpSht(); + const { smartHousing, otherUsers, setUpSht, coinbase } = await loadFixture(deployFixtures); + const [investor] = otherUsers; + await setUpSht(); const stakeAmount = parseEther("100"); - await sht.connect(user).approve(await smartHousing.getAddress(), stakeAmount); + await coinbase.connect(investor).approve(await smartHousing.getAddress(), stakeAmount); const referrerId = 0n; await expect( smartHousing - .connect(user) - .stake([{ token: await sht.getAddress(), amount: stakeAmount, nonce: 0n }], 120, referrerId), + .connect(investor) + .stake([{ token: await coinbase.getAddress(), amount: stakeAmount, nonce: 0n }], 120, referrerId), ).to.be.revertedWith("Invalid epochs lock period"); }); }); describe("Rewards Claiming", function () { async function deployAndStakeFixture() { - const { smartHousing, projectFunding, otherUsers, owner, setUpSht } = await deployFixtures(); + const { + smartHousing, + projectFunding, + otherUsers: [, investor, ...otherUsers], + setUpSht, + coinbase, + ...fixtures + } = await deployFixtures(); // Setting up SHT - const { sht } = await setUpSht(); + await setUpSht(); // Adding the project const fundingToken = await ethers.deployContract("MintableERC20", ["FundingToken", "FTK"]); - await fundingToken.mint(owner, parseEther("100000")); // Mint tokens to the owner contract - await fundingToken.connect(owner).approve(projectFunding, parseEther("100000")); // Approve tokens const fundingGoal = parseEther("20"); + await fundingToken.mint(investor, fundingGoal); // Mint tokens to the owner contract + await fundingToken.connect(investor).approve(projectFunding, fundingGoal); // Approve tokens const fundingDeadline = (await time.latest()) + 100_000; - await projectFunding.initFirstProject( - { - token: fundingToken, - amount: parseEther("1000"), - }, - "Ulo", - "ULO", - smartHousing, - fundingToken, - fundingGoal, - fundingDeadline, - ); + await coinbase.startICO("Ulo", "ULO", projectFunding, smartHousing, fundingToken, fundingGoal, fundingDeadline); - await projectFunding.fundProject({ token: fundingToken, nonce: 0, amount: fundingGoal }, 1, 0); - await projectFunding.setProjectToken(1); + await projectFunding.connect(investor).fundProject({ token: fundingToken, nonce: 0, amount: fundingGoal }, 1, 0); + await projectFunding.addProjectToEcosystem(1); await time.increase(100_000); - await projectFunding.claimProjectTokens(1); + await projectFunding.connect(investor).claimProjectTokens(1); const lkSHT = await ethers.getContractAt("LkSHT", await projectFunding.lkSht()); const { tokenAddress } = await projectFunding.projects(1); - const housingToken = await ethers.getContractAt("HousingSFT", tokenAddress); + const housingSFT = await ethers.getContractAt("HousingSFT", tokenAddress); // Stake tokens for rewards const stakeAmount = parseEther("100"); - await lkSHT.setApprovalForAll(smartHousing, true); - await housingToken.setApprovalForAll(smartHousing, true); + await lkSHT.connect(investor).setApprovalForAll(smartHousing, true); + await housingSFT.connect(investor).setApprovalForAll(smartHousing, true); const epochsLock = 190; - await smartHousing.stake( + await smartHousing.connect(investor).stake( [ - { token: lkSHT, nonce: 1n, amount: await lkSHT.balanceOf(owner, 1) }, - { token: housingToken, nonce: 1n, amount: 1_000_000 }, + { token: lkSHT, nonce: 1n, amount: await lkSHT.balanceOf(investor, 1) }, + { token: housingSFT, nonce: 1n, amount: 1_000_000 }, ], epochsLock, 0, @@ -241,72 +153,102 @@ describe("SmartHousing", function () { // Simulate time passing await time.increase(100_000); - return { smartHousing, user: owner, sht, stakeAmount, otherUsers }; + return { + ...fixtures, + smartHousing, + investor, + projectFunding, + stakeAmount, + otherUsers, + coinbase, + }; } it("Should allow users to claim rewards", async function () { - const { smartHousing, user, sht } = await loadFixture(deployAndStakeFixture); + const { smartHousing, coinbase, investor } = await loadFixture(deployAndStakeFixture); - // Fast forward time to simulate lock period completion - await ethers.provider.send("evm_increaseTime", [3600 * 24 * 30 * 24]); // 24 months - await ethers.provider.send("evm_mine", []); + // Fast forward time to simulate rewards generation + await time.increase(3600 * 24 * 30 * 24); // 24 months - const initialBalance = await sht.balanceOf(user.address); + const initialBalance = await coinbase.balanceOf(investor.address); // Claim rewards - await smartHousing.connect(user).claimRewards(1, 0); // Claim rewards for the first staking (nonce 1) + await smartHousing.connect(investor).claimRewards(1, 0); // Claim rewards for the first staking (nonce 1) - const finalBalance = await sht.balanceOf(user.address); + const finalBalance = await coinbase.balanceOf(investor.address); expect(finalBalance).to.be.gt(initialBalance); - const userCanClaim = await smartHousing.userCanClaim(user, 1); - expect(userCanClaim).to.be.false; // After claiming, the user should no longer be able to claim for the same stake + const userCanClaim = await smartHousing.userCanClaim(investor, 1); + expect(userCanClaim).to.be.false; // After claiming, the investor should no longer be able to claim for the same stake }); - it("Should revert if trying to claim rewards before lock period ends", async function () { - const { smartHousing, user } = await loadFixture(deployAndStakeFixture); - - // Try to claim rewards before lock period ends - await expect(smartHousing.connect(user).claimRewards(1, 0)).to.be.revertedWith( - "Cannot claim rewards before lock period ends", - ); - }); + it("Should revert if the investor tries to claim rewards for a non-existent stake", async function () { + const { smartHousing, investor } = await loadFixture(deployAndStakeFixture); - it("Should revert if the user tries to claim rewards for a non-existent stake", async function () { - const { smartHousing, user } = await loadFixture(deployAndStakeFixture); - - // Fast forward time to simulate lock period completion - await ethers.provider.send("evm_increaseTime", [3600 * 24 * 30 * 24]); // 24 months - await ethers.provider.send("evm_mine", []); + // Fast forward time to simulate rewards generation + await time.increase(3600 * 24 * 30 * 24); // 24 months // Try to claim rewards for a non-existent stake index - await expect(smartHousing.connect(user).claimRewards(2, 0)).to.be.revertedWith("Stake does not exist"); + await expect(smartHousing.connect(investor).claimRewards(2, 0)).to.be.revertedWith( + "No HST token balance at nonce", + ); }); it("Should correctly distribute rewards among multiple stakeholders", async function () { - const { smartHousing, otherUsers, setUpSht } = await loadFixture(deployFixtures); + const { smartHousing, otherUsers, setUpSht, coinbase, fundingToken, projectFunding } = + await loadFixture(deployFixtures); const [user1, user2] = otherUsers; // Setting up SHT - const { sht } = await setUpSht(); + await setUpSht(); + + const fundingGoal = parseEther("20"); + const fundingDeadline = (await time.latest()) + 100_000; + + await coinbase.startICO("Ulo", "ULO", projectFunding, smartHousing, fundingToken, fundingGoal, fundingDeadline); + await projectFunding.addProjectToEcosystem(1); // User 1 and User 2 stake tokens - const stakeAmount1 = parseEther("100"); - const stakeAmount2 = parseEther("200"); + for (const investor of [user1, user2]) { + const fundAmount = fundingGoal / 2n; + await fundingToken.mint(investor, fundAmount); + await fundingToken.connect(investor).approve(projectFunding, fundAmount); - await sht.connect(user1).approve(await smartHousing.getAddress(), stakeAmount1); - await sht.connect(user2).approve(await smartHousing.getAddress(), stakeAmount2); + await projectFunding.connect(investor).fundProject({ token: fundingToken, nonce: 0, amount: fundAmount }, 1, 0); + } - await smartHousing.connect(user1).stake([{ token: sht, nonce: 0n, amount: stakeAmount1 }], 24, 1); - await smartHousing.connect(user2).stake([{ token: sht, nonce: 0n, amount: stakeAmount2 }], 24, 1); + await time.increase(100_000); + for (const investor of [user1, user2]) { + await projectFunding.connect(investor).claimProjectTokens(1); + } - // Simulate some rent being added - const rentAmount = parseEther("300"); - await smartHousing.connect(user1).addProjectRent(rentAmount); // Assuming user1 is the project funder + const { tokenAddress } = await projectFunding.projects(1); + const housingSFT = await ethers.getContractAt("HousingSFT", tokenAddress); - // Fast forward time to simulate lock period completion - await ethers.provider.send("evm_increaseTime", [3600 * 24 * 30 * 24]); // 24 months - await ethers.provider.send("evm_mine", []); + // Stake tokens for rewards + for (const { investor, amt } of [ + { investor: user1, amt: parseEther("100") }, + { investor: user2, amt: parseEther("200") }, + ]) { + await coinbase.mint(investor, amt); + await coinbase.connect(investor).approve(smartHousing, amt); + + await housingSFT.connect(investor).setApprovalForAll(smartHousing, true); + const [{ nonce, amount }] = await housingSFT.sftBalance(investor); + + const epochsLock = 190; + await smartHousing.connect(investor).stake( + [ + { token: housingSFT, nonce, amount }, + { token: coinbase, nonce: 0n, amount: amt }, + ], + epochsLock, + 0, + ); + } + + // Fast forward time to simulate rewards genration + await time.increase(3600 * 24 * 30 * 24); // 24 months // User 1 claims rewards const initialBalance1 = await ethers.provider.getBalance(user1.address); @@ -315,7 +257,7 @@ describe("SmartHousing", function () { // User 2 claims rewards const initialBalance2 = await ethers.provider.getBalance(user2.address); - await smartHousing.connect(user2).claimRewards(2, 0); // Claim rewards for the second staking (index 2) + await smartHousing.connect(user2).claimRewards(2, 0); // Claim rewards for the second staking (nonce 2) const finalBalance2 = await ethers.provider.getBalance(user2.address); // Check that user2 got twice the rewards of user1 (since they staked twice as much) @@ -326,16 +268,17 @@ describe("SmartHousing", function () { }); it("Should revert if a non-staker tries to claim rewards", async function () { - const { smartHousing, otherUsers } = await loadFixture(deployAndStakeFixture); - const [nonStaker] = otherUsers.slice(2); + const { + smartHousing, + otherUsers: [, , nonStaker], + } = await loadFixture(deployAndStakeFixture); - // Fast forward time to simulate lock period completion - await ethers.provider.send("evm_increaseTime", [3600 * 24 * 30 * 24]); // 24 months - await ethers.provider.send("evm_mine", []); + // Fast forward time to simulate rewards genration + await time.increase(3600 * 24 * 30 * 24); // 24 months // Non-staker tries to claim rewards await expect(smartHousing.connect(nonStaker).claimRewards(1, 0)).to.be.revertedWith( - "Caller does not own the hst token", + "No HST token balance at nonce", ); }); }); diff --git a/packages/backend/test/deployContractsFixture.ts b/packages/backend/test/deployContractsFixture.ts new file mode 100644 index 0000000..a754305 --- /dev/null +++ b/packages/backend/test/deployContractsFixture.ts @@ -0,0 +1,90 @@ +import { ethers } from "hardhat"; +import { AddressLike, BigNumberish } from "ethers"; +import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; +import { HousingProject } from "../typechain-types"; +import { expect } from "chai"; + +async function deployContractsFixtures() { + // Retrieve signers + const [owner, ...otherUsers] = await ethers.getSigners(); + + const FundingToken = await ethers.getContractFactory("MintableERC20"); + const fundingToken = await FundingToken.deploy("FundingToken", "FTK"); + + // Deploy Coinbase contract + const Coinbase = await ethers.getContractFactory("CoinbaseMock"); + const coinbase = await Coinbase.deploy(); + // Deploy ProjectFunding contract + const newLkSHTlib = await ethers.deployContract("NewLkSHT"); + const newHousingProjectlib = await ethers.deployContract("NewHousingProject"); + const projectFunding = await ethers.deployContract("ProjectFunding", [coinbase], { + libraries: { + NewLkSHT: await newLkSHTlib.getAddress(), + NewHousingProject: await newHousingProjectlib.getAddress(), + }, + }); + + // Deploy SmartHousing contract + const newHSTlib = await ethers.deployContract("NewHousingStakingToken"); + const smartHousing = await ethers.deployContract("SmartHousing", [coinbase, projectFunding], { + libraries: { NewHousingStakingToken: await newHSTlib.getAddress() }, + }); + + // Helper function to get HousingSFT contract instance + const getHousingSFT = async (project: HousingProject) => { + const sftAddr = await project.projectSFT(); + + return ethers.getContractAt("HousingSFT", sftAddr); + }; + + // Return the deployed contracts and other relevant fixtures + return { + owner, + coinbase, + projectFunding, + otherUsers, + smartHousing, + newHSTlib, + newLkSHTlib, + fundingToken, + getHousingSFT, + checkHousingTokenAttr: async ({ + expectedMintedAmt, + user, + expectedRPS, + nonce, + housingProject, + }: { + expectedMintedAmt: bigint; + user: HardhatEthersSigner; + expectedRPS: bigint; + nonce: bigint; + housingProject: HousingProject; + }) => { + const housingSFT = await getHousingSFT(housingProject); + const { rewardsPerShare, tokenWeight, originalOwner } = await housingSFT.getUserSFT(user, nonce); + expect(rewardsPerShare).to.equal(expectedRPS); + expect(tokenWeight).to.equal(expectedMintedAmt); + expect(originalOwner).to.equal(user.address); + }, + initFirstProject: ({ + fundingDeadline, + fundingGoal, + smartHousing_ = smartHousing, + fundingToken_ = fundingToken, + projectFunding_ = projectFunding, + name, + symbol, + }: { + fundingGoal: BigNumberish; + fundingDeadline: BigNumberish; + smartHousing_?: AddressLike; + fundingToken_?: AddressLike; + projectFunding_?: AddressLike; + name: string; + symbol: string; + }) => coinbase.startICO(name, symbol, projectFunding_, smartHousing_, fundingToken_, fundingGoal, fundingDeadline), + }; +} + +export { deployContractsFixtures }; diff --git a/packages/ui/contracts/deployedContracts.ts b/packages/ui/contracts/deployedContracts.ts index bc41fc1..e022583 100644 --- a/packages/ui/contracts/deployedContracts.ts +++ b/packages/ui/contracts/deployedContracts.ts @@ -743,14 +743,7 @@ const deployedContracts = { }, ], inheritedFunctions: { - claimRentReward: "contracts/housing-project/RentsModule.sol", - facilityManagementFunds: "contracts/housing-project/RentsModule.sol", - housingToken: "contracts/housing-project/RentsModule.sol", - projectSFT: "contracts/housing-project/RentsModule.sol", - receiveRent: "contracts/housing-project/RentsModule.sol", - rentClaimable: "contracts/housing-project/RentsModule.sol", rewardPerShare: "contracts/housing-project/RentsModule.sol", - rewardsReserve: "contracts/housing-project/RentsModule.sol", owner: "@openzeppelin/contracts/access/Ownable.sol", renounceOwnership: "@openzeppelin/contracts/access/Ownable.sol", transferOwnership: "@openzeppelin/contracts/access/Ownable.sol", @@ -2641,7 +2634,7 @@ const deployedContracts = { type: "uint256", }, ], - name: "setProjectToken", + name: "addProjectToEcosystem", outputs: [], stateMutability: "nonpayable", type: "function", @@ -4393,7 +4386,13 @@ const deployedContracts = { }, ], name: "startICO", - outputs: [], + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], stateMutability: "nonpayable", type: "function", }, @@ -4529,6 +4528,11 @@ const deployedContracts = { name: "smartHousingAddr", type: "address", }, + { + internalType: "address", + name: "housingTokenAddr", + type: "address", + }, ], stateMutability: "nonpayable", type: "constructor", @@ -4553,29 +4557,43 @@ const deployedContracts = { type: "event", }, { - anonymous: false, - inputs: [ + inputs: [], + name: "ECOSYSTEM_PERCENT", + outputs: [ { - indexed: false, - internalType: "address", - name: "tokenAddress", - type: "address", + internalType: "uint256", + name: "", + type: "uint256", }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "FACILITY_PERCENT", + outputs: [ { - indexed: false, - internalType: "string", - name: "name", - type: "string", + internalType: "uint256", + name: "", + type: "uint256", }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "REWARD_PERCENT", + outputs: [ { - indexed: false, internalType: "uint256", - name: "amountRaised", + name: "", type: "uint256", }, ], - name: "TokenIssued", - type: "event", + stateMutability: "view", + type: "function", }, { inputs: [ @@ -4795,21 +4813,16 @@ const deployedContracts = { type: "function", }, { - inputs: [ - { - internalType: "uint256", - name: "amountRaised", - type: "uint256", - }, + inputs: [], + name: "smartHousingAddr", + outputs: [ { internalType: "address", - name: "housingTokenAddr", + name: "", type: "address", }, ], - name: "setTokenDetails", - outputs: [], - stateMutability: "nonpayable", + stateMutability: "view", type: "function", }, { @@ -4827,17 +4840,11 @@ const deployedContracts = { }, ], inheritedFunctions: { - claimRentReward: "contracts/housing-project/RentsModule.sol", - facilityManagementFunds: "contracts/housing-project/RentsModule.sol", - housingToken: "contracts/housing-project/RentsModule.sol", - projectSFT: "contracts/housing-project/RentsModule.sol", - receiveRent: "contracts/housing-project/RentsModule.sol", - rentClaimable: "contracts/housing-project/RentsModule.sol", rewardPerShare: "contracts/housing-project/RentsModule.sol", - rewardsReserve: "contracts/housing-project/RentsModule.sol", owner: "@openzeppelin/contracts/access/Ownable.sol", renounceOwnership: "@openzeppelin/contracts/access/Ownable.sol", transferOwnership: "@openzeppelin/contracts/access/Ownable.sol", + smartHousingAddr: "contracts/housing-project/CallsSmartHousing.sol", }, }, HousingSFT: { @@ -5222,11 +5229,6 @@ const deployedContracts = { name: "depositor", type: "address", }, - { - internalType: "uint256", - name: "amount_raised", - type: "uint256", - }, ], name: "mintSFT", outputs: [ @@ -7134,6 +7136,19 @@ const deployedContracts = { name: "ProjectTokensClaimed", type: "event", }, + { + inputs: [ + { + internalType: "uint256", + name: "projectId", + type: "uint256", + }, + ], + name: "addProjectToEcosystem", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, { inputs: [], name: "allProjects", @@ -7175,6 +7190,11 @@ const deployedContracts = { name: "collectedFunds", type: "uint256", }, + { + internalType: "uint256", + name: "minDeposit", + type: "uint256", + }, ], internalType: "struct ProjectStorage.Data[]", name: "", @@ -7239,7 +7259,13 @@ const deployedContracts = { }, ], name: "deployProject", - outputs: [], + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], stateMutability: "nonpayable", type: "function", }, @@ -7313,39 +7339,51 @@ const deployedContracts = { name: "getProjectData", outputs: [ { - internalType: "uint256", - name: "id", - type: "uint256", - }, - { - internalType: "uint256", - name: "fundingGoal", - type: "uint256", - }, - { - internalType: "uint256", - name: "fundingDeadline", - type: "uint256", - }, - { - internalType: "address", - name: "fundingToken", - type: "address", - }, - { - internalType: "address", - name: "projectAddress", - type: "address", - }, - { - internalType: "uint8", - name: "status", - type: "uint8", - }, - { - internalType: "uint256", - name: "collectedFunds", - type: "uint256", + components: [ + { + internalType: "uint256", + name: "id", + type: "uint256", + }, + { + internalType: "address", + name: "tokenAddress", + type: "address", + }, + { + internalType: "address", + name: "projectAddress", + type: "address", + }, + { + internalType: "uint256", + name: "fundingGoal", + type: "uint256", + }, + { + internalType: "uint256", + name: "fundingDeadline", + type: "uint256", + }, + { + internalType: "address", + name: "fundingToken", + type: "address", + }, + { + internalType: "uint256", + name: "collectedFunds", + type: "uint256", + }, + { + internalType: "uint256", + name: "minDeposit", + type: "uint256", + }, + ], + internalType: "struct ProjectStorage.Data", + name: "projectData", + type: "tuple", }, ], stateMutability: "view", @@ -7415,7 +7453,13 @@ const deployedContracts = { }, ], name: "initFirstProject", - outputs: [], + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], stateMutability: "nonpayable", type: "function", }, @@ -7503,6 +7547,11 @@ const deployedContracts = { name: "collectedFunds", type: "uint256", }, + { + internalType: "uint256", + name: "minDeposit", + type: "uint256", + }, ], stateMutability: "view", type: "function", @@ -7533,19 +7582,6 @@ const deployedContracts = { stateMutability: "nonpayable", type: "function", }, - { - inputs: [ - { - internalType: "uint256", - name: "projectId", - type: "uint256", - }, - ], - name: "setProjectToken", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, { inputs: [], name: "smartHousingAddress", diff --git a/yarn.lock b/yarn.lock index e8738f3..6097c49 100644 --- a/yarn.lock +++ b/yarn.lock @@ -262,52 +262,6 @@ __metadata: languageName: node linkType: hard -"@chainsafe/as-sha256@npm:^0.3.1": - version: 0.3.1 - resolution: "@chainsafe/as-sha256@npm:0.3.1" - checksum: 58ea733be1657b0e31dbf48b0dba862da0833df34a81c1460c7352f04ce90874f70003cbf34d0afb9e5e53a33ee2d63a261a8b12462be85b2ba0a6f7f13d6150 - languageName: node - linkType: hard - -"@chainsafe/persistent-merkle-tree@npm:^0.4.2": - version: 0.4.2 - resolution: "@chainsafe/persistent-merkle-tree@npm:0.4.2" - dependencies: - "@chainsafe/as-sha256": ^0.3.1 - checksum: f9cfcb2132a243992709715dbd28186ab48c7c0c696f29d30857693cca5526bf753974a505ef68ffd5623bbdbcaa10f9083f4dd40bf99eb6408e451cc26a1a9e - languageName: node - linkType: hard - -"@chainsafe/persistent-merkle-tree@npm:^0.5.0": - version: 0.5.0 - resolution: "@chainsafe/persistent-merkle-tree@npm:0.5.0" - dependencies: - "@chainsafe/as-sha256": ^0.3.1 - checksum: 2c67203da776c79cd3a6132e2d672fe132393b2e63dc71604e3134acc8c0ec25cc5e431051545939ea0f7c5ff2066fb806b9e5cab974ca085d046226a1671f7d - languageName: node - linkType: hard - -"@chainsafe/ssz@npm:^0.10.0": - version: 0.10.2 - resolution: "@chainsafe/ssz@npm:0.10.2" - dependencies: - "@chainsafe/as-sha256": ^0.3.1 - "@chainsafe/persistent-merkle-tree": ^0.5.0 - checksum: 6bb70cf741d0a19dd0b28b3f6f067b96fa39f556e2eefa6ac745b21db9c3b3a8393dc3cca8ff4a6ce065ed71ddc3fb1b2b390a92004b9d01067c26e2558e5503 - languageName: node - linkType: hard - -"@chainsafe/ssz@npm:^0.9.2": - version: 0.9.4 - resolution: "@chainsafe/ssz@npm:0.9.4" - dependencies: - "@chainsafe/as-sha256": ^0.3.1 - "@chainsafe/persistent-merkle-tree": ^0.4.2 - case: ^1.6.3 - checksum: c6eaedeae9e5618b3c666ff4507a27647f665a8dcf17d5ca86da4ed4788c5a93868f256d0005467d184fdf35ec03f323517ec2e55ec42492d769540a2ec396bc - languageName: node - linkType: hard - "@coinbase/wallet-sdk@npm:4.0.4": version: 4.0.4 resolution: "@coinbase/wallet-sdk@npm:4.0.4" @@ -804,7 +758,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/providers@npm:5.7.2, @ethersproject/providers@npm:^5.7.1, @ethersproject/providers@npm:^5.7.2, @ethersproject/providers@npm:~5.7.1": +"@ethersproject/providers@npm:5.7.2, @ethersproject/providers@npm:^5.7.2, @ethersproject/providers@npm:~5.7.1": version: 5.7.2 resolution: "@ethersproject/providers@npm:5.7.2" dependencies: @@ -2122,161 +2076,117 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/ethereumjs-block@npm:5.0.2": - version: 5.0.2 - resolution: "@nomicfoundation/ethereumjs-block@npm:5.0.2" - dependencies: - "@nomicfoundation/ethereumjs-common": 4.0.2 - "@nomicfoundation/ethereumjs-rlp": 5.0.2 - "@nomicfoundation/ethereumjs-trie": 6.0.2 - "@nomicfoundation/ethereumjs-tx": 5.0.2 - "@nomicfoundation/ethereumjs-util": 9.0.2 - ethereum-cryptography: 0.1.3 - ethers: ^5.7.1 - checksum: 7ff744f44a01f1c059ca7812a1cfc8089f87aa506af6cb39c78331dca71b32993cbd6fa05ad03f8c4f4fab73bb998a927af69e0d8ff01ae192ee5931606e09f5 +"@nomicfoundation/edr-darwin-arm64@npm:0.5.2": + version: 0.5.2 + resolution: "@nomicfoundation/edr-darwin-arm64@npm:0.5.2" + checksum: f6ab386603c6e080fe7f611b739eb6d1d6a370220318b725cb582702563577150b3be14b6d0be71cb72bdb854e6992c587ecfc6833216f750eae8e7cd96de46f languageName: node linkType: hard -"@nomicfoundation/ethereumjs-blockchain@npm:7.0.2": - version: 7.0.2 - resolution: "@nomicfoundation/ethereumjs-blockchain@npm:7.0.2" - dependencies: - "@nomicfoundation/ethereumjs-block": 5.0.2 - "@nomicfoundation/ethereumjs-common": 4.0.2 - "@nomicfoundation/ethereumjs-ethash": 3.0.2 - "@nomicfoundation/ethereumjs-rlp": 5.0.2 - "@nomicfoundation/ethereumjs-trie": 6.0.2 - "@nomicfoundation/ethereumjs-tx": 5.0.2 - "@nomicfoundation/ethereumjs-util": 9.0.2 - abstract-level: ^1.0.3 - debug: ^4.3.3 - ethereum-cryptography: 0.1.3 - level: ^8.0.0 - lru-cache: ^5.1.1 - memory-level: ^1.0.0 - checksum: b7e440dcd73e32aa72d13bfd28cb472773c9c60ea808a884131bf7eb3f42286ad594a0864215f599332d800f3fe1f772fff4b138d2dcaa8f41e4d8389bff33e7 +"@nomicfoundation/edr-darwin-x64@npm:0.5.2": + version: 0.5.2 + resolution: "@nomicfoundation/edr-darwin-x64@npm:0.5.2" + checksum: 6f91f6d0294c0450e0501983f1de34a48582fe93f48428bc4b798ac93bb5483a96d626c2b4c62ac91102f00c826a3f9bfa16d748301440ebe1bbb2920ba3ba6d languageName: node linkType: hard -"@nomicfoundation/ethereumjs-common@npm:4.0.2": - version: 4.0.2 - resolution: "@nomicfoundation/ethereumjs-common@npm:4.0.2" - dependencies: - "@nomicfoundation/ethereumjs-util": 9.0.2 - crc-32: ^1.2.0 - checksum: f0d84704d6254d374299c19884312bd5666974b4b6f342d3f10bc76e549de78d20e45a53d25fbdc146268a52335497127e4f069126da7c60ac933a158e704887 +"@nomicfoundation/edr-linux-arm64-gnu@npm:0.5.2": + version: 0.5.2 + resolution: "@nomicfoundation/edr-linux-arm64-gnu@npm:0.5.2" + checksum: bd84cc2741bb2be3c3a60bae9dbb8ca7794a68b8675684c97f2c6e7310e5cba7efd1cf18d392d42481cda83fb478f83c0bd605104c5cf08bab44ec07669c3010 languageName: node linkType: hard -"@nomicfoundation/ethereumjs-ethash@npm:3.0.2": - version: 3.0.2 - resolution: "@nomicfoundation/ethereumjs-ethash@npm:3.0.2" - dependencies: - "@nomicfoundation/ethereumjs-block": 5.0.2 - "@nomicfoundation/ethereumjs-rlp": 5.0.2 - "@nomicfoundation/ethereumjs-util": 9.0.2 - abstract-level: ^1.0.3 - bigint-crypto-utils: ^3.0.23 - ethereum-cryptography: 0.1.3 - checksum: e4011e4019dd9b92f7eeebfc1e6c9a9685c52d8fd0ee4f28f03e50048a23b600c714490827f59fdce497b3afb503b3fd2ebf6815ff307e9949c3efeff1403278 +"@nomicfoundation/edr-linux-arm64-musl@npm:0.5.2": + version: 0.5.2 + resolution: "@nomicfoundation/edr-linux-arm64-musl@npm:0.5.2" + checksum: e7f7d82f16be1b26805bd90964c456aecb4a6a1397e87d507810d37bd383064271fa63932564e725fdb30868925334338ec459fe32f84fc11206644b7b37825c languageName: node linkType: hard -"@nomicfoundation/ethereumjs-evm@npm:2.0.2": - version: 2.0.2 - resolution: "@nomicfoundation/ethereumjs-evm@npm:2.0.2" - dependencies: - "@ethersproject/providers": ^5.7.1 - "@nomicfoundation/ethereumjs-common": 4.0.2 - "@nomicfoundation/ethereumjs-tx": 5.0.2 - "@nomicfoundation/ethereumjs-util": 9.0.2 - debug: ^4.3.3 - ethereum-cryptography: 0.1.3 - mcl-wasm: ^0.7.1 - rustbn.js: ~0.2.0 - checksum: a23cf570836ddc147606b02df568069de946108e640f902358fef67e589f6b371d856056ee44299d9b4e3497f8ae25faa45e6b18fefd90e9b222dc6a761d85f0 +"@nomicfoundation/edr-linux-x64-gnu@npm:0.5.2": + version: 0.5.2 + resolution: "@nomicfoundation/edr-linux-x64-gnu@npm:0.5.2" + checksum: ec025bf75227638b6b2cd01b7ba01b3ddaddf54c4d18d25e9d0364ac621981be2aaf124f4e60a88da5c9e267adb41a660a42668e2d6c9a6a57e55e8671fc76f1 languageName: node linkType: hard -"@nomicfoundation/ethereumjs-rlp@npm:5.0.2": - version: 5.0.2 - resolution: "@nomicfoundation/ethereumjs-rlp@npm:5.0.2" - bin: - rlp: bin/rlp - checksum: a74434cadefca9aa8754607cc1ad7bb4bbea4ee61c6214918e60a5bbee83206850346eb64e39fd1fe97f854c7ec0163e01148c0c881dda23881938f0645a0ef2 +"@nomicfoundation/edr-linux-x64-musl@npm:0.5.2": + version: 0.5.2 + resolution: "@nomicfoundation/edr-linux-x64-musl@npm:0.5.2" + checksum: c9ff47f72645492383b2a598675878abc029b86325e2c457db1b2c4281916e11e4ef6336c355d40ae3c1736595bc43da51cfcf1e923464011f526f4db64c245b languageName: node linkType: hard -"@nomicfoundation/ethereumjs-statemanager@npm:2.0.2": - version: 2.0.2 - resolution: "@nomicfoundation/ethereumjs-statemanager@npm:2.0.2" - dependencies: - "@nomicfoundation/ethereumjs-common": 4.0.2 - "@nomicfoundation/ethereumjs-rlp": 5.0.2 - debug: ^4.3.3 - ethereum-cryptography: 0.1.3 - ethers: ^5.7.1 - js-sdsl: ^4.1.4 - checksum: 3ab6578e252e53609afd98d8ba42a99f182dcf80252f23ed9a5e0471023ffb2502130f85fc47fa7c94cd149f9be799ed9a0942ca52a143405be9267f4ad94e64 +"@nomicfoundation/edr-win32-x64-msvc@npm:0.5.2": + version: 0.5.2 + resolution: "@nomicfoundation/edr-win32-x64-msvc@npm:0.5.2" + checksum: 56da7a1283470dede413cda5f2fef96e10250ec7a25562254ca0cd8045a653212c91e40fbcf37330e7af4e036d3c3aed83ea617831f9c7a5424389c73c53ed4e languageName: node linkType: hard -"@nomicfoundation/ethereumjs-trie@npm:6.0.2": - version: 6.0.2 - resolution: "@nomicfoundation/ethereumjs-trie@npm:6.0.2" +"@nomicfoundation/edr@npm:^0.5.2": + version: 0.5.2 + resolution: "@nomicfoundation/edr@npm:0.5.2" dependencies: - "@nomicfoundation/ethereumjs-rlp": 5.0.2 - "@nomicfoundation/ethereumjs-util": 9.0.2 - "@types/readable-stream": ^2.3.13 - ethereum-cryptography: 0.1.3 - readable-stream: ^3.6.0 - checksum: d4da918d333851b9f2cce7dbd25ab5753e0accd43d562d98fd991b168b6a08d1794528f0ade40fe5617c84900378376fe6256cdbe52c8d66bf4c53293bbc7c40 + "@nomicfoundation/edr-darwin-arm64": 0.5.2 + "@nomicfoundation/edr-darwin-x64": 0.5.2 + "@nomicfoundation/edr-linux-arm64-gnu": 0.5.2 + "@nomicfoundation/edr-linux-arm64-musl": 0.5.2 + "@nomicfoundation/edr-linux-x64-gnu": 0.5.2 + "@nomicfoundation/edr-linux-x64-musl": 0.5.2 + "@nomicfoundation/edr-win32-x64-msvc": 0.5.2 + checksum: 336b1c7cad96fa78410f0c9cc9524abe9fb1e56384fe990b98bfd17f15f25b4665ad8f0525ccd9511f7c19173841fe712d50db993078629e2fc4047fda4665dc languageName: node linkType: hard -"@nomicfoundation/ethereumjs-tx@npm:5.0.2": - version: 5.0.2 - resolution: "@nomicfoundation/ethereumjs-tx@npm:5.0.2" +"@nomicfoundation/ethereumjs-common@npm:4.0.4": + version: 4.0.4 + resolution: "@nomicfoundation/ethereumjs-common@npm:4.0.4" dependencies: - "@chainsafe/ssz": ^0.9.2 - "@ethersproject/providers": ^5.7.2 - "@nomicfoundation/ethereumjs-common": 4.0.2 - "@nomicfoundation/ethereumjs-rlp": 5.0.2 - "@nomicfoundation/ethereumjs-util": 9.0.2 - ethereum-cryptography: 0.1.3 - checksum: 0bbcea75786b2ccb559afe2ecc9866fb4566a9f157b6ffba4f50960d14f4b3da2e86e273f6fadda9b860e67cfcabf589970fb951b328cb5f900a585cd21842a2 + "@nomicfoundation/ethereumjs-util": 9.0.4 + checksum: ce3f6e4ae15b976efdb7ccda27e19aadb62b5ffee209f9503e68b4fd8633715d4d697c0cc10ccd35f5e4e977edd05100d0f214e28880ec64fff77341dc34fcdf languageName: node linkType: hard -"@nomicfoundation/ethereumjs-util@npm:9.0.2": - version: 9.0.2 - resolution: "@nomicfoundation/ethereumjs-util@npm:9.0.2" +"@nomicfoundation/ethereumjs-rlp@npm:5.0.4": + version: 5.0.4 + resolution: "@nomicfoundation/ethereumjs-rlp@npm:5.0.4" + bin: + rlp: bin/rlp.cjs + checksum: ee2c2e5776c73801dc5ed636f4988b599b4563c2d0037da542ea57eb237c69dd1ac555f6bcb5e06f70515b6459779ba0d68252a6e105132b4659ab4bf62919b0 + languageName: node + linkType: hard + +"@nomicfoundation/ethereumjs-tx@npm:5.0.4": + version: 5.0.4 + resolution: "@nomicfoundation/ethereumjs-tx@npm:5.0.4" dependencies: - "@chainsafe/ssz": ^0.10.0 - "@nomicfoundation/ethereumjs-rlp": 5.0.2 + "@nomicfoundation/ethereumjs-common": 4.0.4 + "@nomicfoundation/ethereumjs-rlp": 5.0.4 + "@nomicfoundation/ethereumjs-util": 9.0.4 ethereum-cryptography: 0.1.3 - checksum: 3a08f7b88079ef9f53b43da9bdcb8195498fd3d3911c2feee2571f4d1204656053f058b2f650471c86f7d2d0ba2f814768c7cfb0f266eede41c848356afc4900 + peerDependencies: + c-kzg: ^2.1.2 + peerDependenciesMeta: + c-kzg: + optional: true + checksum: 0f1c87716682ccbcf4d92ffc6cf8ab557e658b90319d82be3219a091a736859f8803c73c98e4863682e3e86d264751c472d33ff6d3c3daf4e75b5f01d0af8fa3 languageName: node linkType: hard -"@nomicfoundation/ethereumjs-vm@npm:7.0.2": - version: 7.0.2 - resolution: "@nomicfoundation/ethereumjs-vm@npm:7.0.2" - dependencies: - "@nomicfoundation/ethereumjs-block": 5.0.2 - "@nomicfoundation/ethereumjs-blockchain": 7.0.2 - "@nomicfoundation/ethereumjs-common": 4.0.2 - "@nomicfoundation/ethereumjs-evm": 2.0.2 - "@nomicfoundation/ethereumjs-rlp": 5.0.2 - "@nomicfoundation/ethereumjs-statemanager": 2.0.2 - "@nomicfoundation/ethereumjs-trie": 6.0.2 - "@nomicfoundation/ethereumjs-tx": 5.0.2 - "@nomicfoundation/ethereumjs-util": 9.0.2 - debug: ^4.3.3 +"@nomicfoundation/ethereumjs-util@npm:9.0.4": + version: 9.0.4 + resolution: "@nomicfoundation/ethereumjs-util@npm:9.0.4" + dependencies: + "@nomicfoundation/ethereumjs-rlp": 5.0.4 ethereum-cryptography: 0.1.3 - mcl-wasm: ^0.7.1 - rustbn.js: ~0.2.0 - checksum: 1c25ba4d0644cadb8a2b0241a4bb02e578bfd7f70e3492b855c2ab5c120cb159cb8f7486f84dc1597884bd1697feedbfb5feb66e91352afb51f3694fd8e4a043 + peerDependencies: + c-kzg: ^2.1.2 + peerDependenciesMeta: + c-kzg: + optional: true + checksum: 754439f72b11cad2d8986707ad020077dcc763c4055f73e2668a0b4cadb22aa4407faa9b3c587d9eb5b97ac337afbe037eb642bc1d5a16197284f83db3462cbe languageName: node linkType: hard @@ -3098,7 +3008,7 @@ __metadata: "@openzeppelin/contracts": ~4.8.1 "@typechain/ethers-v5": ~10.1.0 "@typechain/ethers-v6": ~0.5.1 - "@typechain/hardhat": ~9.1.0 + "@typechain/hardhat": ^9.1.0 "@types/eslint": ~8 "@types/mocha": ~9.1.1 "@types/prettier": ~2 @@ -3112,9 +3022,9 @@ __metadata: eslint-config-prettier: ~9.1.0 eslint-plugin-prettier: ~5.1.3 ethers: ~6.10.0 - hardhat: ~2.19.4 - hardhat-deploy: ~0.11.45 - hardhat-deploy-ethers: ~0.4.1 + hardhat: ^2.22.8 + hardhat-deploy: ^0.12.4 + hardhat-deploy-ethers: ^0.4.2 hardhat-gas-reporter: ~1.0.9 prb-math: ^2.4.3 prettier: ~3.3.2 @@ -3511,7 +3421,7 @@ __metadata: languageName: node linkType: hard -"@typechain/hardhat@npm:~9.1.0": +"@typechain/hardhat@npm:^9.1.0": version: 9.1.0 resolution: "@typechain/hardhat@npm:9.1.0" dependencies: @@ -3883,16 +3793,6 @@ __metadata: languageName: node linkType: hard -"@types/readable-stream@npm:^2.3.13": - version: 2.3.15 - resolution: "@types/readable-stream@npm:2.3.15" - dependencies: - "@types/node": "*" - safe-buffer: ~5.1.1 - checksum: ec36f525cad09b6c65a1dafcb5ad99b9e2ed824ec49b7aa23180ac427e5d35b8a0706193ecd79ab4253a283ad485ba03d5917a98daaaa144f0ea34f4823e9d82 - languageName: node - linkType: hard - "@types/secp256k1@npm:^4.0.1, @types/secp256k1@npm:^4.0.6": version: 4.0.6 resolution: "@types/secp256k1@npm:4.0.6" @@ -5075,21 +4975,6 @@ __metadata: languageName: node linkType: hard -"abstract-level@npm:^1.0.0, abstract-level@npm:^1.0.2, abstract-level@npm:^1.0.3, abstract-level@npm:^1.0.4": - version: 1.0.4 - resolution: "abstract-level@npm:1.0.4" - dependencies: - buffer: ^6.0.3 - catering: ^2.1.0 - is-buffer: ^2.0.5 - level-supports: ^4.0.0 - level-transcoder: ^1.0.1 - module-error: ^1.0.1 - queue-microtask: ^1.2.3 - checksum: 5b70d08926f5234c3c23ffca848542af4def780dc96d6ca35a81659af80e6439c46f5106bd14a5ea37465173d7dcc8294317048b0194fdf6480103edc4aa9e63 - languageName: node - linkType: hard - "acorn-jsx@npm:^5.3.2": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" @@ -5731,13 +5616,6 @@ __metadata: languageName: node linkType: hard -"bigint-crypto-utils@npm:^3.0.23": - version: 3.3.0 - resolution: "bigint-crypto-utils@npm:3.3.0" - checksum: 9598ce57b23f776c8936d44114c9f051e62b5fa654915b664784cbcbacc5aa0485f4479571c51ff58008abb1210c0d6a234853742f07cf84bda890f2a1e01000 - languageName: node - linkType: hard - "bignumber.js@npm:9.0.1": version: 9.0.1 resolution: "bignumber.js@npm:9.0.1" @@ -5909,18 +5787,6 @@ __metadata: languageName: node linkType: hard -"browser-level@npm:^1.0.1": - version: 1.0.1 - resolution: "browser-level@npm:1.0.1" - dependencies: - abstract-level: ^1.0.2 - catering: ^2.1.1 - module-error: ^1.0.2 - run-parallel-limit: ^1.1.0 - checksum: 67fbc77ce832940bfa25073eccff279f512ad56f545deb996a5b23b02316f5e76f4a79d381acc27eda983f5c9a2566aaf9c97e4fdd0748288c4407307537a29b - languageName: node - linkType: hard - "browser-stdout@npm:^1.3.1": version: 1.3.1 resolution: "browser-stdout@npm:1.3.1" @@ -6119,13 +5985,6 @@ __metadata: languageName: node linkType: hard -"case@npm:^1.6.3": - version: 1.6.3 - resolution: "case@npm:1.6.3" - checksum: febe73278f910b0d28aab7efd6f51c235f9aa9e296148edb56dfb83fd58faa88308c30ce9a0122b6e53e0362c44f4407105bd5ef89c46860fc2b184e540fd68d - languageName: node - linkType: hard - "caseless@npm:^0.12.0, caseless@npm:~0.12.0": version: 0.12.0 resolution: "caseless@npm:0.12.0" @@ -6133,13 +5992,6 @@ __metadata: languageName: node linkType: hard -"catering@npm:^2.1.0, catering@npm:^2.1.1": - version: 2.1.1 - resolution: "catering@npm:2.1.1" - checksum: 205daefa69c935b0c19f3d8f2e0a520dd69aebe9bda55902958003f7c9cff8f967dfb90071b421bd6eb618576f657a89d2bc0986872c9bc04bbd66655e9d4bd6 - languageName: node - linkType: hard - "cbor@npm:^8.1.0": version: 8.1.0 resolution: "cbor@npm:8.1.0" @@ -6339,20 +6191,6 @@ __metadata: languageName: node linkType: hard -"classic-level@npm:^1.2.0": - version: 1.4.1 - resolution: "classic-level@npm:1.4.1" - dependencies: - abstract-level: ^1.0.2 - catering: ^2.1.0 - module-error: ^1.0.1 - napi-macros: ^2.2.2 - node-gyp: latest - node-gyp-build: ^4.3.0 - checksum: 62e7e07297fcd656941eb88f92b91df0046ebb2b34987e98ec870cb736f096e212ef109a25541deba2f30866b9d5df550594ed04948614815dd5964933da50a9 - languageName: node - linkType: hard - "classnames@npm:2.3.1": version: 2.3.1 resolution: "classnames@npm:2.3.1" @@ -6591,13 +6429,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:3.0.2": - version: 3.0.2 - resolution: "commander@npm:3.0.2" - checksum: 6d14ad030d1904428139487ed31febcb04c1604db2b8d9fae711f60ee6718828dc0e11602249e91c8a97b0e721e9c6d53edbc166bad3cde1596851d59a8f824d - languageName: node - linkType: hard - "commander@npm:^10.0.0": version: 10.0.1 resolution: "commander@npm:10.0.1" @@ -6605,6 +6436,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^8.1.0": + version: 8.3.0 + resolution: "commander@npm:8.3.0" + checksum: 0f82321821fc27b83bd409510bb9deeebcfa799ff0bf5d102128b500b7af22872c0c92cb6a0ebc5a4cf19c6b550fba9cedfa7329d18c6442a625f851377bacf0 + languageName: node + linkType: hard + "complex.js@npm:^2.1.1": version: 2.1.1 resolution: "complex.js@npm:2.1.1" @@ -6915,7 +6753,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:~4.3.1, debug@npm:~4.3.2": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:~4.3.1, debug@npm:~4.3.2": version: 4.3.5 resolution: "debug@npm:4.3.5" dependencies: @@ -8483,7 +8321,7 @@ __metadata: languageName: node linkType: hard -"ethers@npm:^5.7.0, ethers@npm:^5.7.1, ethers@npm:^5.7.2": +"ethers@npm:^5.7.0, ethers@npm:^5.7.2, ethers@npm:~5.7.0": version: 5.7.2 resolution: "ethers@npm:5.7.2" dependencies: @@ -9037,19 +8875,6 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^0.30.0": - version: 0.30.0 - resolution: "fs-extra@npm:0.30.0" - dependencies: - graceful-fs: ^4.1.2 - jsonfile: ^2.1.0 - klaw: ^1.0.0 - path-is-absolute: ^1.0.0 - rimraf: ^2.2.8 - checksum: 6edfd65fc813baa27f1603778c0f5ec11f8c5006a20b920437813ee2023eba18aeec8bef1c89b2e6c84f9fc90fdc7c916f4a700466c8c69d22a35d018f2570f0 - languageName: node - linkType: hard - "fs-extra@npm:^10.0.0": version: 10.1.0 resolution: "fs-extra@npm:10.1.0" @@ -9182,13 +9007,6 @@ __metadata: languageName: node linkType: hard -"functional-red-black-tree@npm:^1.0.1": - version: 1.0.1 - resolution: "functional-red-black-tree@npm:1.0.1" - checksum: ca6c170f37640e2d94297da8bb4bf27a1d12bea3e00e6a3e007fd7aa32e37e000f5772acf941b4e4f3cf1c95c3752033d0c509af157ad8f526e7f00723b9eb9f - languageName: node - linkType: hard - "functions-have-names@npm:^1.2.3": version: 1.2.3 resolution: "functions-have-names@npm:1.2.3" @@ -9533,7 +9351,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.1.9, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 @@ -9590,7 +9408,7 @@ __metadata: languageName: node linkType: hard -"hardhat-deploy-ethers@npm:~0.4.1": +"hardhat-deploy-ethers@npm:^0.4.2": version: 0.4.2 resolution: "hardhat-deploy-ethers@npm:0.4.2" peerDependencies: @@ -9601,9 +9419,9 @@ __metadata: languageName: node linkType: hard -"hardhat-deploy@npm:~0.11.45": - version: 0.11.45 - resolution: "hardhat-deploy@npm:0.11.45" +"hardhat-deploy@npm:^0.12.4": + version: 0.12.4 + resolution: "hardhat-deploy@npm:0.12.4" dependencies: "@ethersproject/abi": ^5.7.0 "@ethersproject/abstract-signer": ^5.7.0 @@ -9628,8 +9446,8 @@ __metadata: match-all: ^1.2.6 murmur-128: ^0.2.1 qs: ^6.9.4 - zksync-web3: ^0.14.3 - checksum: 7ecce33c3305857bdd1873a25d391e27ae9f581df75757035cb028ace7bb5fbb83f053435e843bc3d925e7fd8412c3dc582797fe5b4bbe1fef7f3dd989a7c878 + zksync-ethers: ^5.0.0 + checksum: 995a20a7ae8d10d2b961690e0903cd2a4a07198bc3d20a15d4734f2d9aade261b6f0ffb9e01b8fc013de34b687e401ed0c90dfc4d592571576f133ce8cbf3003 languageName: node linkType: hard @@ -9646,22 +9464,16 @@ __metadata: languageName: node linkType: hard -"hardhat@npm:~2.19.4": - version: 2.19.5 - resolution: "hardhat@npm:2.19.5" +"hardhat@npm:^2.22.8": + version: 2.22.8 + resolution: "hardhat@npm:2.22.8" dependencies: "@ethersproject/abi": ^5.1.2 "@metamask/eth-sig-util": ^4.0.0 - "@nomicfoundation/ethereumjs-block": 5.0.2 - "@nomicfoundation/ethereumjs-blockchain": 7.0.2 - "@nomicfoundation/ethereumjs-common": 4.0.2 - "@nomicfoundation/ethereumjs-evm": 2.0.2 - "@nomicfoundation/ethereumjs-rlp": 5.0.2 - "@nomicfoundation/ethereumjs-statemanager": 2.0.2 - "@nomicfoundation/ethereumjs-trie": 6.0.2 - "@nomicfoundation/ethereumjs-tx": 5.0.2 - "@nomicfoundation/ethereumjs-util": 9.0.2 - "@nomicfoundation/ethereumjs-vm": 7.0.2 + "@nomicfoundation/edr": ^0.5.2 + "@nomicfoundation/ethereumjs-common": 4.0.4 + "@nomicfoundation/ethereumjs-tx": 5.0.4 + "@nomicfoundation/ethereumjs-util": 9.0.4 "@nomicfoundation/solidity-analyzer": ^0.1.0 "@sentry/node": ^5.18.1 "@types/bn.js": ^5.1.0 @@ -9692,7 +9504,7 @@ __metadata: raw-body: ^2.4.1 resolve: 1.17.0 semver: ^6.3.0 - solc: 0.7.3 + solc: 0.8.26 source-map-support: ^0.5.13 stacktrace-parser: ^0.1.10 tsort: 0.0.1 @@ -9709,7 +9521,7 @@ __metadata: optional: true bin: hardhat: internal/cli/bootstrap.js - checksum: 316b03a1d090360e6ed471fe125360ec0c66c5bb62e29492898932b1a9a5227c12d7a18343877c59725f321647a01fde0841649bf7d8a4a746148a0d38b0ee27 + checksum: 3731b510540f800b3b931e3ad7db4510dbd35eff18f34382875778db43de2a5ce1c52596c392aa694324f66392e844fede85954ab3cdc08df3da10f2a810135f languageName: node linkType: hard @@ -10241,13 +10053,6 @@ __metadata: languageName: node linkType: hard -"is-buffer@npm:^2.0.5": - version: 2.0.5 - resolution: "is-buffer@npm:2.0.5" - checksum: 764c9ad8b523a9f5a32af29bdf772b08eb48c04d2ad0a7240916ac2688c983bf5f8504bf25b35e66240edeb9d9085461f9b5dae1f3d2861c6b06a65fe983de42 - languageName: node - linkType: hard - "is-callable@npm:^1.1.3, is-callable@npm:^1.1.4, is-callable@npm:^1.2.7": version: 1.2.7 resolution: "is-callable@npm:1.2.7" @@ -10881,18 +10686,6 @@ __metadata: languageName: node linkType: hard -"jsonfile@npm:^2.1.0": - version: 2.4.0 - resolution: "jsonfile@npm:2.4.0" - dependencies: - graceful-fs: ^4.1.6 - dependenciesMeta: - graceful-fs: - optional: true - checksum: f5064aabbc9e35530dc471d8b203ae1f40dbe949ddde4391c6f6a6d310619a15f0efdae5587df594d1d70c555193aaeee9d2ed4aec9ffd5767bd5e4e62d49c3d - languageName: node - linkType: hard - "jsonfile@npm:^4.0.0": version: 4.0.0 resolution: "jsonfile@npm:4.0.0" @@ -10995,18 +10788,6 @@ __metadata: languageName: node linkType: hard -"klaw@npm:^1.0.0": - version: 1.3.1 - resolution: "klaw@npm:1.3.1" - dependencies: - graceful-fs: ^4.1.9 - dependenciesMeta: - graceful-fs: - optional: true - checksum: 8f69e4797c26e7c3f2426bfa85f38a3da3c2cb1b4c6bd850d2377aed440d41ce9d806f2885c2e2e224372c56af4b1d43b8a499adecf9a05e7373dc6b8b7c52e4 - languageName: node - linkType: hard - "kleur@npm:^3.0.3": version: 3.0.3 resolution: "kleur@npm:3.0.3" @@ -11030,34 +10811,6 @@ __metadata: languageName: node linkType: hard -"level-supports@npm:^4.0.0": - version: 4.0.1 - resolution: "level-supports@npm:4.0.1" - checksum: d4552b42bb8cdeada07b0f6356c7a90fefe76279147331f291aceae26e3e56d5f927b09ce921647c0230bfe03ddfbdcef332be921e5c2194421ae2bfa3cf6368 - languageName: node - linkType: hard - -"level-transcoder@npm:^1.0.1": - version: 1.0.1 - resolution: "level-transcoder@npm:1.0.1" - dependencies: - buffer: ^6.0.3 - module-error: ^1.0.1 - checksum: 304f08d802faf3491a533b6d87ad8be3cabfd27f2713bbe9d4c633bf50fcb9460eab5a6776bf015e101ead7ba1c1853e05e7f341112f17a9d0cb37ee5a421a25 - languageName: node - linkType: hard - -"level@npm:^8.0.0": - version: 8.0.1 - resolution: "level@npm:8.0.1" - dependencies: - abstract-level: ^1.0.4 - browser-level: ^1.0.1 - classic-level: ^1.2.0 - checksum: c5641cbba666ef9eb0292aad01d86a4f1af18e637d1fc097c65bf0109ab8d7e6fba8c8faf6c74ae4e48edac4310f7dd87def26ffeebfe395c7afd9bd2461ab97 - languageName: node - linkType: hard - "levn@npm:^0.4.1": version: 0.4.1 resolution: "levn@npm:0.4.1" @@ -11374,15 +11127,6 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^5.1.1": - version: 5.1.1 - resolution: "lru-cache@npm:5.1.1" - dependencies: - yallist: ^3.0.2 - checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb - languageName: node - linkType: hard - "lru-cache@npm:^6.0.0": version: 6.0.0 resolution: "lru-cache@npm:6.0.0" @@ -11468,13 +11212,6 @@ __metadata: languageName: node linkType: hard -"mcl-wasm@npm:^0.7.1": - version: 0.7.9 - resolution: "mcl-wasm@npm:0.7.9" - checksum: 6b6ed5084156b98b2db70b223e1ba2c01953970b48a2e0c4ea3eeb9296610e6b3bfb2a2cce9e92e2d7ad61778b5f5a630e705e663835e915ba188c174a0a37fa - languageName: node - linkType: hard - "md5.js@npm:^1.3.4": version: 1.3.5 resolution: "md5.js@npm:1.3.5" @@ -11502,17 +11239,6 @@ __metadata: languageName: node linkType: hard -"memory-level@npm:^1.0.0": - version: 1.0.0 - resolution: "memory-level@npm:1.0.0" - dependencies: - abstract-level: ^1.0.0 - functional-red-black-tree: ^1.0.1 - module-error: ^1.0.1 - checksum: 80b1b7aedaf936e754adbcd7b9303018c3684fb32f9992fd967c448f145d177f16c724fbba9ed3c3590a9475fd563151eae664d69b83d2ad48714852e9fc5c72 - languageName: node - linkType: hard - "memorystream@npm:^0.3.1": version: 0.3.1 resolution: "memorystream@npm:0.3.1" @@ -11856,13 +11582,6 @@ __metadata: languageName: node linkType: hard -"module-error@npm:^1.0.1, module-error@npm:^1.0.2": - version: 1.0.2 - resolution: "module-error@npm:1.0.2" - checksum: 5d653e35bd55b3e95f8aee2cdac108082ea892e71b8f651be92cde43e4ee86abee4fa8bd7fc3fe5e68b63926d42f63c54cd17b87a560c31f18739295575a3962 - languageName: node - linkType: hard - "motion@npm:10.16.2": version: 10.16.2 resolution: "motion@npm:10.16.2" @@ -11939,13 +11658,6 @@ __metadata: languageName: node linkType: hard -"napi-macros@npm:^2.2.2": - version: 2.2.2 - resolution: "napi-macros@npm:2.2.2" - checksum: c6f9bd71cdbbc37ddc3535aa5be481238641d89585b8a3f4d301cb89abf459e2d294810432bb7d12056d1f9350b1a0899a5afcf460237a3da6c398cf0fec7629 - languageName: node - linkType: hard - "napi-wasm@npm:^1.1.0": version: 1.1.0 resolution: "napi-wasm@npm:1.1.0" @@ -13294,7 +13006,7 @@ __metadata: languageName: node linkType: hard -"queue-microtask@npm:^1.2.2, queue-microtask@npm:^1.2.3": +"queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 @@ -13799,7 +13511,7 @@ __metadata: languageName: node linkType: hard -"require-from-string@npm:^2.0.0, require-from-string@npm:^2.0.2": +"require-from-string@npm:^2.0.2": version: 2.0.2 resolution: "require-from-string@npm:2.0.2" checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b @@ -13970,17 +13682,6 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:^2.2.8": - version: 2.7.1 - resolution: "rimraf@npm:2.7.1" - dependencies: - glob: ^7.1.3 - bin: - rimraf: ./bin.js - checksum: cdc7f6eacb17927f2a075117a823e1c5951792c6498ebcce81ca8203454a811d4cf8900314154d3259bb8f0b42ab17f67396a8694a54cae3283326e57ad250cd - languageName: node - linkType: hard - "rimraf@npm:^3.0.2": version: 3.0.2 resolution: "rimraf@npm:3.0.2" @@ -14032,15 +13733,6 @@ __metadata: languageName: node linkType: hard -"run-parallel-limit@npm:^1.1.0": - version: 1.1.0 - resolution: "run-parallel-limit@npm:1.1.0" - dependencies: - queue-microtask: ^1.2.2 - checksum: 672c3b87e7f939c684b9965222b361421db0930223ed1e43ebf0e7e48ccc1a022ea4de080bef4d5468434e2577c33b7681e3f03b7593fdc49ad250a55381123c - languageName: node - linkType: hard - "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -14050,13 +13742,6 @@ __metadata: languageName: node linkType: hard -"rustbn.js@npm:~0.2.0": - version: 0.2.0 - resolution: "rustbn.js@npm:0.2.0" - checksum: 2148e7ba34e70682907ee29df4784639e6eb025481b2c91249403b7ec57181980161868d9aa24822a5075dd1bb5a180dfedc77309e5f0d27b6301f9b563af99a - languageName: node - linkType: hard - "rxjs@npm:6": version: 6.6.7 resolution: "rxjs@npm:6.6.7" @@ -14531,22 +14216,20 @@ __metadata: languageName: node linkType: hard -"solc@npm:0.7.3": - version: 0.7.3 - resolution: "solc@npm:0.7.3" +"solc@npm:0.8.26": + version: 0.8.26 + resolution: "solc@npm:0.8.26" dependencies: command-exists: ^1.2.8 - commander: 3.0.2 + commander: ^8.1.0 follow-redirects: ^1.12.1 - fs-extra: ^0.30.0 js-sha3: 0.8.0 memorystream: ^0.3.1 - require-from-string: ^2.0.0 semver: ^5.5.0 tmp: 0.0.33 bin: - solcjs: solcjs - checksum: 2d8eb16c6d8f648213c94dc8d977cffe5099cba7d41c82d92d769ef71ae8320a985065ce3d6c306440a85f8e8d2b27fb30bdd3ac38f69e5c1fa0ab8a3fb2f217 + solcjs: solc.js + checksum: e3eaeac76e60676377b357af8f3919d4c8c6a74b74112b49279fe8c74a3dfa1de8afe4788689fc307453bde336edc8572988d2cf9e909f84d870420eb640400c languageName: node linkType: hard @@ -16705,7 +16388,7 @@ __metadata: languageName: node linkType: hard -"yallist@npm:^3.0.0, yallist@npm:^3.0.2, yallist@npm:^3.1.1": +"yallist@npm:^3.0.0, yallist@npm:^3.1.1": version: 3.1.1 resolution: "yallist@npm:3.1.1" checksum: 48f7bb00dc19fc635a13a39fe547f527b10c9290e7b3e836b9a8f1ca04d4d342e85714416b3c2ab74949c9c66f9cebb0473e6bc353b79035356103b47641285d @@ -16875,12 +16558,14 @@ __metadata: languageName: node linkType: hard -"zksync-web3@npm:^0.14.3": - version: 0.14.4 - resolution: "zksync-web3@npm:0.14.4" +"zksync-ethers@npm:^5.0.0": + version: 5.9.2 + resolution: "zksync-ethers@npm:5.9.2" + dependencies: + ethers: ~5.7.0 peerDependencies: - ethers: ^5.7.0 - checksum: f702a3437f48a8d42c4bb35b8dd13671a168aadfc4e23ce723d62959220ccb6bf9c529c60331fe5b91afaa622147c6a37490551474fe3e35c06ac476524b5160 + ethers: ~5.7.0 + checksum: bbad1d48889e6fe03596982bdbdf56024df4024b2ac7713d0c4e63b143eee2bd4a825f98ce131732b22594d3901affddf1d4b863f70f0573dfec86e816eb995e languageName: node linkType: hard