Address Details
contract
0x260d41018b110b2C720a9d55F6Ba1b0C17152D36
- Contract Name
- DirectPaymentsPool
- Creator
- 0x2ceade–010627 at 0xab5f68–20ce29
- Balance
- 0 CELO ( )
- Locked CELO Balance
- 0.00 CELO
- Voting CELO Balance
- 0.00 CELO
- Pending Unlocked Gold
- 0.00 CELO
- Tokens
-
Fetching tokens...
- Transactions
- Fetching transactions...
- Transfers
- Fetching transfers...
- Gas Used
- Fetching gas used...
- Last Balance Update
- 28900170
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- DirectPaymentsPool
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 0
- EVM Version
- paris
- Verified at
- 2024-11-25T18:55:42.753437Z
contracts/DirectPayments/DirectPaymentsPool.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8; import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import { IERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import { IERC721ReceiverUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol"; import { ProvableNFT } from "./ProvableNFT.sol"; import { DirectPaymentsFactory } from "./DirectPaymentsFactory.sol"; import { DirectPayemntsLibrary } from "./DirectPaymentsLibrary.sol"; import "../GoodCollective/GoodCollectiveSuperApp.sol"; interface IMembersValidator { function isMemberValid( address pool, address operator, address member, bytes memory extraData ) external returns (bool); } interface IIdentityV2 { function getWhitelistedRoot(address member) external view returns (address); } /** - optional members validator (but need atleast uniqueness or members) - anyone can claim an nfttype - project id at the registery? - factory -> register the pool, claim nfttype, deploy pool - events */ contract DirectPaymentsPool is IERC721ReceiverUpgradeable, AccessControlUpgradeable, GoodCollectiveSuperApp, UUPSUpgradeable { using SafeERC20Upgradeable for IERC20Upgradeable; error NOT_MANAGER(); error ALREADY_CLAIMED(uint256); error NFT_MISSING(uint256); error OVER_MEMBER_LIMITS(address); error OVER_GLOBAL_LIMITS(); error UNSUPPORTED_NFT(); error NO_BALANCE(); error NFTTYPE_CHANGED(); error EMPTY_MANAGER(); bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE"); bytes32 public constant MEMBER_ROLE = keccak256("MEMBER_ROLE"); bytes32 public constant MINTER_ROLE = keccak256("MINTER"); event PoolCreated( address indexed pool, string indexed projectId, string ipfs, uint32 indexed nftType, DirectPaymentsPool.PoolSettings poolSettings, DirectPaymentsPool.SafetyLimits poolLimits ); event PoolSettingsChanged(PoolSettings settings); event PoolLimitsChanged(SafetyLimits limits); event EventRewardClaimed( uint256 indexed tokenId, uint16 eventType, uint32 eventTimestamp, uint256 eventQuantity, string eventUri, address[] contributers, uint256 rewardPerContributer ); event NFTClaimed(uint256 indexed tokenId, uint256 totalRewards); event NOT_MEMBER_OR_WHITELISTED(address contributer); // Define functions struct PoolSettings { uint32 nftType; uint16[] validEvents; uint128[] rewardPerEvent; address manager; IMembersValidator membersValidator; IIdentityV2 uniquenessValidator; IERC20Upgradeable rewardToken; bool allowRewardOverride; } struct SafetyLimits { uint maxTotalPerMonth; uint256 maxMemberPerMonth; uint256 maxMemberPerDay; } struct LimitsData { uint128 daily; uint128 monthly; uint128 total; uint64 lastReward; uint64 lastMonth; } PoolSettings public settings; SafetyLimits public limits; ProvableNFT public nft; mapping(uint256 => bool) public claimedNfts; mapping(address => bool) private members_unused; // using access control instead mapping(address => LimitsData) public memberLimits; LimitsData public globalLimits; DirectPaymentsFactory public registry; uint32 public managerFeeBps; /// @custom:oz-upgrades-unsafe-allow constructor constructor(ISuperfluid _host, IV3SwapRouter _swapRouter) GoodCollectiveSuperApp(_host, _swapRouter) {} /** * @dev Authorizes an upgrade for the implementation contract. * @param impl The address of the new implementation contract. */ function _authorizeUpgrade(address impl) internal virtual override onlyRole(DEFAULT_ADMIN_ROLE) {} function getRegistry() public view override returns (IRegistry) { return IRegistry(address(registry)); } function getManagerFee() public view override returns (address feeRecipient, uint32 feeBps) { return (settings.manager, managerFeeBps); } /** * @dev Initializes the contract with the given settings and limits. * @param _nft The ProvableNFT contract address. * @param _settings The PoolSettings struct containing pool settings. * @param _limits The SafetyLimits struct containing safety limits. */ function initialize( ProvableNFT _nft, PoolSettings memory _settings, SafetyLimits memory _limits, uint32 _managerFeeBps, DirectPaymentsFactory _registry ) external initializer { registry = _registry; settings = _settings; limits = _limits; nft = _nft; managerFeeBps = _managerFeeBps; _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); // when using factory this gives factory role which then set role to the real msg.sender _setupRole(MANAGER_ROLE, _settings.manager); _setupRole(MINTER_ROLE, _settings.manager); setSuperToken(ISuperToken(address(settings.rewardToken))); } function upgradeToLatest(bytes memory data) external payable virtual { address impl = address(DirectPaymentsFactory(registry).impl()); _authorizeUpgrade(impl); _upgradeToAndCallUUPS(impl, data, false); } /** * @dev Claims rewards for the specified NFT ID. * @param _nftId The ID of the NFT to claim rewards for. */ function claim(uint256 _nftId) external { claim(_nftId, nft.getNFTData(_nftId)); } /** * @dev Claims rewards for a given NFT ID and its associated data. * @param _nftId The ID of the NFT to claim rewards for. * @param _data The associated data for the NFT. * Emits a {ALREADY_CLAIMED} error if the NFT has already been claimed. * Emits a {NFT_MISSING} error if the NFT is not owned by this contract. */ function claim(uint256 _nftId, ProvableNFT.NFTData memory _data) public { nft.proveNFTData(_nftId, _data); if (claimedNfts[_nftId]) revert ALREADY_CLAIMED(_nftId); // TODO: should pool own the NFTs? // if (settings.collectNfts && nft.ownerOf(_nftId) != address(this)) revert NFT_MISSING(_nftId); _claim(_nftId, _data); } /** * @dev Claims rewards for the specified NFT ID. * @param _nftId The ID of the NFT to claim rewards for. * @param _data The NFTData struct containing data about the NFT. */ function _claim(uint256 _nftId, ProvableNFT.NFTData memory _data) internal { claimedNfts[_nftId] = true; uint totalRewards; uint rewardsBalance = settings.rewardToken.balanceOf(address(this)); bool allowRewardOverride = settings.allowRewardOverride; for (uint256 i = 0; i < _data.events.length; i++) { uint reward = ( allowRewardOverride && _data.events[i].rewardOverride > 0 ? _data.events[i].rewardOverride : _eventReward(_data.events[i].subtype) ) * _data.events[i].quantity; if (reward > 0) { totalRewards += reward; if (totalRewards > rewardsBalance) revert NO_BALANCE(); rewardsBalance -= totalRewards; _sendReward(_data.events[i].contributers, uint128(reward)); emit EventRewardClaimed( _nftId, _data.events[i].subtype, _data.events[i].timestamp, _data.events[i].quantity, _data.events[i].eventUri, _data.events[i].contributers, uint128(reward / _data.events[i].contributers.length) ); } } emit NFTClaimed(_nftId, totalRewards); } /** * @dev Returns the reward amount for the specified event type. * @param _eventType The type of the event to get the reward for. * @return reward amount for the specified event type. */ function _eventReward(uint16 _eventType) internal view returns (uint128 reward) { for (uint i = 0; i < settings.validEvents.length; i++) { if (_eventType == settings.validEvents[i]) return settings.rewardPerEvent[i]; } return 0; } /** * @dev Sends rewards to the specified recipients. * @param recipients The addresses of the recipients to send rewards to. * @param reward The total amount of rewards to send. */ function _sendReward(address[] memory recipients, uint128 reward) internal { uint128 perReward = uint128(reward / recipients.length); uint128 totalSent; for (uint i = 0; i < recipients.length; i++) { bool valid = _enforceAndUpdateMemberLimits(recipients[i], perReward); if (valid) { settings.rewardToken.safeTransfer(recipients[i], perReward); totalSent += perReward; } else { emit NOT_MEMBER_OR_WHITELISTED(recipients[i]); } } _enforceAndUpdateGlobalLimits(totalSent); } /** * @dev Enforces and updates the reward limits for the specified member. * @param member The address of the member to enforce and update limits for. * @param reward The amount of rewards to enforce and update limits for. */ function _enforceAndUpdateMemberLimits(address member, uint128 reward) internal returns (bool) { //dont revert on non valid members, just dont reward them (their reward is lost) if (_addMember(member, "") == false) { return false; } DirectPayemntsLibrary._updateMemberLimits(memberLimits[member], reward, _month()); if ( memberLimits[member].daily > limits.maxMemberPerDay || memberLimits[member].monthly > limits.maxMemberPerMonth ) revert OVER_MEMBER_LIMITS(member); return true; } /** * @dev Enforces and updates the global reward limits. * @param reward The amount of rewards to enforce and update limits for. */ function _enforceAndUpdateGlobalLimits(uint128 reward) internal { DirectPayemntsLibrary._updateGlobalLimits(globalLimits, reward, _month()); if (globalLimits.monthly > limits.maxTotalPerMonth) revert OVER_GLOBAL_LIMITS(); } /** * @dev Returns the current month. * @return month current month as a uint64 value. */ function _month() internal view returns (uint64 month) { return uint64(block.timestamp / (60 * 60 * 24 * 30)); } /** * @dev Adds a member to the contract. * @param member The address of the member to add. * @param extraData Additional data to validate the member. */ function _addMember(address member, bytes memory extraData) internal returns (bool isMember) { if (hasRole(MEMBER_ROLE, member)) return true; if (address(settings.uniquenessValidator) != address(0)) { address rootAddress = settings.uniquenessValidator.getWhitelistedRoot(member); if (rootAddress == address(0)) return false; } // if no members validator then anyone can join the pool if (address(settings.membersValidator) != address(0)) { if (settings.membersValidator.isMemberValid(address(this), msg.sender, member, extraData) == false) { return false; } } _grantRole(MEMBER_ROLE, member); return true; } function _grantRole(bytes32 role, address account) internal virtual override { if (role == MEMBER_ROLE) { registry.addMember(account); } super._grantRole(role, account); } function _revokeRole(bytes32 role, address account) internal virtual override { if (role == MEMBER_ROLE) { registry.removeMember(account); } super._revokeRole(role, account); } function mintNFT(address _to, ProvableNFT.NFTData memory _nftData, bool withClaim) external onlyRole(MINTER_ROLE) { uint nftId = nft.mintPermissioned(_to, _nftData, true, ""); if (withClaim) { claim(nftId, _nftData); } } /** * @dev Receives an ERC721 token * @param operator The address of the operator that sent the token. * @param from The address of the sender that sent the token. * @param tokenId The ID of the token received. * @param data Additional data to trigger a claim for rewards. * @return A bytes4 value indicating success or failure. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4) { // bool triggerClaim; // if (data.length > 0) (triggerClaim) = abi.decode(data, (bool)); // if (triggerClaim) { // ProvableNFT.NFTData memory nftData = nft.getNFTData(tokenId); // if (nftData.nftType > 0) // check the nftData is actually stored on-chain, otherwise claim will not work // { // claim(tokenId, nftData); // } // } ProvableNFT.NFTData memory nftData = nft.getNFTData(tokenId); if (nftData.nftType != settings.nftType) revert UNSUPPORTED_NFT(); return DirectPaymentsPool.onERC721Received.selector; } /** * @dev Sets the safety limits for the pool. * @param _limits The new safety limits. */ function setPoolLimits(SafetyLimits memory _limits) public onlyRole(MANAGER_ROLE) { limits = _limits; emit PoolLimitsChanged(_limits); } /** * @dev Sets the settings for the pool. * @param _settings The new pool settings. */ function setPoolSettings(PoolSettings memory _settings, uint32 _managerFeeBps) public onlyRole(MANAGER_ROLE) { managerFeeBps = _managerFeeBps; if (_settings.nftType != settings.nftType) revert NFTTYPE_CHANGED(); if (_settings.manager == address(0)) revert EMPTY_MANAGER(); _revokeRole(DEFAULT_ADMIN_ROLE, settings.manager); settings = _settings; _setupRole(DEFAULT_ADMIN_ROLE, _settings.manager); emit PoolSettingsChanged(_settings); } }
/
// SPDX-License-Identifier: MIT import { DataTypes } from "./utils/DataTypes.sol"; pragma solidity >=0.8.0; pragma experimental ABIEncoderV2; interface ERC20 { function balanceOf(address addr) external view returns (uint256); function transfer(address to, uint256 amount) external returns (bool); function approve(address spender, uint256 amount) external returns (bool); function decimals() external view returns (uint8); function mint(address to, uint256 mintAmount) external returns (uint256); function burn(uint256 amount) external; function totalSupply() external view returns (uint256); function allowance( address owner, address spender ) external view returns (uint256); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); function name() external view returns (string memory); function symbol() external view returns (string memory); event Transfer(address indexed from, address indexed to, uint256 amount); event Transfer( address indexed from, address indexed to, uint256 amount, bytes data ); } interface cERC20 is ERC20 { function mint(uint256 mintAmount) external returns (uint256); function redeemUnderlying(uint256 mintAmount) external returns (uint256); function redeem(uint256 mintAmount) external returns (uint256); function exchangeRateCurrent() external returns (uint256); function exchangeRateStored() external view returns (uint256); function underlying() external returns (address); } interface IGoodDollar is ERC20 { // view functions function feeRecipient() external view returns (address); function getFees( uint256 value, address sender, address recipient ) external view returns (uint256 fee, bool senderPays); function cap() external view returns (uint256); function isPauser(address _pauser) external view returns (bool); function getFees(uint256 value) external view returns (uint256, bool); function isMinter(address minter) external view returns (bool); function formula() external view returns (address); function identity() external view returns (address); function owner() external view returns (address); // state changing functions function setFeeRecipient(address _feeRecipient) external; function setFormula(address _formula) external; function transferOwnership(address _owner) external; function addPauser(address _pauser) external; function pause() external; function unpause() external; function burn(uint256 amount) external; function burnFrom(address account, uint256 amount) external; function renounceMinter() external; function addMinter(address minter) external; function transferAndCall( address to, uint256 value, bytes calldata data ) external returns (bool); function setIdentity(address identity) external; } interface IERC2917 is ERC20 { /// @dev This emit when interests amount per block is changed by the owner of the contract. /// It emits with the old interests amount and the new interests amount. event InterestRatePerBlockChanged(uint256 oldValue, uint256 newValue); /// @dev This emit when a users' productivity has changed /// It emits with the user's address and the the value after the change. event ProductivityIncreased(address indexed user, uint256 value); /// @dev This emit when a users' productivity has changed /// It emits with the user's address and the the value after the change. event ProductivityDecreased(address indexed user, uint256 value); /// @dev Return the current contract's interests rate per block. /// @return The amount of interests currently producing per each block. function interestsPerBlock() external view returns (uint256); /// @notice Change the current contract's interests rate. /// @dev Note the best practice will be restrict the gross product provider's contract address to call this. /// @return The true/fase to notice that the value has successfully changed or not, when it succeed, it will emite the InterestRatePerBlockChanged event. function changeInterestRatePerBlock(uint256 value) external returns (bool); /// @notice It will get the productivity of given user. /// @dev it will return 0 if user has no productivity proved in the contract. /// @return user's productivity and overall productivity. function getProductivity( address user ) external view returns (uint256, uint256); /// @notice increase a user's productivity. /// @dev Note the best practice will be restrict the callee to prove of productivity's contract address. /// @return true to confirm that the productivity added success. function increaseProductivity( address user, uint256 value ) external returns (bool); /// @notice decrease a user's productivity. /// @dev Note the best practice will be restrict the callee to prove of productivity's contract address. /// @return true to confirm that the productivity removed success. function decreaseProductivity( address user, uint256 value ) external returns (bool); /// @notice take() will return the interests that callee will get at current block height. /// @dev it will always calculated by block.number, so it will change when block height changes. /// @return amount of the interests that user are able to mint() at current block height. function take() external view returns (uint256); /// @notice similar to take(), but with the block height joined to calculate return. /// @dev for instance, it returns (_amount, _block), which means at block height _block, the callee has accumulated _amount of interests. /// @return amount of interests and the block height. function takeWithBlock() external view returns (uint256, uint256); /// @notice mint the avaiable interests to callee. /// @dev once it mint, the amount of interests will transfer to callee's address. /// @return the amount of interests minted. function mint() external returns (uint256); } interface Staking { struct Staker { // The staked DAI amount uint256 stakedDAI; // The latest block number which the // staker has staked tokens uint256 lastStake; } function stakeDAI(uint256 amount) external; function withdrawStake() external; function stakers(address staker) external view returns (Staker memory); } interface Uniswap { function swapExactETHForTokens( uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); function swapExactTokensForETH( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function WETH() external pure returns (address); function factory() external pure returns (address); function quote( uint256 amountA, uint256 reserveA, uint256 reserveB ) external pure returns (uint256 amountB); function getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut ) external pure returns (uint256 amountIn); function getAmountOut( uint256 amountI, uint256 reserveIn, uint256 reserveOut ) external pure returns (uint256 amountOut); function getAmountsOut( uint256 amountIn, address[] memory path ) external pure returns (uint256[] memory amounts); } interface UniswapFactory { function getPair( address tokenA, address tokenB ) external view returns (address); } interface UniswapPair { function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function kLast() external view returns (uint256); function token0() external view returns (address); function token1() external view returns (address); function totalSupply() external view returns (uint256); function balanceOf(address owner) external view returns (uint256); } interface Reserve { function buy( address _buyWith, uint256 _tokenAmount, uint256 _minReturn ) external returns (uint256); } interface IIdentity { function isWhitelisted(address user) external view returns (bool); function addWhitelistedWithDID(address account, string memory did) external; function removeWhitelisted(address account) external; function addBlacklisted(address account) external; function removeBlacklisted(address account) external; function isBlacklisted(address user) external view returns (bool); function addIdentityAdmin(address account) external returns (bool); function setAvatar(address _avatar) external; function isIdentityAdmin(address account) external view returns (bool); function owner() external view returns (address); function removeContract(address account) external; function isDAOContract(address account) external view returns (bool); function addrToDID(address account) external view returns (string memory); function didHashToAddress(bytes32 hash) external view returns (address); function lastAuthenticated(address account) external view returns (uint256); event WhitelistedAdded(address user); } interface IIdentityV2 is IIdentity { function addWhitelistedWithDIDAndChain( address account, string memory did, uint256 orgChainId, uint256 dateAuthenticated ) external; function getWhitelistedRoot( address account ) external view returns (address root); } interface IUBIScheme { function currentDay() external view returns (uint256); function periodStart() external view returns (uint256); function hasClaimed(address claimer) external view returns (bool); } interface IFirstClaimPool { function awardUser(address user) external returns (uint256); function claimAmount() external view returns (uint256); function end() external; } interface ProxyAdmin { function getProxyImplementation( address proxy ) external view returns (address); function getProxyAdmin(address proxy) external view returns (address); function upgrade(address proxy, address implementation) external; function owner() external view returns (address); function transferOwnership(address newOwner) external; function upgradeAndCall( address proxy, address implementation, bytes memory data ) external; } /** * @dev Interface for chainlink oracles to obtain price datas */ interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData( uint80 _roundId ) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestAnswer() external view returns (int256); } /** @dev interface for AAVE lending Pool */ interface ILendingPool { /** * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. * - E.g. User deposits 100 USDC and gets in return 100 aUSDC * @param asset The address of the underlying asset to deposit * @param amount The amount to be deposited * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens * is a different wallet * @param referralCode Code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man **/ function deposit( address asset, uint256 amount, address onBehalfOf, uint16 referralCode ) external; /** * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC * @param asset The address of the underlying asset to withdraw * @param amount The underlying amount to be withdrawn * - Send the value type(uint256).max in order to withdraw the whole aToken balance * @param to Address that will receive the underlying, same as msg.sender if the user * wants to receive it on his own wallet, or a different address if the beneficiary is a * different wallet * @return The final amount withdrawn **/ function withdraw( address asset, uint256 amount, address to ) external returns (uint256); /** * @dev Returns the state and configuration of the reserve * @param asset The address of the underlying asset of the reserve * @return The state of the reserve **/ function getReserveData( address asset ) external view returns (DataTypes.ReserveData memory); } interface IDonationStaking { function stakeDonations() external payable; } interface INameService { function getAddress(string memory _name) external view returns (address); } interface IAaveIncentivesController { /** * @dev Claims reward for an user, on all the assets of the lending pool, accumulating the pending rewards * @param amount Amount of rewards to claim * @param to Address that will be receiving the rewards * @return Rewards claimed **/ function claimRewards( address[] calldata assets, uint256 amount, address to ) external returns (uint256); /** * @dev Returns the total of rewards of an user, already accrued + not yet accrued * @param user The address of the user * @return The rewards **/ function getRewardsBalance( address[] calldata assets, address user ) external view returns (uint256); } interface IGoodStaking { function collectUBIInterest( address recipient ) external returns (uint256, uint256, uint256); function iToken() external view returns (address); function currentGains( bool _returnTokenBalanceInUSD, bool _returnTokenGainsInUSD ) external view returns (uint256, uint256, uint256, uint256, uint256); function getRewardEarned(address user) external view returns (uint256); function getGasCostForInterestTransfer() external view returns (uint256); function rewardsMinted( address user, uint256 rewardsPerBlock, uint256 blockStart, uint256 blockEnd ) external returns (uint256); } interface IHasRouter { function getRouter() external view returns (Uniswap); } interface IAdminWallet { function addAdmins(address payable[] memory _admins) external; function removeAdmins(address[] memory _admins) external; function owner() external view returns (address); function transferOwnership(address _owner) external; } interface IMultichainRouter { // Swaps `amount` `token` from this chain to `toChainID` chain with recipient `to` function anySwapOut( address token, address to, uint256 amount, uint256 toChainID ) external; // Swaps `amount` `token` from this chain to `toChainID` chain with recipient `to` function anySwapOutUnderlying( address token, address to, uint256 amount, uint256 toChainID ) external; }
/IFeesFormula.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8; interface IFeesFormula { function getTxFees( uint256 value, address sender, address recipient ) external view returns (uint256 fee, bool senderPays); }
/superfluid/ISuperGoodDollar.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol"; import { ISuperToken } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/CustomSuperTokenBase.sol"; import "../IFeesFormula.sol"; import "../../Interfaces.sol"; // GoodDollar specific functions interface IGoodDollarCustom { // view functions function feeRecipient() external view returns (address); function getFees( uint256 value ) external view returns (uint256 fee, bool senderPays); function getFees( uint256 value, address sender, address recipient ) external view returns (uint256 fee, bool senderPays); function formula() external view returns (IFeesFormula); function identity() external view returns (IIdentity); function cap() external view returns (uint256); function isMinter(address _minter) external view returns (bool); function isPauser(address _pauser) external view returns (bool); function owner() external view returns (address); // state changing functions function setFeeRecipient(address _feeRecipient) external; function setFormula(IFeesFormula _formula) external; function setIdentity(IIdentityV2 _identity) external; function transferOwnership(address _owner) external; function transferAndCall( address to, uint256 value, bytes calldata data ) external returns (bool); function mint(address to, uint256 amount) external returns (bool); function burn(uint256 amount) external; function burnFrom(address account, uint256 amount) external; function addMinter(address _minter) external; function renounceMinter() external; function addPauser(address _pauser) external; function pause() external; function unpause() external; } interface ISuperGoodDollar is IGoodDollarCustom, ISuperToken, IERC20PermitUpgradeable { function initialize( string calldata name, string calldata symbol, uint256 _cap, IFeesFormula _formula, IIdentity _identity, address _feeRecipient, address _owner ) external; }
/DataTypes.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; library DataTypes { // refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties. struct ReserveData { //stores the reserve configuration ReserveConfigurationMap configuration; //the liquidity index. Expressed in ray uint128 liquidityIndex; //variable borrow index. Expressed in ray uint128 variableBorrowIndex; //the current supply rate. Expressed in ray uint128 currentLiquidityRate; //the current variable borrow rate. Expressed in ray uint128 currentVariableBorrowRate; //the current stable borrow rate. Expressed in ray uint128 currentStableBorrowRate; uint40 lastUpdateTimestamp; //tokens addresses address aTokenAddress; address stableDebtTokenAddress; address variableDebtTokenAddress; //address of the interest rate strategy address interestRateStrategyAddress; //the id of the reserve. Represents the position in the list of the active reserves uint8 id; } struct ReserveConfigurationMap { //bit 0-15: LTV //bit 16-31: Liq. threshold //bit 32-47: Liq. bonus //bit 48-55: Decimals //bit 56: Reserve is active //bit 57: reserve is frozen //bit 58: borrowing is enabled //bit 59: stable rate borrowing enabled //bit 60-63: reserved //bit 64-79: reserve factor uint256 data; } enum InterestRateMode { NONE, STABLE, VARIABLE } }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControlUpgradeable.sol"; import "../utils/ContextUpgradeable.sol"; import "../utils/StringsUpgradeable.sol"; import "../utils/introspection/ERC165Upgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable { function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", StringsUpgradeable.toHexString(account), " is missing role ", StringsUpgradeable.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControlUpgradeable { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.3) (interfaces/IERC1967.sol) pragma solidity ^0.8.0; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. * * _Available since v4.9._ */ interface IERC1967Upgradeable { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822ProxiableUpgradeable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
/ERC1967UpgradeUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.3) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeaconUpgradeable.sol"; import "../../interfaces/IERC1967Upgradeable.sol"; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/StorageSlotUpgradeable.sol"; import "../utils/Initializable.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable { function __ERC1967Upgrade_init() internal onlyInitializing { } function __ERC1967Upgrade_init_unchained() internal onlyInitializing { } // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { _functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data); } } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) { require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed"); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
/IBeaconUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeaconUpgradeable { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
/Initializable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
/UUPSUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.0; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../ERC1967/ERC1967UpgradeUpgradeable.sol"; import "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable { function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeTo(address newImplementation) external virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
/IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
/extensions/draft-IERC20PermitUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
/utils/SafeERC20Upgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/draft-IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20Upgradeable { using AddressUpgradeable for address; function safeTransfer( IERC20Upgradeable token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20Upgradeable token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20Upgradeable token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
/ERC721Upgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.2) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; import "./IERC721Upgradeable.sol"; import "./IERC721ReceiverUpgradeable.sol"; import "./extensions/IERC721MetadataUpgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../utils/StringsUpgradeable.sol"; import "../../utils/introspection/ERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable { using AddressUpgradeable for address; using StringsUpgradeable for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC721_init_unchained(name_, symbol_); } function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) { return interfaceId == type(IERC721Upgradeable).interfaceId || interfaceId == type(IERC721MetadataUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: address zero is not a valid owner"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _ownerOf(tokenId); require(owner != address(0), "ERC721: invalid token ID"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721Upgradeable.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not token owner or approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { _requireMinted(tokenId); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data ) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _safeTransfer(from, to, tokenId, data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory data ) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist */ function _ownerOf(uint256 tokenId) internal view virtual returns (address) { return _owners[tokenId]; } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _ownerOf(tokenId) != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { address owner = ERC721Upgradeable.ownerOf(tokenId); return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint( address to, uint256 tokenId, bytes memory data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId, 1); // Check that tokenId was not minted by `_beforeTokenTransfer` hook require(!_exists(tokenId), "ERC721: token already minted"); unchecked { // Will not overflow unless all 2**256 token ids are minted to the same owner. // Given that tokens are minted one by one, it is impossible in practice that // this ever happens. Might change if we allow batch minting. // The ERC fails to describe this case. _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); _afterTokenTransfer(address(0), to, tokenId, 1); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * This is an internal function that does not check if the sender is authorized to operate on the token. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721Upgradeable.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId, 1); // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook owner = ERC721Upgradeable.ownerOf(tokenId); // Clear approvals delete _tokenApprovals[tokenId]; unchecked { // Cannot overflow, as that would require more tokens to be burned/transferred // out than the owner initially received through minting and transferring in. _balances[owner] -= 1; } delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); _afterTokenTransfer(owner, address(0), tokenId, 1); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721Upgradeable.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId, 1); // Check that tokenId was not transferred by `_beforeTokenTransfer` hook require(ERC721Upgradeable.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); // Clear approvals from the previous owner delete _tokenApprovals[tokenId]; unchecked { // `_balances[from]` cannot overflow for the same reason as described in `_burn`: // `from`'s balance is the number of token held, which is at least one before the current // transfer. // `_balances[to]` could overflow in the conditions described in `_mint`. That would require // all 2**256 token ids to be minted, which in practice is impossible. _balances[from] -= 1; _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId, 1); } /** * @dev Approve `to` to operate on `tokenId` * * Emits an {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721Upgradeable.ownerOf(tokenId), to, tokenId); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Reverts if the `tokenId` has not been minted yet. */ function _requireMinted(uint256 tokenId) internal view virtual { require(_exists(tokenId), "ERC721: invalid token ID"); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory data ) private returns (bool) { if (to.isContract()) { try IERC721ReceiverUpgradeable(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { return retval == IERC721ReceiverUpgradeable.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`. * - When `from` is zero, the tokens will be minted for `to`. * - When `to` is zero, ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * - `batchSize` is non-zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual {} /** * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`. * - When `from` is zero, the tokens were minted for `to`. * - When `to` is zero, ``from``'s tokens were burned. * - `from` and `to` are never both zero. * - `batchSize` is non-zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual {} /** * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. * * WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant * being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such * that `ownerOf(tokenId)` is `a`. */ // solhint-disable-next-line func-name-mixedcase function __unsafe_increaseBalance(address account, uint256 amount) internal { _balances[account] += amount; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[44] private __gap; }
/IERC721ReceiverUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721ReceiverUpgradeable { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
/IERC721Upgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721Upgradeable is IERC165Upgradeable { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
/extensions/IERC721MetadataUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721Upgradeable.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721MetadataUpgradeable is IERC721Upgradeable { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlotUpgradeable { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = MathUpgradeable.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, MathUpgradeable.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
/ERC165Upgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165Upgradeable).interfaceId; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
/IERC165Upgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165Upgradeable { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
/MathUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.0; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. * * _Available since v4.8.3._ */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
/ERC1967Proxy.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol) pragma solidity ^0.8.0; import "../Proxy.sol"; import "./ERC1967Upgrade.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an * implementation address that can be changed. This address is stored in storage in the location specified by * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the * implementation behind the proxy. */ contract ERC1967Proxy is Proxy, ERC1967Upgrade { /** * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`. * * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded * function call, and allows initializing the storage of the proxy like a Solidity constructor. */ constructor(address _logic, bytes memory _data) payable { _upgradeToAndCall(_logic, _data, false); } /** * @dev Returns the current implementation address. */ function _implementation() internal view virtual override returns (address impl) { return ERC1967Upgrade._getImplementation(); } }
/ERC1967Upgrade.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../interfaces/IERC1967.sol"; import "../../interfaces/draft-IERC1822.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ */ abstract contract ERC1967Upgrade is IERC1967 { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol) pragma solidity ^0.8.0; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function * and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _fallback() internal virtual { _beforeFallback(); _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback() external payable virtual { _fallback(); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data * is empty. */ receive() external payable virtual { _fallback(); } /** * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` * call, or as part of the Solidity `fallback` or `receive` functions. * * If overridden should call `super._beforeFallback()`. */ function _beforeFallback() internal virtual {} }
/BeaconProxy.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol) pragma solidity ^0.8.0; import "./IBeacon.sol"; import "../Proxy.sol"; import "../ERC1967/ERC1967Upgrade.sol"; /** * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. * * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't * conflict with the storage layout of the implementation behind the proxy. * * _Available since v3.4._ */ contract BeaconProxy is Proxy, ERC1967Upgrade { /** * @dev Initializes the proxy with `beacon`. * * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity * constructor. * * Requirements: * * - `beacon` must be a contract with the interface {IBeacon}. */ constructor(address beacon, bytes memory data) payable { _upgradeBeaconToAndCall(beacon, data, false); } /** * @dev Returns the current beacon address. */ function _beacon() internal view virtual returns (address) { return _getBeacon(); } /** * @dev Returns the current implementation address of the associated beacon. */ function _implementation() internal view virtual override returns (address) { return IBeacon(_getBeacon()).implementation(); } /** * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}. * * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. * * Requirements: * * - `beacon` must be a contract. * - The implementation returned by `beacon` must be a contract. */ function _setBeacon(address beacon, bytes memory data) internal virtual { _upgradeBeaconToAndCall(beacon, data, false); } }
/IBeacon.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
/UpgradeableBeacon.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/UpgradeableBeacon.sol) pragma solidity ^0.8.0; import "./IBeacon.sol"; import "../../access/Ownable.sol"; import "../../utils/Address.sol"; /** * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their * implementation contract, which is where they will delegate all function calls. * * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon. */ contract UpgradeableBeacon is IBeacon, Ownable { address private _implementation; /** * @dev Emitted when the implementation returned by the beacon is changed. */ event Upgraded(address indexed implementation); /** * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the * beacon. */ constructor(address implementation_) { _setImplementation(implementation_); } /** * @dev Returns the current implementation address. */ function implementation() public view virtual override returns (address) { return _implementation; } /** * @dev Upgrades the beacon to a new implementation. * * Emits an {Upgraded} event. * * Requirements: * * - msg.sender must be the owner of the contract. * - `newImplementation` must be a contract. */ function upgradeTo(address newImplementation) public virtual onlyOwner { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Sets the implementation contract address for this beacon * * Requirements: * * - `newImplementation` must be a contract. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "UpgradeableBeacon: implementation is not a contract"); _implementation = newImplementation; } }
/IERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
/IERC721.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
/extensions/IERC721Metadata.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
/IERC777.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC777/IERC777.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC777Token standard as defined in the EIP. * * This contract uses the * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let * token holders and recipients react to token movements by using setting implementers * for the associated interfaces in said registry. See {IERC1820Registry} and * {ERC1820Implementer}. */ interface IERC777 { /** * @dev Emitted when `amount` tokens are created by `operator` and assigned to `to`. * * Note that some additional user `data` and `operatorData` can be logged in the event. */ event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); /** * @dev Emitted when `operator` destroys `amount` tokens from `account`. * * Note that some additional user `data` and `operatorData` can be logged in the event. */ event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); /** * @dev Emitted when `operator` is made operator for `tokenHolder`. */ event AuthorizedOperator(address indexed operator, address indexed tokenHolder); /** * @dev Emitted when `operator` is revoked its operator status for `tokenHolder`. */ event RevokedOperator(address indexed operator, address indexed tokenHolder); /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() external view returns (string memory); /** * @dev Returns the smallest part of the token that is not divisible. This * means all token operations (creation, movement and destruction) must have * amounts that are a multiple of this number. * * For most token contracts, this value will equal 1. */ function granularity() external view returns (uint256); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by an account (`owner`). */ function balanceOf(address owner) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * If send or receive hooks are registered for the caller and `recipient`, * the corresponding functions will be called with `data` and empty * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. * * Emits a {Sent} event. * * Requirements * * - the caller must have at least `amount` tokens. * - `recipient` cannot be the zero address. * - if `recipient` is a contract, it must implement the {IERC777Recipient} * interface. */ function send(address recipient, uint256 amount, bytes calldata data) external; /** * @dev Destroys `amount` tokens from the caller's account, reducing the * total supply. * * If a send hook is registered for the caller, the corresponding function * will be called with `data` and empty `operatorData`. See {IERC777Sender}. * * Emits a {Burned} event. * * Requirements * * - the caller must have at least `amount` tokens. */ function burn(uint256 amount, bytes calldata data) external; /** * @dev Returns true if an account is an operator of `tokenHolder`. * Operators can send and burn tokens on behalf of their owners. All * accounts are their own operator. * * See {operatorSend} and {operatorBurn}. */ function isOperatorFor(address operator, address tokenHolder) external view returns (bool); /** * @dev Make an account an operator of the caller. * * See {isOperatorFor}. * * Emits an {AuthorizedOperator} event. * * Requirements * * - `operator` cannot be calling address. */ function authorizeOperator(address operator) external; /** * @dev Revoke an account's operator status for the caller. * * See {isOperatorFor} and {defaultOperators}. * * Emits a {RevokedOperator} event. * * Requirements * * - `operator` cannot be calling address. */ function revokeOperator(address operator) external; /** * @dev Returns the list of default operators. These accounts are operators * for all token holders, even if {authorizeOperator} was never called on * them. * * This list is immutable, but individual holders may revoke these via * {revokeOperator}, in which case {isOperatorFor} will return false. */ function defaultOperators() external view returns (address[] memory); /** * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must * be an operator of `sender`. * * If send or receive hooks are registered for `sender` and `recipient`, * the corresponding functions will be called with `data` and * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. * * Emits a {Sent} event. * * Requirements * * - `sender` cannot be the zero address. * - `sender` must have at least `amount` tokens. * - the caller must be an operator for `sender`. * - `recipient` cannot be the zero address. * - if `recipient` is a contract, it must implement the {IERC777Recipient} * interface. */ function operatorSend( address sender, address recipient, uint256 amount, bytes calldata data, bytes calldata operatorData ) external; /** * @dev Destroys `amount` tokens from `account`, reducing the total supply. * The caller must be an operator of `account`. * * If a send hook is registered for `account`, the corresponding function * will be called with `data` and `operatorData`. See {IERC777Sender}. * * Emits a {Burned} event. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. * - the caller must be an operator for `account`. */ function operatorBurn(address account, uint256 amount, bytes calldata data, bytes calldata operatorData) external; event Sent( address indexed operator, address indexed from, address indexed to, uint256 amount, bytes data, bytes operatorData ); }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
/
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
/IERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
/CFAv1Library.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; import { ISuperfluid, ISuperfluidToken, IConstantFlowAgreementV1 } from "../interfaces/superfluid/ISuperfluid.sol"; /** * @title Constant flow agreement v1 library * @author Superfluid * @dev for working with the constant flow agreement within solidity * @dev the first set of functions are each for callAgreement() * @dev the second set of functions are each for use in callAgreementWithContext() */ library CFAv1Library { /** * @dev Initialization data * @param host Superfluid host for calling agreements * @param cfa Constant Flow Agreement contract */ struct InitData { ISuperfluid host; IConstantFlowAgreementV1 cfa; } /** * @dev Create flow without userData * @param cfaLibrary The cfaLibrary storage variable * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate */ function createFlow( InitData storage cfaLibrary, address receiver, ISuperfluidToken token, int96 flowRate ) internal { createFlow(cfaLibrary, receiver, token, flowRate, new bytes(0)); } /** * @dev Create flow with userData * @param cfaLibrary The cfaLibrary storage variable * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate * @param userData The user provided data */ function createFlow( InitData storage cfaLibrary, address receiver, ISuperfluidToken token, int96 flowRate, bytes memory userData ) internal { cfaLibrary.host.callAgreement( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.createFlow, ( token, receiver, flowRate, new bytes(0) // placeholder ) ), userData ); } /** * @dev Update flow without userData * @param cfaLibrary The cfaLibrary storage variable * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate */ function updateFlow( InitData storage cfaLibrary, address receiver, ISuperfluidToken token, int96 flowRate ) internal { updateFlow(cfaLibrary, receiver, token, flowRate, new bytes(0)); } /** * @dev Update flow with userData * @param cfaLibrary The cfaLibrary storage variable * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate * @param userData The user provided data */ function updateFlow( InitData storage cfaLibrary, address receiver, ISuperfluidToken token, int96 flowRate, bytes memory userData ) internal { cfaLibrary.host.callAgreement( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.updateFlow, ( token, receiver, flowRate, new bytes(0) // placeholder ) ), userData ); } /** * @dev Delete flow without userData * @param cfaLibrary The cfaLibrary storage variable * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow */ function deleteFlow( InitData storage cfaLibrary, address sender, address receiver, ISuperfluidToken token ) internal { deleteFlow(cfaLibrary, sender, receiver, token, new bytes(0)); } /** * @dev Delete flow with userData * @param cfaLibrary The cfaLibrary storage variable * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow * @param userData The user provided data */ function deleteFlow( InitData storage cfaLibrary, address sender, address receiver, ISuperfluidToken token, bytes memory userData ) internal { cfaLibrary.host.callAgreement( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.deleteFlow, ( token, sender, receiver, new bytes(0) // placeholder ) ), userData ); } /** * @dev Create flow with context and userData * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate */ function createFlowWithCtx( InitData storage cfaLibrary, bytes memory ctx, address receiver, ISuperfluidToken token, int96 flowRate ) internal returns (bytes memory newCtx) { return createFlowWithCtx(cfaLibrary, ctx, receiver, token, flowRate, new bytes(0)); } /** * @dev Create flow with context and userData * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate * @param userData The user provided data */ function createFlowWithCtx( InitData storage cfaLibrary, bytes memory ctx, address receiver, ISuperfluidToken token, int96 flowRate, bytes memory userData ) internal returns (bytes memory newCtx) { (newCtx, ) = cfaLibrary.host.callAgreementWithContext( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.createFlow, ( token, receiver, flowRate, new bytes(0) // placeholder ) ), userData, ctx ); } /** * @dev Update flow with context * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate */ function updateFlowWithCtx( InitData storage cfaLibrary, bytes memory ctx, address receiver, ISuperfluidToken token, int96 flowRate ) internal returns (bytes memory newCtx) { return updateFlowWithCtx(cfaLibrary, ctx, receiver, token, flowRate, new bytes(0)); } /** * @dev Update flow with context and userData * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate * @param userData The user provided data */ function updateFlowWithCtx( InitData storage cfaLibrary, bytes memory ctx, address receiver, ISuperfluidToken token, int96 flowRate, bytes memory userData ) internal returns (bytes memory newCtx) { (newCtx, ) = cfaLibrary.host.callAgreementWithContext( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.updateFlow, ( token, receiver, flowRate, new bytes(0) // placeholder ) ), userData, ctx ); } /** * @dev Delete flow with context * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow */ function deleteFlowWithCtx( InitData storage cfaLibrary, bytes memory ctx, address sender, address receiver, ISuperfluidToken token ) internal returns (bytes memory newCtx) { return deleteFlowWithCtx(cfaLibrary, ctx, sender, receiver, token, new bytes(0)); } /** * @dev Delete flow with context and userData * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow * @param userData The user provided data */ function deleteFlowWithCtx( InitData storage cfaLibrary, bytes memory ctx, address sender, address receiver, ISuperfluidToken token, bytes memory userData ) internal returns (bytes memory newCtx) { (newCtx, ) = cfaLibrary.host.callAgreementWithContext( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.deleteFlow, ( token, sender, receiver, new bytes(0) // placeholder ) ), userData, ctx ); } /** * @dev Creates flow as an operator without userData * @param cfaLibrary The cfaLibrary storage variable * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate */ function createFlowByOperator( InitData storage cfaLibrary, address sender, address receiver, ISuperfluidToken token, int96 flowRate ) internal returns (bytes memory newCtx) { return createFlowByOperator(cfaLibrary, sender, receiver, token, flowRate, new bytes(0)); } /** * @dev Creates flow as an operator with userData * @param cfaLibrary The cfaLibrary storage variable * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate * @param userData The user provided data */ function createFlowByOperator( InitData storage cfaLibrary, address sender, address receiver, ISuperfluidToken token, int96 flowRate, bytes memory userData ) internal returns (bytes memory newCtx) { return cfaLibrary.host.callAgreement( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.createFlowByOperator, ( token, sender, receiver, flowRate, new bytes(0) // placeholder ) ), userData ); } /** * @dev Creates flow as an operator without userData with context * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate */ function createFlowByOperatorWithCtx( InitData storage cfaLibrary, bytes memory ctx, address sender, address receiver, ISuperfluidToken token, int96 flowRate ) internal returns (bytes memory newCtx) { return createFlowByOperatorWithCtx( cfaLibrary, ctx, sender, receiver, token, flowRate, new bytes(0) ); } /** * @dev Creates flow as an operator with userData and context * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate * @param userData The user provided data */ function createFlowByOperatorWithCtx( InitData storage cfaLibrary, bytes memory ctx, address sender, address receiver, ISuperfluidToken token, int96 flowRate, bytes memory userData ) internal returns (bytes memory newCtx) { (newCtx, ) = cfaLibrary.host.callAgreementWithContext( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.createFlowByOperator, ( token, sender, receiver, flowRate, new bytes(0) // placeholder ) ), userData, ctx ); } /** * @dev Updates a flow as an operator without userData * @param cfaLibrary The cfaLibrary storage variable * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate */ function updateFlowByOperator( InitData storage cfaLibrary, address sender, address receiver, ISuperfluidToken token, int96 flowRate ) internal returns (bytes memory newCtx) { return updateFlowByOperator(cfaLibrary, sender, receiver, token, flowRate, new bytes(0)); } /** * @dev Updates flow as an operator with userData * @param cfaLibrary The cfaLibrary storage variable * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate * @param userData The user provided data */ function updateFlowByOperator( InitData storage cfaLibrary, address sender, address receiver, ISuperfluidToken token, int96 flowRate, bytes memory userData ) internal returns (bytes memory newCtx) { return cfaLibrary.host.callAgreement( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.updateFlowByOperator, ( token, sender, receiver, flowRate, new bytes(0) ) ), userData ); } /** * @dev Updates a flow as an operator without userData with context * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate */ function updateFlowByOperatorWithCtx( InitData storage cfaLibrary, bytes memory ctx, address sender, address receiver, ISuperfluidToken token, int96 flowRate ) internal returns (bytes memory newCtx) { return updateFlowByOperatorWithCtx( cfaLibrary, ctx, sender, receiver, token, flowRate, new bytes(0) ); } /** * @dev Updates flow as an operator with userData and context * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow * @param flowRate The desired flowRate * @param userData The user provided data */ function updateFlowByOperatorWithCtx( InitData storage cfaLibrary, bytes memory ctx, address sender, address receiver, ISuperfluidToken token, int96 flowRate, bytes memory userData ) internal returns (bytes memory newCtx) { (newCtx, ) = cfaLibrary.host.callAgreementWithContext( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.updateFlowByOperator, ( token, sender, receiver, flowRate, new bytes(0) ) ), userData, ctx ); } /** * @dev Deletes a flow as an operator without userData * @param cfaLibrary The cfaLibrary storage variable * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow */ function deleteFlowByOperator( InitData storage cfaLibrary, address sender, address receiver, ISuperfluidToken token ) internal returns (bytes memory newCtx) { return deleteFlowByOperator(cfaLibrary, sender, receiver, token, new bytes(0)); } /** * @dev Deletes a flow as an operator with userData * @param cfaLibrary The cfaLibrary storage variable * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow * @param userData The user provided data */ function deleteFlowByOperator( InitData storage cfaLibrary, address sender, address receiver, ISuperfluidToken token, bytes memory userData ) internal returns (bytes memory newCtx) { return cfaLibrary.host.callAgreement( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.deleteFlowByOperator, ( token, sender, receiver, new bytes(0) ) ), userData ); } /** * @dev Deletes a flow as an operator without userData with context * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow */ function deleteFlowByOperatorWithCtx( InitData storage cfaLibrary, bytes memory ctx, address sender, address receiver, ISuperfluidToken token ) internal returns (bytes memory newCtx) { return deleteFlowByOperatorWithCtx(cfaLibrary, ctx, sender, receiver, token, new bytes(0)); } /** * @dev Deletes a flow as an operator with userData and context * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param sender The sender of the flow * @param receiver The receiver of the flow * @param token The token to flow * @param userData The user provided data */ function deleteFlowByOperatorWithCtx( InitData storage cfaLibrary, bytes memory ctx, address sender, address receiver, ISuperfluidToken token, bytes memory userData ) internal returns (bytes memory newCtx) { (newCtx, ) = cfaLibrary.host.callAgreementWithContext( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.deleteFlowByOperator, ( token, sender, receiver, new bytes(0) ) ), userData, ctx ); } /** * @dev Updates the permissions of a flow operator * @param cfaLibrary The cfaLibrary storage variable * @param flowOperator The operator that can create/update/delete flows * @param token The token of flows handled by the operator * @param permissions The number of the permissions: create = 1; update = 2; delete = 4; * To give multiple permissions, sum the above. create_delete = 5; create_update_delete = 7; etc * @param flowRateAllowance The allowance for flow creation. Decremented as flowRate increases */ function updateFlowOperatorPermissions( InitData storage cfaLibrary, address flowOperator, ISuperfluidToken token, uint8 permissions, int96 flowRateAllowance ) internal returns (bytes memory newCtx) { return cfaLibrary.host.callAgreement( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.updateFlowOperatorPermissions, ( token, flowOperator, permissions, flowRateAllowance, new bytes(0) ) ), new bytes(0) ); } /** * @dev Updates the permissions of a flow operator with context * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param flowOperator The operator that can create/update/delete flows * @param token The token of flows handled by the operator * @param permissions The number of the permissions: create = 1; update = 2; delete = 4; * To give multiple permissions, sum the above. create_delete = 5; create_update_delete = 7; etc * @param flowRateAllowance The allowance for flow creation. Decremented as flowRate increases */ function updateFlowOperatorPermissionsWithCtx( InitData storage cfaLibrary, bytes memory ctx, address flowOperator, ISuperfluidToken token, uint8 permissions, int96 flowRateAllowance ) internal returns (bytes memory newCtx) { (newCtx, ) = cfaLibrary.host.callAgreementWithContext( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.updateFlowOperatorPermissions, ( token, flowOperator, permissions, flowRateAllowance, new bytes(0) ) ), new bytes(0), ctx ); } /** * @dev Grants full, unlimited permission to a flow operator * @param cfaLibrary The cfaLibrary storage variable * @param flowOperator The operator that can create/update/delete flows * @param token The token of flows handled by the operator */ function authorizeFlowOperatorWithFullControl( InitData storage cfaLibrary, address flowOperator, ISuperfluidToken token ) internal returns (bytes memory newCtx) { return cfaLibrary.host.callAgreement( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.authorizeFlowOperatorWithFullControl, ( token, flowOperator, new bytes(0) ) ), new bytes(0) ); } /** * @dev Grants full, unlimited permission to a flow operator with context * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param flowOperator The operator that can create/update/delete flows * @param token The token of flows handled by the operator */ function authorizeFlowOperatorWithFullControlWithCtx( InitData storage cfaLibrary, bytes memory ctx, address flowOperator, ISuperfluidToken token ) internal returns (bytes memory newCtx) { (newCtx, ) = cfaLibrary.host.callAgreementWithContext( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.authorizeFlowOperatorWithFullControl, ( token, flowOperator, new bytes(0) ) ), new bytes(0), ctx ); } /** * @dev Revokes all permissions from a flow operator * @param cfaLibrary The cfaLibrary storage variable * @param flowOperator The operator that can create/update/delete flows * @param token The token of flows handled by the operator */ function revokeFlowOperatorWithFullControl( InitData storage cfaLibrary, address flowOperator, ISuperfluidToken token ) internal returns (bytes memory newCtx) { return cfaLibrary.host.callAgreement( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.revokeFlowOperatorWithFullControl, ( token, flowOperator, new bytes(0) ) ), new bytes(0) ); } /** * @dev Revokes all permissions from a flow operator * @param cfaLibrary The cfaLibrary storage variable * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param flowOperator The operator that can create/update/delete flows * @param token The token of flows handled by the operator */ function revokeFlowOperatorWithFullControlWithCtx( InitData storage cfaLibrary, bytes memory ctx, address flowOperator, ISuperfluidToken token ) internal returns (bytes memory newCtx) { (newCtx, ) = cfaLibrary.host.callAgreementWithContext( cfaLibrary.cfa, abi.encodeCall( cfaLibrary.cfa.revokeFlowOperatorWithFullControl, ( token, flowOperator, new bytes(0) ) ), new bytes(0), ctx ); } }
/SuperTokenV1Library.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; import { ISuperfluid, ISuperToken, IConstantFlowAgreementV1, IInstantDistributionAgreementV1 } from "../interfaces/superfluid/ISuperfluid.sol"; /** * @title Library for Token Centric Interface * @author Superfluid * @dev Set `using for ISuperToken` in including file, and call any of these functions on an instance * of ISuperToken. * Note that it is important to "warm up" the cache and cache the host, cfa, ida before calling, * this is only applicable to Foundry tests where the vm.expectRevert() will not work as expected. */ library SuperTokenV1Library { /** CFA BASE CRUD ************************************* */ /** * @dev Create flow without userData * @param token The token used in flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate */ function createFlow(ISuperToken token, address receiver, int96 flowRate) internal returns (bool) { return createFlow(token, receiver, flowRate, new bytes(0)); } /** * @dev Create flow with userData * @param token The token used in flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate * @param userData The userdata passed along with call */ function createFlow(ISuperToken token, address receiver, int96 flowRate, bytes memory userData) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); host.callAgreement( cfa, abi.encodeCall( cfa.createFlow, (token, receiver, flowRate, new bytes(0)) ), userData // userData ); return true; } /** * @dev Update flow without userData * @param token The token used in flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate */ function updateFlow(ISuperToken token, address receiver, int96 flowRate) internal returns (bool) { return updateFlow(token, receiver, flowRate, new bytes(0)); } /** * @dev Update flow with userData * @param token The token used in flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate * @param userData The userdata passed along with call */ function updateFlow(ISuperToken token, address receiver, int96 flowRate, bytes memory userData) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); host.callAgreement( cfa, abi.encodeCall( cfa.updateFlow, (token, receiver, flowRate, new bytes(0)) ), userData ); return true; } /** * @dev Delete flow without userData * @param token The token used in flow * @param sender The sender of the flow * @param receiver The receiver of the flow */ function deleteFlow(ISuperToken token, address sender, address receiver) internal returns (bool) { return deleteFlow(token, sender, receiver, new bytes(0)); } /** * @dev Delete flow with userData * @param token The token used in flow * @param sender The sender of the flow * @param receiver The receiver of the flow * @param userData The userdata passed along with call */ function deleteFlow(ISuperToken token, address sender, address receiver, bytes memory userData) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); host.callAgreement( cfa, abi.encodeCall( cfa.deleteFlow, (token, sender, receiver, new bytes(0)) ), userData ); return true; } /** CFA ACL ************************************* */ /** * @dev Update permissions for flow operator * @param token The token used in flow * @param flowOperator The address given flow permissions * @param allowCreate creation permissions * @param allowCreate update permissions * @param allowCreate deletion permissions * @param flowRateAllowance The allowance provided to flowOperator */ function setFlowPermissions( ISuperToken token, address flowOperator, bool allowCreate, bool allowUpdate, bool allowDelete, int96 flowRateAllowance ) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); uint8 permissionsBitmask = (allowCreate ? 1 : 0) | (allowUpdate ? 1 : 0) << 1 | (allowDelete ? 1 : 0) << 2; host.callAgreement( cfa, abi.encodeCall( cfa.updateFlowOperatorPermissions, (token, flowOperator, permissionsBitmask, flowRateAllowance, new bytes(0)) ), new bytes(0) ); return true; } /** * @dev Update permissions for flow operator - give operator max permissions * @param token The token used in flow * @param flowOperator The address given flow permissions */ function setMaxFlowPermissions( ISuperToken token, address flowOperator ) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); host.callAgreement( cfa, abi.encodeCall( cfa.authorizeFlowOperatorWithFullControl, (token, flowOperator, new bytes(0)) ), new bytes(0) ); return true; } /** * @dev Update permissions for flow operator - revoke all permission * @param token The token used in flow * @param flowOperator The address given flow permissions */ function revokeFlowPermissions( ISuperToken token, address flowOperator ) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); host.callAgreement( cfa, abi.encodeCall( cfa.revokeFlowOperatorWithFullControl, (token, flowOperator, new bytes(0)) ), new bytes(0) ); return true; } /** * @dev Increases the flow rate allowance for flow operator * @notice allowing userData to be a parameter here triggered stack too deep error * @param token The token used in flow * @param flowOperator The address whose flow rate allowance is increased * @param addedFlowRateAllowance amount to increase allowance by */ function increaseFlowRateAllowance(ISuperToken token, address flowOperator, int96 addedFlowRateAllowance) internal returns (bool) { return increaseFlowRateAllowance(token, flowOperator, addedFlowRateAllowance, new bytes(0)); } /** * @dev Increases the flow rate allowance for flow operator * @notice allowing userData to be a parameter here triggered stack too deep error * @param token The token used in flow * @param flowOperator The address whose flow rate allowance is increased * @param addedFlowRateAllowance amount to increase allowance by * @param userData The userdata passed along with call */ function increaseFlowRateAllowance( ISuperToken token, address flowOperator, int96 addedFlowRateAllowance, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); host.callAgreement( cfa, abi.encodeCall(cfa.increaseFlowRateAllowance, (token, flowOperator, addedFlowRateAllowance, new bytes(0))), userData ); return true; } /** * @dev Decreases the flow rate allowance for flow operator * @notice allowing userData to be a parameter here triggered stack too deep error * @param token The token used in flow * @param flowOperator The address whose flow rate allowance is decreased * @param subtractedFlowRateAllowance amount to decrease allowance by */ function decreaseFlowRateAllowance(ISuperToken token, address flowOperator, int96 subtractedFlowRateAllowance) internal returns (bool) { return decreaseFlowRateAllowance(token, flowOperator, subtractedFlowRateAllowance, new bytes(0)); } /** * @dev Decreases the flow rate allowance for flow operator * @notice allowing userData to be a parameter here triggered stack too deep error * @param token The token used in flow * @param flowOperator The address whose flow rate allowance is decreased * @param subtractedFlowRateAllowance amount to decrease allowance by * @param userData The userdata passed along with call */ function decreaseFlowRateAllowance( ISuperToken token, address flowOperator, int96 subtractedFlowRateAllowance, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); host.callAgreement( cfa, abi.encodeCall( cfa.decreaseFlowRateAllowance, (token, flowOperator, subtractedFlowRateAllowance, new bytes(0)) ), userData ); return true; } /** * @dev Increases the flow rate allowance for flow operator and adds the permissions * @notice allowing userData to be a parameter here triggered stack too deep error * @param token The token used in flow * @param flowOperator The address whose flow rate allowance is increased * @param permissionsToAdd The permissions to add for the flow operator * @param addedFlowRateAllowance amount to increase allowance by */ function increaseFlowRateAllowanceWithPermissions( ISuperToken token, address flowOperator, uint8 permissionsToAdd, int96 addedFlowRateAllowance ) internal returns (bool) { return increaseFlowRateAllowanceWithPermissions( token, flowOperator, permissionsToAdd, addedFlowRateAllowance, new bytes(0) ); } /** * @dev Increases the flow rate allowance for flow operator and adds the permissions * @notice allowing userData to be a parameter here triggered stack too deep error * @param token The token used in flow * @param flowOperator The address whose flow rate allowance is increased * @param permissionsToAdd The permissions to add for the flow operator * @param addedFlowRateAllowance amount to increase allowance by * @param userData The userdata passed along with call */ function increaseFlowRateAllowanceWithPermissions( ISuperToken token, address flowOperator, uint8 permissionsToAdd, int96 addedFlowRateAllowance, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); host.callAgreement( cfa, abi.encodeCall( cfa.increaseFlowRateAllowanceWithPermissions, (token, flowOperator, permissionsToAdd, addedFlowRateAllowance, new bytes(0)) ), userData ); return true; } /** * @dev Decreases the flow rate allowance for flow operator and removes the permissions * @notice allowing userData to be a parameter here triggered stack too deep error * @param token The token used in flow * @param flowOperator The address whose flow rate allowance is subtracted * @param permissionsToRemove The permissions to remove for the flow operator * @param subtractedFlowRateAllowance amount to subtract allowance by */ function decreaseFlowRateAllowanceWithPermissions( ISuperToken token, address flowOperator, uint8 permissionsToRemove, int96 subtractedFlowRateAllowance ) internal returns (bool) { return decreaseFlowRateAllowanceWithPermissions( token, flowOperator, permissionsToRemove, subtractedFlowRateAllowance, new bytes(0) ); } /** * @dev Decreases the flow rate allowance for flow operator and removes the permissions * @notice allowing userData to be a parameter here triggered stack too deep error * @param token The token used in flow * @param flowOperator The address whose flow rate allowance is subtracted * @param permissionsToRemove The permissions to remove for the flow operator * @param subtractedFlowRateAllowance amount to subtract allowance by * @param userData The userdata passed along with call */ function decreaseFlowRateAllowanceWithPermissions( ISuperToken token, address flowOperator, uint8 permissionsToRemove, int96 subtractedFlowRateAllowance, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); host.callAgreement( cfa, abi.encodeCall( cfa.decreaseFlowRateAllowanceWithPermissions, (token, flowOperator, permissionsToRemove, subtractedFlowRateAllowance, new bytes(0)) ), userData ); return true; } /** * @dev Update permissions for flow operator in callback * @notice allowing userData to be a parameter here triggered stack too deep error * @param token The token used in flow * @param flowOperator The address given flow permissions * @param allowCreate creation permissions * @param allowCreate update permissions * @param allowCreate deletion permissions * @param flowRateAllowance The allowance provided to flowOperator * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function setFlowPermissionsWithCtx( ISuperToken token, address flowOperator, bool allowCreate, bool allowUpdate, bool allowDelete, int96 flowRateAllowance, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); uint8 permissionsBitmask = (allowCreate ? 1 : 0) | (allowUpdate ? 1 : 0) << 1 | (allowDelete ? 1 : 0) << 2; (newCtx, ) = host.callAgreementWithContext( cfa, abi.encodeCall( cfa.updateFlowOperatorPermissions, ( token, flowOperator, permissionsBitmask, flowRateAllowance, new bytes(0) ) ), "0x", ctx ); } /** * @dev Update permissions for flow operator - give operator max permissions * @param token The token used in flow * @param flowOperator The address given flow permissions * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function setMaxFlowPermissionsWithCtx( ISuperToken token, address flowOperator, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); (newCtx, ) = host.callAgreementWithContext( cfa, abi.encodeCall( cfa.authorizeFlowOperatorWithFullControl, ( token, flowOperator, new bytes(0) ) ), "0x", ctx ); } /** * @dev Update permissions for flow operator - revoke all permission * @param token The token used in flow * @param flowOperator The address given flow permissions * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function revokeFlowPermissionsWithCtx( ISuperToken token, address flowOperator, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); (newCtx, ) = host.callAgreementWithContext( cfa, abi.encodeCall( cfa.revokeFlowOperatorWithFullControl, (token, flowOperator, new bytes(0)) ), "0x", ctx ); } /** * @dev Creates flow as an operator without userData * @param token The token to flow * @param sender The sender of the flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate */ function createFlowFrom( ISuperToken token, address sender, address receiver, int96 flowRate ) internal returns (bool) { return createFlowFrom(token, sender, receiver, flowRate, new bytes(0)); } /** * @dev Creates flow as an operator with userData * @param token The token to flow * @param sender The sender of the flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate * @param userData The user provided data */ function createFlowFrom( ISuperToken token, address sender, address receiver, int96 flowRate, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); host.callAgreement( cfa, abi.encodeCall( cfa.createFlowByOperator, (token, sender, receiver, flowRate, new bytes(0)) ), userData ); return true; } /** * @dev Updates flow as an operator without userData * @param token The token to flow * @param sender The sender of the flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate */ function updateFlowFrom( ISuperToken token, address sender, address receiver, int96 flowRate ) internal returns (bool) { return updateFlowFrom(token, sender, receiver, flowRate, new bytes(0)); } /** * @dev Updates flow as an operator with userData * @param token The token to flow * @param sender The sender of the flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate * @param userData The user provided data */ function updateFlowFrom( ISuperToken token, address sender, address receiver, int96 flowRate, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); host.callAgreement( cfa, abi.encodeCall( cfa.updateFlowByOperator, (token, sender, receiver, flowRate, new bytes(0)) ), userData ); return true; } /** * @dev Deletes flow as an operator without userData * @param token The token to flow * @param sender The sender of the flow * @param receiver The receiver of the flow */ function deleteFlowFrom( ISuperToken token, address sender, address receiver ) internal returns (bool) { return deleteFlowFrom(token, sender, receiver, new bytes(0)); } /** * @dev Deletes flow as an operator with userData * @param token The token to flow * @param sender The sender of the flow * @param receiver The receiver of the flow * @param userData The user provided data */ function deleteFlowFrom( ISuperToken token, address sender, address receiver, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); host.callAgreement( cfa, abi.encodeCall( cfa.deleteFlowByOperator, (token, sender, receiver, new bytes(0)) ), userData ); return true; } /** CFA With CTX FUNCTIONS ************************************* */ /** * @dev Create flow with context and userData * @param token The token to flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function createFlowWithCtx( ISuperToken token, address receiver, int96 flowRate, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); (newCtx, ) = host.callAgreementWithContext( cfa, abi.encodeCall( cfa.createFlow, ( token, receiver, flowRate, new bytes(0) // placeholder ) ), "0x", ctx ); } /** * @dev Create flow by operator with context * @param token The token to flow * @param sender The sender of the flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function createFlowFromWithCtx( ISuperToken token, address sender, address receiver, int96 flowRate, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); (newCtx, ) = host.callAgreementWithContext( cfa, abi.encodeCall( cfa.createFlowByOperator, ( token, sender, receiver, flowRate, new bytes(0) // placeholder ) ), "0x", ctx ); } /** * @dev Update flow with context * @param token The token to flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function updateFlowWithCtx( ISuperToken token, address receiver, int96 flowRate, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); (newCtx, ) = host.callAgreementWithContext( cfa, abi.encodeCall( cfa.updateFlow, ( token, receiver, flowRate, new bytes(0) // placeholder ) ), "0x", ctx ); } /** * @dev Update flow by operator with context * @param token The token to flow * @param sender The receiver of the flow * @param receiver The receiver of the flow * @param flowRate The desired flowRate * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function updateFlowFromWithCtx( ISuperToken token, address sender, address receiver, int96 flowRate, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); (newCtx, ) = host.callAgreementWithContext( cfa, abi.encodeCall( cfa.updateFlowByOperator, ( token, sender, receiver, flowRate, new bytes(0) // placeholder ) ), "0x", ctx ); } /** * @dev Delete flow with context * @param token The token to flow * @param sender The sender of the flow * @param receiver The receiver of the flow * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function deleteFlowWithCtx( ISuperToken token, address sender, address receiver, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); (newCtx, ) = host.callAgreementWithContext( cfa, abi.encodeCall( cfa.deleteFlow, ( token, sender, receiver, new bytes(0) // placeholder ) ), "0x", ctx ); } /** * @dev Delete flow by operator with context * @param token The token to flow * @param sender The sender of the flow * @param receiver The receiver of the flow * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function deleteFlowFromWithCtx( ISuperToken token, address sender, address receiver, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token); (newCtx, ) = host.callAgreementWithContext( cfa, abi.encodeCall( cfa.deleteFlowByOperator, ( token, sender, receiver, new bytes(0) // placeholder ) ), "0x", ctx ); } /** CFA VIEW FUNCTIONS ************************************* */ /** * @dev get flow rate between two accounts for given token * @param token The token used in flow * @param sender The sender of the flow * @param receiver The receiver of the flow * @return flowRate The flow rate */ function getFlowRate(ISuperToken token, address sender, address receiver) internal view returns(int96 flowRate) { (, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token); (, flowRate, , ) = cfa.getFlow(token, sender, receiver); } /** * @dev get flow info between two accounts for given token * @param token The token used in flow * @param sender The sender of the flow * @param receiver The receiver of the flow * @return lastUpdated Timestamp of flow creation or last flowrate change * @return flowRate The flow rate * @return deposit The amount of deposit the flow * @return owedDeposit The amount of owed deposit of the flow */ function getFlowInfo(ISuperToken token, address sender, address receiver) internal view returns(uint256 lastUpdated, int96 flowRate, uint256 deposit, uint256 owedDeposit) { (, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token); (lastUpdated, flowRate, deposit, owedDeposit) = cfa.getFlow(token, sender, receiver); } /** * @dev get net flow rate for given account for given token * @param token Super token address * @param account Account to query * @return flowRate The net flow rate of the account */ function getNetFlowRate(ISuperToken token, address account) internal view returns (int96 flowRate) { (, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token); return cfa.getNetFlow(token, account); } /** * @dev get the aggregated flow info of the account * @param token Super token address * @param account Account to query * @return lastUpdated Timestamp of the last change of the net flow * @return flowRate The net flow rate of token for account * @return deposit The sum of all deposits for account's flows * @return owedDeposit The sum of all owed deposits for account's flows */ function getNetFlowInfo(ISuperToken token, address account) internal view returns (uint256 lastUpdated, int96 flowRate, uint256 deposit, uint256 owedDeposit) { (, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token); return cfa.getAccountFlowInfo(token, account); } /** * @dev calculate buffer for a flow rate * @param token The token used in flow * @param flowRate The flowrate to calculate the needed buffer for * @return bufferAmount The buffer amount based on flowRate, liquidationPeriod and minimum deposit */ function getBufferAmountByFlowRate(ISuperToken token, int96 flowRate) internal view returns (uint256 bufferAmount) { (, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token); return cfa.getDepositRequiredForFlowRate(token, flowRate); } /** * @dev get existing flow permissions * @param token The token used in flow * @param sender sender of a flow * @param flowOperator the address we are checking permissions of for sender & token * @return allowCreate is true if the flowOperator can create flows * @return allowUpdate is true if the flowOperator can update flows * @return allowDelete is true if the flowOperator can delete flows * @return flowRateAllowance The flow rate allowance the flowOperator is granted (only goes down) */ function getFlowPermissions(ISuperToken token, address sender, address flowOperator) internal view returns (bool allowCreate, bool allowUpdate, bool allowDelete, int96 flowRateAllowance) { (, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token); uint8 permissionsBitmask; (, permissionsBitmask, flowRateAllowance) = cfa.getFlowOperatorData(token, sender, flowOperator); allowCreate = permissionsBitmask & 1 == 1; allowUpdate = permissionsBitmask >> 1 & 1 == 1; allowDelete = permissionsBitmask >> 2 & 1 == 1; } /** IDA VIEW FUNCTIONS ************************************* */ /** * @dev Gets an index by its ID and publisher. * @param token Super token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @return exist True if the index exists. * @return indexValue Total value of the index. * @return totalUnitsApproved Units of the index approved by subscribers. * @return totalUnitsPending Units of teh index not yet approved by subscribers. */ function getIndex(ISuperToken token, address publisher, uint32 indexId) internal view returns (bool exist, uint128 indexValue, uint128 totalUnitsApproved, uint128 totalUnitsPending) { (, IInstantDistributionAgreementV1 ida) = _getHostAndIDA(token); return ida.getIndex(token, publisher, indexId); } /** * @dev Calculates the distribution amount based on the amount of tokens desired to distribute. * @param token Super token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @param amount Amount of tokens desired to distribute. * @return actualAmount Amount to be distributed with correct rounding. * @return newIndexValue The index value after the distribution would be called. */ function calculateDistribution(ISuperToken token, address publisher, uint32 indexId, uint256 amount) internal view returns (uint256 actualAmount, uint128 newIndexValue) { (, IInstantDistributionAgreementV1 ida) = _getHostAndIDA(token); return ida.calculateDistribution(token, publisher, indexId, amount); } /** * @dev List all subscriptions of an address * @param token Super token used in the indexes listed. * @param subscriber Subscriber address. * @return publishers Publishers of the indices. * @return indexIds IDs of the indices. * @return unitsList Units owned of the indices. */ function listSubscriptions( ISuperToken token, address subscriber ) internal view returns ( address[] memory publishers, uint32[] memory indexIds, uint128[] memory unitsList ) { (, IInstantDistributionAgreementV1 ida) = _getHostAndIDA(token); return ida.listSubscriptions(token, subscriber); } /** * @dev Gets subscription by publisher, index id, and subscriber. * @param token Super token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @param subscriber Subscriber to the index. * @return exist True if the subscription exists. * @return approved True if the subscription has been approved by the subscriber. * @return units Units held by the subscriber * @return pendingDistribution If not approved, the amount to be claimed on approval. */ function getSubscription(ISuperToken token, address publisher, uint32 indexId, address subscriber) internal view returns (bool exist, bool approved, uint128 units, uint256 pendingDistribution) { (, IInstantDistributionAgreementV1 ida) = _getHostAndIDA(token); return ida.getSubscription(token, publisher, indexId, subscriber); } /* * @dev Gets subscription by the agreement ID. * @param token Super Token used with the index. * @param agreementId Agreement ID, unique to the subscriber and index ID. * @return publisher Publisher of the index. * @return indexId ID of the index. * @return approved True if the subscription has been approved by the subscriber. * @return units Units held by the subscriber * @return pendingDistribution If not approved, the amount to be claimed on approval. */ function getSubscriptionByID(ISuperToken token, bytes32 agreementId) internal view returns ( address publisher, uint32 indexId, bool approved, uint128 units, uint256 pendingDistribution ) { (, IInstantDistributionAgreementV1 ida) = _getHostAndIDA(token); return ida.getSubscriptionByID(token, agreementId); } /** IDA BASE FUNCTIONS ************************************* */ /** * @dev Creates a new index. * @param token Super Token used with the index. * @param indexId ID of the index. */ function createIndex( ISuperToken token, uint32 indexId ) internal returns (bool) { return createIndex(token, indexId, new bytes(0)); } /** * @dev Creates a new index with userData. * @param token Super Token used with the index. * @param indexId ID of the index. * @param userData Arbitrary user data field. */ function createIndex( ISuperToken token, uint32 indexId, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); host.callAgreement( ida, abi.encodeCall( ida.createIndex, ( token, indexId, new bytes(0) // ctx placeholder ) ), userData ); return true; } /** * @dev Updates an index value. This distributes an amount of tokens equal to * `indexValue - lastIndexValue`. See `distribute` for another way to distribute. * @param token Super Token used with the index. * @param indexId ID of the index. * @param indexValue New TOTAL index value, this will equal the total amount distributed. */ function updateIndexValue( ISuperToken token, uint32 indexId, uint128 indexValue ) internal returns (bool) { return updateIndexValue(token, indexId, indexValue, new bytes(0)); } /** * @dev Updates an index value with userData. This distributes an amount of tokens equal to * `indexValue - lastIndexValue`. See `distribute` for another way to distribute. * @param token Super Token used with the index. * @param indexId ID of the index. * @param indexValue New TOTAL index value, this will equal the total amount distributed. * @param userData Arbitrary user data field. */ function updateIndexValue( ISuperToken token, uint32 indexId, uint128 indexValue, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); host.callAgreement( ida, abi.encodeCall( ida.updateIndex, ( token, indexId, indexValue, new bytes(0) // ctx placeholder ) ), userData ); return true; } /** * @dev Distributes tokens in a more developer friendly way than `updateIndex`. Instead of * passing the new total index value, you pass the amount of tokens desired to be distributed. * @param token Super Token used with the index. * @param indexId ID of the index. * @param amount - total number of tokens desired to be distributed * NOTE in many cases, there can be some precision loss This may cause a slight difference in the amount param specified and the actual amount distributed. See below for math: //indexDelta = amount the index will be updated by during an internal call to _updateIndex(). It is calculated like so: indexDelta = amount / totalUnits (see the distribute() implementatation in ./agreements/InstantDistributionAgreement.sol) * NOTE Solidity does not support floating point numbers So the indexDelta will be rounded down to the nearest integer. This will create a 'remainder' amount of tokens that will not be distributed (we'll call this the 'distribution modulo') distributionModulo = amount - indexDelta * totalUnits * NOTE due to rounding, there may be a small amount of tokens left in the publisher's account This amount is equal to the 'distributionModulo' value // */ function distribute( ISuperToken token, uint32 indexId, uint256 amount ) internal returns (bool) { return distribute(token, indexId, amount, new bytes(0)); } /** * @dev Distributes tokens in a more developer friendly way than `updateIndex` (w user data). Instead of * passing the new total index value, this function will increase the index value by `amount`. * This takes arbitrary user data. * @param token Super Token used with the index. * @param indexId ID of the index. * @param amount Amount by which the index value should increase. * @param userData Arbitrary user data field. */ function distribute( ISuperToken token, uint32 indexId, uint256 amount, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); host.callAgreement( ida, abi.encodeCall( ida.distribute, ( token, indexId, amount, new bytes(0) // ctx placeholder ) ), userData ); return true; } /** * @dev Approves a subscription to an index. The subscriber's real time balance will not update * until the subscription is approved, but once approved, the balance will be updated with * prior distributions. * @param token Super Token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. */ function approveSubscription( ISuperToken token, address publisher, uint32 indexId ) internal returns (bool) { return approveSubscription(token, publisher, indexId, new bytes(0)); } /** * @dev Approves a subscription to an index with user data. The subscriber's real time balance will not update * until the subscription is approved, but once approved, the balance will be updated with * prior distributions. * @param token Super Token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @param userData Arbitrary user data field. */ function approveSubscription( ISuperToken token, address publisher, uint32 indexId, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); host.callAgreement( ida, abi.encodeCall( ida.approveSubscription, ( token, publisher, indexId, new bytes(0) // ctx placeholder ) ), userData ); return true; } /** * @dev Revokes a previously approved subscription. * @param token Super Token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. */ function revokeSubscription( ISuperToken token, address publisher, uint32 indexId ) internal returns (bool) { return revokeSubscription(token, publisher, indexId, new bytes(0)); } /** * @dev Revokes a previously approved subscription. This takes arbitrary user data. * @param token Super Token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @param userData Arbitrary user data field. */ function revokeSubscription( ISuperToken token, address publisher, uint32 indexId, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); host.callAgreement( ida, abi.encodeCall( ida.revokeSubscription, ( token, publisher, indexId, new bytes(0) // ctx placeholder ) ), userData ); return true; } /** * @dev Updates the units of a subscription. This changes the number of shares the subscriber holds * @param token Super Token used with the index. * @param indexId ID of the index. * @param subscriber Subscriber address whose units are to be updated. * @param units New number of units the subscriber holds. */ function updateSubscriptionUnits( ISuperToken token, uint32 indexId, address subscriber, uint128 units ) internal returns (bool) { return updateSubscriptionUnits(token, indexId, subscriber, units, new bytes(0)); } /** * @dev Updates the units of a subscription. This changes the number of shares the subscriber * holds. This takes arbitrary user data. * @param token Super Token used with the index. * @param indexId ID of the index. * @param subscriber Subscriber address whose units are to be updated. * @param units New number of units the subscriber holds. * @param userData Arbitrary user data field. */ function updateSubscriptionUnits( ISuperToken token, uint32 indexId, address subscriber, uint128 units, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); host.callAgreement( ida, abi.encodeCall( ida.updateSubscription, ( token, indexId, subscriber, units, new bytes(0) // ctx placeholder ) ), userData ); return true; } /** * @dev Deletes a subscription, setting a subcriber's units to zero * @param token Super Token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @param subscriber Subscriber address whose units are to be deleted. */ function deleteSubscription( ISuperToken token, address publisher, uint32 indexId, address subscriber ) internal returns (bool) { return deleteSubscription(token, publisher, indexId, subscriber, new bytes(0)); } /** * @dev Deletes a subscription, setting a subcriber's units to zero. This takes arbitrary userdata. * @param token Super Token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @param subscriber Subscriber address whose units are to be deleted. * @param userData Arbitrary user data field. */ function deleteSubscription( ISuperToken token, address publisher, uint32 indexId, address subscriber, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); host.callAgreement( ida, abi.encodeCall( ida.deleteSubscription, ( token, publisher, indexId, subscriber, new bytes(0) // ctx placeholder ) ), userData ); return true; } /** * @dev Claims pending distribution. Subscription should not be approved * @param token Super Token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @param subscriber Subscriber address that receives the claim. */ function claim( ISuperToken token, address publisher, uint32 indexId, address subscriber ) internal returns (bool) { return claim(token, publisher, indexId, subscriber, new bytes(0)); } /** * @dev Claims pending distribution. Subscription should not be approved. This takes arbitrary user data. * @param token Super Token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @param subscriber Subscriber address that receives the claim. * @param userData Arbitrary user data field. */ function claim( ISuperToken token, address publisher, uint32 indexId, address subscriber, bytes memory userData ) internal returns (bool) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); host.callAgreement( ida, abi.encodeCall( ida.claim, ( token, publisher, indexId, subscriber, new bytes(0) // ctx placeholder ) ), userData ); return true; } /** IDA WITH CTX FUNCTIONS ************************************* */ /** * @dev Creates a new index with ctx. * Meant for usage in super app callbacks * @param token Super Token used with the index. * @param indexId ID of the index. * @param ctx from super app callback */ function createIndexWithCtx( ISuperToken token, uint32 indexId, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); (newCtx, ) = host.callAgreementWithContext( ida, abi.encodeCall( ida.createIndex, ( token, indexId, new bytes(0) // ctx placeholder ) ), "0x", ctx ); } /** * @dev Updates an index value with ctx. This distributes an amount of tokens equal to * `indexValue - lastIndexValue`. See `distribute` for another way to distribute. * Meant for usage in super app callbakcs * @param token Super Token used with the index. * @param indexId ID of the index. * @param indexValue New TOTAL index value, this will equal the total amount distributed. * @param ctx from super app callback */ function updateIndexValueWithCtx( ISuperToken token, uint32 indexId, uint128 indexValue, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); (newCtx, ) = host.callAgreementWithContext( ida, abi.encodeCall( ida.updateIndex, ( token, indexId, indexValue, new bytes(0) // ctx placeholder ) ), "0x", ctx ); } /** * @dev Distributes tokens in a more developer friendly way than `updateIndex`.Instead of * passing the new total index value, this function will increase the index value by `amount`. * @param token Super Token used with the index. * @param indexId ID of the index. * @param amount Amount by which the index value should increase. * @param ctx from super app callback */ function distributeWithCtx( ISuperToken token, uint32 indexId, uint256 amount, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); (newCtx, ) = host.callAgreementWithContext( ida, abi.encodeCall( ida.distribute, ( token, indexId, amount, new bytes(0) // ctx placeholder ) ), "0x", ctx ); } /** * @dev Approves a subscription to an index. The subscriber's real time balance will not update * until the subscription is approved, but once approved, the balance will be updated with * prior distributions. * @param token Super Token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @param ctx from super app callback */ function approveSubscriptionWithCtx( ISuperToken token, address publisher, uint32 indexId, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); (newCtx, ) = host.callAgreementWithContext( ida, abi.encodeCall( ida.approveSubscription, ( token, publisher, indexId, new bytes(0) // ctx placeholder ) ), "0x", ctx ); } /** * @dev Revokes a previously approved subscription. Meant for usage in super apps * @param token Super Token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @param ctx from super app callback */ function revokeSubscriptionWithCtx( ISuperToken token, address publisher, uint32 indexId, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); (newCtx, ) = host.callAgreementWithContext( ida, abi.encodeCall( ida.revokeSubscription, ( token, publisher, indexId, new bytes(0) // ctx placeholder ) ), "0x", ctx ); } /** * @dev Updates the units of a subscription. This changes the number of shares the subscriber * holds. Meant for usage in super apps * @param token Super Token used with the index. * @param indexId ID of the index. * @param subscriber Subscriber address whose units are to be updated. * @param units New number of units the subscriber holds. * @param ctx from super app callback */ function updateSubscriptionUnitsWithCtx( ISuperToken token, uint32 indexId, address subscriber, uint128 units, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); (newCtx, ) = host.callAgreementWithContext( ida, abi.encodeCall( ida.updateSubscription, ( token, indexId, subscriber, units, new bytes(0) // ctx placeholder ) ), "0x", ctx ); } /** * @dev Deletes a subscription, setting a subcriber's units to zero. * Meant for usage in super apps * @param token Super Token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @param subscriber Subscriber address whose units are to be deleted. * @param ctx from super app callback */ function deleteSubscriptionWithCtx( ISuperToken token, address publisher, uint32 indexId, address subscriber, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); (newCtx, ) = host.callAgreementWithContext( ida, abi.encodeCall( ida.deleteSubscription, ( token, publisher, indexId, subscriber, new bytes(0) // ctx placeholder ) ), "0x", ctx ); } /** * @dev Claims pending distribution. Subscription should not be approved. * Meant for usage in super app callbacks * @param token Super Token used with the index. * @param publisher Publisher of the index. * @param indexId ID of the index. * @param subscriber Subscriber address that receives the claim. * @param ctx from super app callback */ function claimWithCtx( ISuperToken token, address publisher, uint32 indexId, address subscriber, bytes memory ctx ) internal returns (bytes memory newCtx) { (ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token); (newCtx, ) = host.callAgreementWithContext( ida, abi.encodeCall( ida.claim, ( token, publisher, indexId, subscriber, new bytes(0) // ctx placeholder ) ), "0x", ctx ); } // ************** private helpers ************** // @note We must use hardcoded constants here because: // Only direct number constants and references to such constants are supported by inline assembly. // keccak256("org.superfluid-finance.apps.SuperTokenLibrary.v1.host") bytes32 private constant _HOST_SLOT = 0x65599bf746e17a00ea62e3610586992d88101b78eec3cf380706621fb97ea837; // keccak256("org.superfluid-finance.apps.SuperTokenLibrary.v1.cfa") bytes32 private constant _CFA_SLOT = 0xb969d79d88acd02d04ed7ee7d43b949e7daf093d363abcfbbc43dfdfd1ce969a; // keccak256("org.superfluid-finance.apps.SuperTokenLibrary.v1.ida"); bytes32 private constant _IDA_SLOT = 0xa832ee1924ea960211af2df07d65d166232018f613ac6708043cd8f8773eddeb; // gets the host and cfa addrs for the token and caches it in storage for gas efficiency // to be used in state changing methods function _getAndCacheHostAndCFA(ISuperToken token) private returns(ISuperfluid host, IConstantFlowAgreementV1 cfa) { // check if already in contract storage... assembly { // solium-disable-line host := sload(_HOST_SLOT) cfa := sload(_CFA_SLOT) } if (address(cfa) == address(0)) { // framework contract addrs not yet cached, retrieving now... if (address(host) == address(0)) { host = ISuperfluid(token.getHost()); } cfa = IConstantFlowAgreementV1(address(ISuperfluid(host).getAgreementClass( keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1")))); // now that we got them and are in a transaction context, persist in storage assembly { // solium-disable-line sstore(_HOST_SLOT, host) sstore(_CFA_SLOT, cfa) } } assert(address(host) != address(0)); assert(address(cfa) != address(0)); } // gets the host and ida addrs for the token and caches it in storage for gas efficiency // to be used in state changing methods function _getAndCacheHostAndIDA(ISuperToken token) private returns(ISuperfluid host, IInstantDistributionAgreementV1 ida) { // check if already in contract storage... assembly { // solium-disable-line host := sload(_HOST_SLOT) ida := sload(_IDA_SLOT) } if (address(ida) == address(0)) { // framework contract addrs not yet cached, retrieving now... if (address(host) == address(0)) { host = ISuperfluid(token.getHost()); } ida = IInstantDistributionAgreementV1(address(ISuperfluid(host).getAgreementClass( keccak256("org.superfluid-finance.agreements.InstantDistributionAgreement.v1")))); // now that we got them and are in a transaction context, persist in storage assembly { // solium-disable-line sstore(_HOST_SLOT, host) sstore(_IDA_SLOT, ida) } } assert(address(host) != address(0)); assert(address(ida) != address(0)); } // gets the host and cfa addrs for the token // to be used in non-state changing methods (view functions) function _getHostAndCFA(ISuperToken token) private view returns(ISuperfluid host, IConstantFlowAgreementV1 cfa) { // check if already in contract storage... assembly { // solium-disable-line host := sload(_HOST_SLOT) cfa := sload(_CFA_SLOT) } if (address(cfa) == address(0)) { // framework contract addrs not yet cached in storage, retrieving now... if (address(host) == address(0)) { host = ISuperfluid(token.getHost()); } cfa = IConstantFlowAgreementV1(address(ISuperfluid(host).getAgreementClass( keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1")))); } assert(address(host) != address(0)); assert(address(cfa) != address(0)); } // gets the host and ida addrs for the token // to be used in non-state changing methods (view functions) function _getHostAndIDA(ISuperToken token) private view returns(ISuperfluid host, IInstantDistributionAgreementV1 ida) { // check if already in contract storage... assembly { // solium-disable-line host := sload(_HOST_SLOT) ida := sload(_IDA_SLOT) } if (address(ida) == address(0)) { // framework contract addrs not yet cached in storage, retrieving now... if (address(host) == address(0)) { host = ISuperfluid(token.getHost()); } ida = IInstantDistributionAgreementV1(address(ISuperfluid(host).getAgreementClass( keccak256("org.superfluid-finance.agreements.InstantDistributionAgreement.v1")))); } assert(address(host) != address(0)); assert(address(ida) != address(0)); } }
/agreements/IConstantFlowAgreementV1.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; import { ISuperAgreement } from "../superfluid/ISuperAgreement.sol"; import { ISuperfluidToken } from "../superfluid/ISuperfluidToken.sol"; /** * @title Constant Flow Agreement interface * @author Superfluid */ abstract contract IConstantFlowAgreementV1 is ISuperAgreement { /************************************************************************** * Errors *************************************************************************/ error CFA_ACL_NO_SENDER_CREATE(); // 0x4b993136 error CFA_ACL_NO_SENDER_UPDATE(); // 0xedfa0d3b error CFA_ACL_OPERATOR_NO_CREATE_PERMISSIONS(); // 0xa3eab6ac error CFA_ACL_OPERATOR_NO_UPDATE_PERMISSIONS(); // 0xac434b5f error CFA_ACL_OPERATOR_NO_DELETE_PERMISSIONS(); // 0xe30f1bff error CFA_ACL_FLOW_RATE_ALLOWANCE_EXCEEDED(); // 0xa0645c1f error CFA_ACL_UNCLEAN_PERMISSIONS(); // 0x7939d66c error CFA_ACL_NO_SENDER_FLOW_OPERATOR(); // 0xb0ed394d error CFA_ACL_NO_NEGATIVE_ALLOWANCE(); // 0x86e0377d error CFA_FLOW_ALREADY_EXISTS(); // 0x801b6863 error CFA_FLOW_DOES_NOT_EXIST(); // 0x5a32bf24 error CFA_INSUFFICIENT_BALANCE(); // 0xea76c9b3 error CFA_ZERO_ADDRESS_SENDER(); // 0x1ce9b067 error CFA_ZERO_ADDRESS_RECEIVER(); // 0x78e02b2a error CFA_HOOK_OUT_OF_GAS(); // 0x9f76430b error CFA_DEPOSIT_TOO_BIG(); // 0x752c2b9c error CFA_FLOW_RATE_TOO_BIG(); // 0x0c9c55c1 error CFA_NON_CRITICAL_SENDER(); // 0xce11b5d1 error CFA_INVALID_FLOW_RATE(); // 0x91acad16 error CFA_NO_SELF_FLOW(); // 0xa47338ef /// @dev ISuperAgreement.agreementType implementation function agreementType() external override pure returns (bytes32) { return keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1"); } /** * @notice Get the maximum flow rate allowed with the deposit * @dev The deposit is clipped and rounded down * @param deposit Deposit amount used for creating the flow * @return flowRate The maximum flow rate */ function getMaximumFlowRateFromDeposit( ISuperfluidToken token, uint256 deposit) external view virtual returns (int96 flowRate); /** * @notice Get the deposit required for creating the flow * @dev Calculates the deposit based on the liquidationPeriod and flowRate * @param flowRate Flow rate to be tested * @return deposit The deposit amount based on flowRate and liquidationPeriod * @custom:note * - if calculated deposit (flowRate * liquidationPeriod) is less * than the minimum deposit, we use the minimum deposit otherwise * we use the calculated deposit */ function getDepositRequiredForFlowRate( ISuperfluidToken token, int96 flowRate) external view virtual returns (uint256 deposit); /** * @dev Returns whether it is the patrician period based on host.getNow() * @param account The account we are interested in * @return isCurrentlyPatricianPeriod Whether it is currently the patrician period dictated by governance * @return timestamp The value of host.getNow() */ function isPatricianPeriodNow( ISuperfluidToken token, address account) external view virtual returns (bool isCurrentlyPatricianPeriod, uint256 timestamp); /** * @dev Returns whether it is the patrician period based on timestamp * @param account The account we are interested in * @param timestamp The timestamp we are interested in observing the result of isPatricianPeriod * @return bool Whether it is currently the patrician period dictated by governance */ function isPatricianPeriod( ISuperfluidToken token, address account, uint256 timestamp ) public view virtual returns (bool); /** * @dev msgSender from `ctx` updates permissions for the `flowOperator` with `flowRateAllowance` * @param token Super token address * @param flowOperator The permission grantee address * @param permissions A bitmask representation of the granted permissions * @param flowRateAllowance The flow rate allowance the `flowOperator` is granted (only goes down) * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function updateFlowOperatorPermissions( ISuperfluidToken token, address flowOperator, uint8 permissions, int96 flowRateAllowance, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @notice msgSender from `ctx` increases flow rate allowance for the `flowOperator` by `addedFlowRateAllowance` * @dev if `addedFlowRateAllowance` is negative, we revert with CFA_ACL_NO_NEGATIVE_ALLOWANCE * @param token Super token address * @param flowOperator The permission grantee address * @param addedFlowRateAllowance The flow rate allowance delta * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @return newCtx The new context bytes */ function increaseFlowRateAllowance( ISuperfluidToken token, address flowOperator, int96 addedFlowRateAllowance, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @dev msgSender from `ctx` decreases flow rate allowance for the `flowOperator` by `subtractedFlowRateAllowance` * @dev if `subtractedFlowRateAllowance` is negative, we revert with CFA_ACL_NO_NEGATIVE_ALLOWANCE * @param token Super token address * @param flowOperator The permission grantee address * @param subtractedFlowRateAllowance The flow rate allowance delta * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @return newCtx The new context bytes */ function decreaseFlowRateAllowance( ISuperfluidToken token, address flowOperator, int96 subtractedFlowRateAllowance, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @dev msgSender from `ctx` increases flow rate allowance for the `flowOperator` by `addedFlowRateAllowance` * @dev if `addedFlowRateAllowance` is negative, we revert with CFA_ACL_NO_NEGATIVE_ALLOWANCE * @param token Super token address * @param flowOperator The permission grantee address * @param permissionsToAdd A bitmask representation of the granted permissions to add as a delta * @param addedFlowRateAllowance The flow rate allowance delta * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @return newCtx The new context bytes */ function increaseFlowRateAllowanceWithPermissions( ISuperfluidToken token, address flowOperator, uint8 permissionsToAdd, int96 addedFlowRateAllowance, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @dev msgSender from `ctx` decreases flow rate allowance for the `flowOperator` by `subtractedFlowRateAllowance` * @dev if `subtractedFlowRateAllowance` is negative, we revert with CFA_ACL_NO_NEGATIVE_ALLOWANCE * @param token Super token address * @param flowOperator The permission grantee address * @param permissionsToRemove A bitmask representation of the granted permissions to remove as a delta * @param subtractedFlowRateAllowance The flow rate allowance delta * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @return newCtx The new context bytes */ function decreaseFlowRateAllowanceWithPermissions( ISuperfluidToken token, address flowOperator, uint8 permissionsToRemove, int96 subtractedFlowRateAllowance, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @dev msgSender from `ctx` grants `flowOperator` all permissions with flowRateAllowance as type(int96).max * @param token Super token address * @param flowOperator The permission grantee address * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function authorizeFlowOperatorWithFullControl( ISuperfluidToken token, address flowOperator, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @notice msgSender from `ctx` revokes `flowOperator` create/update/delete permissions * @dev `permissions` and `flowRateAllowance` will both be set to 0 * @param token Super token address * @param flowOperator The permission grantee address * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function revokeFlowOperatorWithFullControl( ISuperfluidToken token, address flowOperator, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @notice Get the permissions of a flow operator between `sender` and `flowOperator` for `token` * @param token Super token address * @param sender The permission granter address * @param flowOperator The permission grantee address * @return flowOperatorId The keccak256 hash of encoded string "flowOperator", sender and flowOperator * @return permissions A bitmask representation of the granted permissions * @return flowRateAllowance The flow rate allowance the `flowOperator` is granted (only goes down) */ function getFlowOperatorData( ISuperfluidToken token, address sender, address flowOperator ) public view virtual returns ( bytes32 flowOperatorId, uint8 permissions, int96 flowRateAllowance ); /** * @notice Get flow operator using flowOperatorId * @param token Super token address * @param flowOperatorId The keccak256 hash of encoded string "flowOperator", sender and flowOperator * @return permissions A bitmask representation of the granted permissions * @return flowRateAllowance The flow rate allowance the `flowOperator` is granted (only goes down) */ function getFlowOperatorDataByID( ISuperfluidToken token, bytes32 flowOperatorId ) external view virtual returns ( uint8 permissions, int96 flowRateAllowance ); /** * @notice Create a flow betwen ctx.msgSender and receiver * @dev flowId (agreementId) is the keccak256 hash of encoded sender and receiver * @param token Super token address * @param receiver Flow receiver address * @param flowRate New flow rate in amount per second * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * * @custom:callbacks * - AgreementCreated * - agreementId - can be used in getFlowByID * - agreementData - abi.encode(address flowSender, address flowReceiver) * * @custom:note * - A deposit is taken as safety margin for the solvency agents * - A extra gas fee may be taken to pay for solvency agent liquidations */ function createFlow( ISuperfluidToken token, address receiver, int96 flowRate, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @notice Create a flow between sender and receiver * @dev A flow created by an approved flow operator (see above for details on callbacks) * @param token Super token address * @param sender Flow sender address (has granted permissions) * @param receiver Flow receiver address * @param flowRate New flow rate in amount per second * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function createFlowByOperator( ISuperfluidToken token, address sender, address receiver, int96 flowRate, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @notice Update the flow rate between ctx.msgSender and receiver * @dev flowId (agreementId) is the keccak256 hash of encoded sender and receiver * @param token Super token address * @param receiver Flow receiver address * @param flowRate New flow rate in amount per second * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * * @custom:callbacks * - AgreementUpdated * - agreementId - can be used in getFlowByID * - agreementData - abi.encode(address flowSender, address flowReceiver) * * @custom:note * - Only the flow sender may update the flow rate * - Even if the flow rate is zero, the flow is not deleted * from the system * - Deposit amount will be adjusted accordingly * - No new gas fee is charged */ function updateFlow( ISuperfluidToken token, address receiver, int96 flowRate, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @notice Update a flow between sender and receiver * @dev A flow updated by an approved flow operator (see above for details on callbacks) * @param token Super token address * @param sender Flow sender address (has granted permissions) * @param receiver Flow receiver address * @param flowRate New flow rate in amount per second * @param ctx Context bytes (see ISuperfluid.sol for Context struct) */ function updateFlowByOperator( ISuperfluidToken token, address sender, address receiver, int96 flowRate, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @dev Get the flow data between `sender` and `receiver` of `token` * @param token Super token address * @param sender Flow receiver * @param receiver Flow sender * @return timestamp Timestamp of when the flow is updated * @return flowRate The flow rate * @return deposit The amount of deposit the flow * @return owedDeposit The amount of owed deposit of the flow */ function getFlow( ISuperfluidToken token, address sender, address receiver ) external view virtual returns ( uint256 timestamp, int96 flowRate, uint256 deposit, uint256 owedDeposit ); /** * @notice Get flow data using agreementId * @dev flowId (agreementId) is the keccak256 hash of encoded sender and receiver * @param token Super token address * @param agreementId The agreement ID * @return timestamp Timestamp of when the flow is updated * @return flowRate The flow rate * @return deposit The deposit amount of the flow * @return owedDeposit The owed deposit amount of the flow */ function getFlowByID( ISuperfluidToken token, bytes32 agreementId ) external view virtual returns ( uint256 timestamp, int96 flowRate, uint256 deposit, uint256 owedDeposit ); /** * @dev Get the aggregated flow info of the account * @param token Super token address * @param account Account for the query * @return timestamp Timestamp of when a flow was last updated for account * @return flowRate The net flow rate of token for account * @return deposit The sum of all deposits for account's flows * @return owedDeposit The sum of all owed deposits for account's flows */ function getAccountFlowInfo( ISuperfluidToken token, address account ) external view virtual returns ( uint256 timestamp, int96 flowRate, uint256 deposit, uint256 owedDeposit); /** * @dev Get the net flow rate of the account * @param token Super token address * @param account Account for the query * @return flowRate Net flow rate */ function getNetFlow( ISuperfluidToken token, address account ) external view virtual returns (int96 flowRate); /** * @notice Delete the flow between sender and receiver * @dev flowId (agreementId) is the keccak256 hash of encoded sender and receiver * @param token Super token address * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param receiver Flow receiver address * * @custom:callbacks * - AgreementTerminated * - agreementId - can be used in getFlowByID * - agreementData - abi.encode(address flowSender, address flowReceiver) * * @custom:note * - Both flow sender and receiver may delete the flow * - If Sender account is insolvent or in critical state, a solvency agent may * also terminate the agreement * - Gas fee may be returned to the sender */ function deleteFlow( ISuperfluidToken token, address sender, address receiver, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @notice Delete the flow between sender and receiver * @dev A flow deleted by an approved flow operator (see above for details on callbacks) * @param token Super token address * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * @param receiver Flow receiver address */ function deleteFlowByOperator( ISuperfluidToken token, address sender, address receiver, bytes calldata ctx ) external virtual returns(bytes memory newCtx); /** * @dev Flow operator updated event * @param token Super token address * @param sender Flow sender address * @param flowOperator Flow operator address * @param permissions Octo bitmask representation of permissions * @param flowRateAllowance The flow rate allowance the `flowOperator` is granted (only goes down) */ event FlowOperatorUpdated( ISuperfluidToken indexed token, address indexed sender, address indexed flowOperator, uint8 permissions, int96 flowRateAllowance ); /** * @dev Flow updated event * @param token Super token address * @param sender Flow sender address * @param receiver Flow recipient address * @param flowRate Flow rate in amount per second for this flow * @param totalSenderFlowRate Total flow rate in amount per second for the sender * @param totalReceiverFlowRate Total flow rate in amount per second for the receiver * @param userData The user provided data * */ event FlowUpdated( ISuperfluidToken indexed token, address indexed sender, address indexed receiver, int96 flowRate, int256 totalSenderFlowRate, int256 totalReceiverFlowRate, bytes userData ); /** * @dev Flow updated extension event * @param flowOperator Flow operator address - the Context.msgSender * @param deposit The deposit amount for the stream */ event FlowUpdatedExtension( address indexed flowOperator, uint256 deposit ); }
/agreements/IInstantDistributionAgreementV1.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; import { ISuperAgreement } from "../superfluid/ISuperAgreement.sol"; import { ISuperfluidToken } from "../superfluid/ISuperfluidToken.sol"; /** * @title Instant Distribution Agreement interface * @author Superfluid * * @notice * - A publisher can create as many as indices as possibly identifiable with `indexId`. * - `indexId` is deliberately limited to 32 bits, to avoid the chance for sha-3 collision. * Despite knowing sha-3 collision is only theoretical. * - A publisher can create a subscription to an index for any subscriber. * - A subscription consists of: * - The index it subscribes to. * - Number of units subscribed. * - An index consists of: * - Current value as `uint128 indexValue`. * - Total units of the approved subscriptions as `uint128 totalUnitsApproved`. * - Total units of the non approved subscription as `uint128 totalUnitsPending`. * - A publisher can update an index with a new value that doesn't decrease. * - A publisher can update a subscription with any number of units. * - A publisher or a subscriber can delete a subscription and reset its units to zero. * - A subscriber must approve the index in order to receive distributions from the publisher * each time the index is updated. * - The amount distributed is $$\Delta{index} * units$$ * - Distributions to a non approved subscription stays in the publisher's deposit until: * - the subscriber approves the subscription (side effect), * - the publisher updates the subscription (side effect), * - the subscriber deletes the subscription even if it is never approved (side effect), * - or the subscriber can explicitly claim them. */ abstract contract IInstantDistributionAgreementV1 is ISuperAgreement { /************************************************************************** * Errors *************************************************************************/ error IDA_INDEX_SHOULD_GROW(); // 0xcfdca725 error IDA_OPERATION_NOT_ALLOWED(); // 0x92da6d17 error IDA_INDEX_ALREADY_EXISTS(); // 0x5c02a517 error IDA_INDEX_DOES_NOT_EXIST(); // 0xedeaa63b error IDA_SUBSCRIPTION_DOES_NOT_EXIST(); // 0xb6c8c980 error IDA_SUBSCRIPTION_ALREADY_APPROVED(); // 0x3eb2f849 error IDA_SUBSCRIPTION_IS_NOT_APPROVED(); // 0x37412573 error IDA_INSUFFICIENT_BALANCE(); // 0x16e759bb error IDA_ZERO_ADDRESS_SUBSCRIBER(); // 0xc90a4674 /// @dev ISuperAgreement.agreementType implementation function agreementType() external override pure returns (bytes32) { return keccak256("org.superfluid-finance.agreements.InstantDistributionAgreement.v1"); } /************************************************************************** * Index operations *************************************************************************/ /** * @dev Create a new index for the publisher * @param token Super token address * @param indexId Id of the index * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * * @custom:callbacks * None */ function createIndex( ISuperfluidToken token, uint32 indexId, bytes calldata ctx) external virtual returns(bytes memory newCtx); /** * @dev Index created event * @param token Super token address * @param publisher Index creator and publisher * @param indexId The specified indexId of the newly created index * @param userData The user provided data */ event IndexCreated( ISuperfluidToken indexed token, address indexed publisher, uint32 indexed indexId, bytes userData); /** * @dev Query the data of a index * @param token Super token address * @param publisher The publisher of the index * @param indexId Id of the index * @return exist Does the index exist * @return indexValue Value of the current index * @return totalUnitsApproved Total units approved for the index * @return totalUnitsPending Total units pending approval for the index */ function getIndex( ISuperfluidToken token, address publisher, uint32 indexId) external view virtual returns( bool exist, uint128 indexValue, uint128 totalUnitsApproved, uint128 totalUnitsPending); /** * @dev Calculate actual distribution amount * @param token Super token address * @param publisher The publisher of the index * @param indexId Id of the index * @param amount The amount of tokens desired to be distributed * @return actualAmount The amount to be distributed after ensuring no rounding errors * @return newIndexValue The index value given the desired amount of tokens to be distributed */ function calculateDistribution( ISuperfluidToken token, address publisher, uint32 indexId, uint256 amount) external view virtual returns( uint256 actualAmount, uint128 newIndexValue); /** * @dev Update index value of an index * @param token Super token address * @param indexId Id of the index * @param indexValue Value of the index * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * * @custom:callbacks * None */ function updateIndex( ISuperfluidToken token, uint32 indexId, uint128 indexValue, bytes calldata ctx) external virtual returns(bytes memory newCtx); /** * @dev Index updated event * @param token Super token address * @param publisher Index updater and publisher * @param indexId The specified indexId of the updated index * @param oldIndexValue The previous index value * @param newIndexValue The updated index value * @param totalUnitsPending The total units pending when the indexValue was updated * @param totalUnitsApproved The total units approved when the indexValue was updated * @param userData The user provided data */ event IndexUpdated( ISuperfluidToken indexed token, address indexed publisher, uint32 indexed indexId, uint128 oldIndexValue, uint128 newIndexValue, uint128 totalUnitsPending, uint128 totalUnitsApproved, bytes userData); /** * @dev Distribute tokens through the index * @param token Super token address * @param indexId Id of the index * @param amount The amount of tokens desired to be distributed * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * * @custom:note * - This is a convenient version of updateIndex. It adds to the index * a delta that equals to `amount / totalUnits` * - The actual amount distributed could be obtained via * `calculateDistribution`. This is due to precision error with index * value and units data range * * @custom:callbacks * None */ function distribute( ISuperfluidToken token, uint32 indexId, uint256 amount, bytes calldata ctx) external virtual returns(bytes memory newCtx); /************************************************************************** * Subscription operations *************************************************************************/ /** * @dev Approve the subscription of an index * @param token Super token address * @param publisher The publisher of the index * @param indexId Id of the index * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * * @custom:callbacks * - if subscription exist * - AgreementCreated callback to the publisher: * - agreementId is for the subscription * - if subscription does not exist * - AgreementUpdated callback to the publisher: * - agreementId is for the subscription */ function approveSubscription( ISuperfluidToken token, address publisher, uint32 indexId, bytes calldata ctx) external virtual returns(bytes memory newCtx); /** * @dev Index subscribed event * @param token Super token address * @param publisher Index publisher * @param indexId The specified indexId * @param subscriber The approved subscriber * @param userData The user provided data */ event IndexSubscribed( ISuperfluidToken indexed token, address indexed publisher, uint32 indexed indexId, address subscriber, bytes userData); /** * @dev Subscription approved event * @param token Super token address * @param subscriber The approved subscriber * @param publisher Index publisher * @param indexId The specified indexId * @param userData The user provided data */ event SubscriptionApproved( ISuperfluidToken indexed token, address indexed subscriber, address publisher, uint32 indexId, bytes userData); /** * @notice Revoke the subscription of an index * @dev "Unapproves" the subscription and moves approved units to pending * @param token Super token address * @param publisher The publisher of the index * @param indexId Id of the index * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * * @custom:callbacks * - AgreementUpdated callback to the publisher: * - agreementId is for the subscription */ function revokeSubscription( ISuperfluidToken token, address publisher, uint32 indexId, bytes calldata ctx) external virtual returns(bytes memory newCtx); /** * @dev Index unsubscribed event * @param token Super token address * @param publisher Index publisher * @param indexId The specified indexId * @param subscriber The unsubscribed subscriber * @param userData The user provided data */ event IndexUnsubscribed( ISuperfluidToken indexed token, address indexed publisher, uint32 indexed indexId, address subscriber, bytes userData); /** * @dev Subscription approved event * @param token Super token address * @param subscriber The approved subscriber * @param publisher Index publisher * @param indexId The specified indexId * @param userData The user provided data */ event SubscriptionRevoked( ISuperfluidToken indexed token, address indexed subscriber, address publisher, uint32 indexId, bytes userData); /** * @dev Update the nuber of units of a subscription * @param token Super token address * @param indexId Id of the index * @param subscriber The subscriber of the index * @param units Number of units of the subscription * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * * @custom:callbacks * - if subscription exist * - AgreementCreated callback to the subscriber: * - agreementId is for the subscription * - if subscription does not exist * - AgreementUpdated callback to the subscriber: * - agreementId is for the subscription */ function updateSubscription( ISuperfluidToken token, uint32 indexId, address subscriber, uint128 units, bytes calldata ctx) external virtual returns(bytes memory newCtx); /** * @dev Index units updated event * @param token Super token address * @param publisher Index publisher * @param indexId The specified indexId * @param subscriber The subscriber units updated * @param units The new units amount * @param userData The user provided data */ event IndexUnitsUpdated( ISuperfluidToken indexed token, address indexed publisher, uint32 indexed indexId, address subscriber, uint128 units, bytes userData); /** * @dev Subscription units updated event * @param token Super token address * @param subscriber The subscriber units updated * @param indexId The specified indexId * @param publisher Index publisher * @param units The new units amount * @param userData The user provided data */ event SubscriptionUnitsUpdated( ISuperfluidToken indexed token, address indexed subscriber, address publisher, uint32 indexId, uint128 units, bytes userData); /** * @dev Get data of a subscription * @param token Super token address * @param publisher The publisher of the index * @param indexId Id of the index * @param subscriber The subscriber of the index * @return exist Does the subscription exist? * @return approved Is the subscription approved? * @return units Units of the suscription * @return pendingDistribution Pending amount of tokens to be distributed for unapproved subscription */ function getSubscription( ISuperfluidToken token, address publisher, uint32 indexId, address subscriber) external view virtual returns( bool exist, bool approved, uint128 units, uint256 pendingDistribution ); /** * @notice Get data of a subscription by agreement ID * @dev indexId (agreementId) is the keccak256 hash of encodePacked("publisher", publisher, indexId) * @param token Super token address * @param agreementId The agreement ID * @return publisher The publisher of the index * @return indexId Id of the index * @return approved Is the subscription approved? * @return units Units of the suscription * @return pendingDistribution Pending amount of tokens to be distributed for unapproved subscription */ function getSubscriptionByID( ISuperfluidToken token, bytes32 agreementId) external view virtual returns( address publisher, uint32 indexId, bool approved, uint128 units, uint256 pendingDistribution ); /** * @dev List subscriptions of an user * @param token Super token address * @param subscriber The subscriber's address * @return publishers Publishers of the subcriptions * @return indexIds Indexes of the subscriptions * @return unitsList Units of the subscriptions */ function listSubscriptions( ISuperfluidToken token, address subscriber) external view virtual returns( address[] memory publishers, uint32[] memory indexIds, uint128[] memory unitsList); /** * @dev Delete the subscription of an user * @param token Super token address * @param publisher The publisher of the index * @param indexId Id of the index * @param subscriber The subscriber's address * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * * @custom:callbacks * - if the subscriber called it * - AgreementTerminated callback to the publsiher: * - agreementId is for the subscription * - if the publisher called it * - AgreementTerminated callback to the subscriber: * - agreementId is for the subscription */ function deleteSubscription( ISuperfluidToken token, address publisher, uint32 indexId, address subscriber, bytes calldata ctx) external virtual returns(bytes memory newCtx); /** * @dev Claim pending distributions * @param token Super token address * @param publisher The publisher of the index * @param indexId Id of the index * @param subscriber The subscriber's address * @param ctx Context bytes (see ISuperfluid.sol for Context struct) * * @custom:note The subscription should not be approved yet * * @custom:callbacks * - AgreementUpdated callback to the publisher: * - agreementId is for the subscription */ function claim( ISuperfluidToken token, address publisher, uint32 indexId, address subscriber, bytes calldata ctx) external virtual returns(bytes memory newCtx); /** * @dev Index distribution claimed event * @param token Super token address * @param publisher Index publisher * @param indexId The specified indexId * @param subscriber The subscriber units updated * @param amount The pending amount claimed */ event IndexDistributionClaimed( ISuperfluidToken indexed token, address indexed publisher, uint32 indexed indexId, address subscriber, uint256 amount); /** * @dev Subscription distribution claimed event * @param token Super token address * @param subscriber The subscriber units updated * @param publisher Index publisher * @param indexId The specified indexId * @param amount The pending amount claimed */ event SubscriptionDistributionClaimed( ISuperfluidToken indexed token, address indexed subscriber, address publisher, uint32 indexId, uint256 amount); }
/superfluid/CustomSuperTokenBase.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; // We export this too because it seems reasonable for a custom super token. // solhint-disable-next-line no-unused-import import { ISuperToken } from "../../interfaces/superfluid/ISuperToken.sol"; /** * @title Custom super token base contract * @author Superfluid * NOTE: * - Because of how solidity lays out its storage variables and how custom * super tokens inherit the SuperToken standard implementation, it is * required that the custom token proxy pads its implementation * with reserved storage used by the Super Token implementation. * - You will need to append your own proxy implementation after the base * - Refer to SETH.sol for an example how it is used. */ abstract contract CustomSuperTokenBase { // This (32) is the hard-coded number of storage slots used by the super token uint256[32] internal _storagePaddings; }
/superfluid/Definitions.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; /** * @title Super app definitions library * @author Superfluid */ library SuperAppDefinitions { /************************************************************************** / App manifest config word /**************************************************************************/ /* * App level is a way to allow the app to whitelist what other app it can * interact with (aka. composite app feature). * * For more details, refer to the technical paper of superfluid protocol. */ uint256 constant internal APP_LEVEL_MASK = 0xFF; // The app is at the final level, hence it doesn't want to interact with any other app uint256 constant internal APP_LEVEL_FINAL = 1 << 0; // The app is at the second level, it may interact with other final level apps if whitelisted uint256 constant internal APP_LEVEL_SECOND = 1 << 1; function getAppCallbackLevel(uint256 configWord) internal pure returns (uint8) { return uint8(configWord & APP_LEVEL_MASK); } uint256 constant internal APP_JAIL_BIT = 1 << 15; function isAppJailed(uint256 configWord) internal pure returns (bool) { return (configWord & SuperAppDefinitions.APP_JAIL_BIT) > 0; } /************************************************************************** / Callback implementation bit masks /**************************************************************************/ uint256 constant internal AGREEMENT_CALLBACK_NOOP_BITMASKS = 0xFF << 32; uint256 constant internal BEFORE_AGREEMENT_CREATED_NOOP = 1 << (32 + 0); uint256 constant internal AFTER_AGREEMENT_CREATED_NOOP = 1 << (32 + 1); uint256 constant internal BEFORE_AGREEMENT_UPDATED_NOOP = 1 << (32 + 2); uint256 constant internal AFTER_AGREEMENT_UPDATED_NOOP = 1 << (32 + 3); uint256 constant internal BEFORE_AGREEMENT_TERMINATED_NOOP = 1 << (32 + 4); uint256 constant internal AFTER_AGREEMENT_TERMINATED_NOOP = 1 << (32 + 5); /************************************************************************** / App Jail Reasons /**************************************************************************/ uint256 constant internal APP_RULE_REGISTRATION_ONLY_IN_CONSTRUCTOR = 1; uint256 constant internal APP_RULE_NO_REGISTRATION_FOR_EOA = 2; uint256 constant internal APP_RULE_NO_REVERT_ON_TERMINATION_CALLBACK = 10; uint256 constant internal APP_RULE_NO_CRITICAL_SENDER_ACCOUNT = 11; uint256 constant internal APP_RULE_NO_CRITICAL_RECEIVER_ACCOUNT = 12; uint256 constant internal APP_RULE_CTX_IS_READONLY = 20; uint256 constant internal APP_RULE_CTX_IS_NOT_CLEAN = 21; uint256 constant internal APP_RULE_CTX_IS_MALFORMATED = 22; uint256 constant internal APP_RULE_COMPOSITE_APP_IS_NOT_WHITELISTED = 30; uint256 constant internal APP_RULE_COMPOSITE_APP_IS_JAILED = 31; uint256 constant internal APP_RULE_MAX_APP_LEVEL_REACHED = 40; // Validate configWord cleaness for future compatibility, or else may introduce undefined future behavior function isConfigWordClean(uint256 configWord) internal pure returns (bool) { return (configWord & ~(APP_LEVEL_MASK | APP_JAIL_BIT | AGREEMENT_CALLBACK_NOOP_BITMASKS)) == uint256(0); } } /** * @title Context definitions library * @author Superfluid */ library ContextDefinitions { /************************************************************************** / Call info /**************************************************************************/ // app level uint256 constant internal CALL_INFO_APP_LEVEL_MASK = 0xFF; // call type uint256 constant internal CALL_INFO_CALL_TYPE_SHIFT = 32; uint256 constant internal CALL_INFO_CALL_TYPE_MASK = 0xF << CALL_INFO_CALL_TYPE_SHIFT; uint8 constant internal CALL_INFO_CALL_TYPE_AGREEMENT = 1; uint8 constant internal CALL_INFO_CALL_TYPE_APP_ACTION = 2; uint8 constant internal CALL_INFO_CALL_TYPE_APP_CALLBACK = 3; function decodeCallInfo(uint256 callInfo) internal pure returns (uint8 appCallbackLevel, uint8 callType) { appCallbackLevel = uint8(callInfo & CALL_INFO_APP_LEVEL_MASK); callType = uint8((callInfo & CALL_INFO_CALL_TYPE_MASK) >> CALL_INFO_CALL_TYPE_SHIFT); } function encodeCallInfo(uint8 appCallbackLevel, uint8 callType) internal pure returns (uint256 callInfo) { return uint256(appCallbackLevel) | (uint256(callType) << CALL_INFO_CALL_TYPE_SHIFT); } } /** * @title Flow Operator definitions library * @author Superfluid */ library FlowOperatorDefinitions { uint8 constant internal AUTHORIZE_FLOW_OPERATOR_CREATE = uint8(1) << 0; uint8 constant internal AUTHORIZE_FLOW_OPERATOR_UPDATE = uint8(1) << 1; uint8 constant internal AUTHORIZE_FLOW_OPERATOR_DELETE = uint8(1) << 2; uint8 constant internal AUTHORIZE_FULL_CONTROL = AUTHORIZE_FLOW_OPERATOR_CREATE | AUTHORIZE_FLOW_OPERATOR_UPDATE | AUTHORIZE_FLOW_OPERATOR_DELETE; uint8 constant internal REVOKE_FLOW_OPERATOR_CREATE = ~(uint8(1) << 0); uint8 constant internal REVOKE_FLOW_OPERATOR_UPDATE = ~(uint8(1) << 1); uint8 constant internal REVOKE_FLOW_OPERATOR_DELETE = ~(uint8(1) << 2); function isPermissionsClean(uint8 permissions) internal pure returns (bool) { return ( permissions & ~(AUTHORIZE_FLOW_OPERATOR_CREATE | AUTHORIZE_FLOW_OPERATOR_UPDATE | AUTHORIZE_FLOW_OPERATOR_DELETE) ) == uint8(0); } } /** * @title Batch operation library * @author Superfluid */ library BatchOperation { /** * @dev ERC20.approve batch operation type * * Call spec: * ISuperToken(target).operationApprove( * abi.decode(data, (address spender, uint256 amount)) * ) */ uint32 constant internal OPERATION_TYPE_ERC20_APPROVE = 1; /** * @dev ERC20.transferFrom batch operation type * * Call spec: * ISuperToken(target).operationTransferFrom( * abi.decode(data, (address sender, address recipient, uint256 amount) * ) */ uint32 constant internal OPERATION_TYPE_ERC20_TRANSFER_FROM = 2; /** * @dev ERC777.send batch operation type * * Call spec: * ISuperToken(target).operationSend( * abi.decode(data, (address recipient, uint256 amount, bytes userData) * ) */ uint32 constant internal OPERATION_TYPE_ERC777_SEND = 3; /** * @dev ERC20.increaseAllowance batch operation type * * Call spec: * ISuperToken(target).operationIncreaseAllowance( * abi.decode(data, (address account, address spender, uint256 addedValue)) * ) */ uint32 constant internal OPERATION_TYPE_ERC20_INCREASE_ALLOWANCE = 4; /** * @dev ERC20.decreaseAllowance batch operation type * * Call spec: * ISuperToken(target).operationDecreaseAllowance( * abi.decode(data, (address account, address spender, uint256 subtractedValue)) * ) */ uint32 constant internal OPERATION_TYPE_ERC20_DECREASE_ALLOWANCE = 5; /** * @dev SuperToken.upgrade batch operation type * * Call spec: * ISuperToken(target).operationUpgrade( * abi.decode(data, (uint256 amount) * ) */ uint32 constant internal OPERATION_TYPE_SUPERTOKEN_UPGRADE = 1 + 100; /** * @dev SuperToken.downgrade batch operation type * * Call spec: * ISuperToken(target).operationDowngrade( * abi.decode(data, (uint256 amount) * ) */ uint32 constant internal OPERATION_TYPE_SUPERTOKEN_DOWNGRADE = 2 + 100; /** * @dev Superfluid.callAgreement batch operation type * * Call spec: * callAgreement( * ISuperAgreement(target)), * abi.decode(data, (bytes callData, bytes userData) * ) */ uint32 constant internal OPERATION_TYPE_SUPERFLUID_CALL_AGREEMENT = 1 + 200; /** * @dev Superfluid.callAppAction batch operation type * * Call spec: * callAppAction( * ISuperApp(target)), * data * ) */ uint32 constant internal OPERATION_TYPE_SUPERFLUID_CALL_APP_ACTION = 2 + 200; } /** * @title Superfluid governance configs library * @author Superfluid */ library SuperfluidGovernanceConfigs { bytes32 constant internal SUPERFLUID_REWARD_ADDRESS_CONFIG_KEY = keccak256("org.superfluid-finance.superfluid.rewardAddress"); bytes32 constant internal CFAV1_PPP_CONFIG_KEY = keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1.PPPConfiguration"); bytes32 constant internal SUPERTOKEN_MINIMUM_DEPOSIT_KEY = keccak256("org.superfluid-finance.superfluid.superTokenMinimumDeposit"); function getTrustedForwarderConfigKey(address forwarder) internal pure returns (bytes32) { return keccak256(abi.encode( "org.superfluid-finance.superfluid.trustedForwarder", forwarder)); } function getAppRegistrationConfigKey(address deployer, string memory registrationKey) internal pure returns (bytes32) { return keccak256(abi.encode( "org.superfluid-finance.superfluid.appWhiteListing.registrationKey", deployer, registrationKey)); } function getAppFactoryConfigKey(address factory) internal pure returns (bytes32) { return keccak256(abi.encode( "org.superfluid-finance.superfluid.appWhiteListing.factory", factory)); } function decodePPPConfig(uint256 pppConfig) internal pure returns (uint256 liquidationPeriod, uint256 patricianPeriod) { liquidationPeriod = (pppConfig >> 32) & type(uint32).max; patricianPeriod = pppConfig & type(uint32).max; } }
/superfluid/IConstantInflowNFT.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.11; import { IFlowNFTBase } from "./IFlowNFTBase.sol"; interface IConstantInflowNFT is IFlowNFTBase { /************************************************************************** * Custom Errors *************************************************************************/ error CIF_NFT_ONLY_CONSTANT_OUTFLOW(); // 0xe81ef57a /************************************************************************** * Write Functions *************************************************************************/ /// @notice The mint function emits the "mint" `Transfer` event. /// @dev We don't modify storage as this is handled in ConstantOutflowNFT.sol and this function's sole purpose /// is to inform clients that search for events. /// @param to the flow receiver (inflow NFT receiver) /// @param newTokenId the new token id function mint(address to, uint256 newTokenId) external; /// @notice This burn function emits the "burn" `Transfer` event. /// @dev We don't modify storage as this is handled in ConstantOutflowNFT.sol and this function's sole purpose /// is to inform clients that search for events. /// @param tokenId desired token id to burn function burn(uint256 tokenId) external; }
/superfluid/IConstantOutflowNFT.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.11; import { ISuperfluidToken } from "./ISuperfluidToken.sol"; import { IFlowNFTBase } from "./IFlowNFTBase.sol"; interface IConstantOutflowNFT is IFlowNFTBase { /************************************************************************** * Custom Errors *************************************************************************/ error COF_NFT_INVALID_SUPER_TOKEN(); // 0x6de98774 error COF_NFT_MINT_TO_AND_FLOW_RECEIVER_SAME(); // 0x0d1d1161 error COF_NFT_MINT_TO_ZERO_ADDRESS(); // 0x43d05e51 error COF_NFT_ONLY_CONSTANT_INFLOW(); // 0xa495a718 error COF_NFT_ONLY_FLOW_AGREEMENTS(); // 0xd367b64f error COF_NFT_TOKEN_ALREADY_EXISTS(); // 0xe2480183 /************************************************************************** * Write Functions *************************************************************************/ /// @notice The onCreate function is called when a new flow is created. /// @param token the super token passed from the CFA (flowVars) /// @param flowSender the flow sender /// @param flowReceiver the flow receiver function onCreate(ISuperfluidToken token, address flowSender, address flowReceiver) external; /// @notice The onUpdate function is called when a flow is updated. /// @param token the super token passed from the CFA (flowVars) /// @param flowSender the flow sender /// @param flowReceiver the flow receiver function onUpdate(ISuperfluidToken token, address flowSender, address flowReceiver) external; /// @notice The onDelete function is called when a flow is deleted. /// @param token the super token passed from the CFA (flowVars) /// @param flowSender the flow sender /// @param flowReceiver the flow receiver function onDelete(ISuperfluidToken token, address flowSender, address flowReceiver) external; }
/superfluid/IFlowNFTBase.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.11; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; interface IFlowNFTBase is IERC721Metadata { // FlowNFTData struct storage packing: // b = bits // WORD 1: | superToken | FREE // | 160b | 96b // WORD 2: | flowSender | FREE // | 160b | 96b // WORD 3: | flowReceiver | flowStartDate | FREE // | 160b | 32b | 64b struct FlowNFTData { address superToken; address flowSender; address flowReceiver; uint32 flowStartDate; } /************************************************************************** * Custom Errors *************************************************************************/ error CFA_NFT_APPROVE_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); // 0xa3352582 error CFA_NFT_APPROVE_TO_CALLER(); // 0xd3c77329 error CFA_NFT_APPROVE_TO_CURRENT_OWNER(); // 0xe4790b25 error CFA_NFT_INVALID_TOKEN_ID(); // 0xeab95e3b error CFA_NFT_ONLY_SUPER_TOKEN_FACTORY(); // 0xebb7505b error CFA_NFT_TRANSFER_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); // 0x2551d606 error CFA_NFT_TRANSFER_FROM_INCORRECT_OWNER(); // 0x5a26c744 error CFA_NFT_TRANSFER_IS_NOT_ALLOWED(); // 0xaa747eca error CFA_NFT_TRANSFER_TO_ZERO_ADDRESS(); // 0xde06d21e /************************************************************************** * Events *************************************************************************/ /// @notice Informs third-party platforms that NFT metadata should be updated /// @dev This event comes from https://eips.ethereum.org/EIPS/eip-4906 /// @param tokenId the id of the token that should have its metadata updated event MetadataUpdate(uint256 tokenId); /************************************************************************** * View *************************************************************************/ /// @notice An external function for querying flow data by `tokenId`` /// @param tokenId the token id /// @return flowData the flow data associated with `tokenId` function flowDataByTokenId( uint256 tokenId ) external view returns (FlowNFTData memory flowData); /// @notice An external function for computing the deterministic tokenId /// @dev tokenId = uint256(keccak256(abi.encode(block.chainId, superToken, flowSender, flowReceiver))) /// @param superToken the super token /// @param flowSender the flow sender /// @param flowReceiver the flow receiver /// @return tokenId the tokenId function getTokenId( address superToken, address flowSender, address flowReceiver ) external view returns (uint256); /************************************************************************** * Write *************************************************************************/ function initialize( string memory nftName, string memory nftSymbol ) external; // initializer; function triggerMetadataUpdate(uint256 tokenId) external; }
/superfluid/IPoolAdminNFT.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.11; // TODO // solhint-disable-next-line no-empty-blocks interface IPoolAdminNFT {}
/superfluid/IPoolMemberNFT.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.11; // TODO // solhint-disable-next-line no-empty-blocks interface IPoolMemberNFT {}
/superfluid/ISuperAgreement.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; import { ISuperfluidToken } from "./ISuperfluidToken.sol"; /** * @title Super agreement interface * @author Superfluid */ interface ISuperAgreement { /** * @dev Get the type of the agreement class */ function agreementType() external view returns (bytes32); /** * @dev Calculate the real-time balance for the account of this agreement class * @param account Account the state belongs to * @param time Time used for the calculation * @return dynamicBalance Dynamic balance portion of real-time balance of this agreement * @return deposit Account deposit amount of this agreement * @return owedDeposit Account owed deposit amount of this agreement */ function realtimeBalanceOf( ISuperfluidToken token, address account, uint256 time ) external view returns ( int256 dynamicBalance, uint256 deposit, uint256 owedDeposit ); }
/superfluid/ISuperApp.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; import { ISuperToken } from "./ISuperToken.sol"; /** * @title SuperApp interface * @author Superfluid * @dev Be aware of the app being jailed, when the word permitted is used. */ interface ISuperApp { /** * @dev Callback before a new agreement is created. * @param superToken The super token used for the agreement. * @param agreementClass The agreement class address. * @param agreementId The agreementId * @param agreementData The agreement data (non-compressed) * @param ctx The context data. * @return cbdata A free format in memory data the app can use to pass * arbitary information to the after-hook callback. * * @custom:note * - It will be invoked with `staticcall`, no state changes are permitted. * - Only revert with a "reason" is permitted. */ function beforeAgreementCreated( ISuperToken superToken, address agreementClass, bytes32 agreementId, bytes calldata agreementData, bytes calldata ctx ) external view returns (bytes memory cbdata); /** * @dev Callback after a new agreement is created. * @param superToken The super token used for the agreement. * @param agreementClass The agreement class address. * @param agreementId The agreementId * @param agreementData The agreement data (non-compressed) * @param cbdata The data returned from the before-hook callback. * @param ctx The context data. * @return newCtx The current context of the transaction. * * @custom:note * - State changes is permitted. * - Only revert with a "reason" is permitted. */ function afterAgreementCreated( ISuperToken superToken, address agreementClass, bytes32 agreementId, bytes calldata agreementData, bytes calldata cbdata, bytes calldata ctx ) external returns (bytes memory newCtx); /** * @dev Callback before a new agreement is updated. * @param superToken The super token used for the agreement. * @param agreementClass The agreement class address. * @param agreementId The agreementId * @param agreementData The agreement data (non-compressed) * @param ctx The context data. * @return cbdata A free format in memory data the app can use to pass * arbitary information to the after-hook callback. * * @custom:note * - It will be invoked with `staticcall`, no state changes are permitted. * - Only revert with a "reason" is permitted. */ function beforeAgreementUpdated( ISuperToken superToken, address agreementClass, bytes32 agreementId, bytes calldata agreementData, bytes calldata ctx ) external view returns (bytes memory cbdata); /** * @dev Callback after a new agreement is updated. * @param superToken The super token used for the agreement. * @param agreementClass The agreement class address. * @param agreementId The agreementId * @param agreementData The agreement data (non-compressed) * @param cbdata The data returned from the before-hook callback. * @param ctx The context data. * @return newCtx The current context of the transaction. * * @custom:note * - State changes is permitted. * - Only revert with a "reason" is permitted. */ function afterAgreementUpdated( ISuperToken superToken, address agreementClass, bytes32 agreementId, bytes calldata agreementData, bytes calldata cbdata, bytes calldata ctx ) external returns (bytes memory newCtx); /** * @dev Callback before a new agreement is terminated. * @param superToken The super token used for the agreement. * @param agreementClass The agreement class address. * @param agreementId The agreementId * @param agreementData The agreement data (non-compressed) * @param ctx The context data. * @return cbdata A free format in memory data the app can use to pass arbitary information to * the after-hook callback. * * @custom:note * - It will be invoked with `staticcall`, no state changes are permitted. * - Revert is not permitted. */ function beforeAgreementTerminated( ISuperToken superToken, address agreementClass, bytes32 agreementId, bytes calldata agreementData, bytes calldata ctx ) external view returns (bytes memory cbdata); /** * @dev Callback after a new agreement is terminated. * @param superToken The super token used for the agreement. * @param agreementClass The agreement class address. * @param agreementId The agreementId * @param agreementData The agreement data (non-compressed) * @param cbdata The data returned from the before-hook callback. * @param ctx The context data. * @return newCtx The current context of the transaction. * * @custom:note * - State changes is permitted. * - Revert is not permitted. */ function afterAgreementTerminated( ISuperToken superToken, address agreementClass, bytes32 agreementId, bytes calldata agreementData, bytes calldata cbdata, bytes calldata ctx ) external returns (bytes memory newCtx); }
/superfluid/ISuperToken.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; import { ISuperfluidToken } from "./ISuperfluidToken.sol"; import { TokenInfo } from "../tokens/TokenInfo.sol"; import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IConstantOutflowNFT } from "./IConstantOutflowNFT.sol"; import { IConstantInflowNFT } from "./IConstantInflowNFT.sol"; /** * @title Super token (Superfluid Token + ERC20 + ERC777) interface * @author Superfluid */ interface ISuperToken is ISuperfluidToken, TokenInfo, IERC20, IERC777 { /************************************************************************** * Errors *************************************************************************/ error SUPER_TOKEN_CALLER_IS_NOT_OPERATOR_FOR_HOLDER(); // 0xf7f02227 error SUPER_TOKEN_NOT_ERC777_TOKENS_RECIPIENT(); // 0xfe737d05 error SUPER_TOKEN_INFLATIONARY_DEFLATIONARY_NOT_SUPPORTED(); // 0xe3e13698 error SUPER_TOKEN_NO_UNDERLYING_TOKEN(); // 0xf79cf656 error SUPER_TOKEN_ONLY_SELF(); // 0x7ffa6648 error SUPER_TOKEN_ONLY_HOST(); // 0x98f73704 error SUPER_TOKEN_ONLY_GOV_OWNER(); // 0xd9c7ed08 error SUPER_TOKEN_APPROVE_FROM_ZERO_ADDRESS(); // 0x81638627 error SUPER_TOKEN_APPROVE_TO_ZERO_ADDRESS(); // 0xdf070274 error SUPER_TOKEN_BURN_FROM_ZERO_ADDRESS(); // 0xba2ab184 error SUPER_TOKEN_MINT_TO_ZERO_ADDRESS(); // 0x0d243157 error SUPER_TOKEN_TRANSFER_FROM_ZERO_ADDRESS(); // 0xeecd6c9b error SUPER_TOKEN_TRANSFER_TO_ZERO_ADDRESS(); // 0xe219bd39 error SUPER_TOKEN_NFT_PROXY_ADDRESS_CHANGED(); // 0x6bef249d /** * @dev Initialize the contract */ function initialize( IERC20 underlyingToken, uint8 underlyingDecimals, string calldata n, string calldata s ) external; /************************************************************************** * Immutable variables *************************************************************************/ // solhint-disable-next-line func-name-mixedcase function CONSTANT_OUTFLOW_NFT() external view returns (IConstantOutflowNFT); // solhint-disable-next-line func-name-mixedcase function CONSTANT_INFLOW_NFT() external view returns (IConstantInflowNFT); /************************************************************************** * TokenInfo & ERC777 *************************************************************************/ /** * @dev Returns the name of the token. */ function name() external view override(IERC777, TokenInfo) returns (string memory); /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() external view override(IERC777, TokenInfo) returns (string memory); /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * @custom:note SuperToken always uses 18 decimals. * * This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() external view override(TokenInfo) returns (uint8); /************************************************************************** * ERC20 & ERC777 *************************************************************************/ /** * @dev See {IERC20-totalSupply}. */ function totalSupply() external view override(IERC777, IERC20) returns (uint256); /** * @dev Returns the amount of tokens owned by an account (`owner`). */ function balanceOf(address account) external view override(IERC777, IERC20) returns(uint256 balance); /************************************************************************** * ERC20 *************************************************************************/ /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * @return Returns Success a boolean value indicating whether the operation succeeded. * * @custom:emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external override(IERC20) returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * @notice This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external override(IERC20) view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * @return Returns Success a boolean value indicating whether the operation succeeded. * * @custom:note Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * @custom:emits an {Approval} event. */ function approve(address spender, uint256 amount) external override(IERC20) returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * @return Returns Success a boolean value indicating whether the operation succeeded. * * @custom:emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external override(IERC20) returns (bool); /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * @custom:emits an {Approval} event indicating the updated allowance. * * @custom:requirements * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) external returns (bool); /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * @custom:emits an {Approval} event indicating the updated allowance. * * @custom:requirements * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); /************************************************************************** * ERC777 *************************************************************************/ /** * @dev Returns the smallest part of the token that is not divisible. This * means all token operations (creation, movement and destruction) must have * amounts that are a multiple of this number. * * @custom:note For super token contracts, this value is always 1 */ function granularity() external view override(IERC777) returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * @dev If send or receive hooks are registered for the caller and `recipient`, * the corresponding functions will be called with `userData` and empty * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. * * @custom:emits a {Sent} event. * * @custom:requirements * - the caller must have at least `amount` tokens. * - `recipient` cannot be the zero address. * - if `recipient` is a contract, it must implement the {IERC777Recipient} * interface. */ function send(address recipient, uint256 amount, bytes calldata userData) external override(IERC777); /** * @dev Destroys `amount` tokens from the caller's account, reducing the * total supply and transfers the underlying token to the caller's account. * * If a send hook is registered for the caller, the corresponding function * will be called with `userData` and empty `operatorData`. See {IERC777Sender}. * * @custom:emits a {Burned} event. * * @custom:requirements * - the caller must have at least `amount` tokens. */ function burn(uint256 amount, bytes calldata userData) external override(IERC777); /** * @dev Returns true if an account is an operator of `tokenHolder`. * Operators can send and burn tokens on behalf of their owners. All * accounts are their own operator. * * See {operatorSend} and {operatorBurn}. */ function isOperatorFor(address operator, address tokenHolder) external override(IERC777) view returns (bool); /** * @dev Make an account an operator of the caller. * * See {isOperatorFor}. * * @custom:emits an {AuthorizedOperator} event. * * @custom:requirements * - `operator` cannot be calling address. */ function authorizeOperator(address operator) external override(IERC777); /** * @dev Revoke an account's operator status for the caller. * * See {isOperatorFor} and {defaultOperators}. * * @custom:emits a {RevokedOperator} event. * * @custom:requirements * - `operator` cannot be calling address. */ function revokeOperator(address operator) external override(IERC777); /** * @dev Returns the list of default operators. These accounts are operators * for all token holders, even if {authorizeOperator} was never called on * them. * * This list is immutable, but individual holders may revoke these via * {revokeOperator}, in which case {isOperatorFor} will return false. */ function defaultOperators() external override(IERC777) view returns (address[] memory); /** * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must * be an operator of `sender`. * * If send or receive hooks are registered for `sender` and `recipient`, * the corresponding functions will be called with `userData` and * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. * * @custom:emits a {Sent} event. * * @custom:requirements * - `sender` cannot be the zero address. * - `sender` must have at least `amount` tokens. * - the caller must be an operator for `sender`. * - `recipient` cannot be the zero address. * - if `recipient` is a contract, it must implement the {IERC777Recipient} * interface. */ function operatorSend( address sender, address recipient, uint256 amount, bytes calldata userData, bytes calldata operatorData ) external override(IERC777); /** * @dev Destroys `amount` tokens from `account`, reducing the total supply. * The caller must be an operator of `account`. * * If a send hook is registered for `account`, the corresponding function * will be called with `userData` and `operatorData`. See {IERC777Sender}. * * @custom:emits a {Burned} event. * * @custom:requirements * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. * - the caller must be an operator for `account`. */ function operatorBurn( address account, uint256 amount, bytes calldata userData, bytes calldata operatorData ) external override(IERC777); /************************************************************************** * SuperToken custom token functions *************************************************************************/ /** * @dev Mint new tokens for the account * If `userData` is not empty, the `tokensReceived` hook is invoked according to ERC777 semantics. * * @custom:modifiers * - onlySelf */ function selfMint( address account, uint256 amount, bytes memory userData ) external; /** * @dev Burn existing tokens for the account * If `userData` is not empty, the `tokensToSend` hook is invoked according to ERC777 semantics. * * @custom:modifiers * - onlySelf */ function selfBurn( address account, uint256 amount, bytes memory userData ) external; /** * @dev Transfer `amount` tokens from the `sender` to `recipient`. * If `spender` isn't the same as `sender`, checks if `spender` has allowance to * spend tokens of `sender`. * * @custom:modifiers * - onlySelf */ function selfTransferFrom( address sender, address spender, address recipient, uint256 amount ) external; /** * @dev Give `spender`, `amount` allowance to spend the tokens of * `account`. * * @custom:modifiers * - onlySelf */ function selfApproveFor( address account, address spender, uint256 amount ) external; /************************************************************************** * SuperToken extra functions *************************************************************************/ /** * @dev Transfer all available balance from `msg.sender` to `recipient` */ function transferAll(address recipient) external; /************************************************************************** * ERC20 wrapping *************************************************************************/ /** * @dev Return the underlying token contract * @return tokenAddr Underlying token address */ function getUnderlyingToken() external view returns(address tokenAddr); /** * @dev Upgrade ERC20 to SuperToken. * @param amount Number of tokens to be upgraded (in 18 decimals) * * @custom:note It will use `transferFrom` to get tokens. Before calling this * function you should `approve` this contract */ function upgrade(uint256 amount) external; /** * @dev Upgrade ERC20 to SuperToken and transfer immediately * @param to The account to receive upgraded tokens * @param amount Number of tokens to be upgraded (in 18 decimals) * @param userData User data for the TokensRecipient callback * * @custom:note It will use `transferFrom` to get tokens. Before calling this * function you should `approve` this contract * * @custom:warning * - there is potential of reentrancy IF the "to" account is a registered ERC777 recipient. * @custom:requirements * - if `userData` is NOT empty AND `to` is a contract, it MUST be a registered ERC777 recipient * otherwise it reverts. */ function upgradeTo(address to, uint256 amount, bytes calldata userData) external; /** * @dev Token upgrade event * @param account Account where tokens are upgraded to * @param amount Amount of tokens upgraded (in 18 decimals) */ event TokenUpgraded( address indexed account, uint256 amount ); /** * @dev Downgrade SuperToken to ERC20. * @dev It will call transfer to send tokens * @param amount Number of tokens to be downgraded */ function downgrade(uint256 amount) external; /** * @dev Downgrade SuperToken to ERC20 and transfer immediately * @param to The account to receive downgraded tokens * @param amount Number of tokens to be downgraded (in 18 decimals) */ function downgradeTo(address to, uint256 amount) external; /** * @dev Token downgrade event * @param account Account whose tokens are downgraded * @param amount Amount of tokens downgraded */ event TokenDowngraded( address indexed account, uint256 amount ); /************************************************************************** * Batch Operations *************************************************************************/ /** * @dev Perform ERC20 approve by host contract. * @param account The account owner to be approved. * @param spender The spender of account owner's funds. * @param amount Number of tokens to be approved. * * @custom:modifiers * - onlyHost */ function operationApprove( address account, address spender, uint256 amount ) external; function operationIncreaseAllowance( address account, address spender, uint256 addedValue ) external; function operationDecreaseAllowance( address account, address spender, uint256 subtractedValue ) external; /** * @dev Perform ERC20 transferFrom by host contract. * @param account The account to spend sender's funds. * @param spender The account where the funds is sent from. * @param recipient The recipient of the funds. * @param amount Number of tokens to be transferred. * * @custom:modifiers * - onlyHost */ function operationTransferFrom( address account, address spender, address recipient, uint256 amount ) external; /** * @dev Perform ERC777 send by host contract. * @param spender The account where the funds is sent from. * @param recipient The recipient of the funds. * @param amount Number of tokens to be transferred. * @param userData Arbitrary user inputted data * * @custom:modifiers * - onlyHost */ function operationSend( address spender, address recipient, uint256 amount, bytes memory userData ) external; /** * @dev Upgrade ERC20 to SuperToken by host contract. * @param account The account to be changed. * @param amount Number of tokens to be upgraded (in 18 decimals) * * @custom:modifiers * - onlyHost */ function operationUpgrade(address account, uint256 amount) external; /** * @dev Downgrade ERC20 to SuperToken by host contract. * @param account The account to be changed. * @param amount Number of tokens to be downgraded (in 18 decimals) * * @custom:modifiers * - onlyHost */ function operationDowngrade(address account, uint256 amount) external; // Flow NFT events /** * @dev Constant Outflow NFT proxy created event * @param constantOutflowNFT constant outflow nft address */ event ConstantOutflowNFTCreated( IConstantOutflowNFT indexed constantOutflowNFT ); /** * @dev Constant Inflow NFT proxy created event * @param constantInflowNFT constant inflow nft address */ event ConstantInflowNFTCreated( IConstantInflowNFT indexed constantInflowNFT ); /************************************************************************** * Function modifiers for access control and parameter validations * * While they cannot be explicitly stated in function definitions, they are * listed in function definition comments instead for clarity. * * NOTE: solidity-coverage not supporting it *************************************************************************/ /// @dev The msg.sender must be the contract itself //modifier onlySelf() virtual }
/superfluid/ISuperTokenFactory.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; import { ISuperToken } from "./ISuperToken.sol"; import { IERC20, ERC20WithTokenInfo } from "../tokens/ERC20WithTokenInfo.sol"; /** * @title Super token factory interface * @author Superfluid */ interface ISuperTokenFactory { /************************************************************************** * Errors *************************************************************************/ error SUPER_TOKEN_FACTORY_ALREADY_EXISTS(); // 0x91d67972 error SUPER_TOKEN_FACTORY_DOES_NOT_EXIST(); // 0x872cac48 error SUPER_TOKEN_FACTORY_UNINITIALIZED(); // 0x1b39b9b4 error SUPER_TOKEN_FACTORY_ONLY_HOST(); // 0x478b8e83 error SUPER_TOKEN_FACTORY_NON_UPGRADEABLE_IS_DEPRECATED(); // 0xc4901a43 error SUPER_TOKEN_FACTORY_ZERO_ADDRESS(); // 0x305c9e82 /************************************************************************** * Immutable Variables **************************************************************************/ /** * @dev Get superfluid host contract address */ function getHost() external view returns(address host); /// @dev Initialize the contract function initialize() external; /** * @notice Get the canonical super token logic. */ function getSuperTokenLogic() external view returns (ISuperToken superToken); /** * @dev Upgradability modes */ enum Upgradability { /// Non upgradable super token, `host.updateSuperTokenLogic` will revert NON_UPGRADABLE, /// Upgradable through `host.updateSuperTokenLogic` operation SEMI_UPGRADABLE, /// Always using the latest super token logic FULL_UPGRADABLE } /** * @notice Create new super token wrapper for the underlying ERC20 token * @param underlyingToken Underlying ERC20 token * @param underlyingDecimals Underlying token decimals * @param upgradability Upgradability mode * @param name Super token name * @param symbol Super token symbol * @return superToken The deployed and initialized wrapper super token */ function createERC20Wrapper( IERC20 underlyingToken, uint8 underlyingDecimals, Upgradability upgradability, string calldata name, string calldata symbol ) external returns (ISuperToken superToken); /** * @notice Create new super token wrapper for the underlying ERC20 token with extra token info * @param underlyingToken Underlying ERC20 token * @param upgradability Upgradability mode * @param name Super token name * @param symbol Super token symbol * @return superToken The deployed and initialized wrapper super token * NOTE: * - It assumes token provide the .decimals() function */ function createERC20Wrapper( ERC20WithTokenInfo underlyingToken, Upgradability upgradability, string calldata name, string calldata symbol ) external returns (ISuperToken superToken); /** * @notice Creates a wrapper super token AND sets it in the canonical list OR reverts if it already exists * @dev salt for create2 is the keccak256 hash of abi.encode(address(_underlyingToken)) * @param _underlyingToken Underlying ERC20 token * @return ISuperToken the created supertoken */ function createCanonicalERC20Wrapper(ERC20WithTokenInfo _underlyingToken) external returns (ISuperToken); /** * @notice Computes/Retrieves wrapper super token address given the underlying token address * @dev We return from our canonical list if it already exists, otherwise we compute it * @dev note that this function only computes addresses for SEMI_UPGRADABLE SuperTokens * @param _underlyingToken Underlying ERC20 token address * @return superTokenAddress Super token address * @return isDeployed whether the super token is deployed AND set in the canonical mapping */ function computeCanonicalERC20WrapperAddress(address _underlyingToken) external view returns (address superTokenAddress, bool isDeployed); /** * @notice Gets the canonical ERC20 wrapper super token address given the underlying token address * @dev We return the address if it exists and the zero address otherwise * @param _underlyingTokenAddress Underlying ERC20 token address * @return superTokenAddress Super token address */ function getCanonicalERC20Wrapper(address _underlyingTokenAddress) external view returns (address superTokenAddress); /** * @dev Creates a new custom super token * @param customSuperTokenProxy address of the custom supertoken proxy */ function initializeCustomSuperToken( address customSuperTokenProxy ) external; /** * @dev Super token logic created event * @param tokenLogic Token logic address */ event SuperTokenLogicCreated(ISuperToken indexed tokenLogic); /** * @dev Super token created event * @param token Newly created super token address */ event SuperTokenCreated(ISuperToken indexed token); /** * @dev Custom super token created event * @param token Newly created custom super token address */ event CustomSuperTokenCreated(ISuperToken indexed token); }
/superfluid/ISuperfluid.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; // ISuperfluid.sol can also be used as an umbrella-import for everything Superfluid, hence we should have these unused // import. // // solhint-disable no-unused-import /// Global definitions import { SuperAppDefinitions, ContextDefinitions, FlowOperatorDefinitions, BatchOperation, SuperfluidGovernanceConfigs } from "./Definitions.sol"; /// Super token related interfaces: /// Note: CustomSuperTokenBase is not included for people building CustomSuperToken. import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.sol"; import { TokenInfo, ERC20WithTokenInfo } from "../tokens/ERC20WithTokenInfo.sol"; import { ISuperfluidToken } from "./ISuperfluidToken.sol"; import { ISuperToken } from "./ISuperToken.sol"; import { ISuperTokenFactory } from "./ISuperTokenFactory.sol"; import { ISETH } from "../tokens/ISETH.sol"; /// Superfluid/ERC20x NFTs import { IFlowNFTBase } from "./IFlowNFTBase.sol"; import { IConstantOutflowNFT } from "./IConstantOutflowNFT.sol"; import { IConstantInflowNFT } from "./IConstantInflowNFT.sol"; import { IPoolAdminNFT } from "./IPoolAdminNFT.sol"; import { IPoolMemberNFT } from "./IPoolMemberNFT.sol"; /// Superfluid agreement interfaces: import { ISuperAgreement } from "./ISuperAgreement.sol"; import { IConstantFlowAgreementV1 } from "../agreements/IConstantFlowAgreementV1.sol"; import { IInstantDistributionAgreementV1 } from "../agreements/IInstantDistributionAgreementV1.sol"; /// Superfluid App interfaces: import { ISuperApp } from "./ISuperApp.sol"; /// Superfluid governance import { ISuperfluidGovernance } from "./ISuperfluidGovernance.sol"; /** * @title Host interface * @author Superfluid * @notice This is the central contract of the system where super agreement, super app * and super token features are connected. * * The Superfluid host contract is also the entry point for the protocol users, * where batch call and meta transaction are provided for UX improvements. * */ interface ISuperfluid { /************************************************************************** * Errors *************************************************************************/ // Superfluid Custom Errors error HOST_AGREEMENT_CALLBACK_IS_NOT_ACTION(); // 0xef4295f6 error HOST_CANNOT_DOWNGRADE_TO_NON_UPGRADEABLE(); // 0x474e7641 error HOST_CALL_AGREEMENT_WITH_CTX_FROM_WRONG_ADDRESS(); // 0x0cd0ebc2 error HOST_CALL_APP_ACTION_WITH_CTX_FROM_WRONG_ADDRESS(); // 0x473f7bd4 error HOST_INVALID_CONFIG_WORD(); // 0xf4c802a4 error HOST_MAX_256_AGREEMENTS(); // 0x7c281a78 error HOST_NON_UPGRADEABLE(); // 0x14f72c9f error HOST_NON_ZERO_LENGTH_PLACEHOLDER_CTX(); // 0x67e9985b error HOST_ONLY_GOVERNANCE(); // 0xc5d22a4e error HOST_UNKNOWN_BATCH_CALL_OPERATION_TYPE(); // 0xb4770115 error HOST_AGREEMENT_ALREADY_REGISTERED(); // 0xdc9ddba8 error HOST_AGREEMENT_IS_NOT_REGISTERED(); // 0x1c9e9bea error HOST_MUST_BE_CONTRACT(); // 0xd4f6b30c error HOST_ONLY_LISTED_AGREEMENT(); // 0x619c5359 error HOST_NEED_MORE_GAS(); // 0xd4f5d496 // App Related Custom Errors // uses SuperAppDefinitions' App Jail Reasons as _code error APP_RULE(uint256 _code); // 0xa85ba64f error HOST_INVALID_OR_EXPIRED_SUPER_APP_REGISTRATION_KEY(); // 0x19ab84d1 error HOST_NOT_A_SUPER_APP(); // 0x163cbe43 error HOST_NO_APP_REGISTRATION_PERMISSIONS(); // 0x5b93ebf0 error HOST_RECEIVER_IS_NOT_SUPER_APP(); // 0x96aa315e error HOST_SENDER_IS_NOT_SUPER_APP(); // 0xbacfdc40 error HOST_SOURCE_APP_NEEDS_HIGHER_APP_LEVEL(); // 0x44725270 error HOST_SUPER_APP_IS_JAILED(); // 0x02384b64 error HOST_SUPER_APP_ALREADY_REGISTERED(); // 0x01b0a935 error HOST_UNAUTHORIZED_SUPER_APP_FACTORY(); // 0x289533c5 /************************************************************************** * Time * * > The Oracle: You have the sight now, Neo. You are looking at the world without time. * > Neo: Then why can't I see what happens to her? * > The Oracle: We can never see past the choices we don't understand. * > - The Oracle and Neo conversing about the future of Trinity and the effects of Neo's choices *************************************************************************/ function getNow() external view returns (uint256); /************************************************************************** * Governance *************************************************************************/ /** * @dev Get the current governance address of the Superfluid host */ function getGovernance() external view returns(ISuperfluidGovernance governance); /** * @dev Replace the current governance with a new one */ function replaceGovernance(ISuperfluidGovernance newGov) external; /** * @dev Governance replaced event * @param oldGov Address of the old governance contract * @param newGov Address of the new governance contract */ event GovernanceReplaced(ISuperfluidGovernance oldGov, ISuperfluidGovernance newGov); /************************************************************************** * Agreement Whitelisting *************************************************************************/ /** * @dev Register a new agreement class to the system * @param agreementClassLogic Initial agreement class code * * @custom:modifiers * - onlyGovernance */ function registerAgreementClass(ISuperAgreement agreementClassLogic) external; /** * @notice Agreement class registered event * @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>" * @param agreementType The agreement type registered * @param code Address of the new agreement */ event AgreementClassRegistered(bytes32 agreementType, address code); /** * @dev Update code of an agreement class * @param agreementClassLogic New code for the agreement class * * @custom:modifiers * - onlyGovernance */ function updateAgreementClass(ISuperAgreement agreementClassLogic) external; /** * @notice Agreement class updated event * @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>" * @param agreementType The agreement type updated * @param code Address of the new agreement */ event AgreementClassUpdated(bytes32 agreementType, address code); /** * @notice Check if the agreement type is whitelisted * @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>" */ function isAgreementTypeListed(bytes32 agreementType) external view returns(bool yes); /** * @dev Check if the agreement class is whitelisted */ function isAgreementClassListed(ISuperAgreement agreementClass) external view returns(bool yes); /** * @notice Get agreement class * @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>" */ function getAgreementClass(bytes32 agreementType) external view returns(ISuperAgreement agreementClass); /** * @dev Map list of the agreement classes using a bitmap * @param bitmap Agreement class bitmap */ function mapAgreementClasses(uint256 bitmap) external view returns (ISuperAgreement[] memory agreementClasses); /** * @notice Create a new bitmask by adding a agreement class to it * @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>" * @param bitmap Agreement class bitmap */ function addToAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType) external view returns (uint256 newBitmap); /** * @notice Create a new bitmask by removing a agreement class from it * @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>" * @param bitmap Agreement class bitmap */ function removeFromAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType) external view returns (uint256 newBitmap); /************************************************************************** * Super Token Factory **************************************************************************/ /** * @dev Get the super token factory * @return factory The factory */ function getSuperTokenFactory() external view returns (ISuperTokenFactory factory); /** * @dev Get the super token factory logic (applicable to upgradable deployment) * @return logic The factory logic */ function getSuperTokenFactoryLogic() external view returns (address logic); /** * @dev Update super token factory * @param newFactory New factory logic */ function updateSuperTokenFactory(ISuperTokenFactory newFactory) external; /** * @dev SuperToken factory updated event * @param newFactory Address of the new factory */ event SuperTokenFactoryUpdated(ISuperTokenFactory newFactory); /** * @notice Update the super token logic to the latest (canonical) implementation * if `newLogicOverride` is zero, or to `newLogicOverride` otherwise. * or to the provided implementation `. * @dev Refer to ISuperTokenFactory.Upgradability for expected behaviours */ function updateSuperTokenLogic(ISuperToken token, address newLogicOverride) external; /** * @notice Update the super token logic to the provided one * @dev newLogic must implement UUPSProxiable with matching proxiableUUID */ event SuperTokenLogicUpdated(ISuperToken indexed token, address code); /************************************************************************** * App Registry *************************************************************************/ /** * @dev Message sender (must be a contract) declares itself as a super app. * @custom:deprecated you should use `registerAppWithKey` or `registerAppByFactory` instead, * because app registration is currently governance permissioned on mainnets. * @param configWord The super app manifest configuration, flags are defined in * `SuperAppDefinitions` */ function registerApp(uint256 configWord) external; /** * @dev App registered event * @param app Address of jailed app */ event AppRegistered(ISuperApp indexed app); /** * @dev Message sender declares itself as a super app. * @param configWord The super app manifest configuration, flags are defined in `SuperAppDefinitions` * @param registrationKey The registration key issued by the governance, needed to register on a mainnet. * @notice See https://github.com/superfluid-finance/protocol-monorepo/wiki/Super-App-White-listing-Guide * On testnets or in dev environment, a placeholder (e.g. empty string) can be used. * While the message sender must be the super app itself, the transaction sender (tx.origin) * must be the deployer account the registration key was issued for. */ function registerAppWithKey(uint256 configWord, string calldata registrationKey) external; /** * @dev Message sender (must be a contract) declares app as a super app * @param configWord The super app manifest configuration, flags are defined in `SuperAppDefinitions` * @notice On mainnet deployments, only factory contracts pre-authorized by governance can use this. * See https://github.com/superfluid-finance/protocol-monorepo/wiki/Super-App-White-listing-Guide */ function registerAppByFactory(ISuperApp app, uint256 configWord) external; /** * @dev Query if the app is registered * @param app Super app address */ function isApp(ISuperApp app) external view returns(bool); /** * @dev Query app callbacklevel * @param app Super app address */ function getAppCallbackLevel(ISuperApp app) external view returns(uint8 appCallbackLevel); /** * @dev Get the manifest of the super app * @param app Super app address */ function getAppManifest( ISuperApp app ) external view returns ( bool isSuperApp, bool isJailed, uint256 noopMask ); /** * @dev Query if the app has been jailed * @param app Super app address */ function isAppJailed(ISuperApp app) external view returns (bool isJail); /** * @dev Whitelist the target app for app composition for the source app (msg.sender) * @param targetApp The target super app address */ function allowCompositeApp(ISuperApp targetApp) external; /** * @dev Query if source app is allowed to call the target app as downstream app * @param app Super app address * @param targetApp The target super app address */ function isCompositeAppAllowed( ISuperApp app, ISuperApp targetApp ) external view returns (bool isAppAllowed); /************************************************************************** * Agreement Framework * * Agreements use these function to trigger super app callbacks, updates * app credit and charge gas fees. * * These functions can only be called by registered agreements. *************************************************************************/ /** * @dev (For agreements) StaticCall the app before callback * @param app The super app. * @param callData The call data sending to the super app. * @param isTermination Is it a termination callback? * @param ctx Current ctx, it will be validated. * @return cbdata Data returned from the callback. */ function callAppBeforeCallback( ISuperApp app, bytes calldata callData, bool isTermination, bytes calldata ctx ) external // onlyAgreement // assertValidCtx(ctx) returns(bytes memory cbdata); /** * @dev (For agreements) Call the app after callback * @param app The super app. * @param callData The call data sending to the super app. * @param isTermination Is it a termination callback? * @param ctx Current ctx, it will be validated. * @return newCtx The current context of the transaction. */ function callAppAfterCallback( ISuperApp app, bytes calldata callData, bool isTermination, bytes calldata ctx ) external // onlyAgreement // assertValidCtx(ctx) returns(bytes memory newCtx); /** * @dev (For agreements) Create a new callback stack * @param ctx The current ctx, it will be validated. * @param app The super app. * @param appCreditGranted App credit granted so far. * @param appCreditUsed App credit used so far. * @return newCtx The current context of the transaction. */ function appCallbackPush( bytes calldata ctx, ISuperApp app, uint256 appCreditGranted, int256 appCreditUsed, ISuperfluidToken appCreditToken ) external // onlyAgreement // assertValidCtx(ctx) returns (bytes memory newCtx); /** * @dev (For agreements) Pop from the current app callback stack * @param ctx The ctx that was pushed before the callback stack. * @param appCreditUsedDelta App credit used by the app. * @return newCtx The current context of the transaction. * * @custom:security * - Here we cannot do assertValidCtx(ctx), since we do not really save the stack in memory. * - Hence there is still implicit trust that the agreement handles the callback push/pop pair correctly. */ function appCallbackPop( bytes calldata ctx, int256 appCreditUsedDelta ) external // onlyAgreement returns (bytes memory newCtx); /** * @dev (For agreements) Use app credit. * @param ctx The current ctx, it will be validated. * @param appCreditUsedMore See app credit for more details. * @return newCtx The current context of the transaction. */ function ctxUseCredit( bytes calldata ctx, int256 appCreditUsedMore ) external // onlyAgreement // assertValidCtx(ctx) returns (bytes memory newCtx); /** * @dev (For agreements) Jail the app. * @param app The super app. * @param reason Jail reason code. * @return newCtx The current context of the transaction. */ function jailApp( bytes calldata ctx, ISuperApp app, uint256 reason ) external // onlyAgreement // assertValidCtx(ctx) returns (bytes memory newCtx); /** * @dev Jail event for the app * @param app Address of jailed app * @param reason Reason the app is jailed (see Definitions.sol for the full list) */ event Jail(ISuperApp indexed app, uint256 reason); /************************************************************************** * Contextless Call Proxies * * NOTE: For EOAs or non-app contracts, they are the entry points for interacting * with agreements or apps. * * NOTE: The contextual call data should be generated using * abi.encodeWithSelector. The context parameter should be set to "0x", * an empty bytes array as a placeholder to be replaced by the host * contract. *************************************************************************/ /** * @dev Call agreement function * @param agreementClass The agreement address you are calling * @param callData The contextual call data with placeholder ctx * @param userData Extra user data being sent to the super app callbacks */ function callAgreement( ISuperAgreement agreementClass, bytes calldata callData, bytes calldata userData ) external //cleanCtx //isAgreement(agreementClass) returns(bytes memory returnedData); /** * @notice Call app action * @dev Main use case is calling app action in a batch call via the host * @param callData The contextual call data * * @custom:note See "Contextless Call Proxies" above for more about contextual call data. */ function callAppAction( ISuperApp app, bytes calldata callData ) external //cleanCtx //isAppActive(app) //isValidAppAction(callData) returns(bytes memory returnedData); /************************************************************************** * Contextual Call Proxies and Context Utilities * * For apps, they must use context they receive to interact with * agreements or apps. * * The context changes must be saved and returned by the apps in their * callbacks always, any modification to the context will be detected and * the violating app will be jailed. *************************************************************************/ /** * @dev Context Struct * * @custom:note on backward compatibility: * - Non-dynamic fields are padded to 32bytes and packed * - Dynamic fields are referenced through a 32bytes offset to their "parents" field (or root) * - The order of the fields hence should not be rearranged in order to be backward compatible: * - non-dynamic fields will be parsed at the same memory location, * - and dynamic fields will simply have a greater offset than it was. * - We cannot change the structure of the Context struct because of ABI compatibility requirements */ struct Context { // // Call context // // app callback level uint8 appCallbackLevel; // type of call uint8 callType; // the system timestamp uint256 timestamp; // The intended message sender for the call address msgSender; // // Callback context // // For callbacks it is used to know which agreement function selector is called bytes4 agreementSelector; // User provided data for app callbacks bytes userData; // // App context // // app credit granted uint256 appCreditGranted; // app credit wanted by the app callback uint256 appCreditWantedDeprecated; // app credit used, allowing negative values over a callback session // the appCreditUsed value over a callback sessions is calculated with: // existing flow data owed deposit + sum of the callback agreements // deposit deltas // the final value used to modify the state is determined by the // _adjustNewAppCreditUsed function (in AgreementLibrary.sol) which takes // the appCreditUsed value reached in the callback session and the app // credit granted int256 appCreditUsed; // app address address appAddress; // app credit in super token ISuperfluidToken appCreditToken; } function callAgreementWithContext( ISuperAgreement agreementClass, bytes calldata callData, bytes calldata userData, bytes calldata ctx ) external // requireValidCtx(ctx) // onlyAgreement(agreementClass) returns (bytes memory newCtx, bytes memory returnedData); function callAppActionWithContext( ISuperApp app, bytes calldata callData, bytes calldata ctx ) external // requireValidCtx(ctx) // isAppActive(app) returns (bytes memory newCtx); function decodeCtx(bytes memory ctx) external pure returns (Context memory context); function isCtxValid(bytes calldata ctx) external view returns (bool); /************************************************************************** * Batch call **************************************************************************/ /** * @dev Batch operation data */ struct Operation { // Operation type. Defined in BatchOperation (Definitions.sol) uint32 operationType; // Operation target address target; // Data specific to the operation bytes data; } /** * @dev Batch call function * @param operations Array of batch operations */ function batchCall(Operation[] calldata operations) external; /** * @dev Batch call function for trusted forwarders (EIP-2771) * @param operations Array of batch operations */ function forwardBatchCall(Operation[] calldata operations) external; /************************************************************************** * Function modifiers for access control and parameter validations * * While they cannot be explicitly stated in function definitions, they are * listed in function definition comments instead for clarity. * * TODO: turning these off because solidity-coverage doesn't like it *************************************************************************/ /* /// @dev The current superfluid context is clean. modifier cleanCtx() virtual; /// @dev Require the ctx being valid. modifier requireValidCtx(bytes memory ctx) virtual; /// @dev Assert the ctx being valid. modifier assertValidCtx(bytes memory ctx) virtual; /// @dev The agreement is a listed agreement. modifier isAgreement(ISuperAgreement agreementClass) virtual; // onlyGovernance /// @dev The msg.sender must be a listed agreement. modifier onlyAgreement() virtual; /// @dev The app is registered and not jailed. modifier isAppActive(ISuperApp app) virtual; */ }
/superfluid/ISuperfluidGovernance.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; import { ISuperfluid } from "./ISuperfluid.sol"; import { ISuperToken } from "./ISuperToken.sol"; import { ISuperfluidToken } from "./ISuperfluidToken.sol"; /** * @title Superfluid governance interface * @author Superfluid */ interface ISuperfluidGovernance { /************************************************************************** * Errors *************************************************************************/ error SF_GOV_INVALID_LIQUIDATION_OR_PATRICIAN_PERIOD(); // 0xe171980a error SF_GOV_MUST_BE_CONTRACT(); // 0x80dddd73 /** * @dev Replace the current governance with a new governance */ function replaceGovernance( ISuperfluid host, address newGov) external; /** * @dev Register a new agreement class */ function registerAgreementClass( ISuperfluid host, address agreementClass) external; /** * @dev Update logics of the contracts * * @custom:note * - Because they might have inter-dependencies, it is good to have one single function to update them all */ function updateContracts( ISuperfluid host, address hostNewLogic, address[] calldata agreementClassNewLogics, address superTokenFactoryNewLogic ) external; /** * @dev Update supertoken logic contract to the latest that is managed by the super token factory */ function batchUpdateSuperTokenLogic( ISuperfluid host, ISuperToken[] calldata tokens) external; /** * @dev Update supertoken logic contract to the provided logic contracts. * Note that this is an overloaded version taking an additional argument `tokenLogics` */ function batchUpdateSuperTokenLogic( ISuperfluid host, ISuperToken[] calldata tokens, address[] calldata tokenLogics) external; /** * @dev Set configuration as address value */ function setConfig( ISuperfluid host, ISuperfluidToken superToken, bytes32 key, address value ) external; /** * @dev Set configuration as uint256 value */ function setConfig( ISuperfluid host, ISuperfluidToken superToken, bytes32 key, uint256 value ) external; /** * @dev Clear configuration */ function clearConfig( ISuperfluid host, ISuperfluidToken superToken, bytes32 key ) external; /** * @dev Get configuration as address value */ function getConfigAsAddress( ISuperfluid host, ISuperfluidToken superToken, bytes32 key) external view returns (address value); /** * @dev Get configuration as uint256 value */ function getConfigAsUint256( ISuperfluid host, ISuperfluidToken superToken, bytes32 key) external view returns (uint256 value); }
/superfluid/ISuperfluidToken.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; import { ISuperAgreement } from "./ISuperAgreement.sol"; /** * @title Superfluid token interface * @author Superfluid */ interface ISuperfluidToken { /************************************************************************** * Errors *************************************************************************/ error SF_TOKEN_AGREEMENT_ALREADY_EXISTS(); // 0xf05521f6 error SF_TOKEN_AGREEMENT_DOES_NOT_EXIST(); // 0xdae18809 error SF_TOKEN_BURN_INSUFFICIENT_BALANCE(); // 0x10ecdf44 error SF_TOKEN_MOVE_INSUFFICIENT_BALANCE(); // 0x2f4cb941 error SF_TOKEN_ONLY_LISTED_AGREEMENT(); // 0xc9ff6644 error SF_TOKEN_ONLY_HOST(); // 0xc51efddd /************************************************************************** * Basic information *************************************************************************/ /** * @dev Get superfluid host contract address */ function getHost() external view returns(address host); /** * @dev Encoded liquidation type data mainly used for handling stack to deep errors * * @custom:note * - version: 1 * - liquidationType key: * - 0 = reward account receives reward (PIC period) * - 1 = liquidator account receives reward (Pleb period) * - 2 = liquidator account receives reward (Pirate period/bailout) */ struct LiquidationTypeData { uint256 version; uint8 liquidationType; } /************************************************************************** * Real-time balance functions *************************************************************************/ /** * @dev Calculate the real balance of a user, taking in consideration all agreements of the account * @param account for the query * @param timestamp Time of balance * @return availableBalance Real-time balance * @return deposit Account deposit * @return owedDeposit Account owed Deposit */ function realtimeBalanceOf( address account, uint256 timestamp ) external view returns ( int256 availableBalance, uint256 deposit, uint256 owedDeposit); /** * @notice Calculate the realtime balance given the current host.getNow() value * @dev realtimeBalanceOf with timestamp equals to block timestamp * @param account for the query * @return availableBalance Real-time balance * @return deposit Account deposit * @return owedDeposit Account owed Deposit */ function realtimeBalanceOfNow( address account ) external view returns ( int256 availableBalance, uint256 deposit, uint256 owedDeposit, uint256 timestamp); /** * @notice Check if account is critical * @dev A critical account is when availableBalance < 0 * @param account The account to check * @param timestamp The time we'd like to check if the account is critical (should use future) * @return isCritical Whether the account is critical */ function isAccountCritical( address account, uint256 timestamp ) external view returns(bool isCritical); /** * @notice Check if account is critical now (current host.getNow()) * @dev A critical account is when availableBalance < 0 * @param account The account to check * @return isCritical Whether the account is critical */ function isAccountCriticalNow( address account ) external view returns(bool isCritical); /** * @notice Check if account is solvent * @dev An account is insolvent when the sum of deposits for a token can't cover the negative availableBalance * @param account The account to check * @param timestamp The time we'd like to check if the account is solvent (should use future) * @return isSolvent True if the account is solvent, false otherwise */ function isAccountSolvent( address account, uint256 timestamp ) external view returns(bool isSolvent); /** * @notice Check if account is solvent now * @dev An account is insolvent when the sum of deposits for a token can't cover the negative availableBalance * @param account The account to check * @return isSolvent True if the account is solvent, false otherwise */ function isAccountSolventNow( address account ) external view returns(bool isSolvent); /** * @notice Get a list of agreements that is active for the account * @dev An active agreement is one that has state for the account * @param account Account to query * @return activeAgreements List of accounts that have non-zero states for the account */ function getAccountActiveAgreements(address account) external view returns(ISuperAgreement[] memory activeAgreements); /************************************************************************** * Super Agreement hosting functions *************************************************************************/ /** * @dev Create a new agreement * @param id Agreement ID * @param data Agreement data */ function createAgreement( bytes32 id, bytes32[] calldata data ) external; /** * @dev Agreement created event * @param agreementClass Contract address of the agreement * @param id Agreement ID * @param data Agreement data */ event AgreementCreated( address indexed agreementClass, bytes32 id, bytes32[] data ); /** * @dev Get data of the agreement * @param agreementClass Contract address of the agreement * @param id Agreement ID * @return data Data of the agreement */ function getAgreementData( address agreementClass, bytes32 id, uint dataLength ) external view returns(bytes32[] memory data); /** * @dev Create a new agreement * @param id Agreement ID * @param data Agreement data */ function updateAgreementData( bytes32 id, bytes32[] calldata data ) external; /** * @dev Agreement updated event * @param agreementClass Contract address of the agreement * @param id Agreement ID * @param data Agreement data */ event AgreementUpdated( address indexed agreementClass, bytes32 id, bytes32[] data ); /** * @dev Close the agreement * @param id Agreement ID */ function terminateAgreement( bytes32 id, uint dataLength ) external; /** * @dev Agreement terminated event * @param agreementClass Contract address of the agreement * @param id Agreement ID */ event AgreementTerminated( address indexed agreementClass, bytes32 id ); /** * @dev Update agreement state slot * @param account Account to be updated * * @custom:note * - To clear the storage out, provide zero-ed array of intended length */ function updateAgreementStateSlot( address account, uint256 slotId, bytes32[] calldata slotData ) external; /** * @dev Agreement account state updated event * @param agreementClass Contract address of the agreement * @param account Account updated * @param slotId slot id of the agreement state */ event AgreementStateUpdated( address indexed agreementClass, address indexed account, uint256 slotId ); /** * @dev Get data of the slot of the state of an agreement * @param agreementClass Contract address of the agreement * @param account Account to query * @param slotId slot id of the state * @param dataLength length of the state data */ function getAgreementStateSlot( address agreementClass, address account, uint256 slotId, uint dataLength ) external view returns (bytes32[] memory slotData); /** * @notice Settle balance from an account by the agreement * @dev The agreement needs to make sure that the balance delta is balanced afterwards * @param account Account to query. * @param delta Amount of balance delta to be settled * * @custom:modifiers * - onlyAgreement */ function settleBalance( address account, int256 delta ) external; /** * @dev Make liquidation payouts (v2) * @param id Agreement ID * @param liquidationTypeData Data regarding the version of the liquidation schema and the type * @param liquidatorAccount Address of the executor of the liquidation * @param useDefaultRewardAccount Whether or not the default reward account receives the rewardAmount * @param targetAccount Account to be liquidated * @param rewardAmount The amount the rewarded account will receive * @param targetAccountBalanceDelta The delta amount the target account balance should change by * * @custom:note * - If a bailout is required (bailoutAmount > 0) * - the actual reward (single deposit) goes to the executor, * - while the reward account becomes the bailout account * - total bailout include: bailout amount + reward amount * - the targetAccount will be bailed out * - If a bailout is not required * - the targetAccount will pay the rewardAmount * - the liquidator (reward account in PIC period) will receive the rewardAmount * * @custom:modifiers * - onlyAgreement */ function makeLiquidationPayoutsV2 ( bytes32 id, bytes memory liquidationTypeData, address liquidatorAccount, bool useDefaultRewardAccount, address targetAccount, uint256 rewardAmount, int256 targetAccountBalanceDelta ) external; /** * @dev Agreement liquidation event v2 (including agent account) * @param agreementClass Contract address of the agreement * @param id Agreement ID * @param liquidatorAccount Address of the executor of the liquidation * @param targetAccount Account of the stream sender * @param rewardAmountReceiver Account that collects the reward or bails out insolvent accounts * @param rewardAmount The amount the reward recipient account balance should change by * @param targetAccountBalanceDelta The amount the sender account balance should change by * @param liquidationTypeData The encoded liquidation type data including the version (how to decode) * * @custom:note * Reward account rule: * - if the agreement is liquidated during the PIC period * - the rewardAmountReceiver will get the rewardAmount (remaining deposit), regardless of the liquidatorAccount * - the targetAccount will pay for the rewardAmount * - if the agreement is liquidated after the PIC period AND the targetAccount is solvent * - the rewardAmountReceiver will get the rewardAmount (remaining deposit) * - the targetAccount will pay for the rewardAmount * - if the targetAccount is insolvent * - the liquidatorAccount will get the rewardAmount (single deposit) * - the default reward account (governance) will pay for both the rewardAmount and bailoutAmount * - the targetAccount will receive the bailoutAmount */ event AgreementLiquidatedV2( address indexed agreementClass, bytes32 id, address indexed liquidatorAccount, address indexed targetAccount, address rewardAmountReceiver, uint256 rewardAmount, int256 targetAccountBalanceDelta, bytes liquidationTypeData ); /************************************************************************** * Function modifiers for access control and parameter validations * * While they cannot be explicitly stated in function definitions, they are * listed in function definition comments instead for clarity. * * NOTE: solidity-coverage not supporting it *************************************************************************/ /// @dev The msg.sender must be host contract //modifier onlyHost() virtual; /// @dev The msg.sender must be a listed agreement. //modifier onlyAgreement() virtual; /************************************************************************** * DEPRECATED *************************************************************************/ /** * @dev Agreement liquidation event (DEPRECATED BY AgreementLiquidatedBy) * @param agreementClass Contract address of the agreement * @param id Agreement ID * @param penaltyAccount Account of the agreement to be penalized * @param rewardAccount Account that collect the reward * @param rewardAmount Amount of liquidation reward * * @custom:deprecated Use AgreementLiquidatedV2 instead */ event AgreementLiquidated( address indexed agreementClass, bytes32 id, address indexed penaltyAccount, address indexed rewardAccount, uint256 rewardAmount ); /** * @dev System bailout occurred (DEPRECATED BY AgreementLiquidatedBy) * @param bailoutAccount Account that bailout the penalty account * @param bailoutAmount Amount of account bailout * * @custom:deprecated Use AgreementLiquidatedV2 instead */ event Bailout( address indexed bailoutAccount, uint256 bailoutAmount ); /** * @dev Agreement liquidation event (DEPRECATED BY AgreementLiquidatedV2) * @param liquidatorAccount Account of the agent that performed the liquidation. * @param agreementClass Contract address of the agreement * @param id Agreement ID * @param penaltyAccount Account of the agreement to be penalized * @param bondAccount Account that collect the reward or bailout accounts * @param rewardAmount Amount of liquidation reward * @param bailoutAmount Amount of liquidation bailouot * * @custom:deprecated Use AgreementLiquidatedV2 instead * * @custom:note * Reward account rule: * - if bailout is equal to 0, then * - the bondAccount will get the rewardAmount, * - the penaltyAccount will pay for the rewardAmount. * - if bailout is larger than 0, then * - the liquidatorAccount will get the rewardAmouont, * - the bondAccount will pay for both the rewardAmount and bailoutAmount, * - the penaltyAccount will pay for the rewardAmount while get the bailoutAmount. */ event AgreementLiquidatedBy( address liquidatorAccount, address indexed agreementClass, bytes32 id, address indexed penaltyAccount, address indexed bondAccount, uint256 rewardAmount, uint256 bailoutAmount ); }
/tokens/ERC20WithTokenInfo.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { TokenInfo } from "./TokenInfo.sol"; /** * @title ERC20 token with token info interface * @author Superfluid * @dev Using abstract contract instead of interfaces because old solidity * does not support interface inheriting other interfaces * solhint-disable-next-line no-empty-blocks * */ // solhint-disable-next-line no-empty-blocks abstract contract ERC20WithTokenInfo is IERC20, TokenInfo {}
/tokens/ISETH.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; import { ISuperToken } from "../superfluid/ISuperToken.sol"; /** * @title Super ETH (SETH) custom token interface * @author Superfluid */ interface ISETHCustom { // using native token function upgradeByETH() external payable; function upgradeByETHTo(address to) external payable; function downgradeToETH(uint wad) external; } /** * @title Super ETH (SETH) full interface * @author Superfluid */ // solhint-disable-next-line no-empty-blocks interface ISETH is ISETHCustom, ISuperToken {}
/tokens/TokenInfo.sol
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.11; /** * @title ERC20 token info interface * @author Superfluid * @dev ERC20 standard interface does not specify these functions, but * often the token implementations have them. */ interface TokenInfo { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() external view returns (string memory); /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() external view returns (uint8); }
/IV3SwapRouter.sol
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.5; pragma abicoder v2; import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 interface IV3SwapRouter is IUniswapV3SwapCallback { struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; } /// @notice Swaps `amountIn` of one token for as much as possible of another token /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance, /// and swap the entire amount, enabling contracts to send tokens before calling this function. /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata /// @return amountOut The amount of the received token function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); struct ExactInputParams { bytes path; address recipient; uint256 amountIn; uint256 amountOutMinimum; } /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance, /// and swap the entire amount, enabling contracts to send tokens before calling this function. /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata /// @return amountOut The amount of the received token function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } /// @notice Swaps as little as possible of one token for `amountOut` of another token /// that may remain in the router after the swap. /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata /// @return amountIn The amount of the input token function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); struct ExactOutputParams { bytes path; address recipient; uint256 amountOut; uint256 amountInMaximum; } /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) /// that may remain in the router after the swap. /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata /// @return amountIn The amount of the input token function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); }
/callback/IUniswapV3SwapCallback.sol
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Callback for IUniswapV3PoolActions#swap /// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface interface IUniswapV3SwapCallback { /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. /// @dev In the implementation you must pay the pool tokens owed for the swap. /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call function uniswapV3SwapCallback( int256 amount0Delta, int256 amount1Delta, bytes calldata data ) external; }
/TransferHelper.sol
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.6.0; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; library TransferHelper { /// @notice Transfers tokens from the targeted address to the given destination /// @notice Errors with 'STF' if transfer fails /// @param token The contract address of the token to be transferred /// @param from The originating address from which the tokens will be transferred /// @param to The destination address of the transfer /// @param value The amount to be transferred function safeTransferFrom( address token, address from, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF'); } /// @notice Transfers tokens from msg.sender to a recipient /// @dev Errors with ST if transfer fails /// @param token The contract address of the token which will be transferred /// @param to The recipient of the transfer /// @param value The value of the transfer function safeTransfer( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST'); } /// @notice Approves the stipulated contract to spend the given allowance in the given token /// @dev Errors with 'SA' if transfer fails /// @param token The contract address of the token to be approved /// @param to The target of the approval /// @param value The amount of the given token the target will be allowed to spend function safeApprove( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA'); } /// @notice Transfers ETH to the recipient address /// @dev Fails with `STE` /// @param to The destination of the transfer /// @param value The value to be transferred function safeTransferETH(address to, uint256 value) internal { (bool success, ) = to.call{value: value}(new bytes(0)); require(success, 'STE'); } }
/
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; // import the DirectPayments contract import "./DirectPaymentsPool.sol"; import "./ProvableNFT.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; // import "hardhat/console.sol"; contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable { error NOT_PROJECT_OWNER(); error NOT_POOL(); event PoolCreated( address indexed pool, string indexed projectId, string ipfs, uint32 indexed nftType, DirectPaymentsPool.PoolSettings poolSettings, DirectPaymentsPool.SafetyLimits poolLimits ); event PoolDetailsChanged(address indexed pool, string ipfs); event PoolVerifiedChanged(address indexed pool, bool isVerified); event UpdatedImpl(address indexed impl); struct PoolRegistry { string ipfs; bool isVerified; string projectId; } UpgradeableBeacon public impl; ProvableNFT public nft; uint32 public nextNftType; mapping(address => PoolRegistry) public registry; mapping(bytes32 => DirectPaymentsPool) public projectIdToControlPool; address public feeRecipient; uint32 public feeBps; mapping(address => address[]) public memberPools; address[] public pools; modifier onlyProjectOwnerOrNon(string memory projectId) { DirectPaymentsPool controlPool = projectIdToControlPool[keccak256(bytes(projectId))]; // console.log("result %s", controlPool.hasRole(controlPool.DEFAULT_ADMIN_ROLE(), msg.sender)); if (address(controlPool) != address(0)) { if (controlPool.hasRole(controlPool.DEFAULT_ADMIN_ROLE(), msg.sender) == false) { revert NOT_PROJECT_OWNER(); } } _; } modifier onlyPoolOwner(DirectPaymentsPool pool) { if (pool.hasRole(pool.DEFAULT_ADMIN_ROLE(), msg.sender) == false) { revert NOT_PROJECT_OWNER(); } _; } modifier onlyPool() { if (bytes(registry[msg.sender].projectId).length == 0) { revert NOT_POOL(); } _; } function _authorizeUpgrade(address _impl) internal virtual override onlyRole(DEFAULT_ADMIN_ROLE) {} function initialize( address _owner, address _dpimpl, ProvableNFT _nft, address _feeRecipient, uint32 _feeBps ) external initializer { nextNftType = 1; impl = new UpgradeableBeacon(_dpimpl); nft = _nft; feeRecipient = _feeRecipient; feeBps = _feeBps; _setupRole(DEFAULT_ADMIN_ROLE, _owner); } //TODO: implement a pool that's auto upgradeable using beacon method function createBeaconPool( string memory _projectId, string memory _ipfs, DirectPaymentsPool.PoolSettings memory _settings, DirectPaymentsPool.SafetyLimits memory _limits, uint32 _managerFeeBps ) external onlyProjectOwnerOrNon(_projectId) returns (DirectPaymentsPool pool) { return _createPool(_projectId, _ipfs, _settings, _limits, _managerFeeBps, true); } function createPool( string memory _projectId, string memory _ipfs, DirectPaymentsPool.PoolSettings memory _settings, DirectPaymentsPool.SafetyLimits memory _limits, uint32 _managerFeeBps ) external onlyProjectOwnerOrNon(_projectId) returns (DirectPaymentsPool pool) { return _createPool(_projectId, _ipfs, _settings, _limits, _managerFeeBps, false); } function _createPool( string memory _projectId, string memory _ipfs, DirectPaymentsPool.PoolSettings memory _settings, DirectPaymentsPool.SafetyLimits memory _limits, uint32 _managerFeeBps, bool useBeacon ) internal returns (DirectPaymentsPool pool) { //TODO: add check if msg.sender is whitelisted _settings.nftType = nextNftType; bytes memory initCall = abi.encodeCall( DirectPaymentsPool.initialize, (nft, _settings, _limits, _managerFeeBps, this) ); if (useBeacon) { pool = DirectPaymentsPool(address(new BeaconProxy(address(impl), initCall))); } else { pool = DirectPaymentsPool(address(new ERC1967Proxy(impl.implementation(), initCall))); } nft.grantRole(nft.getManagerRole(nextNftType), address(pool)); //access control to project is determinted by the first pool access control rules if (address(projectIdToControlPool[keccak256(bytes(_projectId))]) == address(0)) projectIdToControlPool[keccak256(bytes(_projectId))] = pool; registry[address(pool)].ipfs = _ipfs; registry[address(pool)].projectId = _projectId; pool.grantRole(DEFAULT_ADMIN_ROLE, msg.sender); pool.renounceRole(DEFAULT_ADMIN_ROLE, address(this)); pools.push(address(pool)); emit PoolCreated(address(pool), _projectId, _ipfs, nextNftType, _settings, _limits); nextNftType++; } function changePoolDetails(DirectPaymentsPool _pool, string memory _ipfs) external onlyPoolOwner(_pool) { registry[address(_pool)].ipfs = _ipfs; emit PoolDetailsChanged(address(_pool), _ipfs); } function setVerified(DirectPaymentsPool _pool, bool _isVerified) external onlyRole(DEFAULT_ADMIN_ROLE) { registry[address(_pool)].isVerified = _isVerified; emit PoolVerifiedChanged(address(_pool), _isVerified); } function updateImpl(address _impl) external onlyRole(DEFAULT_ADMIN_ROLE) { impl.upgradeTo(_impl); emit UpdatedImpl(_impl); } function setFeeInfo(address _feeRecipient, uint32 _feeBps) external onlyRole(DEFAULT_ADMIN_ROLE) { feeBps = _feeBps; feeRecipient = _feeRecipient; } function addMember(address member) external onlyPool { memberPools[member].push(msg.sender); } function removeMember(address member) external onlyPool { for (uint i = 0; i < memberPools[member].length; i++) { if (memberPools[member][i] == msg.sender) { memberPools[member][i] = memberPools[member][memberPools[member].length - 1]; memberPools[member].pop(); } } } }
/
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import "./DirectPaymentsPool.sol"; library DirectPayemntsLibrary { function _updateMemberLimits( DirectPaymentsPool.LimitsData storage memberStats, uint128 reward, uint64 curMonth ) internal { if (memberStats.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward { memberStats.daily = reward; } else { memberStats.daily += reward; } if (memberStats.lastMonth < curMonth) //month switched { memberStats.monthly = reward; } else { memberStats.monthly += reward; } memberStats.total += reward; memberStats.lastReward = uint64(block.timestamp); memberStats.lastMonth = curMonth; } function _updateGlobalLimits( DirectPaymentsPool.LimitsData storage globalLimits, uint128 reward, uint64 curMonth ) internal { if (globalLimits.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward { globalLimits.daily = reward; } else { globalLimits.daily += reward; } if (globalLimits.lastMonth < curMonth) //month switched { globalLimits.monthly = reward; } else { globalLimits.monthly += reward; } globalLimits.total += reward; globalLimits.lastReward = uint64(block.timestamp); globalLimits.lastMonth = curMonth; } }
/
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { ERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import { StringsUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; /** An NFT that can store data related to actions, the data is stored on-chain or as hash of the content that can later be proved. */ contract ProvableNFT is ERC721Upgradeable, AccessControlUpgradeable, UUPSUpgradeable { error BAD_DATAHASH(bytes32 dataHash, bytes32 tokenId); error NOT_MINTER(); error NOT_MANAGER(uint32); error BAD_NFTTYPE(); bytes32 public constant MINTER_ROLE = keccak256(abi.encodePacked("MINTER")); bytes16 private constant _SYMBOLS = "0123456789abcdef"; event ProvableNftMinted(uint256 tokenId, address to, bytes32 nftDataHash); struct EventData { uint16 subtype; uint32 timestamp; uint256 quantity; string eventUri; //extra data related to event address[] contributers; uint128 rewardOverride; //override reward defined per 1 quantity of event, pool will use this instead of its own reward if allowRewardOverride is true } struct NFTData { uint32 nftType; //should be non zero uint16 version; string nftUri; //extra data related to nft EventData[] events; } mapping(uint256 => NFTData) internal nftDatas; function initialize(string memory _name, string memory _symbol) external initializer { __ERC721_init(_name, _symbol); _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); } function _authorizeUpgrade(address /*newimpl*/) internal virtual override { _onlyManager(0); } function supportsInterface( bytes4 interfaceId ) public view virtual override(AccessControlUpgradeable, ERC721Upgradeable) returns (bool) { return super.supportsInterface(interfaceId); } function _onlyManager(uint32 nftType) internal view { if ( ((nftType > 0 && hasRole(getManagerRole(nftType), msg.sender)) || hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) == false ) { revert NOT_MANAGER(nftType); } } /** * @dev Mint a new NFT with the given URI and data hash. * * Requirements: * - The caller must have the `Manager` role. * * Emits a {Transfer} event and a {URI} event. * * @param _to The address that will receive the minted NFT. * @param _uri The URI for the NFT's metadata. * @param _nftDataHash The hash of the NFT's data. * @return tokenId ID of the newly minted NFT. */ function mint(address _to, string memory _uri, bytes32 _nftDataHash) public returns (uint256 tokenId) { _onlyManager(0); NFTData memory nftData; return _mint(_to, _uri, _nftDataHash, nftData, ""); //send false in calldata, assuming default receiver is a directpaymentspool. without nft data on chain it will fail. } function _mint( address _to, string memory _uri, bytes32 _nftDataHash, NFTData memory /*_nftData*/, bytes memory _callData ) internal returns (uint256 tokenId) { tokenId = uint256(_nftDataHash); nftDatas[tokenId].nftUri = _uri; _safeMint(_to, tokenId, _callData); emit ProvableNftMinted(tokenId, _to, _nftDataHash); } /** * @dev Mint a new permissioned NFT with the given data. * * This function is only accessible to users with the `Manager` role for the given NFT type. * * Stores nftData in contract storage if `_withStore` is true. * * @param _to The address that will receive the minted NFT. * @param _nftData The data for the NFT. * @param _withStore Whether or not to store the NFT data in the contract. * @param _callData call data to pass to erc721receiver * @return tokenId ID of the newly minted NFT. */ function mintPermissioned( address _to, NFTData memory _nftData, bool _withStore, bytes memory _callData ) external returns (uint256 tokenId) { _onlyManager(_nftData.nftType); if (_nftData.nftType == 0) revert BAD_NFTTYPE(); bytes32 dataHash = keccak256(abi.encode(_nftData)); tokenId = uint256(dataHash); if (_withStore) { NFTData storage store = nftDatas[tokenId]; store.nftUri = _nftData.nftUri; store.nftType = _nftData.nftType; store.version = _nftData.version; for (uint256 i = 0; i < _nftData.events.length; i++) { store.events.push(_nftData.events[i]); } } _mint(_to, _nftData.nftUri, dataHash, _nftData, _callData); } function proveNFTData(uint256 _tokenId, NFTData memory _nftData) public view returns (NFTData memory data) { _requireMinted(_tokenId); if (keccak256(abi.encode(_nftData)) != bytes32(_tokenId)) revert BAD_DATAHASH(keccak256(abi.encode(_nftData)), bytes32(_tokenId)); return _nftData; } function getNFTData(uint256 _tokenId) external view returns (NFTData memory) { return nftDatas[_tokenId]; } function getNFTEvent(uint256 _tokenId, uint256 _index) external view returns (EventData memory) { return nftDatas[_tokenId].events[_index]; } function getNFTEvents(uint256 _tokenId) external view returns (EventData[] memory) { return nftDatas[_tokenId].events; } function addManager(address _manager, uint32 _nftType) external { grantRole(getManagerRole(_nftType), _manager); } function getManagerRole(uint32 _nftType) public pure returns (bytes32 roleHash) { return keccak256(abi.encodePacked("MANAGER_", _nftType)); } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, nftDatas[tokenId].nftUri)) : nftDatas[tokenId].nftUri; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual override returns (string memory) { return ""; } }
/
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { SuperAppBaseFlow } from "./SuperAppBaseFlow.sol"; import { ISuperfluid, ISuperToken, SuperAppDefinitions } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; import { ISuperGoodDollar } from "@gooddollar/goodprotocol/contracts/token/superfluid/ISuperGoodDollar.sol"; import { SuperTokenV1Library } from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol"; import { CFAv1Library, IConstantFlowAgreementV1 } from "@superfluid-finance/ethereum-contracts/contracts/apps/CFAv1Library.sol"; import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; import "@uniswap/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol"; import "../DirectPayments/DirectPaymentsFactory.sol"; import "../utils/HelperLibrary.sol"; // import "hardhat/console.sol"; abstract contract GoodCollectiveSuperApp is SuperAppBaseFlow { int96 public constant MIN_FLOW_RATE = 386e9; using SuperTokenV1Library for ISuperToken; using CFAv1Library for CFAv1Library.InitData; error ZERO_ADDRESS(); error ZERO_AMOUNT(); error UNSUPPORTED_TOKEN(); error ONLY_HOST_OR_SENDER(address); error FEE_FLOW_FAILED(int96 curFeeRate, int96 newFeeRate); error MIN_FLOWRATE(int96 flowRate); /** * @dev Emitted when a supporter's contribution or flow rate is updated * @param supporter The address of the supporter * @param previousContribution The previous total contribution amount * @param contribution The new total contribution amount * @param previousFlowRate The previous flow rate if isFlowUpdate otherwise 0 * @param flowRate The new flow rate * @param isFlowUpdate True if the update was a flow rate update, false if it was a single contribution update */ event SupporterUpdated( address indexed supporter, uint256 previousContribution, uint256 contribution, int96 previousFlowRate, int96 flowRate, bool isFlowUpdate ); //TODO: // ask about "receiver" can it be different then app? /// @custom:oz-upgrades-unsafe-allow state-variable-immutable IV3SwapRouter public immutable swapRouter; struct SupporterData { uint256 contribution; int96 flowRate; uint128 lastUpdated; } ISuperToken public superToken; mapping(address => SupporterData) public supporters; //initialize cfaV1 variable CFAv1Library.InitData public cfaV1; IGoodCollectiveSuperApp.Stats public stats; uint256[45] private _reserved; /// @custom:oz-upgrades-unsafe-allow constructor constructor(ISuperfluid _host, IV3SwapRouter _swapRouter) SuperAppBaseFlow(_host) { if (address(_host) == address(0)) revert ZERO_ADDRESS(); swapRouter = _swapRouter; } function getRegistry() public view virtual returns (IRegistry); function getManagerFee() public view virtual returns (address admin, uint32 feeBps); /** * @dev Sets the address of the super token and registers the app with the host * @param _superToken The address of the super token contract */ function setSuperToken(ISuperToken _superToken) internal { if (address(_superToken) == address(0)) revert ZERO_ADDRESS(); // Set the super token address superToken = _superToken; // Define the callback definitions for the app uint256 callBackDefinitions = SuperAppDefinitions.APP_LEVEL_FINAL; // Register the app with the host host.registerApp(callBackDefinitions); //initialize InitData struct, and set equal to cfaV1 cfaV1 = CFAv1Library.InitData( host, IConstantFlowAgreementV1( address(host.getAgreementClass(keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1"))) ) ); } function isAcceptedSuperToken(ISuperToken _superToken) public view override returns (bool) { return address(superToken) == address(_superToken); } function getRealtimeContribution(address _user) public view returns (uint256) { SupporterData memory supporter = supporters[_user]; if (supporter.flowRate == 0) return supporter.contribution; return supporter.contribution + uint96(supporter.flowRate) * (block.timestamp - supporter.lastUpdated); } function getRealtimeStats() public view returns ( uint256 netIncome, uint256 totalFees, uint256 protocolFees, uint256 managerFees, int96 incomeFlowRate, int96 feeRate, int96 managerFeeRate ) { return HelperLibrary.getRealtimeStats(stats, superToken); } /** * @dev This function is called when a token transfer occurs * @param _sender The address of the sender * @param _amount The amount of tokens being transferred * @return bool Returns true to indicate that the transfer was successful */ function onTokenTransfer(address _sender, uint256 _amount, bytes calldata /*_data*/) external returns (bool) { if (msg.sender != address(superToken)) revert UNSUPPORTED_TOKEN(); if (_amount == 0) revert ZERO_AMOUNT(); // Update the contribution amount for the sender in the supporters mapping _updateSupporter(_sender, int256(_amount), 0, ""); return true; } /** * @dev allow single contribution. user needs to approve tokens first. can be used in superfluid batch actions. * @param _sender The address of the sender who is contributing tokens. * @param _amount The amount of tokens being contributed. * @param _ctx The context of the transaction for superfluid in case this was used in superfluid batch. otherwise can be empty. * @return Returns the context of the transaction. */ function support( address _sender, uint256 _amount, bytes memory _ctx ) external onlyHostOrSender(_sender) returns (bytes memory) { if (_amount == 0) revert ZERO_AMOUNT(); // Transfer the tokens from the sender to this contract TransferHelper.safeTransferFrom(address(superToken), _sender, address(this), _amount); // Update the contribution amount for the sender in the supporters mapping _updateSupporter(_sender, int256(_amount), 0, ""); //we pass empty ctx since this is not a flow but a single donation return _ctx; } /** * @dev allow single contribution. user needs to approve tokens first. can be used in superfluid batch actions. * @param _sender The address of the sender who is contributing tokens. * @param _customData The SwapData struct containing information about the swap * @param _ctx The context of the transaction for superfluid in case this was used in superfluid batch. otherwise can be empty. * @return Returns the context of the transaction. */ function supportWithSwap( address _sender, HelperLibrary.SwapData memory _customData, bytes memory _ctx ) external onlyHostOrSender(_sender) returns (bytes memory) { uint256 balance = superToken.balanceOf(address(this)); HelperLibrary.handleSwap(swapRouter, _customData, address(superToken), _sender, address(this)); uint256 amountReceived = superToken.balanceOf(address(this)) - balance; if (amountReceived == 0) revert ZERO_AMOUNT(); // Update the contribution amount for the sender in the supporters mapping _updateSupporter(_sender, int256(amountReceived), 0, ""); //we pass empty ctx since this is not a flow but a single donation return _ctx; } /** * @dev Handles the swap of tokens using the SwapData struct * @param _customData The SwapData struct containing information about the swap * @param _sender The address of the sender of the transaction * @param _ctx The context of the transaction for superfluid * @return Returns the context of the transaction */ function handleSwap( HelperLibrary.SwapData memory _customData, address _sender, bytes memory _ctx ) external onlyHostOrSender(_sender) returns (bytes memory) { HelperLibrary.handleSwap(swapRouter, _customData, address(superToken), _sender); // Return the context of the transaction return _ctx; } /** * @dev Called when a new flow is created * @param _sender The address of the sender of the transaction * @param _ctx The context of the transaction * @return Returns the new context of the transaction */ function onFlowCreated( ISuperToken /*superToken*/, address _sender, bytes calldata _ctx ) internal virtual override returns (bytes memory /*newCtx*/) { // Update the supporter's information return _updateSupporter(_sender, 0, 0, _ctx); } /** * @dev Called when an existing flow is updated * @param _sender The address of the sender of the transaction * @param _previousFlowRate The previous flow rate of the stream * @param _lastUpdated The timestamp of the last update to the stream * @param _ctx The context of the transaction * @return Returns the new context of the transaction */ function onFlowUpdated( ISuperToken /*superToken*/, address _sender, int96 _previousFlowRate, uint256 _lastUpdated, bytes calldata _ctx ) internal virtual override returns (bytes memory /*newCtx*/) { // Update the supporter's information return _updateSupporter(_sender, _previousFlowRate, _lastUpdated, _ctx); } /** * @dev Called when an existing flow is deleted * @param _sender The address of the sender of the transaction * @param _previousFlowRate The previous flow rate of the stream * @param _lastUpdated The timestamp of the last update to the stream * @param _ctx The context of the transaction * @return Returns the new context of the transaction */ function onFlowDeleted( ISuperToken /*superToken*/, address _sender, address /*receiver*/, int96 _previousFlowRate, uint256 _lastUpdated, bytes calldata _ctx ) internal virtual override returns (bytes memory /*newCtx*/) { // Update the supporter's information return _updateSupporter(_sender, _previousFlowRate, _lastUpdated, _ctx); } /** * @dev Updates the information for a supporter * @param _supporter The address of the supporter * @param _previousFlowRateOrAmount The previous flow rate of the stream or single donation amount * @param _lastUpdated The timestamp of the last update to the stream * @param _ctx flow context */ function _updateSupporter( address _supporter, int256 _previousFlowRateOrAmount, uint256 _lastUpdated, bytes memory _ctx ) internal returns (bytes memory newCtx) { newCtx = _ctx; bool _isFlow = _ctx.length > 0; (address feeRecipient, uint32 feeBps) = getManagerFee(); HelperLibrary.updateStats( stats, superToken, getRegistry(), feeBps, _isFlow ? 0 : uint256(_previousFlowRateOrAmount) ); // Get the current flow rate for the supporter int96 flowRate = superToken.getFlowRate(_supporter, address(this)); uint256 prevContribution = supporters[_supporter].contribution; if (_isFlow) { //enforce minimal flow rate if (flowRate > 0 && flowRate < MIN_FLOW_RATE) revert MIN_FLOWRATE(flowRate); // Update the supporter's information supporters[_supporter].lastUpdated = uint128(block.timestamp); supporters[_supporter].flowRate = flowRate; supporters[_supporter].contribution += uint256(_previousFlowRateOrAmount) * (block.timestamp - _lastUpdated); // address feeRecipient; // uint32 feeBps; if (address(getRegistry()) != address(0)) { feeRecipient = getRegistry().feeRecipient(); feeBps = getRegistry().feeBps(); // console.log("taking fees %s %s", feeRecipient, feeBps); newCtx = HelperLibrary.takeFeeFlow( cfaV1, superToken, stats.lastFeeRecipient, feeRecipient, feeBps, flowRate - int96(_previousFlowRateOrAmount), // we use diff, because manager takes fee from many streams not just this one newCtx ); stats.lastFeeRecipient = feeRecipient; } // console.log("protocol fee stream ok"); (feeRecipient, feeBps) = getManagerFee(); newCtx = HelperLibrary.takeFeeFlow( cfaV1, superToken, stats.lastManagerFeeRecipient, feeRecipient, feeBps, flowRate - int96(_previousFlowRateOrAmount), // we use diff, because manager takes fee from many streams not just this one newCtx ); stats.lastManagerFeeRecipient = feeRecipient; // console.log("admin fee stream ok"); // we update the last rate after we do all changes to our own flows stats.lastIncomeRate = superToken.getNetFlowRate(address(this)); } else { if (address(getRegistry()) != address(0)) { feeRecipient = getRegistry().feeRecipient(); feeBps = getRegistry().feeBps(); _takeFeeSingle(feeRecipient, feeBps, uint256(_previousFlowRateOrAmount)); } (feeRecipient, feeBps) = getManagerFee(); _takeFeeSingle(feeRecipient, feeBps, uint256(_previousFlowRateOrAmount)); supporters[_supporter].contribution += uint256(_previousFlowRateOrAmount); } emit SupporterUpdated( _supporter, prevContribution, supporters[_supporter].contribution, _isFlow ? int96(int256(_previousFlowRateOrAmount)) : int96(0), flowRate, _isFlow ); } function _takeFeeSingle(address recipient, uint32 feeBps, uint256 _amount) internal { if (recipient == address(0)) return; uint256 fee = (_amount * feeBps) / 10000; TransferHelper.safeTransfer(address(superToken), recipient, fee); } /** * for methods that can be called via superfluid batch or directly */ modifier onlyHostOrSender(address _sender) { if (msg.sender != _sender && msg.sender != address(host)) revert ONLY_HOST_OR_SENDER(msg.sender); _; } }
/
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IRegistry { function feeRecipient() external view returns (address); function feeBps() external view returns (uint32); } interface IGoodCollectiveSuperApp { struct Stats { uint256 netIncome; //without fees uint256 totalFees; uint256 lastUpdate; address lastFeeRecipient; int96 lastIncomeRate; address lastManagerFeeRecipient; uint256 protocolFees; uint256 managerFees; // adding fields MUST update GoodCollectiveSuperApp storage layout } function getAdminFee() external view returns (address admin, uint32 feeBps); }
/
// SPDX-License-Identifier: AGPLv3 pragma solidity >=0.8.0; import { ISuperfluid, ISuperToken, ISuperApp, SuperAppDefinitions } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; import { SuperTokenV1Library } from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol"; // import "hardhat/console.sol"; abstract contract SuperAppBaseFlow is ISuperApp { using SuperTokenV1Library for ISuperToken; bytes32 public constant CFAV1_TYPE = keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1"); /// @custom:oz-upgrades-unsafe-allow state-variable-immutable ISuperfluid public immutable host; /// @dev Thrown when the callback caller is not the host. error UnauthorizedHost(); /// @dev Thrown if a required callback wasn't implemented (overridden by the SuperApp) error NotImplemented(); /// @dev Thrown when SuperTokens not accepted by the SuperApp are streamed to it error NotAcceptedSuperToken(); /** * @dev Initializes the contract by setting the expected Superfluid Host. * and register which callbacks the Host can engage when appropriate. */ /// @custom:oz-upgrades-unsafe-allow constructor constructor(ISuperfluid host_) { host = host_; } /** * @dev Optional (positive) filter for accepting only specific SuperTokens. * The default implementation accepts all SuperTokens. * Can be overridden by the SuperApp in order to apply arbitrary filters. */ function isAcceptedSuperToken(ISuperToken /*superToken*/) public view virtual returns (bool); // --------------------------------------------------------------------------------------------- // CFA specific convenience callbacks // to be overridden and implemented by inheriting SuperApps /// @dev override if the SuperApp shall have custom logic invoked when a new flow /// to it is created. function onFlowCreated( ISuperToken /*superToken*/, address /*sender*/, bytes calldata ctx ) internal virtual returns (bytes memory /*newCtx*/) { return ctx; } /// @dev override if the SuperApp shall have custom logic invoked when an existing flow /// to it is updated (flowrate change). function onFlowUpdated( ISuperToken /*superToken*/, address /*sender*/, int96 /*previousFlowRate*/, uint256 /*lastUpdated*/, bytes calldata ctx ) internal virtual returns (bytes memory /*newCtx*/) { return ctx; } /// @dev override if the SuperApp shall have custom logic invoked when an existing flow /// to it is deleted (flowrate set to 0). /// Unlike the other callbacks, this method is NOT allowed to revert. /// Failing to satisfy that requirement leads to jailing (defunct SuperApp). function onFlowDeleted( ISuperToken /*superToken*/, address /*sender*/, address /*receiver*/, int96 /*previousFlowRate*/, uint256 /*lastUpdated*/, bytes calldata ctx ) internal virtual returns (bytes memory /*newCtx*/) { return ctx; } function beforeAgreementCreated( ISuperToken superToken, address agreementClass, bytes32 /*agreementId*/, bytes calldata /*agreementData*/, bytes calldata /*ctx*/ ) external view returns (bytes memory /*beforeData*/) { if (msg.sender != address(host)) revert UnauthorizedHost(); if (!isAcceptedAgreement(agreementClass)) return "0x"; if (!isAcceptedSuperToken(superToken)) revert NotAcceptedSuperToken(); return "0x"; } function afterAgreementCreated( ISuperToken superToken, address /*agreementClass*/, bytes32 /*agreementId*/, bytes calldata agreementData, bytes calldata /*cbdata*/, bytes calldata ctx ) external returns (bytes memory newCtx) { (address sender, ) = abi.decode(agreementData, (address, address)); return onFlowCreated( superToken, sender, ctx // userData can be acquired with `host.decodeCtx(ctx).userData` ); } // UPDATED callbacks function beforeAgreementUpdated( ISuperToken superToken, address agreementClass, bytes32 /*agreementId*/, bytes calldata agreementData, bytes calldata /*ctx*/ ) external view returns (bytes memory /*beforeData*/) { if (msg.sender != address(host)) revert UnauthorizedHost(); if (!isAcceptedAgreement(agreementClass)) return "0x"; if (!isAcceptedSuperToken(superToken)) revert NotAcceptedSuperToken(); (address sender, ) = abi.decode(agreementData, (address, address)); (uint256 lastUpdated, int96 flowRate, , ) = superToken.getFlowInfo(sender, address(this)); return abi.encode(flowRate, lastUpdated); } function afterAgreementUpdated( ISuperToken superToken, address /*agreementClass*/, bytes32 /*agreementId*/, bytes calldata agreementData, bytes calldata cbdata, bytes calldata ctx ) external returns (bytes memory newCtx) { (address sender, ) = abi.decode(agreementData, (address, address)); (int96 previousFlowRate, uint256 lastUpdated) = abi.decode(cbdata, (int96, uint256)); return onFlowUpdated( superToken, sender, previousFlowRate, lastUpdated, ctx // userData can be acquired with `host.decodeCtx(ctx).userData` ); } // DELETED callbacks function beforeAgreementTerminated( ISuperToken superToken, address agreementClass, bytes32 /*agreementId*/, bytes calldata agreementData, bytes calldata /*ctx*/ ) external view returns (bytes memory /*beforeData*/) { // we're not allowed to revert in this callback, thus just return empty beforeData on failing checks if (msg.sender != address(host) || !isAcceptedAgreement(agreementClass) || !isAcceptedSuperToken(superToken)) { return "0x"; } (address sender, address receiver) = abi.decode(agreementData, (address, address)); (uint256 lastUpdated, int96 flowRate, , ) = superToken.getFlowInfo(sender, receiver); return abi.encode(lastUpdated, flowRate); } function afterAgreementTerminated( ISuperToken superToken, address agreementClass, bytes32 /*agreementId*/, bytes calldata agreementData, bytes calldata cbdata, bytes calldata ctx ) external returns (bytes memory newCtx) { // we're not allowed to revert in this callback, thus just return ctx on failing checks if (msg.sender != address(host) || !isAcceptedAgreement(agreementClass) || !isAcceptedSuperToken(superToken)) { return ctx; } (address sender, address receiver) = abi.decode(agreementData, (address, address)); (uint256 lastUpdated, int96 previousFlowRate) = abi.decode(cbdata, (uint256, int96)); return onFlowDeleted(superToken, sender, receiver, previousFlowRate, lastUpdated, ctx); } // --------------------------------------------------------------------------------------------- // HELPERS /** * @dev Expect Super Agreement involved in callback to be an accepted one * This function can be overridden with custom logic and to revert if desired * Current implementation expects ConstantFlowAgreement */ function isAcceptedAgreement(address agreementClass) internal view virtual returns (bool) { return agreementClass == address(host.getAgreementClass(CFAV1_TYPE)); } }
/
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; import "@uniswap/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol"; import { ISuperToken } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; import { SuperTokenV1Library } from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol"; import { CFAv1Library } from "@superfluid-finance/ethereum-contracts/contracts/apps/CFAv1Library.sol"; import "../GoodCollective/IGoodCollectiveSuperApp.sol"; // import "hardhat/console.sol"; library HelperLibrary { using SuperTokenV1Library for ISuperToken; using CFAv1Library for CFAv1Library.InitData; /** * @dev A struct containing information about a token swap * @param swapFrom The address of the token being swapped * @param amount The amount of tokens being swapped * @param minReturn The minimum amount of tokens to be received in the swap * @param timestamp The deadline for the swap to occur * @param path The path of tokens to take in a uniswap v3 multi-hop swap, encoded as bytes */ struct SwapData { address swapFrom; uint256 amount; uint256 minReturn; uint256 deadline; bytes path; } function handleSwap( IV3SwapRouter swapRouter, SwapData memory _customData, address outTokenIfNoPath, address _sender ) external returns (uint256 amountOut) { return handleSwap(swapRouter, _customData, outTokenIfNoPath, _sender, _sender); } function handleSwap( IV3SwapRouter swapRouter, SwapData memory _customData, address outTokenIfNoPath, address _sender, address _recipient ) public returns (uint256 amountOut) { // Transfer the tokens from the sender to this contract TransferHelper.safeTransferFrom(_customData.swapFrom, _sender, address(this), _customData.amount); // Approve the router to spend the tokens TransferHelper.safeApprove(_customData.swapFrom, address(swapRouter), _customData.amount); if (_customData.path.length > 0) { // If a path is provided, execute a multi-hop swap IV3SwapRouter.ExactInputParams memory params = IV3SwapRouter.ExactInputParams({ path: _customData.path, recipient: _recipient, amountIn: _customData.amount, amountOutMinimum: _customData.minReturn }); return swapRouter.exactInput(params); } else { // If no path is provided, execute a single-hop swap IV3SwapRouter.ExactInputSingleParams memory params = IV3SwapRouter.ExactInputSingleParams({ tokenIn: _customData.swapFrom, tokenOut: outTokenIfNoPath, fee: 10000, recipient: _recipient, amountIn: _customData.amount, amountOutMinimum: _customData.minReturn, sqrtPriceLimitX96: 0 }); // Execute the swap using `exactInputSingle` return swapRouter.exactInputSingle(params); } } function getRealtimeStats( IGoodCollectiveSuperApp.Stats memory stats, ISuperToken superToken ) external view returns ( uint256 netIncome, uint256 totalFees, uint256 protocolFees, uint256 managerFees, int96 incomeFlowRate, int96 feeRate, int96 managerFeeRate ) { incomeFlowRate = stats.lastIncomeRate; netIncome = stats.netIncome + uint96(stats.lastIncomeRate) * (block.timestamp - stats.lastUpdate); feeRate = superToken.getFlowRate(address(this), stats.lastFeeRecipient); managerFeeRate = superToken.getFlowRate(address(this), stats.lastManagerFeeRecipient); protocolFees = stats.protocolFees + uint96(superToken.getFlowRate(address(this), stats.lastFeeRecipient)) * (block.timestamp - stats.lastUpdate); managerFees = stats.managerFees + uint96(superToken.getFlowRate(address(this), stats.lastManagerFeeRecipient)) * (block.timestamp - stats.lastUpdate); totalFees = protocolFees + managerFees; } // this should be called before any flow rate changes function updateStats( IGoodCollectiveSuperApp.Stats storage stats, ISuperToken superToken, IRegistry registry, uint32 managerFeeBps, uint256 _amount ) external { uint feeBps; if (address(registry) != address(0)) { feeBps = registry.feeBps(); } //use last rate before the current possible rate update stats.netIncome += uint96(stats.lastIncomeRate) * (block.timestamp - stats.lastUpdate); if (stats.lastFeeRecipient != address(0)) { //fees sent to last recipient, the flowRate to recipient still wasnt updated. stats.protocolFees += uint96(superToken.getFlowRate(address(this), stats.lastFeeRecipient)) * (block.timestamp - stats.lastUpdate); } if (stats.lastManagerFeeRecipient != address(0)) { //fees sent to last recipient, the flowRate to recipient still wasnt updated. stats.managerFees += uint96(superToken.getFlowRate(address(this), stats.lastManagerFeeRecipient)) * (block.timestamp - stats.lastUpdate); } if (_amount > 0) { stats.netIncome += (_amount * (10000 - feeBps - managerFeeBps)) / 10000; stats.protocolFees += (_amount * feeBps) / 10000; stats.managerFees += (_amount * managerFeeBps) / 10000; } stats.totalFees = stats.managerFees + stats.protocolFees; stats.lastUpdate = block.timestamp; } function takeFeeFlow( CFAv1Library.InitData storage cfaV1, ISuperToken superToken, address prevRecipient, address recipient, uint32 feeBps, int96 _diffRate, bytes memory _ctx ) public returns (bytes memory newCtx) { newCtx = _ctx; if (address(recipient) == address(0)) return newCtx; int96 curFeeRate = superToken.getFlowRate(address(this), prevRecipient); bool newRecipient; if (recipient != prevRecipient) { newRecipient = true; if (prevRecipient != address(0)) { //delete old recipient flow if (curFeeRate > 0) newCtx = cfaV1.deleteFlowWithCtx(newCtx, address(this), prevRecipient, superToken); //passing in the ctx which is sent to the callback here } } if (recipient == address(0)) return newCtx; int96 newFeeRate = curFeeRate + (_diffRate * int32(feeBps)) / 10000; if (newRecipient == false && curFeeRate > 0) { if (newFeeRate <= 0) { newCtx = cfaV1.deleteFlowWithCtx(newCtx, address(this), recipient, superToken); //passing in the ctx which is sent to the callback here } else { newCtx = cfaV1.updateFlowWithCtx(newCtx, recipient, superToken, newFeeRate); //passing in the ctx which is sent to the callback here } } else if (newFeeRate > 0) newCtx = cfaV1.createFlowWithCtx(newCtx, recipient, superToken, newFeeRate); //passing in the ctx which is sent to the callback here } }
Compiler Settings
{"remappings":[],"optimizer":{"runs":0,"enabled":true},"metadata":{"useLiteralContent":true,"bytecodeHash":"ipfs"},"libraries":{},"evmVersion":"paris","compilationTarget":{"contracts/DirectPayments/DirectPaymentsPool.sol":"DirectPaymentsPool"}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_host","internalType":"contract ISuperfluid"},{"type":"address","name":"_swapRouter","internalType":"contract IV3SwapRouter"}]},{"type":"error","name":"ALREADY_CLAIMED","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"error","name":"EMPTY_MANAGER","inputs":[]},{"type":"error","name":"FEE_FLOW_FAILED","inputs":[{"type":"int96","name":"curFeeRate","internalType":"int96"},{"type":"int96","name":"newFeeRate","internalType":"int96"}]},{"type":"error","name":"MIN_FLOWRATE","inputs":[{"type":"int96","name":"flowRate","internalType":"int96"}]},{"type":"error","name":"NFTTYPE_CHANGED","inputs":[]},{"type":"error","name":"NFT_MISSING","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"error","name":"NOT_MANAGER","inputs":[]},{"type":"error","name":"NO_BALANCE","inputs":[]},{"type":"error","name":"NotAcceptedSuperToken","inputs":[]},{"type":"error","name":"NotImplemented","inputs":[]},{"type":"error","name":"ONLY_HOST_OR_SENDER","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"error","name":"OVER_GLOBAL_LIMITS","inputs":[]},{"type":"error","name":"OVER_MEMBER_LIMITS","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"error","name":"UNSUPPORTED_NFT","inputs":[]},{"type":"error","name":"UNSUPPORTED_TOKEN","inputs":[]},{"type":"error","name":"UnauthorizedHost","inputs":[]},{"type":"error","name":"ZERO_ADDRESS","inputs":[]},{"type":"error","name":"ZERO_AMOUNT","inputs":[]},{"type":"event","name":"AdminChanged","inputs":[{"type":"address","name":"previousAdmin","internalType":"address","indexed":false},{"type":"address","name":"newAdmin","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"BeaconUpgraded","inputs":[{"type":"address","name":"beacon","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"EventRewardClaimed","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"uint16","name":"eventType","internalType":"uint16","indexed":false},{"type":"uint32","name":"eventTimestamp","internalType":"uint32","indexed":false},{"type":"uint256","name":"eventQuantity","internalType":"uint256","indexed":false},{"type":"string","name":"eventUri","internalType":"string","indexed":false},{"type":"address[]","name":"contributers","internalType":"address[]","indexed":false},{"type":"uint256","name":"rewardPerContributer","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"uint8","name":"version","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"NFTClaimed","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"uint256","name":"totalRewards","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"NOT_MEMBER_OR_WHITELISTED","inputs":[{"type":"address","name":"contributer","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"PoolCreated","inputs":[{"type":"address","name":"pool","internalType":"address","indexed":true},{"type":"string","name":"projectId","internalType":"string","indexed":true},{"type":"string","name":"ipfs","internalType":"string","indexed":false},{"type":"uint32","name":"nftType","internalType":"uint32","indexed":true},{"type":"tuple","name":"poolSettings","internalType":"struct DirectPaymentsPool.PoolSettings","indexed":false,"components":[{"type":"uint32","name":"nftType","internalType":"uint32"},{"type":"uint16[]","name":"validEvents","internalType":"uint16[]"},{"type":"uint128[]","name":"rewardPerEvent","internalType":"uint128[]"},{"type":"address","name":"manager","internalType":"address"},{"type":"address","name":"membersValidator","internalType":"contract IMembersValidator"},{"type":"address","name":"uniquenessValidator","internalType":"contract IIdentityV2"},{"type":"address","name":"rewardToken","internalType":"contract IERC20Upgradeable"},{"type":"bool","name":"allowRewardOverride","internalType":"bool"}]},{"type":"tuple","name":"poolLimits","internalType":"struct DirectPaymentsPool.SafetyLimits","indexed":false,"components":[{"type":"uint256","name":"maxTotalPerMonth","internalType":"uint256"},{"type":"uint256","name":"maxMemberPerMonth","internalType":"uint256"},{"type":"uint256","name":"maxMemberPerDay","internalType":"uint256"}]}],"anonymous":false},{"type":"event","name":"PoolLimitsChanged","inputs":[{"type":"tuple","name":"limits","internalType":"struct DirectPaymentsPool.SafetyLimits","indexed":false,"components":[{"type":"uint256","name":"maxTotalPerMonth","internalType":"uint256"},{"type":"uint256","name":"maxMemberPerMonth","internalType":"uint256"},{"type":"uint256","name":"maxMemberPerDay","internalType":"uint256"}]}],"anonymous":false},{"type":"event","name":"PoolSettingsChanged","inputs":[{"type":"tuple","name":"settings","internalType":"struct DirectPaymentsPool.PoolSettings","indexed":false,"components":[{"type":"uint32","name":"nftType","internalType":"uint32"},{"type":"uint16[]","name":"validEvents","internalType":"uint16[]"},{"type":"uint128[]","name":"rewardPerEvent","internalType":"uint128[]"},{"type":"address","name":"manager","internalType":"address"},{"type":"address","name":"membersValidator","internalType":"contract IMembersValidator"},{"type":"address","name":"uniquenessValidator","internalType":"contract IIdentityV2"},{"type":"address","name":"rewardToken","internalType":"contract IERC20Upgradeable"},{"type":"bool","name":"allowRewardOverride","internalType":"bool"}]}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"previousAdminRole","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"newAdminRole","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SupporterUpdated","inputs":[{"type":"address","name":"supporter","internalType":"address","indexed":true},{"type":"uint256","name":"previousContribution","internalType":"uint256","indexed":false},{"type":"uint256","name":"contribution","internalType":"uint256","indexed":false},{"type":"int96","name":"previousFlowRate","internalType":"int96","indexed":false},{"type":"int96","name":"flowRate","internalType":"int96","indexed":false},{"type":"bool","name":"isFlowUpdate","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"Upgraded","inputs":[{"type":"address","name":"implementation","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"CFAV1_TYPE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DEFAULT_ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"MANAGER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"MEMBER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"MINTER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"int96","name":"","internalType":"int96"}],"name":"MIN_FLOW_RATE","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes","name":"newCtx","internalType":"bytes"}],"name":"afterAgreementCreated","inputs":[{"type":"address","name":"superToken","internalType":"contract ISuperToken"},{"type":"address","name":"","internalType":"address"},{"type":"bytes32","name":"","internalType":"bytes32"},{"type":"bytes","name":"agreementData","internalType":"bytes"},{"type":"bytes","name":"","internalType":"bytes"},{"type":"bytes","name":"ctx","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes","name":"newCtx","internalType":"bytes"}],"name":"afterAgreementTerminated","inputs":[{"type":"address","name":"superToken","internalType":"contract ISuperToken"},{"type":"address","name":"agreementClass","internalType":"address"},{"type":"bytes32","name":"","internalType":"bytes32"},{"type":"bytes","name":"agreementData","internalType":"bytes"},{"type":"bytes","name":"cbdata","internalType":"bytes"},{"type":"bytes","name":"ctx","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes","name":"newCtx","internalType":"bytes"}],"name":"afterAgreementUpdated","inputs":[{"type":"address","name":"superToken","internalType":"contract ISuperToken"},{"type":"address","name":"","internalType":"address"},{"type":"bytes32","name":"","internalType":"bytes32"},{"type":"bytes","name":"agreementData","internalType":"bytes"},{"type":"bytes","name":"cbdata","internalType":"bytes"},{"type":"bytes","name":"ctx","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"beforeAgreementCreated","inputs":[{"type":"address","name":"superToken","internalType":"contract ISuperToken"},{"type":"address","name":"agreementClass","internalType":"address"},{"type":"bytes32","name":"","internalType":"bytes32"},{"type":"bytes","name":"","internalType":"bytes"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"beforeAgreementTerminated","inputs":[{"type":"address","name":"superToken","internalType":"contract ISuperToken"},{"type":"address","name":"agreementClass","internalType":"address"},{"type":"bytes32","name":"","internalType":"bytes32"},{"type":"bytes","name":"agreementData","internalType":"bytes"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"beforeAgreementUpdated","inputs":[{"type":"address","name":"superToken","internalType":"contract ISuperToken"},{"type":"address","name":"agreementClass","internalType":"address"},{"type":"bytes32","name":"","internalType":"bytes32"},{"type":"bytes","name":"agreementData","internalType":"bytes"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"host","internalType":"contract ISuperfluid"},{"type":"address","name":"cfa","internalType":"contract IConstantFlowAgreementV1"}],"name":"cfaV1","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claim","inputs":[{"type":"uint256","name":"_nftId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claim","inputs":[{"type":"uint256","name":"_nftId","internalType":"uint256"},{"type":"tuple","name":"_data","internalType":"struct ProvableNFT.NFTData","components":[{"type":"uint32","name":"nftType","internalType":"uint32"},{"type":"uint16","name":"version","internalType":"uint16"},{"type":"string","name":"nftUri","internalType":"string"},{"type":"tuple[]","name":"events","internalType":"struct ProvableNFT.EventData[]","components":[{"type":"uint16","name":"subtype","internalType":"uint16"},{"type":"uint32","name":"timestamp","internalType":"uint32"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"string","name":"eventUri","internalType":"string"},{"type":"address[]","name":"contributers","internalType":"address[]"},{"type":"uint128","name":"rewardOverride","internalType":"uint128"}]}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"claimedNfts","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"feeRecipient","internalType":"address"},{"type":"uint32","name":"feeBps","internalType":"uint32"}],"name":"getManagerFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRealtimeContribution","inputs":[{"type":"address","name":"_user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"netIncome","internalType":"uint256"},{"type":"uint256","name":"totalFees","internalType":"uint256"},{"type":"uint256","name":"protocolFees","internalType":"uint256"},{"type":"uint256","name":"managerFees","internalType":"uint256"},{"type":"int96","name":"incomeFlowRate","internalType":"int96"},{"type":"int96","name":"feeRate","internalType":"int96"},{"type":"int96","name":"managerFeeRate","internalType":"int96"}],"name":"getRealtimeStats","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IRegistry"}],"name":"getRegistry","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRoleAdmin","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint128","name":"daily","internalType":"uint128"},{"type":"uint128","name":"monthly","internalType":"uint128"},{"type":"uint128","name":"total","internalType":"uint128"},{"type":"uint64","name":"lastReward","internalType":"uint64"},{"type":"uint64","name":"lastMonth","internalType":"uint64"}],"name":"globalLimits","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"handleSwap","inputs":[{"type":"tuple","name":"_customData","internalType":"struct HelperLibrary.SwapData","components":[{"type":"address","name":"swapFrom","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"minReturn","internalType":"uint256"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"bytes","name":"path","internalType":"bytes"}]},{"type":"address","name":"_sender","internalType":"address"},{"type":"bytes","name":"_ctx","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ISuperfluid"}],"name":"host","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_nft","internalType":"contract ProvableNFT"},{"type":"tuple","name":"_settings","internalType":"struct DirectPaymentsPool.PoolSettings","components":[{"type":"uint32","name":"nftType","internalType":"uint32"},{"type":"uint16[]","name":"validEvents","internalType":"uint16[]"},{"type":"uint128[]","name":"rewardPerEvent","internalType":"uint128[]"},{"type":"address","name":"manager","internalType":"address"},{"type":"address","name":"membersValidator","internalType":"contract IMembersValidator"},{"type":"address","name":"uniquenessValidator","internalType":"contract IIdentityV2"},{"type":"address","name":"rewardToken","internalType":"contract IERC20Upgradeable"},{"type":"bool","name":"allowRewardOverride","internalType":"bool"}]},{"type":"tuple","name":"_limits","internalType":"struct DirectPaymentsPool.SafetyLimits","components":[{"type":"uint256","name":"maxTotalPerMonth","internalType":"uint256"},{"type":"uint256","name":"maxMemberPerMonth","internalType":"uint256"},{"type":"uint256","name":"maxMemberPerDay","internalType":"uint256"}]},{"type":"uint32","name":"_managerFeeBps","internalType":"uint32"},{"type":"address","name":"_registry","internalType":"contract DirectPaymentsFactory"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isAcceptedSuperToken","inputs":[{"type":"address","name":"_superToken","internalType":"contract ISuperToken"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"maxTotalPerMonth","internalType":"uint256"},{"type":"uint256","name":"maxMemberPerMonth","internalType":"uint256"},{"type":"uint256","name":"maxMemberPerDay","internalType":"uint256"}],"name":"limits","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"managerFeeBps","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint128","name":"daily","internalType":"uint128"},{"type":"uint128","name":"monthly","internalType":"uint128"},{"type":"uint128","name":"total","internalType":"uint128"},{"type":"uint64","name":"lastReward","internalType":"uint64"},{"type":"uint64","name":"lastMonth","internalType":"uint64"}],"name":"memberLimits","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"mintNFT","inputs":[{"type":"address","name":"_to","internalType":"address"},{"type":"tuple","name":"_nftData","internalType":"struct ProvableNFT.NFTData","components":[{"type":"uint32","name":"nftType","internalType":"uint32"},{"type":"uint16","name":"version","internalType":"uint16"},{"type":"string","name":"nftUri","internalType":"string"},{"type":"tuple[]","name":"events","internalType":"struct ProvableNFT.EventData[]","components":[{"type":"uint16","name":"subtype","internalType":"uint16"},{"type":"uint32","name":"timestamp","internalType":"uint32"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"string","name":"eventUri","internalType":"string"},{"type":"address[]","name":"contributers","internalType":"address[]"},{"type":"uint128","name":"rewardOverride","internalType":"uint128"}]}]},{"type":"bool","name":"withClaim","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ProvableNFT"}],"name":"nft","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"onERC721Received","inputs":[{"type":"address","name":"operator","internalType":"address"},{"type":"address","name":"from","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"onTokenTransfer","inputs":[{"type":"address","name":"_sender","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"proxiableUUID","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract DirectPaymentsFactory"}],"name":"registry","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPoolLimits","inputs":[{"type":"tuple","name":"_limits","internalType":"struct DirectPaymentsPool.SafetyLimits","components":[{"type":"uint256","name":"maxTotalPerMonth","internalType":"uint256"},{"type":"uint256","name":"maxMemberPerMonth","internalType":"uint256"},{"type":"uint256","name":"maxMemberPerDay","internalType":"uint256"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPoolSettings","inputs":[{"type":"tuple","name":"_settings","internalType":"struct DirectPaymentsPool.PoolSettings","components":[{"type":"uint32","name":"nftType","internalType":"uint32"},{"type":"uint16[]","name":"validEvents","internalType":"uint16[]"},{"type":"uint128[]","name":"rewardPerEvent","internalType":"uint128[]"},{"type":"address","name":"manager","internalType":"address"},{"type":"address","name":"membersValidator","internalType":"contract IMembersValidator"},{"type":"address","name":"uniquenessValidator","internalType":"contract IIdentityV2"},{"type":"address","name":"rewardToken","internalType":"contract IERC20Upgradeable"},{"type":"bool","name":"allowRewardOverride","internalType":"bool"}]},{"type":"uint32","name":"_managerFeeBps","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"nftType","internalType":"uint32"},{"type":"address","name":"manager","internalType":"address"},{"type":"address","name":"membersValidator","internalType":"contract IMembersValidator"},{"type":"address","name":"uniquenessValidator","internalType":"contract IIdentityV2"},{"type":"address","name":"rewardToken","internalType":"contract IERC20Upgradeable"},{"type":"bool","name":"allowRewardOverride","internalType":"bool"}],"name":"settings","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"netIncome","internalType":"uint256"},{"type":"uint256","name":"totalFees","internalType":"uint256"},{"type":"uint256","name":"lastUpdate","internalType":"uint256"},{"type":"address","name":"lastFeeRecipient","internalType":"address"},{"type":"int96","name":"lastIncomeRate","internalType":"int96"},{"type":"address","name":"lastManagerFeeRecipient","internalType":"address"},{"type":"uint256","name":"protocolFees","internalType":"uint256"},{"type":"uint256","name":"managerFees","internalType":"uint256"}],"name":"stats","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ISuperToken"}],"name":"superToken","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"support","inputs":[{"type":"address","name":"_sender","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"bytes","name":"_ctx","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"supportWithSwap","inputs":[{"type":"address","name":"_sender","internalType":"address"},{"type":"tuple","name":"_customData","internalType":"struct HelperLibrary.SwapData","components":[{"type":"address","name":"swapFrom","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"minReturn","internalType":"uint256"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"bytes","name":"path","internalType":"bytes"}]},{"type":"bytes","name":"_ctx","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"contribution","internalType":"uint256"},{"type":"int96","name":"flowRate","internalType":"int96"},{"type":"uint128","name":"lastUpdated","internalType":"uint128"}],"name":"supporters","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IV3SwapRouter"}],"name":"swapRouter","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"upgradeTo","inputs":[{"type":"address","name":"newImplementation","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"upgradeToAndCall","inputs":[{"type":"address","name":"newImplementation","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"upgradeToLatest","inputs":[{"type":"bytes","name":"data","internalType":"bytes"}]}]
Contract Creation Code
0x60e06040523060c0523480156200001557600080fd5b506040516200616e3803806200616e833981016040819052620000389162000098565b6001600160a01b038216608081905282908290620000695760405163538ba4f960e01b815260040160405180910390fd5b6001600160a01b031660a05250620000d7915050565b6001600160a01b03811681146200009557600080fd5b50565b60008060408385031215620000ac57600080fd5b8251620000b9816200007f565b6020840151909250620000cc816200007f565b809150509250929050565b60805160a05160c051615ff7620001776000396000818161106b015281816110ab0152818161145401528181611494015261150c01526000818161090101528181610e220152611fa7015260008181610ba901528181610da401528181610f2d015281816115ba015281816116a70152818161184b01528181611c0f01528181611ebd015281816122600152818161257c01526125e10152615ff76000f3fe60806040526004361061024f5760003560e01c80630150aefb1461025457806301ffc9a71461029a5780630947e8c7146102ba5780630c710776146102f4578063150b7a021461032057806319805538146103595780631a2a84b3146103925780631bb15f3d146103c05780631db128c71461046c578063230dbd2914610499578063248a9ca3146104b95780632b4116f7146104d95780632f2ff15d1461050657806330d9c9151461052857806336568abe146105485780633659cfe614610568578063379607f51461058857806347ccca02146105a85780634b1e337f146105c95780634f1ef286146105e957806352d1902d146105fc57806353c11f99146106115780635ab1bd53146106315780635f9e7d7714610646578063647c75e21461066657806372ca8a3e146106d757806376ba085b146106f75780637b10399914610717578063860aefcf14610738578063884d1f401461077557806391d14854146107955780639e83995f146107b55780639f351ce4146107d55780639f8fddd2146107f5578063a10f469e14610815578063a217fddf14610837578063a4c0ed361461084c578063ae8272001461086c578063bcb4546f1461087f578063c2e11e3f146108a1578063c31c9c07146108ef578063d3112b2e14610923578063d539139314610958578063d547741f1461097a578063d80528ae1461099a578063d86ed3e514610a2b578063dc61d5c214610a4b578063def482a414610a9e578063e06174e414610abe578063ec87621c14610b55578063f3d5e34814610b77578063f437bc5914610b97575b600080fd5b34801561026057600080fd5b5061028561026f366004614567565b61013e6020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156102a657600080fd5b506102856102b5366004614580565b610bcb565b3480156102c657600080fd5b50610143546102df90600160a01b900463ffffffff1681565b60405163ffffffff9091168152602001610291565b34801561030057600080fd5b5061030d6459df64940081565b604051600b9190910b8152602001610291565b34801561032c57600080fd5b5061034061033b366004614617565b610c02565b6040516001600160e01b03199091168152602001610291565b34801561036557600080fd5b5061036e610cbd565b604080516001600160a01b03909316835263ffffffff909116602083015201610291565b34801561039e57600080fd5b506103b26103ad366004614696565b610ce2565b604051908152602001610291565b3480156103cc57600080fd5b506104286103db366004614696565b61014060205260009081526040902080546001909101546001600160801b0380831692600160801b90819004821692918216916001600160401b03918104821691600160c01b9091041685565b604080516001600160801b039687168152948616602086015292909416918301919091526001600160401b039081166060830152909116608082015260a001610291565b34801561047857600080fd5b5061048c61048736600461487b565b610d82565b6040516102919190614942565b3480156104a557600080fd5b5061048c6104b4366004614955565b610ea3565b3480156104c557600080fd5b506103b26104d4366004614567565b610eea565b3480156104e557600080fd5b506097546104f9906001600160a01b031681565b6040516102919190614a1f565b34801561051257600080fd5b50610526610521366004614a33565b610eff565b005b34801561053457600080fd5b5061048c610543366004614a63565b610f20565b34801561055457600080fd5b50610526610563366004614a33565b610fe3565b34801561057457600080fd5b50610526610583366004614696565b611061565b34801561059457600080fd5b506105266105a3366004614567565b611129565b3480156105b457600080fd5b5061013d546104f9906001600160a01b031681565b3480156105d557600080fd5b506105266105e4366004614d98565b6111a1565b6105266105f7366004614e20565b61144a565b34801561060857600080fd5b506103b26114ff565b34801561061d57600080fd5b5061048c61062c366004614955565b6115ad565b34801561063d57600080fd5b506104f961168a565b34801561065257600080fd5b5061048c610661366004614a63565b61169a565b34801561067257600080fd5b506106b0610681366004614696565b60986020526000908152604090208054600190910154600b81900b90600160601b90046001600160801b031683565b60408051938452600b9290920b60208401526001600160801b031690820152606001610291565b3480156106e357600080fd5b506102856106f2366004614696565b61177f565b34801561070357600080fd5b50610526610712366004615071565b611793565b34801561072357600080fd5b50610143546104f9906001600160a01b031681565b34801561074457600080fd5b5061013a5461013b5461013c5461075a92919083565b60408051938452602084019290925290820152606001610291565b34801561078157600080fd5b5061048c610790366004614a63565b61183e565b3480156107a157600080fd5b506102856107b0366004614a33565b61193b565b3480156107c157600080fd5b506105266107d03660046150d4565b611966565b3480156107e157600080fd5b506105266107f036600461511a565b611b36565b34801561080157600080fd5b5061048c610810366004615156565b611bed565b34801561082157600080fd5b506103b2600080516020615fa283398151915281565b34801561084357600080fd5b506103b2600081565b34801561085857600080fd5b506102856108673660046151a4565b611ca7565b61052661087a3660046151ff565b611d20565b34801561088b57600080fd5b506103b2600080516020615edb83398151915281565b3480156108ad57600080fd5b506101415461014254610428916001600160801b0380821692600160801b92839004821692918116916001600160401b03908204811691600160c01b90041685565b3480156108fb57600080fd5b506104f97f000000000000000000000000000000000000000000000000000000000000000081565b34801561092f57600080fd5b50609954609a5461094a916001600160a01b03908116911682565b604051610291929190615233565b34801561096457600080fd5b506103b2600080516020615efb83398151915281565b34801561098657600080fd5b50610526610995366004614a33565b611da6565b3480156109a657600080fd5b50609b54609c54609d54609e54609f5460a05460a1546109e1969594936001600160a01b0380821694600160a01b909204600b0b9391169188565b604080519889526020890197909752958701949094526001600160a01b039283166060870152600b9190910b60808601521660a084015260c083015260e082015261010001610291565b348015610a3757600080fd5b5061048c610a46366004614955565b611dc2565b348015610a5757600080fd5b50610a60611df0565b604080519788526020880196909652948601939093526060850191909152600b90810b608085015290810b60a08401520b60c082015260e001610291565b348015610aaa57600080fd5b5061048c610ab936600461524d565b611e9b565b348015610aca57600080fd5b506101335461013654610137546101385461013954610b0d9463ffffffff16936001600160a01b039081169381169281169190811690600160a01b900460ff1686565b6040805163ffffffff90971687526001600160a01b039586166020880152938516938601939093529083166060850152919091166080830152151560a082015260c001610291565b348015610b6157600080fd5b506103b2600080516020615f5b83398151915281565b348015610b8357600080fd5b50610526610b923660046152ab565b6120ee565b348015610ba357600080fd5b506104f97f000000000000000000000000000000000000000000000000000000000000000081565b60006001600160e01b03198216637965db0b60e01b1480610bfc57506301ffc9a760e01b6001600160e01b03198316145b92915050565b61013d546040516302b5313d60e21b81526004810185905260009182916001600160a01b0390911690630ad4c4f490602401600060405180830381865afa158015610c51573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c79919081019061539c565b61013354815191925063ffffffff918216911614610caa5760405163f26722ad60e01b815260040160405180910390fd5b50630a85bd0160e11b9695505050505050565b61013654610143546001600160a01b0390911691600160a01b90910463ffffffff1690565b6001600160a01b0381166000908152609860209081526040808320815160608101835281548152600190910154600b81900b938201849052600160601b90046001600160801b031691810191909152908203610d3f575192915050565b6040810151610d57906001600160801b03164261556f565b81602001516001600160601b0316610d6f9190615582565b8151610d7b9190615599565b9392505050565b606082336001600160a01b03821614801590610dc75750336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614155b15610df0573360405163087231bf60e31b8152600401610de79190614a1f565b60405180910390fd5b6097546040516358c0dacb60e01b81527385608a0f804d0a9a72c022c812125aa25fa5b9bf916358c0dacb91610e58917f0000000000000000000000000000000000000000000000000000000000000000918a916001600160a01b0316908a906004016155f1565b602060405180830381865af4158015610e75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e99919061562c565b5091949350505050565b60606000610eb387890189615645565b509050600080610ec587890189615682565b91509150610ed78d8484848a8a612166565b93505050505b9998505050505050505050565b60009081526065602052604090206001015490565b610f0882610eea565b610f11816121ad565b610f1b83836121b7565b505050565b6060336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f6b57604051632f2d36a760e01b815260040160405180910390fd5b610f748761223a565b610f975750604080518082019091526002815261060f60f31b6020820152610fd8565b610fa08861177f565b610fbd57604051631ea25bab60e31b815260040160405180910390fd5b50604080518082019091526002815261060f60f31b60208201525b979650505050505050565b6001600160a01b03811633146110535760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610de7565b61105d82826122ee565b5050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036110a95760405162461bcd60e51b8152600401610de7906156ae565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166110db612371565b6001600160a01b0316146111015760405162461bcd60e51b8152600401610de7906156e8565b61110a8161238d565b6040805160008082526020820190925261112691839190612398565b50565b61013d546040516302b5313d60e21b8152600481018390526111269183916001600160a01b0390911690630ad4c4f490602401600060405180830381865afa158015611179573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107f0919081019061539c565b600054610100900460ff16158080156111c15750600054600160ff909116105b806111e257506111d030612503565b1580156111e2575060005460ff166001145b6112455760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610de7565b6000805460ff191660011790558015611268576000805461ff0019166101001790555b61014380546001600160a01b0319166001600160a01b0384161790558451610133805463ffffffff191663ffffffff90921691909117815560208087015180518893926112bb9261013492910190614403565b50604082015180516112d79160028401916020909101906144ac565b5060608201516003820180546001600160a01b03199081166001600160a01b03938416179091556080840151600484018054831691841691909117905560a0840151600584018054831691841691909117905560c08401516006909301805460e0909501519383166001600160a81b031990951694909417600160a01b931515840217909355865161013a55602087015161013b55604087015161013c5561013d805490931690891617909155610143805463ffffffff60a01b191663ffffffff86169092029190911790556113ae600033612512565b6113ca600080516020615f5b8339815191528660600151612512565b6113e6600080516020615efb8339815191528660600151612512565b610139546113fc906001600160a01b031661251c565b8015611442576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036114925760405162461bcd60e51b8152600401610de7906156ae565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166114c4612371565b6001600160a01b0316146114ea5760405162461bcd60e51b8152600401610de7906156e8565b6114f38261238d565b61105d82826001612398565b6000306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461159a5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152608401610de7565b50600080516020615f3b83398151915290565b6060336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415806115ed57506115eb8961223a565b155b806115fe57506115fc8a61177f565b155b156116425782828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929350610edd92505050565b600080611651888a018a615645565b9092509050600080611665888a018a615722565b915091506116788e858584868c8c6126be565b9e9d5050505050505050505050505050565b610143546001600160a01b031690565b6060336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415806116da57506116d88761223a565b155b806116eb57506116e98861177f565b155b1561170f5750604080518082019091526002815261060f60f31b6020820152610fd8565b60008061171e86880188615645565b909250905060008061173a6001600160a01b038d168585612711565b505091509150818160405160200161175f929190918252600b0b602082015260400190565b604051602081830303815290604052945050505050979650505050505050565b6097546001600160a01b0390811691161490565b600080516020615efb8339815191526117ab816121ad565b61013d546040516321aa1d2160e11b81526000916001600160a01b0316906343543a42906117e29088908890600190600401615883565b6020604051808303816000875af1158015611801573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611825919061562c565b90508215611837576118378185611b36565b5050505050565b6060336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461188957604051632f2d36a760e01b815260040160405180910390fd5b6118928761223a565b6118b55750604080518082019091526002815261060f60f31b6020820152610fd8565b6118be8861177f565b6118db57604051631ea25bab60e31b815260040160405180910390fd5b60006118e985870187615645565b5090506000806119036001600160a01b038c168430612711565b505060408051600b9290920b60208301528181019290925281518082038301815260609091019091529b9a5050505050505050505050565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b600080516020615f5b83398151915261197e816121ad565b610143805463ffffffff808516600160a01b0263ffffffff60a01b199092169190911790915561013354845182169116146119cc57604051630f91888160e01b815260040160405180910390fd5b60608301516001600160a01b03166119f75760405163890bc98f60e01b815260040160405180910390fd5b61013654611a10906000906001600160a01b03166122ee565b8251610133805463ffffffff191663ffffffff9092169190911781556020808501518051869392611a479261013492910190614403565b5060408201518051611a639160028401916020909101906144ac565b506060828101516003830180546001600160a01b039283166001600160a01b031991821617909155608085015160048501805491841691831691909117905560a08501516005850180549184169190921617905560c08401516006909301805460e0909501511515600160a01b026001600160a81b03199095169390911692909217929092179055830151611afa90600090612512565b7f3eed38e4b04ae182994f6ef05c58a3987f571a66d6860d9046621cc204f407a083604051611b299190615933565b60405180910390a1505050565b61013d5460405163049b73f560e31b81526001600160a01b03909116906324db9fa890611b6990859085906004016159e4565b600060405180830381865afa158015611b86573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611bae919081019061539c565b50600082815261013e602052604090205460ff1615611be3576040516330e51df560e11b815260048101839052602401610de7565b61105d82826127a9565b606083336001600160a01b03821614801590611c325750336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614155b15611c52573360405163087231bf60e31b8152600401610de79190614a1f565b83600003611c7357604051630f6fa54560e41b815260040160405180910390fd5b609754611c8b906001600160a01b0316863087612af0565b610e998585600060405180602001604052806000815250612bf2565b6097546000906001600160a01b03163314611cd557604051630ce706f760e41b815260040160405180910390fd5b83600003611cf657604051630f6fa54560e41b815260040160405180910390fd5b611d128585600060405180602001604052806000815250612bf2565b50600190505b949350505050565b6101435460408051638abf607760e01b815290516000926001600160a01b031691638abf60779160048083019260209291908290030181865afa158015611d6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d8f91906159fd565b9050611d9a8161238d565b61105d81836000612398565b611daf82610eea565b611db8816121ad565b610f1b83836122ee565b60606000611dd287890189615645565b509050611de18b82868661329a565b9b9a5050505050505050505050565b60975460405163b2f918a160e01b81526000918291829182918291829182917385608a0f804d0a9a72c022c812125aa25fa5b9bf9163b2f918a191611e4491609b916001600160a01b031690600401615a1a565b60e060405180830381865af4158015611e61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e859190615aa4565b959d949c50929a50909850965094509092509050565b606083336001600160a01b03821614801590611ee05750336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614155b15611f00573360405163087231bf60e31b8152600401610de79190614a1f565b6097546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611f31903090600401614a1f565b602060405180830381865afa158015611f4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f72919061562c565b6097546040516321437a5360e01b81529192507385608a0f804d0a9a72c022c812125aa25fa5b9bf916321437a5391611fe1917f0000000000000000000000000000000000000000000000000000000000000000918a916001600160a01b03909116908c903090600401615b18565b602060405180830381865af4158015611ffe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612022919061562c565b506097546040516370a0823160e01b815260009183916001600160a01b03909116906370a0823190612058903090600401614a1f565b602060405180830381865afa158015612075573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612099919061562c565b6120a3919061556f565b9050806000036120c657604051630f6fa54560e41b815260040160405180910390fd5b6120e28782600060405180602001604052806000815250612bf2565b50939695505050505050565b600080516020615f5b833981519152612106816121ad565b815161013a8190556020808401805161013b556040808601805161013c5581519485529151928401929092525182820152517f220b9fb6f33ff05be83cf4d215109467b91026cf1f239e2acb4b7095cf09d5c59181900360600190a15050565b6060610fd88686600b0b8686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612bf292505050565b61112681336132e8565b600080516020615fa28339815191528203612230576101435460405163329b55b760e21b81526001600160a01b039091169063ca6d56dc906121fd908490600401614a1f565b600060405180830381600087803b15801561221757600080fd5b505af115801561222b573d6000803e3d6000fd5b505050505b61105d8282613341565b604051635b69006f60e11b8152600080516020615edb83398151915260048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b6d200de90602401602060405180830381865afa1580156122af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122d391906159fd565b6001600160a01b0316826001600160a01b0316149050919050565b600080516020615fa28339815191528203612367576101435460405163058e524d60e11b81526001600160a01b0390911690630b1ca49a90612334908490600401614a1f565b600060405180830381600087803b15801561234e57600080fd5b505af1158015612362573d6000803e3d6000fd5b505050505b61105d82826133c7565b600080516020615f3b833981519152546001600160a01b031690565b600061105d816121ad565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156123cb57610f1b8361342e565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612425575060408051601f3d908101601f191682019092526124229181019061562c565b60015b6124885760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610de7565b600080516020615f3b83398151915281146124f75760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610de7565b50610f1b8383836134c8565b6001600160a01b03163b151590565b61105d82826121b7565b6001600160a01b0381166125435760405163538ba4f960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b03838116919091179091556040516315a722b960e31b8152600160048201819052917f0000000000000000000000000000000000000000000000000000000000000000169063ad3915c890602401600060405180830381600087803b1580156125c057600080fd5b505af11580156125d4573d6000803e3d6000fd5b50506040805180820182527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168082529151635b69006f60e11b8152600080516020615edb833981519152600482015290935060208401925063b6d200de90602401602060405180830381865afa15801561265b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267f91906159fd565b6001600160a01b039081169091528151609980546001600160a01b0319908116928416929092179055602090920151609a805490931691161790555050565b60606127058786600b0b8686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612bf292505050565b98975050505050505050565b6000806000806000612722886134f3565b604051631cd43d1160e31b81529092506001600160a01b038316915063e6a1e88890612756908b908b908b90600401615b59565b608060405180830381865afa158015612773573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127979190615b7c565b929b919a509850909650945050505050565b600082815261013e6020526040808220805460ff191660011790556101395490516370a0823160e01b815282916001600160a01b0316906370a08231906127f4903090600401614a1f565b602060405180830381865afa158015612811573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612835919061562c565b61013954909150600160a01b900460ff1660005b846060015151811015612aae5760008560600151828151811061286e5761286e615bba565b6020026020010151604001518380156128b1575060008760600151848151811061289a5761289a615bba565b602002602001015160a001516001600160801b0316115b6128e4576128df876060015184815181106128ce576128ce615bba565b602002602001015160000151613662565b612907565b866060015183815181106128fa576128fa615bba565b602002602001015160a001515b6001600160801b031661291a9190615582565b90508015612a9b5761292c8186615599565b94508385111561294f5760405163701b93d160e11b815260040160405180910390fd5b612959858561556f565b93506129868660600151838151811061297457612974615bba565b60200260200101516080015182613719565b867f66417923523a2d06a43299cb4e498d17eef686f73ae2484f05c36479f5ae5a6d876060015184815181106129be576129be615bba565b602002602001015160000151886060015185815181106129e0576129e0615bba565b60200260200101516020015189606001518681518110612a0257612a02615bba565b6020026020010151604001518a606001518781518110612a2457612a24615bba565b6020026020010151606001518b606001518881518110612a4657612a46615bba565b6020026020010151608001518c606001518981518110612a6857612a68615bba565b6020026020010151608001515188612a809190615bd0565b604051612a9296959493929190615bf2565b60405180910390a25b5080612aa681615c4f565b915050612849565b50847fdc780326abc7aa2bf7cfbd02de3cdd5c8020124228dbcbc133d6bcbd74a784cc84604051612ae191815260200190565b60405180910390a25050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691612b549190615c68565b6000604051808303816000865af19150503d8060008114612b91576040519150601f19603f3d011682016040523d82523d6000602084013e612b96565b606091505b5091509150818015612bc0575080511580612bc0575080806020019051810190612bc09190615c84565b6114425760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b6044820152606401610de7565b805181901515600080612c03610cbd565b60975491935091507385608a0f804d0a9a72c022c812125aa25fa5b9bf9063934e2cce90609b906001600160a01b0316612c3b61168a565b8588612c47578c612c4a565b60005b6040516001600160e01b031960e088901b16815260048101959095526001600160a01b03938416602486015292909116604484015263ffffffff166064830152608482015260a40160006040518083038186803b158015612caa57600080fd5b505af4158015612cbe573d6000803e3d6000fd5b505060975460009250612cdc91506001600160a01b03168a30613829565b6001600160a01b038a1660009081526098602052604090205490915084156130d157600082600b0b138015612d1957506459df649400600b83900b125b15612d3c57604051624963df60e91b8152600b83900b6004820152602401610de7565b6001600160a01b038a16600090815260986020526040902060010180546001600160e01b031916600160601b426001600160801b038116919091026001600160601b031916919091176001600160601b03851617909155612d9e90899061556f565b612da8908a615582565b6001600160a01b038b1660009081526098602052604081208054909190612dd0908490615599565b9091555060009050612de061168a565b6001600160a01b031614612fa357612df661168a565b6001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5791906159fd565b9350612e6161168a565b6001600160a01b03166324a9d8536040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec29190615ca1565b92507385608a0f804d0a9a72c022c812125aa25fa5b9bf634d167a906099609760009054906101000a90046001600160a01b0316609b60030160009054906101000a90046001600160a01b031688888f89612f1d9190615cbe565b8d6040518863ffffffff1660e01b8152600401612f409796959493929190615ceb565b600060405180830381865af4158015612f5d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612f859190810190615d3b565b609e80546001600160a01b0319166001600160a01b03871617905595505b612fab610cbd565b80945081955050507385608a0f804d0a9a72c022c812125aa25fa5b9bf634d167a906099609760009054906101000a90046001600160a01b0316609b60040160009054906101000a90046001600160a01b031688888f8961300c9190615cbe565b8d6040518863ffffffff1660e01b815260040161302f9796959493929190615ceb565b600060405180830381865af415801561304c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130749190810190615d3b565b609f80546001600160a01b0319166001600160a01b03878116919091179091556097549197506130a59116306138b7565b609e80546001600160601b0392909216600160a01b026001600160a01b03909216919091179055613210565b60006130db61168a565b6001600160a01b0316146131ca576130f161168a565b6001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561312e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315291906159fd565b935061315c61168a565b6001600160a01b03166324a9d8536040518163ffffffff1660e01b8152600401602060405180830381865afa158015613199573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131bd9190615ca1565b92506131ca84848b613936565b6131d2610cbd565b90945092506131e284848b613936565b6001600160a01b038a16600090815260986020526040812080548b929061320a908490615599565b90915550505b6001600160a01b038a166000818152609860205260409020547f6342e11b65ccb38a3bb259be9cda846c74ad52b36b62a2ee4799dc3db63a04a39083908861325957600061325b565b8c5b604080519384526020840192909252600b90810b8383015286900b60608301528815156080830152519081900360a00190a25050505050949350505050565b60606132df8460008086868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612bf292505050565b95945050505050565b6132f2828261193b565b61105d576132ff81613982565b61330a836020613994565b60405160200161331b929190615d83565b60408051601f198184030181529082905262461bcd60e51b8252610de791600401614942565b61334b828261193b565b61105d5760008281526065602090815260408083206001600160a01b03851684529091529020805460ff191660011790556133833390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6133d1828261193b565b1561105d5760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b61343781612503565b6134995760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610de7565b600080516020615f3b83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6134d183613b2f565b6000825111806134de5750805b15610f1b576134ed8383613b6f565b50505050565b7f65599bf746e17a00ea62e3610586992d88101b78eec3cf380706621fb97ea837547fb969d79d88acd02d04ed7ee7d43b949e7daf093d363abcfbbc43dfdfd1ce969a546001600160a01b038116613631576001600160a01b0382166135b857826001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa158015613591573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b591906159fd565b91505b604051635b69006f60e11b8152600080516020615edb83398151915260048201526001600160a01b0383169063b6d200de90602401602060405180830381865afa15801561360a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061362e91906159fd565b90505b6001600160a01b03821661364757613647615df2565b6001600160a01b03811661365d5761365d615df2565b915091565b6000805b610134548110156137105761013480548290811061368657613686615bba565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff168361ffff16036136fe576101358054829081106136cd576136cd615bba565b90600052602060002090600291828204019190066010029054906101000a90046001600160801b0316915050919050565b8061370881615c4f565b915050613666565b50600092915050565b60008251826001600160801b03166137319190615bd0565b90506000805b845181101561381f57600061376586838151811061375757613757615bba565b602002602001015185613c58565b905080156137bb576137aa86838151811061378257613782615bba565b6020908102919091010151610139546001600160a01b0316906001600160801b038716613d36565b6137b48484615e08565b925061380c565b7f617c38e0fa04973365b7abb47a8f354a5b3fbe3ea04b8a0649580d208a88cc608683815181106137ee576137ee615bba565b60200260200101516040516138039190614a1f565b60405180910390a15b508061381781615c4f565b915050613737565b506134ed81613d8c565b600080613835856134f3565b604051631cd43d1160e31b81529092506001600160a01b038316915063e6a1e8889061386990889088908890600401615b59565b608060405180830381865afa158015613886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138aa9190615b7c565b5090979650505050505050565b6000806138c3846134f3565b60405163e8e7e2d160e01b81529092506001600160a01b038316915063e8e7e2d1906138f59087908790600401615233565b602060405180830381865afa158015613912573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d189190615e2f565b6001600160a01b03831661394957505050565b600061271061395e63ffffffff851684615582565b6139689190615bd0565b6097549091506134ed906001600160a01b03168583613dd2565b6060610bfc6001600160a01b03831660145b606060006139a3836002615582565b6139ae906002615599565b6001600160401b038111156139c5576139c56146b3565b6040519080825280601f01601f1916602001820160405280156139ef576020820181803683370190505b509050600360fc1b81600081518110613a0a57613a0a615bba565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110613a3957613a39615bba565b60200101906001600160f81b031916908160001a9053506000613a5d846002615582565b613a68906001615599565b90505b6001811115613ae0576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110613a9c57613a9c615bba565b1a60f81b828281518110613ab257613ab2615bba565b60200101906001600160f81b031916908160001a90535060049490941c93613ad981615e4c565b9050613a6b565b508315610d7b5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610de7565b613b388161342e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060613b7a83612503565b613bd55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610de7565b600080846001600160a01b031684604051613bf09190615c68565b600060405180830381855af49150503d8060008114613c2b576040519150601f19603f3d011682016040523d82523d6000602084013e613c30565b606091505b50915091506132df8282604051806060016040528060278152602001615f7b60279139613ed5565b6000613c738360405180602001604052806000815250613eee565b1515600003613c8457506000610bfc565b6001600160a01b038316600090815261014060205260409020613caf9083613caa61406b565b61407f565b61013c546001600160a01b038416600090815261014060205260409020546001600160801b03161180613d0d575061013b546001600160a01b03841660009081526101406020526040902054600160801b90046001600160801b0316115b15613d2d5782604051636e661e3360e11b8152600401610de79190614a1f565b50600192915050565b610f1b8363a9059cbb60e01b8484604051602401613d55929190615e63565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261421b565b613d9b61014182613caa61406b565b61013a5461014154600160801b90046001600160801b0316111561112657604051639803f99760e01b815260040160405180910390fd5b600080846001600160a01b031663a9059cbb60e01b8585604051602401613dfa929190615e63565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613e389190615c68565b6000604051808303816000865af19150503d8060008114613e75576040519150601f19603f3d011682016040523d82523d6000602084013e613e7a565b606091505b5091509150818015613ea4575080511580613ea4575080806020019051810190613ea49190615c84565b6118375760405162461bcd60e51b815260206004820152600260248201526114d560f21b6044820152606401610de7565b60608315613ee4575081610d7b565b610d7b83836142ed565b6000613f08600080516020615fa28339815191528461193b565b15613f1557506001610bfc565b610138546001600160a01b031615613fb657610138546040516316874da360e11b81526000916001600160a01b031690632d0e9b4690613f59908790600401614a1f565b602060405180830381865afa158015613f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f9a91906159fd565b90506001600160a01b038116613fb4576000915050610bfc565b505b610137546001600160a01b03161561405357610137546040516356a42afd60e11b81526001600160a01b039091169063ad4855fa90613fff903090339088908890600401615e7c565b6020604051808303816000875af115801561401e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140429190615c84565b151560000361405357506000610bfc565b613d2d600080516020615fa2833981519152846121b7565b600061407a62278d0042615bd0565b905090565b600183015442906140a390600160801b90046001600160401b031662015180615eba565b6001600160401b031610156140d05782546001600160801b0319166001600160801b038316178355614112565b8254829084906000906140ed9084906001600160801b0316615e08565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b60018301546001600160401b03808316600160c01b90920416101561414e5782546001600160801b03808416600160801b029116178355614197565b825482908490601090614172908490600160801b90046001600160801b0316615e08565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b6001830180548391906000906141b79084906001600160801b0316615e08565b82546001600160801b039182166101009390930a92830292820219169190911790915560019490940180546001600160401b03938416600160c01b026001600160c01b034295909516600160801b0294909416951694909417919091179092555050565b6000614270826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166143179092919063ffffffff16565b805190915015610f1b578080602001905181019061428e9190615c84565b610f1b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610de7565b8151156142fd5781518083602001fd5b8060405162461bcd60e51b8152600401610de79190614942565b6060611d18848460008585600080866001600160a01b0316858760405161433e9190615c68565b60006040518083038185875af1925050503d806000811461437b576040519150601f19603f3d011682016040523d82523d6000602084013e614380565b606091505b5091509150610fd887838387606083156143f95782516000036143f2576143a685612503565b6143f25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610de7565b5081611d18565b611d1883836142ed565b82805482825590600052602060002090600f0160109004810192821561449c5791602002820160005b8382111561446c57835183826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030261442c565b801561449a5782816101000a81549061ffff021916905560020160208160010104928301926001030261446c565b505b506144a8929150614552565b5090565b8280548282559060005260206000209060010160029004810192821561449c5791602002820160005b8382111561451f57835183826101000a8154816001600160801b0302191690836001600160801b031602179055509260200192601001602081600f010492830192600103026144d5565b801561449a5782816101000a8154906001600160801b030219169055601001602081600f0104928301926001030261451f565b5b808211156144a85760008155600101614553565b60006020828403121561457957600080fd5b5035919050565b60006020828403121561459257600080fd5b81356001600160e01b031981168114610d7b57600080fd5b6001600160a01b038116811461112657600080fd5b80356145ca816145aa565b919050565b60008083601f8401126145e157600080fd5b5081356001600160401b038111156145f857600080fd5b60208301915083602082850101111561461057600080fd5b9250929050565b60008060008060006080868803121561462f57600080fd5b853561463a816145aa565b9450602086013561464a816145aa565b93506040860135925060608601356001600160401b0381111561466c57600080fd5b614678888289016145cf565b969995985093965092949392505050565b6001600160a01b03169052565b6000602082840312156146a857600080fd5b8135610d7b816145aa565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b03811182821017156146ec576146ec6146b3565b60405290565b604051608081016001600160401b03811182821017156146ec576146ec6146b3565b60405160c081016001600160401b03811182821017156146ec576146ec6146b3565b604051601f8201601f191681016001600160401b038111828210171561475e5761475e6146b3565b604052919050565b60006001600160401b0382111561477f5761477f6146b3565b50601f01601f191660200190565b600082601f83011261479e57600080fd5b81356147b16147ac82614766565b614736565b8181528460208386010111156147c657600080fd5b816020850160208301376000918101602001919091529392505050565b600060a082840312156147f557600080fd5b60405160a081016001600160401b038082118383101715614818576148186146b3565b816040528293508435915061482c826145aa565b818352602085013560208401526040850135604084015260608501356060840152608085013591508082111561486157600080fd5b5061486e8582860161478d565b6080830152505092915050565b60008060006060848603121561489057600080fd5b83356001600160401b03808211156148a757600080fd5b6148b3878388016147e3565b9450602086013591506148c5826145aa565b909250604085013590808211156148db57600080fd5b506148e88682870161478d565b9150509250925092565b60005b8381101561490d5781810151838201526020016148f5565b50506000910152565b6000815180845261492e8160208601602086016148f2565b601f01601f19169290920160200192915050565b602081526000610d7b6020830184614916565b600080600080600080600080600060c08a8c03121561497357600080fd5b893561497e816145aa565b985060208a013561498e816145aa565b975060408a0135965060608a01356001600160401b03808211156149b157600080fd5b6149bd8d838e016145cf565b909850965060808c01359150808211156149d657600080fd5b6149e28d838e016145cf565b909650945060a08c01359150808211156149fb57600080fd5b50614a088c828d016145cf565b915080935050809150509295985092959850929598565b6001600160a01b0391909116815260200190565b60008060408385031215614a4657600080fd5b823591506020830135614a58816145aa565b809150509250929050565b600080600080600080600060a0888a031215614a7e57600080fd5b8735614a89816145aa565b96506020880135614a99816145aa565b95506040880135945060608801356001600160401b0380821115614abc57600080fd5b614ac88b838c016145cf565b909650945060808a0135915080821115614ae157600080fd5b50614aee8a828b016145cf565b989b979a50959850939692959293505050565b63ffffffff8116811461112657600080fd5b80356145ca81614b01565b60006001600160401b03821115614b3757614b376146b3565b5060051b60200190565b61ffff8116811461112657600080fd5b80356145ca81614b41565b600082601f830112614b6d57600080fd5b81356020614b7d6147ac83614b1e565b82815260059290921b84018101918181019086841115614b9c57600080fd5b8286015b84811015614bc0578035614bb381614b41565b8352918301918301614ba0565b509695505050505050565b6001600160801b038116811461112657600080fd5b80356145ca81614bcb565b600082601f830112614bfc57600080fd5b81356020614c0c6147ac83614b1e565b82815260059290921b84018101918181019086841115614c2b57600080fd5b8286015b84811015614bc0578035614c4281614bcb565b8352918301918301614c2f565b801515811461112657600080fd5b80356145ca81614c4f565b60006101008284031215614c7b57600080fd5b614c836146c9565b9050614c8e82614b13565b815260208201356001600160401b0380821115614caa57600080fd5b614cb685838601614b5c565b60208401526040840135915080821115614ccf57600080fd5b50614cdc84828501614beb565b604083015250614cee606083016145bf565b6060820152614cff608083016145bf565b6080820152614d1060a083016145bf565b60a0820152614d2160c083016145bf565b60c0820152614d3260e08301614c5d565b60e082015292915050565b600060608284031215614d4f57600080fd5b604051606081016001600160401b0381118282101715614d7157614d716146b3565b80604052508091508235815260208301356020820152604083013560408201525092915050565b600080600080600060e08688031215614db057600080fd5b8535614dbb816145aa565b945060208601356001600160401b03811115614dd657600080fd5b614de288828901614c68565b945050614df28760408801614d3d565b925060a0860135614e0281614b01565b915060c0860135614e12816145aa565b809150509295509295909350565b60008060408385031215614e3357600080fd5b8235614e3e816145aa565b915060208301356001600160401b03811115614e5957600080fd5b614e658582860161478d565b9150509250929050565b600082601f830112614e8057600080fd5b81356020614e906147ac83614b1e565b82815260059290921b84018101918181019086841115614eaf57600080fd5b8286015b84811015614bc0578035614ec6816145aa565b8352918301918301614eb3565b600060808284031215614ee557600080fd5b614eed6146f2565b90508135614efa81614b01565b8152602082810135614f0b81614b41565b8282015260408301356001600160401b0380821115614f2957600080fd5b614f358683870161478d565b60408501526060850135915080821115614f4e57600080fd5b818501915085601f830112614f6257600080fd5b8135614f706147ac82614b1e565b81815260059190911b83018401908481019088831115614f8f57600080fd5b8585015b8381101561505f57803585811115614fab5760008081fd5b860160c0818c03601f1901811315614fc35760008081fd5b614fcb614714565b614fd68a8401614b51565b8152614fe460408401614b13565b8a820152606083013560408201526080830135888111156150055760008081fd5b6150138e8c8387010161478d565b60608301525060a0808401358981111561502d5760008081fd5b61503b8f8d83880101614e6f565b60808401525061504c838501614be0565b9082015285525050918601918601614f93565b50606087015250939695505050505050565b60008060006060848603121561508657600080fd5b8335615091816145aa565b925060208401356001600160401b038111156150ac57600080fd5b6150b886828701614ed3565b92505060408401356150c981614c4f565b809150509250925092565b600080604083850312156150e757600080fd5b82356001600160401b038111156150fd57600080fd5b61510985828601614c68565b9250506020830135614a5881614b01565b6000806040838503121561512d57600080fd5b8235915060208301356001600160401b0381111561514a57600080fd5b614e6585828601614ed3565b60008060006060848603121561516b57600080fd5b8335615176816145aa565b92506020840135915060408401356001600160401b0381111561519857600080fd5b6148e88682870161478d565b600080600080606085870312156151ba57600080fd5b84356151c5816145aa565b93506020850135925060408501356001600160401b038111156151e757600080fd5b6151f3878288016145cf565b95989497509550505050565b60006020828403121561521157600080fd5b81356001600160401b0381111561522757600080fd5b611d188482850161478d565b6001600160a01b0392831681529116602082015260400190565b60008060006060848603121561526257600080fd5b833561526d816145aa565b925060208401356001600160401b038082111561528957600080fd5b615295878388016147e3565b935060408601359150808211156148db57600080fd5b6000606082840312156152bd57600080fd5b610d7b8383614d3d565b80516145ca81614b01565b80516145ca81614b41565b60006152eb6147ac84614766565b90508281528383830111156152ff57600080fd5b610d7b8360208301846148f2565b600082601f83011261531e57600080fd5b610d7b838351602085016152dd565b600082601f83011261533e57600080fd5b8151602061534e6147ac83614b1e565b82815260059290921b8401810191818101908684111561536d57600080fd5b8286015b84811015614bc0578051615384816145aa565b8352918301918301615371565b80516145ca81614bcb565b600060208083850312156153af57600080fd5b82516001600160401b03808211156153c657600080fd5b90840190608082870312156153da57600080fd5b6153e26146f2565b82516153ed81614b01565b8152828401516153fc81614b41565b8185015260408301518281111561541257600080fd5b61541e8882860161530d565b60408301525060608301518281111561543657600080fd5b80840193505086601f84011261544b57600080fd5b82516154596147ac82614b1e565b81815260059190911b8401850190858101908983111561547857600080fd5b8686015b838110156155465780518681111561549357600080fd5b870160c0818d03601f190112156154aa5760008081fd5b6154b2614714565b6154bd8a83016152d2565b81526154cb604083016152c7565b8a820152606082015160408201526080820151888111156154ec5760008081fd5b6154fa8e8c8386010161530d565b60608301525060a080830151898111156155145760008081fd5b6155228f8d8387010161532d565b60808401525061553460c08401615391565b9082015284525091870191870161547c565b5060608401525090979650505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610bfc57610bfc615559565b8082028115828204841417610bfc57610bfc615559565b80820180821115610bfc57610bfc615559565b60018060a01b0381511682526020810151602083015260408101516040830152606081015160608301526000608082015160a06080850152611d1860a0850182614916565b600060018060a01b0380871683526080602084015261561360808401876155ac565b9481166040840152929092166060909101525092915050565b60006020828403121561563e57600080fd5b5051919050565b6000806040838503121561565857600080fd5b8235615663816145aa565b91506020830135614a58816145aa565b80600b0b811461112657600080fd5b6000806040838503121561569557600080fd5b82356156a081615673565b946020939093013593505050565b6020808252602c90820152600080516020615f1b83398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c90820152600080516020615f1b83398151915260408201526b6163746976652070726f787960a01b606082015260800190565b6000806040838503121561573557600080fd5b823591506020830135614a5881615673565b600081518084526020808501945080840160005b838110156157805781516001600160a01b03168752958201959082019060010161575b565b509495945050505050565b6000608063ffffffff80845116855260208085015161ffff80821683890152604091508187015185838a01526157c3868a0182614916565b90506060808901518a8303828c01528281518085528785019150878160051b860101888401935060005b8281101561587157601f19878303018452845160c08982511684528c8c830151168c8501528a8201518b85015287820151818986015261582f82860182614916565b9150508d8201518482038f8601526158478282615747565b60a0938401516001600160801b0316959093019490945250948a0194938a019391506001016157ed565b509d9c50505050505050505050505050565b6001600160a01b03841681526080602082018190526000906158a79083018561578b565b9215156040830152508082036060909101526000815260200192915050565b600081518084526020808501945080840160005b8381101561578057815161ffff16875295820195908201906001016158da565b600081518084526020808501945080840160005b838110156157805781516001600160801b03168752958201959082019060010161590e565b6020815263ffffffff8251166020820152600060208301516101008060408501526159626101208501836158c6565b91506040850151601f1985840301606086015261597f83826158fa565b92505060608501516159946080860182614689565b5060808501516159a760a0860182614689565b5060a08501516159ba60c0860182614689565b5060c08501516159cd60e0860182614689565b5060e0850151801515858301525090949350505050565b828152604060208201526000611d18604083018461578b565b600060208284031215615a0f57600080fd5b8151610d7b816145aa565b8254815260018301546020820152600283015460408201526003830154610120820190615a53606084016001600160a01b038316614689565b615a65608084018260a01d600b0b9052565b5060048401546001600160a01b0316615a8160a0840182614689565b50600584015460c0830152600684015460e0830152610d7b610100830184614689565b600080600080600080600060e0888a031215615abf57600080fd5b875196506020880151955060408801519450606088015193506080880151615ae681615673565b60a0890151909350615af781615673565b60c0890151909250615b0881615673565b8091505092959891949750929550565b600060018060a01b03808816835260a06020840152615b3a60a08401886155ac565b9581166040840152938416606083015250911660809091015292915050565b6001600160a01b0393841681529183166020830152909116604082015260600190565b60008060008060808587031215615b9257600080fd5b845193506020850151615ba481615673565b6040860151606090960151949790965092505050565b634e487b7160e01b600052603260045260246000fd5b600082615bed57634e487b7160e01b600052601260045260246000fd5b500490565b61ffff8716815263ffffffff8616602082015284604082015260c060608201526000615c2160c0830186614916565b8281036080840152615c338186615747565b91505060018060801b03831660a0830152979650505050505050565b600060018201615c6157615c61615559565b5060010190565b60008251615c7a8184602087016148f2565b9190910192915050565b600060208284031215615c9657600080fd5b8151610d7b81614c4f565b600060208284031215615cb357600080fd5b8151610d7b81614b01565b600b82810b9082900b0360016001605f1b0319811260016001605f1b0382131715610bfc57610bfc615559565b8781526001600160a01b03878116602083015286811660408301528516606082015263ffffffff84166080820152600b83900b60a082015260e060c08201819052600090610edd90830184614916565b600060208284031215615d4d57600080fd5b81516001600160401b03811115615d6357600080fd5b8201601f81018413615d7457600080fd5b611d18848251602084016152dd565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b815260008351615db58160178501602088016148f2565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615de68160288401602088016148f2565b01602801949350505050565b634e487b7160e01b600052600160045260246000fd5b6001600160801b03818116838216019080821115615e2857615e28615559565b5092915050565b600060208284031215615e4157600080fd5b8151610d7b81615673565b600081615e5b57615e5b615559565b506000190190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b038581168252848116602083015283166040820152608060608201819052600090615eb090830184614916565b9695505050505050565b6001600160401b03818116838216019080821115615e2857615e2861555956fea9214cc96615e0085d3bb077758db69497dc2dce3b2b1e97bc93c3d18d83efd3f0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc946756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b08416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564829b824e2329e205435d941c9f13baf578548505283d29261236d8e6596d4636a2646970667358221220c8453256a14ee7ad812368c60c392f4110ff687ed8bbbf09f17228b893212b4264736f6c63430008130033000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575850000000000000000000000005615cdab10dc425a742d643d949a7f474c01abc4
Deployed ByteCode
0x60806040526004361061024f5760003560e01c80630150aefb1461025457806301ffc9a71461029a5780630947e8c7146102ba5780630c710776146102f4578063150b7a021461032057806319805538146103595780631a2a84b3146103925780631bb15f3d146103c05780631db128c71461046c578063230dbd2914610499578063248a9ca3146104b95780632b4116f7146104d95780632f2ff15d1461050657806330d9c9151461052857806336568abe146105485780633659cfe614610568578063379607f51461058857806347ccca02146105a85780634b1e337f146105c95780634f1ef286146105e957806352d1902d146105fc57806353c11f99146106115780635ab1bd53146106315780635f9e7d7714610646578063647c75e21461066657806372ca8a3e146106d757806376ba085b146106f75780637b10399914610717578063860aefcf14610738578063884d1f401461077557806391d14854146107955780639e83995f146107b55780639f351ce4146107d55780639f8fddd2146107f5578063a10f469e14610815578063a217fddf14610837578063a4c0ed361461084c578063ae8272001461086c578063bcb4546f1461087f578063c2e11e3f146108a1578063c31c9c07146108ef578063d3112b2e14610923578063d539139314610958578063d547741f1461097a578063d80528ae1461099a578063d86ed3e514610a2b578063dc61d5c214610a4b578063def482a414610a9e578063e06174e414610abe578063ec87621c14610b55578063f3d5e34814610b77578063f437bc5914610b97575b600080fd5b34801561026057600080fd5b5061028561026f366004614567565b61013e6020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156102a657600080fd5b506102856102b5366004614580565b610bcb565b3480156102c657600080fd5b50610143546102df90600160a01b900463ffffffff1681565b60405163ffffffff9091168152602001610291565b34801561030057600080fd5b5061030d6459df64940081565b604051600b9190910b8152602001610291565b34801561032c57600080fd5b5061034061033b366004614617565b610c02565b6040516001600160e01b03199091168152602001610291565b34801561036557600080fd5b5061036e610cbd565b604080516001600160a01b03909316835263ffffffff909116602083015201610291565b34801561039e57600080fd5b506103b26103ad366004614696565b610ce2565b604051908152602001610291565b3480156103cc57600080fd5b506104286103db366004614696565b61014060205260009081526040902080546001909101546001600160801b0380831692600160801b90819004821692918216916001600160401b03918104821691600160c01b9091041685565b604080516001600160801b039687168152948616602086015292909416918301919091526001600160401b039081166060830152909116608082015260a001610291565b34801561047857600080fd5b5061048c61048736600461487b565b610d82565b6040516102919190614942565b3480156104a557600080fd5b5061048c6104b4366004614955565b610ea3565b3480156104c557600080fd5b506103b26104d4366004614567565b610eea565b3480156104e557600080fd5b506097546104f9906001600160a01b031681565b6040516102919190614a1f565b34801561051257600080fd5b50610526610521366004614a33565b610eff565b005b34801561053457600080fd5b5061048c610543366004614a63565b610f20565b34801561055457600080fd5b50610526610563366004614a33565b610fe3565b34801561057457600080fd5b50610526610583366004614696565b611061565b34801561059457600080fd5b506105266105a3366004614567565b611129565b3480156105b457600080fd5b5061013d546104f9906001600160a01b031681565b3480156105d557600080fd5b506105266105e4366004614d98565b6111a1565b6105266105f7366004614e20565b61144a565b34801561060857600080fd5b506103b26114ff565b34801561061d57600080fd5b5061048c61062c366004614955565b6115ad565b34801561063d57600080fd5b506104f961168a565b34801561065257600080fd5b5061048c610661366004614a63565b61169a565b34801561067257600080fd5b506106b0610681366004614696565b60986020526000908152604090208054600190910154600b81900b90600160601b90046001600160801b031683565b60408051938452600b9290920b60208401526001600160801b031690820152606001610291565b3480156106e357600080fd5b506102856106f2366004614696565b61177f565b34801561070357600080fd5b50610526610712366004615071565b611793565b34801561072357600080fd5b50610143546104f9906001600160a01b031681565b34801561074457600080fd5b5061013a5461013b5461013c5461075a92919083565b60408051938452602084019290925290820152606001610291565b34801561078157600080fd5b5061048c610790366004614a63565b61183e565b3480156107a157600080fd5b506102856107b0366004614a33565b61193b565b3480156107c157600080fd5b506105266107d03660046150d4565b611966565b3480156107e157600080fd5b506105266107f036600461511a565b611b36565b34801561080157600080fd5b5061048c610810366004615156565b611bed565b34801561082157600080fd5b506103b2600080516020615fa283398151915281565b34801561084357600080fd5b506103b2600081565b34801561085857600080fd5b506102856108673660046151a4565b611ca7565b61052661087a3660046151ff565b611d20565b34801561088b57600080fd5b506103b2600080516020615edb83398151915281565b3480156108ad57600080fd5b506101415461014254610428916001600160801b0380821692600160801b92839004821692918116916001600160401b03908204811691600160c01b90041685565b3480156108fb57600080fd5b506104f97f0000000000000000000000005615cdab10dc425a742d643d949a7f474c01abc481565b34801561092f57600080fd5b50609954609a5461094a916001600160a01b03908116911682565b604051610291929190615233565b34801561096457600080fd5b506103b2600080516020615efb83398151915281565b34801561098657600080fd5b50610526610995366004614a33565b611da6565b3480156109a657600080fd5b50609b54609c54609d54609e54609f5460a05460a1546109e1969594936001600160a01b0380821694600160a01b909204600b0b9391169188565b604080519889526020890197909752958701949094526001600160a01b039283166060870152600b9190910b60808601521660a084015260c083015260e082015261010001610291565b348015610a3757600080fd5b5061048c610a46366004614955565b611dc2565b348015610a5757600080fd5b50610a60611df0565b604080519788526020880196909652948601939093526060850191909152600b90810b608085015290810b60a08401520b60c082015260e001610291565b348015610aaa57600080fd5b5061048c610ab936600461524d565b611e9b565b348015610aca57600080fd5b506101335461013654610137546101385461013954610b0d9463ffffffff16936001600160a01b039081169381169281169190811690600160a01b900460ff1686565b6040805163ffffffff90971687526001600160a01b039586166020880152938516938601939093529083166060850152919091166080830152151560a082015260c001610291565b348015610b6157600080fd5b506103b2600080516020615f5b83398151915281565b348015610b8357600080fd5b50610526610b923660046152ab565b6120ee565b348015610ba357600080fd5b506104f97f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca95758581565b60006001600160e01b03198216637965db0b60e01b1480610bfc57506301ffc9a760e01b6001600160e01b03198316145b92915050565b61013d546040516302b5313d60e21b81526004810185905260009182916001600160a01b0390911690630ad4c4f490602401600060405180830381865afa158015610c51573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c79919081019061539c565b61013354815191925063ffffffff918216911614610caa5760405163f26722ad60e01b815260040160405180910390fd5b50630a85bd0160e11b9695505050505050565b61013654610143546001600160a01b0390911691600160a01b90910463ffffffff1690565b6001600160a01b0381166000908152609860209081526040808320815160608101835281548152600190910154600b81900b938201849052600160601b90046001600160801b031691810191909152908203610d3f575192915050565b6040810151610d57906001600160801b03164261556f565b81602001516001600160601b0316610d6f9190615582565b8151610d7b9190615599565b9392505050565b606082336001600160a01b03821614801590610dc75750336001600160a01b037f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575851614155b15610df0573360405163087231bf60e31b8152600401610de79190614a1f565b60405180910390fd5b6097546040516358c0dacb60e01b81527385608a0f804d0a9a72c022c812125aa25fa5b9bf916358c0dacb91610e58917f0000000000000000000000005615cdab10dc425a742d643d949a7f474c01abc4918a916001600160a01b0316908a906004016155f1565b602060405180830381865af4158015610e75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e99919061562c565b5091949350505050565b60606000610eb387890189615645565b509050600080610ec587890189615682565b91509150610ed78d8484848a8a612166565b93505050505b9998505050505050505050565b60009081526065602052604090206001015490565b610f0882610eea565b610f11816121ad565b610f1b83836121b7565b505050565b6060336001600160a01b037f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575851614610f6b57604051632f2d36a760e01b815260040160405180910390fd5b610f748761223a565b610f975750604080518082019091526002815261060f60f31b6020820152610fd8565b610fa08861177f565b610fbd57604051631ea25bab60e31b815260040160405180910390fd5b50604080518082019091526002815261060f60f31b60208201525b979650505050505050565b6001600160a01b03811633146110535760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610de7565b61105d82826122ee565b5050565b6001600160a01b037f000000000000000000000000260d41018b110b2c720a9d55f6ba1b0c17152d361630036110a95760405162461bcd60e51b8152600401610de7906156ae565b7f000000000000000000000000260d41018b110b2c720a9d55f6ba1b0c17152d366001600160a01b03166110db612371565b6001600160a01b0316146111015760405162461bcd60e51b8152600401610de7906156e8565b61110a8161238d565b6040805160008082526020820190925261112691839190612398565b50565b61013d546040516302b5313d60e21b8152600481018390526111269183916001600160a01b0390911690630ad4c4f490602401600060405180830381865afa158015611179573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107f0919081019061539c565b600054610100900460ff16158080156111c15750600054600160ff909116105b806111e257506111d030612503565b1580156111e2575060005460ff166001145b6112455760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610de7565b6000805460ff191660011790558015611268576000805461ff0019166101001790555b61014380546001600160a01b0319166001600160a01b0384161790558451610133805463ffffffff191663ffffffff90921691909117815560208087015180518893926112bb9261013492910190614403565b50604082015180516112d79160028401916020909101906144ac565b5060608201516003820180546001600160a01b03199081166001600160a01b03938416179091556080840151600484018054831691841691909117905560a0840151600584018054831691841691909117905560c08401516006909301805460e0909501519383166001600160a81b031990951694909417600160a01b931515840217909355865161013a55602087015161013b55604087015161013c5561013d805490931690891617909155610143805463ffffffff60a01b191663ffffffff86169092029190911790556113ae600033612512565b6113ca600080516020615f5b8339815191528660600151612512565b6113e6600080516020615efb8339815191528660600151612512565b610139546113fc906001600160a01b031661251c565b8015611442576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6001600160a01b037f000000000000000000000000260d41018b110b2c720a9d55f6ba1b0c17152d361630036114925760405162461bcd60e51b8152600401610de7906156ae565b7f000000000000000000000000260d41018b110b2c720a9d55f6ba1b0c17152d366001600160a01b03166114c4612371565b6001600160a01b0316146114ea5760405162461bcd60e51b8152600401610de7906156e8565b6114f38261238d565b61105d82826001612398565b6000306001600160a01b037f000000000000000000000000260d41018b110b2c720a9d55f6ba1b0c17152d36161461159a5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152608401610de7565b50600080516020615f3b83398151915290565b6060336001600160a01b037f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca957585161415806115ed57506115eb8961223a565b155b806115fe57506115fc8a61177f565b155b156116425782828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929350610edd92505050565b600080611651888a018a615645565b9092509050600080611665888a018a615722565b915091506116788e858584868c8c6126be565b9e9d5050505050505050505050505050565b610143546001600160a01b031690565b6060336001600160a01b037f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca957585161415806116da57506116d88761223a565b155b806116eb57506116e98861177f565b155b1561170f5750604080518082019091526002815261060f60f31b6020820152610fd8565b60008061171e86880188615645565b909250905060008061173a6001600160a01b038d168585612711565b505091509150818160405160200161175f929190918252600b0b602082015260400190565b604051602081830303815290604052945050505050979650505050505050565b6097546001600160a01b0390811691161490565b600080516020615efb8339815191526117ab816121ad565b61013d546040516321aa1d2160e11b81526000916001600160a01b0316906343543a42906117e29088908890600190600401615883565b6020604051808303816000875af1158015611801573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611825919061562c565b90508215611837576118378185611b36565b5050505050565b6060336001600160a01b037f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca957585161461188957604051632f2d36a760e01b815260040160405180910390fd5b6118928761223a565b6118b55750604080518082019091526002815261060f60f31b6020820152610fd8565b6118be8861177f565b6118db57604051631ea25bab60e31b815260040160405180910390fd5b60006118e985870187615645565b5090506000806119036001600160a01b038c168430612711565b505060408051600b9290920b60208301528181019290925281518082038301815260609091019091529b9a5050505050505050505050565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b600080516020615f5b83398151915261197e816121ad565b610143805463ffffffff808516600160a01b0263ffffffff60a01b199092169190911790915561013354845182169116146119cc57604051630f91888160e01b815260040160405180910390fd5b60608301516001600160a01b03166119f75760405163890bc98f60e01b815260040160405180910390fd5b61013654611a10906000906001600160a01b03166122ee565b8251610133805463ffffffff191663ffffffff9092169190911781556020808501518051869392611a479261013492910190614403565b5060408201518051611a639160028401916020909101906144ac565b506060828101516003830180546001600160a01b039283166001600160a01b031991821617909155608085015160048501805491841691831691909117905560a08501516005850180549184169190921617905560c08401516006909301805460e0909501511515600160a01b026001600160a81b03199095169390911692909217929092179055830151611afa90600090612512565b7f3eed38e4b04ae182994f6ef05c58a3987f571a66d6860d9046621cc204f407a083604051611b299190615933565b60405180910390a1505050565b61013d5460405163049b73f560e31b81526001600160a01b03909116906324db9fa890611b6990859085906004016159e4565b600060405180830381865afa158015611b86573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611bae919081019061539c565b50600082815261013e602052604090205460ff1615611be3576040516330e51df560e11b815260048101839052602401610de7565b61105d82826127a9565b606083336001600160a01b03821614801590611c325750336001600160a01b037f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575851614155b15611c52573360405163087231bf60e31b8152600401610de79190614a1f565b83600003611c7357604051630f6fa54560e41b815260040160405180910390fd5b609754611c8b906001600160a01b0316863087612af0565b610e998585600060405180602001604052806000815250612bf2565b6097546000906001600160a01b03163314611cd557604051630ce706f760e41b815260040160405180910390fd5b83600003611cf657604051630f6fa54560e41b815260040160405180910390fd5b611d128585600060405180602001604052806000815250612bf2565b50600190505b949350505050565b6101435460408051638abf607760e01b815290516000926001600160a01b031691638abf60779160048083019260209291908290030181865afa158015611d6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d8f91906159fd565b9050611d9a8161238d565b61105d81836000612398565b611daf82610eea565b611db8816121ad565b610f1b83836122ee565b60606000611dd287890189615645565b509050611de18b82868661329a565b9b9a5050505050505050505050565b60975460405163b2f918a160e01b81526000918291829182918291829182917385608a0f804d0a9a72c022c812125aa25fa5b9bf9163b2f918a191611e4491609b916001600160a01b031690600401615a1a565b60e060405180830381865af4158015611e61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e859190615aa4565b959d949c50929a50909850965094509092509050565b606083336001600160a01b03821614801590611ee05750336001600160a01b037f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575851614155b15611f00573360405163087231bf60e31b8152600401610de79190614a1f565b6097546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611f31903090600401614a1f565b602060405180830381865afa158015611f4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f72919061562c565b6097546040516321437a5360e01b81529192507385608a0f804d0a9a72c022c812125aa25fa5b9bf916321437a5391611fe1917f0000000000000000000000005615cdab10dc425a742d643d949a7f474c01abc4918a916001600160a01b03909116908c903090600401615b18565b602060405180830381865af4158015611ffe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612022919061562c565b506097546040516370a0823160e01b815260009183916001600160a01b03909116906370a0823190612058903090600401614a1f565b602060405180830381865afa158015612075573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612099919061562c565b6120a3919061556f565b9050806000036120c657604051630f6fa54560e41b815260040160405180910390fd5b6120e28782600060405180602001604052806000815250612bf2565b50939695505050505050565b600080516020615f5b833981519152612106816121ad565b815161013a8190556020808401805161013b556040808601805161013c5581519485529151928401929092525182820152517f220b9fb6f33ff05be83cf4d215109467b91026cf1f239e2acb4b7095cf09d5c59181900360600190a15050565b6060610fd88686600b0b8686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612bf292505050565b61112681336132e8565b600080516020615fa28339815191528203612230576101435460405163329b55b760e21b81526001600160a01b039091169063ca6d56dc906121fd908490600401614a1f565b600060405180830381600087803b15801561221757600080fd5b505af115801561222b573d6000803e3d6000fd5b505050505b61105d8282613341565b604051635b69006f60e11b8152600080516020615edb83398151915260048201526000907f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b03169063b6d200de90602401602060405180830381865afa1580156122af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122d391906159fd565b6001600160a01b0316826001600160a01b0316149050919050565b600080516020615fa28339815191528203612367576101435460405163058e524d60e11b81526001600160a01b0390911690630b1ca49a90612334908490600401614a1f565b600060405180830381600087803b15801561234e57600080fd5b505af1158015612362573d6000803e3d6000fd5b505050505b61105d82826133c7565b600080516020615f3b833981519152546001600160a01b031690565b600061105d816121ad565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156123cb57610f1b8361342e565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612425575060408051601f3d908101601f191682019092526124229181019061562c565b60015b6124885760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610de7565b600080516020615f3b83398151915281146124f75760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610de7565b50610f1b8383836134c8565b6001600160a01b03163b151590565b61105d82826121b7565b6001600160a01b0381166125435760405163538ba4f960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b03838116919091179091556040516315a722b960e31b8152600160048201819052917f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca957585169063ad3915c890602401600060405180830381600087803b1580156125c057600080fd5b505af11580156125d4573d6000803e3d6000fd5b50506040805180820182527f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca9575856001600160a01b03168082529151635b69006f60e11b8152600080516020615edb833981519152600482015290935060208401925063b6d200de90602401602060405180830381865afa15801561265b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267f91906159fd565b6001600160a01b039081169091528151609980546001600160a01b0319908116928416929092179055602090920151609a805490931691161790555050565b60606127058786600b0b8686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612bf292505050565b98975050505050505050565b6000806000806000612722886134f3565b604051631cd43d1160e31b81529092506001600160a01b038316915063e6a1e88890612756908b908b908b90600401615b59565b608060405180830381865afa158015612773573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127979190615b7c565b929b919a509850909650945050505050565b600082815261013e6020526040808220805460ff191660011790556101395490516370a0823160e01b815282916001600160a01b0316906370a08231906127f4903090600401614a1f565b602060405180830381865afa158015612811573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612835919061562c565b61013954909150600160a01b900460ff1660005b846060015151811015612aae5760008560600151828151811061286e5761286e615bba565b6020026020010151604001518380156128b1575060008760600151848151811061289a5761289a615bba565b602002602001015160a001516001600160801b0316115b6128e4576128df876060015184815181106128ce576128ce615bba565b602002602001015160000151613662565b612907565b866060015183815181106128fa576128fa615bba565b602002602001015160a001515b6001600160801b031661291a9190615582565b90508015612a9b5761292c8186615599565b94508385111561294f5760405163701b93d160e11b815260040160405180910390fd5b612959858561556f565b93506129868660600151838151811061297457612974615bba565b60200260200101516080015182613719565b867f66417923523a2d06a43299cb4e498d17eef686f73ae2484f05c36479f5ae5a6d876060015184815181106129be576129be615bba565b602002602001015160000151886060015185815181106129e0576129e0615bba565b60200260200101516020015189606001518681518110612a0257612a02615bba565b6020026020010151604001518a606001518781518110612a2457612a24615bba565b6020026020010151606001518b606001518881518110612a4657612a46615bba565b6020026020010151608001518c606001518981518110612a6857612a68615bba565b6020026020010151608001515188612a809190615bd0565b604051612a9296959493929190615bf2565b60405180910390a25b5080612aa681615c4f565b915050612849565b50847fdc780326abc7aa2bf7cfbd02de3cdd5c8020124228dbcbc133d6bcbd74a784cc84604051612ae191815260200190565b60405180910390a25050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691612b549190615c68565b6000604051808303816000865af19150503d8060008114612b91576040519150601f19603f3d011682016040523d82523d6000602084013e612b96565b606091505b5091509150818015612bc0575080511580612bc0575080806020019051810190612bc09190615c84565b6114425760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b6044820152606401610de7565b805181901515600080612c03610cbd565b60975491935091507385608a0f804d0a9a72c022c812125aa25fa5b9bf9063934e2cce90609b906001600160a01b0316612c3b61168a565b8588612c47578c612c4a565b60005b6040516001600160e01b031960e088901b16815260048101959095526001600160a01b03938416602486015292909116604484015263ffffffff166064830152608482015260a40160006040518083038186803b158015612caa57600080fd5b505af4158015612cbe573d6000803e3d6000fd5b505060975460009250612cdc91506001600160a01b03168a30613829565b6001600160a01b038a1660009081526098602052604090205490915084156130d157600082600b0b138015612d1957506459df649400600b83900b125b15612d3c57604051624963df60e91b8152600b83900b6004820152602401610de7565b6001600160a01b038a16600090815260986020526040902060010180546001600160e01b031916600160601b426001600160801b038116919091026001600160601b031916919091176001600160601b03851617909155612d9e90899061556f565b612da8908a615582565b6001600160a01b038b1660009081526098602052604081208054909190612dd0908490615599565b9091555060009050612de061168a565b6001600160a01b031614612fa357612df661168a565b6001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5791906159fd565b9350612e6161168a565b6001600160a01b03166324a9d8536040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec29190615ca1565b92507385608a0f804d0a9a72c022c812125aa25fa5b9bf634d167a906099609760009054906101000a90046001600160a01b0316609b60030160009054906101000a90046001600160a01b031688888f89612f1d9190615cbe565b8d6040518863ffffffff1660e01b8152600401612f409796959493929190615ceb565b600060405180830381865af4158015612f5d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612f859190810190615d3b565b609e80546001600160a01b0319166001600160a01b03871617905595505b612fab610cbd565b80945081955050507385608a0f804d0a9a72c022c812125aa25fa5b9bf634d167a906099609760009054906101000a90046001600160a01b0316609b60040160009054906101000a90046001600160a01b031688888f8961300c9190615cbe565b8d6040518863ffffffff1660e01b815260040161302f9796959493929190615ceb565b600060405180830381865af415801561304c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130749190810190615d3b565b609f80546001600160a01b0319166001600160a01b03878116919091179091556097549197506130a59116306138b7565b609e80546001600160601b0392909216600160a01b026001600160a01b03909216919091179055613210565b60006130db61168a565b6001600160a01b0316146131ca576130f161168a565b6001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561312e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315291906159fd565b935061315c61168a565b6001600160a01b03166324a9d8536040518163ffffffff1660e01b8152600401602060405180830381865afa158015613199573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131bd9190615ca1565b92506131ca84848b613936565b6131d2610cbd565b90945092506131e284848b613936565b6001600160a01b038a16600090815260986020526040812080548b929061320a908490615599565b90915550505b6001600160a01b038a166000818152609860205260409020547f6342e11b65ccb38a3bb259be9cda846c74ad52b36b62a2ee4799dc3db63a04a39083908861325957600061325b565b8c5b604080519384526020840192909252600b90810b8383015286900b60608301528815156080830152519081900360a00190a25050505050949350505050565b60606132df8460008086868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612bf292505050565b95945050505050565b6132f2828261193b565b61105d576132ff81613982565b61330a836020613994565b60405160200161331b929190615d83565b60408051601f198184030181529082905262461bcd60e51b8252610de791600401614942565b61334b828261193b565b61105d5760008281526065602090815260408083206001600160a01b03851684529091529020805460ff191660011790556133833390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6133d1828261193b565b1561105d5760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b61343781612503565b6134995760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610de7565b600080516020615f3b83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6134d183613b2f565b6000825111806134de5750805b15610f1b576134ed8383613b6f565b50505050565b7f65599bf746e17a00ea62e3610586992d88101b78eec3cf380706621fb97ea837547fb969d79d88acd02d04ed7ee7d43b949e7daf093d363abcfbbc43dfdfd1ce969a546001600160a01b038116613631576001600160a01b0382166135b857826001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa158015613591573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b591906159fd565b91505b604051635b69006f60e11b8152600080516020615edb83398151915260048201526001600160a01b0383169063b6d200de90602401602060405180830381865afa15801561360a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061362e91906159fd565b90505b6001600160a01b03821661364757613647615df2565b6001600160a01b03811661365d5761365d615df2565b915091565b6000805b610134548110156137105761013480548290811061368657613686615bba565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff168361ffff16036136fe576101358054829081106136cd576136cd615bba565b90600052602060002090600291828204019190066010029054906101000a90046001600160801b0316915050919050565b8061370881615c4f565b915050613666565b50600092915050565b60008251826001600160801b03166137319190615bd0565b90506000805b845181101561381f57600061376586838151811061375757613757615bba565b602002602001015185613c58565b905080156137bb576137aa86838151811061378257613782615bba565b6020908102919091010151610139546001600160a01b0316906001600160801b038716613d36565b6137b48484615e08565b925061380c565b7f617c38e0fa04973365b7abb47a8f354a5b3fbe3ea04b8a0649580d208a88cc608683815181106137ee576137ee615bba565b60200260200101516040516138039190614a1f565b60405180910390a15b508061381781615c4f565b915050613737565b506134ed81613d8c565b600080613835856134f3565b604051631cd43d1160e31b81529092506001600160a01b038316915063e6a1e8889061386990889088908890600401615b59565b608060405180830381865afa158015613886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138aa9190615b7c565b5090979650505050505050565b6000806138c3846134f3565b60405163e8e7e2d160e01b81529092506001600160a01b038316915063e8e7e2d1906138f59087908790600401615233565b602060405180830381865afa158015613912573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d189190615e2f565b6001600160a01b03831661394957505050565b600061271061395e63ffffffff851684615582565b6139689190615bd0565b6097549091506134ed906001600160a01b03168583613dd2565b6060610bfc6001600160a01b03831660145b606060006139a3836002615582565b6139ae906002615599565b6001600160401b038111156139c5576139c56146b3565b6040519080825280601f01601f1916602001820160405280156139ef576020820181803683370190505b509050600360fc1b81600081518110613a0a57613a0a615bba565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110613a3957613a39615bba565b60200101906001600160f81b031916908160001a9053506000613a5d846002615582565b613a68906001615599565b90505b6001811115613ae0576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110613a9c57613a9c615bba565b1a60f81b828281518110613ab257613ab2615bba565b60200101906001600160f81b031916908160001a90535060049490941c93613ad981615e4c565b9050613a6b565b508315610d7b5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610de7565b613b388161342e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060613b7a83612503565b613bd55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610de7565b600080846001600160a01b031684604051613bf09190615c68565b600060405180830381855af49150503d8060008114613c2b576040519150601f19603f3d011682016040523d82523d6000602084013e613c30565b606091505b50915091506132df8282604051806060016040528060278152602001615f7b60279139613ed5565b6000613c738360405180602001604052806000815250613eee565b1515600003613c8457506000610bfc565b6001600160a01b038316600090815261014060205260409020613caf9083613caa61406b565b61407f565b61013c546001600160a01b038416600090815261014060205260409020546001600160801b03161180613d0d575061013b546001600160a01b03841660009081526101406020526040902054600160801b90046001600160801b0316115b15613d2d5782604051636e661e3360e11b8152600401610de79190614a1f565b50600192915050565b610f1b8363a9059cbb60e01b8484604051602401613d55929190615e63565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261421b565b613d9b61014182613caa61406b565b61013a5461014154600160801b90046001600160801b0316111561112657604051639803f99760e01b815260040160405180910390fd5b600080846001600160a01b031663a9059cbb60e01b8585604051602401613dfa929190615e63565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613e389190615c68565b6000604051808303816000865af19150503d8060008114613e75576040519150601f19603f3d011682016040523d82523d6000602084013e613e7a565b606091505b5091509150818015613ea4575080511580613ea4575080806020019051810190613ea49190615c84565b6118375760405162461bcd60e51b815260206004820152600260248201526114d560f21b6044820152606401610de7565b60608315613ee4575081610d7b565b610d7b83836142ed565b6000613f08600080516020615fa28339815191528461193b565b15613f1557506001610bfc565b610138546001600160a01b031615613fb657610138546040516316874da360e11b81526000916001600160a01b031690632d0e9b4690613f59908790600401614a1f565b602060405180830381865afa158015613f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f9a91906159fd565b90506001600160a01b038116613fb4576000915050610bfc565b505b610137546001600160a01b03161561405357610137546040516356a42afd60e11b81526001600160a01b039091169063ad4855fa90613fff903090339088908890600401615e7c565b6020604051808303816000875af115801561401e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140429190615c84565b151560000361405357506000610bfc565b613d2d600080516020615fa2833981519152846121b7565b600061407a62278d0042615bd0565b905090565b600183015442906140a390600160801b90046001600160401b031662015180615eba565b6001600160401b031610156140d05782546001600160801b0319166001600160801b038316178355614112565b8254829084906000906140ed9084906001600160801b0316615e08565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b60018301546001600160401b03808316600160c01b90920416101561414e5782546001600160801b03808416600160801b029116178355614197565b825482908490601090614172908490600160801b90046001600160801b0316615e08565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b6001830180548391906000906141b79084906001600160801b0316615e08565b82546001600160801b039182166101009390930a92830292820219169190911790915560019490940180546001600160401b03938416600160c01b026001600160c01b034295909516600160801b0294909416951694909417919091179092555050565b6000614270826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166143179092919063ffffffff16565b805190915015610f1b578080602001905181019061428e9190615c84565b610f1b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610de7565b8151156142fd5781518083602001fd5b8060405162461bcd60e51b8152600401610de79190614942565b6060611d18848460008585600080866001600160a01b0316858760405161433e9190615c68565b60006040518083038185875af1925050503d806000811461437b576040519150601f19603f3d011682016040523d82523d6000602084013e614380565b606091505b5091509150610fd887838387606083156143f95782516000036143f2576143a685612503565b6143f25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610de7565b5081611d18565b611d1883836142ed565b82805482825590600052602060002090600f0160109004810192821561449c5791602002820160005b8382111561446c57835183826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030261442c565b801561449a5782816101000a81549061ffff021916905560020160208160010104928301926001030261446c565b505b506144a8929150614552565b5090565b8280548282559060005260206000209060010160029004810192821561449c5791602002820160005b8382111561451f57835183826101000a8154816001600160801b0302191690836001600160801b031602179055509260200192601001602081600f010492830192600103026144d5565b801561449a5782816101000a8154906001600160801b030219169055601001602081600f0104928301926001030261451f565b5b808211156144a85760008155600101614553565b60006020828403121561457957600080fd5b5035919050565b60006020828403121561459257600080fd5b81356001600160e01b031981168114610d7b57600080fd5b6001600160a01b038116811461112657600080fd5b80356145ca816145aa565b919050565b60008083601f8401126145e157600080fd5b5081356001600160401b038111156145f857600080fd5b60208301915083602082850101111561461057600080fd5b9250929050565b60008060008060006080868803121561462f57600080fd5b853561463a816145aa565b9450602086013561464a816145aa565b93506040860135925060608601356001600160401b0381111561466c57600080fd5b614678888289016145cf565b969995985093965092949392505050565b6001600160a01b03169052565b6000602082840312156146a857600080fd5b8135610d7b816145aa565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b03811182821017156146ec576146ec6146b3565b60405290565b604051608081016001600160401b03811182821017156146ec576146ec6146b3565b60405160c081016001600160401b03811182821017156146ec576146ec6146b3565b604051601f8201601f191681016001600160401b038111828210171561475e5761475e6146b3565b604052919050565b60006001600160401b0382111561477f5761477f6146b3565b50601f01601f191660200190565b600082601f83011261479e57600080fd5b81356147b16147ac82614766565b614736565b8181528460208386010111156147c657600080fd5b816020850160208301376000918101602001919091529392505050565b600060a082840312156147f557600080fd5b60405160a081016001600160401b038082118383101715614818576148186146b3565b816040528293508435915061482c826145aa565b818352602085013560208401526040850135604084015260608501356060840152608085013591508082111561486157600080fd5b5061486e8582860161478d565b6080830152505092915050565b60008060006060848603121561489057600080fd5b83356001600160401b03808211156148a757600080fd5b6148b3878388016147e3565b9450602086013591506148c5826145aa565b909250604085013590808211156148db57600080fd5b506148e88682870161478d565b9150509250925092565b60005b8381101561490d5781810151838201526020016148f5565b50506000910152565b6000815180845261492e8160208601602086016148f2565b601f01601f19169290920160200192915050565b602081526000610d7b6020830184614916565b600080600080600080600080600060c08a8c03121561497357600080fd5b893561497e816145aa565b985060208a013561498e816145aa565b975060408a0135965060608a01356001600160401b03808211156149b157600080fd5b6149bd8d838e016145cf565b909850965060808c01359150808211156149d657600080fd5b6149e28d838e016145cf565b909650945060a08c01359150808211156149fb57600080fd5b50614a088c828d016145cf565b915080935050809150509295985092959850929598565b6001600160a01b0391909116815260200190565b60008060408385031215614a4657600080fd5b823591506020830135614a58816145aa565b809150509250929050565b600080600080600080600060a0888a031215614a7e57600080fd5b8735614a89816145aa565b96506020880135614a99816145aa565b95506040880135945060608801356001600160401b0380821115614abc57600080fd5b614ac88b838c016145cf565b909650945060808a0135915080821115614ae157600080fd5b50614aee8a828b016145cf565b989b979a50959850939692959293505050565b63ffffffff8116811461112657600080fd5b80356145ca81614b01565b60006001600160401b03821115614b3757614b376146b3565b5060051b60200190565b61ffff8116811461112657600080fd5b80356145ca81614b41565b600082601f830112614b6d57600080fd5b81356020614b7d6147ac83614b1e565b82815260059290921b84018101918181019086841115614b9c57600080fd5b8286015b84811015614bc0578035614bb381614b41565b8352918301918301614ba0565b509695505050505050565b6001600160801b038116811461112657600080fd5b80356145ca81614bcb565b600082601f830112614bfc57600080fd5b81356020614c0c6147ac83614b1e565b82815260059290921b84018101918181019086841115614c2b57600080fd5b8286015b84811015614bc0578035614c4281614bcb565b8352918301918301614c2f565b801515811461112657600080fd5b80356145ca81614c4f565b60006101008284031215614c7b57600080fd5b614c836146c9565b9050614c8e82614b13565b815260208201356001600160401b0380821115614caa57600080fd5b614cb685838601614b5c565b60208401526040840135915080821115614ccf57600080fd5b50614cdc84828501614beb565b604083015250614cee606083016145bf565b6060820152614cff608083016145bf565b6080820152614d1060a083016145bf565b60a0820152614d2160c083016145bf565b60c0820152614d3260e08301614c5d565b60e082015292915050565b600060608284031215614d4f57600080fd5b604051606081016001600160401b0381118282101715614d7157614d716146b3565b80604052508091508235815260208301356020820152604083013560408201525092915050565b600080600080600060e08688031215614db057600080fd5b8535614dbb816145aa565b945060208601356001600160401b03811115614dd657600080fd5b614de288828901614c68565b945050614df28760408801614d3d565b925060a0860135614e0281614b01565b915060c0860135614e12816145aa565b809150509295509295909350565b60008060408385031215614e3357600080fd5b8235614e3e816145aa565b915060208301356001600160401b03811115614e5957600080fd5b614e658582860161478d565b9150509250929050565b600082601f830112614e8057600080fd5b81356020614e906147ac83614b1e565b82815260059290921b84018101918181019086841115614eaf57600080fd5b8286015b84811015614bc0578035614ec6816145aa565b8352918301918301614eb3565b600060808284031215614ee557600080fd5b614eed6146f2565b90508135614efa81614b01565b8152602082810135614f0b81614b41565b8282015260408301356001600160401b0380821115614f2957600080fd5b614f358683870161478d565b60408501526060850135915080821115614f4e57600080fd5b818501915085601f830112614f6257600080fd5b8135614f706147ac82614b1e565b81815260059190911b83018401908481019088831115614f8f57600080fd5b8585015b8381101561505f57803585811115614fab5760008081fd5b860160c0818c03601f1901811315614fc35760008081fd5b614fcb614714565b614fd68a8401614b51565b8152614fe460408401614b13565b8a820152606083013560408201526080830135888111156150055760008081fd5b6150138e8c8387010161478d565b60608301525060a0808401358981111561502d5760008081fd5b61503b8f8d83880101614e6f565b60808401525061504c838501614be0565b9082015285525050918601918601614f93565b50606087015250939695505050505050565b60008060006060848603121561508657600080fd5b8335615091816145aa565b925060208401356001600160401b038111156150ac57600080fd5b6150b886828701614ed3565b92505060408401356150c981614c4f565b809150509250925092565b600080604083850312156150e757600080fd5b82356001600160401b038111156150fd57600080fd5b61510985828601614c68565b9250506020830135614a5881614b01565b6000806040838503121561512d57600080fd5b8235915060208301356001600160401b0381111561514a57600080fd5b614e6585828601614ed3565b60008060006060848603121561516b57600080fd5b8335615176816145aa565b92506020840135915060408401356001600160401b0381111561519857600080fd5b6148e88682870161478d565b600080600080606085870312156151ba57600080fd5b84356151c5816145aa565b93506020850135925060408501356001600160401b038111156151e757600080fd5b6151f3878288016145cf565b95989497509550505050565b60006020828403121561521157600080fd5b81356001600160401b0381111561522757600080fd5b611d188482850161478d565b6001600160a01b0392831681529116602082015260400190565b60008060006060848603121561526257600080fd5b833561526d816145aa565b925060208401356001600160401b038082111561528957600080fd5b615295878388016147e3565b935060408601359150808211156148db57600080fd5b6000606082840312156152bd57600080fd5b610d7b8383614d3d565b80516145ca81614b01565b80516145ca81614b41565b60006152eb6147ac84614766565b90508281528383830111156152ff57600080fd5b610d7b8360208301846148f2565b600082601f83011261531e57600080fd5b610d7b838351602085016152dd565b600082601f83011261533e57600080fd5b8151602061534e6147ac83614b1e565b82815260059290921b8401810191818101908684111561536d57600080fd5b8286015b84811015614bc0578051615384816145aa565b8352918301918301615371565b80516145ca81614bcb565b600060208083850312156153af57600080fd5b82516001600160401b03808211156153c657600080fd5b90840190608082870312156153da57600080fd5b6153e26146f2565b82516153ed81614b01565b8152828401516153fc81614b41565b8185015260408301518281111561541257600080fd5b61541e8882860161530d565b60408301525060608301518281111561543657600080fd5b80840193505086601f84011261544b57600080fd5b82516154596147ac82614b1e565b81815260059190911b8401850190858101908983111561547857600080fd5b8686015b838110156155465780518681111561549357600080fd5b870160c0818d03601f190112156154aa5760008081fd5b6154b2614714565b6154bd8a83016152d2565b81526154cb604083016152c7565b8a820152606082015160408201526080820151888111156154ec5760008081fd5b6154fa8e8c8386010161530d565b60608301525060a080830151898111156155145760008081fd5b6155228f8d8387010161532d565b60808401525061553460c08401615391565b9082015284525091870191870161547c565b5060608401525090979650505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610bfc57610bfc615559565b8082028115828204841417610bfc57610bfc615559565b80820180821115610bfc57610bfc615559565b60018060a01b0381511682526020810151602083015260408101516040830152606081015160608301526000608082015160a06080850152611d1860a0850182614916565b600060018060a01b0380871683526080602084015261561360808401876155ac565b9481166040840152929092166060909101525092915050565b60006020828403121561563e57600080fd5b5051919050565b6000806040838503121561565857600080fd5b8235615663816145aa565b91506020830135614a58816145aa565b80600b0b811461112657600080fd5b6000806040838503121561569557600080fd5b82356156a081615673565b946020939093013593505050565b6020808252602c90820152600080516020615f1b83398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c90820152600080516020615f1b83398151915260408201526b6163746976652070726f787960a01b606082015260800190565b6000806040838503121561573557600080fd5b823591506020830135614a5881615673565b600081518084526020808501945080840160005b838110156157805781516001600160a01b03168752958201959082019060010161575b565b509495945050505050565b6000608063ffffffff80845116855260208085015161ffff80821683890152604091508187015185838a01526157c3868a0182614916565b90506060808901518a8303828c01528281518085528785019150878160051b860101888401935060005b8281101561587157601f19878303018452845160c08982511684528c8c830151168c8501528a8201518b85015287820151818986015261582f82860182614916565b9150508d8201518482038f8601526158478282615747565b60a0938401516001600160801b0316959093019490945250948a0194938a019391506001016157ed565b509d9c50505050505050505050505050565b6001600160a01b03841681526080602082018190526000906158a79083018561578b565b9215156040830152508082036060909101526000815260200192915050565b600081518084526020808501945080840160005b8381101561578057815161ffff16875295820195908201906001016158da565b600081518084526020808501945080840160005b838110156157805781516001600160801b03168752958201959082019060010161590e565b6020815263ffffffff8251166020820152600060208301516101008060408501526159626101208501836158c6565b91506040850151601f1985840301606086015261597f83826158fa565b92505060608501516159946080860182614689565b5060808501516159a760a0860182614689565b5060a08501516159ba60c0860182614689565b5060c08501516159cd60e0860182614689565b5060e0850151801515858301525090949350505050565b828152604060208201526000611d18604083018461578b565b600060208284031215615a0f57600080fd5b8151610d7b816145aa565b8254815260018301546020820152600283015460408201526003830154610120820190615a53606084016001600160a01b038316614689565b615a65608084018260a01d600b0b9052565b5060048401546001600160a01b0316615a8160a0840182614689565b50600584015460c0830152600684015460e0830152610d7b610100830184614689565b600080600080600080600060e0888a031215615abf57600080fd5b875196506020880151955060408801519450606088015193506080880151615ae681615673565b60a0890151909350615af781615673565b60c0890151909250615b0881615673565b8091505092959891949750929550565b600060018060a01b03808816835260a06020840152615b3a60a08401886155ac565b9581166040840152938416606083015250911660809091015292915050565b6001600160a01b0393841681529183166020830152909116604082015260600190565b60008060008060808587031215615b9257600080fd5b845193506020850151615ba481615673565b6040860151606090960151949790965092505050565b634e487b7160e01b600052603260045260246000fd5b600082615bed57634e487b7160e01b600052601260045260246000fd5b500490565b61ffff8716815263ffffffff8616602082015284604082015260c060608201526000615c2160c0830186614916565b8281036080840152615c338186615747565b91505060018060801b03831660a0830152979650505050505050565b600060018201615c6157615c61615559565b5060010190565b60008251615c7a8184602087016148f2565b9190910192915050565b600060208284031215615c9657600080fd5b8151610d7b81614c4f565b600060208284031215615cb357600080fd5b8151610d7b81614b01565b600b82810b9082900b0360016001605f1b0319811260016001605f1b0382131715610bfc57610bfc615559565b8781526001600160a01b03878116602083015286811660408301528516606082015263ffffffff84166080820152600b83900b60a082015260e060c08201819052600090610edd90830184614916565b600060208284031215615d4d57600080fd5b81516001600160401b03811115615d6357600080fd5b8201601f81018413615d7457600080fd5b611d18848251602084016152dd565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b815260008351615db58160178501602088016148f2565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615de68160288401602088016148f2565b01602801949350505050565b634e487b7160e01b600052600160045260246000fd5b6001600160801b03818116838216019080821115615e2857615e28615559565b5092915050565b600060208284031215615e4157600080fd5b8151610d7b81615673565b600081615e5b57615e5b615559565b506000190190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b038581168252848116602083015283166040820152608060608201819052600090615eb090830184614916565b9695505050505050565b6001600160401b03818116838216019080821115615e2857615e2861555956fea9214cc96615e0085d3bb077758db69497dc2dce3b2b1e97bc93c3d18d83efd3f0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc946756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b08416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564829b824e2329e205435d941c9f13baf578548505283d29261236d8e6596d4636a2646970667358221220c8453256a14ee7ad812368c60c392f4110ff687ed8bbbf09f17228b893212b4264736f6c63430008130033