Contract
0x0170FFCC75d178d426EBad5b1a31451d00Ddbd0D
3
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
View more zero value Internal Transactions in Advanced View mode
Contract Source Code Verified (Exact Match)
Contract Name:
VestingScheduler
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.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: AGPLv3 pragma solidity >= 0.8.0; import { ISuperfluid, ISuperfluidToken } from "../interfaces/superfluid/ISuperfluid.sol"; import { IConstantFlowAgreementV1 } from "../interfaces/agreements/IConstantFlowAgreementV1.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 ); } }
// SPDX-License-Identifier: AGPLv3 pragma solidity >= 0.8.0; import { ISuperfluid, ISuperToken, ISuperApp, SuperAppDefinitions } from "../interfaces/superfluid/ISuperfluid.sol"; abstract contract SuperAppBase is ISuperApp { function beforeAgreementCreated( ISuperToken /*superToken*/, address /*agreementClass*/, bytes32 /*agreementId*/, bytes calldata /*agreementData*/, bytes calldata /*ctx*/ ) external view virtual override returns (bytes memory /*cbdata*/) { revert("Unsupported callback - Before Agreement Created"); } function afterAgreementCreated( ISuperToken /*superToken*/, address /*agreementClass*/, bytes32 /*agreementId*/, bytes calldata /*agreementData*/, bytes calldata /*cbdata*/, bytes calldata /*ctx*/ ) external virtual override returns (bytes memory /*newCtx*/) { revert("Unsupported callback - After Agreement Created"); } function beforeAgreementUpdated( ISuperToken /*superToken*/, address /*agreementClass*/, bytes32 /*agreementId*/, bytes calldata /*agreementData*/, bytes calldata /*ctx*/ ) external view virtual override returns (bytes memory /*cbdata*/) { revert("Unsupported callback - Before Agreement updated"); } function afterAgreementUpdated( ISuperToken /*superToken*/, address /*agreementClass*/, bytes32 /*agreementId*/, bytes calldata /*agreementData*/, bytes calldata /*cbdata*/, bytes calldata /*ctx*/ ) external virtual override returns (bytes memory /*newCtx*/) { revert("Unsupported callback - After Agreement Updated"); } function beforeAgreementTerminated( ISuperToken /*superToken*/, address /*agreementClass*/, bytes32 /*agreementId*/, bytes calldata /*agreementData*/, bytes calldata /*ctx*/ ) external view virtual override returns (bytes memory /*cbdata*/) { revert("Unsupported callback - Before Agreement Terminated"); } function afterAgreementTerminated( ISuperToken /*superToken*/, address /*agreementClass*/, bytes32 /*agreementId*/, bytes calldata /*agreementData*/, bytes calldata /*cbdata*/, bytes calldata /*ctx*/ ) external virtual override returns (bytes memory /*newCtx*/) { revert("Unsupported callback - After Agreement Terminated"); } }
// SPDX-License-Identifier: AGPLv3 pragma solidity >= 0.8.4; 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); /** * @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 ); }
// SPDX-License-Identifier: AGPLv3 pragma solidity >= 0.8.4; /** * @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 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; } }
// SPDX-License-Identifier: AGPLv3 pragma solidity >= 0.8.4; 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 ); }
// SPDX-License-Identifier: AGPLv3 pragma solidity >= 0.8.4; 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); }
// SPDX-License-Identifier: AGPLv3 pragma solidity >= 0.8.4; import { ISuperfluidGovernance } from "./ISuperfluidGovernance.sol"; import { ISuperfluidToken } from "./ISuperfluidToken.sol"; import { ISuperToken } from "./ISuperToken.sol"; import { ISuperTokenFactory } from "./ISuperTokenFactory.sol"; import { ISuperAgreement } from "./ISuperAgreement.sol"; import { ISuperApp } from "./ISuperApp.sol"; import { BatchOperation, ContextDefinitions, FlowOperatorDefinitions, SuperAppDefinitions, SuperfluidGovernanceConfigs } from "./Definitions.sol"; import { TokenInfo } from "../tokens/TokenInfo.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.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 // 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 * @dev Refer to ISuperTokenFactory.Upgradability for expected behaviours */ function updateSuperTokenLogic(ISuperToken token) external; /** * @dev SuperToken logic updated event * @param code Address of the new SuperToken logic */ 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; */ }
// SPDX-License-Identifier: AGPLv3 pragma solidity >= 0.8.4; import { ISuperAgreement } from "./ISuperAgreement.sol"; import { ISuperToken } from "./ISuperToken.sol"; import { ISuperfluidToken } from "./ISuperfluidToken.sol"; import { ISuperfluid } from "./ISuperfluid.sol"; /** * @title Superfluid governance interface * @author Superfluid */ interface ISuperfluidGovernance { /************************************************************************** * Errors *************************************************************************/ error SF_GOV_ARRAYS_NOT_SAME_LENGTH(); // 0x27743aa6 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 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); }
// SPDX-License-Identifier: AGPLv3 pragma solidity >= 0.8.4; 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 ); }
// SPDX-License-Identifier: AGPLv3 pragma solidity >= 0.8.4; import { ISuperfluid } from "./ISuperfluid.sol"; 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"; /** * @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_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 /** * @dev Initialize the contract */ function initialize( IERC20 underlyingToken, uint8 underlyingDecimals, string calldata n, string calldata s ) external; /************************************************************************** * 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 `data` 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 data) 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 `data` 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 data) 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 `data` 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 data, 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 `data` 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 data, bytes calldata operatorData ) external override(IERC777); /************************************************************************** * SuperToken custom token functions *************************************************************************/ /** * @dev Mint new tokens for the account * * @custom:modifiers * - onlySelf */ function selfMint( address account, uint256 amount, bytes memory userData ) external; /** * @dev Burn existing tokens for the account * * @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 data 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 `data` 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 data) 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; /** * @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 data Arbitrary user inputted data * * @custom:modifiers * - onlyHost */ function operationSend( address spender, address recipient, uint256 amount, bytes memory data ) 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; /************************************************************************** * 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 }
// SPDX-License-Identifier: AGPLv3 pragma solidity >= 0.8.4; 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_ZERO_ADDRESS(); // 0x305c9e82 /** * @dev Get superfluid host contract address */ function getHost() external view returns(address host); /// @dev Initialize the contract function initialize() external; /** * @dev Get the current super token logic used by the factory */ 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); }
// SPDX-License-Identifier: AGPLv3 pragma solidity >= 0.8.4; 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 {}
// SPDX-License-Identifier: AGPLv3 pragma solidity >= 0.8.4; /** * @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); }
// SPDX-License-Identifier: AGPLv3 pragma solidity ^0.8.0; import { ISuperToken, ISuperfluid } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperToken.sol"; import { IConstantFlowAgreementV1 } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/agreements/IConstantFlowAgreementV1.sol"; interface IVestingScheduler { error TimeWindowInvalid(); error AccountInvalid(); error ZeroAddress(); error HostInvalid(); error FlowRateInvalid(); error CliffInvalid(); error ScheduleAlreadyExists(); error ScheduleDoesNotExist(); error ScheduleNotFlowing(); /** * @dev Vesting configuration provided by user. * @param cliffAndFlowDate Date of flow start and cliff execution (if a cliff was specified) * @param endDate End date of the vesting * @param flowRate For the stream * @param cliffAmount Amount to be transferred at the cliff */ struct VestingSchedule { uint32 cliffAndFlowDate; uint32 endDate; int96 flowRate; uint256 cliffAmount; } /** * @dev Event emitted on creation of a new vesting schedule * @param superToken SuperToken to be vested * @param sender Vesting sender * @param receiver Vesting receiver * @param startDate Timestamp when the vesting starts * @param cliffDate Timestamp of the cliff * @param flowRate The flowRate for the stream * @param endDate The timestamp when the stream should stop * @param cliffAmount The amount to be transferred at the cliff */ event VestingScheduleCreated( ISuperToken indexed superToken, address indexed sender, address indexed receiver, uint32 startDate, uint32 cliffDate, int96 flowRate, uint32 endDate, uint256 cliffAmount ); /** * @dev Creates a new vesting schedule * @dev If a non-zero cliffDate is set, the startDate has no effect other than being logged in an event. * @dev If cliffDate is set to zero, the startDate becomes the cliff (transfer cliffAmount and start stream). * @param superToken SuperToken to be vested * @param receiver Vesting receiver * @param startDate Timestamp when the vesting should start * @param cliffDate Timestamp of cliff exectution - if 0, startDate acts as cliff * @param flowRate The flowRate for the stream * @param cliffAmount The amount to be transferred at the cliff * @param endDate The timestamp when the stream should stop. * @param ctx Superfluid context used when batching operations. (or bytes(0) if not SF batching) */ function createVestingSchedule( ISuperToken superToken, address receiver, uint32 startDate, uint32 cliffDate, int96 flowRate, uint256 cliffAmount, uint32 endDate, bytes memory ctx ) external returns (bytes memory newCtx); /** * @dev Event emitted on update of a vesting schedule * @param superToken The superToken to be vested * @param sender Vesting sender * @param receiver Vesting receiver * @param oldEndDate Old timestamp when the stream should stop * @param endDate New timestamp when the stream should stop */ event VestingScheduleUpdated( ISuperToken indexed superToken, address indexed sender, address indexed receiver, uint32 oldEndDate, uint32 endDate ); /** * @dev Updates the end date for a vesting schedule which already reached the cliff * @notice When updating, there's no restriction to the end date other than not being in the past * @param superToken SuperToken to be vested * @param receiver Vesting receiver * @param endDate The timestamp when the stream should stop * @param ctx Superfluid context used when batching operations. (or bytes(0) if not SF batching) */ function updateVestingSchedule( ISuperToken superToken, address receiver, uint32 endDate, bytes memory ctx ) external returns(bytes memory newCtx); /** * @dev Event emitted on deletion of a vesting schedule * @param superToken The superToken to be vested * @param sender Vesting sender * @param receiver Vesting receiver */ event VestingScheduleDeleted( ISuperToken indexed superToken, address indexed sender, address indexed receiver ); /** * @dev Event emitted on end of a vesting that failed because there was no running stream * @param superToken The superToken to be vested * @param sender Vesting sender * @param receiver Vesting receiver * @param endDate The timestamp when the stream should stop */ event VestingEndFailed( ISuperToken indexed superToken, address indexed sender, address indexed receiver, uint32 endDate ); /** * @dev Deletes a vesting schedule * @param superToken The superToken to be vested * @param receiver Vesting receiver * @param ctx Superfluid context used when batching operations. (or bytes(0) if not SF batching) */ function deleteVestingSchedule( ISuperToken superToken, address receiver, bytes memory ctx ) external returns (bytes memory newCtx); /** * @dev Emitted when the cliff of a scheduled vesting is executed * @param superToken The superToken to be vested * @param sender Vesting sender * @param receiver Vesting receiver * @param cliffAndFlowDate The timestamp when the stream should start * @param flowRate The flowRate for the stream * @param cliffAmount The amount you would like to transfer at the startDate when you start streaming * @param flowDelayCompensation Adjusted amount transferred to receiver. (elapse time from config and tx timestamp) */ event VestingCliffAndFlowExecuted( ISuperToken indexed superToken, address indexed sender, address indexed receiver, uint32 cliffAndFlowDate, int96 flowRate, uint256 cliffAmount, uint256 flowDelayCompensation ); /** * @dev Executes a cliff (transfer and stream start) * @notice Intended to be invoked by a backend service * @param superToken SuperToken to be streamed * @param sender Account who will be send the stream * @param receiver Account who will be receiving the stream */ function executeCliffAndFlow( ISuperToken superToken, address sender, address receiver ) external returns(bool success); /** * @dev Emitted when the end of a scheduled vesting is executed * @param superToken The superToken to be vested * @param sender Vesting sender * @param receiver Vesting receiver * @param endDate The timestamp when the stream should stop * @param earlyEndCompensation adjusted close amount transferred to receiver. * @param didCompensationFail adjusted close amount transfer fail. */ event VestingEndExecuted( ISuperToken indexed superToken, address indexed sender, address indexed receiver, uint32 endDate, uint256 earlyEndCompensation, bool didCompensationFail ); /** * @dev Executes the end of a vesting (stop stream) * @notice Intended to be invoked by a backend service * @param superToken The superToken to be vested * @param sender Vesting sender * @param receiver Vesting receiver */ function executeEndVesting( ISuperToken superToken, address sender, address receiver ) external returns(bool success); /** * @dev Gets data currently stored for a vesting schedule * @param superToken The superToken to be vested * @param sender Vesting sender * @param receiver Vesting receiver */ function getVestingSchedule( address superToken, address sender, address receiver ) external view returns (VestingSchedule memory); }
// SPDX-License-Identifier: AGPLv3 // solhint-disable not-rely-on-time pragma solidity ^0.8.0; import { ISuperfluid, ISuperToken, SuperAppDefinitions } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; import { SuperAppBase } from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperAppBase.sol"; import { IConstantFlowAgreementV1 } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/agreements/IConstantFlowAgreementV1.sol"; import { CFAv1Library } from "@superfluid-finance/ethereum-contracts/contracts/apps/CFAv1Library.sol"; import { IVestingScheduler } from "./interface/IVestingScheduler.sol"; contract VestingScheduler is IVestingScheduler, SuperAppBase { using CFAv1Library for CFAv1Library.InitData; CFAv1Library.InitData public cfaV1; mapping(bytes32 => VestingSchedule) public vestingSchedules; // id = keccak(supertoken, sender, receiver) uint32 public constant MIN_VESTING_DURATION = 7 days; uint32 public constant START_DATE_VALID_AFTER = 3 days; uint32 public constant END_DATE_VALID_BEFORE = 1 days; constructor(ISuperfluid host, string memory registrationKey) { cfaV1 = CFAv1Library.InitData( host, IConstantFlowAgreementV1( address( host.getAgreementClass( keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1") ) ) ) ); // Superfluid SuperApp registration. This is a dumb SuperApp, only for front-end tx batch calls. uint256 configWord = SuperAppDefinitions.APP_LEVEL_FINAL | SuperAppDefinitions.BEFORE_AGREEMENT_CREATED_NOOP | SuperAppDefinitions.AFTER_AGREEMENT_CREATED_NOOP | SuperAppDefinitions.BEFORE_AGREEMENT_UPDATED_NOOP | SuperAppDefinitions.AFTER_AGREEMENT_UPDATED_NOOP | SuperAppDefinitions.BEFORE_AGREEMENT_TERMINATED_NOOP | SuperAppDefinitions.AFTER_AGREEMENT_TERMINATED_NOOP; host.registerAppWithKey(configWord, registrationKey); } /// @dev IVestingScheduler.createVestingSchedule implementation. function createVestingSchedule( ISuperToken superToken, address receiver, uint32 startDate, uint32 cliffDate, int96 flowRate, uint256 cliffAmount, uint32 endDate, bytes memory ctx ) external returns (bytes memory newCtx) { newCtx = ctx; address sender = _getSender(ctx); if (receiver == address(0) || receiver == sender) revert AccountInvalid(); if (address(superToken) == address(0)) revert ZeroAddress(); if (flowRate <= 0) revert FlowRateInvalid(); if (cliffDate != 0 && startDate > cliffDate) revert TimeWindowInvalid(); if (cliffDate == 0 && cliffAmount != 0) revert CliffInvalid(); uint32 cliffAndFlowDate = cliffDate == 0 ? startDate : cliffDate; if (cliffAndFlowDate <= block.timestamp || cliffAndFlowDate >= endDate || cliffAndFlowDate + START_DATE_VALID_AFTER >= endDate - END_DATE_VALID_BEFORE || endDate - cliffAndFlowDate < MIN_VESTING_DURATION ) revert TimeWindowInvalid(); bytes32 hashConfig = keccak256(abi.encodePacked(superToken, sender, receiver)); if (vestingSchedules[hashConfig].endDate != 0) revert ScheduleAlreadyExists(); vestingSchedules[hashConfig] = VestingSchedule( cliffAndFlowDate, endDate, flowRate, cliffAmount ); emit VestingScheduleCreated( superToken, sender, receiver, startDate, cliffDate, flowRate, endDate, cliffAmount ); } function updateVestingSchedule( ISuperToken superToken, address receiver, uint32 endDate, bytes memory ctx ) external returns (bytes memory newCtx) { newCtx = ctx; address sender = _getSender(ctx); bytes32 configHash = keccak256(abi.encodePacked(superToken, sender, receiver)); VestingSchedule memory schedule = vestingSchedules[configHash]; if (endDate <= block.timestamp) revert TimeWindowInvalid(); // Only allow an update if 1. vesting exists 2. executeCliffAndFlow() has been called if (schedule.cliffAndFlowDate != 0 || schedule.endDate == 0) revert ScheduleNotFlowing(); vestingSchedules[configHash].endDate = endDate; emit VestingScheduleUpdated( superToken, sender, receiver, schedule.endDate, endDate ); } /// @dev IVestingScheduler.deleteVestingSchedule implementation. function deleteVestingSchedule( ISuperToken superToken, address receiver, bytes memory ctx ) external returns (bytes memory newCtx) { newCtx = ctx; address sender = _getSender(ctx); bytes32 configHash = keccak256(abi.encodePacked(superToken, sender, receiver)); if (vestingSchedules[configHash].endDate != 0) { delete vestingSchedules[configHash]; emit VestingScheduleDeleted(superToken, sender, receiver); } else { revert ScheduleDoesNotExist(); } } /// @dev IVestingScheduler.executeCliffAndFlow implementation. function executeCliffAndFlow( ISuperToken superToken, address sender, address receiver ) external returns (bool success) { bytes32 configHash = keccak256(abi.encodePacked(superToken, sender, receiver)); VestingSchedule memory schedule = vestingSchedules[configHash]; if (schedule.cliffAndFlowDate > block.timestamp || schedule.cliffAndFlowDate + START_DATE_VALID_AFTER < block.timestamp ) revert TimeWindowInvalid(); // Invalidate configuration straight away -- avoid any chance of re-execution or re-entry. delete vestingSchedules[configHash].cliffAndFlowDate; delete vestingSchedules[configHash].cliffAmount; // Compensate for the fact that flow will almost always be executed slightly later than scheduled. uint256 flowDelayCompensation = (block.timestamp - schedule.cliffAndFlowDate) * uint96(schedule.flowRate); // If there's cliff or compensation then transfer that amount. if (schedule.cliffAmount != 0 || flowDelayCompensation != 0) { superToken.transferFrom( sender, receiver, schedule.cliffAmount + flowDelayCompensation ); } // Create a flow according to the vesting schedule configuration. cfaV1.createFlowByOperator(sender, receiver, superToken, schedule.flowRate); emit VestingCliffAndFlowExecuted( superToken, sender, receiver, schedule.cliffAndFlowDate, schedule.flowRate, schedule.cliffAmount, flowDelayCompensation ); return true; } /// @dev IVestingScheduler.executeEndVesting implementation. function executeEndVesting( ISuperToken superToken, address sender, address receiver ) external returns (bool success){ bytes32 configHash = keccak256(abi.encodePacked(superToken, sender, receiver)); VestingSchedule memory schedule = vestingSchedules[configHash]; if (schedule.endDate - END_DATE_VALID_BEFORE > block.timestamp) revert TimeWindowInvalid(); // Invalidate configuration straight away -- avoid any chance of re-execution or re-entry. delete vestingSchedules[configHash]; // If vesting is not running, we can't do anything, just emit failing event. if(_isFlowOngoing(superToken, sender, receiver)) { // delete first the stream and unlock deposit amount. cfaV1.deleteFlowByOperator(sender, receiver, superToken); uint256 earlyEndCompensation = schedule.endDate > block.timestamp ? (schedule.endDate - block.timestamp) * uint96(schedule.flowRate) : 0; bool didCompensationFail; if (earlyEndCompensation != 0) { // try-catch this because if the account does not have tokens for earlyEndCompensation // we should delete the flow anyway. try superToken.transferFrom(sender, receiver, earlyEndCompensation) // solhint-disable-next-line no-empty-blocks {} catch { didCompensationFail = true; } } emit VestingEndExecuted( superToken, sender, receiver, schedule.endDate, earlyEndCompensation, didCompensationFail ); } else { emit VestingEndFailed( superToken, sender, receiver, schedule.endDate ); } return true; } /// @dev IVestingScheduler.getVestingSchedule implementation. function getVestingSchedule( address supertoken, address sender, address receiver ) external view returns (VestingSchedule memory) { return vestingSchedules[keccak256(abi.encodePacked(supertoken, sender, receiver))]; } /// @dev get sender of transaction from Superfluid Context or transaction itself. function _getSender(bytes memory ctx) internal view returns (address sender) { if (ctx.length != 0) { if (msg.sender != address(cfaV1.host)) revert HostInvalid(); sender = cfaV1.host.decodeCtx(ctx).msgSender; } else { sender = msg.sender; } // This is an invariant and should never happen. assert(sender != address(0)); } /// @dev get flowRate of stream function _isFlowOngoing(ISuperToken superToken, address sender, address receiver) internal view returns (bool) { (,int96 flowRate,,) = cfaV1.cfa.getFlow(superToken, sender, receiver); return flowRate != 0; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
[{"inputs":[{"internalType":"contract ISuperfluid","name":"host","type":"address"},{"internalType":"string","name":"registrationKey","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountInvalid","type":"error"},{"inputs":[],"name":"CliffInvalid","type":"error"},{"inputs":[],"name":"FlowRateInvalid","type":"error"},{"inputs":[],"name":"HostInvalid","type":"error"},{"inputs":[],"name":"ScheduleAlreadyExists","type":"error"},{"inputs":[],"name":"ScheduleDoesNotExist","type":"error"},{"inputs":[],"name":"ScheduleNotFlowing","type":"error"},{"inputs":[],"name":"TimeWindowInvalid","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint32","name":"cliffAndFlowDate","type":"uint32"},{"indexed":false,"internalType":"int96","name":"flowRate","type":"int96"},{"indexed":false,"internalType":"uint256","name":"cliffAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"flowDelayCompensation","type":"uint256"}],"name":"VestingCliffAndFlowExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint32","name":"endDate","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"earlyEndCompensation","type":"uint256"},{"indexed":false,"internalType":"bool","name":"didCompensationFail","type":"bool"}],"name":"VestingEndExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint32","name":"endDate","type":"uint32"}],"name":"VestingEndFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint32","name":"startDate","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"cliffDate","type":"uint32"},{"indexed":false,"internalType":"int96","name":"flowRate","type":"int96"},{"indexed":false,"internalType":"uint32","name":"endDate","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"cliffAmount","type":"uint256"}],"name":"VestingScheduleCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"}],"name":"VestingScheduleDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint32","name":"oldEndDate","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"endDate","type":"uint32"}],"name":"VestingScheduleUpdated","type":"event"},{"inputs":[],"name":"END_DATE_VALID_BEFORE","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_VESTING_DURATION","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"START_DATE_VALID_AFTER","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"afterAgreementCreated","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"afterAgreementTerminated","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"afterAgreementUpdated","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"beforeAgreementCreated","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"beforeAgreementTerminated","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"beforeAgreementUpdated","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cfaV1","outputs":[{"internalType":"contract ISuperfluid","name":"host","type":"address"},{"internalType":"contract IConstantFlowAgreementV1","name":"cfa","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint32","name":"startDate","type":"uint32"},{"internalType":"uint32","name":"cliffDate","type":"uint32"},{"internalType":"int96","name":"flowRate","type":"int96"},{"internalType":"uint256","name":"cliffAmount","type":"uint256"},{"internalType":"uint32","name":"endDate","type":"uint32"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"createVestingSchedule","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"deleteVestingSchedule","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"executeCliffAndFlow","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"executeEndVesting","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"supertoken","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"getVestingSchedule","outputs":[{"components":[{"internalType":"uint32","name":"cliffAndFlowDate","type":"uint32"},{"internalType":"uint32","name":"endDate","type":"uint32"},{"internalType":"int96","name":"flowRate","type":"int96"},{"internalType":"uint256","name":"cliffAmount","type":"uint256"}],"internalType":"struct IVestingScheduler.VestingSchedule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint32","name":"endDate","type":"uint32"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"updateVestingSchedule","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"vestingSchedules","outputs":[{"internalType":"uint32","name":"cliffAndFlowDate","type":"uint32"},{"internalType":"uint32","name":"endDate","type":"uint32"},{"internalType":"int96","name":"flowRate","type":"int96"},{"internalType":"uint256","name":"cliffAmount","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620020e3380380620020e38339810160408190526200003491620001cc565b6040805180820182526001600160a01b0384168082529151635b69006f60e11b81527fa9214cc96615e0085d3bb077758db69497dc2dce3b2b1e97bc93c3d18d83efd360048201529091602083019163b6d200de90602401602060405180830381865afa158015620000aa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000d091906200029c565b6001600160a01b039081169091528151600080549183166001600160a01b031992831617905560209092015160018054918316919093161790915560405163bd1c448b60e01b8152643f000000019184169063bd1c448b906200013a9084908690600401620002c3565b600060405180830381600087803b1580156200015557600080fd5b505af11580156200016a573d6000803e3d6000fd5b50505050505050620002ff565b6001600160a01b03811681146200018d57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620001c3578181015183820152602001620001a9565b50506000910152565b60008060408385031215620001e057600080fd5b8251620001ed8162000177565b60208401519092506001600160401b03808211156200020b57600080fd5b818501915085601f8301126200022057600080fd5b81518181111562000235576200023562000190565b604051601f8201601f19908116603f0116810190838211818310171562000260576200026062000190565b816040528281528860208487010111156200027a57600080fd5b6200028d836020830160208801620001a6565b80955050505050509250929050565b600060208284031215620002af57600080fd5b8151620002bc8162000177565b9392505050565b8281526040602082015260008251806040840152620002ea816060850160208701620001a6565b601f01601f1916919091016060019392505050565b611dd4806200030f6000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c80637648e965116100a25780639223d9c1116100715780639223d9c1146102c7578063ac42347a146102da578063d3112b2e146102ed578063d86ed3e514610327578063f67b5c7e1461033a57600080fd5b80637648e96514610236578063835942d714610249578063884d1f401461025c57806389a1976f1461026f57600080fd5b806353c11f99116100de57806353c11f99146101755780635f9e7d7714610188578063604178871461019b57806371de407e1461021357600080fd5b8063230dbd29146101105780632719e010146101395780633011071e1461015857806330d9c91514610162575b600080fd5b61012361011e36600461152a565b610344565b6040516101309190611645565b60405180910390f35b6101436203f48081565b60405163ffffffff9091168152602001610130565b61014362093a8081565b61012361017036600461165f565b6103ab565b61012361018336600461152a565b61040e565b61012361019636600461165f565b610473565b6101e26101a93660046116fe565b6002602052600090815260409020805460019091015463ffffffff80831692600160201b810490911691600160401b909104600b0b9084565b6040805163ffffffff9586168152949093166020850152600b9190910b918301919091526060820152608001610130565b610226610221366004611717565b6104da565b6040519015158152602001610130565b610123610244366004611874565b61078c565b610123610257366004611925565b610b0d565b61012361026a36600461165f565b610c82565b61028261027d366004611717565b610ce5565b6040516101309190600060808201905063ffffffff808451168352806020850151166020840152506040830151600b0b60408301526060830151606083015292915050565b6102266102d5366004611717565b610d91565b6101236102e8366004611998565b610fe3565b600054600154610307916001600160a01b03908116911682565b604080516001600160a01b03938416815292909116602083015201610130565b61012361033536600461152a565b6110c5565b6101436201518081565b60405162461bcd60e51b815260206004820152602e60248201527f556e737570706f727465642063616c6c6261636b202d2041667465722041677260448201526d19595b595b9d08155c19185d195960921b60648201526060906084015b60405180910390fd5b60405162461bcd60e51b815260206004820152602f60248201527f556e737570706f727465642063616c6c6261636b202d204265666f726520416760448201526e1c99595b595b9d0810dc99585d1959608a1b60648201526060906084016103a2565b60405162461bcd60e51b815260206004820152603160248201527f556e737570706f727465642063616c6c6261636b202d2041667465722041677260448201527019595b595b9d0815195c9b5a5b985d1959607a1b60648201526060906084016103a2565b60405162461bcd60e51b815260206004820152603360248201527f556e737570706f727465642063616c6c6261636b202d20204265666f7265204160448201527219dc99595b595b9d0815195c9b5a5b985d1959606a1b60648201526060906084016103a2565b6000808484846040516020016104f2939291906119fa565b60408051601f198184030181528282528051602091820120600081815260028352839020608085018452805463ffffffff8082168752600160201b820416938601849052600160401b9004600b0b9385019390935260019092015460608401529092504290610565906201518090611a3f565b63ffffffff16111561058a57604051633a230cd960e01b815260040160405180910390fd5b600082815260026020526040812080546001600160a01b0319168155600101556105b5868686611127565b1561071a576105c760008686896111ba565b50600042826020015163ffffffff16116105e2576000610610565b81604001516001600160601b031642836020015163ffffffff166106069190611a63565b6106109190611a7c565b90506000811561069b576040516323b872dd60e01b81526001600160a01b0388811660048301528781166024830152604482018490528916906323b872dd906064016020604051808303816000875af192505050801561068d575060408051601f3d908101601f1916820190925261068a91810190611a93565b60015b6106995750600161069b565b505b856001600160a01b0316876001600160a01b0316896001600160a01b03167f18c0f95c8f947c789fc5b704b2f1299671614639c64bf6af260bd210bc184ba28660200151868660405161070b9392919063ffffffff93909316835260208301919091521515604082015260600190565b60405180910390a45050610780565b836001600160a01b0316856001600160a01b0316876001600160a01b03167fcb5ed4b0fc620b552fbd3a82d5fb0f9a57eb30a7ef218f4a4974b871f648f6e88460200151604051610777919063ffffffff91909116815260200190565b60405180910390a45b50600195945050505050565b806000610798826111e6565b90506001600160a01b03891615806107c15750806001600160a01b0316896001600160a01b0316145b156107df5760405163a9c6791d60e01b815260040160405180910390fd5b6001600160a01b038a166108065760405163d92e233d60e01b815260040160405180910390fd5b600086600b0b1361082a576040516308bea1af60e41b815260040160405180910390fd5b63ffffffff87161580159061084a57508663ffffffff168863ffffffff16115b1561086857604051633a230cd960e01b815260040160405180910390fd5b63ffffffff871615801561087b57508415155b1561089957604051635357da6360e01b815260040160405180910390fd5b600063ffffffff8816156108ad57876108af565b885b9050428163ffffffff161115806108d257508463ffffffff168163ffffffff1610155b8061090157506108e56201518086611a3f565b63ffffffff166108f86203f48083611ab5565b63ffffffff1610155b8061091d575062093a806109158287611a3f565b63ffffffff16105b1561093b57604051633a230cd960e01b815260040160405180910390fd5b60008b838c604051602001610952939291906119fa565b60408051808303601f19018152918152815160209283012060008181526002909352912054909150600160201b900463ffffffff16156109a55760405163e109c26360e01b815260040160405180910390fd5b60405180608001604052808363ffffffff1681526020018763ffffffff16815260200189600b0b8152602001888152506002600083815260200190815260200160002060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a8154816001600160601b030219169083600b0b6001600160601b03160217905550606082015181600101559050508a6001600160a01b0316836001600160a01b03168d6001600160a01b03167fff14b28ed767437ab23fdd4d479cc5ab6784d392145c3197ce1e8e953a33b5d68d8d8d8c8e604051610af695949392919063ffffffff95861681529385166020850152600b9290920b60408401529092166060820152608081019190915260a00190565b60405180910390a450505098975050505050505050565b806000610b19826111e6565b90506000868287604051602001610b32939291906119fa565b60408051601f198184030181528282528051602091820120600081815260028352839020608085018452805463ffffffff8082168752600160201b8204811694870194909452600160401b9004600b0b9385019390935260019092015460608401529092504290871611610bb957604051633a230cd960e01b815260040160405180910390fd5b805163ffffffff16151580610bd65750602081015163ffffffff16155b15610bf45760405163e23d21e760e01b815260040160405180910390fd5b600082815260026020908152604091829020805467ffffffff000000001916600160201b63ffffffff8b81169182029290921790925584830151845191168152918201526001600160a01b038981169286821692918c16917f5656285dd3a31235e7b67252cd44c997ee7a3d1b7656497c444212a7caa30c3e910160405180910390a4505050949350505050565b60405162461bcd60e51b815260206004820152602f60248201527f556e737570706f727465642063616c6c6261636b202d204265666f726520416760448201526e1c99595b595b9d081d5c19185d1959608a1b60648201526060906084016103a2565b60408051608081018252600080825260208201819052918101829052606081019190915260026000858585604051602001610d22939291906119fa565b60408051808303601f1901815291815281516020928301208352828201939093529082016000208251608081018452815463ffffffff8082168352600160201b82041693820193909352600160401b909204600b0b928201929092526001909101546060820152949350505050565b600080848484604051602001610da9939291906119fa565b60408051601f198184030181528282528051602091820120600081815260028352839020608085018452805463ffffffff808216808852600160201b830490911694870194909452600160401b9004600b0b938501939093526001909201546060840152909250421080610e32575080514290610e2a906203f48090611ab5565b63ffffffff16105b15610e5057604051633a230cd960e01b815260040160405180910390fd5b600082815260026020526040808220805463ffffffff1916815560010182905582015182516001600160601b0390911690610e919063ffffffff1642611a63565b610e9b9190611a7c565b905081606001516000141580610eb057508015155b15610f5057866001600160a01b03166323b872dd8787848660600151610ed69190611ad2565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015610f2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4e9190611a93565b505b6040820151610f6790600090889088908b906112ba565b508151604080840151606080860151835163ffffffff9095168552600b9290920b60208501529183015281018290526001600160a01b0380871691888216918a16907f55b5747e4a57fe6e94a7f59d179a30836f6f42c9b33d2aa3a8887107510952a49060800160405180910390a45060019695505050505050565b806000610fef826111e6565b90506000858286604051602001611008939291906119fa565b60408051808303601f19018152918152815160209283012060008181526002909352912054909150600160201b900463ffffffff16156110a35760008181526002602052604080822080546001600160a01b0319168155600101829055516001600160a01b038088169285821692918a16917fffdbd3e70c7da1df271588aaf77ca99625058da916f9d29cdc13d6f8e4f900ab9190a46110bc565b6040516319cfbfcd60e11b815260040160405180910390fd5b50509392505050565b60405162461bcd60e51b815260206004820152602e60248201527f556e737570706f727465642063616c6c6261636b202d2041667465722041677260448201526d19595b595b9d0810dc99585d195960921b60648201526060906084016103a2565b600154604051631cd43d1160e31b81526001600160a01b03858116600483015284811660248301528381166044830152600092839291169063e6a1e88890606401608060405180830381865afa158015611185573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a99190611ae5565b5050600b0b15159695505050505050565b6040805160008152602081019091526060906111dd9086908690869086906112e9565b95945050505050565b6000815160001461129c576000546001600160a01b0316331461121c57604051632772d7f360e21b815260040160405180910390fd5b600054604051631fb6491d60e11b81526001600160a01b0390911690633f6c923a9061124c908590600401611645565b600060405180830381865afa158015611269573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112919190810190611ba4565b60600151905061129f565b50335b6001600160a01b0381166112b5576112b5611cab565b919050565b6040805160008152602081019091526060906112df90879087908790879087906113c4565b9695505050505050565b845460018601546040805160008152602081019091526060926001600160a01b03908116926339255d5b929116908190634c8b181f906113329089908c908c9060448101611cc1565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261137d939250908790600401611cf5565b6000604051808303816000875af115801561139c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112df9190810190611d2b565b855460018701546060916001600160a01b03908116916339255d5b9116806394229ecb888b8b8a60006040519080825280601f01601f191660200182016040528015611417576020820181803683370190505b5060405160240161142c959493929190611d60565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252611477939250908790600401611cf5565b6000604051808303816000875af1158015611496573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114be9190810190611d2b565b979650505050505050565b6001600160a01b03811681146114de57600080fd5b50565b60008083601f8401126114f357600080fd5b50813567ffffffffffffffff81111561150b57600080fd5b60208301915083602082850101111561152357600080fd5b9250929050565b600080600080600080600080600060c08a8c03121561154857600080fd5b8935611553816114c9565b985060208a0135611563816114c9565b975060408a0135965060608a013567ffffffffffffffff8082111561158757600080fd5b6115938d838e016114e1565b909850965060808c01359150808211156115ac57600080fd5b6115b88d838e016114e1565b909650945060a08c01359150808211156115d157600080fd5b506115de8c828d016114e1565b915080935050809150509295985092959850929598565b60005b838110156116105781810151838201526020016115f8565b50506000910152565b600081518084526116318160208601602086016115f5565b601f01601f19169290920160200192915050565b6020815260006116586020830184611619565b9392505050565b600080600080600080600060a0888a03121561167a57600080fd5b8735611685816114c9565b96506020880135611695816114c9565b955060408801359450606088013567ffffffffffffffff808211156116b957600080fd5b6116c58b838c016114e1565b909650945060808a01359150808211156116de57600080fd5b506116eb8a828b016114e1565b989b979a50959850939692959293505050565b60006020828403121561171057600080fd5b5035919050565b60008060006060848603121561172c57600080fd5b8335611737816114c9565b92506020840135611747816114c9565b91506040840135611757816114c9565b809150509250925092565b803563ffffffff811681146112b557600080fd5b80600b0b81146114de57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051610160810167ffffffffffffffff811182821017156117bf576117bf611785565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156117ee576117ee611785565b604052919050565b600067ffffffffffffffff82111561181057611810611785565b50601f01601f191660200190565b600082601f83011261182f57600080fd5b813561184261183d826117f6565b6117c5565b81815284602083860101111561185757600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600080600080610100898b03121561189157600080fd5b883561189c816114c9565b975060208901356118ac816114c9565b96506118ba60408a01611762565b95506118c860608a01611762565b945060808901356118d881611776565b935060a089013592506118ed60c08a01611762565b915060e089013567ffffffffffffffff81111561190957600080fd5b6119158b828c0161181e565b9150509295985092959890939650565b6000806000806080858703121561193b57600080fd5b8435611946816114c9565b93506020850135611956816114c9565b925061196460408601611762565b9150606085013567ffffffffffffffff81111561198057600080fd5b61198c8782880161181e565b91505092959194509250565b6000806000606084860312156119ad57600080fd5b83356119b8816114c9565b925060208401356119c8816114c9565b9150604084013567ffffffffffffffff8111156119e457600080fd5b6119f08682870161181e565b9150509250925092565b6bffffffffffffffffffffffff19606094851b8116825292841b83166014820152921b166028820152603c0190565b634e487b7160e01b600052601160045260246000fd5b63ffffffff828116828216039080821115611a5c57611a5c611a29565b5092915050565b81810381811115611a7657611a76611a29565b92915050565b8082028115828204841417611a7657611a76611a29565b600060208284031215611aa557600080fd5b8151801515811461165857600080fd5b63ffffffff818116838216019080821115611a5c57611a5c611a29565b80820180821115611a7657611a76611a29565b60008060008060808587031215611afb57600080fd5b845193506020850151611b0d81611776565b6040860151606090960151949790965092505050565b805160ff811681146112b557600080fd5b80516112b5816114c9565b80516001600160e01b0319811681146112b557600080fd5b600082601f830112611b6857600080fd5b8151611b7661183d826117f6565b818152846020838601011115611b8b57600080fd5b611b9c8260208301602087016115f5565b949350505050565b600060208284031215611bb657600080fd5b815167ffffffffffffffff80821115611bce57600080fd5b908301906101608286031215611be357600080fd5b611beb61179b565b611bf483611b23565b8152611c0260208401611b23565b602082015260408301516040820152611c1d60608401611b34565b6060820152611c2e60808401611b3f565b608082015260a083015182811115611c4557600080fd5b611c5187828601611b57565b60a08301525060c083015160c082015260e083015160e0820152610100915081830151828201526101209150611c88828401611b34565b828201526101409150611c9c828401611b34565b91810191909152949350505050565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b0385811682528481166020830152831660408201526080606082018190526000906112df90830184611619565b6001600160a01b0384168152606060208201819052600090611d1990830185611619565b82810360408401526112df8185611619565b600060208284031215611d3d57600080fd5b815167ffffffffffffffff811115611d5457600080fd5b611b9c84828501611b57565b6001600160a01b038681168252858116602083015284166040820152600b83900b606082015260a0608082018190526000906114be9083018461161956fea264697066735822122085589f47e26c080ebfa397b03ed0168d73eda8fcf48cd7f83ea74e06e042c7d264736f6c634300081100330000000000000000000000002dfe937cd98ab92e59cf3139138f18c823a4efe7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000026b31000000000000000000000000000000000000000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002dfe937cd98ab92e59cf3139138f18c823a4efe7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000026b31000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : host (address): 0x2dfe937cd98ab92e59cf3139138f18c823a4efe7
Arg [1] : registrationKey (string): k1
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000002dfe937cd98ab92e59cf3139138f18c823a4efe7
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [3] : 6b31000000000000000000000000000000000000000000000000000000000000
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.