Address Details
contract
0xC64ED8278B73cC3A623ffFa50Ad5F622c3775a5D
- Contract Name
- DirectPaymentsFactory
- Creator
- 0x2ceade–010627 at 0x1f9b82–a03896
- 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
- 28900174
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- DirectPaymentsFactory
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 0
- EVM Version
- paris
- Verified at
- 2024-11-25T22:33:54.512965Z
contracts/DirectPayments/DirectPaymentsFactory.sol
// 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 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 "./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; 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 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/DirectPaymentsFactory.sol":"DirectPaymentsFactory"}}
Contract ABI
[{"type":"error","name":"NOT_POOL","inputs":[]},{"type":"error","name":"NOT_PROJECT_OWNER","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":"Initialized","inputs":[{"type":"uint8","name":"version","internalType":"uint8","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":"PoolDetailsChanged","inputs":[{"type":"address","name":"pool","internalType":"address","indexed":true},{"type":"string","name":"ipfs","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"PoolVerifiedChanged","inputs":[{"type":"address","name":"pool","internalType":"address","indexed":true},{"type":"bool","name":"isVerified","internalType":"bool","indexed":false}],"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":"UpdatedImpl","inputs":[{"type":"address","name":"impl","internalType":"address","indexed":true}],"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":"DEFAULT_ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addMember","inputs":[{"type":"address","name":"member","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"changePoolDetails","inputs":[{"type":"address","name":"_pool","internalType":"contract DirectPaymentsPool"},{"type":"string","name":"_ipfs","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":"pool","internalType":"contract DirectPaymentsPool"}],"name":"createBeaconPool","inputs":[{"type":"string","name":"_projectId","internalType":"string"},{"type":"string","name":"_ipfs","internalType":"string"},{"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":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":"pool","internalType":"contract DirectPaymentsPool"}],"name":"createPool","inputs":[{"type":"string","name":"_projectId","internalType":"string"},{"type":"string","name":"_ipfs","internalType":"string"},{"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":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"feeBps","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feeRecipient","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRoleAdmin","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"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 UpgradeableBeacon"}],"name":"impl","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"address","name":"_dpimpl","internalType":"address"},{"type":"address","name":"_nft","internalType":"contract ProvableNFT"},{"type":"address","name":"_feeRecipient","internalType":"address"},{"type":"uint32","name":"_feeBps","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"memberPools","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"nextNftType","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ProvableNFT"}],"name":"nft","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"pools","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract DirectPaymentsPool"}],"name":"projectIdToControlPool","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"proxiableUUID","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"ipfs","internalType":"string"},{"type":"bool","name":"isVerified","internalType":"bool"},{"type":"string","name":"projectId","internalType":"string"}],"name":"registry","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeMember","inputs":[{"type":"address","name":"member","internalType":"address"}]},{"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":"setFeeInfo","inputs":[{"type":"address","name":"_feeRecipient","internalType":"address"},{"type":"uint32","name":"_feeBps","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setVerified","inputs":[{"type":"address","name":"_pool","internalType":"contract DirectPaymentsPool"},{"type":"bool","name":"_isVerified","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateImpl","inputs":[{"type":"address","name":"_impl","internalType":"address"}]},{"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"}]}]
Contract Creation Code
0x60a06040523060805234801561001457600080fd5b50608051613eae61004c600039600081816109b6015281816109f901528181610a8a01528181610acd0152610cb70152613eae6000f3fe608060405260043610620001645760003560e01c806301ffc9a71462000169578063038defd714620001a35780630b1ca49a14620001d9578063248a9ca3146200020057806324a9d85314620002345780632f2ff15d146200027057806336568abe14620002955780633659cfe614620002ba5780634690484014620002df57806347ccca0214620003105780634f1ef28614620003325780634f962c8c146200034957806352d1902d146200036e57806357b707671462000386578063592f7b0514620003ab57806376967ae014620003d15780638abf607714620003f657806391d1485414620004185780639cedd89b146200043d5780639cf5c6131462000477578063a217fddf146200049c578063ac4afa3814620004b3578063ae6ec80114620004d8578063ca6d56dc14620004fd578063d547741f1462000522578063e9e50b041462000547578063f8a2334c146200056c578063fcf1e0091462000591575b600080fd5b3480156200017657600080fd5b506200018e620001883660046200206d565b620005b6565b60405190151581526020015b60405180910390f35b348015620001b057600080fd5b50620001c8620001c2366004620020c1565b620005ee565b6040516200019a9392919062002135565b348015620001e657600080fd5b50620001fe620001f8366004620020c1565b62000739565b005b3480156200020d57600080fd5b50620002256200021f36600462002170565b620008ee565b6040519081526020016200019a565b3480156200024157600080fd5b5060ff546200025a90600160a01b900463ffffffff1681565b60405163ffffffff90911681526020016200019a565b3480156200027d57600080fd5b50620001fe6200028f3660046200218a565b62000903565b348015620002a257600080fd5b50620001fe620002b43660046200218a565b6200092a565b348015620002c757600080fd5b50620001fe620002d9366004620020c1565b620009ac565b348015620002ec57600080fd5b5060ff5462000301906001600160a01b031681565b6040516200019a9190620021ca565b3480156200031d57600080fd5b5060fc5462000301906001600160a01b031681565b620001fe62000343366004620022b0565b62000a80565b3480156200035657600080fd5b50620001fe620003683660046200233d565b62000b41565b3480156200037b57600080fd5b506200022562000caa565b3480156200039357600080fd5b5062000301620003a536600462002388565b62000d5b565b348015620003b857600080fd5b5060fc546200025a90600160a01b900463ffffffff1681565b348015620003de57600080fd5b5062000301620003f03660046200256b565b62000d95565b3480156200040357600080fd5b5060fb5462000301906001600160a01b031681565b3480156200042557600080fd5b506200018e620004373660046200218a565b62000ed9565b3480156200044a57600080fd5b50620003016200045c36600462002170565b60fe602052600090815260409020546001600160a01b031681565b3480156200048457600080fd5b50620001fe62000496366004620026f1565b62000f04565b348015620004a957600080fd5b5062000225600081565b348015620004c057600080fd5b5062000301620004d236600462002170565b62000f6d565b348015620004e557600080fd5b5062000301620004f73660046200256b565b62000f99565b3480156200050a57600080fd5b50620001fe6200051c366004620020c1565b620010d1565b3480156200052f57600080fd5b50620001fe620005413660046200218a565b6200114d565b3480156200055457600080fd5b50620001fe6200056636600462002724565b6200116f565b3480156200057957600080fd5b50620001fe6200058b3660046200275e565b620011bc565b3480156200059e57600080fd5b50620001fe620005b0366004620020c1565b6200138a565b60006001600160e01b03198216637965db0b60e01b1480620005e857506301ffc9a760e01b6001600160e01b03198316145b92915050565b60fd602052600090815260409020805481906200060b90620027ca565b80601f01602080910402602001604051908101604052809291908181526020018280546200063990620027ca565b80156200068a5780601f106200065e576101008083540402835291602001916200068a565b820191906000526020600020905b8154815290600101906020018083116200066c57829003601f168201915b5050506001840154600285018054949560ff909216949193509150620006b090620027ca565b80601f0160208091040260200160405190810160405280929190818152602001828054620006de90620027ca565b80156200072f5780601f1062000703576101008083540402835291602001916200072f565b820191906000526020600020905b8154815290600101906020018083116200071157829003601f168201915b5050505050905083565b33600090815260fd6020526040902060020180546200075890620027ca565b90506000036200077b57604051630cc15fbb60e11b815260040160405180910390fd5b60005b6001600160a01b03821660009081526101006020526040902054811015620008ea576001600160a01b038216600090815261010060205260409020805433919083908110620007d157620007d162002806565b6000918252602090912001546001600160a01b031603620008d5576001600160a01b0382166000908152610100602052604090208054620008159060019062002832565b8154811062000828576200082862002806565b60009182526020808320909101546001600160a01b038581168452610100909252604090922080549190921691908390811062000869576200086962002806565b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918416815261010090915260409020805480620008b257620008b262002848565b600082815260209020810160001990810180546001600160a01b03191690550190555b80620008e1816200285e565b9150506200077e565b5050565b60009081526065602052604090206001015490565b6200090e82620008ee565b620009198162001435565b62000925838362001441565b505050565b6001600160a01b0381163314620009a05760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b620008ea8282620014cb565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003620009f75760405162461bcd60e51b815260040162000997906200287a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031662000a2b62001535565b6001600160a01b03161462000a545760405162461bcd60e51b81526004016200099790620028b5565b62000a5f8162001552565b6040805160008082526020820190925262000a7d918391906200155f565b50565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300362000acb5760405162461bcd60e51b815260040162000997906200287a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031662000aff62001535565b6001600160a01b03161462000b285760405162461bcd60e51b81526004016200099790620028b5565b62000b338262001552565b620008ea828260016200155f565b81806001600160a01b03166391d14854826001600160a01b031663a217fddf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000b90573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000bb69190620028f0565b336040518363ffffffff1660e01b815260040162000bd69291906200290a565b602060405180830381865afa15801562000bf4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c1a919062002921565b151560000362000c3d57604051631d799a6d60e21b815260040160405180910390fd5b6001600160a01b038316600090815260fd6020526040902062000c6183826200298b565b50826001600160a01b03167f941ad6ac0538b96f9e89b9b52ec11031b50591baa2f16c0cdf1f94c69f389d6d8360405162000c9d919062002a57565b60405180910390a2505050565b6000306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161462000d475760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b606482015260840162000997565b5060008051602062003e3283398151915290565b610100602052816000526040600020818154811062000d7957600080fd5b6000918252602090912001546001600160a01b03169150829050565b8451602080870191909120600090815260fe909152604081205486906001600160a01b0316801562000ebc57806001600160a01b03166391d14854826001600160a01b031663a217fddf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000e0f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000e359190620028f0565b336040518363ffffffff1660e01b815260040162000e559291906200290a565b602060405180830381865afa15801562000e73573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000e99919062002921565b151560000362000ebc57604051631d799a6d60e21b815260040160405180910390fd5b62000ecd88888888886000620016d7565b98975050505050505050565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b600062000f118162001435565b6001600160a01b038316600081815260fd6020908152604091829020600101805460ff191686151590811790915591519182527fafdc942e2e075abc791516f168aed9293862095eb31c0dab19c8d0d061018a93910162000c9d565b610101818154811062000f7f57600080fd5b6000918252602090912001546001600160a01b0316905081565b8451602080870191909120600090815260fe909152604081205486906001600160a01b03168015620010c057806001600160a01b03166391d14854826001600160a01b031663a217fddf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001013573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620010399190620028f0565b336040518363ffffffff1660e01b8152600401620010599291906200290a565b602060405180830381865afa15801562001077573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200109d919062002921565b1515600003620010c057604051631d799a6d60e21b815260040160405180910390fd5b62000ecd88888888886001620016d7565b33600090815260fd602052604090206002018054620010f090620027ca565b90506000036200111357604051630cc15fbb60e11b815260040160405180910390fd5b6001600160a01b03166000908152610100602090815260408220805460018101825590835291200180546001600160a01b03191633179055565b6200115882620008ee565b620011638162001435565b620009258383620014cb565b60006200117c8162001435565b5060ff80546001600160a01b039093166001600160a01b031963ffffffff909316600160a01b02929092166001600160c01b031990931692909217179055565b600054610100900460ff1615808015620011dd5750600054600160ff909116105b80620012025750620011ef3062001b9e565b15801562001202575060005460ff166001145b620012675760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840162000997565b6000805460ff1916600117905580156200128b576000805461ff0019166101001790555b60fc805463ffffffff60a01b1916600160a01b1790556040518590620012b19062002043565b620012bd9190620021ca565b604051809103906000f080158015620012da573d6000803e3d6000fd5b5060fb80546001600160a01b03199081166001600160a01b039384161790915560fc805490911686831617905560ff80549185166001600160c01b031990921691909117600160a01b63ffffffff8516021790556200133b60008762001bad565b801562001382576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6000620013978162001435565b60fb54604051631b2ce7f360e11b81526001600160a01b0390911690633659cfe690620013c9908590600401620021ca565b600060405180830381600087803b158015620013e457600080fd5b505af1158015620013f9573d6000803e3d6000fd5b50506040516001600160a01b03851692507f71ce7583e9b7e543de8a69a6af369c0b3528b287064f9dce26a38025e36dc2c79150600090a25050565b62000a7d813362001bb9565b6200144d828262000ed9565b620008ea5760008281526065602090815260408083206001600160a01b03851684529091529020805460ff19166001179055620014873390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b620014d7828262000ed9565b15620008ea5760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60008051602062003e32833981519152546001600160a01b031690565b6000620008ea8162001435565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156200159557620009258362001c1d565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015620015f2575060408051601f3d908101601f19168201909252620015ef91810190620028f0565b60015b620016575760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840162000997565b60008051602062003e328339815191528114620016c95760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840162000997565b506200092583838362001cbc565b60fc5463ffffffff600160a01b8204168552604051600091829162001711916001600160a01b031690889088908890309060240162002bb1565b60408051601f198184030181529190526020810180516001600160e01b0316634b1e337f60e01b17905290508215620017965760fb546040516001600160a01b03909116908290620017639062002051565b6200177092919062002c05565b604051809103906000f0801580156200178d573d6000803e3d6000fd5b5091506200184d565b60fb60009054906101000a90046001600160a01b03166001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620017ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001810919062002c33565b816040516200181f906200205f565b6200182c92919062002c05565b604051809103906000f08015801562001849573d6000803e3d6000fd5b5091505b60fc54604051634e93f47b60e01b815263ffffffff600160a01b83041660048201526001600160a01b0390911690632f2ff15d908290634e93f47b90602401602060405180830381865afa158015620018aa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620018d09190620028f0565b846040518363ffffffff1660e01b8152600401620018f09291906200290a565b600060405180830381600087803b1580156200190b57600080fd5b505af115801562001920573d6000803e3d6000fd5b505089516020808c0191909120600090815260fe90915260409020546001600160a01b031691506200198190505787516020808a0191909120600090815260fe9091526040902080546001600160a01b0319166001600160a01b0384161790555b6001600160a01b038216600090815260fd60205260409020620019a588826200298b565b506001600160a01b038216600090815260fd60205260409020600201620019cd89826200298b565b50604051632f2ff15d60e01b81526001600160a01b03831690632f2ff15d90620019ff9060009033906004016200290a565b600060405180830381600087803b15801562001a1a57600080fd5b505af115801562001a2f573d6000803e3d6000fd5b5050604051631b2b455f60e11b81526001600160a01b03851692506336568abe915062001a649060009030906004016200290a565b600060405180830381600087803b15801562001a7f57600080fd5b505af115801562001a94573d6000803e3d6000fd5b505061010180546001810182556000919091527f109ea3cebb188b9c1b9fc5bb3920be60dfdc8699098dff92f3d80daaca7476890180546001600160a01b0319166001600160a01b038616179055505060fc54604051600160a01b90910463ffffffff169062001b06908a9062002c53565b6040518091039020836001600160a01b03167fabf24e13dd04b5233e0ccecc88963e42e9d8b5ceae25458b61109fcbc0201bfe8a8a8a60405162001b4d9392919062002c71565b60405180910390a460fc8054600160a01b900463ffffffff1690601462001b748362002cac565b91906101000a81548163ffffffff021916908363ffffffff16021790555050509695505050505050565b6001600160a01b03163b151590565b620008ea828262001441565b62001bc5828262000ed9565b620008ea5762001bd58162001ced565b62001be283602062001d00565b60405160200162001bf592919062002cd2565b60408051601f198184030181529082905262461bcd60e51b8252620009979160040162002a57565b62001c288162001b9e565b62001c8c5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840162000997565b60008051602062003e3283398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b62001cc78362001ec0565b60008251118062001cd55750805b15620009255762001ce7838362001f02565b50505050565b6060620005e86001600160a01b03831660145b6060600062001d1183600262002d45565b62001d1e90600262002d5f565b6001600160401b0381111562001d385762001d38620021de565b6040519080825280601f01601f19166020018201604052801562001d63576020820181803683370190505b509050600360fc1b8160008151811062001d815762001d8162002806565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811062001db35762001db362002806565b60200101906001600160f81b031916908160001a905350600062001dd984600262002d45565b62001de690600162002d5f565b90505b600181111562001e68576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811062001e1e5762001e1e62002806565b1a60f81b82828151811062001e375762001e3762002806565b60200101906001600160f81b031916908160001a90535060049490941c9362001e608162002d75565b905062001de9565b50831562001eb95760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640162000997565b9392505050565b62001ecb8162001c1d565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606062001f0f8362001b9e565b62001f6c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840162000997565b600080846001600160a01b03168460405162001f89919062002c53565b600060405180830381855af49150503d806000811462001fc6576040519150601f19603f3d011682016040523d82523d6000602084013e62001fcb565b606091505b509150915062001ff6828260405180606001604052806027815260200162003e526027913962001fff565b95945050505050565b606083156200201057508162001eb9565b62001eb98383815115620020275781518083602001fd5b8060405162461bcd60e51b815260040162000997919062002a57565b6104c98062002d9083390190565b6106cd806200325983390190565b6104ec806200392683390190565b6000602082840312156200208057600080fd5b81356001600160e01b03198116811462001eb957600080fd5b6001600160a01b038116811462000a7d57600080fd5b8035620020bc8162002099565b919050565b600060208284031215620020d457600080fd5b813562001eb98162002099565b60005b83811015620020fe578181015183820152602001620020e4565b50506000910152565b6000815180845262002121816020860160208601620020e1565b601f01601f19169290920160200192915050565b6060815260006200214a606083018662002107565b8415156020840152828103604084015262002166818562002107565b9695505050505050565b6000602082840312156200218357600080fd5b5035919050565b600080604083850312156200219e57600080fd5b823591506020830135620021b28162002099565b809150509250929050565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b03811182821017156200221a576200221a620021de565b60405290565b604051601f8201601f191681016001600160401b03811182821017156200224b576200224b620021de565b604052919050565b60006001600160401b038311156200226f576200226f620021de565b62002284601f8401601f191660200162002220565b90508281528383830111156200229957600080fd5b828260208301376000602084830101529392505050565b60008060408385031215620022c457600080fd5b8235620022d18162002099565b915060208301356001600160401b03811115620022ed57600080fd5b8301601f81018513620022ff57600080fd5b620023108582356020840162002253565b9150509250929050565b600082601f8301126200232c57600080fd5b62001eb98383356020850162002253565b600080604083850312156200235157600080fd5b82356200235e8162002099565b915060208301356001600160401b038111156200237a57600080fd5b62002310858286016200231a565b600080604083850312156200239c57600080fd5b8235620023a98162002099565b946020939093013593505050565b803563ffffffff81168114620020bc57600080fd5b60006001600160401b03821115620023e857620023e8620021de565b5060051b60200190565b600082601f8301126200240457600080fd5b813560206200241d6200241783620023cc565b62002220565b82815260059290921b840181019181810190868411156200243d57600080fd5b8286015b848110156200246c57803561ffff811681146200245e5760008081fd5b835291830191830162002441565b509695505050505050565b600082601f8301126200248957600080fd5b813560206200249c6200241783620023cc565b82815260059290921b84018101918181019086841115620024bc57600080fd5b8286015b848110156200246c5780356001600160801b0381168114620024e25760008081fd5b8352918301918301620024c0565b801515811462000a7d57600080fd5b8035620020bc81620024f0565b6000606082840312156200251f57600080fd5b604051606081016001600160401b0381118282101715620025445762002544620021de565b80604052508091508235815260208301356020820152604083013560408201525092915050565b600080600080600060e086880312156200258457600080fd5b85356001600160401b03808211156200259c57600080fd5b620025aa89838a016200231a565b96506020880135915080821115620025c157600080fd5b620025cf89838a016200231a565b95506040880135915080821115620025e657600080fd5b90870190610100828a031215620025fc57600080fd5b62002606620021f4565b6200261183620023b7565b81526020830135828111156200262657600080fd5b620026348b828601620023f2565b6020830152506040830135828111156200264d57600080fd5b6200265b8b82860162002477565b6040830152506200266f60608401620020af565b60608201526200268260808401620020af565b60808201526200269560a08401620020af565b60a0820152620026a860c08401620020af565b60c0820152620026bb60e08401620024ff565b60e0820152809550505050620026d587606088016200250c565b9150620026e560c08701620023b7565b90509295509295909350565b600080604083850312156200270557600080fd5b8235620027128162002099565b91506020830135620021b281620024f0565b600080604083850312156200273857600080fd5b8235620027458162002099565b91506200275560208401620023b7565b90509250929050565b600080600080600060a086880312156200277757600080fd5b8535620027848162002099565b94506020860135620027968162002099565b93506040860135620027a88162002099565b92506060860135620027ba8162002099565b9150620026e560808701620023b7565b600181811c90821680620027df57607f821691505b6020821081036200280057634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115620005e857620005e86200281c565b634e487b7160e01b600052603160045260246000fd5b6000600182016200287357620028736200281c565b5060010190565b6020808252602c9082015260008051602062003e1283398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c9082015260008051602062003e1283398151915260408201526b6163746976652070726f787960a01b606082015260800190565b6000602082840312156200290357600080fd5b5051919050565b9182526001600160a01b0316602082015260400190565b6000602082840312156200293457600080fd5b815162001eb981620024f0565b601f8211156200092557600081815260208120601f850160051c810160208610156200296a5750805b601f850160051c820191505b81811015620013825782815560010162002976565b81516001600160401b03811115620029a757620029a7620021de565b620029bf81620029b88454620027ca565b8462002941565b602080601f831160018114620029f75760008415620029de5750858301515b600019600386901b1c1916600185901b17855562001382565b600085815260208120601f198616915b8281101562002a285788860151825594840194600190910190840162002a07565b508582101562002a475787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60208152600062001eb9602083018462002107565b600081518084526020808501945080840160005b8381101562002aa75781516001600160801b03168752958201959082019060010162002a80565b509495945050505050565b805163ffffffff168252602080820151610100828501819052815190850181905260009261012086019281019184905b8082101562002b0857835161ffff16855293820193928201926001919091019062002ae2565b505050506040830151848203604086015262002b25828262002a6c565b915050606083015162002b3c6060860182620021bd565b50608083015162002b516080860182620021bd565b5060a083015162002b6660a0860182620021bd565b5060c083015162002b7b60c0860182620021bd565b5060e083015162002b9060e086018215159052565b509392505050565b8051825260208082015190830152604090810151910152565b600060018060a01b03808816835260e0602084015262002bd560e084018862002ab2565b915062002be6604084018762002b98565b63ffffffff851660a084015280841660c0840152509695505050505050565b6001600160a01b038316815260406020820181905260009062002c2b9083018462002107565b949350505050565b60006020828403121562002c4657600080fd5b815162001eb98162002099565b6000825162002c67818460208701620020e1565b9190910192915050565b60a08152600062002c8660a083018662002107565b828103602084015262002c9a818662002ab2565b91505062002c2b604083018462002b98565b600063ffffffff80831681810362002cc85762002cc86200281c565b6001019392505050565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b81526000835162002d06816017850160208801620020e1565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835162002d39816028840160208801620020e1565b01602801949350505050565b8082028115828204841417620005e857620005e86200281c565b80820180821115620005e857620005e86200281c565b60008162002d875762002d876200281c565b50600019019056fe608060405234801561001057600080fd5b506040516104c93803806104c983398101604081905261002f9161013a565b61003833610047565b61004181610097565b5061016a565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0381163b6101185760405162461bcd60e51b815260206004820152603360248201527f5570677261646561626c65426561636f6e3a20696d706c656d656e746174696f60448201527f6e206973206e6f74206120636f6e747261637400000000000000000000000000606482015260840160405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006020828403121561014c57600080fd5b81516001600160a01b038116811461016357600080fd5b9392505050565b610350806101796000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80633659cfe61461005c5780635c60da1b14610071578063715018a61461009a5780638da5cb5b146100a2578063f2fde38b146100aa575b600080fd5b61006f61006a3660046102ea565b6100bd565b005b6001546001600160a01b03165b6040516001600160a01b03909116815260200160405180910390f35b61006f610105565b61007e610119565b61006f6100b83660046102ea565b610128565b6100c56101a6565b6100ce81610205565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b61010d6101a6565b610117600061029a565b565b6000546001600160a01b031690565b6101306101a6565b6001600160a01b03811661019a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b6101a38161029a565b50565b336101af610119565b6001600160a01b0316146101175760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610191565b6001600160a01b0381163b6102785760405162461bcd60e51b815260206004820152603360248201527f5570677261646561626c65426561636f6e3a20696d706c656d656e746174696f6044820152721b881a5cc81b9bdd08184818dbdb9d1c9858dd606a1b6064820152608401610191565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156102fc57600080fd5b81356001600160a01b038116811461031357600080fd5b939250505056fea264697066735822122038970e7cf09dc887c70d5260fa612ed542a4b7fc825586d54bcad83fc1ebdd9164736f6c6343000813003360806040526040516106cd3803806106cd83398101604081905261002291610421565b61002e82826000610035565b505061054b565b61003e836100f6565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100f1576100ef836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e991906104e1565b8361026e565b505b505050565b6100ff8161029a565b61015e5760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101c8816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561019f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101c391906104e1565b61029a565b61022d5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610155565b7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392909216919091179055565b606061029383836040518060600160405280602781526020016106a6602791396102a9565b9392505050565b6001600160a01b03163b151590565b6060600080856001600160a01b0316856040516102c691906104fc565b600060405180830381855af49150503d8060008114610301576040519150601f19603f3d011682016040523d82523d6000602084013e610306565b606091505b50909250905061031886838387610322565b9695505050505050565b6060831561038f5782516000036103885761033c8561029a565b6103885760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610155565b5081610399565b61039983836103a1565b949350505050565b8151156103b15781518083602001fd5b8060405162461bcd60e51b81526004016101559190610518565b80516001600160a01b03811681146103e257600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610418578181015183820152602001610400565b50506000910152565b6000806040838503121561043457600080fd5b61043d836103cb565b60208401519092506001600160401b038082111561045a57600080fd5b818501915085601f83011261046e57600080fd5b815181811115610480576104806103e7565b604051601f8201601f19908116603f011681019083821181831017156104a8576104a86103e7565b816040528281528860208487010111156104c157600080fd5b6104d28360208301602088016103fd565b80955050505050509250929050565b6000602082840312156104f357600080fd5b610293826103cb565b6000825161050e8184602087016103fd565b9190910192915050565b60208152600082518060208401526105378160408501602087016103fd565b601f01601f19169190910160400192915050565b61014c8061055a6000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610029565b6100c2565b565b600061005c7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610099573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100bd91906100e6565b905090565b3660008037600080366000845af43d6000803e8080156100e1573d6000f35b3d6000fd5b6000602082840312156100f857600080fd5b81516001600160a01b038116811461010f57600080fd5b939250505056fea26469706673582212207b4f4f4bd905b812712d76801c617b8aa3f4c3f8d6d9e59a18563606189dd4e564736f6c63430008130033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656460806040526040516104ec3803806104ec833981016040819052610022916102e9565b61002e82826000610035565b5050610406565b61003e83610061565b60008251118061004b5750805b1561005c5761005a83836100a1565b505b505050565b61006a816100cd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606100c683836040518060600160405280602781526020016104c56027913961017e565b9392505050565b6100d6816101f7565b61013d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080856001600160a01b03168560405161019b91906103b7565b600060405180830381855af49150503d80600081146101d6576040519150601f19603f3d011682016040523d82523d6000602084013e6101db565b606091505b5090925090506101ed86838387610206565b9695505050505050565b6001600160a01b03163b151590565b6060831561027357825160000361026c57610220856101f7565b61026c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610134565b508161027d565b61027d8383610285565b949350505050565b8151156102955781518083602001fd5b8060405162461bcd60e51b815260040161013491906103d3565b634e487b7160e01b600052604160045260246000fd5b60005b838110156102e05781810151838201526020016102c8565b50506000910152565b600080604083850312156102fc57600080fd5b82516001600160a01b038116811461031357600080fd5b60208401519092506001600160401b038082111561033057600080fd5b818501915085601f83011261034457600080fd5b815181811115610356576103566102af565b604051601f8201601f19908116603f0116810190838211818310171561037e5761037e6102af565b8160405282815288602084870101111561039757600080fd5b6103a88360208301602088016102c5565b80955050505050509250929050565b600082516103c98184602087016102c5565b9190910192915050565b60208152600082518060208401526103f28160408501602087016102c5565b601f01601f19169190910160400192915050565b60b1806104146000396000f3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea2646970667358221220a4cda07e5b291f61d81b4ee016ef5ca6a806aa56384b08ff8d52828dbed4d68d64736f6c63430008130033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656446756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122044f5c400a13c9fd8ca4b2b561a2460b2351e0706773dd9516462a1e1f772b88e64736f6c63430008130033
Deployed ByteCode
0x608060405260043610620001645760003560e01c806301ffc9a71462000169578063038defd714620001a35780630b1ca49a14620001d9578063248a9ca3146200020057806324a9d85314620002345780632f2ff15d146200027057806336568abe14620002955780633659cfe614620002ba5780634690484014620002df57806347ccca0214620003105780634f1ef28614620003325780634f962c8c146200034957806352d1902d146200036e57806357b707671462000386578063592f7b0514620003ab57806376967ae014620003d15780638abf607714620003f657806391d1485414620004185780639cedd89b146200043d5780639cf5c6131462000477578063a217fddf146200049c578063ac4afa3814620004b3578063ae6ec80114620004d8578063ca6d56dc14620004fd578063d547741f1462000522578063e9e50b041462000547578063f8a2334c146200056c578063fcf1e0091462000591575b600080fd5b3480156200017657600080fd5b506200018e620001883660046200206d565b620005b6565b60405190151581526020015b60405180910390f35b348015620001b057600080fd5b50620001c8620001c2366004620020c1565b620005ee565b6040516200019a9392919062002135565b348015620001e657600080fd5b50620001fe620001f8366004620020c1565b62000739565b005b3480156200020d57600080fd5b50620002256200021f36600462002170565b620008ee565b6040519081526020016200019a565b3480156200024157600080fd5b5060ff546200025a90600160a01b900463ffffffff1681565b60405163ffffffff90911681526020016200019a565b3480156200027d57600080fd5b50620001fe6200028f3660046200218a565b62000903565b348015620002a257600080fd5b50620001fe620002b43660046200218a565b6200092a565b348015620002c757600080fd5b50620001fe620002d9366004620020c1565b620009ac565b348015620002ec57600080fd5b5060ff5462000301906001600160a01b031681565b6040516200019a9190620021ca565b3480156200031d57600080fd5b5060fc5462000301906001600160a01b031681565b620001fe62000343366004620022b0565b62000a80565b3480156200035657600080fd5b50620001fe620003683660046200233d565b62000b41565b3480156200037b57600080fd5b506200022562000caa565b3480156200039357600080fd5b5062000301620003a536600462002388565b62000d5b565b348015620003b857600080fd5b5060fc546200025a90600160a01b900463ffffffff1681565b348015620003de57600080fd5b5062000301620003f03660046200256b565b62000d95565b3480156200040357600080fd5b5060fb5462000301906001600160a01b031681565b3480156200042557600080fd5b506200018e620004373660046200218a565b62000ed9565b3480156200044a57600080fd5b50620003016200045c36600462002170565b60fe602052600090815260409020546001600160a01b031681565b3480156200048457600080fd5b50620001fe62000496366004620026f1565b62000f04565b348015620004a957600080fd5b5062000225600081565b348015620004c057600080fd5b5062000301620004d236600462002170565b62000f6d565b348015620004e557600080fd5b5062000301620004f73660046200256b565b62000f99565b3480156200050a57600080fd5b50620001fe6200051c366004620020c1565b620010d1565b3480156200052f57600080fd5b50620001fe620005413660046200218a565b6200114d565b3480156200055457600080fd5b50620001fe6200056636600462002724565b6200116f565b3480156200057957600080fd5b50620001fe6200058b3660046200275e565b620011bc565b3480156200059e57600080fd5b50620001fe620005b0366004620020c1565b6200138a565b60006001600160e01b03198216637965db0b60e01b1480620005e857506301ffc9a760e01b6001600160e01b03198316145b92915050565b60fd602052600090815260409020805481906200060b90620027ca565b80601f01602080910402602001604051908101604052809291908181526020018280546200063990620027ca565b80156200068a5780601f106200065e576101008083540402835291602001916200068a565b820191906000526020600020905b8154815290600101906020018083116200066c57829003601f168201915b5050506001840154600285018054949560ff909216949193509150620006b090620027ca565b80601f0160208091040260200160405190810160405280929190818152602001828054620006de90620027ca565b80156200072f5780601f1062000703576101008083540402835291602001916200072f565b820191906000526020600020905b8154815290600101906020018083116200071157829003601f168201915b5050505050905083565b33600090815260fd6020526040902060020180546200075890620027ca565b90506000036200077b57604051630cc15fbb60e11b815260040160405180910390fd5b60005b6001600160a01b03821660009081526101006020526040902054811015620008ea576001600160a01b038216600090815261010060205260409020805433919083908110620007d157620007d162002806565b6000918252602090912001546001600160a01b031603620008d5576001600160a01b0382166000908152610100602052604090208054620008159060019062002832565b8154811062000828576200082862002806565b60009182526020808320909101546001600160a01b038581168452610100909252604090922080549190921691908390811062000869576200086962002806565b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918416815261010090915260409020805480620008b257620008b262002848565b600082815260209020810160001990810180546001600160a01b03191690550190555b80620008e1816200285e565b9150506200077e565b5050565b60009081526065602052604090206001015490565b6200090e82620008ee565b620009198162001435565b62000925838362001441565b505050565b6001600160a01b0381163314620009a05760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b620008ea8282620014cb565b6001600160a01b037f000000000000000000000000c64ed8278b73cc3a623fffa50ad5f622c3775a5d163003620009f75760405162461bcd60e51b815260040162000997906200287a565b7f000000000000000000000000c64ed8278b73cc3a623fffa50ad5f622c3775a5d6001600160a01b031662000a2b62001535565b6001600160a01b03161462000a545760405162461bcd60e51b81526004016200099790620028b5565b62000a5f8162001552565b6040805160008082526020820190925262000a7d918391906200155f565b50565b6001600160a01b037f000000000000000000000000c64ed8278b73cc3a623fffa50ad5f622c3775a5d16300362000acb5760405162461bcd60e51b815260040162000997906200287a565b7f000000000000000000000000c64ed8278b73cc3a623fffa50ad5f622c3775a5d6001600160a01b031662000aff62001535565b6001600160a01b03161462000b285760405162461bcd60e51b81526004016200099790620028b5565b62000b338262001552565b620008ea828260016200155f565b81806001600160a01b03166391d14854826001600160a01b031663a217fddf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000b90573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000bb69190620028f0565b336040518363ffffffff1660e01b815260040162000bd69291906200290a565b602060405180830381865afa15801562000bf4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c1a919062002921565b151560000362000c3d57604051631d799a6d60e21b815260040160405180910390fd5b6001600160a01b038316600090815260fd6020526040902062000c6183826200298b565b50826001600160a01b03167f941ad6ac0538b96f9e89b9b52ec11031b50591baa2f16c0cdf1f94c69f389d6d8360405162000c9d919062002a57565b60405180910390a2505050565b6000306001600160a01b037f000000000000000000000000c64ed8278b73cc3a623fffa50ad5f622c3775a5d161462000d475760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b606482015260840162000997565b5060008051602062003e3283398151915290565b610100602052816000526040600020818154811062000d7957600080fd5b6000918252602090912001546001600160a01b03169150829050565b8451602080870191909120600090815260fe909152604081205486906001600160a01b0316801562000ebc57806001600160a01b03166391d14854826001600160a01b031663a217fddf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000e0f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000e359190620028f0565b336040518363ffffffff1660e01b815260040162000e559291906200290a565b602060405180830381865afa15801562000e73573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000e99919062002921565b151560000362000ebc57604051631d799a6d60e21b815260040160405180910390fd5b62000ecd88888888886000620016d7565b98975050505050505050565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b600062000f118162001435565b6001600160a01b038316600081815260fd6020908152604091829020600101805460ff191686151590811790915591519182527fafdc942e2e075abc791516f168aed9293862095eb31c0dab19c8d0d061018a93910162000c9d565b610101818154811062000f7f57600080fd5b6000918252602090912001546001600160a01b0316905081565b8451602080870191909120600090815260fe909152604081205486906001600160a01b03168015620010c057806001600160a01b03166391d14854826001600160a01b031663a217fddf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001013573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620010399190620028f0565b336040518363ffffffff1660e01b8152600401620010599291906200290a565b602060405180830381865afa15801562001077573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200109d919062002921565b1515600003620010c057604051631d799a6d60e21b815260040160405180910390fd5b62000ecd88888888886001620016d7565b33600090815260fd602052604090206002018054620010f090620027ca565b90506000036200111357604051630cc15fbb60e11b815260040160405180910390fd5b6001600160a01b03166000908152610100602090815260408220805460018101825590835291200180546001600160a01b03191633179055565b6200115882620008ee565b620011638162001435565b620009258383620014cb565b60006200117c8162001435565b5060ff80546001600160a01b039093166001600160a01b031963ffffffff909316600160a01b02929092166001600160c01b031990931692909217179055565b600054610100900460ff1615808015620011dd5750600054600160ff909116105b80620012025750620011ef3062001b9e565b15801562001202575060005460ff166001145b620012675760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840162000997565b6000805460ff1916600117905580156200128b576000805461ff0019166101001790555b60fc805463ffffffff60a01b1916600160a01b1790556040518590620012b19062002043565b620012bd9190620021ca565b604051809103906000f080158015620012da573d6000803e3d6000fd5b5060fb80546001600160a01b03199081166001600160a01b039384161790915560fc805490911686831617905560ff80549185166001600160c01b031990921691909117600160a01b63ffffffff8516021790556200133b60008762001bad565b801562001382576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6000620013978162001435565b60fb54604051631b2ce7f360e11b81526001600160a01b0390911690633659cfe690620013c9908590600401620021ca565b600060405180830381600087803b158015620013e457600080fd5b505af1158015620013f9573d6000803e3d6000fd5b50506040516001600160a01b03851692507f71ce7583e9b7e543de8a69a6af369c0b3528b287064f9dce26a38025e36dc2c79150600090a25050565b62000a7d813362001bb9565b6200144d828262000ed9565b620008ea5760008281526065602090815260408083206001600160a01b03851684529091529020805460ff19166001179055620014873390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b620014d7828262000ed9565b15620008ea5760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60008051602062003e32833981519152546001600160a01b031690565b6000620008ea8162001435565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156200159557620009258362001c1d565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015620015f2575060408051601f3d908101601f19168201909252620015ef91810190620028f0565b60015b620016575760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840162000997565b60008051602062003e328339815191528114620016c95760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840162000997565b506200092583838362001cbc565b60fc5463ffffffff600160a01b8204168552604051600091829162001711916001600160a01b031690889088908890309060240162002bb1565b60408051601f198184030181529190526020810180516001600160e01b0316634b1e337f60e01b17905290508215620017965760fb546040516001600160a01b03909116908290620017639062002051565b6200177092919062002c05565b604051809103906000f0801580156200178d573d6000803e3d6000fd5b5091506200184d565b60fb60009054906101000a90046001600160a01b03166001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620017ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001810919062002c33565b816040516200181f906200205f565b6200182c92919062002c05565b604051809103906000f08015801562001849573d6000803e3d6000fd5b5091505b60fc54604051634e93f47b60e01b815263ffffffff600160a01b83041660048201526001600160a01b0390911690632f2ff15d908290634e93f47b90602401602060405180830381865afa158015620018aa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620018d09190620028f0565b846040518363ffffffff1660e01b8152600401620018f09291906200290a565b600060405180830381600087803b1580156200190b57600080fd5b505af115801562001920573d6000803e3d6000fd5b505089516020808c0191909120600090815260fe90915260409020546001600160a01b031691506200198190505787516020808a0191909120600090815260fe9091526040902080546001600160a01b0319166001600160a01b0384161790555b6001600160a01b038216600090815260fd60205260409020620019a588826200298b565b506001600160a01b038216600090815260fd60205260409020600201620019cd89826200298b565b50604051632f2ff15d60e01b81526001600160a01b03831690632f2ff15d90620019ff9060009033906004016200290a565b600060405180830381600087803b15801562001a1a57600080fd5b505af115801562001a2f573d6000803e3d6000fd5b5050604051631b2b455f60e11b81526001600160a01b03851692506336568abe915062001a649060009030906004016200290a565b600060405180830381600087803b15801562001a7f57600080fd5b505af115801562001a94573d6000803e3d6000fd5b505061010180546001810182556000919091527f109ea3cebb188b9c1b9fc5bb3920be60dfdc8699098dff92f3d80daaca7476890180546001600160a01b0319166001600160a01b038616179055505060fc54604051600160a01b90910463ffffffff169062001b06908a9062002c53565b6040518091039020836001600160a01b03167fabf24e13dd04b5233e0ccecc88963e42e9d8b5ceae25458b61109fcbc0201bfe8a8a8a60405162001b4d9392919062002c71565b60405180910390a460fc8054600160a01b900463ffffffff1690601462001b748362002cac565b91906101000a81548163ffffffff021916908363ffffffff16021790555050509695505050505050565b6001600160a01b03163b151590565b620008ea828262001441565b62001bc5828262000ed9565b620008ea5762001bd58162001ced565b62001be283602062001d00565b60405160200162001bf592919062002cd2565b60408051601f198184030181529082905262461bcd60e51b8252620009979160040162002a57565b62001c288162001b9e565b62001c8c5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840162000997565b60008051602062003e3283398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b62001cc78362001ec0565b60008251118062001cd55750805b15620009255762001ce7838362001f02565b50505050565b6060620005e86001600160a01b03831660145b6060600062001d1183600262002d45565b62001d1e90600262002d5f565b6001600160401b0381111562001d385762001d38620021de565b6040519080825280601f01601f19166020018201604052801562001d63576020820181803683370190505b509050600360fc1b8160008151811062001d815762001d8162002806565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811062001db35762001db362002806565b60200101906001600160f81b031916908160001a905350600062001dd984600262002d45565b62001de690600162002d5f565b90505b600181111562001e68576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811062001e1e5762001e1e62002806565b1a60f81b82828151811062001e375762001e3762002806565b60200101906001600160f81b031916908160001a90535060049490941c9362001e608162002d75565b905062001de9565b50831562001eb95760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640162000997565b9392505050565b62001ecb8162001c1d565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606062001f0f8362001b9e565b62001f6c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840162000997565b600080846001600160a01b03168460405162001f89919062002c53565b600060405180830381855af49150503d806000811462001fc6576040519150601f19603f3d011682016040523d82523d6000602084013e62001fcb565b606091505b509150915062001ff6828260405180606001604052806027815260200162003e526027913962001fff565b95945050505050565b606083156200201057508162001eb9565b62001eb98383815115620020275781518083602001fd5b8060405162461bcd60e51b815260040162000997919062002a57565b6104c98062002d9083390190565b6106cd806200325983390190565b6104ec806200392683390190565b6000602082840312156200208057600080fd5b81356001600160e01b03198116811462001eb957600080fd5b6001600160a01b038116811462000a7d57600080fd5b8035620020bc8162002099565b919050565b600060208284031215620020d457600080fd5b813562001eb98162002099565b60005b83811015620020fe578181015183820152602001620020e4565b50506000910152565b6000815180845262002121816020860160208601620020e1565b601f01601f19169290920160200192915050565b6060815260006200214a606083018662002107565b8415156020840152828103604084015262002166818562002107565b9695505050505050565b6000602082840312156200218357600080fd5b5035919050565b600080604083850312156200219e57600080fd5b823591506020830135620021b28162002099565b809150509250929050565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b03811182821017156200221a576200221a620021de565b60405290565b604051601f8201601f191681016001600160401b03811182821017156200224b576200224b620021de565b604052919050565b60006001600160401b038311156200226f576200226f620021de565b62002284601f8401601f191660200162002220565b90508281528383830111156200229957600080fd5b828260208301376000602084830101529392505050565b60008060408385031215620022c457600080fd5b8235620022d18162002099565b915060208301356001600160401b03811115620022ed57600080fd5b8301601f81018513620022ff57600080fd5b620023108582356020840162002253565b9150509250929050565b600082601f8301126200232c57600080fd5b62001eb98383356020850162002253565b600080604083850312156200235157600080fd5b82356200235e8162002099565b915060208301356001600160401b038111156200237a57600080fd5b62002310858286016200231a565b600080604083850312156200239c57600080fd5b8235620023a98162002099565b946020939093013593505050565b803563ffffffff81168114620020bc57600080fd5b60006001600160401b03821115620023e857620023e8620021de565b5060051b60200190565b600082601f8301126200240457600080fd5b813560206200241d6200241783620023cc565b62002220565b82815260059290921b840181019181810190868411156200243d57600080fd5b8286015b848110156200246c57803561ffff811681146200245e5760008081fd5b835291830191830162002441565b509695505050505050565b600082601f8301126200248957600080fd5b813560206200249c6200241783620023cc565b82815260059290921b84018101918181019086841115620024bc57600080fd5b8286015b848110156200246c5780356001600160801b0381168114620024e25760008081fd5b8352918301918301620024c0565b801515811462000a7d57600080fd5b8035620020bc81620024f0565b6000606082840312156200251f57600080fd5b604051606081016001600160401b0381118282101715620025445762002544620021de565b80604052508091508235815260208301356020820152604083013560408201525092915050565b600080600080600060e086880312156200258457600080fd5b85356001600160401b03808211156200259c57600080fd5b620025aa89838a016200231a565b96506020880135915080821115620025c157600080fd5b620025cf89838a016200231a565b95506040880135915080821115620025e657600080fd5b90870190610100828a031215620025fc57600080fd5b62002606620021f4565b6200261183620023b7565b81526020830135828111156200262657600080fd5b620026348b828601620023f2565b6020830152506040830135828111156200264d57600080fd5b6200265b8b82860162002477565b6040830152506200266f60608401620020af565b60608201526200268260808401620020af565b60808201526200269560a08401620020af565b60a0820152620026a860c08401620020af565b60c0820152620026bb60e08401620024ff565b60e0820152809550505050620026d587606088016200250c565b9150620026e560c08701620023b7565b90509295509295909350565b600080604083850312156200270557600080fd5b8235620027128162002099565b91506020830135620021b281620024f0565b600080604083850312156200273857600080fd5b8235620027458162002099565b91506200275560208401620023b7565b90509250929050565b600080600080600060a086880312156200277757600080fd5b8535620027848162002099565b94506020860135620027968162002099565b93506040860135620027a88162002099565b92506060860135620027ba8162002099565b9150620026e560808701620023b7565b600181811c90821680620027df57607f821691505b6020821081036200280057634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115620005e857620005e86200281c565b634e487b7160e01b600052603160045260246000fd5b6000600182016200287357620028736200281c565b5060010190565b6020808252602c9082015260008051602062003e1283398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c9082015260008051602062003e1283398151915260408201526b6163746976652070726f787960a01b606082015260800190565b6000602082840312156200290357600080fd5b5051919050565b9182526001600160a01b0316602082015260400190565b6000602082840312156200293457600080fd5b815162001eb981620024f0565b601f8211156200092557600081815260208120601f850160051c810160208610156200296a5750805b601f850160051c820191505b81811015620013825782815560010162002976565b81516001600160401b03811115620029a757620029a7620021de565b620029bf81620029b88454620027ca565b8462002941565b602080601f831160018114620029f75760008415620029de5750858301515b600019600386901b1c1916600185901b17855562001382565b600085815260208120601f198616915b8281101562002a285788860151825594840194600190910190840162002a07565b508582101562002a475787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60208152600062001eb9602083018462002107565b600081518084526020808501945080840160005b8381101562002aa75781516001600160801b03168752958201959082019060010162002a80565b509495945050505050565b805163ffffffff168252602080820151610100828501819052815190850181905260009261012086019281019184905b8082101562002b0857835161ffff16855293820193928201926001919091019062002ae2565b505050506040830151848203604086015262002b25828262002a6c565b915050606083015162002b3c6060860182620021bd565b50608083015162002b516080860182620021bd565b5060a083015162002b6660a0860182620021bd565b5060c083015162002b7b60c0860182620021bd565b5060e083015162002b9060e086018215159052565b509392505050565b8051825260208082015190830152604090810151910152565b600060018060a01b03808816835260e0602084015262002bd560e084018862002ab2565b915062002be6604084018762002b98565b63ffffffff851660a084015280841660c0840152509695505050505050565b6001600160a01b038316815260406020820181905260009062002c2b9083018462002107565b949350505050565b60006020828403121562002c4657600080fd5b815162001eb98162002099565b6000825162002c67818460208701620020e1565b9190910192915050565b60a08152600062002c8660a083018662002107565b828103602084015262002c9a818662002ab2565b91505062002c2b604083018462002b98565b600063ffffffff80831681810362002cc85762002cc86200281c565b6001019392505050565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b81526000835162002d06816017850160208801620020e1565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835162002d39816028840160208801620020e1565b01602801949350505050565b8082028115828204841417620005e857620005e86200281c565b80820180821115620005e857620005e86200281c565b60008162002d875762002d876200281c565b50600019019056fe608060405234801561001057600080fd5b506040516104c93803806104c983398101604081905261002f9161013a565b61003833610047565b61004181610097565b5061016a565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0381163b6101185760405162461bcd60e51b815260206004820152603360248201527f5570677261646561626c65426561636f6e3a20696d706c656d656e746174696f60448201527f6e206973206e6f74206120636f6e747261637400000000000000000000000000606482015260840160405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006020828403121561014c57600080fd5b81516001600160a01b038116811461016357600080fd5b9392505050565b610350806101796000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80633659cfe61461005c5780635c60da1b14610071578063715018a61461009a5780638da5cb5b146100a2578063f2fde38b146100aa575b600080fd5b61006f61006a3660046102ea565b6100bd565b005b6001546001600160a01b03165b6040516001600160a01b03909116815260200160405180910390f35b61006f610105565b61007e610119565b61006f6100b83660046102ea565b610128565b6100c56101a6565b6100ce81610205565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b61010d6101a6565b610117600061029a565b565b6000546001600160a01b031690565b6101306101a6565b6001600160a01b03811661019a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b6101a38161029a565b50565b336101af610119565b6001600160a01b0316146101175760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610191565b6001600160a01b0381163b6102785760405162461bcd60e51b815260206004820152603360248201527f5570677261646561626c65426561636f6e3a20696d706c656d656e746174696f6044820152721b881a5cc81b9bdd08184818dbdb9d1c9858dd606a1b6064820152608401610191565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156102fc57600080fd5b81356001600160a01b038116811461031357600080fd5b939250505056fea264697066735822122038970e7cf09dc887c70d5260fa612ed542a4b7fc825586d54bcad83fc1ebdd9164736f6c6343000813003360806040526040516106cd3803806106cd83398101604081905261002291610421565b61002e82826000610035565b505061054b565b61003e836100f6565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100f1576100ef836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e991906104e1565b8361026e565b505b505050565b6100ff8161029a565b61015e5760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101c8816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561019f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101c391906104e1565b61029a565b61022d5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610155565b7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392909216919091179055565b606061029383836040518060600160405280602781526020016106a6602791396102a9565b9392505050565b6001600160a01b03163b151590565b6060600080856001600160a01b0316856040516102c691906104fc565b600060405180830381855af49150503d8060008114610301576040519150601f19603f3d011682016040523d82523d6000602084013e610306565b606091505b50909250905061031886838387610322565b9695505050505050565b6060831561038f5782516000036103885761033c8561029a565b6103885760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610155565b5081610399565b61039983836103a1565b949350505050565b8151156103b15781518083602001fd5b8060405162461bcd60e51b81526004016101559190610518565b80516001600160a01b03811681146103e257600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610418578181015183820152602001610400565b50506000910152565b6000806040838503121561043457600080fd5b61043d836103cb565b60208401519092506001600160401b038082111561045a57600080fd5b818501915085601f83011261046e57600080fd5b815181811115610480576104806103e7565b604051601f8201601f19908116603f011681019083821181831017156104a8576104a86103e7565b816040528281528860208487010111156104c157600080fd5b6104d28360208301602088016103fd565b80955050505050509250929050565b6000602082840312156104f357600080fd5b610293826103cb565b6000825161050e8184602087016103fd565b9190910192915050565b60208152600082518060208401526105378160408501602087016103fd565b601f01601f19169190910160400192915050565b61014c8061055a6000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610029565b6100c2565b565b600061005c7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610099573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100bd91906100e6565b905090565b3660008037600080366000845af43d6000803e8080156100e1573d6000f35b3d6000fd5b6000602082840312156100f857600080fd5b81516001600160a01b038116811461010f57600080fd5b939250505056fea26469706673582212207b4f4f4bd905b812712d76801c617b8aa3f4c3f8d6d9e59a18563606189dd4e564736f6c63430008130033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656460806040526040516104ec3803806104ec833981016040819052610022916102e9565b61002e82826000610035565b5050610406565b61003e83610061565b60008251118061004b5750805b1561005c5761005a83836100a1565b505b505050565b61006a816100cd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606100c683836040518060600160405280602781526020016104c56027913961017e565b9392505050565b6100d6816101f7565b61013d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080856001600160a01b03168560405161019b91906103b7565b600060405180830381855af49150503d80600081146101d6576040519150601f19603f3d011682016040523d82523d6000602084013e6101db565b606091505b5090925090506101ed86838387610206565b9695505050505050565b6001600160a01b03163b151590565b6060831561027357825160000361026c57610220856101f7565b61026c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610134565b508161027d565b61027d8383610285565b949350505050565b8151156102955781518083602001fd5b8060405162461bcd60e51b815260040161013491906103d3565b634e487b7160e01b600052604160045260246000fd5b60005b838110156102e05781810151838201526020016102c8565b50506000910152565b600080604083850312156102fc57600080fd5b82516001600160a01b038116811461031357600080fd5b60208401519092506001600160401b038082111561033057600080fd5b818501915085601f83011261034457600080fd5b815181811115610356576103566102af565b604051601f8201601f19908116603f0116810190838211818310171561037e5761037e6102af565b8160405282815288602084870101111561039757600080fd5b6103a88360208301602088016102c5565b80955050505050509250929050565b600082516103c98184602087016102c5565b9190910192915050565b60208152600082518060208401526103f28160408501602087016102c5565b601f01601f19169190910160400192915050565b60b1806104146000396000f3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea2646970667358221220a4cda07e5b291f61d81b4ee016ef5ca6a806aa56384b08ff8d52828dbed4d68d64736f6c63430008130033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656446756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122044f5c400a13c9fd8ca4b2b561a2460b2351e0706773dd9516462a1e1f772b88e64736f6c63430008130033