Source Code
Multichain Info
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
InstantDistributionAgreementV1
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.19;
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {
IInstantDistributionAgreementV1, ISuperfluidToken
} from "../interfaces/agreements/IInstantDistributionAgreementV1.sol";
import { ISuperfluid, SuperAppDefinitions } from "../interfaces/superfluid/ISuperfluid.sol";
import { AgreementBase } from "./AgreementBase.sol";
import { SlotsBitmapLibrary } from "../libs/SlotsBitmapLibrary.sol";
import { AgreementLibrary } from "./AgreementLibrary.sol";
/**
* @title InstantDistributionAgreementV1 contract
* @author Superfluid
* @dev Please read IInstantDistributionAgreementV1 for implementation notes.
* @dev For more technical notes, please visit protocol-monorepo wiki area.
*
* Storage Layout Notes
* Agreement State
* NOTE The Agreement State slot is computed with the following function:
* keccak256(abi.encode("AgreementState", msg.sender, account, slotId))
* Publisher Deposit State Slot
* slotId = _PUBLISHER_DEPOSIT_STATE_SLOT_ID or 1 << 32 or 4294967296
* msg.sender = address of IDAv1
* account = context.msgSender
* Publisher Deposit State stores deposit state for a publisher, this is the pending value.
*
* Subscriber Subscription Data Slot Id Start
* slotId = _SUBSCRIBER_SUB_DATA_STATE_SLOT_ID_START or 1 << 128 or 340282366920938463463374607431768211456
* msg.sender = address of IDAv1
* account = context.msgSender
* Subscriber Subscription Data Slot Id Start indicates the starting slot for where we begin to store the indexes a
* subscriber is a part of.
*
* Slots Bitmap Data Slot
* slotId = _SUBSCRIBER_SUBS_BITMAP_STATE_SLOT_ID or 0
* msg.sender = address of IDAv1
* account = context.msgSender
* Slots Bitmap Data Slot stores the bitmap of the slots that are "enabled" for a subscriber.
* This is used as an optimization to only get the data (index id's) for the slots that are "enabled".
*
*
* Agreement Data
* NOTE The Agreement Data slot is calculated with the following function:
* keccak256(abi.encode("AgreementData", agreementClass, agreementId))
* agreementClass = address of IDAv1
* agreementId = PublisherId | SubscriptionId
*
* PublisherId = keccak256(abi.encode("publisher", publisher, indexId))
* publisher = "owner" of the index
* indexId = arbitrary value for allowing multiple indexes by the same token-publisher pair
* PublisherId stores IndexData for an Index.
*
* SubscriptionId = keccak256(abi.encode("subscriber", subscriber, iId))
* iId = PublisherId, the index this particular subscriber is subscribed to
* SubscriptionId stores SubscriptionData for a subscriber to an Index.
*/
contract InstantDistributionAgreementV1 is
AgreementBase,
IInstantDistributionAgreementV1
{
using SafeCast for uint256;
address public constant SLOTS_BITMAP_LIBRARY_ADDRESS = address(SlotsBitmapLibrary);
/// @dev Maximum number of subscriptions a subscriber can have
uint32 public constant MAX_NUM_SUBSCRIPTIONS = SlotsBitmapLibrary._MAX_NUM_SLOTS;
/// @dev Subscriber state slot id for storing subs bitmap
uint256 private constant _SUBSCRIBER_SUBS_BITMAP_STATE_SLOT_ID = 0;
/// @dev Publisher state slot id for storing its deposit amount
uint256 private constant _PUBLISHER_DEPOSIT_STATE_SLOT_ID = 1 << 32;
/// @dev Subscriber state slot id starting ptoint for subscription data
uint256 private constant _SUBSCRIBER_SUB_DATA_STATE_SLOT_ID_START = 1 << 128;
/// @dev A special id that indicating the subscription is not approved yet
uint32 private constant _UNALLOCATED_SUB_ID = type(uint32).max;
// solhint-disable-next-line no-empty-blocks
constructor(ISuperfluid host) AgreementBase(address(host)) {}
/// @dev Agreement data for the index
struct IndexData {
uint128 indexValue;
uint128 totalUnitsApproved;
uint128 totalUnitsPending;
}
/// @dev Agreement data for the subscription
struct SubscriptionData {
uint32 subId;
address publisher;
uint32 indexId;
uint128 indexValue;
uint128 units;
}
/**************************************************************************
* ISuperAgreement interface
*************************************************************************/
/// @dev ISuperAgreement.realtimeBalanceOf implementation
function realtimeBalanceOf(
ISuperfluidToken token,
address account,
uint256 /*time*/
)
external view override
returns (
int256 dynamicBalance,
uint256 deposit,
uint256 owedDeposit
)
{
// as a subscriber
// read all subs and calculate the real-time balance
uint32[] memory slotIds;
bytes32[] memory sidList;
(slotIds, sidList) = _listSubscriptionIds(token, account);
for (uint32 i = 0; i < sidList.length; ++i) {
bool exist;
SubscriptionData memory sdata;
bytes32 iId;
{
uint32 subId = slotIds[i];
(exist, sdata) = _getSubscriptionData(token, sidList[i]);
assert(exist);
assert(sdata.subId == subId);
iId = token.getAgreementStateSlot(
address(this),
account,
_SUBSCRIBER_SUB_DATA_STATE_SLOT_ID_START + subId, 1)[0];
}
{
IndexData memory idata;
(exist, idata) = _getIndexData(token, iId);
assert(exist);
dynamicBalance = dynamicBalance + (
// NOTE casting these values to int256 is okay because the original values
// are uint128
int256(uint256(idata.indexValue - sdata.indexValue)) * int256(uint256(sdata.units))
);
}
}
// as a publisher
// calculate the deposits due to pending subscriptions
deposit = _getPublisherDeposit(token, account);
owedDeposit = 0;
}
/**************************************************************************
* Index operations
*************************************************************************/
/// @dev IInstantDistributionAgreementV1.createIndex implementation
function createIndex(
ISuperfluidToken token,
uint32 indexId,
bytes calldata ctx
)
external override
returns(bytes memory newCtx)
{
ISuperfluid.Context memory context = AgreementLibrary.authorizeTokenAccess(token, ctx);
address publisher = context.msgSender;
bytes32 iId = _getPublisherId(publisher, indexId);
if (_hasIndexData(token, iId)) {
revert IDA_INDEX_ALREADY_EXISTS();
}
token.createAgreement(iId, _encodeIndexData(IndexData(0, 0, 0)));
emit IndexCreated(token, publisher, indexId, context.userData);
// nothing to be recorded so far
newCtx = ctx;
}
/// @dev IInstantDistributionAgreementV1.getIndex implementation
function getIndex(
ISuperfluidToken token,
address publisher,
uint32 indexId
)
external view override
returns (
bool exist,
uint128 indexValue,
uint128 totalUnitsApproved,
uint128 totalUnitsPending)
{
IndexData memory idata;
bytes32 iId = _getPublisherId(publisher, indexId);
(exist, idata) = _getIndexData(token, iId);
if (exist) {
indexValue = idata.indexValue;
totalUnitsApproved = idata.totalUnitsApproved;
totalUnitsPending = idata.totalUnitsPending;
}
}
/// @dev IInstantDistributionAgreementV1.calculateDistribution implementation
function calculateDistribution(
ISuperfluidToken token,
address publisher,
uint32 indexId,
uint256 amount
)
external view override
returns(
uint256 actualAmount,
uint128 newIndexValue)
{
bytes32 iId = _getPublisherId(publisher, indexId);
(bool exist, IndexData memory idata) = _getIndexData(token, iId);
if (!exist) revert IDA_INDEX_DOES_NOT_EXIST();
uint256 totalUnits = uint256(idata.totalUnitsApproved + idata.totalUnitsPending);
uint128 indexDelta = (amount / totalUnits).toUint128();
newIndexValue = idata.indexValue + indexDelta;
actualAmount = uint256(indexDelta) * totalUnits;
}
/// @dev IInstantDistributionAgreementV1.updateIndex implementation
function updateIndex(
ISuperfluidToken token,
uint32 indexId,
uint128 indexValue,
bytes calldata ctx
)
external override
returns(bytes memory newCtx)
{
ISuperfluid.Context memory context = AgreementLibrary.authorizeTokenAccess(token, ctx);
address publisher = context.msgSender;
(bytes32 iId, IndexData memory idata) = _loadIndexData(token, publisher, indexId);
if (indexValue < idata.indexValue) revert IDA_INDEX_SHOULD_GROW();
_updateIndex(token, publisher, indexId, iId, idata, indexValue, context.userData);
// nothing to be recorded so far
newCtx = ctx;
}
/// @dev IInstantDistributionAgreementV1.distribute implementation
function distribute(
ISuperfluidToken token,
uint32 indexId,
uint256 amount,
bytes calldata ctx
)
external override
returns(bytes memory newCtx)
{
ISuperfluid.Context memory context = AgreementLibrary.authorizeTokenAccess(token, ctx);
address publisher = context.msgSender;
(bytes32 iId, IndexData memory idata) = _loadIndexData(token, publisher, indexId);
uint256 totalUnits = uint256(idata.totalUnitsApproved + idata.totalUnitsPending);
if (totalUnits > 0) {
uint128 indexDelta = (amount / totalUnits).toUint128();
_updateIndex(token, publisher, indexId, iId, idata, idata.indexValue + indexDelta, context.userData);
}
// nothing to be recorded so far
newCtx = ctx;
}
function _updateIndex(
ISuperfluidToken token,
address publisher,
uint32 indexId,
bytes32 iId,
IndexData memory idata,
uint128 newIndexValue,
bytes memory userData
)
private
{
// - settle the publisher balance INSTANT-ly (ding ding ding, IDA)
// - adjust static balance directly
token.settleBalance(publisher,
// NOTE casting these values to int256 is okay because the original values
// are uint128
(-int256(uint256(newIndexValue - idata.indexValue))) * int256(uint256(idata.totalUnitsApproved)));
// - adjust the publisher's deposit amount
_adjustPublisherDeposit(token, publisher,
// NOTE casting these values to int256 is okay because the original values
// are uint128
int256(uint256(newIndexValue - idata.indexValue)) * int256(uint256(idata.totalUnitsPending)));
// adjust the publisher's index data
uint128 oldIndexValue = idata.indexValue;
idata.indexValue = newIndexValue;
token.updateAgreementData(iId, _encodeIndexData(idata));
emit IndexUpdated(
token,
publisher,
indexId,
oldIndexValue,
newIndexValue,
idata.totalUnitsPending,
idata.totalUnitsApproved,
userData);
// check account solvency
if (token.isAccountCriticalNow(publisher)) {
revert IDA_INSUFFICIENT_BALANCE();
}
}
function _loadIndexData(
ISuperfluidToken token,
address publisher,
uint32 indexId)
private view
returns (
bytes32 iId,
IndexData memory idata
)
{
bool exist;
iId = _getPublisherId(publisher, indexId);
(exist, idata) = _getIndexData(token, iId);
if (!exist) revert IDA_INDEX_DOES_NOT_EXIST();
}
/**************************************************************************
* Subscription operations
*************************************************************************/
// Stack variables to avoid stack too deep errors in some functions
// solhint-disable-next-line contract-name-camelcase
struct _SubscriptionOperationVars {
bytes32 iId;
bool subscriptionExists;
bytes32 sId;
IndexData idata;
SubscriptionData sdata;
bytes cbdata;
}
/// @dev IInstantDistributionAgreementV1.approveSubscription implementation
function approveSubscription(
ISuperfluidToken token,
address publisher,
uint32 indexId,
bytes calldata ctx
)
external override
returns(bytes memory newCtx)
{
_SubscriptionOperationVars memory vars;
AgreementLibrary.CallbackInputs memory cbStates;
address subscriber;
bytes memory userData;
{
ISuperfluid.Context memory context = AgreementLibrary.authorizeTokenAccess(token, ctx);
subscriber = context.msgSender;
userData = context.userData;
}
(
vars.iId,
vars.sId,
vars.idata,
vars.subscriptionExists,
vars.sdata
) = _loadAllData(token, publisher, subscriber, indexId, false);
if (vars.subscriptionExists) {
// required condition check
if (vars.sdata.subId != _UNALLOCATED_SUB_ID) {
revert IDA_SUBSCRIPTION_ALREADY_APPROVED();
}
}
newCtx = ctx;
cbStates = AgreementLibrary.createCallbackInputs(
token,
publisher,
vars.sId,
"");
if (!vars.subscriptionExists) {
cbStates.noopBit = SuperAppDefinitions.BEFORE_AGREEMENT_CREATED_NOOP;
vars.cbdata = AgreementLibrary.callAppBeforeCallback(cbStates, newCtx);
vars.sdata = SubscriptionData({
publisher: publisher,
indexId: indexId,
subId: 0,
units: 0,
indexValue: vars.idata.indexValue
});
// add to subscription list of the subscriber
vars.sdata.subId = _findAndFillSubsBitmap(token, subscriber, vars.iId);
token.createAgreement(vars.sId, _encodeSubscriptionData(vars.sdata));
cbStates.noopBit = SuperAppDefinitions.AFTER_AGREEMENT_CREATED_NOOP;
(, newCtx) = AgreementLibrary.callAppAfterCallback(cbStates, vars.cbdata, newCtx);
} else {
cbStates.noopBit = SuperAppDefinitions.BEFORE_AGREEMENT_UPDATED_NOOP;
vars.cbdata = AgreementLibrary.callAppBeforeCallback(cbStates, newCtx);
// NOTE casting these values to int256 is okay because the original values
// are uint128
int balanceDelta = int256(uint256(vars.idata.indexValue - vars.sdata.indexValue))
* int256(uint256(vars.sdata.units));
// update publisher data and adjust publisher's deposits
vars.idata.totalUnitsApproved += vars.sdata.units;
vars.idata.totalUnitsPending -= vars.sdata.units;
token.updateAgreementData(vars.iId, _encodeIndexData(vars.idata));
_adjustPublisherDeposit(token, publisher, -balanceDelta);
token.settleBalance(publisher, -balanceDelta);
// update subscription data and adjust subscriber's balance
token.settleBalance(subscriber, balanceDelta);
vars.sdata.indexValue = vars.idata.indexValue;
vars.sdata.subId = _findAndFillSubsBitmap(token, subscriber, vars.iId);
token.updateAgreementData(vars.sId, _encodeSubscriptionData(vars.sdata));
cbStates.noopBit = SuperAppDefinitions.AFTER_AGREEMENT_UPDATED_NOOP;
(, newCtx) = AgreementLibrary.callAppAfterCallback(cbStates, vars.cbdata, newCtx);
}
// can index up to three words, hence splitting into two events from publisher or subscriber's view.
emit IndexSubscribed(token, publisher, indexId, subscriber, userData);
emit SubscriptionApproved(token, subscriber, publisher, indexId, userData);
}
/// @dev IInstantDistributionAgreementV1.revokeSubscription implementation
function revokeSubscription(
ISuperfluidToken token,
address publisher,
uint32 indexId,
bytes calldata ctx
)
external override
returns(bytes memory newCtx)
{
_SubscriptionOperationVars memory vars;
AgreementLibrary.CallbackInputs memory cbStates;
address subscriber;
bytes memory userData;
{
ISuperfluid.Context memory context = AgreementLibrary.authorizeTokenAccess(token, ctx);
subscriber = context.msgSender;
userData = context.userData;
}
(
vars.iId,
vars.sId,
vars.idata,
,
vars.sdata
) = _loadAllData(token, publisher, subscriber, indexId, true);
// should not revoke an pending(un-approved) subscription
if (vars.sdata.subId == _UNALLOCATED_SUB_ID) {
revert IDA_SUBSCRIPTION_IS_NOT_APPROVED();
}
cbStates = AgreementLibrary.createCallbackInputs(
token,
publisher,
vars.sId,
"");
newCtx = ctx;
cbStates.noopBit = SuperAppDefinitions.BEFORE_AGREEMENT_TERMINATED_NOOP;
vars.cbdata = AgreementLibrary.callAppBeforeCallback(cbStates, newCtx);
// NOTE downcasting these values to int256 is okay because the original values
// are uint128
int256 balanceDelta = int256(uint256(vars.idata.indexValue - vars.sdata.indexValue))
* int256(uint256(vars.sdata.units));
vars.idata.totalUnitsApproved = vars.idata.totalUnitsApproved - vars.sdata.units;
vars.idata.totalUnitsPending = vars.idata.totalUnitsPending + vars.sdata.units;
token.updateAgreementData(vars.iId, _encodeIndexData(vars.idata));
// remove subscription from subscriber's bitmap
_clearSubsBitmap(token, subscriber, vars.sdata.subId);
// sync pending distributions
vars.sdata.indexValue = vars.idata.indexValue;
// unlink publisher and subscriber
vars.sdata.subId = _UNALLOCATED_SUB_ID;
token.updateAgreementData(vars.sId, _encodeSubscriptionData(vars.sdata));
// settle subscriber static balance as a result to keep balance unchanged
token.settleBalance(subscriber, balanceDelta);
cbStates.noopBit = SuperAppDefinitions.AFTER_AGREEMENT_TERMINATED_NOOP;
(, newCtx) = AgreementLibrary.callAppAfterCallback(cbStates, vars.cbdata, newCtx);
emit IndexUnsubscribed(token, publisher, indexId, subscriber, userData);
emit SubscriptionRevoked(token, subscriber, publisher, indexId, userData);
}
/// @dev IInstantDistributionAgreementV1.updateSubscription implementation
function updateSubscription(
ISuperfluidToken token,
uint32 indexId,
address subscriber,
uint128 units,
bytes calldata ctx
)
external override
returns(bytes memory newCtx)
{
if (subscriber == address(0)) {
revert IDA_ZERO_ADDRESS_SUBSCRIBER();
}
_SubscriptionOperationVars memory vars;
AgreementLibrary.CallbackInputs memory cbStates;
bytes memory userData;
address publisher;
{
ISuperfluid.Context memory context = AgreementLibrary.authorizeTokenAccess(token, ctx);
userData = context.userData;
publisher = context.msgSender;
}
(
vars.iId,
vars.sId,
vars.idata,
vars.subscriptionExists,
vars.sdata
) = _loadAllData(token, publisher, subscriber, indexId, false);
cbStates = AgreementLibrary.createCallbackInputs(
token,
subscriber,
vars.sId,
"");
newCtx = ctx;
// before-hook callback
if (vars.subscriptionExists) {
cbStates.noopBit = SuperAppDefinitions.BEFORE_AGREEMENT_UPDATED_NOOP;
vars.cbdata = AgreementLibrary.callAppBeforeCallback(cbStates, newCtx);
} else {
cbStates.noopBit = SuperAppDefinitions.BEFORE_AGREEMENT_CREATED_NOOP;
vars.cbdata = AgreementLibrary.callAppBeforeCallback(cbStates, newCtx);
}
// update publisher data
if (vars.subscriptionExists && vars.sdata.subId != _UNALLOCATED_SUB_ID) {
// if the subscription exist and not approved, update the approved units amount
// update total units
vars.idata.totalUnitsApproved = (
uint256(vars.idata.totalUnitsApproved) +
uint256(units) -
uint256(vars.sdata.units)
).toUint128();
token.updateAgreementData(vars.iId, _encodeIndexData(vars.idata));
} else if (vars.subscriptionExists) {
// if the subscription exists and approved, update the pending units amount
// update pending subscription units of the publisher
vars.idata.totalUnitsPending = (
uint256(vars.idata.totalUnitsPending) +
uint256(units) -
uint256(vars.sdata.units)
).toUint128();
token.updateAgreementData(vars.iId, _encodeIndexData(vars.idata));
} else {
// if the subscription does not exist, create it and then update the pending units amount
// create unallocated subscription
vars.sdata = SubscriptionData({
publisher: publisher,
indexId: indexId,
subId: _UNALLOCATED_SUB_ID,
units: units,
indexValue: vars.idata.indexValue
});
token.createAgreement(vars.sId, _encodeSubscriptionData(vars.sdata));
vars.idata.totalUnitsPending = vars.idata.totalUnitsPending + units;
token.updateAgreementData(vars.iId, _encodeIndexData(vars.idata));
}
// NOTE casting these values to int256 is okay because the original values
// are uint128
int256 balanceDelta = int256(uint256(vars.idata.indexValue - vars.sdata.indexValue))
* int256(uint256(vars.sdata.units));
// adjust publisher's deposit and balances if subscription is pending
if (vars.sdata.subId == _UNALLOCATED_SUB_ID) {
_adjustPublisherDeposit(token, publisher, -balanceDelta);
token.settleBalance(publisher, -balanceDelta);
}
// settle subscriber static balance
token.settleBalance(subscriber, balanceDelta);
// update subscription data if necessary
if (vars.subscriptionExists) {
vars.sdata.indexValue = vars.idata.indexValue;
vars.sdata.units = units;
token.updateAgreementData(vars.sId, _encodeSubscriptionData(vars.sdata));
}
// after-hook callback
if (vars.subscriptionExists) {
cbStates.noopBit = SuperAppDefinitions.AFTER_AGREEMENT_UPDATED_NOOP;
(, newCtx) = AgreementLibrary.callAppAfterCallback(cbStates, vars.cbdata, newCtx);
} else {
cbStates.noopBit = SuperAppDefinitions.AFTER_AGREEMENT_CREATED_NOOP;
(, newCtx) = AgreementLibrary.callAppAfterCallback(cbStates, vars.cbdata, newCtx);
}
emit IndexUnitsUpdated(token, publisher, indexId, subscriber, units, userData);
emit SubscriptionUnitsUpdated(token, subscriber, publisher, indexId, units, userData);
}
/// @dev IInstantDistributionAgreementV1.getSubscription implementation
function getSubscription(
ISuperfluidToken token,
address publisher,
uint32 indexId,
address subscriber
)
external view override
returns (
bool exist,
bool approved,
uint128 units,
uint256 pendingDistribution
)
{
bytes32 iId;
bytes32 sId;
IndexData memory idata;
SubscriptionData memory sdata;
(
iId,
sId,
idata,
exist,
sdata
) = _loadAllData(token, publisher, subscriber, indexId, false);
if (!exist) return (false, false, 0, 0);
approved = sdata.subId != _UNALLOCATED_SUB_ID;
units = sdata.units;
pendingDistribution = approved ? 0 : uint256(idata.indexValue - sdata.indexValue) * uint256(sdata.units);
}
/// @dev IInstantDistributionAgreementV1.getSubscriptionByID implementation
function getSubscriptionByID(
ISuperfluidToken token,
bytes32 agreementId
)
external view override
returns(
address publisher,
uint32 indexId,
bool approved,
uint128 units,
uint256 pendingDistribution
)
{
bool exist;
bytes32 iId;
IndexData memory idata;
SubscriptionData memory sdata;
(exist, sdata) = _getSubscriptionData(token, agreementId);
if (!exist) {
revert IDA_SUBSCRIPTION_DOES_NOT_EXIST();
}
publisher = sdata.publisher;
indexId = sdata.indexId;
iId = _getPublisherId(publisher, indexId);
(exist, idata) = _getIndexData(token, iId);
assert(exist);
approved = sdata.subId != _UNALLOCATED_SUB_ID;
units = sdata.units;
pendingDistribution = approved ? 0 :
uint256(idata.indexValue - sdata.indexValue) * uint256(sdata.units);
}
/// @dev IInstantDistributionAgreementV1.listSubscriptions implementation
function listSubscriptions(
ISuperfluidToken token,
address subscriber
)
external view override
returns(
address[] memory publishers,
uint32[] memory indexIds,
uint128[] memory unitsList)
{
uint32[] memory slotIds;
bytes32[] memory sidList;
(slotIds, sidList) = _listSubscriptionIds(token, subscriber);
bool exist;
SubscriptionData memory sdata;
publishers = new address[](sidList.length);
indexIds = new uint32[](sidList.length);
unitsList = new uint128[](sidList.length);
for (uint32 i = 0; i < sidList.length; ++i) {
uint32 subId = slotIds[i];
bytes32 sId = sidList[i];
(exist, sdata) = _getSubscriptionData(token, sId);
assert(exist);
assert(sdata.subId == subId);
publishers[i] = sdata.publisher;
indexIds[i] = sdata.indexId;
unitsList[i] = sdata.units;
}
}
/// @dev IInstantDistributionAgreementV1.deleteSubscription implementation
function deleteSubscription(
ISuperfluidToken token,
address publisher,
uint32 indexId,
address subscriber,
bytes calldata ctx
)
external override
returns(bytes memory newCtx)
{
_SubscriptionOperationVars memory vars;
AgreementLibrary.CallbackInputs memory cbStates;
address sender;
bytes memory userData;
{
ISuperfluid.Context memory context = AgreementLibrary.authorizeTokenAccess(token, ctx);
sender = context.msgSender;
userData = context.userData;
}
if (subscriber == address(0)) {
revert IDA_ZERO_ADDRESS_SUBSCRIBER();
}
// only publisher can delete a subscription
// follows from the invariant that only the publisher
// has the ability to modify the units a subscriber has
if (sender != publisher) revert IDA_OPERATION_NOT_ALLOWED();
(
vars.iId,
vars.sId,
vars.idata,
,
vars.sdata
) = _loadAllData(token, publisher, subscriber, indexId, true);
cbStates = AgreementLibrary.createCallbackInputs(
token,
subscriber,
vars.sId,
"");
newCtx = ctx;
cbStates.noopBit = SuperAppDefinitions.BEFORE_AGREEMENT_TERMINATED_NOOP;
vars.cbdata = AgreementLibrary.callAppBeforeCallback(cbStates, newCtx);
// NOTE casting these values to int256 is okay because the original values
// are uint128
int256 balanceDelta = int256(uint256(vars.idata.indexValue - vars.sdata.indexValue))
* int256(uint256(vars.sdata.units));
// update publisher index agreement data
if (vars.sdata.subId != _UNALLOCATED_SUB_ID) {
vars.idata.totalUnitsApproved = vars.idata.totalUnitsApproved - vars.sdata.units;
} else {
vars.idata.totalUnitsPending = vars.idata.totalUnitsPending - vars.sdata.units;
}
token.updateAgreementData(vars.iId, _encodeIndexData(vars.idata));
// remove subscription from subscriber's bitmap
if (vars.sdata.subId != _UNALLOCATED_SUB_ID) {
_clearSubsBitmap(token, subscriber, vars.sdata.subId);
}
// move from publisher's deposit to static balance
if (vars.sdata.subId == _UNALLOCATED_SUB_ID) {
_adjustPublisherDeposit(token, publisher, -balanceDelta);
token.settleBalance(publisher, -balanceDelta);
}
// terminate subscription agreement data
token.terminateAgreement(vars.sId, 2);
// settle subscriber static balance
token.settleBalance(subscriber, balanceDelta);
cbStates.noopBit = SuperAppDefinitions.AFTER_AGREEMENT_TERMINATED_NOOP;
(, newCtx) = AgreementLibrary.callAppAfterCallback(cbStates, vars.cbdata, newCtx);
emit IndexUnsubscribed(token, publisher, indexId, subscriber, userData);
emit SubscriptionRevoked(token, subscriber, publisher, indexId, userData);
emit IndexUnitsUpdated(token, publisher, indexId, subscriber, 0, userData);
emit SubscriptionUnitsUpdated(token, subscriber, publisher, indexId, 0, userData);
}
function claim(
ISuperfluidToken token,
address publisher,
uint32 indexId,
address subscriber,
bytes calldata ctx
)
external override
returns(bytes memory newCtx)
{
AgreementLibrary.authorizeTokenAccess(token, ctx);
if (subscriber == address(0)) {
revert IDA_ZERO_ADDRESS_SUBSCRIBER();
}
_SubscriptionOperationVars memory vars;
AgreementLibrary.CallbackInputs memory cbStates;
(
vars.iId,
vars.sId,
vars.idata,
,
vars.sdata
) = _loadAllData(token, publisher, subscriber, indexId, true);
// required condition check
if (vars.sdata.subId != _UNALLOCATED_SUB_ID) {
revert IDA_SUBSCRIPTION_ALREADY_APPROVED();
}
uint256 pendingDistribution = uint256(vars.idata.indexValue - vars.sdata.indexValue)
* uint256(vars.sdata.units);
cbStates = AgreementLibrary.createCallbackInputs(
token,
publisher,
vars.sId,
"");
newCtx = ctx;
if (pendingDistribution > 0) {
cbStates.noopBit = SuperAppDefinitions.BEFORE_AGREEMENT_UPDATED_NOOP;
vars.cbdata = AgreementLibrary.callAppBeforeCallback(cbStates, newCtx);
// adjust publisher's deposits
_adjustPublisherDeposit(token, publisher, -int256(pendingDistribution));
token.settleBalance(publisher, -int256(pendingDistribution));
// update subscription data and adjust subscriber's balance
vars.sdata.indexValue = vars.idata.indexValue;
token.updateAgreementData(vars.sId, _encodeSubscriptionData(vars.sdata));
token.settleBalance(subscriber, int256(pendingDistribution));
emit IndexDistributionClaimed(token, publisher, indexId, subscriber, pendingDistribution);
emit SubscriptionDistributionClaimed(token, subscriber, publisher, indexId, pendingDistribution);
cbStates.noopBit = SuperAppDefinitions.AFTER_AGREEMENT_UPDATED_NOOP;
(, newCtx) = AgreementLibrary.callAppAfterCallback(cbStates, vars.cbdata, newCtx);
} else {
// nothing to be recorded in this case
newCtx = ctx;
}
}
function _loadAllData(
ISuperfluidToken token,
address publisher,
address subscriber,
uint32 indexId,
bool requireSubscriptionExisting
)
private view
returns (
bytes32 iId,
bytes32 sId,
IndexData memory idata,
bool subscriptionExists,
SubscriptionData memory sdata
)
{
bool indexExists;
iId = _getPublisherId(publisher, indexId);
sId = _getSubscriptionId(subscriber, iId);
(indexExists, idata) = _getIndexData(token, iId);
if (!indexExists) revert IDA_INDEX_DOES_NOT_EXIST();
(subscriptionExists, sdata) = _getSubscriptionData(token, sId);
if (requireSubscriptionExisting) {
if (!subscriptionExists) {
revert IDA_SUBSCRIPTION_DOES_NOT_EXIST();
}
// sanity check
assert(sdata.publisher == publisher);
assert(sdata.indexId == indexId);
}
}
/**************************************************************************
* internal helpers
*************************************************************************/
function _getPublisherId(
address publisher,
uint32 indexId
)
private pure
returns (bytes32 iId)
{
return keccak256(abi.encodePacked("publisher", publisher, indexId));
}
function _getSubscriptionId(
address subscriber,
bytes32 iId
)
private pure
returns (bytes32 sId)
{
return keccak256(abi.encodePacked("subscription", subscriber, iId));
}
// # Index data operations
//
// Data packing:
//
// WORD 1: | existence bit | indexValue |
// | 128b | 128b |
// WORD 2: | totalUnitsPending | totalUnitsApproved |
// | 128b | 12b |
function _encodeIndexData(
IndexData memory idata
)
private pure
returns (bytes32[] memory data) {
data = new bytes32[](2);
data[0] = bytes32(
uint256(1 << 128) /* existance bit */ |
uint256(idata.indexValue)
);
data[1] = bytes32(
(uint256(idata.totalUnitsApproved)) |
(uint256(idata.totalUnitsPending) << 128)
);
}
function _hasIndexData(
ISuperfluidToken token,
bytes32 iId
)
private view
returns (bool exist)
{
bytes32[] memory adata = token.getAgreementData(address(this), iId, 2);
uint256 a = uint256(adata[0]);
exist = a > 0;
}
function _getIndexData(
ISuperfluidToken token,
bytes32 iId
)
private view
returns (bool exist, IndexData memory idata)
{
bytes32[] memory adata = token.getAgreementData(address(this), iId, 2);
uint256 a = uint256(adata[0]);
uint256 b = uint256(adata[1]);
exist = a > 0;
if (exist) {
// NOTE We will do an unsafe downcast from uint256 => uint128
// as we know this is safe
// see https://gist.github.com/0xdavinchee/9834dc689543f19ec07872ad7d766b09
idata.indexValue = uint128(a);
idata.totalUnitsApproved = uint128(b);
idata.totalUnitsPending = uint128(b >> 128);
}
}
// # Publisher's deposit amount
//
// It is stored in state slot in one word
function _getPublisherDeposit(
ISuperfluidToken token,
address publisher
)
private view
returns (uint256)
{
bytes32[] memory data = token.getAgreementStateSlot(
address(this),
publisher,
_PUBLISHER_DEPOSIT_STATE_SLOT_ID,
1);
return uint256(data[0]);
}
function _adjustPublisherDeposit(
ISuperfluidToken token,
address publisher,
int256 delta
)
private
{
if (delta == 0) return;
bytes32[] memory data = token.getAgreementStateSlot(
address(this),
publisher,
_PUBLISHER_DEPOSIT_STATE_SLOT_ID,
1);
data[0] = bytes32(uint256(uint256(data[0]).toInt256() + delta));
token.updateAgreementStateSlot(
publisher,
_PUBLISHER_DEPOSIT_STATE_SLOT_ID,
data);
}
// # Subscription data operations
//
// Data packing:
//
// WORD 1: | publisher | RESERVED | indexId | subId |
// | 160b | 32b | 32b | 32b |
// WORD 2: | units | indexValue |
// | 128b | 128b |
function _encodeSubscriptionData(
SubscriptionData memory sdata
)
private pure
returns (bytes32[] memory data)
{
data = new bytes32[](2);
data[0] = bytes32(
(uint256(uint160(sdata.publisher)) << (12*8)) |
(uint256(sdata.indexId) << 32) |
uint256(sdata.subId)
);
data[1] = bytes32(
uint256(sdata.indexValue) |
(uint256(sdata.units) << 128)
);
}
function _getSubscriptionData(
ISuperfluidToken token,
bytes32 sId
)
private view
returns (bool exist, SubscriptionData memory sdata)
{
bytes32[] memory adata = token.getAgreementData(address(this), sId, 2);
uint256 a = uint256(adata[0]);
uint256 b = uint256(adata[1]);
exist = a > 0;
if (exist) {
sdata.publisher = address(uint160(a >> (12*8)));
sdata.indexId = uint32((a >> 32) & type(uint32).max);
sdata.subId = uint32(a & type(uint32).max);
// NOTE We will do an unsafe downcast from uint256 => uint128
// as we know this is safe
// see https://gist.github.com/0xdavinchee/9834dc689543f19ec07872ad7d766b09
sdata.indexValue = uint128(b);
sdata.units = uint128(b >> 128);
}
}
// # Subscription bitmap operations
//
// ## Subscription bitmap state slot
//
// slotId: _SUBSCRIBER_SUBS_BITMAP_STATE_SLOT_ID)
//
// Subscriber can store up to _MAX_NUM_SUBS amount of subscriptions.
// For each subscription approved it allocated with a subId with a value in [0, _MAX_NUM_SUBS).
// The allocation is to fill one bit in the subscription bitmap.
//
// ## Subscription reference state slots
//
// slotId: _SUBSCRIBER_SUB_DATA_STATE_SLOT_ID_START + subId)
//
// It stores the index data ID.
function _findAndFillSubsBitmap(
ISuperfluidToken token,
address subscriber,
bytes32 iId
)
private
returns (uint32 subId)
{
return SlotsBitmapLibrary.findEmptySlotAndFill(
token,
subscriber,
_SUBSCRIBER_SUBS_BITMAP_STATE_SLOT_ID,
_SUBSCRIBER_SUB_DATA_STATE_SLOT_ID_START,
iId);
}
function _clearSubsBitmap(
ISuperfluidToken token,
address subscriber,
uint32 subId
)
private
{
SlotsBitmapLibrary.clearSlot(
token,
subscriber,
_SUBSCRIBER_SUBS_BITMAP_STATE_SLOT_ID,
subId);
}
function _listSubscriptionIds(
ISuperfluidToken token,
address subscriber
)
private view
returns (
uint32[] memory slotIds,
bytes32[] memory sidList)
{
(slotIds, sidList) = SlotsBitmapLibrary.listData(
token,
subscriber,
_SUBSCRIBER_SUBS_BITMAP_STATE_SLOT_ID,
_SUBSCRIBER_SUB_DATA_STATE_SLOT_ID_START);
// map data to subId
for (uint i = 0; i < sidList.length; ++i) {
sidList[i] = _getSubscriptionId(subscriber, sidList[i]);
}
}
}// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.19;
/**
* @title UUPS (Universal Upgradeable Proxy Standard) Shared Library
*/
library UUPSUtils {
/**
* @dev Implementation slot constant.
* Using https://eips.ethereum.org/EIPS/eip-1967 standard
* Storage slot 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
* (obtained as bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)).
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/// @dev Get implementation address.
function implementation() internal view returns (address impl) {
assembly { // solium-disable-line
impl := sload(_IMPLEMENTATION_SLOT)
}
}
/// @dev Set new implementation address.
function setImplementation(address codeAddress) internal {
assembly {
// solium-disable-line
sstore(
_IMPLEMENTATION_SLOT,
codeAddress
)
}
}
}// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.19;
import { UUPSUtils } from "./UUPSUtils.sol";
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
/**
* @title UUPS (Universal Upgradeable Proxy Standard) Proxiable contract.
*/
abstract contract UUPSProxiable is Initializable {
/**
* @dev Get current implementation code address.
*/
function getCodeAddress() public view returns (address codeAddress)
{
return UUPSUtils.implementation();
}
function updateCode(address newAddress) external virtual;
// allows to mark logic contracts as initialized
// solhint-disable-next-line no-empty-blocks
function castrate() external initializer { }
/**
* @dev Proxiable UUID marker function, this would help to avoid wrong logic
* contract to be used for upgrading.
*
* NOTE: The semantics of the UUID deviates from the actual UUPS standard,
* where it is equivalent of _IMPLEMENTATION_SLOT.
*/
function proxiableUUID() public view virtual returns (bytes32);
/**
* @dev Update code address function.
* It is internal, so the derived contract could setup its own permission logic.
*/
function _updateCodeAddress(address newAddress) internal
{
// require UUPSProxy.initializeProxy first
require(UUPSUtils.implementation() != address(0), "UUPSProxiable: not upgradable");
require(
proxiableUUID() == UUPSProxiable(newAddress).proxiableUUID(),
"UUPSProxiable: not compatible logic"
);
require(
address(this) != newAddress,
"UUPSProxiable: proxy loop"
);
UUPSUtils.setImplementation(newAddress);
emit CodeUpdated(proxiableUUID(), newAddress);
}
event CodeUpdated(bytes32 uuid, address codeAddress);
}// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.19;
import {ISuperfluidToken} from "../interfaces/superfluid/ISuperfluidToken.sol";
/**
* @title Slots Bitmap library
* @author Superfluid
* @dev A library implements slots bitmap on Superfluid Token storage
* NOTE:
* - A slots bitmap allows you to iterate through a list of data efficiently.
* - A data slot can be enabled or disabled with the help of bitmap.
* - MAX_NUM_SLOTS is 256 in this implementation (using one uint256)
* - Superfluid token storage usage:
* - getAgreementStateSlot(bitmapStateSlotId) stores the bitmap of enabled data slots
* - getAgreementStateSlot(dataStateSlotIDStart + stotId) stores the data of the slot
*/
library SlotsBitmapLibrary {
uint32 internal constant _MAX_NUM_SLOTS = 256;
function findEmptySlotAndFill(
ISuperfluidToken token,
address account,
uint256 bitmapStateSlotId,
uint256 dataStateSlotIDStart,
bytes32 data
)
public
returns (uint32 slotId)
{
uint256 subsBitmap = uint256(token.getAgreementStateSlot(
address(this),
account,
bitmapStateSlotId, 1)[0]);
for (slotId = 0; slotId < _MAX_NUM_SLOTS; ++slotId) {
if ((uint256(subsBitmap >> slotId) & 1) == 0) {
// update slot data
bytes32[] memory slotData = new bytes32[](1);
slotData[0] = data;
token.updateAgreementStateSlot(
account,
dataStateSlotIDStart + slotId,
slotData);
// update slot map
slotData[0] = bytes32(subsBitmap | (1 << uint256(slotId)));
token.updateAgreementStateSlot(
account,
bitmapStateSlotId,
slotData);
// update the slots
break;
}
}
require(slotId < _MAX_NUM_SLOTS, "SlotBitmap out of bound");
}
function clearSlot(
ISuperfluidToken token,
address account,
uint256 bitmapStateSlotId,
uint32 slotId
)
public
{
uint256 subsBitmap = uint256(token.getAgreementStateSlot(
address(this),
account,
bitmapStateSlotId, 1)[0]);
bytes32[] memory slotData = new bytes32[](1);
// [SECURITY] NOTE: We do not allow clearing of nonexistent slots
assert(subsBitmap & (1 << uint256(slotId)) != 0);
slotData[0] = bytes32(subsBitmap & ~(1 << uint256(slotId)));
// zero the data
token.updateAgreementStateSlot(
account,
bitmapStateSlotId,
slotData);
}
function listData(
ISuperfluidToken token,
address account,
uint256 bitmapStateSlotId,
uint256 dataStateSlotIDStart
)
public view
returns (
uint32[] memory slotIds,
bytes32[] memory dataList)
{
uint256 subsBitmap = uint256(token.getAgreementStateSlot(
address(this),
account,
bitmapStateSlotId, 1)[0]);
slotIds = new uint32[](_MAX_NUM_SLOTS);
dataList = new bytes32[](_MAX_NUM_SLOTS);
// read all slots
uint nSlots;
for (uint32 slotId = 0; slotId < _MAX_NUM_SLOTS; ++slotId) {
if ((uint256(subsBitmap >> slotId) & 1) == 0) continue;
slotIds[nSlots] = slotId;
dataList[nSlots] = token.getAgreementStateSlot(
address(this),
account,
dataStateSlotIDStart + slotId, 1)[0];
++nSlots;
}
// resize memory arrays
assembly {
mstore(slotIds, nSlots)
mstore(dataList, nSlots)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;
import { ISuperToken } from "../superfluid/ISuperToken.sol";
/**
* @title Super ETH (SETH) custom token interface
* @author Superfluid
*/
interface ISETHCustom {
// using native token
function upgradeByETH() external payable;
function upgradeByETHTo(address to) external payable;
function downgradeToETH(uint wad) external;
}
/**
* @title Super ETH (SETH) full interface
* @author Superfluid
*/
// solhint-disable-next-line no-empty-blocks
interface ISETH is ISETHCustom, ISuperToken {}// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;
import { ISuperAgreement } from "./ISuperAgreement.sol";
/**
* @title Superfluid token interface
* @author Superfluid
*/
interface ISuperfluidToken {
/**************************************************************************
* Errors
*************************************************************************/
error SF_TOKEN_AGREEMENT_ALREADY_EXISTS(); // 0xf05521f6
error SF_TOKEN_AGREEMENT_DOES_NOT_EXIST(); // 0xdae18809
error SF_TOKEN_BURN_INSUFFICIENT_BALANCE(); // 0x10ecdf44
error SF_TOKEN_MOVE_INSUFFICIENT_BALANCE(); // 0x2f4cb941
error SF_TOKEN_ONLY_LISTED_AGREEMENT(); // 0xc9ff6644
error SF_TOKEN_ONLY_HOST(); // 0xc51efddd
/**************************************************************************
* Basic information
*************************************************************************/
/**
* @dev Get superfluid host contract address
*/
function getHost() external view returns(address host);
/**
* @dev Encoded liquidation type data mainly used for handling stack to deep errors
*
* @custom:note
* - version: 1
* - liquidationType key:
* - 0 = reward account receives reward (PIC period)
* - 1 = liquidator account receives reward (Pleb period)
* - 2 = liquidator account receives reward (Pirate period/bailout)
*/
struct LiquidationTypeData {
uint256 version;
uint8 liquidationType;
}
/**************************************************************************
* Real-time balance functions
*************************************************************************/
/**
* @dev Calculate the real balance of a user, taking in consideration all agreements of the account
* @param account for the query
* @param timestamp Time of balance
* @return availableBalance Real-time balance
* @return deposit Account deposit
* @return owedDeposit Account owed Deposit
*/
function realtimeBalanceOf(
address account,
uint256 timestamp
)
external view
returns (
int256 availableBalance,
uint256 deposit,
uint256 owedDeposit);
/**
* @notice Calculate the realtime balance given the current host.getNow() value
* @dev realtimeBalanceOf with timestamp equals to block timestamp
* @param account for the query
* @return availableBalance Real-time balance
* @return deposit Account deposit
* @return owedDeposit Account owed Deposit
*/
function realtimeBalanceOfNow(
address account
)
external view
returns (
int256 availableBalance,
uint256 deposit,
uint256 owedDeposit,
uint256 timestamp);
/**
* @notice Check if account is critical
* @dev A critical account is when availableBalance < 0
* @param account The account to check
* @param timestamp The time we'd like to check if the account is critical (should use future)
* @return isCritical Whether the account is critical
*/
function isAccountCritical(
address account,
uint256 timestamp
)
external view
returns(bool isCritical);
/**
* @notice Check if account is critical now (current host.getNow())
* @dev A critical account is when availableBalance < 0
* @param account The account to check
* @return isCritical Whether the account is critical
*/
function isAccountCriticalNow(
address account
)
external view
returns(bool isCritical);
/**
* @notice Check if account is solvent
* @dev An account is insolvent when the sum of deposits for a token can't cover the negative availableBalance
* @param account The account to check
* @param timestamp The time we'd like to check if the account is solvent (should use future)
* @return isSolvent True if the account is solvent, false otherwise
*/
function isAccountSolvent(
address account,
uint256 timestamp
)
external view
returns(bool isSolvent);
/**
* @notice Check if account is solvent now
* @dev An account is insolvent when the sum of deposits for a token can't cover the negative availableBalance
* @param account The account to check
* @return isSolvent True if the account is solvent, false otherwise
*/
function isAccountSolventNow(
address account
)
external view
returns(bool isSolvent);
/**
* @notice Get a list of agreements that is active for the account
* @dev An active agreement is one that has state for the account
* @param account Account to query
* @return activeAgreements List of accounts that have non-zero states for the account
*/
function getAccountActiveAgreements(address account)
external view
returns(ISuperAgreement[] memory activeAgreements);
/**************************************************************************
* Super Agreement hosting functions
*************************************************************************/
/**
* @dev Create a new agreement
* @param id Agreement ID
* @param data Agreement data
*/
function createAgreement(
bytes32 id,
bytes32[] calldata data
)
external;
/**
* @dev Agreement created event
* @param agreementClass Contract address of the agreement
* @param id Agreement ID
* @param data Agreement data
*/
event AgreementCreated(
address indexed agreementClass,
bytes32 id,
bytes32[] data
);
/**
* @dev Get data of the agreement
* @param agreementClass Contract address of the agreement
* @param id Agreement ID
* @return data Data of the agreement
*/
function getAgreementData(
address agreementClass,
bytes32 id,
uint dataLength
)
external view
returns(bytes32[] memory data);
/**
* @dev Create a new agreement
* @param id Agreement ID
* @param data Agreement data
*/
function updateAgreementData(
bytes32 id,
bytes32[] calldata data
)
external;
/**
* @dev Agreement updated event
* @param agreementClass Contract address of the agreement
* @param id Agreement ID
* @param data Agreement data
*/
event AgreementUpdated(
address indexed agreementClass,
bytes32 id,
bytes32[] data
);
/**
* @dev Close the agreement
* @param id Agreement ID
*/
function terminateAgreement(
bytes32 id,
uint dataLength
)
external;
/**
* @dev Agreement terminated event
* @param agreementClass Contract address of the agreement
* @param id Agreement ID
*/
event AgreementTerminated(
address indexed agreementClass,
bytes32 id
);
/**
* @dev Update agreement state slot
* @param account Account to be updated
*
* @custom:note
* - To clear the storage out, provide zero-ed array of intended length
*/
function updateAgreementStateSlot(
address account,
uint256 slotId,
bytes32[] calldata slotData
)
external;
/**
* @dev Agreement account state updated event
* @param agreementClass Contract address of the agreement
* @param account Account updated
* @param slotId slot id of the agreement state
*/
event AgreementStateUpdated(
address indexed agreementClass,
address indexed account,
uint256 slotId
);
/**
* @dev Get data of the slot of the state of an agreement
* @param agreementClass Contract address of the agreement
* @param account Account to query
* @param slotId slot id of the state
* @param dataLength length of the state data
*/
function getAgreementStateSlot(
address agreementClass,
address account,
uint256 slotId,
uint dataLength
)
external view
returns (bytes32[] memory slotData);
/**
* @notice Settle balance from an account by the agreement
* @dev The agreement needs to make sure that the balance delta is balanced afterwards
* @param account Account to query.
* @param delta Amount of balance delta to be settled
*
* @custom:modifiers
* - onlyAgreement
*/
function settleBalance(
address account,
int256 delta
)
external;
/**
* @dev Make liquidation payouts (v2)
* @param id Agreement ID
* @param liquidationTypeData Data regarding the version of the liquidation schema and the type
* @param liquidatorAccount Address of the executor of the liquidation
* @param useDefaultRewardAccount Whether or not the default reward account receives the rewardAmount
* @param targetAccount Account to be liquidated
* @param rewardAmount The amount the rewarded account will receive
* @param targetAccountBalanceDelta The delta amount the target account balance should change by
*
* @custom:note
* - If a bailout is required (bailoutAmount > 0)
* - the actual reward (single deposit) goes to the executor,
* - while the reward account becomes the bailout account
* - total bailout include: bailout amount + reward amount
* - the targetAccount will be bailed out
* - If a bailout is not required
* - the targetAccount will pay the rewardAmount
* - the liquidator (reward account in PIC period) will receive the rewardAmount
*
* @custom:modifiers
* - onlyAgreement
*/
function makeLiquidationPayoutsV2
(
bytes32 id,
bytes memory liquidationTypeData,
address liquidatorAccount,
bool useDefaultRewardAccount,
address targetAccount,
uint256 rewardAmount,
int256 targetAccountBalanceDelta
) external;
/**
* @dev Agreement liquidation event v2 (including agent account)
* @param agreementClass Contract address of the agreement
* @param id Agreement ID
* @param liquidatorAccount Address of the executor of the liquidation
* @param targetAccount Account of the stream sender
* @param rewardAmountReceiver Account that collects the reward or bails out insolvent accounts
* @param rewardAmount The amount the reward recipient account balance should change by
* @param targetAccountBalanceDelta The amount the sender account balance should change by
* @param liquidationTypeData The encoded liquidation type data including the version (how to decode)
*
* @custom:note
* Reward account rule:
* - if the agreement is liquidated during the PIC period
* - the rewardAmountReceiver will get the rewardAmount (remaining deposit), regardless of the liquidatorAccount
* - the targetAccount will pay for the rewardAmount
* - if the agreement is liquidated after the PIC period AND the targetAccount is solvent
* - the rewardAmountReceiver will get the rewardAmount (remaining deposit)
* - the targetAccount will pay for the rewardAmount
* - if the targetAccount is insolvent
* - the liquidatorAccount will get the rewardAmount (single deposit)
* - the default reward account (governance) will pay for both the rewardAmount and bailoutAmount
* - the targetAccount will receive the bailoutAmount
*/
event AgreementLiquidatedV2(
address indexed agreementClass,
bytes32 id,
address indexed liquidatorAccount,
address indexed targetAccount,
address rewardAmountReceiver,
uint256 rewardAmount,
int256 targetAccountBalanceDelta,
bytes liquidationTypeData
);
/**************************************************************************
* Function modifiers for access control and parameter validations
*
* While they cannot be explicitly stated in function definitions, they are
* listed in function definition comments instead for clarity.
*
* NOTE: solidity-coverage not supporting it
*************************************************************************/
/// @dev The msg.sender must be host contract
//modifier onlyHost() virtual;
/// @dev The msg.sender must be a listed agreement.
//modifier onlyAgreement() virtual;
/**************************************************************************
* DEPRECATED
*************************************************************************/
/**
* @dev Agreement liquidation event (DEPRECATED BY AgreementLiquidatedBy)
* @param agreementClass Contract address of the agreement
* @param id Agreement ID
* @param penaltyAccount Account of the agreement to be penalized
* @param rewardAccount Account that collect the reward
* @param rewardAmount Amount of liquidation reward
*
* @custom:deprecated Use AgreementLiquidatedV2 instead
*/
event AgreementLiquidated(
address indexed agreementClass,
bytes32 id,
address indexed penaltyAccount,
address indexed rewardAccount,
uint256 rewardAmount
);
/**
* @dev System bailout occurred (DEPRECATED BY AgreementLiquidatedBy)
* @param bailoutAccount Account that bailout the penalty account
* @param bailoutAmount Amount of account bailout
*
* @custom:deprecated Use AgreementLiquidatedV2 instead
*/
event Bailout(
address indexed bailoutAccount,
uint256 bailoutAmount
);
/**
* @dev Agreement liquidation event (DEPRECATED BY AgreementLiquidatedV2)
* @param liquidatorAccount Account of the agent that performed the liquidation.
* @param agreementClass Contract address of the agreement
* @param id Agreement ID
* @param penaltyAccount Account of the agreement to be penalized
* @param bondAccount Account that collect the reward or bailout accounts
* @param rewardAmount Amount of liquidation reward
* @param bailoutAmount Amount of liquidation bailouot
*
* @custom:deprecated Use AgreementLiquidatedV2 instead
*
* @custom:note
* Reward account rule:
* - if bailout is equal to 0, then
* - the bondAccount will get the rewardAmount,
* - the penaltyAccount will pay for the rewardAmount.
* - if bailout is larger than 0, then
* - the liquidatorAccount will get the rewardAmouont,
* - the bondAccount will pay for both the rewardAmount and bailoutAmount,
* - the penaltyAccount will pay for the rewardAmount while get the bailoutAmount.
*/
event AgreementLiquidatedBy(
address liquidatorAccount,
address indexed agreementClass,
bytes32 id,
address indexed penaltyAccount,
address indexed bondAccount,
uint256 rewardAmount,
uint256 bailoutAmount
);
}// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;
import { ISuperfluid } from "./ISuperfluid.sol";
import { ISuperToken } from "./ISuperToken.sol";
import { ISuperfluidToken } from "./ISuperfluidToken.sol";
/**
* @title Superfluid governance interface
* @author Superfluid
*/
interface ISuperfluidGovernance {
/**************************************************************************
* Errors
*************************************************************************/
error SF_GOV_INVALID_LIQUIDATION_OR_PATRICIAN_PERIOD(); // 0xe171980a
error SF_GOV_MUST_BE_CONTRACT(); // 0x80dddd73
/**
* @dev Replace the current governance with a new governance
*/
function replaceGovernance(
ISuperfluid host,
address newGov) external;
/**
* @dev Register a new agreement class
*/
function registerAgreementClass(
ISuperfluid host,
address agreementClass) external;
/**
* @dev Update logics of the contracts
*
* @custom:note
* - Because they might have inter-dependencies, it is good to have one single function to update them all
*/
function updateContracts(
ISuperfluid host,
address hostNewLogic,
address[] calldata agreementClassNewLogics,
address superTokenFactoryNewLogic,
address beaconNewLogic
) external;
/**
* @dev Update supertoken logic contract to the latest that is managed by the super token factory
*/
function batchUpdateSuperTokenLogic(
ISuperfluid host,
ISuperToken[] calldata tokens) external;
/**
* @dev Update supertoken logic contract to the provided logic contracts.
* Note that this is an overloaded version taking an additional argument `tokenLogics`
*/
function batchUpdateSuperTokenLogic(
ISuperfluid host,
ISuperToken[] calldata tokens,
address[] calldata tokenLogics) external;
/**
* @dev Set configuration as address value
*/
function setConfig(
ISuperfluid host,
ISuperfluidToken superToken,
bytes32 key,
address value
) external;
/**
* @dev Set configuration as uint256 value
*/
function setConfig(
ISuperfluid host,
ISuperfluidToken superToken,
bytes32 key,
uint256 value
) external;
/**
* @dev Clear configuration
*/
function clearConfig(
ISuperfluid host,
ISuperfluidToken superToken,
bytes32 key
) external;
/**
* @dev Get configuration as address value
*/
function getConfigAsAddress(
ISuperfluid host,
ISuperfluidToken superToken,
bytes32 key) external view returns (address value);
/**
* @dev Get configuration as uint256 value
*/
function getConfigAsUint256(
ISuperfluid host,
ISuperfluidToken superToken,
bytes32 key) external view returns (uint256 value);
}// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;
// ISuperfluid.sol can also be used as an umbrella-import for everything Superfluid, hence we should have these unused
// import.
//
// solhint-disable no-unused-import
/// Global definitions
import {
SuperAppDefinitions,
ContextDefinitions,
FlowOperatorDefinitions,
BatchOperation,
SuperfluidGovernanceConfigs
} from "./Definitions.sol";
/// Super token related interfaces:
/// Note: CustomSuperTokenBase is not included for people building CustomSuperToken.
import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.sol";
import { ISuperfluidToken } from "./ISuperfluidToken.sol";
import { ISuperToken } from "./ISuperToken.sol";
import { ISuperTokenFactory } from "./ISuperTokenFactory.sol";
import { ISETH } from "../tokens/ISETH.sol";
/// Superfluid/ERC20x NFTs
import { IFlowNFTBase } from "./IFlowNFTBase.sol";
import { IConstantOutflowNFT } from "./IConstantOutflowNFT.sol";
import { IConstantInflowNFT } from "./IConstantInflowNFT.sol";
import { IPoolAdminNFT } from "../agreements/gdav1/IPoolAdminNFT.sol";
import { IPoolMemberNFT } from "../agreements/gdav1/IPoolMemberNFT.sol";
/// Superfluid agreement interfaces:
import { ISuperAgreement } from "./ISuperAgreement.sol";
import { IConstantFlowAgreementV1 } from "../agreements/IConstantFlowAgreementV1.sol";
import { IInstantDistributionAgreementV1 } from "../agreements/IInstantDistributionAgreementV1.sol";
import { IGeneralDistributionAgreementV1, PoolConfig } from "../agreements/gdav1/IGeneralDistributionAgreementV1.sol";
import { ISuperfluidPool } from "../agreements/gdav1/ISuperfluidPool.sol";
/// Superfluid App interfaces:
import { ISuperApp } from "./ISuperApp.sol";
/// Superfluid governance
import { ISuperfluidGovernance } from "./ISuperfluidGovernance.sol";
/**
* @title Host interface
* @author Superfluid
* @notice This is the central contract of the system where super agreement, super app
* and super token features are connected.
*
* The Superfluid host contract is also the entry point for the protocol users,
* where batch call and meta transaction are provided for UX improvements.
*
*/
interface ISuperfluid {
/**************************************************************************
* Errors
*************************************************************************/
// Superfluid Custom Errors
error HOST_AGREEMENT_CALLBACK_IS_NOT_ACTION(); // 0xef4295f6
error HOST_CANNOT_DOWNGRADE_TO_NON_UPGRADEABLE(); // 0x474e7641
error HOST_CALL_AGREEMENT_WITH_CTX_FROM_WRONG_ADDRESS(); // 0x0cd0ebc2
error HOST_CALL_APP_ACTION_WITH_CTX_FROM_WRONG_ADDRESS(); // 0x473f7bd4
error HOST_INVALID_CONFIG_WORD(); // 0xf4c802a4
error HOST_MAX_256_AGREEMENTS(); // 0x7c281a78
error HOST_NON_UPGRADEABLE(); // 0x14f72c9f
error HOST_NON_ZERO_LENGTH_PLACEHOLDER_CTX(); // 0x67e9985b
error HOST_ONLY_GOVERNANCE(); // 0xc5d22a4e
error HOST_UNKNOWN_BATCH_CALL_OPERATION_TYPE(); // 0xb4770115
error HOST_AGREEMENT_ALREADY_REGISTERED(); // 0xdc9ddba8
error HOST_AGREEMENT_IS_NOT_REGISTERED(); // 0x1c9e9bea
error HOST_MUST_BE_CONTRACT(); // 0xd4f6b30c
error HOST_ONLY_LISTED_AGREEMENT(); // 0x619c5359
error HOST_NEED_MORE_GAS(); // 0xd4f5d496
// App Related Custom Errors
// uses SuperAppDefinitions' App Jail Reasons as _code
error APP_RULE(uint256 _code); // 0xa85ba64f
error HOST_NOT_A_SUPER_APP(); // 0x163cbe43
error HOST_NO_APP_REGISTRATION_PERMISSION(); // 0xb56455f0
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
/**************************************************************************
* Time
*
* > The Oracle: You have the sight now, Neo. You are looking at the world without time.
* > Neo: Then why can't I see what happens to her?
* > The Oracle: We can never see past the choices we don't understand.
* > - The Oracle and Neo conversing about the future of Trinity and the effects of Neo's choices
*************************************************************************/
function getNow() external view returns (uint256);
/**************************************************************************
* Governance
*************************************************************************/
/**
* @dev Get the current governance address of the Superfluid host
*/
function getGovernance() external view returns(ISuperfluidGovernance governance);
/**
* @dev Replace the current governance with a new one
*/
function replaceGovernance(ISuperfluidGovernance newGov) external;
/**
* @dev Governance replaced event
* @param oldGov Address of the old governance contract
* @param newGov Address of the new governance contract
*/
event GovernanceReplaced(ISuperfluidGovernance oldGov, ISuperfluidGovernance newGov);
/**************************************************************************
* Agreement Whitelisting
*************************************************************************/
/**
* @dev Register a new agreement class to the system
* @param agreementClassLogic Initial agreement class code
*
* @custom:modifiers
* - onlyGovernance
*/
function registerAgreementClass(ISuperAgreement agreementClassLogic) external;
/**
* @notice Agreement class registered event
* @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
* @param agreementType The agreement type registered
* @param code Address of the new agreement
*/
event AgreementClassRegistered(bytes32 agreementType, address code);
/**
* @dev Update code of an agreement class
* @param agreementClassLogic New code for the agreement class
*
* @custom:modifiers
* - onlyGovernance
*/
function updateAgreementClass(ISuperAgreement agreementClassLogic) external;
/**
* @notice Agreement class updated event
* @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
* @param agreementType The agreement type updated
* @param code Address of the new agreement
*/
event AgreementClassUpdated(bytes32 agreementType, address code);
/**
* @notice Check if the agreement type is whitelisted
* @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
*/
function isAgreementTypeListed(bytes32 agreementType) external view returns(bool yes);
/**
* @dev Check if the agreement class is whitelisted
*/
function isAgreementClassListed(ISuperAgreement agreementClass) external view returns(bool yes);
/**
* @notice Get agreement class
* @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
*/
function getAgreementClass(bytes32 agreementType) external view returns(ISuperAgreement agreementClass);
/**
* @dev Map list of the agreement classes using a bitmap
* @param bitmap Agreement class bitmap
*/
function mapAgreementClasses(uint256 bitmap)
external view
returns (ISuperAgreement[] memory agreementClasses);
/**
* @notice Create a new bitmask by adding a agreement class to it
* @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
* @param bitmap Agreement class bitmap
*/
function addToAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType)
external view
returns (uint256 newBitmap);
/**
* @notice Create a new bitmask by removing a agreement class from it
* @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
* @param bitmap Agreement class bitmap
*/
function removeFromAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType)
external view
returns (uint256 newBitmap);
/**************************************************************************
* Super Token Factory
**************************************************************************/
/**
* @dev Get the super token factory
* @return factory The factory
*/
function getSuperTokenFactory() external view returns (ISuperTokenFactory factory);
/**
* @dev Get the super token factory logic (applicable to upgradable deployment)
* @return logic The factory logic
*/
function getSuperTokenFactoryLogic() external view returns (address logic);
/**
* @dev Update super token factory
* @param newFactory New factory logic
*/
function updateSuperTokenFactory(ISuperTokenFactory newFactory) external;
/**
* @dev SuperToken factory updated event
* @param newFactory Address of the new factory
*/
event SuperTokenFactoryUpdated(ISuperTokenFactory newFactory);
/**
* @notice Update the super token logic to the latest (canonical) implementation
* if `newLogicOverride` is zero, or to `newLogicOverride` otherwise.
* or to the provided implementation `.
* @dev Refer to ISuperTokenFactory.Upgradability for expected behaviours
*/
function updateSuperTokenLogic(ISuperToken token, address newLogicOverride) external;
/**
* @notice Update the super token logic to the provided one
* @dev newLogic must implement UUPSProxiable with matching proxiableUUID
*/
event SuperTokenLogicUpdated(ISuperToken indexed token, address code);
/**
* @notice Change the SuperToken admin address
* @dev The admin is the only account allowed to update the token logic
* For backward compatibility, the "host" is the default "admin" if unset (address(0)).
*/
function changeSuperTokenAdmin(ISuperToken token, address newAdmin) external;
/**
* @notice Change the implementation address the pool beacon points to
* @dev Updating the logic the beacon points to will update the logic of all the Pool BeaconProxy instances
*/
function updatePoolBeaconLogic(address newBeaconLogic) external;
/**
* @dev Pool Beacon logic updated event
* @param beaconProxy addrss of the beacon proxy
* @param newBeaconLogic address of the new beacon logic
*/
event PoolBeaconLogicUpdated(address indexed beaconProxy, address newBeaconLogic);
/**************************************************************************
* App Registry
*************************************************************************/
/**
* @dev Message sender (must be a contract) registers itself as a super app.
* @param configWord The super app manifest configuration, flags are defined in
* `SuperAppDefinitions`
* @notice On some mainnet deployments, pre-authorization by governance may be needed for this to succeed.
* See https://github.com/superfluid-finance/protocol-monorepo/wiki/Super-App-White-listing-Guide
*/
function registerApp(uint256 configWord) external;
/**
* @dev Registers an app (must be a contract) as a super app.
* @param app The super app address
* @param configWord The super app manifest configuration, flags are defined in
* `SuperAppDefinitions`
* @notice On some mainnet deployments, pre-authorization by governance may be needed for this to succeed.
* See https://github.com/superfluid-finance/protocol-monorepo/wiki/Super-App-White-listing-Guide
*/
function registerApp(ISuperApp app, uint256 configWord) external;
/**
* @dev App registered event
* @param app Address of jailed app
*/
event AppRegistered(ISuperApp indexed app);
/**
* @dev DO NOT USE for new deployments
* @custom:deprecated you should use `registerApp(uint256 configWord) instead.
*/
function registerAppWithKey(uint256 configWord, string calldata registrationKey) external;
/**
* @dev DO NOT USE for new deployments
* @custom:deprecated you should use `registerApp(ISuperApp app, uint256 configWord) instead.
*/
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 payable;
/**
* @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: MIT
pragma solidity >= 0.8.11;
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { ISuperToken } from "./ISuperToken.sol";
/**
* @title Super token factory interface
* @author Superfluid
*/
interface ISuperTokenFactory {
/**************************************************************************
* Errors
*************************************************************************/
error SUPER_TOKEN_FACTORY_ALREADY_EXISTS(); // 0x91d67972
error SUPER_TOKEN_FACTORY_DOES_NOT_EXIST(); // 0x872cac48
error SUPER_TOKEN_FACTORY_UNINITIALIZED(); // 0x1b39b9b4
error SUPER_TOKEN_FACTORY_ONLY_HOST(); // 0x478b8e83
error SUPER_TOKEN_FACTORY_NON_UPGRADEABLE_IS_DEPRECATED(); // 0xc4901a43
error SUPER_TOKEN_FACTORY_ZERO_ADDRESS(); // 0x305c9e82
/**
* @dev Get superfluid host contract address
*/
function getHost() external view returns(address host);
/// @dev Initialize the contract
function initialize() external;
/**
* @notice Get the canonical super token logic.
*/
function getSuperTokenLogic() external view returns (ISuperToken superToken);
/**
* @dev Upgradability modes
*/
enum Upgradability {
/// Non upgradable super token, `host.updateSuperTokenLogic` will revert
NON_UPGRADABLE,
/// Upgradable through `host.updateSuperTokenLogic` operation
SEMI_UPGRADABLE,
/// Always using the latest super token logic
FULL_UPGRADABLE
}
/**
* @notice Create new super token wrapper for the underlying ERC20 token
* @param underlyingToken Underlying ERC20 token
* @param underlyingDecimals Underlying token decimals
* @param upgradability Upgradability mode
* @param name Super token name
* @param symbol Super token symbol
* @param admin Admin address
* @return superToken The deployed and initialized wrapper super token
*/
function createERC20Wrapper(
IERC20Metadata underlyingToken,
uint8 underlyingDecimals,
Upgradability upgradability,
string calldata name,
string calldata symbol,
address admin
)
external
returns (ISuperToken superToken);
/**
* @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(
IERC20Metadata 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
* @param underlyingToken Underlying ERC20 token
* @param upgradability Upgradability mode
* @param name Super token name
* @param symbol Super token symbol
* @param admin Admin address
* @return superToken The deployed and initialized wrapper super token
*/
function createERC20Wrapper(
IERC20Metadata underlyingToken,
Upgradability upgradability,
string calldata name,
string calldata symbol,
address admin
)
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(
IERC20Metadata 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(IERC20Metadata _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: MIT
pragma solidity >= 0.8.11;
import { ISuperfluidToken } from "./ISuperfluidToken.sol";
import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.sol";
import { IConstantOutflowNFT } from "./IConstantOutflowNFT.sol";
import { IConstantInflowNFT } from "./IConstantInflowNFT.sol";
import { IPoolAdminNFT } from "../agreements/gdav1/IPoolAdminNFT.sol";
import { IPoolMemberNFT } from "../agreements/gdav1/IPoolMemberNFT.sol";
/**
* @title Super token (Superfluid Token + ERC20 + ERC777) interface
* @author Superfluid
*/
interface ISuperToken is ISuperfluidToken, IERC20Metadata, 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_ADMIN(); // 0x0484acab
error SUPER_TOKEN_ONLY_GOV_OWNER(); // 0xd9c7ed08
error SUPER_TOKEN_APPROVE_FROM_ZERO_ADDRESS(); // 0x81638627
error SUPER_TOKEN_APPROVE_TO_ZERO_ADDRESS(); // 0xdf070274
error SUPER_TOKEN_BURN_FROM_ZERO_ADDRESS(); // 0xba2ab184
error SUPER_TOKEN_MINT_TO_ZERO_ADDRESS(); // 0x0d243157
error SUPER_TOKEN_TRANSFER_FROM_ZERO_ADDRESS(); // 0xeecd6c9b
error SUPER_TOKEN_TRANSFER_TO_ZERO_ADDRESS(); // 0xe219bd39
error SUPER_TOKEN_NFT_PROXY_ADDRESS_CHANGED(); // 0x6bef249d
/**
* @dev Initialize the contract
*/
function initialize(
IERC20 underlyingToken,
uint8 underlyingDecimals,
string calldata n,
string calldata s
) external;
/**
* @dev Initialize the contract with an admin
*/
function initializeWithAdmin(
IERC20 underlyingToken,
uint8 underlyingDecimals,
string calldata n,
string calldata s,
address admin
) external;
/**
* @notice Changes the admin for the SuperToken
* @dev Only the current admin can call this function
* if admin is address(0), it is implicitly the host address
* @param newAdmin New admin address
*/
function changeAdmin(address newAdmin) external;
event AdminChanged(address indexed oldAdmin, address indexed newAdmin);
/**
* @dev Returns the admin address for the SuperToken
*/
function getAdmin() external view returns (address admin);
/**************************************************************************
* Immutable variables
*************************************************************************/
// solhint-disable-next-line func-name-mixedcase
function CONSTANT_OUTFLOW_NFT() external view returns (IConstantOutflowNFT);
// solhint-disable-next-line func-name-mixedcase
function CONSTANT_INFLOW_NFT() external view returns (IConstantInflowNFT);
// solhint-disable-next-line func-name-mixedcase
function POOL_ADMIN_NFT() external view returns (IPoolAdminNFT);
// solhint-disable-next-line func-name-mixedcase
function POOL_MEMBER_NFT() external view returns (IPoolMemberNFT);
/**************************************************************************
* IERC20Metadata & ERC777
*************************************************************************/
/**
* @dev Returns the name of the token.
*/
function name() external view override(IERC777, IERC20Metadata) returns (string memory);
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() external view override(IERC777, IERC20Metadata) 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(IERC20Metadata) returns (uint8);
/**************************************************************************
* ERC20 & ERC777
*************************************************************************/
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() external view override(IERC777, IERC20) returns (uint256);
/**
* @dev Returns the amount of tokens owned by an account (`owner`).
*/
function balanceOf(address account) external view override(IERC777, IERC20) returns(uint256 balance);
/**************************************************************************
* ERC20
*************************************************************************/
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* @return Returns Success a boolean value indicating whether the operation succeeded.
*
* @custom:emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external override(IERC20) returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* @notice This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external override(IERC20) view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* @return Returns Success a boolean value indicating whether the operation succeeded.
*
* @custom:note Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* @custom:emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external override(IERC20) returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* @return Returns Success a boolean value indicating whether the operation succeeded.
*
* @custom:emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external override(IERC20) returns (bool);
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* @custom:emits an {Approval} event indicating the updated allowance.
*
* @custom:requirements
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* @custom:emits an {Approval} event indicating the updated allowance.
*
* @custom:requirements
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
/**************************************************************************
* ERC777
*************************************************************************/
/**
* @dev Returns the smallest part of the token that is not divisible. This
* means all token operations (creation, movement and destruction) must have
* amounts that are a multiple of this number.
*
* @custom:note For super token contracts, this value is always 1
*/
function granularity() external view override(IERC777) returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* @dev If send or receive hooks are registered for the caller and `recipient`,
* the corresponding functions will be called with `userData` and empty
* `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
*
* @custom:emits a {Sent} event.
*
* @custom:requirements
* - the caller must have at least `amount` tokens.
* - `recipient` cannot be the zero address.
* - if `recipient` is a contract, it must implement the {IERC777Recipient}
* interface.
*/
function send(address recipient, uint256 amount, bytes calldata userData) external override(IERC777);
/**
* @dev Destroys `amount` tokens from the caller's account, reducing the
* total supply and transfers the underlying token to the caller's account.
*
* If a send hook is registered for the caller, the corresponding function
* will be called with `userData` and empty `operatorData`. See {IERC777Sender}.
*
* @custom:emits a {Burned} event.
*
* @custom:requirements
* - the caller must have at least `amount` tokens.
*/
function burn(uint256 amount, bytes calldata userData) external override(IERC777);
/**
* @dev Returns true if an account is an operator of `tokenHolder`.
* Operators can send and burn tokens on behalf of their owners. All
* accounts are their own operator.
*
* See {operatorSend} and {operatorBurn}.
*/
function isOperatorFor(address operator, address tokenHolder) external override(IERC777) view returns (bool);
/**
* @dev Make an account an operator of the caller.
*
* See {isOperatorFor}.
*
* @custom:emits an {AuthorizedOperator} event.
*
* @custom:requirements
* - `operator` cannot be calling address.
*/
function authorizeOperator(address operator) external override(IERC777);
/**
* @dev Revoke an account's operator status for the caller.
*
* See {isOperatorFor} and {defaultOperators}.
*
* @custom:emits a {RevokedOperator} event.
*
* @custom:requirements
* - `operator` cannot be calling address.
*/
function revokeOperator(address operator) external override(IERC777);
/**
* @dev Returns the list of default operators. These accounts are operators
* for all token holders, even if {authorizeOperator} was never called on
* them.
*
* This list is immutable, but individual holders may revoke these via
* {revokeOperator}, in which case {isOperatorFor} will return false.
*/
function defaultOperators() external override(IERC777) view returns (address[] memory);
/**
* @dev Moves `amount` tokens from `sender` to `recipient`. The caller must
* be an operator of `sender`.
*
* If send or receive hooks are registered for `sender` and `recipient`,
* the corresponding functions will be called with `userData` and
* `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
*
* @custom:emits a {Sent} event.
*
* @custom:requirements
* - `sender` cannot be the zero address.
* - `sender` must have at least `amount` tokens.
* - the caller must be an operator for `sender`.
* - `recipient` cannot be the zero address.
* - if `recipient` is a contract, it must implement the {IERC777Recipient}
* interface.
*/
function operatorSend(
address sender,
address recipient,
uint256 amount,
bytes calldata userData,
bytes calldata operatorData
) external override(IERC777);
/**
* @dev Destroys `amount` tokens from `account`, reducing the total supply.
* The caller must be an operator of `account`.
*
* If a send hook is registered for `account`, the corresponding function
* will be called with `userData` and `operatorData`. See {IERC777Sender}.
*
* @custom:emits a {Burned} event.
*
* @custom:requirements
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
* - the caller must be an operator for `account`.
*/
function operatorBurn(
address account,
uint256 amount,
bytes calldata userData,
bytes calldata operatorData
) external override(IERC777);
/**************************************************************************
* SuperToken custom token functions
*************************************************************************/
/**
* @dev Mint new tokens for the account
* If `userData` is not empty, the `tokensReceived` hook is invoked according to ERC777 semantics.
*
* @custom:modifiers
* - onlySelf
*/
function selfMint(
address account,
uint256 amount,
bytes memory userData
) external;
/**
* @dev Burn existing tokens for the account
* If `userData` is not empty, the `tokensToSend` hook is invoked according to ERC777 semantics.
*
* @custom:modifiers
* - onlySelf
*/
function selfBurn(
address account,
uint256 amount,
bytes memory userData
) external;
/**
* @dev Transfer `amount` tokens from the `sender` to `recipient`.
* If `spender` isn't the same as `sender`, checks if `spender` has allowance to
* spend tokens of `sender`.
*
* @custom:modifiers
* - onlySelf
*/
function selfTransferFrom(
address sender,
address spender,
address recipient,
uint256 amount
) external;
/**
* @dev Give `spender`, `amount` allowance to spend the tokens of
* `account`.
*
* @custom:modifiers
* - onlySelf
*/
function selfApproveFor(
address account,
address spender,
uint256 amount
) external;
/**************************************************************************
* SuperToken extra functions
*************************************************************************/
/**
* @dev Transfer all available balance from `msg.sender` to `recipient`
*/
function transferAll(address recipient) external;
/**************************************************************************
* ERC20 wrapping
*************************************************************************/
/**
* @dev Return the underlying token contract
* @return tokenAddr Underlying token address
*/
function getUnderlyingToken() external view returns(address tokenAddr);
/**
* @dev Return the underlying token decimals
* @return underlyingDecimals Underlying token decimals
*/
function getUnderlyingDecimals() external view returns (uint8 underlyingDecimals);
/**
* @dev Return the underlying token conversion rate
* @param amount Number of tokens to be upgraded (in 18 decimals)
* @return underlyingAmount The underlying token amount after scaling
* @return adjustedAmount The super token amount after scaling
*/
function toUnderlyingAmount(uint256 amount)
external
view
returns (uint256 underlyingAmount, uint256 adjustedAmount);
/**
* @dev Upgrade ERC20 to SuperToken.
* @param amount Number of tokens to be upgraded (in 18 decimals)
*
* @custom:note It will use `transferFrom` to get tokens. Before calling this
* function you should `approve` this contract
*/
function upgrade(uint256 amount) external;
/**
* @dev Upgrade ERC20 to SuperToken and transfer immediately
* @param to The account to receive upgraded tokens
* @param amount Number of tokens to be upgraded (in 18 decimals)
* @param userData User data for the TokensRecipient callback
*
* @custom:note It will use `transferFrom` to get tokens. Before calling this
* function you should `approve` this contract
*
* @custom:warning
* - there is potential of reentrancy IF the "to" account is a registered ERC777 recipient.
* @custom:requirements
* - if `userData` is NOT empty AND `to` is a contract, it MUST be a registered ERC777 recipient
* otherwise it reverts.
*/
function upgradeTo(address to, uint256 amount, bytes calldata userData) external;
/**
* @dev Token upgrade event
* @param account Account where tokens are upgraded to
* @param amount Amount of tokens upgraded (in 18 decimals)
*/
event TokenUpgraded(
address indexed account,
uint256 amount
);
/**
* @dev Downgrade SuperToken to ERC20.
* @dev It will call transfer to send tokens
* @param amount Number of tokens to be downgraded
*/
function downgrade(uint256 amount) external;
/**
* @dev Downgrade SuperToken to ERC20 and transfer immediately
* @param to The account to receive downgraded tokens
* @param amount Number of tokens to be downgraded (in 18 decimals)
*/
function downgradeTo(address to, uint256 amount) external;
/**
* @dev Token downgrade event
* @param account Account whose tokens are downgraded
* @param amount Amount of tokens downgraded
*/
event TokenDowngraded(
address indexed account,
uint256 amount
);
/**************************************************************************
* Batch Operations
*************************************************************************/
/**
* @dev Perform ERC20 approve by host contract.
* @param account The account owner to be approved.
* @param spender The spender of account owner's funds.
* @param amount Number of tokens to be approved.
*
* @custom:modifiers
* - onlyHost
*/
function operationApprove(
address account,
address spender,
uint256 amount
) external;
function operationIncreaseAllowance(
address account,
address spender,
uint256 addedValue
) external;
function operationDecreaseAllowance(
address account,
address spender,
uint256 subtractedValue
) external;
/**
* @dev Perform ERC20 transferFrom by host contract.
* @param account The account to spend sender's funds.
* @param spender The account where the funds is sent from.
* @param recipient The recipient of the funds.
* @param amount Number of tokens to be transferred.
*
* @custom:modifiers
* - onlyHost
*/
function operationTransferFrom(
address account,
address spender,
address recipient,
uint256 amount
) external;
/**
* @dev Perform ERC777 send by host contract.
* @param spender The account where the funds is sent from.
* @param recipient The recipient of the funds.
* @param amount Number of tokens to be transferred.
* @param userData Arbitrary user inputted data
*
* @custom:modifiers
* - onlyHost
*/
function operationSend(
address spender,
address recipient,
uint256 amount,
bytes memory userData
) external;
/**
* @dev Upgrade ERC20 to SuperToken by host contract.
* @param account The account to be changed.
* @param amount Number of tokens to be upgraded (in 18 decimals)
*
* @custom:modifiers
* - onlyHost
*/
function operationUpgrade(address account, uint256 amount) external;
/**
* @dev Downgrade ERC20 to SuperToken by host contract.
* @param account The account to be changed.
* @param amount Number of tokens to be downgraded (in 18 decimals)
*
* @custom:modifiers
* - onlyHost
*/
function operationDowngrade(address account, uint256 amount) external;
// Flow NFT events
/**
* @dev Constant Outflow NFT proxy created event
* @param constantOutflowNFT constant outflow nft address
*/
event ConstantOutflowNFTCreated(
IConstantOutflowNFT indexed constantOutflowNFT
);
/**
* @dev Constant Inflow NFT proxy created event
* @param constantInflowNFT constant inflow nft address
*/
event ConstantInflowNFTCreated(
IConstantInflowNFT indexed constantInflowNFT
);
/**
* @dev Pool Admin NFT proxy created event
* @param poolAdminNFT pool admin nft address
*/
event PoolAdminNFTCreated(
IPoolAdminNFT indexed poolAdminNFT
);
/**
* @dev Pool Member NFT proxy created event
* @param poolMemberNFT pool member nft address
*/
event PoolMemberNFTCreated(
IPoolMemberNFT indexed poolMemberNFT
);
/**************************************************************************
* 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: MIT
pragma solidity >= 0.8.11;
import { ISuperToken } from "./ISuperToken.sol";
/**
* @title SuperApp interface
* @author Superfluid
* @dev Be aware of the app being jailed, when the word permitted is used.
*/
interface ISuperApp {
/**
* @dev Callback before a new agreement is created.
* @param superToken The super token used for the agreement.
* @param agreementClass The agreement class address.
* @param agreementId The agreementId
* @param agreementData The agreement data (non-compressed)
* @param ctx The context data.
* @return cbdata A free format in memory data the app can use to pass
* arbitary information to the after-hook callback.
*
* @custom:note
* - It will be invoked with `staticcall`, no state changes are permitted.
* - Only revert with a "reason" is permitted.
*/
function beforeAgreementCreated(
ISuperToken superToken,
address agreementClass,
bytes32 agreementId,
bytes calldata agreementData,
bytes calldata ctx
)
external
view
returns (bytes memory cbdata);
/**
* @dev Callback after a new agreement is created.
* @param superToken The super token used for the agreement.
* @param agreementClass The agreement class address.
* @param agreementId The agreementId
* @param agreementData The agreement data (non-compressed)
* @param cbdata The data returned from the before-hook callback.
* @param ctx The context data.
* @return newCtx The current context of the transaction.
*
* @custom:note
* - State changes is permitted.
* - Only revert with a "reason" is permitted.
*/
function afterAgreementCreated(
ISuperToken superToken,
address agreementClass,
bytes32 agreementId,
bytes calldata agreementData,
bytes calldata cbdata,
bytes calldata ctx
)
external
returns (bytes memory newCtx);
/**
* @dev Callback before a new agreement is updated.
* @param superToken The super token used for the agreement.
* @param agreementClass The agreement class address.
* @param agreementId The agreementId
* @param agreementData The agreement data (non-compressed)
* @param ctx The context data.
* @return cbdata A free format in memory data the app can use to pass
* arbitary information to the after-hook callback.
*
* @custom:note
* - It will be invoked with `staticcall`, no state changes are permitted.
* - Only revert with a "reason" is permitted.
*/
function beforeAgreementUpdated(
ISuperToken superToken,
address agreementClass,
bytes32 agreementId,
bytes calldata agreementData,
bytes calldata ctx
)
external
view
returns (bytes memory cbdata);
/**
* @dev Callback after a new agreement is updated.
* @param superToken The super token used for the agreement.
* @param agreementClass The agreement class address.
* @param agreementId The agreementId
* @param agreementData The agreement data (non-compressed)
* @param cbdata The data returned from the before-hook callback.
* @param ctx The context data.
* @return newCtx The current context of the transaction.
*
* @custom:note
* - State changes is permitted.
* - Only revert with a "reason" is permitted.
*/
function afterAgreementUpdated(
ISuperToken superToken,
address agreementClass,
bytes32 agreementId,
bytes calldata agreementData,
bytes calldata cbdata,
bytes calldata ctx
)
external
returns (bytes memory newCtx);
/**
* @dev Callback before a new agreement is terminated.
* @param superToken The super token used for the agreement.
* @param agreementClass The agreement class address.
* @param agreementId The agreementId
* @param agreementData The agreement data (non-compressed)
* @param ctx The context data.
* @return cbdata A free format in memory data the app can use to pass arbitary information to
* the after-hook callback.
*
* @custom:note
* - It will be invoked with `staticcall`, no state changes are permitted.
* - Revert is not permitted.
*/
function beforeAgreementTerminated(
ISuperToken superToken,
address agreementClass,
bytes32 agreementId,
bytes calldata agreementData,
bytes calldata ctx
)
external
view
returns (bytes memory cbdata);
/**
* @dev Callback after a new agreement is terminated.
* @param superToken The super token used for the agreement.
* @param agreementClass The agreement class address.
* @param agreementId The agreementId
* @param agreementData The agreement data (non-compressed)
* @param cbdata The data returned from the before-hook callback.
* @param ctx The context data.
* @return newCtx The current context of the transaction.
*
* @custom:note
* - State changes is permitted.
* - Revert is not permitted.
*/
function afterAgreementTerminated(
ISuperToken superToken,
address agreementClass,
bytes32 agreementId,
bytes calldata agreementData,
bytes calldata cbdata,
bytes calldata ctx
)
external
returns (bytes memory newCtx);
}// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;
import { ISuperfluidToken } from "./ISuperfluidToken.sol";
/**
* @title Super agreement interface
* @author Superfluid
*/
interface ISuperAgreement {
/**
* @dev Get the type of the agreement class
*/
function agreementType() external view returns (bytes32);
/**
* @dev Calculate the real-time balance for the account of this agreement class
* @param account Account the state belongs to
* @param time Time used for the calculation
* @return dynamicBalance Dynamic balance portion of real-time balance of this agreement
* @return deposit Account deposit amount of this agreement
* @return owedDeposit Account owed deposit amount of this agreement
*/
function realtimeBalanceOf(
ISuperfluidToken token,
address account,
uint256 time
)
external
view
returns (
int256 dynamicBalance,
uint256 deposit,
uint256 owedDeposit
);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;
import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
interface IFlowNFTBase is IERC721Metadata {
// FlowNFTData struct storage packing:
// b = bits
// WORD 1: | superToken | FREE
// | 160b | 96b
// WORD 2: | flowSender | FREE
// | 160b | 96b
// WORD 3: | flowReceiver | flowStartDate | FREE
// | 160b | 32b | 64b
struct FlowNFTData {
address superToken;
address flowSender;
address flowReceiver;
uint32 flowStartDate;
}
/**************************************************************************
* Custom Errors
*************************************************************************/
error CFA_NFT_APPROVE_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); // 0xa3352582
error CFA_NFT_APPROVE_TO_CALLER(); // 0xd3c77329
error CFA_NFT_APPROVE_TO_CURRENT_OWNER(); // 0xe4790b25
error CFA_NFT_INVALID_TOKEN_ID(); // 0xeab95e3b
error CFA_NFT_ONLY_SUPER_TOKEN_FACTORY(); // 0xebb7505b
error CFA_NFT_TRANSFER_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); // 0x2551d606
error CFA_NFT_TRANSFER_FROM_INCORRECT_OWNER(); // 0x5a26c744
error CFA_NFT_TRANSFER_IS_NOT_ALLOWED(); // 0xaa747eca
error CFA_NFT_TRANSFER_TO_ZERO_ADDRESS(); // 0xde06d21e
/**************************************************************************
* Events
*************************************************************************/
/// @notice Informs third-party platforms that NFT metadata should be updated
/// @dev This event comes from https://eips.ethereum.org/EIPS/eip-4906
/// @param tokenId the id of the token that should have its metadata updated
event MetadataUpdate(uint256 tokenId);
/**************************************************************************
* View
*************************************************************************/
/// @notice An external function for querying flow data by `tokenId``
/// @param tokenId the token id
/// @return flowData the flow data associated with `tokenId`
function flowDataByTokenId(
uint256 tokenId
) external view returns (FlowNFTData memory flowData);
/// @notice An external function for computing the deterministic tokenId
/// @dev tokenId = uint256(keccak256(abi.encode(block.chainId, superToken, flowSender, flowReceiver)))
/// @param superToken the super token
/// @param flowSender the flow sender
/// @param flowReceiver the flow receiver
/// @return tokenId the tokenId
function getTokenId(
address superToken,
address flowSender,
address flowReceiver
) external view returns (uint256);
/**************************************************************************
* Write
*************************************************************************/
function initialize(
string memory nftName,
string memory nftSymbol
) external; // initializer;
function triggerMetadataUpdate(uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;
import { ISuperfluidToken } from "./ISuperfluidToken.sol";
import { IFlowNFTBase } from "./IFlowNFTBase.sol";
interface IConstantOutflowNFT is IFlowNFTBase {
/**************************************************************************
* Custom Errors
*************************************************************************/
error COF_NFT_INVALID_SUPER_TOKEN(); // 0x6de98774
error COF_NFT_MINT_TO_AND_FLOW_RECEIVER_SAME(); // 0x0d1d1161
error COF_NFT_MINT_TO_ZERO_ADDRESS(); // 0x43d05e51
error COF_NFT_ONLY_CONSTANT_INFLOW(); // 0xa495a718
error COF_NFT_ONLY_FLOW_AGREEMENTS(); // 0xd367b64f
error COF_NFT_TOKEN_ALREADY_EXISTS(); // 0xe2480183
/**************************************************************************
* Write Functions
*************************************************************************/
/// @notice The onCreate function is called when a new flow is created.
/// @param token the super token passed from the CFA (flowVars)
/// @param flowSender the flow sender
/// @param flowReceiver the flow receiver
function onCreate(ISuperfluidToken token, address flowSender, address flowReceiver) external;
/// @notice The onUpdate function is called when a flow is updated.
/// @param token the super token passed from the CFA (flowVars)
/// @param flowSender the flow sender
/// @param flowReceiver the flow receiver
function onUpdate(ISuperfluidToken token, address flowSender, address flowReceiver) external;
/// @notice The onDelete function is called when a flow is deleted.
/// @param token the super token passed from the CFA (flowVars)
/// @param flowSender the flow sender
/// @param flowReceiver the flow receiver
function onDelete(ISuperfluidToken token, address flowSender, address flowReceiver) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;
import { IFlowNFTBase } from "./IFlowNFTBase.sol";
interface IConstantInflowNFT is IFlowNFTBase {
/**************************************************************************
* Custom Errors
*************************************************************************/
error CIF_NFT_ONLY_CONSTANT_OUTFLOW(); // 0xe81ef57a
/**************************************************************************
* Write Functions
*************************************************************************/
/// @notice The mint function emits the "mint" `Transfer` event.
/// @dev We don't modify storage as this is handled in ConstantOutflowNFT.sol and this function's sole purpose
/// is to inform clients that search for events.
/// @param to the flow receiver (inflow NFT receiver)
/// @param newTokenId the new token id
function mint(address to, uint256 newTokenId) external;
/// @notice This burn function emits the "burn" `Transfer` event.
/// @dev We don't modify storage as this is handled in ConstantOutflowNFT.sol and this function's sole purpose
/// is to inform clients that search for events.
/// @param tokenId desired token id to burn
function burn(uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;
/**
* @title Super app definitions library
* @author Superfluid
*/
library SuperAppDefinitions {
/**************************************************************************
/ App manifest config word
/**************************************************************************/
/*
* App level is a way to allow the app to whitelist what other app it can
* interact with (aka. composite app feature).
*
* For more details, refer to the technical paper of superfluid protocol.
*/
uint256 constant internal APP_LEVEL_MASK = 0xFF;
// The app is at the final level, hence it doesn't want to interact with any other app
uint256 constant internal APP_LEVEL_FINAL = 1 << 0;
// The app is at the second level, it may interact with other final level apps if whitelisted
uint256 constant internal APP_LEVEL_SECOND = 1 << 1;
function getAppCallbackLevel(uint256 configWord) internal pure returns (uint8) {
return uint8(configWord & APP_LEVEL_MASK);
}
uint256 constant internal APP_JAIL_BIT = 1 << 15;
function isAppJailed(uint256 configWord) internal pure returns (bool) {
return (configWord & SuperAppDefinitions.APP_JAIL_BIT) > 0;
}
/**************************************************************************
/ Callback implementation bit masks
/**************************************************************************/
uint256 constant internal AGREEMENT_CALLBACK_NOOP_BITMASKS = 0xFF << 32;
uint256 constant internal BEFORE_AGREEMENT_CREATED_NOOP = 1 << (32 + 0);
uint256 constant internal AFTER_AGREEMENT_CREATED_NOOP = 1 << (32 + 1);
uint256 constant internal BEFORE_AGREEMENT_UPDATED_NOOP = 1 << (32 + 2);
uint256 constant internal AFTER_AGREEMENT_UPDATED_NOOP = 1 << (32 + 3);
uint256 constant internal BEFORE_AGREEMENT_TERMINATED_NOOP = 1 << (32 + 4);
uint256 constant internal AFTER_AGREEMENT_TERMINATED_NOOP = 1 << (32 + 5);
/**************************************************************************
/ App Jail Reasons
/**************************************************************************/
uint256 constant internal APP_RULE_NO_REVERT_ON_TERMINATION_CALLBACK = 10;
uint256 constant internal APP_RULE_NO_CRITICAL_SENDER_ACCOUNT = 11;
uint256 constant internal APP_RULE_NO_CRITICAL_RECEIVER_ACCOUNT = 12;
uint256 constant internal APP_RULE_CTX_IS_READONLY = 20;
uint256 constant internal APP_RULE_CTX_IS_NOT_CLEAN = 21;
uint256 constant internal APP_RULE_CTX_IS_MALFORMATED = 22;
uint256 constant internal APP_RULE_COMPOSITE_APP_IS_NOT_WHITELISTED = 30;
uint256 constant internal APP_RULE_COMPOSITE_APP_IS_JAILED = 31;
uint256 constant internal APP_RULE_MAX_APP_LEVEL_REACHED = 40;
// Validate configWord cleaness for future compatibility, or else may introduce undefined future behavior
function isConfigWordClean(uint256 configWord) internal pure returns (bool) {
return (configWord & ~(APP_LEVEL_MASK | APP_JAIL_BIT | AGREEMENT_CALLBACK_NOOP_BITMASKS)) == uint256(0);
}
}
/**
* @title Context definitions library
* @author Superfluid
*/
library ContextDefinitions {
/**************************************************************************
/ Call info
/**************************************************************************/
// app level
uint256 constant internal CALL_INFO_APP_LEVEL_MASK = 0xFF;
// call type
uint256 constant internal CALL_INFO_CALL_TYPE_SHIFT = 32;
uint256 constant internal CALL_INFO_CALL_TYPE_MASK = 0xF << CALL_INFO_CALL_TYPE_SHIFT;
uint8 constant internal CALL_INFO_CALL_TYPE_AGREEMENT = 1;
uint8 constant internal CALL_INFO_CALL_TYPE_APP_ACTION = 2;
uint8 constant internal CALL_INFO_CALL_TYPE_APP_CALLBACK = 3;
function decodeCallInfo(uint256 callInfo)
internal pure
returns (uint8 appCallbackLevel, uint8 callType)
{
appCallbackLevel = uint8(callInfo & CALL_INFO_APP_LEVEL_MASK);
callType = uint8((callInfo & CALL_INFO_CALL_TYPE_MASK) >> CALL_INFO_CALL_TYPE_SHIFT);
}
function encodeCallInfo(uint8 appCallbackLevel, uint8 callType)
internal pure
returns (uint256 callInfo)
{
return uint256(appCallbackLevel) | (uint256(callType) << CALL_INFO_CALL_TYPE_SHIFT);
}
}
/**
* @title Flow Operator definitions library
* @author Superfluid
*/
library FlowOperatorDefinitions {
uint8 constant internal AUTHORIZE_FLOW_OPERATOR_CREATE = uint8(1) << 0;
uint8 constant internal AUTHORIZE_FLOW_OPERATOR_UPDATE = uint8(1) << 1;
uint8 constant internal AUTHORIZE_FLOW_OPERATOR_DELETE = uint8(1) << 2;
uint8 constant internal AUTHORIZE_FULL_CONTROL =
AUTHORIZE_FLOW_OPERATOR_CREATE | AUTHORIZE_FLOW_OPERATOR_UPDATE | AUTHORIZE_FLOW_OPERATOR_DELETE;
uint8 constant internal REVOKE_FLOW_OPERATOR_CREATE = ~(uint8(1) << 0);
uint8 constant internal REVOKE_FLOW_OPERATOR_UPDATE = ~(uint8(1) << 1);
uint8 constant internal REVOKE_FLOW_OPERATOR_DELETE = ~(uint8(1) << 2);
function isPermissionsClean(uint8 permissions) internal pure returns (bool) {
return (
permissions & ~(AUTHORIZE_FLOW_OPERATOR_CREATE
| AUTHORIZE_FLOW_OPERATOR_UPDATE
| AUTHORIZE_FLOW_OPERATOR_DELETE)
) == uint8(0);
}
}
/**
* @title Batch operation library
* @author Superfluid
*/
library BatchOperation {
/**
* @dev ERC20.approve batch operation type
*
* Call spec:
* ISuperToken(target).operationApprove(
* abi.decode(data, (address spender, uint256 amount))
* )
*/
uint32 constant internal OPERATION_TYPE_ERC20_APPROVE = 1;
/**
* @dev ERC20.transferFrom batch operation type
*
* Call spec:
* ISuperToken(target).operationTransferFrom(
* abi.decode(data, (address sender, address recipient, uint256 amount)
* )
*/
uint32 constant internal OPERATION_TYPE_ERC20_TRANSFER_FROM = 2;
/**
* @dev ERC777.send batch operation type
*
* Call spec:
* ISuperToken(target).operationSend(
* abi.decode(data, (address recipient, uint256 amount, bytes userData)
* )
*/
uint32 constant internal OPERATION_TYPE_ERC777_SEND = 3;
/**
* @dev ERC20.increaseAllowance batch operation type
*
* Call spec:
* ISuperToken(target).operationIncreaseAllowance(
* abi.decode(data, (address account, address spender, uint256 addedValue))
* )
*/
uint32 constant internal OPERATION_TYPE_ERC20_INCREASE_ALLOWANCE = 4;
/**
* @dev ERC20.decreaseAllowance batch operation type
*
* Call spec:
* ISuperToken(target).operationDecreaseAllowance(
* abi.decode(data, (address account, address spender, uint256 subtractedValue))
* )
*/
uint32 constant internal OPERATION_TYPE_ERC20_DECREASE_ALLOWANCE = 5;
/**
* @dev SuperToken.upgrade batch operation type
*
* Call spec:
* ISuperToken(target).operationUpgrade(
* abi.decode(data, (uint256 amount)
* )
*/
uint32 constant internal OPERATION_TYPE_SUPERTOKEN_UPGRADE = 1 + 100;
/**
* @dev SuperToken.downgrade batch operation type
*
* Call spec:
* ISuperToken(target).operationDowngrade(
* abi.decode(data, (uint256 amount)
* )
*/
uint32 constant internal OPERATION_TYPE_SUPERTOKEN_DOWNGRADE = 2 + 100;
/**
* @dev Superfluid.callAgreement batch operation type
*
* Call spec:
* callAgreement(
* ISuperAgreement(target)),
* abi.decode(data, (bytes callData, bytes userData)
* )
*/
uint32 constant internal OPERATION_TYPE_SUPERFLUID_CALL_AGREEMENT = 1 + 200;
/**
* @dev Superfluid.callAppAction batch operation type
*
* Call spec:
* callAppAction(
* ISuperApp(target)),
* data
* )
*/
uint32 constant internal OPERATION_TYPE_SUPERFLUID_CALL_APP_ACTION = 2 + 200;
}
/**
* @title Superfluid governance configs library
* @author Superfluid
*/
library SuperfluidGovernanceConfigs {
bytes32 constant internal SUPERFLUID_REWARD_ADDRESS_CONFIG_KEY =
keccak256("org.superfluid-finance.superfluid.rewardAddress");
bytes32 constant internal CFAV1_PPP_CONFIG_KEY =
keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1.PPPConfiguration");
bytes32 constant internal SUPERTOKEN_MINIMUM_DEPOSIT_KEY =
keccak256("org.superfluid-finance.superfluid.superTokenMinimumDeposit");
function getTrustedForwarderConfigKey(address forwarder) internal pure returns (bytes32) {
return keccak256(abi.encode(
"org.superfluid-finance.superfluid.trustedForwarder",
forwarder));
}
function getAppRegistrationConfigKey(address deployer, string memory registrationKey) internal pure
returns (bytes32)
{
return keccak256(abi.encode(
"org.superfluid-finance.superfluid.appWhiteListing.registrationKey",
deployer,
registrationKey));
}
function getAppFactoryConfigKey(address factory) internal pure returns (bytes32)
{
return keccak256(abi.encode(
"org.superfluid-finance.superfluid.appWhiteListing.factory",
factory));
}
function decodePPPConfig(uint256 pppConfig) internal pure
returns (uint256 liquidationPeriod, uint256 patricianPeriod)
{
liquidationPeriod = (pppConfig >> 32) & type(uint32).max;
patricianPeriod = pppConfig & type(uint32).max;
}
}// SPDX-License-Identifier: AGPLv3
pragma solidity >=0.8.4;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ISuperfluidToken } from "../../superfluid/ISuperfluidToken.sol";
/**
* @dev The interface for any super token pool regardless of the distribution schemes.
*/
interface ISuperfluidPool is IERC20 {
// Structs
struct PoolIndexData {
uint128 totalUnits;
uint32 wrappedSettledAt;
int96 wrappedFlowRate;
int256 wrappedSettledValue;
}
struct MemberData {
uint128 ownedUnits;
uint32 syncedSettledAt;
int96 syncedFlowRate;
int256 syncedSettledValue;
int256 settledValue;
int256 claimedValue;
}
// Custom Errors
error SUPERFLUID_POOL_INVALID_TIME(); // 0x83c35016
error SUPERFLUID_POOL_NO_POOL_MEMBERS(); // 0xe10f405a
error SUPERFLUID_POOL_NO_ZERO_ADDRESS(); // 0x54eb6ee6
error SUPERFLUID_POOL_NOT_POOL_ADMIN_OR_GDA(); // 0x1c5fbdcb
error SUPERFLUID_POOL_NOT_GDA(); // 0xfcbe3f9e
error SUPERFLUID_POOL_TRANSFER_UNITS_NOT_ALLOWED(); // 0x2285efba
// Events
event MemberUnitsUpdated(
ISuperfluidToken indexed token, address indexed member, uint128 oldUnits, uint128 newUnits
);
event DistributionClaimed(
ISuperfluidToken indexed token, address indexed member, int256 claimedAmount, int256 totalClaimed
);
/// @notice A boolean indicating whether pool members can transfer their units
function transferabilityForUnitsOwner() external view returns (bool);
/// @notice A boolean indicating whether addresses other than the pool admin can distribute via the pool
function distributionFromAnyAddress() external view returns (bool);
/// @notice The pool admin
/// @dev The admin is the creator of the pool and has permissions to update member units
/// and is the recipient of the adjustment flow rate
function admin() external view returns (address);
/// @notice The SuperToken for the pool
function superToken() external view returns (ISuperfluidToken);
/// @notice The total units of the pool
function getTotalUnits() external view returns (uint128);
/// @notice The total number of units of connected members
function getTotalConnectedUnits() external view returns (uint128);
/// @notice The total number of units of disconnected members
function getTotalDisconnectedUnits() external view returns (uint128);
/// @notice The total number of units for `memberAddress`
/// @param memberAddress The address of the member
function getUnits(address memberAddress) external view returns (uint128);
/// @notice The total flow rate of the pool
function getTotalFlowRate() external view returns (int96);
/// @notice The flow rate of the connected members
function getTotalConnectedFlowRate() external view returns (int96);
/// @notice The flow rate of the disconnected members
function getTotalDisconnectedFlowRate() external view returns (int96);
/// @notice The balance of all the disconnected members at `time`
/// @param time The time to query
function getDisconnectedBalance(uint32 time) external view returns (int256 balance);
/// @notice The flow rate a member is receiving from the pool
/// @param memberAddress The address of the member
function getMemberFlowRate(address memberAddress) external view returns (int96);
/// @notice The claimable balance for `memberAddr` at `time` in the pool
/// @param memberAddr The address of the member
/// @param time The time to query
function getClaimable(address memberAddr, uint32 time) external view returns (int256);
/// @notice The claimable balance for `memberAddr` at `block.timestamp` in the pool
/// @param memberAddr The address of the member
function getClaimableNow(address memberAddr) external view returns (int256 claimableBalance, uint256 timestamp);
/// @notice Sets `memberAddr` ownedUnits to `newUnits`
/// @param memberAddr The address of the member
/// @param newUnits The new units for the member
function updateMemberUnits(address memberAddr, uint128 newUnits) external returns (bool);
/// @notice Claims the claimable balance for `memberAddr` at `block.timestamp`
/// @param memberAddr The address of the member
function claimAll(address memberAddr) external returns (bool);
/// @notice Claims the claimable balance for `msg.sender` at `block.timestamp`
function claimAll() external returns (bool);
/// @notice Increases the allowance of `spender` by `addedValue`
/// @param spender The address of the spender
/// @param addedValue The amount to increase the allowance by
/// @return true if successful
function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
/// @notice Decreases the allowance of `spender` by `subtractedValue`
/// @param spender The address of the spender
/// @param subtractedValue The amount to decrease the allowance by
/// @return true if successful
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
}// SPDX-License-Identifier: AGPLv3
pragma solidity >=0.8.4;
import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
interface IPoolNFTBase is IERC721Metadata {
error POOL_NFT_APPROVE_TO_CALLER(); // 0x9212b333
error POOL_NFT_ONLY_SUPER_TOKEN_FACTORY(); // 0x1fd7e3d8
error POOL_NFT_INVALID_TOKEN_ID(); // 0x09275994
error POOL_NFT_APPROVE_TO_CURRENT_OWNER(); // 0x020226d3
error POOL_NFT_APPROVE_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); // 0x1e82f255
error POOL_NFT_NOT_REGISTERED_POOL(); // 0x6421912e
error POOL_NFT_TRANSFER_NOT_ALLOWED(); // 0x432fb160
error POOL_NFT_TRANSFER_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); // 0x4028ee0e
/// @notice Informs third-party platforms that NFT metadata should be updated
/// @dev This event comes from https://eips.ethereum.org/EIPS/eip-4906
/// @param tokenId the id of the token that should have its metadata updated
event MetadataUpdate(uint256 tokenId);
function initialize(string memory nftName, string memory nftSymbol) external; // initializer;
function triggerMetadataUpdate(uint256 tokenId) external;
/// @notice Gets the token id
/// @dev For PoolAdminNFT, `account` is admin and for PoolMemberNFT, `account` is member
function getTokenId(address pool, address account) external view returns (uint256 tokenId);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;
import { IPoolNFTBase } from "./IPoolNFTBase.sol";
interface IPoolMemberNFT is IPoolNFTBase {
// PoolMemberNFTData struct storage packing:
// b = bits
// WORD 1: | pool | FREE
// | 160b | 96b
// WORD 2: | member | FREE
// | 160b | 96b
// WORD 3: | units | FREE
// | 128b | 128b
struct PoolMemberNFTData {
address pool;
address member;
uint128 units;
}
/// Errors ///
error POOL_MEMBER_NFT_NO_ZERO_POOL();
error POOL_MEMBER_NFT_NO_ZERO_MEMBER();
error POOL_MEMBER_NFT_NO_UNITS();
error POOL_MEMBER_NFT_HAS_UNITS();
function onCreate(address pool, address member) external;
function onUpdate(address pool, address member) external;
function onDelete(address pool, address member) external;
/// View Functions ///
function poolMemberDataByTokenId(uint256 tokenId) external view returns (PoolMemberNFTData memory data);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;
import { IPoolNFTBase } from "./IPoolNFTBase.sol";
interface IPoolAdminNFT is IPoolNFTBase {
// PoolAdminNFTData struct storage packing:
// b = bits
// WORD 1: | pool | FREE
// | 160b | 96b
// WORD 2: | admin | FREE
// | 160b | 96b
struct PoolAdminNFTData {
address pool;
address admin;
}
/// Write Functions ///
function mint(address pool) external;
function poolAdminDataByTokenId(uint256 tokenId) external view returns (PoolAdminNFTData memory data);
}// SPDX-License-Identifier: AGPLv3
pragma solidity >=0.8.4;
import { ISuperAgreement } from "../../superfluid/ISuperAgreement.sol";
import { ISuperfluidToken } from "../../superfluid/ISuperfluidToken.sol";
import { ISuperfluidPool } from "../../agreements/gdav1/ISuperfluidPool.sol";
struct PoolConfig {
/// @dev if true, the pool members can transfer their owned units
/// else, only the pool admin can manipulate the units for pool members
bool transferabilityForUnitsOwner;
/// @dev if true, anyone can execute distributions via the pool
/// else, only the pool admin can execute distributions via the pool
bool distributionFromAnyAddress;
}
/**
* @title General Distribution Agreement interface
* @author Superfluid
*/
abstract contract IGeneralDistributionAgreementV1 is ISuperAgreement {
// Structs
struct UniversalIndexData {
int96 flowRate;
uint32 settledAt;
uint256 totalBuffer;
bool isPool;
int256 settledValue;
}
struct FlowDistributionData {
uint32 lastUpdated;
int96 flowRate;
uint256 buffer; // stored as uint96
}
struct PoolMemberData {
address pool;
uint32 poolID; // the slot id in the pool's subs bitmap
}
struct StackVarsLiquidation {
ISuperfluidToken token;
int256 availableBalance;
address sender;
bytes32 distributionFlowHash;
int256 signedTotalGDADeposit;
address liquidator;
}
// Custom Errors
error GDA_DISTRIBUTE_FOR_OTHERS_NOT_ALLOWED(); // 0xf67d263e
error GDA_DISTRIBUTE_FROM_ANY_ADDRESS_NOT_ALLOWED(); // 0x7761a5e5
error GDA_FLOW_DOES_NOT_EXIST(); // 0x29f4697e
error GDA_NON_CRITICAL_SENDER(); // 0x666f381d
error GDA_INSUFFICIENT_BALANCE(); // 0x33115c3f
error GDA_NO_NEGATIVE_FLOW_RATE(); // 0x15f25663
error GDA_ADMIN_CANNOT_BE_POOL(); // 0x9ab88a26
error GDA_NOT_POOL_ADMIN(); // 0x3a87e565
error GDA_NO_ZERO_ADDRESS_ADMIN(); // 0x82c5d837
error GDA_ONLY_SUPER_TOKEN_POOL(); // 0x90028c37
// Events
event InstantDistributionUpdated(
ISuperfluidToken indexed token,
ISuperfluidPool indexed pool,
address indexed distributor,
address operator,
uint256 requestedAmount,
uint256 actualAmount,
bytes userData
);
event FlowDistributionUpdated(
ISuperfluidToken indexed token,
ISuperfluidPool indexed pool,
address indexed distributor,
// operator's have permission to liquidate critical flows
// on behalf of others
address operator,
int96 oldFlowRate,
int96 newDistributorToPoolFlowRate,
int96 newTotalDistributionFlowRate,
address adjustmentFlowRecipient,
int96 adjustmentFlowRate,
bytes userData
);
event PoolCreated(ISuperfluidToken indexed token, address indexed admin, ISuperfluidPool pool);
event PoolConnectionUpdated(
ISuperfluidToken indexed token,
ISuperfluidPool indexed pool,
address indexed account,
bool connected,
bytes userData
);
event BufferAdjusted(
ISuperfluidToken indexed token,
ISuperfluidPool indexed pool,
address indexed from,
int256 bufferDelta,
uint256 newBufferAmount,
uint256 totalBufferAmount
);
/// @dev ISuperAgreement.agreementType implementation
function agreementType() external pure override returns (bytes32) {
return keccak256("org.superfluid-finance.agreements.GeneralDistributionAgreement.v1");
}
/// @dev Gets the GDA net flow rate of `account` for `token`.
/// @param token The token address
/// @param account The account address
/// @return net flow rate
function getNetFlow(ISuperfluidToken token, address account) external view virtual returns (int96);
/// @notice Gets the GDA flow rate of `from` to `to` for `token`.
/// @dev This is primarily used to get the flow distribution flow rate from a distributor to a pool or the
/// adjustment flow rate of a pool.
/// @param token The token address
/// @param from The sender address
/// @param to The receiver address (the pool)
/// @return flow rate
function getFlowRate(ISuperfluidToken token, address from, ISuperfluidPool to)
external
view
virtual
returns (int96);
/// @notice Executes an optimistic estimation of what the actual flow distribution flow rate may be.
/// The actual flow distribution flow rate is the flow rate that will be sent from `from`.
/// NOTE: this is only precise in an atomic transaction. DO NOT rely on this if querying off-chain.
/// @dev The difference between the requested flow rate and the actual flow rate is the adjustment flow rate,
/// this adjustment flow rate goes to the pool admin.
/// @param token The token address
/// @param from The sender address
/// @param to The pool address
/// @param requestedFlowRate The requested flow rate
/// @return actualFlowRate and totalDistributionFlowRate
function estimateFlowDistributionActualFlowRate(
ISuperfluidToken token,
address from,
ISuperfluidPool to,
int96 requestedFlowRate
) external view virtual returns (int96 actualFlowRate, int96 totalDistributionFlowRate);
/// @notice Executes an optimistic estimation of what the actual amount distributed may be.
/// The actual amount distributed is the amount that will be sent from `from`.
/// NOTE: this is only precise in an atomic transaction. DO NOT rely on this if querying off-chain.
/// @dev The difference between the requested amount and the actual amount is the adjustment amount.
/// @param token The token address
/// @param from The sender address
/// @param to The pool address
/// @param requestedAmount The requested amount
/// @return actualAmount
function estimateDistributionActualAmount(
ISuperfluidToken token,
address from,
ISuperfluidPool to,
uint256 requestedAmount
) external view virtual returns (uint256 actualAmount);
/// @notice Gets the adjustment flow rate of `pool` for `token`.
/// @param pool The pool address
/// @return adjustment flow rate
function getPoolAdjustmentFlowRate(address pool) external view virtual returns (int96);
////////////////////////////////////////////////////////////////////////////////
// Pool Operations
////////////////////////////////////////////////////////////////////////////////
/// @notice Creates a new pool for `token` where the admin is `admin`.
/// @param token The token address
/// @param admin The admin of the pool
/// @param poolConfig The pool configuration (see PoolConfig struct)
function createPool(ISuperfluidToken token, address admin, PoolConfig memory poolConfig)
external
virtual
returns (ISuperfluidPool pool);
function updateMemberUnits(ISuperfluidPool pool, address memberAddress, uint128 newUnits, bytes calldata ctx)
external
virtual
returns (bytes memory newCtx);
function claimAll(ISuperfluidPool pool, address memberAddress, bytes calldata ctx)
external
virtual
returns (bytes memory newCtx);
/// @notice Connects `msg.sender` to `pool`.
/// @dev This is used to connect a pool to the GDA.
/// @param pool The pool address
/// @param ctx Context bytes (see ISuperfluid.sol for Context struct)
/// @return newCtx the new context bytes
function connectPool(ISuperfluidPool pool, bytes calldata ctx) external virtual returns (bytes memory newCtx);
/// @notice Disconnects `msg.sender` from `pool`.
/// @dev This is used to disconnect a pool from the GDA.
/// @param pool The pool address
/// @param ctx Context bytes (see ISuperfluidPoolAdmin for Context struct)
/// @return newCtx the new context bytes
function disconnectPool(ISuperfluidPool pool, bytes calldata ctx) external virtual returns (bytes memory newCtx);
/// @notice Checks whether `account` is a pool.
/// @param token The token address
/// @param account The account address
/// @return true if `account` is a pool
function isPool(ISuperfluidToken token, address account) external view virtual returns (bool);
/// Check if an address is connected to the pool
function isMemberConnected(ISuperfluidPool pool, address memberAddr) external view virtual returns (bool);
/// Get pool adjustment flow information: (recipient, flowHash, flowRate)
function getPoolAdjustmentFlowInfo(ISuperfluidPool pool) external view virtual returns (address, bytes32, int96);
////////////////////////////////////////////////////////////////////////////////
// Agreement Operations
////////////////////////////////////////////////////////////////////////////////
/// @notice Tries to distribute `requestedAmount` of `token` from `from` to `pool`.
/// @dev NOTE: The actual amount distributed may differ.
/// @param token The token address
/// @param from The sender address
/// @param pool The pool address
/// @param requestedAmount The requested amount
/// @param ctx Context bytes (see ISuperfluidPool for Context struct)
/// @return newCtx the new context bytes
function distribute(
ISuperfluidToken token,
address from,
ISuperfluidPool pool,
uint256 requestedAmount,
bytes calldata ctx
) external virtual returns (bytes memory newCtx);
/// @notice Tries to distributeFlow `requestedFlowRate` of `token` from `from` to `pool`.
/// @dev NOTE: The actual distribution flow rate may differ.
/// @param token The token address
/// @param from The sender address
/// @param pool The pool address
/// @param requestedFlowRate The requested flow rate
/// @param ctx Context bytes (see ISuperfluidPool for Context struct)
/// @return newCtx the new context bytes
function distributeFlow(
ISuperfluidToken token,
address from,
ISuperfluidPool pool,
int96 requestedFlowRate,
bytes calldata ctx
) external virtual returns (bytes memory newCtx);
////////////////////////////////////////////////////////////////////////////////
// Solvency Functions
////////////////////////////////////////////////////////////////////////////////
/**
* @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);
}// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;
import { ISuperAgreement } from "../superfluid/ISuperAgreement.sol";
import { ISuperfluidToken } from "../superfluid/ISuperfluidToken.sol";
/**
* @title Instant Distribution Agreement interface
* @author Superfluid
*
* @notice
* - A publisher can create as many as indices as possibly identifiable with `indexId`.
* - `indexId` is deliberately limited to 32 bits, to avoid the chance for sha-3 collision.
* Despite knowing sha-3 collision is only theoretical.
* - A publisher can create a subscription to an index for any subscriber.
* - A subscription consists of:
* - The index it subscribes to.
* - Number of units subscribed.
* - An index consists of:
* - Current value as `uint128 indexValue`.
* - Total units of the approved subscriptions as `uint128 totalUnitsApproved`.
* - Total units of the non approved subscription as `uint128 totalUnitsPending`.
* - A publisher can update an index with a new value that doesn't decrease.
* - A publisher can update a subscription with any number of units.
* - A publisher or a subscriber can delete a subscription and reset its units to zero.
* - A subscriber must approve the index in order to receive distributions from the publisher
* each time the index is updated.
* - The amount distributed is $$\Delta{index} * units$$
* - Distributions to a non approved subscription stays in the publisher's deposit until:
* - the subscriber approves the subscription (side effect),
* - the publisher updates the subscription (side effect),
* - the subscriber deletes the subscription even if it is never approved (side effect),
* - or the subscriber can explicitly claim them.
*/
abstract contract IInstantDistributionAgreementV1 is ISuperAgreement {
/**************************************************************************
* Errors
*************************************************************************/
error IDA_INDEX_SHOULD_GROW(); // 0xcfdca725
error IDA_OPERATION_NOT_ALLOWED(); // 0x92da6d17
error IDA_INDEX_ALREADY_EXISTS(); // 0x5c02a517
error IDA_INDEX_DOES_NOT_EXIST(); // 0xedeaa63b
error IDA_SUBSCRIPTION_DOES_NOT_EXIST(); // 0xb6c8c980
error IDA_SUBSCRIPTION_ALREADY_APPROVED(); // 0x3eb2f849
error IDA_SUBSCRIPTION_IS_NOT_APPROVED(); // 0x37412573
error IDA_INSUFFICIENT_BALANCE(); // 0x16e759bb
error IDA_ZERO_ADDRESS_SUBSCRIBER(); // 0xc90a4674
/// @dev ISuperAgreement.agreementType implementation
function agreementType() external override pure returns (bytes32) {
return keccak256("org.superfluid-finance.agreements.InstantDistributionAgreement.v1");
}
/**************************************************************************
* Index operations
*************************************************************************/
/**
* @dev Create a new index for the publisher
* @param token Super token address
* @param indexId Id of the index
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* None
*/
function createIndex(
ISuperfluidToken token,
uint32 indexId,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Index created event
* @param token Super token address
* @param publisher Index creator and publisher
* @param indexId The specified indexId of the newly created index
* @param userData The user provided data
*/
event IndexCreated(
ISuperfluidToken indexed token,
address indexed publisher,
uint32 indexed indexId,
bytes userData);
/**
* @dev Query the data of a index
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @return exist Does the index exist
* @return indexValue Value of the current index
* @return totalUnitsApproved Total units approved for the index
* @return totalUnitsPending Total units pending approval for the index
*/
function getIndex(
ISuperfluidToken token,
address publisher,
uint32 indexId)
external
view
virtual
returns(
bool exist,
uint128 indexValue,
uint128 totalUnitsApproved,
uint128 totalUnitsPending);
/**
* @dev Calculate actual distribution amount
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @param amount The amount of tokens desired to be distributed
* @return actualAmount The amount to be distributed after ensuring no rounding errors
* @return newIndexValue The index value given the desired amount of tokens to be distributed
*/
function calculateDistribution(
ISuperfluidToken token,
address publisher,
uint32 indexId,
uint256 amount)
external view
virtual
returns(
uint256 actualAmount,
uint128 newIndexValue);
/**
* @dev Update index value of an index
* @param token Super token address
* @param indexId Id of the index
* @param indexValue Value of the index
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* None
*/
function updateIndex(
ISuperfluidToken token,
uint32 indexId,
uint128 indexValue,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Index updated event
* @param token Super token address
* @param publisher Index updater and publisher
* @param indexId The specified indexId of the updated index
* @param oldIndexValue The previous index value
* @param newIndexValue The updated index value
* @param totalUnitsPending The total units pending when the indexValue was updated
* @param totalUnitsApproved The total units approved when the indexValue was updated
* @param userData The user provided data
*/
event IndexUpdated(
ISuperfluidToken indexed token,
address indexed publisher,
uint32 indexed indexId,
uint128 oldIndexValue,
uint128 newIndexValue,
uint128 totalUnitsPending,
uint128 totalUnitsApproved,
bytes userData);
/**
* @dev Distribute tokens through the index
* @param token Super token address
* @param indexId Id of the index
* @param amount The amount of tokens desired to be distributed
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:note
* - This is a convenient version of updateIndex. It adds to the index
* a delta that equals to `amount / totalUnits`
* - The actual amount distributed could be obtained via
* `calculateDistribution`. This is due to precision error with index
* value and units data range
*
* @custom:callbacks
* None
*/
function distribute(
ISuperfluidToken token,
uint32 indexId,
uint256 amount,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**************************************************************************
* Subscription operations
*************************************************************************/
/**
* @dev Approve the subscription of an index
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* - if subscription exist
* - AgreementCreated callback to the publisher:
* - agreementId is for the subscription
* - if subscription does not exist
* - AgreementUpdated callback to the publisher:
* - agreementId is for the subscription
*/
function approveSubscription(
ISuperfluidToken token,
address publisher,
uint32 indexId,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Index subscribed event
* @param token Super token address
* @param publisher Index publisher
* @param indexId The specified indexId
* @param subscriber The approved subscriber
* @param userData The user provided data
*/
event IndexSubscribed(
ISuperfluidToken indexed token,
address indexed publisher,
uint32 indexed indexId,
address subscriber,
bytes userData);
/**
* @dev Subscription approved event
* @param token Super token address
* @param subscriber The approved subscriber
* @param publisher Index publisher
* @param indexId The specified indexId
* @param userData The user provided data
*/
event SubscriptionApproved(
ISuperfluidToken indexed token,
address indexed subscriber,
address publisher,
uint32 indexId,
bytes userData);
/**
* @notice Revoke the subscription of an index
* @dev "Unapproves" the subscription and moves approved units to pending
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* - AgreementUpdated callback to the publisher:
* - agreementId is for the subscription
*/
function revokeSubscription(
ISuperfluidToken token,
address publisher,
uint32 indexId,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Index unsubscribed event
* @param token Super token address
* @param publisher Index publisher
* @param indexId The specified indexId
* @param subscriber The unsubscribed subscriber
* @param userData The user provided data
*/
event IndexUnsubscribed(
ISuperfluidToken indexed token,
address indexed publisher,
uint32 indexed indexId,
address subscriber,
bytes userData);
/**
* @dev Subscription approved event
* @param token Super token address
* @param subscriber The approved subscriber
* @param publisher Index publisher
* @param indexId The specified indexId
* @param userData The user provided data
*/
event SubscriptionRevoked(
ISuperfluidToken indexed token,
address indexed subscriber,
address publisher,
uint32 indexId,
bytes userData);
/**
* @dev Update the nuber of units of a subscription
* @param token Super token address
* @param indexId Id of the index
* @param subscriber The subscriber of the index
* @param units Number of units of the subscription
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* - if subscription exist
* - AgreementCreated callback to the subscriber:
* - agreementId is for the subscription
* - if subscription does not exist
* - AgreementUpdated callback to the subscriber:
* - agreementId is for the subscription
*/
function updateSubscription(
ISuperfluidToken token,
uint32 indexId,
address subscriber,
uint128 units,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Index units updated event
* @param token Super token address
* @param publisher Index publisher
* @param indexId The specified indexId
* @param subscriber The subscriber units updated
* @param units The new units amount
* @param userData The user provided data
*/
event IndexUnitsUpdated(
ISuperfluidToken indexed token,
address indexed publisher,
uint32 indexed indexId,
address subscriber,
uint128 units,
bytes userData);
/**
* @dev Subscription units updated event
* @param token Super token address
* @param subscriber The subscriber units updated
* @param indexId The specified indexId
* @param publisher Index publisher
* @param units The new units amount
* @param userData The user provided data
*/
event SubscriptionUnitsUpdated(
ISuperfluidToken indexed token,
address indexed subscriber,
address publisher,
uint32 indexId,
uint128 units,
bytes userData);
/**
* @dev Get data of a subscription
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @param subscriber The subscriber of the index
* @return exist Does the subscription exist?
* @return approved Is the subscription approved?
* @return units Units of the suscription
* @return pendingDistribution Pending amount of tokens to be distributed for unapproved subscription
*/
function getSubscription(
ISuperfluidToken token,
address publisher,
uint32 indexId,
address subscriber)
external
view
virtual
returns(
bool exist,
bool approved,
uint128 units,
uint256 pendingDistribution
);
/**
* @notice Get data of a subscription by agreement ID
* @dev indexId (agreementId) is the keccak256 hash of encodePacked("publisher", publisher, indexId)
* @param token Super token address
* @param agreementId The agreement ID
* @return publisher The publisher of the index
* @return indexId Id of the index
* @return approved Is the subscription approved?
* @return units Units of the suscription
* @return pendingDistribution Pending amount of tokens to be distributed for unapproved subscription
*/
function getSubscriptionByID(
ISuperfluidToken token,
bytes32 agreementId)
external
view
virtual
returns(
address publisher,
uint32 indexId,
bool approved,
uint128 units,
uint256 pendingDistribution
);
/**
* @dev List subscriptions of an user
* @param token Super token address
* @param subscriber The subscriber's address
* @return publishers Publishers of the subcriptions
* @return indexIds Indexes of the subscriptions
* @return unitsList Units of the subscriptions
*/
function listSubscriptions(
ISuperfluidToken token,
address subscriber)
external
view
virtual
returns(
address[] memory publishers,
uint32[] memory indexIds,
uint128[] memory unitsList);
/**
* @dev Delete the subscription of an user
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @param subscriber The subscriber's address
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* - if the subscriber called it
* - AgreementTerminated callback to the publsiher:
* - agreementId is for the subscription
* - if the publisher called it
* - AgreementTerminated callback to the subscriber:
* - agreementId is for the subscription
*/
function deleteSubscription(
ISuperfluidToken token,
address publisher,
uint32 indexId,
address subscriber,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Claim pending distributions
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @param subscriber The subscriber's address
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:note The subscription should not be approved yet
*
* @custom:callbacks
* - AgreementUpdated callback to the publisher:
* - agreementId is for the subscription
*/
function claim(
ISuperfluidToken token,
address publisher,
uint32 indexId,
address subscriber,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Index distribution claimed event
* @param token Super token address
* @param publisher Index publisher
* @param indexId The specified indexId
* @param subscriber The subscriber units updated
* @param amount The pending amount claimed
*/
event IndexDistributionClaimed(
ISuperfluidToken indexed token,
address indexed publisher,
uint32 indexed indexId,
address subscriber,
uint256 amount);
/**
* @dev Subscription distribution claimed event
* @param token Super token address
* @param subscriber The subscriber units updated
* @param publisher Index publisher
* @param indexId The specified indexId
* @param amount The pending amount claimed
*/
event SubscriptionDistributionClaimed(
ISuperfluidToken indexed token,
address indexed subscriber,
address publisher,
uint32 indexId,
uint256 amount);
}// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;
import { ISuperAgreement } from "../superfluid/ISuperAgreement.sol";
import { ISuperfluidToken } from "../superfluid/ISuperfluidToken.sol";
/**
* @title Constant Flow Agreement interface
* @author Superfluid
*/
abstract contract IConstantFlowAgreementV1 is ISuperAgreement {
/**************************************************************************
* Errors
*************************************************************************/
error CFA_ACL_NO_SENDER_CREATE(); // 0x4b993136
error CFA_ACL_NO_SENDER_UPDATE(); // 0xedfa0d3b
error CFA_ACL_OPERATOR_NO_CREATE_PERMISSIONS(); // 0xa3eab6ac
error CFA_ACL_OPERATOR_NO_UPDATE_PERMISSIONS(); // 0xac434b5f
error CFA_ACL_OPERATOR_NO_DELETE_PERMISSIONS(); // 0xe30f1bff
error CFA_ACL_FLOW_RATE_ALLOWANCE_EXCEEDED(); // 0xa0645c1f
error CFA_ACL_UNCLEAN_PERMISSIONS(); // 0x7939d66c
error CFA_ACL_NO_SENDER_FLOW_OPERATOR(); // 0xb0ed394d
error CFA_ACL_NO_NEGATIVE_ALLOWANCE(); // 0x86e0377d
error CFA_FLOW_ALREADY_EXISTS(); // 0x801b6863
error CFA_FLOW_DOES_NOT_EXIST(); // 0x5a32bf24
error CFA_INSUFFICIENT_BALANCE(); // 0xea76c9b3
error CFA_ZERO_ADDRESS_SENDER(); // 0x1ce9b067
error CFA_ZERO_ADDRESS_RECEIVER(); // 0x78e02b2a
error CFA_HOOK_OUT_OF_GAS(); // 0x9f76430b
error CFA_DEPOSIT_TOO_BIG(); // 0x752c2b9c
error CFA_FLOW_RATE_TOO_BIG(); // 0x0c9c55c1
error CFA_NON_CRITICAL_SENDER(); // 0xce11b5d1
error CFA_INVALID_FLOW_RATE(); // 0x91acad16
error CFA_NO_SELF_FLOW(); // 0xa47338ef
/// @dev ISuperAgreement.agreementType implementation
function agreementType() external override pure returns (bytes32) {
return keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1");
}
/**
* @notice Get the maximum flow rate allowed with the deposit
* @dev The deposit is clipped and rounded down
* @param deposit Deposit amount used for creating the flow
* @return flowRate The maximum flow rate
*/
function getMaximumFlowRateFromDeposit(
ISuperfluidToken token,
uint256 deposit)
external view virtual
returns (int96 flowRate);
/**
* @notice Get the deposit required for creating the flow
* @dev Calculates the deposit based on the liquidationPeriod and flowRate
* @param flowRate Flow rate to be tested
* @return deposit The deposit amount based on flowRate and liquidationPeriod
* @custom:note
* - if calculated deposit (flowRate * liquidationPeriod) is less
* than the minimum deposit, we use the minimum deposit otherwise
* we use the calculated deposit
*/
function getDepositRequiredForFlowRate(
ISuperfluidToken token,
int96 flowRate)
external view virtual
returns (uint256 deposit);
/**
* @dev Returns whether it is the patrician period based on host.getNow()
* @param account The account we are interested in
* @return isCurrentlyPatricianPeriod Whether it is currently the patrician period dictated by governance
* @return timestamp The value of host.getNow()
*/
function isPatricianPeriodNow(
ISuperfluidToken token,
address account)
external view virtual
returns (bool isCurrentlyPatricianPeriod, uint256 timestamp);
/**
* @dev Returns whether it is the patrician period based on timestamp
* @param account The account we are interested in
* @param timestamp The timestamp we are interested in observing the result of isPatricianPeriod
* @return bool Whether it is currently the patrician period dictated by governance
*/
function isPatricianPeriod(
ISuperfluidToken token,
address account,
uint256 timestamp
)
public view virtual
returns (bool);
/**
* @dev msgSender from `ctx` updates permissions for the `flowOperator` with `flowRateAllowance`
* @param token Super token address
* @param flowOperator The permission grantee address
* @param permissions A bitmask representation of the granted permissions
* @param flowRateAllowance The flow rate allowance the `flowOperator` is granted (only goes down)
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*/
function updateFlowOperatorPermissions(
ISuperfluidToken token,
address flowOperator,
uint8 permissions,
int96 flowRateAllowance,
bytes calldata ctx
)
external virtual
returns(bytes memory newCtx);
/**
* @notice msgSender from `ctx` increases flow rate allowance for the `flowOperator` by `addedFlowRateAllowance`
* @dev if `addedFlowRateAllowance` is negative, we revert with CFA_ACL_NO_NEGATIVE_ALLOWANCE
* @param token Super token address
* @param flowOperator The permission grantee address
* @param addedFlowRateAllowance The flow rate allowance delta
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The new context bytes
*/
function increaseFlowRateAllowance(
ISuperfluidToken token,
address flowOperator,
int96 addedFlowRateAllowance,
bytes calldata ctx
) external virtual returns(bytes memory newCtx);
/**
* @dev msgSender from `ctx` decreases flow rate allowance for the `flowOperator` by `subtractedFlowRateAllowance`
* @dev if `subtractedFlowRateAllowance` is negative, we revert with CFA_ACL_NO_NEGATIVE_ALLOWANCE
* @param token Super token address
* @param flowOperator The permission grantee address
* @param subtractedFlowRateAllowance The flow rate allowance delta
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The new context bytes
*/
function decreaseFlowRateAllowance(
ISuperfluidToken token,
address flowOperator,
int96 subtractedFlowRateAllowance,
bytes calldata ctx
) external virtual returns(bytes memory newCtx);
/**
* @dev msgSender from `ctx` increases flow rate allowance for the `flowOperator` by `addedFlowRateAllowance`
* @dev if `addedFlowRateAllowance` is negative, we revert with CFA_ACL_NO_NEGATIVE_ALLOWANCE
* @param token Super token address
* @param flowOperator The permission grantee address
* @param permissionsToAdd A bitmask representation of the granted permissions to add as a delta
* @param addedFlowRateAllowance The flow rate allowance delta
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The new context bytes
*/
function increaseFlowRateAllowanceWithPermissions(
ISuperfluidToken token,
address flowOperator,
uint8 permissionsToAdd,
int96 addedFlowRateAllowance,
bytes calldata ctx
) external virtual returns(bytes memory newCtx);
/**
* @dev msgSender from `ctx` decreases flow rate allowance for the `flowOperator` by `subtractedFlowRateAllowance`
* @dev if `subtractedFlowRateAllowance` is negative, we revert with CFA_ACL_NO_NEGATIVE_ALLOWANCE
* @param token Super token address
* @param flowOperator The permission grantee address
* @param permissionsToRemove A bitmask representation of the granted permissions to remove as a delta
* @param subtractedFlowRateAllowance The flow rate allowance delta
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The new context bytes
*/
function decreaseFlowRateAllowanceWithPermissions(
ISuperfluidToken token,
address flowOperator,
uint8 permissionsToRemove,
int96 subtractedFlowRateAllowance,
bytes calldata ctx
) external virtual returns(bytes memory newCtx);
/**
* @dev msgSender from `ctx` grants `flowOperator` all permissions with flowRateAllowance as type(int96).max
* @param token Super token address
* @param flowOperator The permission grantee address
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*/
function authorizeFlowOperatorWithFullControl(
ISuperfluidToken token,
address flowOperator,
bytes calldata ctx
)
external virtual
returns(bytes memory newCtx);
/**
* @notice msgSender from `ctx` revokes `flowOperator` create/update/delete permissions
* @dev `permissions` and `flowRateAllowance` will both be set to 0
* @param token Super token address
* @param flowOperator The permission grantee address
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*/
function revokeFlowOperatorWithFullControl(
ISuperfluidToken token,
address flowOperator,
bytes calldata ctx
)
external virtual
returns(bytes memory newCtx);
/**
* @notice Get the permissions of a flow operator between `sender` and `flowOperator` for `token`
* @param token Super token address
* @param sender The permission granter address
* @param flowOperator The permission grantee address
* @return flowOperatorId The keccak256 hash of encoded string "flowOperator", sender and flowOperator
* @return permissions A bitmask representation of the granted permissions
* @return flowRateAllowance The flow rate allowance the `flowOperator` is granted (only goes down)
*/
function getFlowOperatorData(
ISuperfluidToken token,
address sender,
address flowOperator
)
public view virtual
returns (
bytes32 flowOperatorId,
uint8 permissions,
int96 flowRateAllowance
);
/**
* @notice Get flow operator using flowOperatorId
* @param token Super token address
* @param flowOperatorId The keccak256 hash of encoded string "flowOperator", sender and flowOperator
* @return permissions A bitmask representation of the granted permissions
* @return flowRateAllowance The flow rate allowance the `flowOperator` is granted (only goes down)
*/
function getFlowOperatorDataByID(
ISuperfluidToken token,
bytes32 flowOperatorId
)
external view virtual
returns (
uint8 permissions,
int96 flowRateAllowance
);
/**
* @notice Create a flow betwen ctx.msgSender and receiver
* @dev flowId (agreementId) is the keccak256 hash of encoded sender and receiver
* @param token Super token address
* @param receiver Flow receiver address
* @param flowRate New flow rate in amount per second
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* - AgreementCreated
* - agreementId - can be used in getFlowByID
* - agreementData - abi.encode(address flowSender, address flowReceiver)
*
* @custom:note
* - A deposit is taken as safety margin for the solvency agents
* - A extra gas fee may be taken to pay for solvency agent liquidations
*/
function createFlow(
ISuperfluidToken token,
address receiver,
int96 flowRate,
bytes calldata ctx
)
external virtual
returns(bytes memory newCtx);
/**
* @notice Create a flow between sender and receiver
* @dev A flow created by an approved flow operator (see above for details on callbacks)
* @param token Super token address
* @param sender Flow sender address (has granted permissions)
* @param receiver Flow receiver address
* @param flowRate New flow rate in amount per second
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*/
function createFlowByOperator(
ISuperfluidToken token,
address sender,
address receiver,
int96 flowRate,
bytes calldata ctx
)
external virtual
returns(bytes memory newCtx);
/**
* @notice Update the flow rate between ctx.msgSender and receiver
* @dev flowId (agreementId) is the keccak256 hash of encoded sender and receiver
* @param token Super token address
* @param receiver Flow receiver address
* @param flowRate New flow rate in amount per second
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* - AgreementUpdated
* - agreementId - can be used in getFlowByID
* - agreementData - abi.encode(address flowSender, address flowReceiver)
*
* @custom:note
* - Only the flow sender may update the flow rate
* - Even if the flow rate is zero, the flow is not deleted
* from the system
* - Deposit amount will be adjusted accordingly
* - No new gas fee is charged
*/
function updateFlow(
ISuperfluidToken token,
address receiver,
int96 flowRate,
bytes calldata ctx
)
external virtual
returns(bytes memory newCtx);
/**
* @notice Update a flow between sender and receiver
* @dev A flow updated by an approved flow operator (see above for details on callbacks)
* @param token Super token address
* @param sender Flow sender address (has granted permissions)
* @param receiver Flow receiver address
* @param flowRate New flow rate in amount per second
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*/
function updateFlowByOperator(
ISuperfluidToken token,
address sender,
address receiver,
int96 flowRate,
bytes calldata ctx
)
external virtual
returns(bytes memory newCtx);
/**
* @dev Get the flow data between `sender` and `receiver` of `token`
* @param token Super token address
* @param sender Flow sender
* @param receiver Flow receiver
* @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.19;
import {
ISuperfluid,
ISuperfluidToken,
ISuperApp,
SuperAppDefinitions
} from "../interfaces/superfluid/ISuperfluid.sol";
import { ISuperfluidToken } from "../interfaces/superfluid/ISuperfluidToken.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
/**
* @title Agreement Library
* @author Superfluid
* @dev Helper library for building super agreement
*/
library AgreementLibrary {
using SafeCast for uint256;
using SafeCast for int256;
/**************************************************************************
* Context helpers
*************************************************************************/
/**
* @dev Authorize the msg.sender to access token agreement storage
*
* NOTE:
* - msg.sender must be the expected host contract.
* - it should revert on unauthorized access.
*/
function authorizeTokenAccess(ISuperfluidToken token, bytes memory ctx)
internal view
returns (ISuperfluid.Context memory)
{
require(token.getHost() == msg.sender, "unauthorized host");
require(ISuperfluid(msg.sender).isCtxValid(ctx), "invalid ctx");
// [SECURITY] NOTE: we are holding the assumption here that the decoded ctx is correct
// at this point.
return ISuperfluid(msg.sender).decodeCtx(ctx);
}
/**************************************************************************
* Agreement callback helpers
*************************************************************************/
struct CallbackInputs {
ISuperfluidToken token;
address account;
bytes32 agreementId;
bytes agreementData;
uint256 appCreditGranted;
int256 appCreditUsed;
uint256 noopBit;
}
function createCallbackInputs(
ISuperfluidToken token,
address account,
bytes32 agreementId,
bytes memory agreementData
)
internal pure
returns (CallbackInputs memory inputs)
{
inputs.token = token;
inputs.account = account;
inputs.agreementId = agreementId;
inputs.agreementData = agreementData;
}
function callAppBeforeCallback(
CallbackInputs memory inputs,
bytes memory ctx
)
internal
returns(bytes memory cbdata)
{
bool isSuperApp;
bool isJailed;
uint256 noopMask;
(isSuperApp, isJailed, noopMask) = ISuperfluid(msg.sender).getAppManifest(ISuperApp(inputs.account));
if (isSuperApp && !isJailed) {
bytes memory appCtx = _pushCallbackStack(ctx, inputs);
if ((noopMask & inputs.noopBit) == 0) {
bytes memory callData = abi.encodeWithSelector(
_selectorFromNoopBit(inputs.noopBit),
inputs.token,
address(this) /* agreementClass */,
inputs.agreementId,
inputs.agreementData,
new bytes(0) // placeholder ctx
);
cbdata = ISuperfluid(msg.sender).callAppBeforeCallback(
ISuperApp(inputs.account),
callData,
inputs.noopBit == SuperAppDefinitions.BEFORE_AGREEMENT_TERMINATED_NOOP,
appCtx);
}
// [SECURITY] NOTE: ctx should be const, do not modify it ever to ensure callback stack correctness
_popCallbackStack(ctx, 0);
}
}
function callAppAfterCallback(
CallbackInputs memory inputs,
bytes memory cbdata,
bytes /* const */ memory ctx
)
internal
returns (ISuperfluid.Context memory appContext, bytes memory newCtx)
{
bool isSuperApp;
bool isJailed;
uint256 noopMask;
(isSuperApp, isJailed, noopMask) = ISuperfluid(msg.sender).getAppManifest(ISuperApp(inputs.account));
newCtx = ctx;
if (isSuperApp && !isJailed) {
newCtx = _pushCallbackStack(newCtx, inputs);
if ((noopMask & inputs.noopBit) == 0) {
bytes memory callData = abi.encodeWithSelector(
_selectorFromNoopBit(inputs.noopBit),
inputs.token,
address(this) /* agreementClass */,
inputs.agreementId,
inputs.agreementData,
cbdata,
new bytes(0) // placeholder ctx
);
newCtx = ISuperfluid(msg.sender).callAppAfterCallback(
ISuperApp(inputs.account),
callData,
inputs.noopBit == SuperAppDefinitions.AFTER_AGREEMENT_TERMINATED_NOOP,
newCtx);
appContext = ISuperfluid(msg.sender).decodeCtx(newCtx);
// adjust credit used to the range [appCreditUsed..appCreditGranted]
appContext.appCreditUsed = _adjustNewAppCreditUsed(
inputs.appCreditGranted,
appContext.appCreditUsed
);
}
// [SECURITY] NOTE: ctx should be const, do not modify it ever to ensure callback stack correctness
newCtx = _popCallbackStack(ctx, appContext.appCreditUsed);
}
}
/**
* @dev Determines how much app credit the app will use.
* @param appCreditGranted set prior to callback based on input flow
* @param appCallbackDepositDelta set in callback - sum of deposit deltas of callback agreements and
* current flow owed deposit amount
*/
function _adjustNewAppCreditUsed(
uint256 appCreditGranted,
int256 appCallbackDepositDelta
) internal pure returns (int256) {
// NOTE: we use max(0, ...) because appCallbackDepositDelta can be negative and appCallbackDepositDelta
// should never go below 0, otherwise the SuperApp can return more money than borrowed
return max(
0,
// NOTE: we use min(appCreditGranted, appCallbackDepositDelta) to ensure that the SuperApp borrows
// appCreditGranted at most and appCallbackDepositDelta at least (if smaller than appCreditGranted)
min(
appCreditGranted.toInt256(),
appCallbackDepositDelta
)
);
}
function _selectorFromNoopBit(uint256 noopBit)
private pure
returns (bytes4 selector)
{
if (noopBit == SuperAppDefinitions.BEFORE_AGREEMENT_CREATED_NOOP) {
return ISuperApp.beforeAgreementCreated.selector;
} else if (noopBit == SuperAppDefinitions.BEFORE_AGREEMENT_UPDATED_NOOP) {
return ISuperApp.beforeAgreementUpdated.selector;
} else if (noopBit == SuperAppDefinitions.BEFORE_AGREEMENT_TERMINATED_NOOP) {
return ISuperApp.beforeAgreementTerminated.selector;
} else if (noopBit == SuperAppDefinitions.AFTER_AGREEMENT_CREATED_NOOP) {
return ISuperApp.afterAgreementCreated.selector;
} else if (noopBit == SuperAppDefinitions.AFTER_AGREEMENT_UPDATED_NOOP) {
return ISuperApp.afterAgreementUpdated.selector;
} else /* if (noopBit == SuperAppDefinitions.AFTER_AGREEMENT_TERMINATED_NOOP) */ {
return ISuperApp.afterAgreementTerminated.selector;
}
}
function _pushCallbackStack(
bytes memory ctx,
CallbackInputs memory inputs
)
private
returns (bytes memory appCtx)
{
// app credit params stack PUSH
// pass app credit and current credit used to the app,
appCtx = ISuperfluid(msg.sender).appCallbackPush(
ctx,
ISuperApp(inputs.account),
inputs.appCreditGranted,
inputs.appCreditUsed,
inputs.token);
}
function _popCallbackStack(
bytes memory ctx,
int256 appCreditUsedDelta
)
private
returns (bytes memory newCtx)
{
// app credit params stack POP
return ISuperfluid(msg.sender).appCallbackPop(ctx, appCreditUsedDelta);
}
/**************************************************************************
* Misc
*************************************************************************/
function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; }
function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; }
function min(int256 a, int256 b) internal pure returns (int256) { return a > b ? b : a; }
}// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.19;
import { UUPSProxiable } from "../upgradability/UUPSProxiable.sol";
import { ISuperAgreement } from "../interfaces/superfluid/ISuperAgreement.sol";
/**
* @title Superfluid agreement base boilerplate contract
* @author Superfluid
*/
abstract contract AgreementBase is
UUPSProxiable,
ISuperAgreement
{
address immutable internal _host;
// Custom Erorrs
error AGREEMENT_BASE_ONLY_HOST(); // 0x1601d91e
constructor(address host)
{
_host = host;
}
function proxiableUUID()
public view override
returns (bytes32)
{
return ISuperAgreement(this).agreementType();
}
function updateCode(address newAddress)
external override
{
if (msg.sender != _host) revert AGREEMENT_BASE_ONLY_HOST();
return _updateCodeAddress(newAddress);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC777/IERC777.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC777Token standard as defined in the EIP.
*
* This contract uses the
* https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let
* token holders and recipients react to token movements by using setting implementers
* for the associated interfaces in said registry. See {IERC1820Registry} and
* {ERC1820Implementer}.
*/
interface IERC777 {
/**
* @dev Emitted when `amount` tokens are created by `operator` and assigned to `to`.
*
* Note that some additional user `data` and `operatorData` can be logged in the event.
*/
event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);
/**
* @dev Emitted when `operator` destroys `amount` tokens from `account`.
*
* Note that some additional user `data` and `operatorData` can be logged in the event.
*/
event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);
/**
* @dev Emitted when `operator` is made operator for `tokenHolder`.
*/
event AuthorizedOperator(address indexed operator, address indexed tokenHolder);
/**
* @dev Emitted when `operator` is revoked its operator status for `tokenHolder`.
*/
event RevokedOperator(address indexed operator, address indexed tokenHolder);
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the smallest part of the token that is not divisible. This
* means all token operations (creation, movement and destruction) must have
* amounts that are a multiple of this number.
*
* For most token contracts, this value will equal 1.
*/
function granularity() external view returns (uint256);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by an account (`owner`).
*/
function balanceOf(address owner) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* If send or receive hooks are registered for the caller and `recipient`,
* the corresponding functions will be called with `data` and empty
* `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
*
* Emits a {Sent} event.
*
* Requirements
*
* - the caller must have at least `amount` tokens.
* - `recipient` cannot be the zero address.
* - if `recipient` is a contract, it must implement the {IERC777Recipient}
* interface.
*/
function send(address recipient, uint256 amount, bytes calldata data) external;
/**
* @dev Destroys `amount` tokens from the caller's account, reducing the
* total supply.
*
* If a send hook is registered for the caller, the corresponding function
* will be called with `data` and empty `operatorData`. See {IERC777Sender}.
*
* Emits a {Burned} event.
*
* Requirements
*
* - the caller must have at least `amount` tokens.
*/
function burn(uint256 amount, bytes calldata data) external;
/**
* @dev Returns true if an account is an operator of `tokenHolder`.
* Operators can send and burn tokens on behalf of their owners. All
* accounts are their own operator.
*
* See {operatorSend} and {operatorBurn}.
*/
function isOperatorFor(address operator, address tokenHolder) external view returns (bool);
/**
* @dev Make an account an operator of the caller.
*
* See {isOperatorFor}.
*
* Emits an {AuthorizedOperator} event.
*
* Requirements
*
* - `operator` cannot be calling address.
*/
function authorizeOperator(address operator) external;
/**
* @dev Revoke an account's operator status for the caller.
*
* See {isOperatorFor} and {defaultOperators}.
*
* Emits a {RevokedOperator} event.
*
* Requirements
*
* - `operator` cannot be calling address.
*/
function revokeOperator(address operator) external;
/**
* @dev Returns the list of default operators. These accounts are operators
* for all token holders, even if {authorizeOperator} was never called on
* them.
*
* This list is immutable, but individual holders may revoke these via
* {revokeOperator}, in which case {isOperatorFor} will return false.
*/
function defaultOperators() external view returns (address[] memory);
/**
* @dev Moves `amount` tokens from `sender` to `recipient`. The caller must
* be an operator of `sender`.
*
* If send or receive hooks are registered for `sender` and `recipient`,
* the corresponding functions will be called with `data` and
* `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
*
* Emits a {Sent} event.
*
* Requirements
*
* - `sender` cannot be the zero address.
* - `sender` must have at least `amount` tokens.
* - the caller must be an operator for `sender`.
* - `recipient` cannot be the zero address.
* - if `recipient` is a contract, it must implement the {IERC777Recipient}
* interface.
*/
function operatorSend(
address sender,
address recipient,
uint256 amount,
bytes calldata data,
bytes calldata operatorData
) external;
/**
* @dev Destroys `amount` tokens from `account`, reducing the total supply.
* The caller must be an operator of `account`.
*
* If a send hook is registered for `account`, the corresponding function
* will be called with `data` and `operatorData`. See {IERC777Sender}.
*
* Emits a {Burned} event.
*
* Requirements
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
* - the caller must be an operator for `account`.
*/
function operatorBurn(address account, uint256 amount, bytes calldata data, bytes calldata operatorData) external;
event Sent(
address indexed operator,
address indexed from,
address indexed to,
uint256 amount,
bytes data,
bytes operatorData
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/Address.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}{
"remappings": [],
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"libraries": {
"/contracts/libs/SlotsBitmapLibrary.sol": {
"SlotsBitmapLibrary": "0x992805ED822C786BCdBA4Cb1F07b5CadA3bC3CBa"
}
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract ISuperfluid","name":"host","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AGREEMENT_BASE_ONLY_HOST","type":"error"},{"inputs":[],"name":"IDA_INDEX_ALREADY_EXISTS","type":"error"},{"inputs":[],"name":"IDA_INDEX_DOES_NOT_EXIST","type":"error"},{"inputs":[],"name":"IDA_INDEX_SHOULD_GROW","type":"error"},{"inputs":[],"name":"IDA_INSUFFICIENT_BALANCE","type":"error"},{"inputs":[],"name":"IDA_OPERATION_NOT_ALLOWED","type":"error"},{"inputs":[],"name":"IDA_SUBSCRIPTION_ALREADY_APPROVED","type":"error"},{"inputs":[],"name":"IDA_SUBSCRIPTION_DOES_NOT_EXIST","type":"error"},{"inputs":[],"name":"IDA_SUBSCRIPTION_IS_NOT_APPROVED","type":"error"},{"inputs":[],"name":"IDA_ZERO_ADDRESS_SUBSCRIBER","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"uuid","type":"bytes32"},{"indexed":false,"internalType":"address","name":"codeAddress","type":"address"}],"name":"CodeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"publisher","type":"address"},{"indexed":true,"internalType":"uint32","name":"indexId","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"userData","type":"bytes"}],"name":"IndexCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"publisher","type":"address"},{"indexed":true,"internalType":"uint32","name":"indexId","type":"uint32"},{"indexed":false,"internalType":"address","name":"subscriber","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"IndexDistributionClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"publisher","type":"address"},{"indexed":true,"internalType":"uint32","name":"indexId","type":"uint32"},{"indexed":false,"internalType":"address","name":"subscriber","type":"address"},{"indexed":false,"internalType":"bytes","name":"userData","type":"bytes"}],"name":"IndexSubscribed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"publisher","type":"address"},{"indexed":true,"internalType":"uint32","name":"indexId","type":"uint32"},{"indexed":false,"internalType":"address","name":"subscriber","type":"address"},{"indexed":false,"internalType":"uint128","name":"units","type":"uint128"},{"indexed":false,"internalType":"bytes","name":"userData","type":"bytes"}],"name":"IndexUnitsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"publisher","type":"address"},{"indexed":true,"internalType":"uint32","name":"indexId","type":"uint32"},{"indexed":false,"internalType":"address","name":"subscriber","type":"address"},{"indexed":false,"internalType":"bytes","name":"userData","type":"bytes"}],"name":"IndexUnsubscribed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"publisher","type":"address"},{"indexed":true,"internalType":"uint32","name":"indexId","type":"uint32"},{"indexed":false,"internalType":"uint128","name":"oldIndexValue","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"newIndexValue","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"totalUnitsPending","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"totalUnitsApproved","type":"uint128"},{"indexed":false,"internalType":"bytes","name":"userData","type":"bytes"}],"name":"IndexUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"subscriber","type":"address"},{"indexed":false,"internalType":"address","name":"publisher","type":"address"},{"indexed":false,"internalType":"uint32","name":"indexId","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"userData","type":"bytes"}],"name":"SubscriptionApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"subscriber","type":"address"},{"indexed":false,"internalType":"address","name":"publisher","type":"address"},{"indexed":false,"internalType":"uint32","name":"indexId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SubscriptionDistributionClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"subscriber","type":"address"},{"indexed":false,"internalType":"address","name":"publisher","type":"address"},{"indexed":false,"internalType":"uint32","name":"indexId","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"userData","type":"bytes"}],"name":"SubscriptionRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"subscriber","type":"address"},{"indexed":false,"internalType":"address","name":"publisher","type":"address"},{"indexed":false,"internalType":"uint32","name":"indexId","type":"uint32"},{"indexed":false,"internalType":"uint128","name":"units","type":"uint128"},{"indexed":false,"internalType":"bytes","name":"userData","type":"bytes"}],"name":"SubscriptionUnitsUpdated","type":"event"},{"inputs":[],"name":"MAX_NUM_SUBSCRIPTIONS","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SLOTS_BITMAP_LIBRARY_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"agreementType","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"address","name":"publisher","type":"address"},{"internalType":"uint32","name":"indexId","type":"uint32"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"approveSubscription","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"address","name":"publisher","type":"address"},{"internalType":"uint32","name":"indexId","type":"uint32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"calculateDistribution","outputs":[{"internalType":"uint256","name":"actualAmount","type":"uint256"},{"internalType":"uint128","name":"newIndexValue","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"castrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"address","name":"publisher","type":"address"},{"internalType":"uint32","name":"indexId","type":"uint32"},{"internalType":"address","name":"subscriber","type":"address"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"claim","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"uint32","name":"indexId","type":"uint32"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"createIndex","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"address","name":"publisher","type":"address"},{"internalType":"uint32","name":"indexId","type":"uint32"},{"internalType":"address","name":"subscriber","type":"address"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"deleteSubscription","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"uint32","name":"indexId","type":"uint32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"distribute","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCodeAddress","outputs":[{"internalType":"address","name":"codeAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"address","name":"publisher","type":"address"},{"internalType":"uint32","name":"indexId","type":"uint32"}],"name":"getIndex","outputs":[{"internalType":"bool","name":"exist","type":"bool"},{"internalType":"uint128","name":"indexValue","type":"uint128"},{"internalType":"uint128","name":"totalUnitsApproved","type":"uint128"},{"internalType":"uint128","name":"totalUnitsPending","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"address","name":"publisher","type":"address"},{"internalType":"uint32","name":"indexId","type":"uint32"},{"internalType":"address","name":"subscriber","type":"address"}],"name":"getSubscription","outputs":[{"internalType":"bool","name":"exist","type":"bool"},{"internalType":"bool","name":"approved","type":"bool"},{"internalType":"uint128","name":"units","type":"uint128"},{"internalType":"uint256","name":"pendingDistribution","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"bytes32","name":"agreementId","type":"bytes32"}],"name":"getSubscriptionByID","outputs":[{"internalType":"address","name":"publisher","type":"address"},{"internalType":"uint32","name":"indexId","type":"uint32"},{"internalType":"bool","name":"approved","type":"bool"},{"internalType":"uint128","name":"units","type":"uint128"},{"internalType":"uint256","name":"pendingDistribution","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"address","name":"subscriber","type":"address"}],"name":"listSubscriptions","outputs":[{"internalType":"address[]","name":"publishers","type":"address[]"},{"internalType":"uint32[]","name":"indexIds","type":"uint32[]"},{"internalType":"uint128[]","name":"unitsList","type":"uint128[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"realtimeBalanceOf","outputs":[{"internalType":"int256","name":"dynamicBalance","type":"int256"},{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"uint256","name":"owedDeposit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"address","name":"publisher","type":"address"},{"internalType":"uint32","name":"indexId","type":"uint32"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"revokeSubscription","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"updateCode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"uint32","name":"indexId","type":"uint32"},{"internalType":"uint128","name":"indexValue","type":"uint128"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"updateIndex","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidToken","name":"token","type":"address"},{"internalType":"uint32","name":"indexId","type":"uint32"},{"internalType":"address","name":"subscriber","type":"address"},{"internalType":"uint128","name":"units","type":"uint128"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"updateSubscription","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a06040523480156200001157600080fd5b506040516200531638038062005316833981016040819052620000349162000046565b6001600160a01b031660805262000078565b6000602082840312156200005957600080fd5b81516001600160a01b03811681146200007157600080fd5b9392505050565b6080516152826200009460003960006110f301526152826000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c80637fbc7639116100b8578063acafa1b81161007c578063acafa1b814610336578063acf4a6c214610349578063b6dacdb81461035c578063b96731c21461037e578063cd7245c514610391578063d787840a146103e957600080fd5b80637fbc76391461029f578063899baaec146102b25780639903ad38146102e25780639b2e48bc146102ea578063a5653ced1461031857600080fd5b806350d75d25116100ff57806350d75d251461020457806352d1902d1461020c5780635b534051146102225780636041ae96146102665780637730599e1461027957600080fd5b8063232d2b581461013c57806323fc23f3146101655780632e5e74c6146101a95780633fd4176a146101bc57806346951954146101ef575b600080fd5b61014f61014a3660046143b8565b6103fc565b60405161015c9190614493565b60405180910390f35b6101786101733660046144a6565b610b16565b6040805194151585526001600160801b0393841660208601529183169184019190915216606082015260800161015c565b61014f6101b73660046144f1565b610b81565b6101d773992805ed822c786bcdba4cb1f07b5cada3bc3cba81565b6040516001600160a01b03909116815260200161015c565b6102026101fd366004614545565b6110e8565b005b6101d761113d565b61021461116c565b60405190815260200161015c565b610235610230366004614569565b6111d0565b60405161015c9493929190931515845291151560208401526001600160801b03166040830152606082015260800190565b61014f6102743660046145c5565b6112a6565b7f8aedc3b5d4bf031e11a7e2940f7251c005698405d58e02e1c247fed3b1b3a674610214565b61014f6102ad366004614640565b6116cb565b6102c56102c0366004614681565b6117b8565b604080519283526001600160801b0390911660208301520161015c565b61020261185d565b6102fd6102f83660046146d2565b61196b565b6040805193845260208401929092529082015260600161015c565b61032161010081565b60405163ffffffff909116815260200161015c565b61014f6103443660046144f1565b611b76565b61014f6103573660046145c5565b611f7b565b61036f61036a366004614713565b612535565b60405161015c93929190614790565b61014f61038c36600461482d565b61278a565b6103a461039f366004614882565b61288a565b604080516001600160a01b03909616865263ffffffff9094166020860152911515928401929092526001600160801b039091166060830152608082015260a00161015c565b61014f6103f73660046148ae565b61298c565b60606001600160a01b03851661042557604051633242919d60e21b815260040160405180910390fd5b61042d614210565b61043561426e565b606060008061047a8c89898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b90508060a00151925080606001519150506104998b828b8d6000612d14565b60808901521515602080890191909152606088019190915260408088018390529287528251908101909252600082526104d5918d918c91612e07565b925086868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050602086015191965050156105395764040000000060c084015261052f8386612e35565b60a0850152610554565b64010000000060c084015261054e8386612e35565b60a08501525b83602001518015610571575060808401515163ffffffff90811614155b1561064c576105c08460800151608001516001600160801b0316896001600160801b03168660600151602001516001600160801b03166105b19190614928565b6105bb919061493b565b612fec565b6060850180516001600160801b03909216602090920191909152845190516001600160a01b038d169163a1b2bf8b916105f890613059565b6040518363ffffffff1660e01b815260040161061592919061497e565b600060405180830381600087803b15801561062f57600080fd5b505af1158015610643573d6000803e3d6000fd5b50505050610833565b8360200151156106c9576106918460800151608001516001600160801b0316896001600160801b03168660600151604001516001600160801b03166105b19190614928565b6060850180516001600160801b03909216604090920191909152845190516001600160a01b038d169163a1b2bf8b916105f890613059565b6040518060a0016040528063ffffffff80168152602001826001600160a01b031681526020018b63ffffffff1681526020018560600151600001516001600160801b03168152602001896001600160801b031681525084608001819052508a6001600160a01b03166312a6a3f8856040015161074887608001516130f7565b6040518363ffffffff1660e01b815260040161076592919061497e565b600060405180830381600087803b15801561077f57600080fd5b505af1158015610793573d6000803e3d6000fd5b50505050878460600151604001516107ab9190614997565b6060850180516001600160801b03909216604090920191909152845190516001600160a01b038d169163a1b2bf8b916107e390613059565b6040518363ffffffff1660e01b815260040161080092919061497e565b600060405180830381600087803b15801561081a57600080fd5b505af115801561082e573d6000803e3d6000fd5b505050505b60008460800151608001516001600160801b031685608001516060015186606001516000015161086391906149be565b6001600160801b031661087691906149de565b905063ffffffff801685608001516000015163ffffffff160361090f576108a68c836108a184614a0e565b61319e565b6001600160a01b038c1663cf97256d836108bf84614a0e565b6040518363ffffffff1660e01b81526004016108dc929190614a2a565b600060405180830381600087803b1580156108f657600080fd5b505af115801561090a573d6000803e3d6000fd5b505050505b60405163cf97256d60e01b81526001600160a01b038d169063cf97256d9061093d908d908590600401614a2a565b600060405180830381600087803b15801561095757600080fd5b505af115801561096b573d6000803e3d6000fd5b50505050846020015115610a115760608086015151608080880180516001600160801b039384169401939093528251918c16910152604086015190516001600160a01b038e169163a1b2bf8b916109c1906130f7565b6040518363ffffffff1660e01b81526004016109de92919061497e565b600060405180830381600087803b1580156109f857600080fd5b505af1158015610a0c573d6000803e3d6000fd5b505050505b846020015115610a405764080000000060c085015260a0850151610a37908590886132ec565b9650610a609050565b64020000000060c085015260a0850151610a5c908590886132ec565b9650505b8a63ffffffff16826001600160a01b03168d6001600160a01b03167f0115987243fd19d615b5ea62a80372a06a2b37fec378b148ee7a507c5c4c0a398d8d88604051610aae93929190614a43565b60405180910390a4896001600160a01b03168c6001600160a01b03167fe0707ac7efb8b59c22189af8d004ed17dc9e4379e71b9066119b62c182524977848e8d88604051610aff9493929190614a7f565b60405180910390a350505050509695505050505050565b600080600080610b3f604080516060810182526000808252602082018190529181019190915290565b6000610b4b8888613538565b9050610b57898261359f565b90965091508515610b7657815160208301516040840151919650945092505b505093509350935093565b6060610b8b614210565b610b9361426e565b600060606000610bd98c89898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b606081015160a0909101519093509150506001600160a01b038816610c1157604051633242919d60e21b815260040160405180910390fd5b896001600160a01b0316826001600160a01b031614610c43576040516392da6d1760e01b815260040160405180910390fd5b610c518b8b8a8c6001612d14565b6080890152506060870152604080870182905291865281516020810190925260008252610c81918d918b91612e07565b925086868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505064100000000060c087015250909550610cd290508386612e35565b60a08501526080808501519081015160609182015191860151516000926001600160801b0390921691610d04916149be565b6001600160801b0316610d1791906149de565b60808601515190915063ffffffff90811614610d6457846080015160800151856060015160200151610d4991906149be565b60608601516001600160801b03909116602090910152610d97565b846080015160800151856060015160400151610d8091906149be565b60608601516001600160801b039091166040909101525b8b6001600160a01b031663a1b2bf8b8660000151610db88860600151613059565b6040518363ffffffff1660e01b8152600401610dd592919061497e565b600060405180830381600087803b158015610def57600080fd5b505af1158015610e03573d6000803e3d6000fd5b5050505060808501515163ffffffff90811614610e2d57610e2d8c8a8760800151600001516136b3565b60808501515163ffffffff1663fffffffe1901610ebb57610e528c8c6108a184614a0e565b6001600160a01b038c1663cf97256d8c610e6b84614a0e565b6040518363ffffffff1660e01b8152600401610e88929190614a2a565b600060405180830381600087803b158015610ea257600080fd5b505af1158015610eb6573d6000803e3d6000fd5b505050505b6040858101519051632704839760e01b81526004810191909152600260248201526001600160a01b038d1690632704839790604401600060405180830381600087803b158015610f0a57600080fd5b505af1158015610f1e573d6000803e3d6000fd5b505060405163cf97256d60e01b81526001600160a01b038f16925063cf97256d9150610f50908c908590600401614a2a565b600060405180830381600087803b158015610f6a57600080fd5b505af1158015610f7e573d6000803e3d6000fd5b505064200000000060c0870152505060a0850151610f9e908590886132ec565b9050809650508963ffffffff168b6001600160a01b03168d6001600160a01b03167fe1f8e9cd8061e5b251769965bda6ca9ef1674bc6541fb9131039fa53f024d1428c86604051610ff0929190614ac8565b60405180910390a4886001600160a01b03168c6001600160a01b03167f9e02127550b99adc8cc6ee332a36f31338facdbc396cebefce9a047247cd04558d8d8660405161103f93929190614aec565b60405180910390a38963ffffffff168b6001600160a01b03168d6001600160a01b03167f0115987243fd19d615b5ea62a80372a06a2b37fec378b148ee7a507c5c4c0a398c60008760405161109693929190614a43565b60405180910390a4886001600160a01b03168c6001600160a01b03167fe0707ac7efb8b59c22189af8d004ed17dc9e4379e71b9066119b62c1825249778d8d600087604051610aff9493929190614a7f565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461113157604051630b00ec8f60e11b815260040160405180910390fd5b61113a8161373e565b50565b60006111677f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b905090565b6000306001600160a01b0316637730599e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111679190614b1c565b6000806000806000806111fc604080516060810182526000808252602082018190529181019190915290565b6112046142a9565b6112128c8c8b8d6000612d14565b909b50929650909450925090508761123b5760008060008097509750975097505050505061129b565b8051608082015163ffffffff9182169091141597509550866112915780608001516001600160801b03168160600151836000015161127991906149be565b6001600160801b031661128c9190614b35565b611294565b60005b9450505050505b945094509450949050565b60606112b0614210565b6112b861426e565b6000606060006112fe8b89898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b9050806060015192508060a0015191505061131d8a8a848b6001612d14565b6080890181905260608901929092525060408701919091529085525163ffffffff1663fffffffe190161136357604051633741257360e01b815260040160405180910390fd5b6113828a8a866040015160405180602001604052806000815250612e07565b925086868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505064100000000060c0870152509095506113d390508386612e35565b60a08501526080808501519081015160609182015191860151516000926001600160801b0390921691611405916149be565b6001600160801b031661141891906149de565b905084608001516080015185606001516020015161143691906149be565b6060860180516001600160801b0390921660209092019190915260808087015101519051604001516114689190614997565b6060860180516001600160801b03909216604090920191909152855190516001600160a01b038d169163a1b2bf8b916114a090613059565b6040518363ffffffff1660e01b81526004016114bd92919061497e565b600060405180830381600087803b1580156114d757600080fd5b505af11580156114eb573d6000803e3d6000fd5b505050506115028b848760800151600001516136b3565b606080860151516080870180516001600160801b039092169190920152805163ffffffff9052604086015190516001600160a01b038d169163a1b2bf8b91611549906130f7565b6040518363ffffffff1660e01b815260040161156692919061497e565b600060405180830381600087803b15801561158057600080fd5b505af1158015611594573d6000803e3d6000fd5b505060405163cf97256d60e01b81526001600160a01b038e16925063cf97256d91506115c69086908590600401614a2a565b600060405180830381600087803b1580156115e057600080fd5b505af11580156115f4573d6000803e3d6000fd5b505064200000000060c0870152505060a0850151611614908590886132ec565b9050809650508863ffffffff168a6001600160a01b03168c6001600160a01b03167fe1f8e9cd8061e5b251769965bda6ca9ef1674bc6541fb9131039fa53f024d1428686604051611666929190614ac8565b60405180910390a4826001600160a01b03168b6001600160a01b03167f9e02127550b99adc8cc6ee332a36f31338facdbc396cebefce9a047247cd04558c8c866040516116b593929190614aec565b60405180910390a3505050505095945050505050565b6060600061170f8785858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b60608101519091506000806117258a848b613946565b9150915080600001516001600160801b0316886001600160801b031610156117605760405163cfdca72560e01b815260040160405180910390fd5b6117738a848b85858d8a60a001516139a5565b86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929d9c50505050505050505050505050565b60008060006117c78686613538565b90506000806117d6898461359f565b91509150816117f85760405163edeaa63b60e01b815260040160405180910390fd5b60008160400151826020015161180e9190614997565b6001600160801b0316905060006118286105bb838a614b4c565b8351909150611838908290614997565b955061184d826001600160801b038316614b35565b9650505050505094509492505050565b600054610100900460ff161580801561187d5750600054600160ff909116105b806118975750303b158015611897575060005460ff166001145b6118ff5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015611922576000805461ff0019166101001790555b801561113a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a150565b600080600060608061197d8888613bd4565b909250905060005b81518163ffffffff161015611b5a57600061199e6142a9565b600080868563ffffffff16815181106119b9576119b9614b6e565b602002602001015190506119ec8d878763ffffffff16815181106119df576119df614b6e565b6020026020010151613cc7565b9094509250836119fe576119fe614b84565b8063ffffffff16836000015163ffffffff1614611a1d57611a1d614b84565b6001600160a01b038d16634b61cc33308e611a4263ffffffff8616600160801b614928565b60016040518563ffffffff1660e01b8152600401611a639493929190614b9a565b600060405180830381865afa158015611a80573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611aa89190810190614cc0565b600081518110611aba57611aba614b6e565b6020026020010151915050611ae8604080516060810182526000808252602082018190529181019190915290565b611af28d8361359f565b909450905083611b0457611b04614b84565b82608001516001600160801b031683606001518260000151611b2691906149be565b6001600160801b0316611b3991906149de565b611b43908b614cf4565b99505050505080611b5390614d1c565b9050611985565b50611b658888613de3565b935060009250505093509350939050565b6060611bb88784848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b506001600160a01b038416611be057604051633242919d60e21b815260040160405180910390fd5b611be8614210565b611bf061426e565b611bfe8989888a6001612d14565b6080870181905260608701929092525060408501919091529083525163ffffffff90811614611c4057604051633eb2f84960e01b815260040160405180910390fd5b60008260800151608001516001600160801b0316836080015160600151846060015160000151611c7091906149be565b6001600160801b0316611c839190614b35565b9050611ca48a8a856040015160405180602001604052806000815250612e07565b915085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509296505082159150611f3490505764040000000060c0830152611cfc8285612e35565b60a0840152611d0f8a8a6108a184614a0e565b6001600160a01b038a1663cf97256d8a611d2884614a0e565b6040518363ffffffff1660e01b8152600401611d45929190614a2a565b600060405180830381600087803b158015611d5f57600080fd5b505af1158015611d73573d6000803e3d6000fd5b50505050606083810151516080850180516001600160801b039092169190920152604084015190516001600160a01b038c169163a1b2bf8b91611db5906130f7565b6040518363ffffffff1660e01b8152600401611dd292919061497e565b600060405180830381600087803b158015611dec57600080fd5b505af1158015611e00573d6000803e3d6000fd5b505060405163cf97256d60e01b81526001600160a01b038d16925063cf97256d9150611e32908a908590600401614a2a565b600060405180830381600087803b158015611e4c57600080fd5b505af1158015611e60573d6000803e3d6000fd5b505050508763ffffffff16896001600160a01b03168b6001600160a01b03167f467eccd248ef31c8bcef16d94856855799a8783aeef10f3759e43614059a6bb18a85604051611eb0929190614a2a565b60405180910390a4604080516001600160a01b038b8116825263ffffffff8b166020830152918101839052818916918c16907f48a3d91d4a07e4982b081260e24f922bd33bb965882772d6de19c922c3eabdea9060600160405180910390a364080000000060c083015260a0830151611f2b908390866132ec565b9450611f6e9050565b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509296505050505b5050509695505050505050565b6060611f85614210565b611f8d61426e565b600060606000611fd38b89898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b9050806060015192508060a00151915050611ff28a8a848b6000612d14565b60808901521580156020890152606088019190915260408701919091529085526120425760808401515163ffffffff9081161461204257604051633eb2f84960e01b815260040160405180910390fd5b86868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052506040808a015181516020810190925291815294995061209b948f94508e9350909150612e07565b925083602001516121c45764010000000060c08401526120bb8386612e35565b60a08086019190915260408051918201815260008083526001600160a01b038c16602084015263ffffffff8b1691830191909152606080870151516001600160801b031690830152608080830191909152850152835161211e908b908490613e8c565b60808501805163ffffffff909216909152604085015190516001600160a01b038c16916312a6a3f891612150906130f7565b6040518363ffffffff1660e01b815260040161216d92919061497e565b600060405180830381600087803b15801561218757600080fd5b505af115801561219b573d6000803e3d6000fd5b505064020000000060c0860152505060a08401516121bb908490876132ec565b95506124859050565b64040000000060c08401526121d98386612e35565b60a08501526080808501519081015160609182015191860151516000926001600160801b039092169161220b916149be565b6001600160801b031661221e91906149de565b9050846080015160800151856060015160200181815161223e9190614997565b6001600160801b03169052506080808601510151606086015160400180516122679083906149be565b6001600160801b0316905250845160608601516001600160a01b038d169163a1b2bf8b9161229490613059565b6040518363ffffffff1660e01b81526004016122b192919061497e565b600060405180830381600087803b1580156122cb57600080fd5b505af11580156122df573d6000803e3d6000fd5b505050506122f28b8b836108a190614a0e565b6001600160a01b038b1663cf97256d8b61230b84614a0e565b6040518363ffffffff1660e01b8152600401612328929190614a2a565b600060405180830381600087803b15801561234257600080fd5b505af1158015612356573d6000803e3d6000fd5b505060405163cf97256d60e01b81526001600160a01b038e16925063cf97256d91506123889086908590600401614a2a565b600060405180830381600087803b1580156123a257600080fd5b505af11580156123b6573d6000803e3d6000fd5b5050506060808701515160808801516001600160801b039091169101525084516123e3908c908590613e8c565b60808601805163ffffffff909216909152604086015190516001600160a01b038d169163a1b2bf8b91612415906130f7565b6040518363ffffffff1660e01b815260040161243292919061497e565b600060405180830381600087803b15801561244c57600080fd5b505af1158015612460573d6000803e3d6000fd5b505064080000000060c0870152505060a0850151612480908590886132ec565b965050505b8763ffffffff16896001600160a01b03168b6001600160a01b03167f492d2641617cfaf24ac7328f85bc5bdf5113537d78dc7671afa4f49a73f053c285856040516124d1929190614ac8565b60405180910390a4816001600160a01b03168a6001600160a01b03167fc0b8396b655615cdb85fe462a9a1792480816f909cd46d9517a940b386dfbf6b8b8b8560405161252093929190614aec565b60405180910390a35050505095945050505050565b60608060608060606125478787613bd4565b909250905060006125566142a9565b82516001600160401b0381111561256f5761256f614bc3565b604051908082528060200260200182016040528015612598578160200160208202803683370190505b50965082516001600160401b038111156125b4576125b4614bc3565b6040519080825280602002602001820160405280156125dd578160200160208202803683370190505b50955082516001600160401b038111156125f9576125f9614bc3565b604051908082528060200260200182016040528015612622578160200160208202803683370190505b50945060005b83518163ffffffff16101561277e576000858263ffffffff168151811061265157612651614b6e565b602002602001015190506000858363ffffffff168151811061267557612675614b6e565b602002602001015190506126898c82613cc7565b90955093508461269b5761269b614b84565b8163ffffffff16846000015163ffffffff16146126ba576126ba614b84565b83602001518a8463ffffffff16815181106126d7576126d7614b6e565b60200260200101906001600160a01b031690816001600160a01b0316815250508360400151898463ffffffff168151811061271457612714614b6e565b602002602001019063ffffffff16908163ffffffff16815250508360800151888463ffffffff168151811061274b5761274b614b6e565b60200260200101906001600160801b031690816001600160801b03168152505050508061277790614d1c565b9050612628565b50505050509250925092565b606060006127ce8785858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b60608101519091506000806127e48a848b613946565b915091506000816040015182602001516127fe9190614997565b6001600160801b03169050801561284457600061281e6105bb838c614b4c565b90506128428c868d87878689600001516128389190614997565b8c60a001516139a5565b505b87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929e9d5050505050505050505050505050565b60008060008060008060006128b8604080516060810182526000808252602082018190529181019190915290565b6128c06142a9565b6128ca8b8b613cc7565b9094509050836128ed5760405163016d919360e71b815260040160405180910390fd5b80602001519850806040015197506129058989613538565b92506129118b8461359f565b90945091508361292357612923614b84565b8051608082015163ffffffff9182169091141597509550866129795780608001516001600160801b03168160600151836000015161296191906149be565b6001600160801b03166129749190614b35565b61297c565b60005b9450505050509295509295909350565b606060006129d08685858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b606081015190915060006129e48288613538565b90506129f08882613f33565b15612a0e57604051635c02a51760e01b815260040160405180910390fd5b876001600160a01b03166312a6a3f882612a5f604051806060016040528060006001600160801b0316815260200160006001600160801b0316815260200160006001600160801b0316815250613059565b6040518363ffffffff1660e01b8152600401612a7c92919061497e565b600060405180830381600087803b158015612a9657600080fd5b505af1158015612aaa573d6000803e3d6000fd5b505050508663ffffffff16826001600160a01b0316896001600160a01b03167f01ab8663165edfb7390d9e5f75d960a66dacf4f01fa9787e3a731c870d0da9218660a00151604051612afc9190614493565b60405180910390a485858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929b9a5050505050505050505050565b612b4f6142d7565b336001600160a01b0316836001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bbb9190614d4a565b6001600160a01b031614612c055760405162461bcd60e51b81526020600482015260116024820152701d5b985d5d1a1bdc9a5e9959081a1bdcdd607a1b60448201526064016118f6565b604051632fd0a1cd60e21b8152339063bf42873490612c28908590600401614493565b602060405180830381865afa158015612c45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c699190614d77565b612ca35760405162461bcd60e51b815260206004820152600b60248201526a0d2dcecc2d8d2c840c6e8f60ab1b60448201526064016118f6565b604051631fb6491d60e11b81523390633f6c923a90612cc6908590600401614493565b600060405180830381865afa158015612ce3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d0b9190810190614e1e565b90505b92915050565b6040805160608101825260008082526020820181905291810182905281906000612d3c6142a9565b6000612d488a89613538565b9550612d548987613fdf565b9450612d608b8761359f565b9450905080612d825760405163edeaa63b60e01b815260040160405180910390fd5b612d8c8b86613cc7565b90935091508615612df95782612db55760405163016d919360e71b815260040160405180910390fd5b896001600160a01b031682602001516001600160a01b031614612dda57612dda614b84565b8763ffffffff16826040015163ffffffff1614612df957612df9614b84565b509550955095509550959050565b612e0f61426e565b6001600160a01b0394851681529290931660208301526040820152606081019190915290565b6020820151604051633e7d48bd60e21b81526001600160a01b03909116600482015260609060009081908190339063f9f522f490602401606060405180830381865afa158015612e89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ead9190614f24565b91945092509050828015612ebf575081155b15612fe3576000612ed08688614020565b90508660c001518216600003612fd5576000612eef8860c0015161409e565b88516040808b015160608c015182516000815260208101909352612f1b93923092919060448101614f60565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b031990951694909417909352918a015160c08b01519251633a020f0160e11b815291935033926374041e0292612f8a9291869164100000000091909114908890600401614fa5565b6000604051808303816000875af1158015612fa9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612fd19190810190614fee565b9550505b612fe0866000614135565b50505b50505092915050565b60006001600160801b038211156130555760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b60648201526084016118f6565b5090565b604080516002808252606080830184529260208301908036833701905050905081600001516001600160801b0316600160801b1760001b816000815181106130a3576130a3614b6e565b602002602001018181525050608082604001516001600160801b0316901b82602001516001600160801b03161760001b816001815181106130e6576130e6614b6e565b602002602001018181525050919050565b6040805160028082526060808301845292602083019080368337019050509050816000015163ffffffff166020836040015163ffffffff16901b606084602001516001600160a01b0316901b171760001b8160008151811061315b5761315b614b6e565b602002602001018181525050608082608001516001600160801b0316901b82606001516001600160801b03161760001b816001815181106130e6576130e6614b6e565b806000036131ab57505050565b604051634b61cc3360e01b81526000906001600160a01b03851690634b61cc33906131e6903090879064010000000090600190600401614b9a565b600060405180830381865afa158015613203573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261322b9190810190614cc0565b9050816132548260008151811061324457613244614b6e565b602002602001015160001c61415d565b61325e9190614cf4565b60001b8160008151811061327457613274614b6e565b602090810291909101015260405163048620af60e11b81526001600160a01b0385169063090c415e906132b4908690640100000000908690600401615022565b600060405180830381600087803b1580156132ce57600080fd5b505af11580156132e2573d6000803e3d6000fd5b5050505050505050565b6132f46142d7565b6020840151604051633e7d48bd60e21b81526001600160a01b03909116600482015260609060009081908190339063f9f522f490602401606060405180830381865afa158015613348573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061336c9190614f24565b88965091945092509050828015613381575081155b1561352d576133908489614020565b93508760c00151811660000361351b5760006133af8960c0015161409e565b89516040808c015160608d0151825160008152602081019093526133dd9392309291908e9060448101615049565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b031990951694909417909352918b015160c08c0151925163079b42a160e21b81529193503392631e6d0a849261344c9291869164200000000091909114908b90600401614fa5565b6000604051808303816000875af115801561346b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526134939190810190614fee565b604051631fb6491d60e11b81529095503390633f6c923a906134b9908890600401614493565b600060405180830381865afa1580156134d6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526134fe9190810190614e1e565b955061351389608001518761010001516141c7565b610100870152505b61352a86866101000151614135565b93505b505050935093915050565b60405168383ab13634b9b432b960b91b60208201526bffffffffffffffffffffffff19606084901b1660298201526001600160e01b031960e083901b16603d8201526000906041015b60405160208183030381529060405280519060200120905092915050565b60408051606081018252600080825260208201819052918101829052604051636c2d9f2f60e01b815230600482015260248101849052600260448201526000906001600160a01b03861690636c2d9f2f90606401600060405180830381865afa158015613610573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136389190810190614cc0565b905060008160008151811061364f5761364f614b6e565b602002602001015160001c905060008260018151811061367157613671614b6e565b602002602001015160001c905060008211945084156136a9576001600160801b03808316855281166020850152608081901c60408501525b5050509250929050565b604051631528e57f60e31b81526001600160a01b038085166004830152831660248201526000604482015263ffffffff8216606482015273992805ed822c786bcdba4cb1f07b5cada3bc3cba9063a9472bf89060840160006040518083038186803b15801561372157600080fd5b505af4158015613735573d6000803e3d6000fd5b50505050505050565b60006137687f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6001600160a01b0316036137be5760405162461bcd60e51b815260206004820152601d60248201527f5555505350726f786961626c653a206e6f742075706772616461626c6500000060448201526064016118f6565b806001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138209190614b1c565b61382861116c565b146138815760405162461bcd60e51b815260206004820152602360248201527f5555505350726f786961626c653a206e6f7420636f6d70617469626c65206c6f60448201526267696360e81b60648201526084016118f6565b6001600160a01b03811630036138d95760405162461bcd60e51b815260206004820152601960248201527f5555505350726f786961626c653a2070726f7879206c6f6f700000000000000060448201526064016118f6565b613901817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b7fe011bc04c286c344a8fcbb8de77f953da762c3e25d8cdea984147fc4168a5dcc61392a61116c565b604080519182526001600160a01b038416602083015201611960565b60408051606081018252600080825260208201819052918101829052600061396e8585613538565b925061397a868461359f565b925090508061399c5760405163edeaa63b60e01b815260040160405180910390fd5b50935093915050565b866001600160a01b031663cf97256d8785602001516001600160801b03168660000151866139d391906149be565b6001600160801b03166139e590614a0e565b6139ef91906149de565b6040518363ffffffff1660e01b8152600401613a0c929190614a2a565b600060405180830381600087803b158015613a2657600080fd5b505af1158015613a3a573d6000803e3d6000fd5b50505050613a74878785604001516001600160801b0316866000015186613a6191906149be565b6001600160801b03166108a191906149de565b82516001600160801b03831684526001600160a01b03881663a1b2bf8b86613a9b87613059565b6040518363ffffffff1660e01b8152600401613ab892919061497e565b600060405180830381600087803b158015613ad257600080fd5b505af1158015613ae6573d6000803e3d6000fd5b505050508563ffffffff16876001600160a01b0316896001600160a01b03167f81e37f3d9f16cbf29a62d6a1c21d79b23ef29b54124ec44af43a50fffb9304f3848789604001518a6020015189604051613b449594939291906150af565b60405180910390a46040516379359f6f60e01b81526001600160a01b0388811660048301528916906379359f6f90602401602060405180830381865afa158015613b92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bb69190614d77565b156132e2576040516316e759bb60e01b815260040160405180910390fd5b60608073992805ed822c786bcdba4cb1f07b5cada3bc3cba6306967a8c85856000600160801b6040518563ffffffff1660e01b8152600401613c199493929190614b9a565b600060405180830381865af4158015613c36573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613c5e91908101906150eb565b909250905060005b8151811015613cbf57613c9284838381518110613c8557613c85614b6e565b6020026020010151613fdf565b828281518110613ca457613ca4614b6e565b6020908102919091010152613cb8816151af565b9050613c66565b509250929050565b6000613cd16142a9565b604051636c2d9f2f60e01b815230600482015260248101849052600260448201526000906001600160a01b03861690636c2d9f2f90606401600060405180830381865afa158015613d26573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613d4e9190810190614cc0565b9050600081600081518110613d6557613d65614b6e565b602002602001015160001c9050600082600181518110613d8757613d87614b6e565b602002602001015160001c905060008211945084156136a957606082811c60208087019190915283901c63ffffffff9081166040870152831685526001600160801b03821690850152608081811c908501525050509250929050565b600080836001600160a01b0316634b61cc33308564010000000060016040518563ffffffff1660e01b8152600401613e1e9493929190614b9a565b600060405180830381865afa158015613e3b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613e639190810190614cc0565b905080600081518110613e7857613e78614b6e565b602002602001015160001c91505092915050565b604051630a32470160e41b81526001600160a01b03808516600483015283166024820152600060448201819052600160801b6064830152608482018390529073992805ed822c786bcdba4cb1f07b5cada3bc3cba9063a32470109060a401602060405180830381865af4158015613f07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f2b91906151c8565b949350505050565b604051636c2d9f2f60e01b8152306004820152602481018290526002604482015260009081906001600160a01b03851690636c2d9f2f90606401600060405180830381865afa158015613f8a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613fb29190810190614cc0565b9050600081600081518110613fc957613fc9614b6e565b6020908102919091010151151595945050505050565b604080516b39bab139b1b934b83a34b7b760a11b6020820152606084811b6bffffffffffffffffffffffff1916602c83015291810183905260009101613581565b6020810151608082015160a08301518351604051630768fabb60e41b8152606094339463768fabb094614057948a946004016151e5565b6000604051808303816000875af1158015614076573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d0b9190810190614fee565b600064010000000082036140ba57506330d9c91560e01b919050565b64040000000082036140d45750630221347d60e61b919050565b64100000000082036140ee5750635f9e7d7760e01b919050565b6402000000008203614108575063d86ed3e560e01b919050565b6408000000008203614122575063230dbd2960e01b919050565b506353c11f9960e01b919050565b919050565b604051634c4d861f60e11b8152606090339063989b0c3e90614057908690869060040161522a565b60006001600160ff1b038211156130555760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b60648201526084016118f6565b6000612d0b60006141e06141da8661415d565b856141e5565b6141fa565b60008183136141f45782612d0b565b50919050565b60008183136142095781612d0b565b5090919050565b6040805160c0810182526000808252602082018190529181019190915260608101614254604080516060810182526000808252602082018190529181019190915290565b81526020016142616142a9565b8152602001606081525090565b6040805160e0810182526000808252602082018190529181018290526060808201526080810182905260a0810182905260c081019190915290565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b604080516101608101825260008082526020820181905291810182905260608082018390526080820183905260a082015260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b6001600160a01b038116811461113a57600080fd5b63ffffffff8116811461113a57600080fd5b80356001600160801b038116811461413057600080fd5b60008083601f84011261438257600080fd5b5081356001600160401b0381111561439957600080fd5b6020830191508360208285010111156143b157600080fd5b9250929050565b60008060008060008060a087890312156143d157600080fd5b86356143dc81614332565b955060208701356143ec81614347565b945060408701356143fc81614332565b935061440a60608801614359565b925060808701356001600160401b0381111561442557600080fd5b61443189828a01614370565b979a9699509497509295939492505050565b60005b8381101561445e578181015183820152602001614446565b50506000910152565b6000815180845261447f816020860160208601614443565b601f01601f19169290920160200192915050565b602081526000612d0b6020830184614467565b6000806000606084860312156144bb57600080fd5b83356144c681614332565b925060208401356144d681614332565b915060408401356144e681614347565b809150509250925092565b60008060008060008060a0878903121561450a57600080fd5b863561451581614332565b9550602087013561452581614332565b9450604087013561453581614347565b9350606087013561440a81614332565b60006020828403121561455757600080fd5b813561456281614332565b9392505050565b6000806000806080858703121561457f57600080fd5b843561458a81614332565b9350602085013561459a81614332565b925060408501356145aa81614347565b915060608501356145ba81614332565b939692955090935050565b6000806000806000608086880312156145dd57600080fd5b85356145e881614332565b945060208601356145f881614332565b9350604086013561460881614347565b925060608601356001600160401b0381111561462357600080fd5b61462f88828901614370565b969995985093965092949392505050565b60008060008060006080868803121561465857600080fd5b853561466381614332565b9450602086013561467381614347565b935061460860408701614359565b6000806000806080858703121561469757600080fd5b84356146a281614332565b935060208501356146b281614332565b925060408501356146c281614347565b9396929550929360600135925050565b6000806000606084860312156146e757600080fd5b83356146f281614332565b9250602084013561470281614332565b929592945050506040919091013590565b6000806040838503121561472657600080fd5b823561473181614332565b9150602083013561474181614332565b809150509250929050565b600081518084526020808501945080840160005b838110156147855781516001600160801b031687529582019590820190600101614760565b509495945050505050565b606080825284519082018190526000906020906080840190828801845b828110156147d25781516001600160a01b0316845292840192908401906001016147ad565b5050508381038285015285518082528683019183019060005b8181101561480d57835163ffffffff16835292840192918401916001016147eb565b50508481036040860152614821818761474c565b98975050505050505050565b60008060008060006080868803121561484557600080fd5b853561485081614332565b9450602086013561486081614347565b93506040860135925060608601356001600160401b0381111561462357600080fd5b6000806040838503121561489557600080fd5b82356148a081614332565b946020939093013593505050565b600080600080606085870312156148c457600080fd5b84356148cf81614332565b935060208501356148df81614347565b925060408501356001600160401b038111156148fa57600080fd5b61490687828801614370565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115612d0e57612d0e614912565b81810381811115612d0e57612d0e614912565b600081518084526020808501945080840160005b8381101561478557815187529582019590820190600101614962565b828152604060208201526000613f2b604083018461494e565b6001600160801b038181168382160190808211156149b7576149b7614912565b5092915050565b6001600160801b038281168282160390808211156149b7576149b7614912565b80820260008212600160ff1b841416156149fa576149fa614912565b8181058314821517612d0e57612d0e614912565b6000600160ff1b8201614a2357614a23614912565b5060000390565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03841681526001600160801b0383166020820152606060408201819052600090614a7690830184614467565b95945050505050565b6001600160a01b038516815263ffffffff841660208201526001600160801b0383166040820152608060608201819052600090614abe90830184614467565b9695505050505050565b6001600160a01b0383168152604060208201819052600090613f2b90830184614467565b6001600160a01b038416815263ffffffff83166020820152606060408201819052600090614a7690830184614467565b600060208284031215614b2e57600080fd5b5051919050565b8082028115828204841417612d0e57612d0e614912565b600082614b6957634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b634e487b7160e01b600052604160045260246000fd5b60405161016081016001600160401b0381118282101715614bfc57614bfc614bc3565b60405290565b604051601f8201601f191681016001600160401b0381118282101715614c2a57614c2a614bc3565b604052919050565b60006001600160401b03821115614c4b57614c4b614bc3565b5060051b60200190565b600082601f830112614c6657600080fd5b81516020614c7b614c7683614c32565b614c02565b82815260059290921b84018101918181019086841115614c9a57600080fd5b8286015b84811015614cb55780518352918301918301614c9e565b509695505050505050565b600060208284031215614cd257600080fd5b81516001600160401b03811115614ce857600080fd5b613f2b84828501614c55565b8082018281126000831280158216821582161715614d1457614d14614912565b505092915050565b600063ffffffff808316818103614d3557614d35614912565b6001019392505050565b805161413081614332565b600060208284031215614d5c57600080fd5b815161456281614332565b8051801515811461413057600080fd5b600060208284031215614d8957600080fd5b612d0b82614d67565b805160ff8116811461413057600080fd5b80516001600160e01b03198116811461413057600080fd5b600082601f830112614dcc57600080fd5b81516001600160401b03811115614de557614de5614bc3565b614df8601f8201601f1916602001614c02565b818152846020838601011115614e0d57600080fd5b613f2b826020830160208701614443565b600060208284031215614e3057600080fd5b81516001600160401b0380821115614e4757600080fd5b908301906101608286031215614e5c57600080fd5b614e64614bd9565b614e6d83614d92565b8152614e7b60208401614d92565b602082015260408301516040820152614e9660608401614d3f565b6060820152614ea760808401614da3565b608082015260a083015182811115614ebe57600080fd5b614eca87828601614dbb565b60a08301525060c083015160c082015260e083015160e0820152610100915081830151828201526101209150614f01828401614d3f565b828201526101409150614f15828401614d3f565b91810191909152949350505050565b600080600060608486031215614f3957600080fd5b614f4284614d67565b9250614f5060208501614d67565b9150604084015190509250925092565b6001600160a01b038681168252851660208201526040810184905260a060608201819052600090614f9390830185614467565b82810360808401526148218185614467565b6001600160a01b0385168152608060208201819052600090614fc990830186614467565b84151560408401528281036060840152614fe38185614467565b979650505050505050565b60006020828403121561500057600080fd5b81516001600160401b0381111561501657600080fd5b613f2b84828501614dbb565b60018060a01b0384168152826020820152606060408201526000614a76606083018461494e565b6001600160a01b038781168252861660208201526040810185905260c06060820181905260009061507c90830186614467565b828103608084015261508e8186614467565b905082810360a08401526150a28185614467565b9998505050505050505050565b60006001600160801b0380881683528087166020840152808616604084015280851660608401525060a06080830152614fe360a0830184614467565b600080604083850312156150fe57600080fd5b82516001600160401b038082111561511557600080fd5b818501915085601f83011261512957600080fd5b81516020615139614c7683614c32565b82815260059290921b8401810191818101908984111561515857600080fd5b948201945b8386101561517f57855161517081614347565b8252948201949082019061515d565b9188015191965090935050508082111561519857600080fd5b506151a585828601614c55565b9150509250929050565b6000600182016151c1576151c1614912565b5060010190565b6000602082840312156151da57600080fd5b815161456281614347565b60a0815260006151f860a0830188614467565b6001600160a01b0396871660208401526040830195909552506060810192909252909216608090920191909152919050565b60408152600061523d6040830185614467565b9050826020830152939250505056fea2646970667358221220ebc7fa3b2c4167f0bd9d5f0a8d36220316e9d9e44294b7f55fc5f2ce31b3474464736f6c63430008130033000000000000000000000000a4ff07cf81c02cfd356184879d953970ca957585
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101375760003560e01c80637fbc7639116100b8578063acafa1b81161007c578063acafa1b814610336578063acf4a6c214610349578063b6dacdb81461035c578063b96731c21461037e578063cd7245c514610391578063d787840a146103e957600080fd5b80637fbc76391461029f578063899baaec146102b25780639903ad38146102e25780639b2e48bc146102ea578063a5653ced1461031857600080fd5b806350d75d25116100ff57806350d75d251461020457806352d1902d1461020c5780635b534051146102225780636041ae96146102665780637730599e1461027957600080fd5b8063232d2b581461013c57806323fc23f3146101655780632e5e74c6146101a95780633fd4176a146101bc57806346951954146101ef575b600080fd5b61014f61014a3660046143b8565b6103fc565b60405161015c9190614493565b60405180910390f35b6101786101733660046144a6565b610b16565b6040805194151585526001600160801b0393841660208601529183169184019190915216606082015260800161015c565b61014f6101b73660046144f1565b610b81565b6101d773992805ed822c786bcdba4cb1f07b5cada3bc3cba81565b6040516001600160a01b03909116815260200161015c565b6102026101fd366004614545565b6110e8565b005b6101d761113d565b61021461116c565b60405190815260200161015c565b610235610230366004614569565b6111d0565b60405161015c9493929190931515845291151560208401526001600160801b03166040830152606082015260800190565b61014f6102743660046145c5565b6112a6565b7f8aedc3b5d4bf031e11a7e2940f7251c005698405d58e02e1c247fed3b1b3a674610214565b61014f6102ad366004614640565b6116cb565b6102c56102c0366004614681565b6117b8565b604080519283526001600160801b0390911660208301520161015c565b61020261185d565b6102fd6102f83660046146d2565b61196b565b6040805193845260208401929092529082015260600161015c565b61032161010081565b60405163ffffffff909116815260200161015c565b61014f6103443660046144f1565b611b76565b61014f6103573660046145c5565b611f7b565b61036f61036a366004614713565b612535565b60405161015c93929190614790565b61014f61038c36600461482d565b61278a565b6103a461039f366004614882565b61288a565b604080516001600160a01b03909616865263ffffffff9094166020860152911515928401929092526001600160801b039091166060830152608082015260a00161015c565b61014f6103f73660046148ae565b61298c565b60606001600160a01b03851661042557604051633242919d60e21b815260040160405180910390fd5b61042d614210565b61043561426e565b606060008061047a8c89898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b90508060a00151925080606001519150506104998b828b8d6000612d14565b60808901521515602080890191909152606088019190915260408088018390529287528251908101909252600082526104d5918d918c91612e07565b925086868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050602086015191965050156105395764040000000060c084015261052f8386612e35565b60a0850152610554565b64010000000060c084015261054e8386612e35565b60a08501525b83602001518015610571575060808401515163ffffffff90811614155b1561064c576105c08460800151608001516001600160801b0316896001600160801b03168660600151602001516001600160801b03166105b19190614928565b6105bb919061493b565b612fec565b6060850180516001600160801b03909216602090920191909152845190516001600160a01b038d169163a1b2bf8b916105f890613059565b6040518363ffffffff1660e01b815260040161061592919061497e565b600060405180830381600087803b15801561062f57600080fd5b505af1158015610643573d6000803e3d6000fd5b50505050610833565b8360200151156106c9576106918460800151608001516001600160801b0316896001600160801b03168660600151604001516001600160801b03166105b19190614928565b6060850180516001600160801b03909216604090920191909152845190516001600160a01b038d169163a1b2bf8b916105f890613059565b6040518060a0016040528063ffffffff80168152602001826001600160a01b031681526020018b63ffffffff1681526020018560600151600001516001600160801b03168152602001896001600160801b031681525084608001819052508a6001600160a01b03166312a6a3f8856040015161074887608001516130f7565b6040518363ffffffff1660e01b815260040161076592919061497e565b600060405180830381600087803b15801561077f57600080fd5b505af1158015610793573d6000803e3d6000fd5b50505050878460600151604001516107ab9190614997565b6060850180516001600160801b03909216604090920191909152845190516001600160a01b038d169163a1b2bf8b916107e390613059565b6040518363ffffffff1660e01b815260040161080092919061497e565b600060405180830381600087803b15801561081a57600080fd5b505af115801561082e573d6000803e3d6000fd5b505050505b60008460800151608001516001600160801b031685608001516060015186606001516000015161086391906149be565b6001600160801b031661087691906149de565b905063ffffffff801685608001516000015163ffffffff160361090f576108a68c836108a184614a0e565b61319e565b6001600160a01b038c1663cf97256d836108bf84614a0e565b6040518363ffffffff1660e01b81526004016108dc929190614a2a565b600060405180830381600087803b1580156108f657600080fd5b505af115801561090a573d6000803e3d6000fd5b505050505b60405163cf97256d60e01b81526001600160a01b038d169063cf97256d9061093d908d908590600401614a2a565b600060405180830381600087803b15801561095757600080fd5b505af115801561096b573d6000803e3d6000fd5b50505050846020015115610a115760608086015151608080880180516001600160801b039384169401939093528251918c16910152604086015190516001600160a01b038e169163a1b2bf8b916109c1906130f7565b6040518363ffffffff1660e01b81526004016109de92919061497e565b600060405180830381600087803b1580156109f857600080fd5b505af1158015610a0c573d6000803e3d6000fd5b505050505b846020015115610a405764080000000060c085015260a0850151610a37908590886132ec565b9650610a609050565b64020000000060c085015260a0850151610a5c908590886132ec565b9650505b8a63ffffffff16826001600160a01b03168d6001600160a01b03167f0115987243fd19d615b5ea62a80372a06a2b37fec378b148ee7a507c5c4c0a398d8d88604051610aae93929190614a43565b60405180910390a4896001600160a01b03168c6001600160a01b03167fe0707ac7efb8b59c22189af8d004ed17dc9e4379e71b9066119b62c182524977848e8d88604051610aff9493929190614a7f565b60405180910390a350505050509695505050505050565b600080600080610b3f604080516060810182526000808252602082018190529181019190915290565b6000610b4b8888613538565b9050610b57898261359f565b90965091508515610b7657815160208301516040840151919650945092505b505093509350935093565b6060610b8b614210565b610b9361426e565b600060606000610bd98c89898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b606081015160a0909101519093509150506001600160a01b038816610c1157604051633242919d60e21b815260040160405180910390fd5b896001600160a01b0316826001600160a01b031614610c43576040516392da6d1760e01b815260040160405180910390fd5b610c518b8b8a8c6001612d14565b6080890152506060870152604080870182905291865281516020810190925260008252610c81918d918b91612e07565b925086868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505064100000000060c087015250909550610cd290508386612e35565b60a08501526080808501519081015160609182015191860151516000926001600160801b0390921691610d04916149be565b6001600160801b0316610d1791906149de565b60808601515190915063ffffffff90811614610d6457846080015160800151856060015160200151610d4991906149be565b60608601516001600160801b03909116602090910152610d97565b846080015160800151856060015160400151610d8091906149be565b60608601516001600160801b039091166040909101525b8b6001600160a01b031663a1b2bf8b8660000151610db88860600151613059565b6040518363ffffffff1660e01b8152600401610dd592919061497e565b600060405180830381600087803b158015610def57600080fd5b505af1158015610e03573d6000803e3d6000fd5b5050505060808501515163ffffffff90811614610e2d57610e2d8c8a8760800151600001516136b3565b60808501515163ffffffff1663fffffffe1901610ebb57610e528c8c6108a184614a0e565b6001600160a01b038c1663cf97256d8c610e6b84614a0e565b6040518363ffffffff1660e01b8152600401610e88929190614a2a565b600060405180830381600087803b158015610ea257600080fd5b505af1158015610eb6573d6000803e3d6000fd5b505050505b6040858101519051632704839760e01b81526004810191909152600260248201526001600160a01b038d1690632704839790604401600060405180830381600087803b158015610f0a57600080fd5b505af1158015610f1e573d6000803e3d6000fd5b505060405163cf97256d60e01b81526001600160a01b038f16925063cf97256d9150610f50908c908590600401614a2a565b600060405180830381600087803b158015610f6a57600080fd5b505af1158015610f7e573d6000803e3d6000fd5b505064200000000060c0870152505060a0850151610f9e908590886132ec565b9050809650508963ffffffff168b6001600160a01b03168d6001600160a01b03167fe1f8e9cd8061e5b251769965bda6ca9ef1674bc6541fb9131039fa53f024d1428c86604051610ff0929190614ac8565b60405180910390a4886001600160a01b03168c6001600160a01b03167f9e02127550b99adc8cc6ee332a36f31338facdbc396cebefce9a047247cd04558d8d8660405161103f93929190614aec565b60405180910390a38963ffffffff168b6001600160a01b03168d6001600160a01b03167f0115987243fd19d615b5ea62a80372a06a2b37fec378b148ee7a507c5c4c0a398c60008760405161109693929190614a43565b60405180910390a4886001600160a01b03168c6001600160a01b03167fe0707ac7efb8b59c22189af8d004ed17dc9e4379e71b9066119b62c1825249778d8d600087604051610aff9493929190614a7f565b336001600160a01b037f000000000000000000000000a4ff07cf81c02cfd356184879d953970ca957585161461113157604051630b00ec8f60e11b815260040160405180910390fd5b61113a8161373e565b50565b60006111677f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b905090565b6000306001600160a01b0316637730599e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111679190614b1c565b6000806000806000806111fc604080516060810182526000808252602082018190529181019190915290565b6112046142a9565b6112128c8c8b8d6000612d14565b909b50929650909450925090508761123b5760008060008097509750975097505050505061129b565b8051608082015163ffffffff9182169091141597509550866112915780608001516001600160801b03168160600151836000015161127991906149be565b6001600160801b031661128c9190614b35565b611294565b60005b9450505050505b945094509450949050565b60606112b0614210565b6112b861426e565b6000606060006112fe8b89898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b9050806060015192508060a0015191505061131d8a8a848b6001612d14565b6080890181905260608901929092525060408701919091529085525163ffffffff1663fffffffe190161136357604051633741257360e01b815260040160405180910390fd5b6113828a8a866040015160405180602001604052806000815250612e07565b925086868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505064100000000060c0870152509095506113d390508386612e35565b60a08501526080808501519081015160609182015191860151516000926001600160801b0390921691611405916149be565b6001600160801b031661141891906149de565b905084608001516080015185606001516020015161143691906149be565b6060860180516001600160801b0390921660209092019190915260808087015101519051604001516114689190614997565b6060860180516001600160801b03909216604090920191909152855190516001600160a01b038d169163a1b2bf8b916114a090613059565b6040518363ffffffff1660e01b81526004016114bd92919061497e565b600060405180830381600087803b1580156114d757600080fd5b505af11580156114eb573d6000803e3d6000fd5b505050506115028b848760800151600001516136b3565b606080860151516080870180516001600160801b039092169190920152805163ffffffff9052604086015190516001600160a01b038d169163a1b2bf8b91611549906130f7565b6040518363ffffffff1660e01b815260040161156692919061497e565b600060405180830381600087803b15801561158057600080fd5b505af1158015611594573d6000803e3d6000fd5b505060405163cf97256d60e01b81526001600160a01b038e16925063cf97256d91506115c69086908590600401614a2a565b600060405180830381600087803b1580156115e057600080fd5b505af11580156115f4573d6000803e3d6000fd5b505064200000000060c0870152505060a0850151611614908590886132ec565b9050809650508863ffffffff168a6001600160a01b03168c6001600160a01b03167fe1f8e9cd8061e5b251769965bda6ca9ef1674bc6541fb9131039fa53f024d1428686604051611666929190614ac8565b60405180910390a4826001600160a01b03168b6001600160a01b03167f9e02127550b99adc8cc6ee332a36f31338facdbc396cebefce9a047247cd04558c8c866040516116b593929190614aec565b60405180910390a3505050505095945050505050565b6060600061170f8785858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b60608101519091506000806117258a848b613946565b9150915080600001516001600160801b0316886001600160801b031610156117605760405163cfdca72560e01b815260040160405180910390fd5b6117738a848b85858d8a60a001516139a5565b86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929d9c50505050505050505050505050565b60008060006117c78686613538565b90506000806117d6898461359f565b91509150816117f85760405163edeaa63b60e01b815260040160405180910390fd5b60008160400151826020015161180e9190614997565b6001600160801b0316905060006118286105bb838a614b4c565b8351909150611838908290614997565b955061184d826001600160801b038316614b35565b9650505050505094509492505050565b600054610100900460ff161580801561187d5750600054600160ff909116105b806118975750303b158015611897575060005460ff166001145b6118ff5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015611922576000805461ff0019166101001790555b801561113a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a150565b600080600060608061197d8888613bd4565b909250905060005b81518163ffffffff161015611b5a57600061199e6142a9565b600080868563ffffffff16815181106119b9576119b9614b6e565b602002602001015190506119ec8d878763ffffffff16815181106119df576119df614b6e565b6020026020010151613cc7565b9094509250836119fe576119fe614b84565b8063ffffffff16836000015163ffffffff1614611a1d57611a1d614b84565b6001600160a01b038d16634b61cc33308e611a4263ffffffff8616600160801b614928565b60016040518563ffffffff1660e01b8152600401611a639493929190614b9a565b600060405180830381865afa158015611a80573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611aa89190810190614cc0565b600081518110611aba57611aba614b6e565b6020026020010151915050611ae8604080516060810182526000808252602082018190529181019190915290565b611af28d8361359f565b909450905083611b0457611b04614b84565b82608001516001600160801b031683606001518260000151611b2691906149be565b6001600160801b0316611b3991906149de565b611b43908b614cf4565b99505050505080611b5390614d1c565b9050611985565b50611b658888613de3565b935060009250505093509350939050565b6060611bb88784848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b506001600160a01b038416611be057604051633242919d60e21b815260040160405180910390fd5b611be8614210565b611bf061426e565b611bfe8989888a6001612d14565b6080870181905260608701929092525060408501919091529083525163ffffffff90811614611c4057604051633eb2f84960e01b815260040160405180910390fd5b60008260800151608001516001600160801b0316836080015160600151846060015160000151611c7091906149be565b6001600160801b0316611c839190614b35565b9050611ca48a8a856040015160405180602001604052806000815250612e07565b915085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509296505082159150611f3490505764040000000060c0830152611cfc8285612e35565b60a0840152611d0f8a8a6108a184614a0e565b6001600160a01b038a1663cf97256d8a611d2884614a0e565b6040518363ffffffff1660e01b8152600401611d45929190614a2a565b600060405180830381600087803b158015611d5f57600080fd5b505af1158015611d73573d6000803e3d6000fd5b50505050606083810151516080850180516001600160801b039092169190920152604084015190516001600160a01b038c169163a1b2bf8b91611db5906130f7565b6040518363ffffffff1660e01b8152600401611dd292919061497e565b600060405180830381600087803b158015611dec57600080fd5b505af1158015611e00573d6000803e3d6000fd5b505060405163cf97256d60e01b81526001600160a01b038d16925063cf97256d9150611e32908a908590600401614a2a565b600060405180830381600087803b158015611e4c57600080fd5b505af1158015611e60573d6000803e3d6000fd5b505050508763ffffffff16896001600160a01b03168b6001600160a01b03167f467eccd248ef31c8bcef16d94856855799a8783aeef10f3759e43614059a6bb18a85604051611eb0929190614a2a565b60405180910390a4604080516001600160a01b038b8116825263ffffffff8b166020830152918101839052818916918c16907f48a3d91d4a07e4982b081260e24f922bd33bb965882772d6de19c922c3eabdea9060600160405180910390a364080000000060c083015260a0830151611f2b908390866132ec565b9450611f6e9050565b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509296505050505b5050509695505050505050565b6060611f85614210565b611f8d61426e565b600060606000611fd38b89898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b9050806060015192508060a00151915050611ff28a8a848b6000612d14565b60808901521580156020890152606088019190915260408701919091529085526120425760808401515163ffffffff9081161461204257604051633eb2f84960e01b815260040160405180910390fd5b86868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052506040808a015181516020810190925291815294995061209b948f94508e9350909150612e07565b925083602001516121c45764010000000060c08401526120bb8386612e35565b60a08086019190915260408051918201815260008083526001600160a01b038c16602084015263ffffffff8b1691830191909152606080870151516001600160801b031690830152608080830191909152850152835161211e908b908490613e8c565b60808501805163ffffffff909216909152604085015190516001600160a01b038c16916312a6a3f891612150906130f7565b6040518363ffffffff1660e01b815260040161216d92919061497e565b600060405180830381600087803b15801561218757600080fd5b505af115801561219b573d6000803e3d6000fd5b505064020000000060c0860152505060a08401516121bb908490876132ec565b95506124859050565b64040000000060c08401526121d98386612e35565b60a08501526080808501519081015160609182015191860151516000926001600160801b039092169161220b916149be565b6001600160801b031661221e91906149de565b9050846080015160800151856060015160200181815161223e9190614997565b6001600160801b03169052506080808601510151606086015160400180516122679083906149be565b6001600160801b0316905250845160608601516001600160a01b038d169163a1b2bf8b9161229490613059565b6040518363ffffffff1660e01b81526004016122b192919061497e565b600060405180830381600087803b1580156122cb57600080fd5b505af11580156122df573d6000803e3d6000fd5b505050506122f28b8b836108a190614a0e565b6001600160a01b038b1663cf97256d8b61230b84614a0e565b6040518363ffffffff1660e01b8152600401612328929190614a2a565b600060405180830381600087803b15801561234257600080fd5b505af1158015612356573d6000803e3d6000fd5b505060405163cf97256d60e01b81526001600160a01b038e16925063cf97256d91506123889086908590600401614a2a565b600060405180830381600087803b1580156123a257600080fd5b505af11580156123b6573d6000803e3d6000fd5b5050506060808701515160808801516001600160801b039091169101525084516123e3908c908590613e8c565b60808601805163ffffffff909216909152604086015190516001600160a01b038d169163a1b2bf8b91612415906130f7565b6040518363ffffffff1660e01b815260040161243292919061497e565b600060405180830381600087803b15801561244c57600080fd5b505af1158015612460573d6000803e3d6000fd5b505064080000000060c0870152505060a0850151612480908590886132ec565b965050505b8763ffffffff16896001600160a01b03168b6001600160a01b03167f492d2641617cfaf24ac7328f85bc5bdf5113537d78dc7671afa4f49a73f053c285856040516124d1929190614ac8565b60405180910390a4816001600160a01b03168a6001600160a01b03167fc0b8396b655615cdb85fe462a9a1792480816f909cd46d9517a940b386dfbf6b8b8b8560405161252093929190614aec565b60405180910390a35050505095945050505050565b60608060608060606125478787613bd4565b909250905060006125566142a9565b82516001600160401b0381111561256f5761256f614bc3565b604051908082528060200260200182016040528015612598578160200160208202803683370190505b50965082516001600160401b038111156125b4576125b4614bc3565b6040519080825280602002602001820160405280156125dd578160200160208202803683370190505b50955082516001600160401b038111156125f9576125f9614bc3565b604051908082528060200260200182016040528015612622578160200160208202803683370190505b50945060005b83518163ffffffff16101561277e576000858263ffffffff168151811061265157612651614b6e565b602002602001015190506000858363ffffffff168151811061267557612675614b6e565b602002602001015190506126898c82613cc7565b90955093508461269b5761269b614b84565b8163ffffffff16846000015163ffffffff16146126ba576126ba614b84565b83602001518a8463ffffffff16815181106126d7576126d7614b6e565b60200260200101906001600160a01b031690816001600160a01b0316815250508360400151898463ffffffff168151811061271457612714614b6e565b602002602001019063ffffffff16908163ffffffff16815250508360800151888463ffffffff168151811061274b5761274b614b6e565b60200260200101906001600160801b031690816001600160801b03168152505050508061277790614d1c565b9050612628565b50505050509250925092565b606060006127ce8785858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b60608101519091506000806127e48a848b613946565b915091506000816040015182602001516127fe9190614997565b6001600160801b03169050801561284457600061281e6105bb838c614b4c565b90506128428c868d87878689600001516128389190614997565b8c60a001516139a5565b505b87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929e9d5050505050505050505050505050565b60008060008060008060006128b8604080516060810182526000808252602082018190529181019190915290565b6128c06142a9565b6128ca8b8b613cc7565b9094509050836128ed5760405163016d919360e71b815260040160405180910390fd5b80602001519850806040015197506129058989613538565b92506129118b8461359f565b90945091508361292357612923614b84565b8051608082015163ffffffff9182169091141597509550866129795780608001516001600160801b03168160600151836000015161296191906149be565b6001600160801b03166129749190614b35565b61297c565b60005b9450505050509295509295909350565b606060006129d08685858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b4792505050565b606081015190915060006129e48288613538565b90506129f08882613f33565b15612a0e57604051635c02a51760e01b815260040160405180910390fd5b876001600160a01b03166312a6a3f882612a5f604051806060016040528060006001600160801b0316815260200160006001600160801b0316815260200160006001600160801b0316815250613059565b6040518363ffffffff1660e01b8152600401612a7c92919061497e565b600060405180830381600087803b158015612a9657600080fd5b505af1158015612aaa573d6000803e3d6000fd5b505050508663ffffffff16826001600160a01b0316896001600160a01b03167f01ab8663165edfb7390d9e5f75d960a66dacf4f01fa9787e3a731c870d0da9218660a00151604051612afc9190614493565b60405180910390a485858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929b9a5050505050505050505050565b612b4f6142d7565b336001600160a01b0316836001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bbb9190614d4a565b6001600160a01b031614612c055760405162461bcd60e51b81526020600482015260116024820152701d5b985d5d1a1bdc9a5e9959081a1bdcdd607a1b60448201526064016118f6565b604051632fd0a1cd60e21b8152339063bf42873490612c28908590600401614493565b602060405180830381865afa158015612c45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c699190614d77565b612ca35760405162461bcd60e51b815260206004820152600b60248201526a0d2dcecc2d8d2c840c6e8f60ab1b60448201526064016118f6565b604051631fb6491d60e11b81523390633f6c923a90612cc6908590600401614493565b600060405180830381865afa158015612ce3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d0b9190810190614e1e565b90505b92915050565b6040805160608101825260008082526020820181905291810182905281906000612d3c6142a9565b6000612d488a89613538565b9550612d548987613fdf565b9450612d608b8761359f565b9450905080612d825760405163edeaa63b60e01b815260040160405180910390fd5b612d8c8b86613cc7565b90935091508615612df95782612db55760405163016d919360e71b815260040160405180910390fd5b896001600160a01b031682602001516001600160a01b031614612dda57612dda614b84565b8763ffffffff16826040015163ffffffff1614612df957612df9614b84565b509550955095509550959050565b612e0f61426e565b6001600160a01b0394851681529290931660208301526040820152606081019190915290565b6020820151604051633e7d48bd60e21b81526001600160a01b03909116600482015260609060009081908190339063f9f522f490602401606060405180830381865afa158015612e89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ead9190614f24565b91945092509050828015612ebf575081155b15612fe3576000612ed08688614020565b90508660c001518216600003612fd5576000612eef8860c0015161409e565b88516040808b015160608c015182516000815260208101909352612f1b93923092919060448101614f60565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b031990951694909417909352918a015160c08b01519251633a020f0160e11b815291935033926374041e0292612f8a9291869164100000000091909114908890600401614fa5565b6000604051808303816000875af1158015612fa9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612fd19190810190614fee565b9550505b612fe0866000614135565b50505b50505092915050565b60006001600160801b038211156130555760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b60648201526084016118f6565b5090565b604080516002808252606080830184529260208301908036833701905050905081600001516001600160801b0316600160801b1760001b816000815181106130a3576130a3614b6e565b602002602001018181525050608082604001516001600160801b0316901b82602001516001600160801b03161760001b816001815181106130e6576130e6614b6e565b602002602001018181525050919050565b6040805160028082526060808301845292602083019080368337019050509050816000015163ffffffff166020836040015163ffffffff16901b606084602001516001600160a01b0316901b171760001b8160008151811061315b5761315b614b6e565b602002602001018181525050608082608001516001600160801b0316901b82606001516001600160801b03161760001b816001815181106130e6576130e6614b6e565b806000036131ab57505050565b604051634b61cc3360e01b81526000906001600160a01b03851690634b61cc33906131e6903090879064010000000090600190600401614b9a565b600060405180830381865afa158015613203573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261322b9190810190614cc0565b9050816132548260008151811061324457613244614b6e565b602002602001015160001c61415d565b61325e9190614cf4565b60001b8160008151811061327457613274614b6e565b602090810291909101015260405163048620af60e11b81526001600160a01b0385169063090c415e906132b4908690640100000000908690600401615022565b600060405180830381600087803b1580156132ce57600080fd5b505af11580156132e2573d6000803e3d6000fd5b5050505050505050565b6132f46142d7565b6020840151604051633e7d48bd60e21b81526001600160a01b03909116600482015260609060009081908190339063f9f522f490602401606060405180830381865afa158015613348573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061336c9190614f24565b88965091945092509050828015613381575081155b1561352d576133908489614020565b93508760c00151811660000361351b5760006133af8960c0015161409e565b89516040808c015160608d0151825160008152602081019093526133dd9392309291908e9060448101615049565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b031990951694909417909352918b015160c08c0151925163079b42a160e21b81529193503392631e6d0a849261344c9291869164200000000091909114908b90600401614fa5565b6000604051808303816000875af115801561346b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526134939190810190614fee565b604051631fb6491d60e11b81529095503390633f6c923a906134b9908890600401614493565b600060405180830381865afa1580156134d6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526134fe9190810190614e1e565b955061351389608001518761010001516141c7565b610100870152505b61352a86866101000151614135565b93505b505050935093915050565b60405168383ab13634b9b432b960b91b60208201526bffffffffffffffffffffffff19606084901b1660298201526001600160e01b031960e083901b16603d8201526000906041015b60405160208183030381529060405280519060200120905092915050565b60408051606081018252600080825260208201819052918101829052604051636c2d9f2f60e01b815230600482015260248101849052600260448201526000906001600160a01b03861690636c2d9f2f90606401600060405180830381865afa158015613610573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136389190810190614cc0565b905060008160008151811061364f5761364f614b6e565b602002602001015160001c905060008260018151811061367157613671614b6e565b602002602001015160001c905060008211945084156136a9576001600160801b03808316855281166020850152608081901c60408501525b5050509250929050565b604051631528e57f60e31b81526001600160a01b038085166004830152831660248201526000604482015263ffffffff8216606482015273992805ed822c786bcdba4cb1f07b5cada3bc3cba9063a9472bf89060840160006040518083038186803b15801561372157600080fd5b505af4158015613735573d6000803e3d6000fd5b50505050505050565b60006137687f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6001600160a01b0316036137be5760405162461bcd60e51b815260206004820152601d60248201527f5555505350726f786961626c653a206e6f742075706772616461626c6500000060448201526064016118f6565b806001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138209190614b1c565b61382861116c565b146138815760405162461bcd60e51b815260206004820152602360248201527f5555505350726f786961626c653a206e6f7420636f6d70617469626c65206c6f60448201526267696360e81b60648201526084016118f6565b6001600160a01b03811630036138d95760405162461bcd60e51b815260206004820152601960248201527f5555505350726f786961626c653a2070726f7879206c6f6f700000000000000060448201526064016118f6565b613901817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b7fe011bc04c286c344a8fcbb8de77f953da762c3e25d8cdea984147fc4168a5dcc61392a61116c565b604080519182526001600160a01b038416602083015201611960565b60408051606081018252600080825260208201819052918101829052600061396e8585613538565b925061397a868461359f565b925090508061399c5760405163edeaa63b60e01b815260040160405180910390fd5b50935093915050565b866001600160a01b031663cf97256d8785602001516001600160801b03168660000151866139d391906149be565b6001600160801b03166139e590614a0e565b6139ef91906149de565b6040518363ffffffff1660e01b8152600401613a0c929190614a2a565b600060405180830381600087803b158015613a2657600080fd5b505af1158015613a3a573d6000803e3d6000fd5b50505050613a74878785604001516001600160801b0316866000015186613a6191906149be565b6001600160801b03166108a191906149de565b82516001600160801b03831684526001600160a01b03881663a1b2bf8b86613a9b87613059565b6040518363ffffffff1660e01b8152600401613ab892919061497e565b600060405180830381600087803b158015613ad257600080fd5b505af1158015613ae6573d6000803e3d6000fd5b505050508563ffffffff16876001600160a01b0316896001600160a01b03167f81e37f3d9f16cbf29a62d6a1c21d79b23ef29b54124ec44af43a50fffb9304f3848789604001518a6020015189604051613b449594939291906150af565b60405180910390a46040516379359f6f60e01b81526001600160a01b0388811660048301528916906379359f6f90602401602060405180830381865afa158015613b92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bb69190614d77565b156132e2576040516316e759bb60e01b815260040160405180910390fd5b60608073992805ed822c786bcdba4cb1f07b5cada3bc3cba6306967a8c85856000600160801b6040518563ffffffff1660e01b8152600401613c199493929190614b9a565b600060405180830381865af4158015613c36573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613c5e91908101906150eb565b909250905060005b8151811015613cbf57613c9284838381518110613c8557613c85614b6e565b6020026020010151613fdf565b828281518110613ca457613ca4614b6e565b6020908102919091010152613cb8816151af565b9050613c66565b509250929050565b6000613cd16142a9565b604051636c2d9f2f60e01b815230600482015260248101849052600260448201526000906001600160a01b03861690636c2d9f2f90606401600060405180830381865afa158015613d26573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613d4e9190810190614cc0565b9050600081600081518110613d6557613d65614b6e565b602002602001015160001c9050600082600181518110613d8757613d87614b6e565b602002602001015160001c905060008211945084156136a957606082811c60208087019190915283901c63ffffffff9081166040870152831685526001600160801b03821690850152608081811c908501525050509250929050565b600080836001600160a01b0316634b61cc33308564010000000060016040518563ffffffff1660e01b8152600401613e1e9493929190614b9a565b600060405180830381865afa158015613e3b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613e639190810190614cc0565b905080600081518110613e7857613e78614b6e565b602002602001015160001c91505092915050565b604051630a32470160e41b81526001600160a01b03808516600483015283166024820152600060448201819052600160801b6064830152608482018390529073992805ed822c786bcdba4cb1f07b5cada3bc3cba9063a32470109060a401602060405180830381865af4158015613f07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f2b91906151c8565b949350505050565b604051636c2d9f2f60e01b8152306004820152602481018290526002604482015260009081906001600160a01b03851690636c2d9f2f90606401600060405180830381865afa158015613f8a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613fb29190810190614cc0565b9050600081600081518110613fc957613fc9614b6e565b6020908102919091010151151595945050505050565b604080516b39bab139b1b934b83a34b7b760a11b6020820152606084811b6bffffffffffffffffffffffff1916602c83015291810183905260009101613581565b6020810151608082015160a08301518351604051630768fabb60e41b8152606094339463768fabb094614057948a946004016151e5565b6000604051808303816000875af1158015614076573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d0b9190810190614fee565b600064010000000082036140ba57506330d9c91560e01b919050565b64040000000082036140d45750630221347d60e61b919050565b64100000000082036140ee5750635f9e7d7760e01b919050565b6402000000008203614108575063d86ed3e560e01b919050565b6408000000008203614122575063230dbd2960e01b919050565b506353c11f9960e01b919050565b919050565b604051634c4d861f60e11b8152606090339063989b0c3e90614057908690869060040161522a565b60006001600160ff1b038211156130555760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b60648201526084016118f6565b6000612d0b60006141e06141da8661415d565b856141e5565b6141fa565b60008183136141f45782612d0b565b50919050565b60008183136142095781612d0b565b5090919050565b6040805160c0810182526000808252602082018190529181019190915260608101614254604080516060810182526000808252602082018190529181019190915290565b81526020016142616142a9565b8152602001606081525090565b6040805160e0810182526000808252602082018190529181018290526060808201526080810182905260a0810182905260c081019190915290565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b604080516101608101825260008082526020820181905291810182905260608082018390526080820183905260a082015260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b6001600160a01b038116811461113a57600080fd5b63ffffffff8116811461113a57600080fd5b80356001600160801b038116811461413057600080fd5b60008083601f84011261438257600080fd5b5081356001600160401b0381111561439957600080fd5b6020830191508360208285010111156143b157600080fd5b9250929050565b60008060008060008060a087890312156143d157600080fd5b86356143dc81614332565b955060208701356143ec81614347565b945060408701356143fc81614332565b935061440a60608801614359565b925060808701356001600160401b0381111561442557600080fd5b61443189828a01614370565b979a9699509497509295939492505050565b60005b8381101561445e578181015183820152602001614446565b50506000910152565b6000815180845261447f816020860160208601614443565b601f01601f19169290920160200192915050565b602081526000612d0b6020830184614467565b6000806000606084860312156144bb57600080fd5b83356144c681614332565b925060208401356144d681614332565b915060408401356144e681614347565b809150509250925092565b60008060008060008060a0878903121561450a57600080fd5b863561451581614332565b9550602087013561452581614332565b9450604087013561453581614347565b9350606087013561440a81614332565b60006020828403121561455757600080fd5b813561456281614332565b9392505050565b6000806000806080858703121561457f57600080fd5b843561458a81614332565b9350602085013561459a81614332565b925060408501356145aa81614347565b915060608501356145ba81614332565b939692955090935050565b6000806000806000608086880312156145dd57600080fd5b85356145e881614332565b945060208601356145f881614332565b9350604086013561460881614347565b925060608601356001600160401b0381111561462357600080fd5b61462f88828901614370565b969995985093965092949392505050565b60008060008060006080868803121561465857600080fd5b853561466381614332565b9450602086013561467381614347565b935061460860408701614359565b6000806000806080858703121561469757600080fd5b84356146a281614332565b935060208501356146b281614332565b925060408501356146c281614347565b9396929550929360600135925050565b6000806000606084860312156146e757600080fd5b83356146f281614332565b9250602084013561470281614332565b929592945050506040919091013590565b6000806040838503121561472657600080fd5b823561473181614332565b9150602083013561474181614332565b809150509250929050565b600081518084526020808501945080840160005b838110156147855781516001600160801b031687529582019590820190600101614760565b509495945050505050565b606080825284519082018190526000906020906080840190828801845b828110156147d25781516001600160a01b0316845292840192908401906001016147ad565b5050508381038285015285518082528683019183019060005b8181101561480d57835163ffffffff16835292840192918401916001016147eb565b50508481036040860152614821818761474c565b98975050505050505050565b60008060008060006080868803121561484557600080fd5b853561485081614332565b9450602086013561486081614347565b93506040860135925060608601356001600160401b0381111561462357600080fd5b6000806040838503121561489557600080fd5b82356148a081614332565b946020939093013593505050565b600080600080606085870312156148c457600080fd5b84356148cf81614332565b935060208501356148df81614347565b925060408501356001600160401b038111156148fa57600080fd5b61490687828801614370565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115612d0e57612d0e614912565b81810381811115612d0e57612d0e614912565b600081518084526020808501945080840160005b8381101561478557815187529582019590820190600101614962565b828152604060208201526000613f2b604083018461494e565b6001600160801b038181168382160190808211156149b7576149b7614912565b5092915050565b6001600160801b038281168282160390808211156149b7576149b7614912565b80820260008212600160ff1b841416156149fa576149fa614912565b8181058314821517612d0e57612d0e614912565b6000600160ff1b8201614a2357614a23614912565b5060000390565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03841681526001600160801b0383166020820152606060408201819052600090614a7690830184614467565b95945050505050565b6001600160a01b038516815263ffffffff841660208201526001600160801b0383166040820152608060608201819052600090614abe90830184614467565b9695505050505050565b6001600160a01b0383168152604060208201819052600090613f2b90830184614467565b6001600160a01b038416815263ffffffff83166020820152606060408201819052600090614a7690830184614467565b600060208284031215614b2e57600080fd5b5051919050565b8082028115828204841417612d0e57612d0e614912565b600082614b6957634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b634e487b7160e01b600052604160045260246000fd5b60405161016081016001600160401b0381118282101715614bfc57614bfc614bc3565b60405290565b604051601f8201601f191681016001600160401b0381118282101715614c2a57614c2a614bc3565b604052919050565b60006001600160401b03821115614c4b57614c4b614bc3565b5060051b60200190565b600082601f830112614c6657600080fd5b81516020614c7b614c7683614c32565b614c02565b82815260059290921b84018101918181019086841115614c9a57600080fd5b8286015b84811015614cb55780518352918301918301614c9e565b509695505050505050565b600060208284031215614cd257600080fd5b81516001600160401b03811115614ce857600080fd5b613f2b84828501614c55565b8082018281126000831280158216821582161715614d1457614d14614912565b505092915050565b600063ffffffff808316818103614d3557614d35614912565b6001019392505050565b805161413081614332565b600060208284031215614d5c57600080fd5b815161456281614332565b8051801515811461413057600080fd5b600060208284031215614d8957600080fd5b612d0b82614d67565b805160ff8116811461413057600080fd5b80516001600160e01b03198116811461413057600080fd5b600082601f830112614dcc57600080fd5b81516001600160401b03811115614de557614de5614bc3565b614df8601f8201601f1916602001614c02565b818152846020838601011115614e0d57600080fd5b613f2b826020830160208701614443565b600060208284031215614e3057600080fd5b81516001600160401b0380821115614e4757600080fd5b908301906101608286031215614e5c57600080fd5b614e64614bd9565b614e6d83614d92565b8152614e7b60208401614d92565b602082015260408301516040820152614e9660608401614d3f565b6060820152614ea760808401614da3565b608082015260a083015182811115614ebe57600080fd5b614eca87828601614dbb565b60a08301525060c083015160c082015260e083015160e0820152610100915081830151828201526101209150614f01828401614d3f565b828201526101409150614f15828401614d3f565b91810191909152949350505050565b600080600060608486031215614f3957600080fd5b614f4284614d67565b9250614f5060208501614d67565b9150604084015190509250925092565b6001600160a01b038681168252851660208201526040810184905260a060608201819052600090614f9390830185614467565b82810360808401526148218185614467565b6001600160a01b0385168152608060208201819052600090614fc990830186614467565b84151560408401528281036060840152614fe38185614467565b979650505050505050565b60006020828403121561500057600080fd5b81516001600160401b0381111561501657600080fd5b613f2b84828501614dbb565b60018060a01b0384168152826020820152606060408201526000614a76606083018461494e565b6001600160a01b038781168252861660208201526040810185905260c06060820181905260009061507c90830186614467565b828103608084015261508e8186614467565b905082810360a08401526150a28185614467565b9998505050505050505050565b60006001600160801b0380881683528087166020840152808616604084015280851660608401525060a06080830152614fe360a0830184614467565b600080604083850312156150fe57600080fd5b82516001600160401b038082111561511557600080fd5b818501915085601f83011261512957600080fd5b81516020615139614c7683614c32565b82815260059290921b8401810191818101908984111561515857600080fd5b948201945b8386101561517f57855161517081614347565b8252948201949082019061515d565b9188015191965090935050508082111561519857600080fd5b506151a585828601614c55565b9150509250929050565b6000600182016151c1576151c1614912565b5060010190565b6000602082840312156151da57600080fd5b815161456281614347565b60a0815260006151f860a0830188614467565b6001600160a01b0396871660208401526040830195909552506060810192909252909216608090920191909152919050565b60408152600061523d6040830185614467565b9050826020830152939250505056fea2646970667358221220ebc7fa3b2c4167f0bd9d5f0a8d36220316e9d9e44294b7f55fc5f2ce31b3474464736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a4ff07cf81c02cfd356184879d953970ca957585
-----Decoded View---------------
Arg [0] : host (address): 0xA4Ff07cF81C02CFD356184879D953970cA957585
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000a4ff07cf81c02cfd356184879d953970ca957585
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.