Source Code
Overview
CELO Balance
CELO Value
$0.00Multichain Info
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 39643668 | 206 days ago | 0 CELO | |||||
| 39643667 | 206 days ago | 0 CELO | |||||
| 39643667 | 206 days ago | 0 CELO | |||||
| 39643667 | 206 days ago | 0 CELO | |||||
| 39643667 | 206 days ago | 0 CELO | |||||
| 39643667 | 206 days ago | 0 CELO | |||||
| 39643667 | 206 days ago | 0 CELO | |||||
| 39643666 | 206 days ago | 0 CELO | |||||
| 39643666 | 206 days ago | 0 CELO | |||||
| 39643664 | 206 days ago | 0 CELO | |||||
| 39643664 | 206 days ago | 0 CELO | |||||
| 39643663 | 206 days ago | 0 CELO | |||||
| 39643663 | 206 days ago | 0 CELO | |||||
| 39643663 | 206 days ago | 0 CELO | |||||
| 39643663 | 206 days ago | 0 CELO | |||||
| 39643661 | 206 days ago | 0 CELO | |||||
| 39643661 | 206 days ago | 0 CELO | |||||
| 39643660 | 206 days ago | 0 CELO | |||||
| 39643660 | 206 days ago | 0 CELO | |||||
| 39643660 | 206 days ago | 0 CELO | |||||
| 39643660 | 206 days ago | 0 CELO | |||||
| 39643658 | 206 days ago | 0 CELO | |||||
| 39643658 | 206 days ago | 0 CELO | |||||
| 39643656 | 206 days ago | 0 CELO | |||||
| 39643656 | 206 days ago | 0 CELO |
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:
Superfluid
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.23;
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { UUPSProxiable } from "../upgradability/UUPSProxiable.sol";
import { UUPSProxy } from "../upgradability/UUPSProxy.sol";
import {
ISuperfluid,
ISuperfluidGovernance,
ISuperAgreement,
ISuperApp,
SuperAppDefinitions,
ContextDefinitions,
BatchOperation,
SuperfluidGovernanceConfigs,
ISuperfluidToken,
ISuperToken,
ISuperTokenFactory
} from "../interfaces/superfluid/ISuperfluid.sol";
import { GeneralDistributionAgreementV1 } from "../agreements/gdav1/GeneralDistributionAgreementV1.sol";
import { SuperfluidUpgradeableBeacon } from "../upgradability/SuperfluidUpgradeableBeacon.sol";
import { CallUtils } from "../libs/CallUtils.sol";
import { CallbackUtils } from "../libs/CallbackUtils.sol";
import { BaseRelayRecipient } from "../libs/BaseRelayRecipient.sol";
import { SimpleForwarder } from "../utils/SimpleForwarder.sol";
import { ERC2771Forwarder } from "../utils/ERC2771Forwarder.sol";
/**
* @dev The Superfluid host implementation.
*
* NOTE:
* - Please read ISuperfluid for implementation notes.
* - For some deeper technical notes, please visit protocol-monorepo wiki area.
*
* @author Superfluid
*/
contract Superfluid is
UUPSProxiable,
ISuperfluid,
BaseRelayRecipient
{
using SafeCast for uint256;
struct AppManifest {
uint256 configWord;
}
// solhint-disable-next-line var-name-mixedcase
bool immutable public NON_UPGRADABLE_DEPLOYMENT;
// solhint-disable-next-line var-name-mixedcase
bool immutable public APP_WHITE_LISTING_ENABLED;
uint64 immutable public CALLBACK_GAS_LIMIT;
// simple forwarder contract used to relay arbitrary calls for batch operations
SimpleForwarder immutable public SIMPLE_FORWARDER;
ERC2771Forwarder immutable internal _ERC2771_FORWARDER;
/**
* @dev Maximum number of level of apps can be composed together
*
* NOTE:
* - TODO Composite app feature is currently disabled. Hence app cannot
* will not be able to call other app.
*/
// solhint-disable-next-line var-name-mixedcase
uint constant public MAX_APP_CALLBACK_LEVEL = 1;
uint32 constant public MAX_NUM_AGREEMENTS = 256;
/* WARNING: NEVER RE-ORDER VARIABLES! Always double-check that new
variables are added APPEND-ONLY. Re-ordering variables can
permanently BREAK the deployed proxy contract. */
/// @dev Governance contract
ISuperfluidGovernance internal _gov;
/// @dev Agreement list indexed by agreement index minus one
ISuperAgreement[] internal _agreementClasses;
/// @dev Mapping between agreement type to agreement index (starting from 1)
mapping (bytes32 => uint) internal _agreementClassIndices;
/// @dev Super token
ISuperTokenFactory internal _superTokenFactory;
/// @dev App manifests
mapping(ISuperApp => AppManifest) internal _appManifests;
/// @dev Composite app white-listing: source app => (target app => isAllowed)
mapping(ISuperApp => mapping(ISuperApp => bool)) internal _compositeApps;
/// @dev Ctx stamp of the current transaction, it should always be cleared to
/// zero before transaction finishes
bytes32 internal _ctxStamp;
/// @dev if app whitelisting is enabled, this is to make sure the keys are used only once
mapping(bytes32 => bool) internal _appKeysUsedDeprecated;
/// NOTE: Whenever modifying the storage layout here it is important to update the validateStorageLayout
/// function in its respective mock contract to ensure that it doesn't break anything or lead to unexpected
/// behaviors/layout when upgrading
constructor(
bool nonUpgradable,
bool appWhiteListingEnabled,
uint64 callbackGasLimit,
address simpleForwarderAddress,
address erc2771ForwarderAddress
) {
NON_UPGRADABLE_DEPLOYMENT = nonUpgradable;
APP_WHITE_LISTING_ENABLED = appWhiteListingEnabled;
CALLBACK_GAS_LIMIT = callbackGasLimit;
SIMPLE_FORWARDER = SimpleForwarder(simpleForwarderAddress);
_ERC2771_FORWARDER = ERC2771Forwarder(erc2771ForwarderAddress);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// UUPSProxiable
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function initialize(
ISuperfluidGovernance gov
)
external
initializer // OpenZeppelin Initializable
{
_gov = gov;
}
function proxiableUUID() public pure override returns (bytes32) {
return keccak256("org.superfluid-finance.contracts.Superfluid.implementation");
}
function updateCode(address newAddress) external override onlyGovernance {
if (NON_UPGRADABLE_DEPLOYMENT) revert HOST_NON_UPGRADEABLE();
if (Superfluid(newAddress).NON_UPGRADABLE_DEPLOYMENT()) revert HOST_CANNOT_DOWNGRADE_TO_NON_UPGRADEABLE();
_updateCodeAddress(newAddress);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Time
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function getNow() public view returns (uint256) {
// solhint-disable-next-line not-rely-on-time
return block.timestamp;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Governance
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function getGovernance() external view override returns (ISuperfluidGovernance) {
return _gov;
}
function replaceGovernance(ISuperfluidGovernance newGov) external override onlyGovernance {
emit GovernanceReplaced(_gov, newGov);
_gov = newGov;
}
/**************************************************************************
* Agreement Whitelisting
*************************************************************************/
function registerAgreementClass(ISuperAgreement agreementClassLogic) external onlyGovernance override {
bytes32 agreementType = agreementClassLogic.agreementType();
if (_agreementClassIndices[agreementType] != 0) {
revert HOST_AGREEMENT_ALREADY_REGISTERED();
}
if (_agreementClasses.length >= MAX_NUM_AGREEMENTS) revert HOST_MAX_256_AGREEMENTS();
ISuperAgreement agreementClass;
if (!NON_UPGRADABLE_DEPLOYMENT) {
// initialize the proxy
UUPSProxy proxy = new UUPSProxy();
proxy.initializeProxy(address(agreementClassLogic));
agreementClass = ISuperAgreement(address(proxy));
} else {
agreementClass = ISuperAgreement(address(agreementClassLogic));
}
// register the agreement proxy
_agreementClasses.push((agreementClass));
_agreementClassIndices[agreementType] = _agreementClasses.length;
emit AgreementClassRegistered(agreementType, address(agreementClassLogic));
}
function updateAgreementClass(ISuperAgreement agreementClassLogic) external onlyGovernance override {
if (NON_UPGRADABLE_DEPLOYMENT) revert HOST_NON_UPGRADEABLE();
bytes32 agreementType = agreementClassLogic.agreementType();
uint idx = _agreementClassIndices[agreementType];
if (idx == 0) {
revert HOST_AGREEMENT_IS_NOT_REGISTERED();
}
UUPSProxiable proxiable = UUPSProxiable(address(_agreementClasses[idx - 1]));
proxiable.updateCode(address(agreementClassLogic));
emit AgreementClassUpdated(agreementType, address(agreementClassLogic));
}
function isAgreementTypeListed(bytes32 agreementType)
external view override
returns (bool yes)
{
uint idx = _agreementClassIndices[agreementType];
return idx != 0;
}
function isAgreementClassListed(ISuperAgreement agreementClass)
public view override
returns (bool yes)
{
bytes32 agreementType = agreementClass.agreementType();
uint idx = _agreementClassIndices[agreementType];
// it should also be the same agreement class proxy address
return idx != 0 && _agreementClasses[idx - 1] == agreementClass;
}
function getAgreementClass(bytes32 agreementType)
external view override
returns(ISuperAgreement agreementClass)
{
uint idx = _agreementClassIndices[agreementType];
if (idx == 0) {
revert HOST_AGREEMENT_IS_NOT_REGISTERED();
}
return ISuperAgreement(_agreementClasses[idx - 1]);
}
function mapAgreementClasses(uint256 bitmap)
external view override
returns (ISuperAgreement[] memory agreementClasses) {
uint i;
uint n;
// create memory output using the counted size
agreementClasses = new ISuperAgreement[](_agreementClasses.length);
// add to the output
n = 0;
for (i = 0; i < _agreementClasses.length; ++i) {
if ((bitmap & (1 << i)) > 0) {
agreementClasses[n++] = _agreementClasses[i];
}
}
// resize memory arrays
assembly { mstore(agreementClasses, n) }
}
function addToAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType)
external view override
returns (uint256 newBitmap)
{
uint idx = _agreementClassIndices[agreementType];
if (idx == 0) {
revert HOST_AGREEMENT_IS_NOT_REGISTERED();
}
return bitmap | (1 << (idx - 1));
}
function removeFromAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType)
external view override
returns (uint256 newBitmap)
{
uint idx = _agreementClassIndices[agreementType];
if (idx == 0) {
revert HOST_AGREEMENT_IS_NOT_REGISTERED();
}
return bitmap & ~(1 << (idx - 1));
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Super Token Factory
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function getSuperTokenFactory()
external view override
returns (ISuperTokenFactory factory)
{
return _superTokenFactory;
}
function getSuperTokenFactoryLogic()
external view override
returns (address logic)
{
assert(address(_superTokenFactory) != address(0));
if (NON_UPGRADABLE_DEPLOYMENT) return address(_superTokenFactory);
else return UUPSProxiable(address(_superTokenFactory)).getCodeAddress();
}
function updateSuperTokenFactory(ISuperTokenFactory newFactory)
external override
onlyGovernance
{
if (address(_superTokenFactory) == address(0)) {
if (!NON_UPGRADABLE_DEPLOYMENT) {
// initialize the proxy
UUPSProxy proxy = new UUPSProxy();
proxy.initializeProxy(address(newFactory));
_superTokenFactory = ISuperTokenFactory(address(proxy));
} else {
_superTokenFactory = newFactory;
}
_superTokenFactory.initialize();
} else {
if (NON_UPGRADABLE_DEPLOYMENT) revert HOST_NON_UPGRADEABLE();
UUPSProxiable(address(_superTokenFactory)).updateCode(address(newFactory));
}
emit SuperTokenFactoryUpdated(_superTokenFactory);
}
function updateSuperTokenLogic(ISuperToken token, address newLogicOverride)
external override
onlyGovernance
{
address newLogic = newLogicOverride != address(0) ?
newLogicOverride :
address(_superTokenFactory.getSuperTokenLogic());
// assuming it's uups proxiable
UUPSProxiable(address(token)).updateCode(newLogic);
emit SuperTokenLogicUpdated(token, newLogic);
}
function changeSuperTokenAdmin(ISuperToken token, address newAdmin) external onlyGovernance {
token.changeAdmin(newAdmin);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Superfluid Upgradeable Beacon
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @inheritdoc ISuperfluid
function updatePoolBeaconLogic(address newLogic) external override onlyGovernance {
GeneralDistributionAgreementV1 gda = GeneralDistributionAgreementV1(
address(
this.getAgreementClass(keccak256("org.superfluid-finance.agreements.GeneralDistributionAgreement.v1"))
)
);
SuperfluidUpgradeableBeacon beacon = SuperfluidUpgradeableBeacon(address(gda.superfluidPoolBeacon()));
beacon.upgradeTo(newLogic);
emit PoolBeaconLogicUpdated(address(beacon), newLogic);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// App Registry
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @inheritdoc ISuperfluid
function registerApp(uint256 configWord) external override {
if (APP_WHITE_LISTING_ENABLED) {
// for historical reasons, we internal use "k1" as default registration key
// solhint-disable-next-line avoid-tx-origin
_enforceAppRegistrationPermissioning("k1", tx.origin);
}
_registerApp(ISuperApp(msg.sender), configWord);
}
/// @inheritdoc ISuperfluid
function registerApp(ISuperApp app, uint256 configWord) external override {
// Cannot register an EOA as SuperApp
if ((address(app)).code.length == 0) revert HOST_MUST_BE_CONTRACT();
if (APP_WHITE_LISTING_ENABLED) {
_enforceAppRegistrationPermissioning("k1", msg.sender);
}
_registerApp(app, configWord);
}
/// @custom:deprecated
function registerAppWithKey(uint256 configWord, string calldata registrationKey)
external override
{
if (APP_WHITE_LISTING_ENABLED) {
// solhint-disable-next-line avoid-tx-origin
_enforceAppRegistrationPermissioning(registrationKey, tx.origin);
}
_registerApp(ISuperApp(msg.sender), configWord);
}
// internally we keep using the gov config method with key
function _enforceAppRegistrationPermissioning(string memory registrationKey, address deployer) internal view {
bytes32 configKey = SuperfluidGovernanceConfigs.getAppRegistrationConfigKey(
// solhint-disable-next-line avoid-tx-origin
deployer,
registrationKey
);
// check if the key is valid and not expired
if (
_gov.getConfigAsUint256(
this,
ISuperfluidToken(address(0)),
configKey
// solhint-disable-next-line not-rely-on-time
) < block.timestamp)
{
revert HOST_NO_APP_REGISTRATION_PERMISSION();
}
}
/// @custom:deprecated
function registerAppByFactory(ISuperApp app, uint256 configWord) external override {
// Cannot register an EOA as SuperApp
if ((address(app)).code.length == 0) revert HOST_MUST_BE_CONTRACT();
if (APP_WHITE_LISTING_ENABLED) {
// enforce permissiniong with legacy gov config key for app factory
bytes32 configKey = SuperfluidGovernanceConfigs.getAppFactoryConfigKey(msg.sender);
bool isAuthorizedAppFactory = _gov.getConfigAsUint256(this, ISuperfluidToken(address(0)), configKey) == 1;
if (!isAuthorizedAppFactory) revert HOST_NO_APP_REGISTRATION_PERMISSION();
// We do not enforce any assumptions about what a "factory" is. It is whatever gov decided to.
}
_registerApp(app, configWord);
}
function _registerApp(ISuperApp app, uint256 configWord) private {
// validate configWord
if (
!SuperAppDefinitions.isConfigWordClean(configWord) ||
SuperAppDefinitions.getAppCallbackLevel(configWord) == 0 ||
(configWord & SuperAppDefinitions.APP_JAIL_BIT) != 0
) {
revert HOST_INVALID_CONFIG_WORD();
}
if (_appManifests[ISuperApp(app)].configWord != 0) revert HOST_SUPER_APP_ALREADY_REGISTERED();
_appManifests[ISuperApp(app)] = AppManifest(configWord);
emit AppRegistered(app);
}
function isApp(ISuperApp app) public view override returns(bool) {
return _appManifests[app].configWord > 0;
}
function getAppCallbackLevel(ISuperApp appAddr) public override view returns(uint8) {
return SuperAppDefinitions.getAppCallbackLevel(_appManifests[appAddr].configWord);
}
function getAppManifest(
ISuperApp app
)
external view override
returns (
bool isSuperApp,
bool isJailed,
uint256 noopMask
)
{
AppManifest memory manifest = _appManifests[app];
isSuperApp = (manifest.configWord > 0);
if (isSuperApp) {
isJailed = SuperAppDefinitions.isAppJailed(manifest.configWord);
noopMask = manifest.configWord & SuperAppDefinitions.AGREEMENT_CALLBACK_NOOP_BITMASKS;
}
}
function isAppJailed(
ISuperApp app
)
external view override
returns(bool)
{
return SuperAppDefinitions.isAppJailed(_appManifests[app].configWord);
}
function allowCompositeApp(
ISuperApp targetApp
)
external override
{
ISuperApp sourceApp = ISuperApp(msg.sender);
if (!isApp(sourceApp)) revert HOST_SENDER_IS_NOT_SUPER_APP();
if (!isApp(targetApp)) revert HOST_RECEIVER_IS_NOT_SUPER_APP();
if (getAppCallbackLevel(sourceApp) <= getAppCallbackLevel(targetApp)) {
revert HOST_SOURCE_APP_NEEDS_HIGHER_APP_LEVEL();
}
_compositeApps[sourceApp][targetApp] = true;
}
function isCompositeAppAllowed(
ISuperApp app,
ISuperApp targetApp
)
external view override
returns (bool)
{
return _compositeApps[app][targetApp];
}
/**************************************************************************
* Agreement Framework
*************************************************************************/
function callAppBeforeCallback(
ISuperApp app,
bytes calldata callData,
bool isTermination,
bytes calldata ctx
)
external override
onlyAgreement
assertValidCtx(ctx)
returns(bytes memory cbdata)
{
(bool success, bytes memory returnedData) = _callCallback(app, true, isTermination, callData, ctx);
if (success) {
if (CallUtils.isValidAbiEncodedBytes(returnedData)) {
cbdata = abi.decode(returnedData, (bytes));
} else {
if (!isTermination) {
revert APP_RULE(SuperAppDefinitions.APP_RULE_CTX_IS_MALFORMATED);
} else {
_jailApp(app, SuperAppDefinitions.APP_RULE_CTX_IS_MALFORMATED);
}
}
}
}
function callAppAfterCallback(
ISuperApp app,
bytes calldata callData,
bool isTermination,
bytes calldata ctx
)
external override
onlyAgreement
assertValidCtx(ctx)
returns(bytes memory newCtx)
{
(bool success, bytes memory returnedData) = _callCallback(app, false, isTermination, callData, ctx);
if (success) {
// the non static callback should not return empty ctx
if (CallUtils.isValidAbiEncodedBytes(returnedData)) {
newCtx = abi.decode(returnedData, (bytes));
if (!_isCtxValid(newCtx)) {
if (!isTermination) {
revert APP_RULE(SuperAppDefinitions.APP_RULE_CTX_IS_READONLY);
} else {
newCtx = ctx;
_jailApp(app, SuperAppDefinitions.APP_RULE_CTX_IS_READONLY);
}
}
} else {
if (!isTermination) {
revert APP_RULE(SuperAppDefinitions.APP_RULE_CTX_IS_MALFORMATED);
} else {
newCtx = ctx;
_jailApp(app, SuperAppDefinitions.APP_RULE_CTX_IS_MALFORMATED);
}
}
} else {
newCtx = ctx;
}
}
function appCallbackPush(
bytes calldata ctx,
ISuperApp app,
uint256 appCreditGranted,
int256 appCreditUsed,
ISuperfluidToken appCreditToken
)
external override
onlyAgreement
assertValidCtx(ctx)
returns (bytes memory appCtx)
{
Context memory context = decodeCtx(ctx);
// NOTE: we use 1 as a magic number here as we want to do this check once we are in a callback
// we use 1 instead of MAX_APP_CALLBACK_LEVEL because 1 captures what we are trying to enforce
if (isApp(ISuperApp(context.msgSender)) && context.appCallbackLevel >= 1) {
if (!_compositeApps[ISuperApp(context.msgSender)][app]) {
revert APP_RULE(SuperAppDefinitions.APP_RULE_COMPOSITE_APP_IS_NOT_WHITELISTED);
}
}
context.appCallbackLevel++;
context.callType = ContextDefinitions.CALL_INFO_CALL_TYPE_APP_CALLBACK;
context.appCreditGranted = appCreditGranted;
context.appCreditUsed = appCreditUsed;
context.appAddress = address(app);
context.appCreditToken = appCreditToken;
appCtx = _updateContext(context);
}
function appCallbackPop(
bytes calldata ctx,
int256 appCreditUsedDelta
)
external override
onlyAgreement
returns (bytes memory newCtx)
{
Context memory context = decodeCtx(ctx);
context.appCreditUsed += appCreditUsedDelta;
newCtx = _updateContext(context);
}
function ctxUseCredit(
bytes calldata ctx,
int256 appCreditUsedMore
)
external override
onlyAgreement
assertValidCtx(ctx)
returns (bytes memory newCtx)
{
Context memory context = decodeCtx(ctx);
context.appCreditUsed += appCreditUsedMore;
newCtx = _updateContext(context);
}
function jailApp(
bytes calldata ctx,
ISuperApp app,
uint256 reason
)
external override
onlyAgreement
assertValidCtx(ctx)
returns (bytes memory newCtx)
{
_jailApp(app, reason);
return ctx;
}
/**************************************************************************
* Contextless Call Proxies
*************************************************************************/
function _callAgreement(
address msgSender,
ISuperAgreement agreementClass,
bytes memory callData,
bytes memory userData
)
internal
cleanCtx
isAgreement(agreementClass)
returns(bytes memory returnedData)
{
// beware of the endianness
bytes4 agreementSelector = CallUtils.parseSelector(callData);
//Build context data
bytes memory ctx = _updateContext(Context({
appCallbackLevel: 0,
callType: ContextDefinitions.CALL_INFO_CALL_TYPE_AGREEMENT,
timestamp: getNow(),
msgSender: msgSender,
agreementSelector: agreementSelector,
userData: userData,
appCreditGranted: 0,
appCreditWantedDeprecated: 0,
appCreditUsed: 0,
appAddress: address(0),
appCreditToken: ISuperfluidToken(address(0))
}));
bool success;
(success, returnedData) = _callExternalWithReplacedCtx(address(agreementClass), callData, 0, ctx);
if (!success) {
CallUtils.revertFromReturnedData(returnedData);
}
// clear the stamp
_ctxStamp = 0;
}
function callAgreement(
ISuperAgreement agreementClass,
bytes memory callData,
bytes memory userData
)
external override
returns(bytes memory returnedData)
{
return _callAgreement(msg.sender, agreementClass, callData, userData);
}
function _callAppAction(
address msgSender,
ISuperApp app,
uint256 value,
bytes memory callData
)
internal
cleanCtx
isAppActive(app)
isValidAppAction(callData)
returns(bytes memory returnedData)
{
// Build context data
bytes memory ctx = _updateContext(Context({
appCallbackLevel: 0,
callType: ContextDefinitions.CALL_INFO_CALL_TYPE_APP_ACTION,
timestamp: getNow(),
msgSender: msgSender,
agreementSelector: 0,
userData: "",
appCreditGranted: 0,
appCreditWantedDeprecated: 0,
appCreditUsed: 0,
appAddress: address(app),
appCreditToken: ISuperfluidToken(address(0))
}));
bool success;
(success, returnedData) = _callExternalWithReplacedCtx(address(app), callData, value, ctx);
if (success) {
ctx = abi.decode(returnedData, (bytes));
if (!_isCtxValid(ctx)) revert APP_RULE(SuperAppDefinitions.APP_RULE_CTX_IS_READONLY);
} else {
CallUtils.revertFromReturnedData(returnedData);
}
// clear the stamp
_ctxStamp = 0;
}
function callAppAction(
ISuperApp app,
bytes memory callData
)
external override // NOTE: modifiers are called in _callAppAction
returns(bytes memory returnedData)
{
return _callAppAction(msg.sender, app, 0, callData);
}
/**************************************************************************
* Contextual Call Proxies
*************************************************************************/
function callAgreementWithContext(
ISuperAgreement agreementClass,
bytes calldata callData,
bytes calldata userData,
bytes calldata ctx
)
external override
requireValidCtx(ctx)
isAgreement(agreementClass)
returns (bytes memory newCtx, bytes memory returnedData)
{
Context memory context = decodeCtx(ctx);
if (context.appAddress != msg.sender) revert HOST_CALL_AGREEMENT_WITH_CTX_FROM_WRONG_ADDRESS();
address oldSender = context.msgSender;
context.msgSender = msg.sender;
//context.agreementSelector =;
context.userData = userData;
newCtx = _updateContext(context);
bool success;
(success, returnedData) = _callExternalWithReplacedCtx(address(agreementClass), callData, 0, newCtx);
if (success) {
(newCtx) = abi.decode(returnedData, (bytes));
assert(_isCtxValid(newCtx));
// back to old msg.sender
context = decodeCtx(newCtx);
context.msgSender = oldSender;
newCtx = _updateContext(context);
} else {
CallUtils.revertFromReturnedData(returnedData);
}
}
function callAppActionWithContext(
ISuperApp app,
bytes calldata callData,
bytes calldata ctx
)
external override
requireValidCtx(ctx)
isAppActive(app)
isValidAppAction(callData)
returns(bytes memory newCtx)
{
Context memory context = decodeCtx(ctx);
if (context.appAddress != msg.sender) revert HOST_CALL_APP_ACTION_WITH_CTX_FROM_WRONG_ADDRESS();
address oldSender = context.msgSender;
context.msgSender = msg.sender;
newCtx = _updateContext(context);
(bool success, bytes memory returnedData) = _callExternalWithReplacedCtx(address(app), callData, 0, newCtx);
if (success) {
(newCtx) = abi.decode(returnedData, (bytes));
if (!_isCtxValid(newCtx)) revert APP_RULE(SuperAppDefinitions.APP_RULE_CTX_IS_READONLY);
// back to old msg.sender
context = decodeCtx(newCtx);
context.msgSender = oldSender;
newCtx = _updateContext(context);
} else {
CallUtils.revertFromReturnedData(returnedData);
}
}
function decodeCtx(bytes memory ctx)
public pure override
returns (Context memory context)
{
return _decodeCtx(ctx);
}
function isCtxValid(bytes calldata ctx)
external view override
returns (bool)
{
return _isCtxValid(ctx);
}
/**************************************************************************
* Batch call
**************************************************************************/
function _batchCall(
address payable msgSender,
Operation[] calldata operations
)
internal
{
for (uint256 i = 0; i < operations.length; ++i) {
uint32 operationType = operations[i].operationType;
if (operationType == BatchOperation.OPERATION_TYPE_ERC20_APPROVE) {
(address spender, uint256 amount) =
abi.decode(operations[i].data, (address, uint256));
ISuperToken(operations[i].target).operationApprove(
msgSender,
spender,
amount);
} else if (operationType == BatchOperation.OPERATION_TYPE_ERC20_TRANSFER_FROM) {
(address sender, address receiver, uint256 amount) =
abi.decode(operations[i].data, (address, address, uint256));
ISuperToken(operations[i].target).operationTransferFrom(
msgSender,
sender,
receiver,
amount);
} else if (operationType == BatchOperation.OPERATION_TYPE_ERC777_SEND) {
(address recipient, uint256 amount, bytes memory userData) =
abi.decode(operations[i].data, (address, uint256, bytes));
ISuperToken(operations[i].target).operationSend(
msgSender,
recipient,
amount,
userData);
} else if (operationType == BatchOperation.OPERATION_TYPE_ERC20_INCREASE_ALLOWANCE) {
(address spender, uint256 addedValue) =
abi.decode(operations[i].data, (address, uint256));
ISuperToken(operations[i].target).operationIncreaseAllowance(
msgSender,
spender,
addedValue);
} else if (operationType == BatchOperation.OPERATION_TYPE_ERC20_DECREASE_ALLOWANCE) {
(address spender, uint256 subtractedValue) =
abi.decode(operations[i].data, (address, uint256));
ISuperToken(operations[i].target).operationDecreaseAllowance(
msgSender,
spender,
subtractedValue);
} else if (operationType == BatchOperation.OPERATION_TYPE_SUPERTOKEN_UPGRADE) {
ISuperToken(operations[i].target).operationUpgrade(
msgSender,
abi.decode(operations[i].data, (uint256))); // amount
} else if (operationType == BatchOperation.OPERATION_TYPE_SUPERTOKEN_DOWNGRADE) {
ISuperToken(operations[i].target).operationDowngrade(
msgSender,
abi.decode(operations[i].data, (uint256))); // amount
} else if (operationType == BatchOperation.OPERATION_TYPE_SUPERTOKEN_UPGRADE_TO) {
(address to, uint256 amount) = abi.decode(operations[i].data, (address, uint256));
ISuperToken(operations[i].target).operationUpgradeTo(
msgSender,
to,
amount);
} else if (operationType == BatchOperation.OPERATION_TYPE_SUPERTOKEN_DOWNGRADE_TO) {
(address to, uint256 amount) = abi.decode(operations[i].data, (address, uint256));
ISuperToken(operations[i].target).operationDowngradeTo(
msgSender,
to,
amount);
} else if (operationType == BatchOperation.OPERATION_TYPE_SUPERFLUID_CALL_AGREEMENT) {
(bytes memory callData, bytes memory userData) = abi.decode(operations[i].data, (bytes, bytes));
_callAgreement(
msgSender,
ISuperAgreement(operations[i].target),
callData,
userData);
}
// The following operations for call proxies allow forwarding of native tokens.
// we use `address(this).balance` instead of `msg.value`, because the latter ist not
// updated after forwarding to the first operation, while `balance` is.
// The initial balance is equal to `msg.value` because there's no other path
// for the contract to receive native tokens.
else if (operationType == BatchOperation.OPERATION_TYPE_SUPERFLUID_CALL_APP_ACTION) {
_callAppAction(
msgSender,
ISuperApp(operations[i].target),
address(this).balance,
operations[i].data);
} else if (operationType == BatchOperation.OPERATION_TYPE_SIMPLE_FORWARD_CALL) {
(bool success, bytes memory returnData) =
SIMPLE_FORWARDER.forwardCall{value: address(this).balance}(
operations[i].target,
operations[i].data);
if (!success) {
CallUtils.revertFromReturnedData(returnData);
}
} else if (operationType == BatchOperation.OPERATION_TYPE_ERC2771_FORWARD_CALL) {
(bool success, bytes memory returnData) =
_ERC2771_FORWARDER.forward2771Call{value: address(this).balance}(
operations[i].target,
msgSender,
operations[i].data);
if (!success) {
CallUtils.revertFromReturnedData(returnData);
}
} else {
revert HOST_UNKNOWN_BATCH_CALL_OPERATION_TYPE();
}
}
if (address(this).balance != 0) {
// return any native tokens left to the sender.
msgSender.transfer(address(this).balance);
}
}
/// @dev ISuperfluid.batchCall implementation
function batchCall(
Operation[] calldata operations
)
external override payable
{
_batchCall(payable(msg.sender), operations);
}
/// @dev ISuperfluid.forwardBatchCall implementation
function forwardBatchCall(Operation[] calldata operations)
external override payable
{
_batchCall(_getTransactionSigner(), operations);
}
/// @dev BaseRelayRecipient.isTrustedForwarder implementation
function isTrustedForwarder(address forwarder)
public view override
returns(bool)
{
return _gov.getConfigAsUint256(
this,
ISuperfluidToken(address(0)),
SuperfluidGovernanceConfigs.getTrustedForwarderConfigKey(forwarder)
) != 0;
}
/// @dev IRelayRecipient.versionRecipient implementation
function versionRecipient()
external override pure
returns (string memory)
{
return "v1";
}
function getERC2771Forwarder() external view override returns(address) {
return address(_ERC2771_FORWARDER);
}
/**************************************************************************
* Internal
**************************************************************************/
function _jailApp(ISuperApp app, uint256 reason)
internal
{
if ((_appManifests[app].configWord & SuperAppDefinitions.APP_JAIL_BIT) == 0) {
_appManifests[app].configWord |= SuperAppDefinitions.APP_JAIL_BIT;
emit Jail(app, reason);
}
}
function _updateContext(Context memory context)
private
returns (bytes memory ctx)
{
if (context.appCallbackLevel > MAX_APP_CALLBACK_LEVEL) {
revert APP_RULE(SuperAppDefinitions.APP_RULE_MAX_APP_LEVEL_REACHED);
}
uint256 callInfo = ContextDefinitions.encodeCallInfo(context.appCallbackLevel, context.callType);
uint256 creditIO =
context.appCreditGranted.toUint128() |
(uint256(context.appCreditWantedDeprecated.toUint128()) << 128);
// NOTE: nested encoding done due to stack too deep error when decoding in _decodeCtx
ctx = abi.encode(
abi.encode(
callInfo,
context.timestamp,
context.msgSender,
context.agreementSelector,
context.userData
),
abi.encode(
creditIO,
context.appCreditUsed,
context.appAddress,
context.appCreditToken
)
);
_ctxStamp = keccak256(ctx);
}
function _decodeCtx(bytes memory ctx)
private pure
returns (Context memory context)
{
bytes memory ctx1;
bytes memory ctx2;
(ctx1, ctx2) = abi.decode(ctx, (bytes, bytes));
{
uint256 callInfo;
(
callInfo,
context.timestamp,
context.msgSender,
context.agreementSelector,
context.userData
) = abi.decode(ctx1, (
uint256,
uint256,
address,
bytes4,
bytes));
(context.appCallbackLevel, context.callType) = ContextDefinitions.decodeCallInfo(callInfo);
}
{
uint256 creditIO;
(
creditIO,
context.appCreditUsed,
context.appAddress,
context.appCreditToken
) = abi.decode(ctx2, (
uint256,
int256,
address,
ISuperfluidToken));
context.appCreditGranted = creditIO & type(uint128).max;
context.appCreditWantedDeprecated = creditIO >> 128;
}
}
function _isCtxValid(bytes memory ctx) private view returns (bool) {
return ctx.length != 0 && keccak256(ctx) == _ctxStamp;
}
function _callExternalWithReplacedCtx(
address target,
bytes memory callData,
uint256 value,
bytes memory ctx
)
private
returns(bool success, bytes memory returnedData)
{
assert(target != address(0));
// STEP 1 : replace placeholder ctx with actual ctx
callData = _replacePlaceholderCtx(callData, ctx);
// STEP 2: Call external with replaced context
/* solhint-disable-next-line avoid-low-level-calls */
(success, returnedData) = target.call{value: value}(callData);
// if target is not a contract or some arbitrary address,
// success will be true and returnedData will be 0x (length = 0)
// this leads to unintended behaviors, so we want to check to ensure
// that the length of returnedData is greater than 0
if (success) {
if (returnedData.length == 0) {
revert APP_RULE(SuperAppDefinitions.APP_RULE_CTX_IS_MALFORMATED);
}
}
}
function _callCallback(
ISuperApp app,
bool isStaticall,
bool isTermination,
bytes memory callData,
bytes memory ctx
)
private
returns(bool success, bytes memory returnedData)
{
assert(address(app) != address(0));
callData = _replacePlaceholderCtx(callData, ctx);
uint256 callbackGasLimit = CALLBACK_GAS_LIMIT;
bool insufficientCallbackGasProvided;
(success, insufficientCallbackGasProvided, returnedData) = isStaticall ?
CallbackUtils.staticCall(address(app), callData, callbackGasLimit) :
CallbackUtils.externalCall(address(app), callData, callbackGasLimit);
if (!success) {
if (!insufficientCallbackGasProvided) {
if (!isTermination) {
CallUtils.revertFromReturnedData(returnedData);
} else {
_jailApp(app, SuperAppDefinitions.APP_RULE_NO_REVERT_ON_TERMINATION_CALLBACK);
}
} else {
// For legit out of gas issue, the call may still fail if more gas is provided
// and this is okay, because there can be incentive to jail the app by providing
// more gas.
revert HOST_NEED_MORE_GAS();
}
}
}
/**
* @dev Replace the placeholder ctx with the actual ctx
*/
function _replacePlaceholderCtx(bytes memory data, bytes memory ctx)
internal pure
returns (bytes memory dataWithCtx)
{
// 1.a ctx needs to be padded to align with 32 bytes boundary
uint256 dataLen = data.length;
// Double check if the ctx is a placeholder ctx
//
// NOTE: This can't check all cases - user can still put nonzero length of zero data
// developer experience check. So this is more like a sanity check for clumsy app developers.
//
// So, agreements MUST NOT TRUST the ctx passed to it, and always use the isCtxValid first.
{
uint256 placeHolderCtxLength;
// NOTE: len(data) is data.length + 32 https://docs.soliditylang.org/en/latest/abi-spec.html
// solhint-disable-next-line no-inline-assembly
assembly { placeHolderCtxLength := mload(add(data, dataLen)) }
if (placeHolderCtxLength != 0) revert HOST_NON_ZERO_LENGTH_PLACEHOLDER_CTX();
}
// 1.b remove the placeholder ctx
// solhint-disable-next-line no-inline-assembly
assembly { mstore(data, sub(dataLen, 0x20)) }
// 1.c pack data with the replacement ctx
return abi.encodePacked(
data,
// bytes with padded length
uint256(ctx.length),
ctx, new bytes(CallUtils.padLength32(ctx.length) - ctx.length) // ctx padding
);
// NOTE: the alternative placeholderCtx is passing extra calldata to the agreements
// agreements would use assembly code to read the ctx
// Because selector is part of calldata, we do the padding internally, instead of
// outside
}
modifier requireValidCtx(bytes memory ctx) {
if (!_isCtxValid(ctx)) revert APP_RULE(SuperAppDefinitions.APP_RULE_CTX_IS_READONLY);
_;
}
modifier assertValidCtx(bytes memory ctx) {
assert(_isCtxValid(ctx));
_;
}
modifier cleanCtx() {
if (_ctxStamp != 0) revert APP_RULE(SuperAppDefinitions.APP_RULE_CTX_IS_NOT_CLEAN);
_;
}
modifier isAgreement(ISuperAgreement agreementClass) {
if (!isAgreementClassListed(agreementClass)) {
revert HOST_ONLY_LISTED_AGREEMENT();
}
_;
}
modifier onlyGovernance() {
if (msg.sender != address(_gov)) revert HOST_ONLY_GOVERNANCE();
_;
}
modifier onlyAgreement() {
if (!isAgreementClassListed(ISuperAgreement(msg.sender))) {
revert HOST_ONLY_LISTED_AGREEMENT();
}
_;
}
modifier isAppActive(ISuperApp app) {
uint256 configWord = _appManifests[app].configWord;
if (configWord == 0) revert HOST_NOT_A_SUPER_APP();
if (SuperAppDefinitions.isAppJailed(configWord)) revert HOST_SUPER_APP_IS_JAILED();
_;
}
modifier isValidAppAction(bytes memory callData) {
bytes4 actionSelector = CallUtils.parseSelector(callData);
if (actionSelector == ISuperApp.beforeAgreementCreated.selector ||
actionSelector == ISuperApp.afterAgreementCreated.selector ||
actionSelector == ISuperApp.beforeAgreementUpdated.selector ||
actionSelector == ISuperApp.afterAgreementUpdated.selector ||
actionSelector == ISuperApp.beforeAgreementTerminated.selector ||
actionSelector == ISuperApp.afterAgreementTerminated.selector) {
revert HOST_AGREEMENT_CALLBACK_IS_NOT_ACTION();
}
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title Forwards arbitrary calls
* @dev The purpose of this contract is to let accounts forward arbitrary calls,
* without themselves being the msg.sender from the perspective of the call target.
* This is necessary for security reasons if the calling account has privileged access anywhere.
*/
contract SimpleForwarder is Ownable {
/**
* @dev Forwards a call for which msg.sender doesn't matter
* @param target The target contract to call
* @param data The call data
* Note: restricted to `onlyOwner` in order to minimize attack surface
*/
function forwardCall(address target, bytes calldata data)
external payable onlyOwner
returns (bool success, bytes memory returnData)
{
// solhint-disable-next-line avoid-low-level-calls
(success, returnData) = target.call{value: msg.value}(data);
}
/**
* @dev Allows to withdraw native tokens (ETH) which got stuck in this contract.
* This could happen if a call fails, but the caller doesn't revert the tx.
*/
function withdrawLostNativeTokens(address payable receiver) external onlyOwner {
receiver.transfer(address(this).balance);
}
}// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.23;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title Forwards calls preserving the original msg.sender according to ERC-2771
*/
contract ERC2771Forwarder is Ownable {
/**
* @dev Forwards a call passing along the original msg.sender encoded as specified in ERC-2771.
* @param target The target contract to call
* @param msgSender The original msg.sender passed along by the trusted contract owner
* @param data The call data
*/
function forward2771Call(address target, address msgSender, bytes memory data)
external payable onlyOwner
returns(bool success, bytes memory returnData)
{
// solhint-disable-next-line avoid-low-level-calls
(success, returnData) = target.call{value: msg.value}(abi.encodePacked(data, msgSender));
}
/**
* @dev Allows to withdraw native tokens (ETH) which got stuck in this contract.
* This could happen if a call fails, but the caller doesn't revert the tx.
*/
function withdrawLostNativeTokens(address payable receiver) external onlyOwner {
receiver.transfer(address(this).balance);
}
}// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.23;
/**
* @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.23;
import { UUPSUtils } from "./UUPSUtils.sol";
import { Proxy } from "@openzeppelin/contracts/proxy/Proxy.sol";
/**
* @title UUPS (Universal Upgradeable Proxy Standard) Proxy
*
* NOTE:
* - Compliant with [Universal Upgradeable Proxy Standard](https://eips.ethereum.org/EIPS/eip-1822)
* - Compiiant with [Standard Proxy Storage Slots](https://eips.ethereum.org/EIPS/eip-1967)
* - Implements delegation of calls to other contracts, with proper forwarding of
* return values and bubbling of failures.
* - It defines a fallback function that delegates all calls to the implementation.
*/
contract UUPSProxy is Proxy {
/**
* @dev Proxy initialization function.
* This should only be called once and it is permission-less.
* @param initialAddress Initial logic contract code address to be used.
*/
function initializeProxy(address initialAddress) external {
require(initialAddress != address(0), "UUPSProxy: zero address");
require(UUPSUtils.implementation() == address(0), "UUPSProxy: already initialized");
UUPSUtils.setImplementation(initialAddress);
}
/// @dev Proxy._implementation implementation
function _implementation() internal virtual override view returns (address)
{
return UUPSUtils.implementation();
}
}// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.23;
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.23;
import {
UpgradeableBeacon
} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
import { BeaconProxiable } from "./BeaconProxiable.sol";
contract SuperfluidUpgradeableBeacon is UpgradeableBeacon {
error ZERO_ADDRESS_IMPLEMENTATION(); // 0x80883162
error INCOMPATIBLE_LOGIC(); // 0x5af2144c
error NO_PROXY_LOOP(); // 0z66750bca
constructor(address implementation_) UpgradeableBeacon(implementation_) {}
function upgradeTo(address newImplementation) public override onlyOwner {
if (newImplementation == address(0)) {
revert ZERO_ADDRESS_IMPLEMENTATION();
}
if (newImplementation == address(this)) {
revert NO_PROXY_LOOP();
}
if (BeaconProxiable(newImplementation).proxiableUUID() != BeaconProxiable(implementation()).proxiableUUID()) {
revert INCOMPATIBLE_LOGIC();
}
super.upgradeTo(newImplementation);
}
}// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.23;
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
abstract contract BeaconProxiable is Initializable {
// 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.
*/
function proxiableUUID() public pure virtual returns (bytes32);
}// SPDX-License-Identifier: AGPLv3
import {
ISuperfluid,
ISuperfluidToken,
ISuperfluidGovernance,
SuperfluidGovernanceConfigs
} from "../interfaces/superfluid/ISuperfluid.sol";
pragma solidity ^0.8.23;
library SolvencyHelperLibrary {
function decode3PsData(ISuperfluid host, ISuperfluidToken token)
internal
view
returns (uint256 liquidationPeriod, uint256 patricianPeriod)
{
ISuperfluidGovernance gov = ISuperfluidGovernance(host.getGovernance());
// @note we are explicitly using CFAV1_PPP_CONFIG_KEY for both CFA and GDA
uint256 pppConfig = gov.getConfigAsUint256(host, token, SuperfluidGovernanceConfigs.CFAV1_PPP_CONFIG_KEY);
(liquidationPeriod, patricianPeriod) = SuperfluidGovernanceConfigs.decodePPPConfig(pppConfig);
}
function isPatricianPeriod(
int256 availableBalance,
int256 signedTotalDeposit,
uint256 liquidationPeriod,
uint256 patricianPeriod
) internal pure returns (bool) {
if (signedTotalDeposit == 0) {
return false;
}
int256 totalRewardLeft = availableBalance + signedTotalDeposit;
int256 totalOutflowRate = signedTotalDeposit / int256(liquidationPeriod);
return totalRewardLeft / totalOutflowRate > int256(liquidationPeriod - patricianPeriod);
}
}// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.23;
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: AGPLv3
pragma solidity ^0.8.23;
/**
* @title Callback utilities solidity library
* @notice An internal library used to handle different types of out of gas errors in callbacks
*
* @dev
*
* ## Problem Statement
*
* When calling an untrusted external callback (or hook), gas limit is usually provided to prevent
* grief attack from them. However, such gas limits are nested. From the callback invoking site, one
* might need to differentiate the cases between the outer-layer induced out-of-gas vs. the callback
* resulted out-of-gas.
*
* This library solves such challenge by safely marking the second case with an explicit flag of
* insufficient-callback-gas-provided. In order to use this library, one must first understand the
* concept of callback gas limit zones.
*
* ## Definitions: callback gas limit zones
*
* +---------------------------+--------------+---------------------+
* | insufficient-callback-gas | transitional | out-of-callback-gas |
* +---------------------------+--------------+---------------------+
*
* - insufficient-callback-gas zone
*
* This zone includes all outer gas limits that are below callback gas limit. The invariance of
* this zone is that calling the callback shall return with the insufficient-callback-gas-provided
* set to true if more gas is needed to execute the callback.
*
* - out-of-callback-gas zone
*
* Within this continuous zone, the invariance is that calling the callback shall never return
* with the insufficient-callback-gas-provided flag set to true.
*
* - transitional zone
*
* Between the insufficient-callback-gas zone to the out-of-callback-gas zone, there is a zone of
* unspecified size where insufficient-callback-gas-provided may be set to true. This is due the
* factors of EIP-150 Magic N and callback setup overhead.
*
* ## EIP-150 Magic N
*
* "If a call asks for more gas than the maximum allowed amount (i.e. the total amount of gas
* remaining in the parent after subtracting the gas cost of the call and memory expansion), do not
* return an OOG error; instead, if a call asks for more gas than all but one 64th of the maximum
* allowed amount, call with all but one 64th of the maximum allowed amount of gas (this is
* equivalent to a version of EIP-90 plus EIP-114). CREATE only provides all but one 64th of the
* parent gas to the child call."
*
* Another article about this topic:
* https://medium.com/%40wighawag/ethereum-the-concept-of-gas-and-its-dangers-28d0eb809bb2
*
*/
library CallbackUtils {
/// The magic N constant from the EIP-150
uint256 internal constant EIP150_MAGIC_N = 64;
/// Make a call to the target with a callback gas limit.
function externalCall(address target, bytes memory callData, uint256 callbackGasLimit) internal
returns (bool success, bool insufficientCallbackGasProvided, bytes memory returnedData)
{
uint256 gasLeftBefore = gasleft();
// solhint-disable-next-line avoid-low-level-calls
(success, returnedData) = address(target).call{ gas: callbackGasLimit }(callData);
if (!success) {
if (gasleft() <= gasLeftBefore / EIP150_MAGIC_N) insufficientCallbackGasProvided = true;
}
}
/// Make a staticcall to the target with a callback gas limit.
function staticCall(address target, bytes memory callData, uint256 callbackGasLimit) internal view
returns (bool success, bool insufficientCallbackGasProvided, bytes memory returnedData)
{
uint256 gasLeftBefore = gasleft();
// solhint-disable-next-line avoid-low-level-calls
(success, returnedData) = address(target).staticcall{ gas: callbackGasLimit }(callData);
if (!success) {
if (gasleft() <= gasLeftBefore / EIP150_MAGIC_N) insufficientCallbackGasProvided = true;
}
}
/// Reliably consume all the gas given.
function consumeAllGas() internal pure {
// Neither revert or assert consume all gas since Solidity 0.8.20
// https://docs.soliditylang.org/en/v0.8.20/control-structures.html#panic-via-assert-and-error-via-require
// @solidity memory-safe-assembly
// solhint-disable-next-line no-inline-assembly
assembly { invalid() }
}
}// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.23;
/**
* @title Call utilities library that is absent from the OpenZeppelin
* @author Superfluid
*/
library CallUtils {
/// @dev Bubble up the revert from the returnedData (supports Panic, Error & Custom Errors)
/// @notice This is needed in order to provide some human-readable revert message from a call
/// @param returnedData Response of the call
function revertFromReturnedData(bytes memory returnedData) internal pure {
if (returnedData.length < 4) {
// case 1: catch all
revert("CallUtils: target revert()");
} else {
bytes4 errorSelector;
assembly {
errorSelector := mload(add(returnedData, 0x20))
}
if (errorSelector == bytes4(0x4e487b71) /* $ seth sig "Panic(uint256)" */) {
// case 2: Panic(uint256) (Defined since 0.8.0)
// solhint-disable-next-line max-line-length
// ref: https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require)
string memory reason = "CallUtils: target panicked: 0x__";
uint errorCode;
assembly {
errorCode := mload(add(returnedData, 0x24))
let reasonWord := mload(add(reason, 0x20))
// [0..9] is converted to ['0'..'9']
// [0xa..0xf] is not correctly converted to ['a'..'f']
// but since panic code doesn't have those cases, we will ignore them for now!
let e1 := add(and(errorCode, 0xf), 0x30)
let e2 := shl(8, add(shr(4, and(errorCode, 0xf0)), 0x30))
reasonWord := or(
and(reasonWord, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000),
or(e2, e1))
mstore(add(reason, 0x20), reasonWord)
}
revert(reason);
} else {
// - case 3: Error(string) (Defined at least since 0.7.0)
// - "The require function either creates an error without any data or an error of type Error(string).
// It should be used to ensure valid conditions that cannot be detected until execution time."
// - $ cast sig 'Error(string)' # 0x08c379a0
// - case 4: Custom errors (Defined since 0.8.0)
// - In all these cases, we bubble up the error directly.
uint len = returnedData.length;
assembly { revert(add(returnedData, 0x20), len) }
}
}
}
/**
* @dev Helper method to parse data and extract the method signature (selector).
*
* Copied from: https://github.com/argentlabs/argent-contracts/
* blob/master/contracts/modules/common/Utils.sol#L54-L60
*/
function parseSelector(bytes memory callData) internal pure returns (bytes4 selector) {
require(callData.length >= 4, "CallUtils: invalid callData");
// solhint-disable-next-line no-inline-assembly
assembly {
selector := mload(add(callData, 0x20))
}
}
/**
* @dev Pad length to 32 bytes word boundary
*/
function padLength32(uint256 len) internal pure returns (uint256 paddedLen) {
return ((len / 32) + (((len & 31) > 0) /* rounding? */ ? 1 : 0)) * 32;
}
/**
* @dev Validate if the data is encoded correctly with abi.encode(bytesData)
*
* Expected ABI Encode Layout:
* | word 1 | word 2 | word 3 | the rest...
* | data length | bytesData offset | bytesData length | bytesData + padLength32 zeros |
*/
function isValidAbiEncodedBytes(bytes memory data) internal pure returns (bool) {
if (data.length < 64) return false;
uint bytesOffset;
uint bytesLen;
// bytes offset is always expected to be 32
assembly { bytesOffset := mload(add(data, 32)) }
if (bytesOffset != 32) return false;
assembly { bytesLen := mload(add(data, 64)) }
// the data length should be bytesData.length + 64 + padded bytes length
return data.length == 64 + padLength32(bytesLen);
}
}// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.23;
import { IRelayRecipient } from "../interfaces/utils/IRelayRecipient.sol";
/**
* @title Base relay recipient contract
* @author Superfluid
* @dev A base contract to be inherited by any contract that want to receive relayed transactions
* A subclass must use "_msgSender()" instead of "msg.sender"
* MODIFIED FROM: https://github.com/opengsn/forwarder/blob/master/contracts/BaseRelayRecipient.sol
*/
abstract contract BaseRelayRecipient is IRelayRecipient {
/**
* @dev Check if the forwarder is trusted
*/
function isTrustedForwarder(address forwarder) public view virtual override returns(bool);
/**
* @dev Return the transaction signer of this call
*
* if the call came through our trusted forwarder, return the original sender.
* otherwise, return `msg.sender`.
* should be used in the contract anywhere instead of msg.sender
*/
function _getTransactionSigner() internal virtual view returns (address payable ret) {
require(msg.data.length >= 24 && isTrustedForwarder(msg.sender), "Not trusted forwarder");
// At this point we know that the sender is a trusted forwarder,
// so we trust that the last bytes of msg.data are the verified sender address.
// extract sender address from the end of msg.data
assembly {
ret := shr(96,calldataload(sub(calldatasize(),20)))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;
// MODIFIED FROM: https://github.com/opengsn/forwarder/blob/master/contracts/interfaces/IRelayRecipient.sol
/**
* @title Relay recipient interface
* @author Superfluid
* @dev A contract must implement this interface in order to support relayed transactions
* @dev It is better to inherit the BaseRelayRecipient as its implementation
*/
interface IRelayRecipient {
/**
* @notice Returns if the forwarder is trusted to forward relayed transactions to us.
* @dev the forwarder is required to verify the sender's signature, and verify
* the call is not a replay.
*/
function isTrustedForwarder(address forwarder) external view returns(bool);
/**
* @dev EIP 2771 version
*
* NOTE:
* - It is not clear if it is actually from the EIP 2771....
* - https://docs.biconomy.io/guides/enable-gasless-transactions/eip-2771
*/
function versionRecipient() external view returns (string memory);
}// 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 { 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,
PoolERC20Metadata
} 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
*
* NOTE: `batchCall` is `payable, because there's limited support for sending
* native tokens to batch operation targets.
* If value is > 0, the whole amount is sent to the first operation matching any of:
* - OPERATION_TYPE_SUPERFLUID_CALL_APP_ACTION
* - OPERATION_TYPE_SIMPLE_FORWARD_CALL
* - OPERATION_TYPE_ERC2771_FORWARD_CALL
* If the first such operation does not allow receiving native tokens,
* the transaction will revert.
* It's currently not possible to send native tokens to multiple operations, or to
* any but the first operation of one of the above mentioned types.
* If no such operation is included, the native tokens will be sent back to the sender.
*/
function batchCall(Operation[] calldata operations) external payable;
/**
* @dev Batch call function with EIP-2771 encoded msgSender
* @param operations Array of batch operations
*
* NOTE: This can be called only by contracts recognized as _trusted forwarder_
* by the host contract (see `Superfluid.isTrustedForwarder`).
* If native tokens are passed along, the same rules as for `batchCall` apply,
* with an optional refund going to the encoded msgSender.
*/
function forwardBatchCall(Operation[] calldata operations) external payable;
/**
* @dev returns the address of the forwarder contract used to route batch operations of type
* OPERATION_TYPE_ERC2771_FORWARD_CALL.
* Needs to be set as _trusted forwarder_ by the call targets of such operations.
*/
// solhint-disable func-name-mixedcase
function getERC2771Forwarder() external view returns(address);
/**************************************************************************
* 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 { IERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import { IERC5267 } from "@openzeppelin/contracts/interfaces/IERC5267.sol";
import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.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, IERC20Permit, IERC5267 {
/**************************************************************************
* 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(); // 0xef1b6ddf
error SUPER_TOKEN_PERMIT_EXPIRED_SIGNATURE(uint256 deadline); // 0x6e72b90f
error SUPER_TOKEN_PERMIT_INVALID_SIGNER(address signer, address owner); // 0xb6422105
/**
* @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 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;
/**
* @dev Upgrade ERC20 to SuperToken by host contract and transfer immediately.
* @param account The account to be changed.
* @param to The account to receive upgraded tokens
* @param amount Number of tokens to be upgraded (in 18 decimals)
*
* @custom:modifiers
* - onlyHost
*/
function operationUpgradeTo(address account, address to, uint256 amount) external;
/**
* @dev Downgrade ERC20 to SuperToken by host contract and transfer immediately.
* @param account The account to be changed.
* @param to The account to receive downgraded tokens
* @param amount Number of tokens to be downgraded (in 18 decimals)
*
* @custom:modifiers
* - onlyHost
*/
function operationDowngradeTo(address account, address to, uint256 amount) external;
/**
* @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;
/**
* @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 SuperToken.upgradeTo batch operation type
*
* Call spec:
* ISuperToken(target).operationUpgradeTo(
* abi.decode(data, (address to, uint256 amount)
* )
*/
uint32 constant internal OPERATION_TYPE_SUPERTOKEN_UPGRADE_TO = 3 + 100;
/**
* @dev SuperToken.downgradeTo batch operation type
*
* Call spec:
* ISuperToken(target).operationDowngradeTo(
* abi.decode(data, (address to, uint256 amount)
* )
*/
uint32 constant internal OPERATION_TYPE_SUPERTOKEN_DOWNGRADE_TO = 4 + 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;
/**
* @dev SimpleForwarder.forwardCall batch operation type
*
* Call spec:
* forwardCall(
* target,
* data
* )
* NOTE: This operation allows to make arbitrary calls to arbitrary targets.
* The calls are routed through a dedicated utility contract `SimpleForwarder`.
* This is important because the host contract has privileged access to other framework contracts,
* SuperTokens, SuperApps etc.
* Allowing arbitrary calls to arbitrary targets with the host as sender would thus be unsafe.
*/
uint32 constant internal OPERATION_TYPE_SIMPLE_FORWARD_CALL = 1 + 300;
/**
* @dev ERC2771Forwarder.forward2771Call batch operation type
*
* Call spec:
* forward2771Call(
* target,
* msgSender,
* data
* )
*
* NOTE: In the context of this operation, the `ERC2771Forwarder` contract acts as the
* _trusted forwarder_ which must be trusted by the _recipient contract_ (operation target).
* It shall do so by dynamically looking up the ERC2771Forwarder used by the host, like this:
*
* function isTrustedForwarder(address forwarder) public view returns(bool) {
* return forwarder == address(host.getERC2771Forwarder());
* }
*
* If used in the context of a `forwardBatchCall`, we effectively have a chaining/nesting
* of ERC-2771 calls where the host acts as _recipient contract_ of the enveloping 2771 call
* and the ERC2771Forwarder acts as the _trusted forwarder_ of the nested 2771 call(s).
* That's why `msgSender` could be either the actual `msg.sender` (if using `batchCall`)
* or the relayed sender address (if using `forwardBatchCall`).
*/
uint32 constant internal OPERATION_TYPE_ERC2771_FORWARD_CALL = 2 + 300;
}
/**
* @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, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { ISuperfluidToken } from "../../superfluid/ISuperfluidToken.sol";
/**
* @dev The interface for any super token pool regardless of the distribution schemes.
*/
interface ISuperfluidPool is IERC20, IERC20Metadata {
// 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
error SUPERFLUID_POOL_SELF_TRANSFER_NOT_ALLOWED(); // 0xceddc0be
// 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 `memberAddr`
/// @param memberAddr The address of the member
function getUnits(address memberAddr) 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 total amount received by `memberAddr` in the pool
/// @param memberAddr The address of the member
/// @return totalAmountReceived The total amount received by the member
function getTotalAmountReceivedByMember(address memberAddr) external view returns (uint256 totalAmountReceived);
/// @notice The flow rate a member is receiving from the pool
/// @param memberAddr The address of the member
function getMemberFlowRate(address memberAddr) 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;
}
struct PoolERC20Metadata {
string name;
string symbol;
uint8 decimals;
}
/**
* @title General Distribution Agreement interface
* @author Superfluid
*/
abstract contract IGeneralDistributionAgreementV1 is ISuperAgreement {
// 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);
/// @dev Gets the GDA flow data between `from` and `to` of `token`
/// @param token The token address
/// @param from The sender address
/// @param to The receiver address
/// @return lastUpdated The timestamp of when the flow was last updated
/// @return flowRate The flow rate
/// @return deposit The amount of deposit the flow
function getFlow(ISuperfluidToken token, address from, ISuperfluidPool to)
external
view
virtual
returns (uint256 lastUpdated, int96 flowRate, uint256 deposit);
/// @dev Gets the aggregated GDA flow info of `account` for `token`
/// @param token The token address
/// @param account The account address
/// @return timestamp The timestamp of when the 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
function getAccountFlowInfo(ISuperfluidToken token, address account)
external
view
virtual
returns (uint256 timestamp, int96 flowRate, uint256 deposit);
/// @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);
/// @notice Creates a new pool for `token` with custom ERC20 metadata.
/// @param token The token address
/// @param admin The admin of the pool
/// @param poolConfig The pool configuration (see PoolConfig struct)
/// @param poolERC20Metadata The pool ERC20 metadata (see PoolERC20Metadata struct)
/// @return pool The pool address
function createPoolWithCustomERC20Metadata(
ISuperfluidToken token,
address admin,
PoolConfig memory poolConfig,
PoolERC20Metadata memory poolERC20Metadata
) 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 [DEPRECATED] Instant Distribution Agreement interface
* @custom:deprecated Use IGeneralDistributionAgreementV1 instead
* @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.23;
import { BeaconProxy } from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import { ISuperfluidToken } from "../../interfaces/superfluid/ISuperfluidToken.sol";
import { SuperfluidPool } from "./SuperfluidPool.sol";
import { PoolConfig, PoolERC20Metadata } from "../../interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol";
library SuperfluidPoolDeployerLibrary {
function deploy(
address beacon,
address admin,
ISuperfluidToken token,
PoolConfig memory config,
PoolERC20Metadata memory poolERC20Metadata
) external returns (SuperfluidPool pool) {
bytes memory initializeCallData = abi.encodeWithSelector(
SuperfluidPool.initialize.selector,
admin,
token,
config.transferabilityForUnitsOwner,
config.distributionFromAnyAddress,
poolERC20Metadata.name,
poolERC20Metadata.symbol,
poolERC20Metadata.decimals
);
BeaconProxy superfluidPoolBeaconProxy = new BeaconProxy(
beacon,
initializeCallData
);
pool = SuperfluidPool(address(superfluidPoolBeaconProxy));
}
}// SPDX-License-Identifier: AGPLv3
// solhint-disable not-rely-on-time
pragma solidity ^0.8.23;
// Notes: We use these interfaces in natspec documentation below, grep @inheritdoc
// solhint-disable-next-line no-unused-import
import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {
BasicParticle,
SemanticMoney,
PDPoolMember,
PDPoolIndex,
PDPoolMemberMU,
Value,
Time,
FlowRate,
Unit
} from "@superfluid-finance/solidity-semantic-money/src/SemanticMoney.sol";
import { ISuperfluid } from "../../interfaces/superfluid/ISuperfluid.sol";
import { ISuperfluidToken } from "../../interfaces/superfluid/ISuperfluidToken.sol";
import { ISuperToken } from "../../interfaces/superfluid/ISuperToken.sol";
import { ISuperfluidPool } from "../../interfaces/agreements/gdav1/ISuperfluidPool.sol";
import { GeneralDistributionAgreementV1 } from "../../agreements/gdav1/GeneralDistributionAgreementV1.sol";
import { BeaconProxiable } from "../../upgradability/BeaconProxiable.sol";
import { IPoolMemberNFT } from "../../interfaces/agreements/gdav1/IPoolMemberNFT.sol";
using SafeCast for uint256;
using SafeCast for int256;
function toSemanticMoneyUnit(uint128 units) pure returns (Unit) {
// @note safe upcasting from uint128 to uint256
// and use of safecast library for downcasting from uint256 to int128
return Unit.wrap(uint256(units).toInt256().toInt128());
}
function poolIndexDataToWrappedParticle(SuperfluidPool.PoolIndexData memory data)
pure
returns (BasicParticle memory wrappedParticle)
{
wrappedParticle = BasicParticle({
_settled_at: Time.wrap(data.wrappedSettledAt),
_flow_rate: FlowRate.wrap(int128(data.wrappedFlowRate)), // upcast from int96 is safe
_settled_value: Value.wrap(data.wrappedSettledValue)
});
}
function poolIndexDataToPDPoolIndex(SuperfluidPool.PoolIndexData memory data)
pure
returns (PDPoolIndex memory pdPoolIndex)
{
pdPoolIndex = PDPoolIndex({
total_units: toSemanticMoneyUnit(data.totalUnits),
_wrapped_particle: poolIndexDataToWrappedParticle(data)
});
}
/**
* @title SuperfluidPool
* @author Superfluid
* @notice A SuperfluidPool which can be used to distribute any SuperToken.
* @dev Because we are using uint128, uint256 doesn't work here.
*/
contract SuperfluidPool is ISuperfluidPool, BeaconProxiable {
using SemanticMoney for BasicParticle;
// 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;
}
// Constants & Immutables
string internal constant _DEFAULT_ERC20_NAME = "Superfluid Pool";
string internal constant _DEFAULT_ERC20_SYMBOL = "POOL";
// ERC20 decimals implicitly defaults to 0
GeneralDistributionAgreementV1 public immutable GDA;
// State variables - NEVER REORDER!
ISuperfluidToken public superToken;
address public admin;
PoolIndexData internal _index;
mapping(address => MemberData) internal _membersData;
/// @dev This is a pseudo member, representing all the disconnected members
MemberData internal _disconnectedMembers;
/// @dev owner => (spender => amount)
mapping(address => mapping(address => uint256)) internal _allowances;
/// @inheritdoc ISuperfluidPool
bool public transferabilityForUnitsOwner;
/// @inheritdoc ISuperfluidPool
bool public distributionFromAnyAddress;
// ERC20 metadata
string internal _erc20Name;
string internal _erc20Symbol;
uint8 internal _erc20Decimals;
constructor(GeneralDistributionAgreementV1 gda) {
GDA = gda;
}
function initialize(
address admin_,
ISuperfluidToken superToken_,
bool transferabilityForUnitsOwner_,
bool distributionFromAnyAddress_,
string memory erc20Name_,
string memory erc20Symbol_,
uint8 erc20Decimals_
) external initializer {
admin = admin_;
superToken = superToken_;
transferabilityForUnitsOwner = transferabilityForUnitsOwner_;
distributionFromAnyAddress = distributionFromAnyAddress_;
_erc20Name = erc20Name_;
_erc20Symbol = erc20Symbol_;
_erc20Decimals = erc20Decimals_;
}
function proxiableUUID() public pure override returns (bytes32) {
return keccak256("org.superfluid-finance.contracts.SuperfluidPool.implementation");
}
/// @dev This function is only meant to be called by the GDAv1 contract
function poolOperatorGetIndex() external view returns (PoolIndexData memory) {
return _index;
}
/// @inheritdoc ISuperfluidPool
function getTotalUnits() external view override returns (uint128) {
return _getTotalUnits();
}
function _getTotalUnits() internal view returns (uint128) {
return _index.totalUnits;
}
/// @inheritdoc IERC20
function allowance(address owner, address spender) external view override returns (uint256) {
return _allowances[owner][spender];
}
/// @inheritdoc IERC20
function approve(address spender, uint256 amount) external override returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
/// @inheritdoc ISuperfluidPool
function increaseAllowance(address spender, uint256 addedValue) external returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender] + addedValue);
return true;
}
/// @inheritdoc ISuperfluidPool
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender] - subtractedValue);
return true;
}
function _approve(address owner, address spender, uint256 amount) internal {
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/// @dev Transfers `amount` units from `msg.sender` to `to`
function transfer(address to, uint256 amount) external override returns (bool) {
_transfer(msg.sender, to, amount);
return true;
}
/// @dev Transfers `amount` units from `from` to `to`
function transferFrom(address from, address to, uint256 amount) external override returns (bool) {
uint256 allowed = _allowances[from][msg.sender];
// if allowed - amount is negative, this reverts due to overflow
if (allowed != type(uint256).max) _allowances[from][msg.sender] = allowed - amount;
_transfer(from, to, amount);
return true;
}
function _transfer(address from, address to, uint256 amount) internal {
if (from == to) revert SUPERFLUID_POOL_SELF_TRANSFER_NOT_ALLOWED();
if (!transferabilityForUnitsOwner) revert SUPERFLUID_POOL_TRANSFER_UNITS_NOT_ALLOWED();
uint128 fromUnitsBefore = _getUnits(from);
uint128 toUnitsBefore = _getUnits(to);
_updateMemberUnits(from, fromUnitsBefore - amount.toUint128());
_updateMemberUnits(to, toUnitsBefore + amount.toUint128());
// assert that the units are updated correctly for from and for to.
emit Transfer(from, to, amount);
}
/// @notice Returns the total number of units for a pool
function totalSupply() external view override returns (uint256) {
return _getTotalUnits();
}
/// @inheritdoc ISuperfluidPool
function getTotalConnectedUnits() external view override returns (uint128) {
return _index.totalUnits - _disconnectedMembers.ownedUnits;
}
/// @inheritdoc ISuperfluidPool
function getTotalDisconnectedUnits() external view override returns (uint128) {
return _disconnectedMembers.ownedUnits;
}
/// @inheritdoc ISuperfluidPool
function getUnits(address memberAddr) external view override returns (uint128) {
return _getUnits(memberAddr);
}
function _getUnits(address memberAddr) internal view returns (uint128) {
return _membersData[memberAddr].ownedUnits;
}
/// @notice Returns the total number of units for an account for this pool
/// @dev Although the type is uint256, this can never be greater than type(int128).max
/// because the custom user type Unit is int128 in the SemanticMoney library
/// @param account The account to query
/// @return The total number of owned units of the account
function balanceOf(address account) external view override returns (uint256) {
return uint256(_getUnits(account));
}
/// @inheritdoc ISuperfluidPool
function getTotalFlowRate() external view override returns (int96) {
return _getTotalFlowRate();
}
function _getTotalFlowRate() internal view returns (int96) {
return (_index.wrappedFlowRate * uint256(_index.totalUnits).toInt256()).toInt96();
}
/// @inheritdoc ISuperfluidPool
function getTotalConnectedFlowRate() external view override returns (int96) {
return _getTotalFlowRate() - _getTotalDisconnectedFlowRate();
}
function _getTotalDisconnectedFlowRate() internal view returns (int96 flowRate) {
PDPoolIndex memory pdPoolIndex = poolIndexDataToPDPoolIndex(_index);
PDPoolMember memory disconnectedMembers = _memberDataToPDPoolMember(_disconnectedMembers);
return int256(FlowRate.unwrap(pdPoolIndex.flow_rate_per_unit().mul(disconnectedMembers.owned_units))).toInt96();
}
/// @inheritdoc ISuperfluidPool
function getTotalDisconnectedFlowRate() external view override returns (int96 flowRate) {
return _getTotalDisconnectedFlowRate();
}
/// @inheritdoc ISuperfluidPool
function getDisconnectedBalance(uint32 time) external view override returns (int256 balance) {
PDPoolIndex memory pdPoolIndex = poolIndexDataToPDPoolIndex(_index);
PDPoolMember memory pdPoolMember = _memberDataToPDPoolMember(_disconnectedMembers);
return Value.unwrap(PDPoolMemberMU(pdPoolIndex, pdPoolMember).rtb(Time.wrap(time)));
}
/// @inheritdoc ISuperfluidPool
function getTotalAmountReceivedByMember(address memberAddr) external view override returns (uint256) {
MemberData memory memberData = _membersData[memberAddr];
// max timestamp is uint32.max
return uint256(
Value.unwrap(
// PDPoolMemberMU(poolIndex, memberData)
PDPoolMemberMU(poolIndexDataToPDPoolIndex(_index), _memberDataToPDPoolMember(memberData)).settle(
Time.wrap(uint32(block.timestamp))
).m._settled_value
)
);
}
/// @inheritdoc ISuperfluidPool
function getMemberFlowRate(address memberAddr) external view override returns (int96) {
uint128 units = _getUnits(memberAddr);
if (units == 0) return 0;
// @note total units must never exceed type(int96).max
else return (_index.wrappedFlowRate * uint256(units).toInt256()).toInt96();
}
/// @inheritdoc IERC20Metadata
function name() external view override returns (string memory) {
return bytes(_erc20Name).length == 0 ? "Superfluid Pool" : _erc20Name;
}
/// @inheritdoc IERC20Metadata
function symbol() external view override returns (string memory) {
return bytes(_erc20Symbol).length == 0 ? "POOL" : _erc20Symbol;
}
/// @inheritdoc IERC20Metadata
function decimals() external view override returns (uint8) {
return _erc20Decimals;
}
function _pdPoolIndexToPoolIndexData(PDPoolIndex memory pdPoolIndex)
internal
pure
returns (PoolIndexData memory data)
{
data = PoolIndexData({
totalUnits: int256(Unit.unwrap(pdPoolIndex.total_units)).toUint256().toUint128(),
wrappedSettledAt: Time.unwrap(pdPoolIndex.settled_at()),
wrappedFlowRate: int256(FlowRate.unwrap(pdPoolIndex.flow_rate_per_unit())).toInt96(),
wrappedSettledValue: Value.unwrap(pdPoolIndex._wrapped_particle._settled_value)
});
}
function _memberDataToPDPoolMember(MemberData memory memberData)
internal
pure
returns (PDPoolMember memory pdPoolMember)
{
pdPoolMember = PDPoolMember({
owned_units: toSemanticMoneyUnit(memberData.ownedUnits),
_synced_particle: BasicParticle({
_settled_at: Time.wrap(memberData.syncedSettledAt),
_flow_rate: FlowRate.wrap(int128(memberData.syncedFlowRate)), // upcast from int96 is safe
_settled_value: Value.wrap(memberData.syncedSettledValue)
}),
_settled_value: Value.wrap(memberData.settledValue)
});
}
function _pdPoolMemberToMemberData(PDPoolMember memory pdPoolMember, int256 claimedValue)
internal
pure
returns (MemberData memory memberData)
{
memberData = MemberData({
ownedUnits: uint256(int256(Unit.unwrap(pdPoolMember.owned_units))).toUint128(),
syncedSettledAt: Time.unwrap(pdPoolMember._synced_particle._settled_at),
syncedFlowRate: int256(FlowRate.unwrap(pdPoolMember._synced_particle._flow_rate)).toInt96(),
syncedSettledValue: Value.unwrap(pdPoolMember._synced_particle._settled_value),
settledValue: Value.unwrap(pdPoolMember._settled_value),
claimedValue: claimedValue
});
}
/// @inheritdoc ISuperfluidPool
function getClaimableNow(address memberAddr)
external
view
override
returns (int256 claimableBalance, uint256 timestamp)
{
timestamp = ISuperfluid(superToken.getHost()).getNow();
return (getClaimable(memberAddr, uint32(timestamp)), timestamp);
}
/// @inheritdoc ISuperfluidPool
function getClaimable(address memberAddr, uint32 time) public view override returns (int256) {
Time t = Time.wrap(time);
PDPoolIndex memory pdPoolIndex = poolIndexDataToPDPoolIndex(_index);
PDPoolMember memory pdPoolMember = _memberDataToPDPoolMember(_membersData[memberAddr]);
return Value.unwrap(
PDPoolMemberMU(pdPoolIndex, pdPoolMember).rtb(t) - Value.wrap(_membersData[memberAddr].claimedValue)
);
}
/// @inheritdoc ISuperfluidPool
function updateMemberUnits(address memberAddr, uint128 newUnits) external returns (bool) {
if (msg.sender != admin && msg.sender != address(GDA)) revert SUPERFLUID_POOL_NOT_POOL_ADMIN_OR_GDA();
uint128 oldUnits = _updateMemberUnits(memberAddr, newUnits);
// Unit updates by admin are effectively mint/burn operations when viewed through the ERC20 lens.
// We thus emit a Transfer event from/to the zero address accordingly.
if (oldUnits < newUnits) {
emit Transfer(address(0), memberAddr, newUnits - oldUnits);
} else if (oldUnits > newUnits) {
emit Transfer(memberAddr, address(0), oldUnits - newUnits);
}
return true;
}
/**
* @notice Checks whether or not the NFT hook can be called.
* @dev A staticcall, so `POOL_MEMBER_NFT` must be a view otherwise the assumption is that it reverts
* @param token the super token that is being streamed
* @return poolMemberNFT the address returned by low level call
*/
function _canCallNFTHook(ISuperfluidToken token) internal view returns (address poolMemberNFT) {
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory data) =
address(token).staticcall(abi.encodeWithSelector(ISuperToken.POOL_MEMBER_NFT.selector));
if (success) {
// @note We are aware this may revert if a Custom SuperToken's
// POOL_MEMBER_NFT does not return data that can be
// decoded to an address. This would mean it was intentionally
// done by the creator of the Custom SuperToken logic and is
// fully expected to revert in that case as the author desired.
poolMemberNFT = abi.decode(data, (address));
}
}
function _handlePoolMemberNFT(address memberAddr, uint128 newUnits) internal {
// Pool Member NFT Logic
IPoolMemberNFT poolMemberNFT = IPoolMemberNFT(_canCallNFTHook(superToken));
if (address(poolMemberNFT) != address(0)) {
uint256 tokenId = poolMemberNFT.getTokenId(address(this), memberAddr);
if (newUnits == 0) {
if (poolMemberNFT.poolMemberDataByTokenId(tokenId).member != address(0)) {
poolMemberNFT.onDelete(address(this), memberAddr);
}
} else {
// if not minted, we mint a new pool member nft
if (poolMemberNFT.poolMemberDataByTokenId(tokenId).member == address(0)) {
poolMemberNFT.onCreate(address(this), memberAddr);
} else {
// if minted, we update the pool member nft
poolMemberNFT.onUpdate(address(this), memberAddr);
}
}
}
}
function _updateMemberUnits(address memberAddr, uint128 newUnits) internal returns (uint128 oldUnits) {
// @note normally we keep the sanitization in the external functions, but here
// this is used in both updateMemberUnits and transfer
if (GDA.isPool(superToken, memberAddr)) revert SUPERFLUID_POOL_NO_POOL_MEMBERS();
if (memberAddr == address(0)) revert SUPERFLUID_POOL_NO_ZERO_ADDRESS();
uint32 time = uint32(ISuperfluid(superToken.getHost()).getNow());
Time t = Time.wrap(time);
Unit wrappedUnits = toSemanticMoneyUnit(newUnits);
PDPoolIndex memory pdPoolIndex = poolIndexDataToPDPoolIndex(_index);
MemberData memory memberData = _membersData[memberAddr];
PDPoolMember memory pdPoolMember = _memberDataToPDPoolMember(memberData);
oldUnits = memberData.ownedUnits;
PDPoolMemberMU memory mu = PDPoolMemberMU(pdPoolIndex, pdPoolMember);
// update pool's disconnected units
if (!GDA.isMemberConnected(ISuperfluidPool(address(this)), memberAddr)) {
_shiftDisconnectedUnits(wrappedUnits - mu.m.owned_units, Value.wrap(0), t);
}
// update pool member's units
{
BasicParticle memory p;
(pdPoolIndex, pdPoolMember, p) = mu.pool_member_update(p, wrappedUnits, t);
_index = _pdPoolIndexToPoolIndexData(pdPoolIndex);
int256 claimedValue = _membersData[memberAddr].claimedValue;
_membersData[memberAddr] = _pdPoolMemberToMemberData(pdPoolMember, claimedValue);
assert(GDA.appendIndexUpdateByPool(superToken, p, t));
}
emit MemberUnitsUpdated(superToken, memberAddr, oldUnits, newUnits);
_handlePoolMemberNFT(memberAddr, newUnits);
}
function _claimAll(address memberAddr, uint32 time) internal returns (int256 amount) {
amount = getClaimable(memberAddr, time);
assert(GDA.poolSettleClaim(superToken, memberAddr, (amount)));
_membersData[memberAddr].claimedValue += amount;
emit DistributionClaimed(superToken, memberAddr, amount, _membersData[memberAddr].claimedValue);
}
/// @inheritdoc ISuperfluidPool
function claimAll() external returns (bool) {
return claimAll(msg.sender);
}
/// @inheritdoc ISuperfluidPool
function claimAll(address memberAddr) public returns (bool) {
bool isConnected = GDA.isMemberConnected(ISuperfluidPool(address(this)), memberAddr);
uint32 time = uint32(ISuperfluid(superToken.getHost()).getNow());
int256 claimedAmount = _claimAll(memberAddr, time);
if (!isConnected) {
_shiftDisconnectedUnits(Unit.wrap(0), Value.wrap(claimedAmount), Time.wrap(time));
}
return true;
}
function operatorSetIndex(PDPoolIndex calldata index) external onlyGDA returns (bool) {
_index = _pdPoolIndexToPoolIndexData(index);
return true;
}
// WARNING for operators: it is undefined behavior if member is already connected or disconnected
function operatorConnectMember(address memberAddr, bool doConnect, uint32 time) external onlyGDA returns (bool) {
int256 claimedAmount = _claimAll(memberAddr, time);
int128 units = uint256(_getUnits(memberAddr)).toInt256().toInt128();
if (doConnect) {
_shiftDisconnectedUnits(Unit.wrap(-units), Value.wrap(claimedAmount), Time.wrap(time));
} else {
_shiftDisconnectedUnits(Unit.wrap(units), Value.wrap(0), Time.wrap(time));
}
return true;
}
function _shiftDisconnectedUnits(Unit shiftUnits, Value claimedAmount, Time t) internal {
PDPoolIndex memory pdPoolIndex = poolIndexDataToPDPoolIndex(_index);
PDPoolMember memory disconnectedMembers = _memberDataToPDPoolMember(_disconnectedMembers);
PDPoolMemberMU memory mu = PDPoolMemberMU(pdPoolIndex, disconnectedMembers);
mu = mu.settle(t);
mu.m.owned_units = mu.m.owned_units + shiftUnits;
// offset the claimed amount from the settled value if any
mu.m._settled_value = mu.m._settled_value - claimedAmount;
_disconnectedMembers = _pdPoolMemberToMemberData(mu.m, 0);
}
modifier onlyGDA() {
if (msg.sender != address(GDA)) revert SUPERFLUID_POOL_NOT_GDA();
_;
}
}// SPDX-License-Identifier: AGPLv3
// solhint-disable not-rely-on-time
pragma solidity ^0.8.23;
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { ISuperfluid, ISuperfluidGovernance } from "../../interfaces/superfluid/ISuperfluid.sol";
import {
BasicParticle,
PDPoolIndex,
SemanticMoney,
Value,
Time,
FlowRate
} from "@superfluid-finance/solidity-semantic-money/src/SemanticMoney.sol";
import { TokenMonad } from "@superfluid-finance/solidity-semantic-money/src/TokenMonad.sol";
import { poolIndexDataToPDPoolIndex, SuperfluidPool } from "./SuperfluidPool.sol";
import { SuperfluidPoolDeployerLibrary } from "./SuperfluidPoolDeployerLibrary.sol";
import {
IGeneralDistributionAgreementV1,
PoolConfig,
PoolERC20Metadata
} from "../../interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol";
import { SuperfluidUpgradeableBeacon } from "../../upgradability/SuperfluidUpgradeableBeacon.sol";
import { ISuperfluidToken } from "../../interfaces/superfluid/ISuperfluidToken.sol";
import { ISuperToken } from "../../interfaces/superfluid/ISuperToken.sol";
import { IPoolAdminNFT } from "../../interfaces/agreements/gdav1/IPoolAdminNFT.sol";
import { ISuperfluidPool } from "../../interfaces/agreements/gdav1/ISuperfluidPool.sol";
import { SlotsBitmapLibrary } from "../../libs/SlotsBitmapLibrary.sol";
import { SolvencyHelperLibrary } from "../../libs/SolvencyHelperLibrary.sol";
import { AgreementBase } from "../AgreementBase.sol";
import { AgreementLibrary } from "../AgreementLibrary.sol";
/**
* @title General Distribution Agreement
* @author Superfluid
* @notice
*
* Storage Layout Notes
* Agreement State
*
* Universal Index Data
* slotId = _UNIVERSAL_INDEX_STATE_SLOT_ID or 0
* msg.sender = address of GDAv1
* account = context.msgSender
* Universal Index Data stores a Basic Particle for an account as well as the total buffer and
* whether the account is a pool or not.
*
* SlotsBitmap Data
* slotId = _POOL_SUBS_BITMAP_STATE_SLOT_ID or 1
* msg.sender = address of GDAv1
* account = context.msgSender
* Slots Bitmap Data Slot stores a bitmap of the slots that are "enabled" for a pool member.
*
* Pool Connections Data Slot Id Start
* slotId (start) = _POOL_CONNECTIONS_DATA_STATE_SLOT_ID_START or 1 << 128 or 340282366920938463463374607431768211456
* msg.sender = address of GDAv1
* account = context.msgSender
* Pool Connections Data Slot Id Start indicates the starting slot for where we begin to store the pools that a
* pool member is a part of.
*
*
* Agreement Data
* NOTE The Agreement Data slot is calculated with the following function:
* keccak256(abi.encode("AgreementData", agreementClass, agreementId))
* agreementClass = address of GDAv1
* agreementId = DistributionFlowId | PoolMemberId
*
* DistributionFlowId =
* keccak256(abi.encode(block.chainid, "distributionFlow", from, pool))
* DistributionFlowId stores FlowDistributionData between a sender (from) and pool.
*
* PoolMemberId =
* keccak256(abi.encode(block.chainid, "poolMember", member, pool))
* PoolMemberId stores PoolMemberData for a member at a pool.
*/
contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDistributionAgreementV1 {
using SafeCast for uint256;
using SafeCast for int256;
using SemanticMoney for BasicParticle;
struct UniversalIndexData {
int96 flowRate;
uint32 settledAt;
uint256 totalBuffer;
bool isPool;
int256 settledValue;
}
struct PoolMemberData {
address pool;
uint32 poolID; // the slot id in the pool's subs bitmap
}
struct FlowDistributionData {
uint32 lastUpdated;
int96 flowRate;
uint256 buffer; // stored as uint96
}
address public constant SLOTS_BITMAP_LIBRARY_ADDRESS = address(SlotsBitmapLibrary);
address public constant SUPERFLUID_POOL_DEPLOYER_ADDRESS = address(SuperfluidPoolDeployerLibrary);
/// @dev Universal Index state slot id for storing universal index data
uint256 private constant _UNIVERSAL_INDEX_STATE_SLOT_ID = 0;
/// @dev Pool member state slot id for storing subs bitmap
uint256 private constant _POOL_SUBS_BITMAP_STATE_SLOT_ID = 1;
/// @dev Pool member state slot id starting point for pool connections
uint256 private constant _POOL_CONNECTIONS_DATA_STATE_SLOT_ID_START = 1 << 128;
/// @dev SuperToken minimum deposit key
bytes32 private constant SUPERTOKEN_MINIMUM_DEPOSIT_KEY =
keccak256("org.superfluid-finance.superfluid.superTokenMinimumDeposit");
SuperfluidUpgradeableBeacon public immutable superfluidPoolBeacon;
constructor(ISuperfluid host, SuperfluidUpgradeableBeacon superfluidPoolBeacon_) AgreementBase(address(host)) {
superfluidPoolBeacon = superfluidPoolBeacon_;
}
function realtimeBalanceOf(ISuperfluidToken token, address account, uint256 time)
public
view
override
returns (int256 rtb, uint256 buf, uint256 owedBuffer)
{
UniversalIndexData memory universalIndexData = _getUIndexData(abi.encode(token), account);
if (_isPool(token, account)) {
rtb = ISuperfluidPool(account).getDisconnectedBalance(uint32(time));
} else {
rtb = Value.unwrap(_getBasicParticleFromUIndex(universalIndexData).rtb(Time.wrap(uint32(time))));
}
int256 fromPools;
{
(uint32[] memory slotIds, bytes32[] memory pidList) = _listPoolConnectionIds(token, account);
for (uint256 i = 0; i < slotIds.length; ++i) {
address pool = address(uint160(uint256(pidList[i])));
(bool exist, PoolMemberData memory poolMemberData) =
_getPoolMemberData(token, account, ISuperfluidPool(pool));
assert(exist);
assert(poolMemberData.pool == pool);
fromPools += ISuperfluidPool(pool).getClaimable(account, uint32(time));
}
}
rtb += fromPools;
buf = uint256(universalIndexData.totalBuffer.toInt256()); // upcasting to uint256 is safe
owedBuffer = 0;
}
/// @dev ISuperAgreement.realtimeBalanceOf implementation
function realtimeBalanceOfNow(ISuperfluidToken token, address account)
external
view
returns (int256 availableBalance, uint256 buffer, uint256 owedBuffer, uint256 timestamp)
{
(availableBalance, buffer, owedBuffer) = realtimeBalanceOf(token, account, block.timestamp);
timestamp = block.timestamp;
}
/// @inheritdoc IGeneralDistributionAgreementV1
function getNetFlow(ISuperfluidToken token, address account) external view override returns (int96 netFlowRate) {
netFlowRate = int256(FlowRate.unwrap(_getUIndex(abi.encode(token), account).flow_rate())).toInt96();
if (_isPool(token, account)) {
netFlowRate += ISuperfluidPool(account).getTotalDisconnectedFlowRate();
}
{
(uint32[] memory slotIds, bytes32[] memory pidList) = _listPoolConnectionIds(token, account);
for (uint256 i = 0; i < slotIds.length; ++i) {
ISuperfluidPool pool = ISuperfluidPool(address(uint160(uint256(pidList[i]))));
netFlowRate += pool.getMemberFlowRate(account);
}
}
}
/// @inheritdoc IGeneralDistributionAgreementV1
function getFlowRate(ISuperfluidToken token, address from, ISuperfluidPool to)
external
view
override
returns (int96)
{
(, FlowDistributionData memory data) = _getFlowDistributionData(token, _getFlowDistributionHash(from, to));
return data.flowRate;
}
/// @inheritdoc IGeneralDistributionAgreementV1
function getFlow(ISuperfluidToken token, address from, ISuperfluidPool to)
external
view
override
returns (uint256 lastUpdated, int96 flowRate, uint256 deposit)
{
(, FlowDistributionData memory data) = _getFlowDistributionData(token, _getFlowDistributionHash(from, to));
lastUpdated = data.lastUpdated;
flowRate = data.flowRate;
deposit = data.buffer;
}
/// @inheritdoc IGeneralDistributionAgreementV1
function getAccountFlowInfo(ISuperfluidToken token, address account)
external
view
override
returns (uint256 timestamp, int96 flowRate, uint256 deposit)
{
UniversalIndexData memory universalIndexData = _getUIndexData(abi.encode(token), account);
timestamp = universalIndexData.settledAt;
flowRate = universalIndexData.flowRate;
deposit = universalIndexData.totalBuffer;
}
/// @inheritdoc IGeneralDistributionAgreementV1
function estimateFlowDistributionActualFlowRate(
ISuperfluidToken token,
address from,
ISuperfluidPool to,
int96 requestedFlowRate
) external view override returns (int96 actualFlowRate, int96 totalDistributionFlowRate) {
bytes memory eff = abi.encode(token);
bytes32 distributionFlowHash = _getFlowDistributionHash(from, to);
BasicParticle memory fromUIndexData = _getUIndex(eff, from);
PDPoolIndex memory pdpIndex = _getPDPIndex("", address(to));
FlowRate oldFlowRate = _getFlowRate(eff, distributionFlowHash);
FlowRate newActualFlowRate;
FlowRate oldDistributionFlowRate = pdpIndex.flow_rate();
FlowRate newDistributionFlowRate;
FlowRate flowRateDelta = FlowRate.wrap(requestedFlowRate) - oldFlowRate;
FlowRate currentAdjustmentFlowRate = _getPoolAdjustmentFlowRate(eff, address(to));
Time t = Time.wrap(uint32(block.timestamp));
(fromUIndexData, pdpIndex, newDistributionFlowRate) =
fromUIndexData.shift_flow2b(pdpIndex, flowRateDelta + currentAdjustmentFlowRate, t);
newActualFlowRate =
oldFlowRate + (newDistributionFlowRate - oldDistributionFlowRate) - currentAdjustmentFlowRate;
actualFlowRate = int256(FlowRate.unwrap(newActualFlowRate)).toInt96();
totalDistributionFlowRate = int256(FlowRate.unwrap(newDistributionFlowRate)).toInt96();
if (actualFlowRate < 0) {
actualFlowRate = 0;
}
}
/// @inheritdoc IGeneralDistributionAgreementV1
function estimateDistributionActualAmount(
ISuperfluidToken token,
address from,
ISuperfluidPool to,
uint256 requestedAmount
) external view override returns (uint256 actualAmount) {
bytes memory eff = abi.encode(token);
Value actualDistributionAmount;
(,, actualDistributionAmount) =
_getUIndex(eff, from).shift2b(_getPDPIndex("", address(to)), Value.wrap(requestedAmount.toInt256()));
actualAmount = uint256(Value.unwrap(actualDistributionAmount));
}
function _createPool(
ISuperfluidToken token,
address admin,
PoolConfig memory config,
PoolERC20Metadata memory poolERC20Metadata
) internal returns (ISuperfluidPool pool) {
// @note ensure if token and admin are the same that nothing funky happens with echidna
if (admin == address(0)) revert GDA_NO_ZERO_ADDRESS_ADMIN();
if (_isPool(token, admin)) revert GDA_ADMIN_CANNOT_BE_POOL();
pool = ISuperfluidPool(
address(
SuperfluidPoolDeployerLibrary.deploy(
address(superfluidPoolBeacon), admin, token, config, poolERC20Metadata
)
)
);
// @note We utilize the storage slot for Universal Index State
// to store whether an account is a pool or not
bytes32[] memory data = new bytes32[](1);
data[0] = bytes32(uint256(1));
token.updateAgreementStateSlot(address(pool), _UNIVERSAL_INDEX_STATE_SLOT_ID, data);
IPoolAdminNFT poolAdminNFT = IPoolAdminNFT(_getPoolAdminNFTAddress(token));
if (address(poolAdminNFT) != address(0)) {
poolAdminNFT.mint(address(pool));
}
emit PoolCreated(token, admin, pool);
}
/// @inheritdoc IGeneralDistributionAgreementV1
function createPool(ISuperfluidToken token, address admin, PoolConfig memory config)
external
override
returns (ISuperfluidPool pool)
{
return _createPool(
token,
admin,
config,
PoolERC20Metadata("", "", 0) // use defaults specified by the implementation contract
);
}
/// @inheritdoc IGeneralDistributionAgreementV1
function createPoolWithCustomERC20Metadata(
ISuperfluidToken token,
address admin,
PoolConfig memory config,
PoolERC20Metadata memory poolERC20Metadata
) external override returns (ISuperfluidPool pool) {
return _createPool(token, admin, config, poolERC20Metadata);
}
/// @inheritdoc IGeneralDistributionAgreementV1
function updateMemberUnits(ISuperfluidPool pool, address memberAddress, uint128 newUnits, bytes calldata ctx)
external
override
returns (bytes memory newCtx)
{
// Only the admin can update member units here
if (AgreementLibrary.authorizeTokenAccess(pool.superToken(), ctx).msgSender != pool.admin()) {
revert GDA_NOT_POOL_ADMIN();
}
newCtx = ctx;
pool.updateMemberUnits(memberAddress, newUnits);
}
/// @inheritdoc IGeneralDistributionAgreementV1
function claimAll(ISuperfluidPool pool, address memberAddress, bytes calldata ctx)
external
override
returns (bytes memory newCtx)
{
AgreementLibrary.authorizeTokenAccess(pool.superToken(), ctx);
newCtx = ctx;
pool.claimAll(memberAddress);
}
/// @inheritdoc IGeneralDistributionAgreementV1
function connectPool(ISuperfluidPool pool, bytes calldata ctx) external override returns (bytes memory newCtx) {
return connectPool(pool, true, ctx);
}
/// @inheritdoc IGeneralDistributionAgreementV1
function disconnectPool(ISuperfluidPool pool, bytes calldata ctx) external override returns (bytes memory newCtx) {
return connectPool(pool, false, ctx);
}
// @note setPoolConnection function naming
function connectPool(ISuperfluidPool pool, bool doConnect, bytes calldata ctx)
public
returns (bytes memory newCtx)
{
ISuperfluidToken token = pool.superToken();
ISuperfluid.Context memory currentContext = AgreementLibrary.authorizeTokenAccess(token, ctx);
address msgSender = currentContext.msgSender;
newCtx = ctx;
bool isConnected = _isMemberConnected(token, address(pool), msgSender);
if (doConnect != isConnected) {
assert(
SuperfluidPool(address(pool)).operatorConnectMember(
msgSender, doConnect, uint32(currentContext.timestamp)
)
);
if (doConnect) {
uint32 poolSlotID =
_findAndFillPoolConnectionsBitmap(token, msgSender, bytes32(uint256(uint160(address(pool)))));
// malicious token can reenter here
// external call to untrusted contract
// what sort of boundary can we trust
token.createAgreement(
_getPoolMemberHash(msgSender, pool),
_encodePoolMemberData(PoolMemberData({ poolID: poolSlotID, pool: address(pool) }))
);
} else {
(, PoolMemberData memory poolMemberData) = _getPoolMemberData(token, msgSender, pool);
token.terminateAgreement(_getPoolMemberHash(msgSender, pool), 1);
_clearPoolConnectionsBitmap(token, msgSender, poolMemberData.poolID);
}
emit PoolConnectionUpdated(token, pool, msgSender, doConnect, currentContext.userData);
}
}
function _isMemberConnected(ISuperfluidToken token, address pool, address member) internal view returns (bool) {
(bool exist,) = _getPoolMemberData(token, member, ISuperfluidPool(pool));
return exist;
}
function isMemberConnected(ISuperfluidPool pool, address member) external view override returns (bool) {
return _isMemberConnected(pool.superToken(), address(pool), member);
}
function appendIndexUpdateByPool(ISuperfluidToken token, BasicParticle memory p, Time t) external returns (bool) {
if (_isPool(token, msg.sender) == false) {
revert GDA_ONLY_SUPER_TOKEN_POOL();
}
bytes memory eff = abi.encode(token);
_setUIndex(eff, msg.sender, _getUIndex(eff, msg.sender).mappend(p));
_setPoolAdjustmentFlowRate(eff, msg.sender, true, /* doShift? */ p.flow_rate(), t);
return true;
}
function poolSettleClaim(ISuperfluidToken superToken, address claimRecipient, int256 amount)
external
returns (bool)
{
if (_isPool(superToken, msg.sender) == false) {
revert GDA_ONLY_SUPER_TOKEN_POOL();
}
// _poolSettleClaim()
_doShift(abi.encode(superToken), msg.sender, claimRecipient, Value.wrap(amount));
return true;
}
/// @inheritdoc IGeneralDistributionAgreementV1
function distribute(
ISuperfluidToken token,
address from,
ISuperfluidPool pool,
uint256 requestedAmount,
bytes calldata ctx
) external override returns (bytes memory newCtx) {
ISuperfluid.Context memory currentContext = AgreementLibrary.authorizeTokenAccess(token, ctx);
newCtx = ctx;
if (_isPool(token, address(pool)) == false ||
// Note: we do not support multi-tokens pools
pool.superToken() != token) {
revert GDA_ONLY_SUPER_TOKEN_POOL();
}
// you cannot distribute if admin is not equal to the ctx.msgSender
if (!pool.distributionFromAnyAddress()) {
if (pool.admin() != currentContext.msgSender) {
revert GDA_DISTRIBUTE_FROM_ANY_ADDRESS_NOT_ALLOWED();
}
}
// the from address must be the same as the ctx.msgSender
// there is no ACL support
if (from != currentContext.msgSender) {
revert GDA_DISTRIBUTE_FOR_OTHERS_NOT_ALLOWED();
}
(, Value actualAmount) = _doDistributeViaPool(
abi.encode(token), currentContext.msgSender, address(pool), Value.wrap(requestedAmount.toInt256())
);
if (token.isAccountCriticalNow(from)) {
revert GDA_INSUFFICIENT_BALANCE();
}
// TODO: tokens are moving from sender => pool, including a transfer event makes sense here
// trigger from the supertoken contract - @note this is possible since solc 0.8.21
emit InstantDistributionUpdated(
token,
pool,
from,
currentContext.msgSender,
requestedAmount,
uint256(Value.unwrap(actualAmount)), // upcast from int256 -> uint256 is safe
currentContext.userData
);
}
// solhint-disable-next-line contract-name-camelcase
struct _StackVars_DistributeFlow {
ISuperfluid.Context currentContext;
bytes32 distributionFlowHash;
FlowRate oldFlowRate;
}
// solhint-disable-next-line contract-name-camelcase
struct _StackVars_Liquidation {
ISuperfluidToken token;
int256 availableBalance;
address sender;
bytes32 distributionFlowHash;
int256 signedTotalGDADeposit;
address liquidator;
}
/// @inheritdoc IGeneralDistributionAgreementV1
function distributeFlow(
ISuperfluidToken token,
address from,
ISuperfluidPool pool,
int96 requestedFlowRate,
bytes calldata ctx
) external override returns (bytes memory newCtx) {
if (_isPool(token, address(pool)) == false ||
// Note: we do not support multi-tokens pools
pool.superToken() != token) {
revert GDA_ONLY_SUPER_TOKEN_POOL();
}
if (requestedFlowRate < 0) {
revert GDA_NO_NEGATIVE_FLOW_RATE();
}
_StackVars_DistributeFlow memory flowVars;
{
flowVars.currentContext = AgreementLibrary.authorizeTokenAccess(token, ctx);
flowVars.distributionFlowHash = _getFlowDistributionHash(from, pool);
flowVars.oldFlowRate = _getFlowRate(abi.encode(token), flowVars.distributionFlowHash);
}
newCtx = ctx;
// we must check if the requestedFlowRate is greater than 0 here
// otherwise we will block liquidators from closing streams in pools
// where the pool config has distributionFromAnyAddress set to false
if (requestedFlowRate > 0 && !pool.distributionFromAnyAddress()) {
if (pool.admin() != flowVars.currentContext.msgSender) {
revert GDA_DISTRIBUTE_FROM_ANY_ADDRESS_NOT_ALLOWED();
}
}
(, FlowRate actualFlowRate, FlowRate newDistributionFlowRate) = _doDistributeFlowViaPool(
abi.encode(token),
from,
address(pool),
flowVars.distributionFlowHash,
FlowRate.wrap(requestedFlowRate),
Time.wrap(uint32(flowVars.currentContext.timestamp))
);
// handle distribute flow on behalf of someone else
// @note move to internal maybe
{
if (from != flowVars.currentContext.msgSender) {
if (requestedFlowRate > 0) {
// @note no ACL support for now
// revert if trying to distribute on behalf of others
revert GDA_DISTRIBUTE_FOR_OTHERS_NOT_ALLOWED();
} else {
// liquidation case, requestedFlowRate == 0
(int256 availableBalance,,) = token.realtimeBalanceOf(from, flowVars.currentContext.timestamp);
// StackVarsLiquidation used to handle good ol' stack too deep
_StackVars_Liquidation memory liquidationData;
{
liquidationData.token = token;
liquidationData.sender = from;
liquidationData.liquidator = flowVars.currentContext.msgSender;
liquidationData.distributionFlowHash = flowVars.distributionFlowHash;
liquidationData.signedTotalGDADeposit =
_getUIndexData(abi.encode(token), from).totalBuffer.toInt256();
liquidationData.availableBalance = availableBalance;
}
// closing stream on behalf of someone else: liquidation case
if (availableBalance < 0) {
_makeLiquidationPayouts(liquidationData);
} else {
revert GDA_NON_CRITICAL_SENDER();
}
}
}
}
{
_adjustBuffer(token, address(pool), from, flowVars.distributionFlowHash, actualFlowRate);
}
// ensure sender has enough balance to execute transaction
if (from == flowVars.currentContext.msgSender) {
(int256 availableBalance,,) = token.realtimeBalanceOf(from, flowVars.currentContext.timestamp);
// if from == msg.sender
if (requestedFlowRate > 0 && availableBalance < 0) {
revert GDA_INSUFFICIENT_BALANCE();
}
}
{
(address adjustmentFlowRecipient,, int96 adjustmentFlowRate) =
_getPoolAdjustmentFlowInfo(abi.encode(token), address(pool));
emit FlowDistributionUpdated(
token,
pool,
from,
flowVars.currentContext.msgSender,
int256(FlowRate.unwrap(flowVars.oldFlowRate)).toInt96(),
int256(FlowRate.unwrap(actualFlowRate)).toInt96(),
int256(FlowRate.unwrap(newDistributionFlowRate)).toInt96(),
adjustmentFlowRecipient,
adjustmentFlowRate,
flowVars.currentContext.userData
);
}
}
function _getPoolAdminNFTAddress(ISuperfluidToken token) internal view returns (address poolAdminNFTAddress) {
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory data) =
address(token).staticcall(abi.encodeWithSelector(ISuperToken.POOL_ADMIN_NFT.selector));
if (success) {
// @note We are aware this may revert if a Custom SuperToken's
// POOL_ADMIN_NFT does not return data that can be
// decoded to an address. This would mean it was intentionally
// done by the creator of the Custom SuperToken logic and is
// fully expected to revert in that case as the author desired.
poolAdminNFTAddress = abi.decode(data, (address));
}
}
function _makeLiquidationPayouts(_StackVars_Liquidation memory data) internal {
(, FlowDistributionData memory flowDistributionData) =
_getFlowDistributionData(ISuperfluidToken(data.token), data.distributionFlowHash);
int256 signedSingleDeposit = flowDistributionData.buffer.toInt256();
bool isCurrentlyPatricianPeriod;
{
(uint256 liquidationPeriod, uint256 patricianPeriod) =
SolvencyHelperLibrary.decode3PsData(ISuperfluid(_host), data.token);
isCurrentlyPatricianPeriod = SolvencyHelperLibrary.isPatricianPeriod(
data.availableBalance, data.signedTotalGDADeposit, liquidationPeriod, patricianPeriod
);
}
int256 totalRewardLeft = data.availableBalance + data.signedTotalGDADeposit;
// critical case
if (totalRewardLeft >= 0) {
int256 rewardAmount = (signedSingleDeposit * totalRewardLeft) / data.signedTotalGDADeposit;
data.token.makeLiquidationPayoutsV2(
data.distributionFlowHash,
abi.encode(2, isCurrentlyPatricianPeriod ? 0 : 1),
data.liquidator,
isCurrentlyPatricianPeriod,
data.sender,
rewardAmount.toUint256(),
rewardAmount * -1
);
} else {
int256 rewardAmount = signedSingleDeposit;
// bailout case
data.token.makeLiquidationPayoutsV2(
data.distributionFlowHash,
abi.encode(2, 2),
data.liquidator,
false,
data.sender,
rewardAmount.toUint256(),
totalRewardLeft * -1
);
}
}
function _adjustBuffer(ISuperfluidToken token, address pool, address from, bytes32 flowHash, FlowRate newFlowRate)
internal
{
// not using oldFlowRate in this model
// surprising effect: reducing flow rate may require more buffer when liquidation_period adjusted upward
ISuperfluidGovernance gov = ISuperfluidGovernance(ISuperfluid(_host).getGovernance());
uint256 minimumDeposit =
gov.getConfigAsUint256(ISuperfluid(msg.sender), ISuperfluidToken(token), SUPERTOKEN_MINIMUM_DEPOSIT_KEY);
(uint256 liquidationPeriod,) = SolvencyHelperLibrary.decode3PsData(ISuperfluid(_host), ISuperfluidToken(token));
(, FlowDistributionData memory flowDistributionData) =
_getFlowDistributionData(ISuperfluidToken(token), flowHash);
// @note downcasting from uint256 -> uint32 for liquidation period
Value newBufferAmount = newFlowRate.mul(Time.wrap(uint32(liquidationPeriod)));
if (Value.unwrap(newBufferAmount).toUint256() < minimumDeposit && FlowRate.unwrap(newFlowRate) > 0) {
newBufferAmount = Value.wrap(minimumDeposit.toInt256());
}
Value bufferDelta = newBufferAmount - Value.wrap(uint256(flowDistributionData.buffer).toInt256());
{
bytes32[] memory data = _encodeFlowDistributionData(
FlowDistributionData({
lastUpdated: uint32(block.timestamp),
flowRate: int256(FlowRate.unwrap(newFlowRate)).toInt96(),
buffer: uint256(Value.unwrap(newBufferAmount)) // upcast to uint256 is safe
})
);
ISuperfluidToken(token).updateAgreementData(flowHash, data);
}
UniversalIndexData memory universalIndexData = _getUIndexData(abi.encode(token), from);
universalIndexData.totalBuffer =
// new buffer
(universalIndexData.totalBuffer.toInt256() + Value.unwrap(bufferDelta)).toUint256();
ISuperfluidToken(token).updateAgreementStateSlot(
from, _UNIVERSAL_INDEX_STATE_SLOT_ID, _encodeUniversalIndexData(universalIndexData)
);
{
emit BufferAdjusted(
ISuperfluidToken(token),
ISuperfluidPool(pool),
from,
Value.unwrap(bufferDelta),
Value.unwrap(newBufferAmount).toUint256(),
universalIndexData.totalBuffer
);
}
}
// Solvency Related Getters
function isPatricianPeriodNow(ISuperfluidToken token, address account)
external
view
override
returns (bool isCurrentlyPatricianPeriod, uint256 timestamp)
{
timestamp = ISuperfluid(_host).getNow();
isCurrentlyPatricianPeriod = isPatricianPeriod(token, account, timestamp);
}
function isPatricianPeriod(ISuperfluidToken token, address account, uint256 timestamp)
public
view
override
returns (bool)
{
(int256 availableBalance,,) = token.realtimeBalanceOf(account, timestamp);
if (availableBalance >= 0) {
return true;
}
(uint256 liquidationPeriod, uint256 patricianPeriod) =
SolvencyHelperLibrary.decode3PsData(ISuperfluid(_host), token);
return SolvencyHelperLibrary.isPatricianPeriod(
availableBalance,
_getUIndexData(abi.encode(token), account).totalBuffer.toInt256(),
liquidationPeriod,
patricianPeriod
);
}
// Hash Getters
function _getPoolMemberHash(address poolMember, ISuperfluidPool pool) internal view returns (bytes32) {
return keccak256(abi.encode(block.chainid, "poolMember", poolMember, address(pool)));
}
function _getFlowDistributionHash(address from, ISuperfluidPool to) internal view returns (bytes32) {
return keccak256(abi.encode(block.chainid, "distributionFlow", from, to));
}
function _getPoolAdjustmentFlowHash(address from, address to) internal view returns (bytes32) {
// this will never be in conflict with other flow has types
return keccak256(abi.encode(block.chainid, "poolAdjustmentFlow", from, to));
}
// # Universal Index operations
//
// Universal Index packing:
// store buffer (96) and one bit to specify is pool in free
// -------- ------------------ ------------------ ------------------ ------------------
// WORD 1: | flowRate | settledAt | totalBuffer | isPool |
// -------- ------------------ ------------------ ------------------ ------------------
// | 96b | 32b | 96b | 32b |
// -------- ------------------ ------------------ ------------------ ------------------
// WORD 2: | settledValue |
// -------- ------------------ ------------------ ------------------ ------------------
// | 256b |
// -------- ------------------ ------------------ ------------------ ------------------
function _encodeUniversalIndexData(BasicParticle memory p, uint256 buffer, bool isPool_)
internal
pure
returns (bytes32[] memory data)
{
data = new bytes32[](2);
data[0] = bytes32(
(uint256(int256(FlowRate.unwrap(p.flow_rate()))) << 160) | (uint256(Time.unwrap(p.settled_at())) << 128)
| (uint256(buffer.toUint96()) << 32) | (isPool_ ? 1 : 0)
);
data[1] = bytes32(uint256(Value.unwrap(p._settled_value)));
}
function _encodeUniversalIndexData(UniversalIndexData memory uIndexData)
internal
pure
returns (bytes32[] memory data)
{
data = new bytes32[](2);
data[0] = bytes32(
(uint256(int256(uIndexData.flowRate)) << 160) | (uint256(uIndexData.settledAt) << 128)
| (uint256(uIndexData.totalBuffer.toUint96()) << 32) | (uIndexData.isPool ? 1 : 0)
);
data[1] = bytes32(uint256(uIndexData.settledValue));
}
function _decodeUniversalIndexData(bytes32[] memory data)
internal
pure
returns (bool exists, UniversalIndexData memory universalIndexData)
{
uint256 a = uint256(data[0]);
uint256 b = uint256(data[1]);
exists = a > 0 || b > 0;
if (exists) {
universalIndexData.flowRate = int96(int256(a >> 160) & int256(uint256(type(uint96).max)));
universalIndexData.settledAt = uint32(uint256(a >> 128) & uint256(type(uint32).max));
universalIndexData.totalBuffer = uint256(a >> 32) & uint256(type(uint96).max);
universalIndexData.isPool = ((a << 224) >> 224) & 1 == 1;
universalIndexData.settledValue = int256(b);
}
}
function _getUIndexData(bytes memory eff, address owner)
internal
view
returns (UniversalIndexData memory universalIndexData)
{
(, universalIndexData) = _decodeUniversalIndexData(
ISuperfluidToken(abi.decode(eff, (address))).getAgreementStateSlot(
address(this), owner, _UNIVERSAL_INDEX_STATE_SLOT_ID, 2
)
);
}
function _getBasicParticleFromUIndex(UniversalIndexData memory universalIndexData)
internal
pure
returns (BasicParticle memory particle)
{
particle._flow_rate = FlowRate.wrap(universalIndexData.flowRate);
particle._settled_at = Time.wrap(universalIndexData.settledAt);
particle._settled_value = Value.wrap(universalIndexData.settledValue);
}
// TokenMonad virtual functions
function _getUIndex(bytes memory eff, address owner) internal view override returns (BasicParticle memory uIndex) {
(, UniversalIndexData memory universalIndexData) = _decodeUniversalIndexData(
ISuperfluidToken(abi.decode(eff, (address))).getAgreementStateSlot(
address(this), owner, _UNIVERSAL_INDEX_STATE_SLOT_ID, 2
)
);
uIndex = _getBasicParticleFromUIndex(universalIndexData);
}
function _setUIndex(bytes memory eff, address owner, BasicParticle memory p)
internal
override
returns (bytes memory)
{
UniversalIndexData memory universalIndexData = _getUIndexData(eff, owner);
ISuperfluidToken(abi.decode(eff, (address))).updateAgreementStateSlot(
owner,
_UNIVERSAL_INDEX_STATE_SLOT_ID,
_encodeUniversalIndexData(p, universalIndexData.totalBuffer, universalIndexData.isPool)
);
return eff;
}
function _getPDPIndex(
bytes memory, // eff,
address pool
) internal view override returns (PDPoolIndex memory) {
SuperfluidPool.PoolIndexData memory data = SuperfluidPool(pool).poolOperatorGetIndex();
return poolIndexDataToPDPoolIndex(data);
}
function _setPDPIndex(bytes memory eff, address pool, PDPoolIndex memory p)
internal
override
returns (bytes memory)
{
assert(SuperfluidPool(pool).operatorSetIndex(p));
return eff;
}
function _getFlowRate(bytes memory eff, bytes32 distributionFlowHash) internal view override returns (FlowRate) {
(, FlowDistributionData memory data) =
_getFlowDistributionData(ISuperfluidToken(abi.decode(eff, (address))), distributionFlowHash);
return FlowRate.wrap(data.flowRate);
}
function _setFlowInfo(
bytes memory eff,
bytes32 flowHash,
address, // from,
address, // to,
FlowRate newFlowRate,
FlowRate // flowRateDelta
) internal override returns (bytes memory) {
address token = abi.decode(eff, (address));
(, FlowDistributionData memory flowDistributionData) =
_getFlowDistributionData(ISuperfluidToken(token), flowHash);
ISuperfluidToken(token).updateAgreementData(
flowHash,
_encodeFlowDistributionData(
FlowDistributionData({
lastUpdated: uint32(block.timestamp),
flowRate: int256(FlowRate.unwrap(newFlowRate)).toInt96(),
buffer: flowDistributionData.buffer
})
)
);
return eff;
}
/// @inheritdoc IGeneralDistributionAgreementV1
function getPoolAdjustmentFlowInfo(ISuperfluidPool pool)
external
view
override
returns (address recipient, bytes32 flowHash, int96 flowRate)
{
return _getPoolAdjustmentFlowInfo(abi.encode(pool.superToken()), address(pool));
}
function _getPoolAdjustmentFlowInfo(bytes memory eff, address pool)
internal
view
returns (address adjustmentRecipient, bytes32 flowHash, int96 flowRate)
{
// pool admin is always the adjustment recipient
adjustmentRecipient = ISuperfluidPool(pool).admin();
flowHash = _getPoolAdjustmentFlowHash(pool, adjustmentRecipient);
return (adjustmentRecipient, flowHash, int256(FlowRate.unwrap(_getFlowRate(eff, flowHash))).toInt96());
}
function _getPoolAdjustmentFlowRate(bytes memory eff, address pool)
internal
view
override
returns (FlowRate flowRate)
{
(,, int96 rawFlowRate) = _getPoolAdjustmentFlowInfo(eff, pool);
flowRate = FlowRate.wrap(int128(rawFlowRate)); // upcasting to int128 is safe
}
function getPoolAdjustmentFlowRate(address pool) external view override returns (int96) {
ISuperfluidToken token = ISuperfluidPool(pool).superToken();
return int256(FlowRate.unwrap(_getPoolAdjustmentFlowRate(abi.encode(token), pool))).toInt96();
}
function _setPoolAdjustmentFlowRate(bytes memory eff, address pool, FlowRate flowRate, Time t)
internal
override
returns (bytes memory)
{
return _setPoolAdjustmentFlowRate(eff, pool, false, /* doShift? */ flowRate, t);
}
function _setPoolAdjustmentFlowRate(bytes memory eff, address pool, bool doShiftFlow, FlowRate flowRate, Time t)
internal
returns (bytes memory)
{
// @note should this also always be
address adjustmentRecipient = ISuperfluidPool(pool).admin();
bytes32 adjustmentFlowHash = _getPoolAdjustmentFlowHash(pool, adjustmentRecipient);
if (doShiftFlow) {
flowRate = flowRate + _getFlowRate(eff, adjustmentFlowHash);
}
eff = _doFlow(eff, pool, adjustmentRecipient, adjustmentFlowHash, flowRate, t);
return eff;
}
/// @inheritdoc IGeneralDistributionAgreementV1
function isPool(ISuperfluidToken token, address account) external view override returns (bool) {
return _isPool(token, account);
}
function _isPool(ISuperfluidToken token, address account) internal view returns (bool exists) {
// @note see createPool, we retrieve the isPool bit from
// UniversalIndex for this pool to determine whether the account
// is a pool
exists = (
(uint256(token.getAgreementStateSlot(address(this), account, _UNIVERSAL_INDEX_STATE_SLOT_ID, 1)[0]) << 224)
>> 224
) & 1 == 1;
}
// FlowDistributionData data packing:
// -------- ---------- ------------- ---------- --------
// WORD A: | reserved | lastUpdated | flowRate | buffer |
// -------- ---------- ------------- ---------- --------
// | 32 | 32 | 96 | 96 |
// -------- ---------- ------------- ---------- --------
function _encodeFlowDistributionData(FlowDistributionData memory flowDistributionData)
internal
pure
returns (bytes32[] memory data)
{
data = new bytes32[](1);
data[0] = bytes32(
(uint256(uint32(flowDistributionData.lastUpdated)) << 192)
| (uint256(uint96(flowDistributionData.flowRate)) << 96) | uint256(flowDistributionData.buffer)
);
}
function _decodeFlowDistributionData(uint256 data)
internal
pure
returns (bool exist, FlowDistributionData memory flowDistributionData)
{
exist = data > 0;
if (exist) {
flowDistributionData.lastUpdated = uint32((data >> 192) & uint256(type(uint32).max));
flowDistributionData.flowRate = int96(int256(data >> 96));
flowDistributionData.buffer = uint96(data & uint256(type(uint96).max));
}
}
function _getFlowDistributionData(ISuperfluidToken token, bytes32 distributionFlowHash)
internal
view
returns (bool exist, FlowDistributionData memory flowDistributionData)
{
(exist, flowDistributionData) =
_decodeFlowDistributionData(uint256(token.getAgreementData(address(this), distributionFlowHash, 1)[0]));
}
// PoolMemberData data packing:
// -------- ---------- -------- -------------
// WORD A: | reserved | poolID | poolAddress |
// -------- ---------- -------- -------------
// | 64 | 32 | 160 |
// -------- ---------- -------- -------------
function _encodePoolMemberData(PoolMemberData memory poolMemberData)
internal
pure
returns (bytes32[] memory data)
{
data = new bytes32[](1);
data[0] = bytes32((uint256(uint32(poolMemberData.poolID)) << 160) | uint256(uint160(poolMemberData.pool)));
}
function _decodePoolMemberData(uint256 data)
internal
pure
returns (bool exist, PoolMemberData memory poolMemberData)
{
exist = data > 0;
if (exist) {
poolMemberData.pool = address(uint160(data & uint256(type(uint160).max)));
poolMemberData.poolID = uint32(data >> 160);
}
}
function _getPoolMemberData(ISuperfluidToken token, address poolMember, ISuperfluidPool pool)
internal
view
returns (bool exist, PoolMemberData memory poolMemberData)
{
(exist, poolMemberData) = _decodePoolMemberData(
uint256(token.getAgreementData(address(this), _getPoolMemberHash(poolMember, pool), 1)[0])
);
}
// SlotsBitmap Pool Data:
function _findAndFillPoolConnectionsBitmap(ISuperfluidToken token, address poolMember, bytes32 poolID)
private
returns (uint32 slotId)
{
return SlotsBitmapLibrary.findEmptySlotAndFill(
token, poolMember, _POOL_SUBS_BITMAP_STATE_SLOT_ID, _POOL_CONNECTIONS_DATA_STATE_SLOT_ID_START, poolID
);
}
function _clearPoolConnectionsBitmap(ISuperfluidToken token, address poolMember, uint32 slotId) private {
SlotsBitmapLibrary.clearSlot(token, poolMember, _POOL_SUBS_BITMAP_STATE_SLOT_ID, slotId);
}
function _listPoolConnectionIds(ISuperfluidToken token, address subscriber)
private
view
returns (uint32[] memory slotIds, bytes32[] memory pidList)
{
(slotIds, pidList) = SlotsBitmapLibrary.listData(
token, subscriber, _POOL_SUBS_BITMAP_STATE_SLOT_ID, _POOL_CONNECTIONS_DATA_STATE_SLOT_ID_START
);
}
}// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.23;
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.23;
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: UNLICENSED
pragma solidity ^0.8.19;
import {
Time, Value, FlowRate,
BasicParticle,
PDPoolIndex
} from "./SemanticMoney.sol";
/**
* @title Monadic interface for Semantic Money as abstract contract.
*
* Note:
*
* eff - Opaque context for all monadic effects. They should be used to provide the context for the getter/setters.
* Its naming is inspired by effect systems.
*/
abstract contract TokenMonad {
function _getUIndex(bytes memory eff, address owner)
virtual internal view returns (BasicParticle memory);
function _setUIndex(bytes memory eff, address owner, BasicParticle memory p)
virtual internal returns (bytes memory);
function _getPDPIndex(bytes memory eff, address pool)
virtual internal view returns (PDPoolIndex memory);
function _setPDPIndex(bytes memory eff, address pool, PDPoolIndex memory p)
virtual internal returns (bytes memory);
function _getFlowRate(bytes memory, bytes32 flowHash)
virtual internal view returns (FlowRate);
function _setFlowInfo(bytes memory eff, bytes32 flowHash, address from, address to,
FlowRate newFlowRate, FlowRate flowRateDelta)
virtual internal returns (bytes memory);
function _getPoolAdjustmentFlowRate(bytes memory eff, address pool)
virtual internal view returns (FlowRate);
function _setPoolAdjustmentFlowRate(bytes memory eff, address pool, FlowRate flowRate, Time)
virtual internal returns (bytes memory);
function _doShift(bytes memory eff, address from, address to, Value amount)
internal returns (bytes memory)
{
if (from == to) return eff; // short circuit
BasicParticle memory a = _getUIndex(eff, from);
BasicParticle memory b = _getUIndex(eff, to);
(a, b) = a.shift2(b, amount);
eff = _setUIndex(eff, from, a);
eff = _setUIndex(eff, to, b);
return eff;
}
function _doFlow(bytes memory eff,
address from, address to, bytes32 flowHash, FlowRate flowRate,
Time t)
internal returns (bytes memory)
{
if (from == to) return eff; // short circuit
FlowRate flowRateDelta = flowRate - _getFlowRate(eff, flowHash);
BasicParticle memory a = _getUIndex(eff, from);
BasicParticle memory b = _getUIndex(eff, to);
(a, b) = a.shift_flow2b(b, flowRateDelta, t);
eff = _setUIndex(eff, from, a);
eff = _setUIndex(eff, to, b);
eff = _setFlowInfo(eff, flowHash, from, to, flowRate, flowRateDelta);
return eff;
}
function _doDistributeViaPool(bytes memory eff, address from, address pool, Value reqAmount)
internal returns (bytes memory, Value actualAmount)
{
assert(from != pool);
// a: from uidx -> b: pool uidx -> c: pool pdpidx
// b is completely by-passed
BasicParticle memory a = _getUIndex(eff, from);
PDPoolIndex memory c = _getPDPIndex(eff, pool);
(a, c, actualAmount) = a.shift2b(c, reqAmount);
eff = _setUIndex(eff, from, a);
eff = _setPDPIndex(eff, pool, c);
return (eff, actualAmount);
}
// Note: because of no-via-ir builds and stack too deep :)
struct DistributeFlowVars {
FlowRate currentAdjustmentFlowRate;
FlowRate newAdjustmentFlowRate;
FlowRate actualFlowRateDelta;
}
function _doDistributeFlowViaPool(bytes memory eff,
address from, address pool, bytes32 flowHash, FlowRate reqFlowRate,
Time t)
internal returns (bytes memory, FlowRate newActualFlowRate, FlowRate newDistributionFlowRate)
{
assert(from != pool);
// a: from uidx -> b: pool uidx -> c: pool pdpidx
// b handles the adjustment flow through _get/_setPoolAdjustmentFlowRate.
BasicParticle memory a = _getUIndex(eff, from);
BasicParticle memory b = _getUIndex(eff, pool);
PDPoolIndex memory c = _getPDPIndex(eff, pool);
DistributeFlowVars memory vars;
vars.currentAdjustmentFlowRate = _getPoolAdjustmentFlowRate(eff, pool);
{
FlowRate oldFlowRate = _getFlowRate(eff, flowHash); // flow rate of : from -> pool
FlowRate oldDistributionFlowRate = c.flow_rate();
FlowRate shiftFlowRate = reqFlowRate - oldFlowRate;
// to readjust, include the current adjustment flow rate here
(b, c, newDistributionFlowRate) = b.shift_flow2b(c, shiftFlowRate + vars.currentAdjustmentFlowRate, t);
assert(FlowRate.unwrap(newDistributionFlowRate) >= 0);
newActualFlowRate = oldFlowRate
+ (newDistributionFlowRate - oldDistributionFlowRate)
- vars.currentAdjustmentFlowRate;
if (FlowRate.unwrap(newActualFlowRate) >= 0) {
// previous adjustment flow is fully utilized
vars.newAdjustmentFlowRate = FlowRate.wrap(0);
} else {
// previous adjustment flow still needed
vars.newAdjustmentFlowRate = -newActualFlowRate;
newActualFlowRate = FlowRate.wrap(0);
}
vars.actualFlowRateDelta = newActualFlowRate - oldFlowRate;
(a, b) = a.shift_flow2b(b, vars.actualFlowRateDelta, t);
}
eff = _setUIndex(eff, from, a);
eff = _setUIndex(eff, pool, b);
eff = _setPDPIndex(eff, pool, c);
eff = _setFlowInfo(eff, flowHash, from, pool, newActualFlowRate, vars.actualFlowRateDelta);
eff = _setPoolAdjustmentFlowRate(eff, pool, vars.newAdjustmentFlowRate, t);
return (eff, newActualFlowRate, newDistributionFlowRate);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
/*******************************************************************************
* On Coding Style: Functional Programming In Solidity
*
* This library is a translation of the Haskell Specification of Semantic Money.
*
* All functions are pure functions, more so than the "pure" solidity function
* in that memory input data are always cloned. This makes true referential
* transparency for all functions defined here.
*
* To visually inform the library users about this paradigm, the coding style
* is deliberately chosen to go against the commonly recommended solhint sets.
* Namely:
*
* - All library and "free range" function names are in snake_cases.
* - All struct variables are in snake_cases.
* - All types are in capitalized CamelCases.
* - Comments are scarce, and written only for solidity specifics. This is to
* minimize regurgitation of the facts and keep original the original
* information where it belongs to. The clarity of the semantics and grunular
* of the API should compensate for that controversial take.
*/
// solhint-disable func-name-mixedcase
// solhint-disable var-name-mixedcase
////////////////////////////////////////////////////////////////////////////////
// Monetary Types and Their Helpers
////////////////////////////////////////////////////////////////////////////////
/********************************************************************************
* About Fix-point Arithmetic
*
* There are two types of integral mul/div used in the system:
*
* - FlowRate `mul`|`div` Time
* - Value `mul`|`div` Unit
*
* There are two major reasons that there is no built-in fixed-point arithmetic
* support in this library:
*
* 1. To avoid any hardcoded decimal assumptions for the types at all cost. This
* means until there is generics for type-level decimal support in solidity,
* we are out of luck.
* 2. The library requires high fidelity arithmetic to adhere strictly to the
* law of conservation of values. Such arithmetic would require:
*
* - distributive laws for multiplications
* - mul.div is a fixed-point function
* - quot remainder law
*
* Fixed-point arithmetic does not satisfy these laws.
*
* Generally speaking, this is the recommended configurations for the decimals
* that works with this library:
*
* - Time, 0 decimals
* - Value, 18 decimals
* - Unit, 0 decimals
* - FlowRate, 18 decimals (in-sync with Value)
*
*/
/**
* @title Absolute time value in seconds represented by uint32 unix timestamp.
* @dev - This should represents absolute values, e.g. block timestamps.
*/
type Time is uint32;
function mt_t_eq(Time a, Time b) pure returns (bool) { return Time.unwrap(a) == Time.unwrap(b); }
function mt_t_neq(Time a, Time b) pure returns (bool) { return Time.unwrap(a) != Time.unwrap(b); }
function mt_t_le(Time a, Time b) pure returns (bool) { return Time.unwrap(a) < Time.unwrap(b); }
function mt_t_lte(Time a, Time b) pure returns (bool) { return Time.unwrap(a) <= Time.unwrap(b); }
function mt_t_gt(Time a, Time b) pure returns (bool) { return Time.unwrap(a) > Time.unwrap(b); }
function mt_t_gte(Time a, Time b) pure returns (bool) { return Time.unwrap(a) >= Time.unwrap(b); }
function mt_t_add_t(Time a, Time b) pure returns (Time) { return Time.wrap(Time.unwrap(a) + Time.unwrap(b)); }
function mt_t_sub_t(Time a, Time b) pure returns (Time) { return Time.wrap(Time.unwrap(a) - Time.unwrap(b)); }
using { mt_t_eq as ==, mt_t_neq as !=, mt_t_le as <, mt_t_lte as <=, mt_t_gt as >, mt_t_gte as >=,
mt_t_add_t as +, mt_t_sub_t as - } for Time global;
/**
* @title Unit value of monetary value represented with 256bits of signed integer.
*/
type Value is int256;
function mt_v_eq(Value a, Value b) pure returns (bool) { return Value.unwrap(a) == Value.unwrap(b); }
function mt_v_neq(Value a, Value b) pure returns (bool) { return Value.unwrap(a) != Value.unwrap(b); }
function mt_v_le(Value a, Value b) pure returns (bool) { return Value.unwrap(a) < Value.unwrap(b); }
function mt_v_lte(Value a, Value b) pure returns (bool) { return Value.unwrap(a) <= Value.unwrap(b); }
function mt_v_gt(Value a, Value b) pure returns (bool) { return Value.unwrap(a) > Value.unwrap(b); }
function mt_v_gte(Value a, Value b) pure returns (bool) { return Value.unwrap(a) >= Value.unwrap(b); }
function mt_v_add_v(Value a, Value b) pure returns (Value) { return Value.wrap(Value.unwrap(a) + Value.unwrap(b)); }
function mt_v_sub_v(Value a, Value b) pure returns (Value) { return Value.wrap(Value.unwrap(a) - Value.unwrap(b)); }
function mt_v_inv(Value a) pure returns (Value) { return Value.wrap(-Value.unwrap(a)); }
using { mt_v_eq as ==, mt_v_neq as !=, mt_v_le as <, mt_v_lte as <=, mt_v_gt as >, mt_v_gte as >=,
mt_v_add_v as +, mt_v_sub_v as -, mt_v_inv as - } for Value global;
/**
* @title Number of units represented with half the size of `Value`.
*/
type Unit is int128;
function mt_u_eq(Unit a, Unit b) pure returns (bool) { return Unit.unwrap(a) == Unit.unwrap(b); }
function mt_u_neq(Unit a, Unit b) pure returns (bool) { return Unit.unwrap(a) != Unit.unwrap(b); }
function mt_u_le(Unit a, Unit b) pure returns (bool) { return Unit.unwrap(a) < Unit.unwrap(b); }
function mt_u_lte(Unit a, Unit b) pure returns (bool) { return Unit.unwrap(a) <= Unit.unwrap(b); }
function mt_u_gt(Unit a, Unit b) pure returns (bool) { return Unit.unwrap(a) > Unit.unwrap(b); }
function mt_u_gte(Unit a, Unit b) pure returns (bool) { return Unit.unwrap(a) >= Unit.unwrap(b); }
function mt_u_add_u(Unit a, Unit b) pure returns (Unit) { return Unit.wrap(Unit.unwrap(a) + Unit.unwrap(b)); }
function mt_u_sub_u(Unit a, Unit b) pure returns (Unit) { return Unit.wrap(Unit.unwrap(a) - Unit.unwrap(b)); }
function mt_u_inv(Unit a) pure returns (Unit) { return Unit.wrap(-Unit.unwrap(a)); }
using { mt_u_eq as ==, mt_u_neq as !=, mt_u_le as <, mt_u_lte as <=, mt_u_gt as >, mt_u_gte as >=,
mt_u_add_u as +, mt_u_sub_u as -, mt_u_inv as - } for Unit global;
/**
* @title FlowRate value represented with half the size of `Value`.
*/
type FlowRate is int128;
function mt_r_eq(FlowRate a, FlowRate b) pure returns (bool) { return FlowRate.unwrap(a) == FlowRate.unwrap(b); }
function mt_r_neq(FlowRate a, FlowRate b) pure returns (bool) { return FlowRate.unwrap(a) != FlowRate.unwrap(b); }
function mt_r_le(FlowRate a, FlowRate b) pure returns (bool) { return FlowRate.unwrap(a) < FlowRate.unwrap(b); }
function mt_r_lte(FlowRate a, FlowRate b) pure returns (bool) { return FlowRate.unwrap(a) <= FlowRate.unwrap(b); }
function mt_r_gt(FlowRate a, FlowRate b) pure returns (bool) { return FlowRate.unwrap(a) > FlowRate.unwrap(b); }
function mt_r_gte(FlowRate a, FlowRate b) pure returns (bool) { return FlowRate.unwrap(a) >= FlowRate.unwrap(b); }
function mt_r_add_r(FlowRate a, FlowRate b) pure returns (FlowRate) {
return FlowRate.wrap(FlowRate.unwrap(a) + FlowRate.unwrap(b));
}
function mt_r_sub_r(FlowRate a, FlowRate b) pure returns (FlowRate) {
return FlowRate.wrap(FlowRate.unwrap(a) - FlowRate.unwrap(b));
}
function mt_r_inv(FlowRate a) pure returns (FlowRate) { return FlowRate.wrap(-FlowRate.unwrap(a)); }
using { mt_r_eq as ==, mt_r_neq as !=, mt_r_le as <, mt_r_lte as <=, mt_r_gt as >, mt_r_gte as >=,
mt_r_add_r as +, mt_r_sub_r as -, mt_r_inv as - } for FlowRate global;
/**
* @dev Additional helper functions for the monetary types
*
* Note that due to solidity current limitations, operators for mixed user defined value types
* are not supported, hence the need of this library.
* Read more at: https://github.com/ethereum/solidity/issues/11969#issuecomment-1448445474
*/
library AdditionalMonetaryTypeHelpers {
// Additional Time operators
//
function quotrem(Time a, Time b) internal pure returns (uint256 quot, uint256 rem) {
quot = Time.unwrap(a) / Time.unwrap(b);
rem = Time.unwrap(a) - quot * Time.unwrap(b);
}
// Additional Value operators
//
function quotrem(Value a, Value b) internal pure returns (int256 quot, int256 rem) {
quot = Value.unwrap(a) / Value.unwrap(b);
rem = Value.unwrap(a) - quot * Value.unwrap(b);
}
function mul(Value a, Unit b) internal pure returns (Value) {
return Value.wrap(Value.unwrap(a) * Unit.unwrap(b));
}
function div(Value a, Unit b) internal pure returns (Value) {
return Value.wrap(Value.unwrap(a) / Unit.unwrap(b));
}
// Additional FlowRate operators
//
function quotrem(FlowRate a, FlowRate b) internal pure returns (int256 quot, int256 rem) {
quot = FlowRate.unwrap(a) / FlowRate.unwrap(b);
rem = FlowRate.unwrap(a) - quot * FlowRate.unwrap(b);
}
function mul(FlowRate r, Time t) internal pure returns (Value) {
return Value.wrap(FlowRate.unwrap(r) * int256(uint256(Time.unwrap(t))));
}
function mul(FlowRate r, Unit u) internal pure returns (FlowRate) {
return FlowRate.wrap(FlowRate.unwrap(r) * Unit.unwrap(u));
}
function div(FlowRate a, Unit b) internal pure returns (FlowRate) {
return FlowRate.wrap(FlowRate.unwrap(a) / Unit.unwrap(b));
}
function quotrem(FlowRate r, Unit u) internal pure returns (FlowRate nr, FlowRate er) {
// quotient and remainder (error term), without using the '%'/modulo operator
nr = r.div(u);
er = r - nr.mul(u);
}
function mul_quotrem(FlowRate r, Unit u1, Unit u2) internal pure returns (FlowRate nr, FlowRate er) {
return r.mul(u1).quotrem(u2);
}
// Additional Unit operators
//
function quotrem(Unit a, Unit b) internal pure returns (int256 quot, int256 rem) {
quot = Unit.unwrap(a) / Unit.unwrap(b);
rem = Unit.unwrap(a) - quot * Unit.unwrap(b);
}
}
using AdditionalMonetaryTypeHelpers for Time global;
using AdditionalMonetaryTypeHelpers for Value global;
using AdditionalMonetaryTypeHelpers for FlowRate global;
using AdditionalMonetaryTypeHelpers for Unit global;
////////////////////////////////////////////////////////////////////////////////
// Basic particle
////////////////////////////////////////////////////////////////////////////////
/**
* @title Basic particle: the building block for payment primitives.
*/
struct BasicParticle {
Time _settled_at;
FlowRate _flow_rate;
Value _settled_value;
}
////////////////////////////////////////////////////////////////////////////////
// Proportional Distribution Pool Data Structures.
//
// Such pool has one index and many members.
////////////////////////////////////////////////////////////////////////////////
/**
* @dev Proportional distribution pool index data.
*/
struct PDPoolIndex {
Unit total_units;
// The value here are usually measured per unit
BasicParticle _wrapped_particle;
}
/**
* @dev Proportional distribution pool member data.
*/
struct PDPoolMember {
Unit owned_units;
Value _settled_value;
// It is a copy of the wrapped_particle of the index at the time an operation is performed.
BasicParticle _synced_particle;
}
/**
* @dev Proportional distribution pool "monetary unit" for a member.
*/
struct PDPoolMemberMU {
PDPoolIndex i;
PDPoolMember m;
}
/**
* @dev Semantic Money Library: providing generalized payment primitives.
*
* Notes:
*
* - Basic payment 2-primitives include shift2 and flow2.
* - As its name suggesting, 2-primitives work over two parties, each party is represented by an "index".
* - A universal index is BasicParticle plus being a Monoid. It is universal in the sense that every monetary
* unit should have one and only one such index.
* - Proportional distribution pool has one index per pool.
* - This solidity library provides 2-primitives for `UniversalIndex-to-UniversalIndex` and
* `UniversalIndex-to-ProportionalDistributionPoolIndex`.
*/
library SemanticMoney {
//
// Basic Particle Operations
//
/// Pure data clone function.
function clone(BasicParticle memory a) internal pure returns (BasicParticle memory b) {
// TODO memcpy
b._settled_at = a._settled_at;
b._flow_rate = a._flow_rate;
b._settled_value = a._settled_value;
}
function settled_at(BasicParticle memory a) internal pure returns (Time) {
return a._settled_at;
}
/// Monetary unit settle function for basic particle/universal index.
function settle(BasicParticle memory a, Time t) internal pure returns (BasicParticle memory b) {
b = a.clone();
b._settled_value = rtb(a, t);
b._settled_at = t;
}
function flow_rate(BasicParticle memory a) internal pure returns (FlowRate) {
return a._flow_rate;
}
/// Monetary unit rtb function for basic particle/universal index.
function rtb(BasicParticle memory a, Time t) internal pure returns (Value v) {
return a._flow_rate.mul(t - a._settled_at) + a._settled_value;
}
function shift1(BasicParticle memory a, Value x) internal pure returns (BasicParticle memory b) {
b = a.clone();
b._settled_value = b._settled_value + x;
}
function flow1(BasicParticle memory a, FlowRate r) internal pure returns (BasicParticle memory b) {
b = a.clone();
b._flow_rate = r;
}
//
// Universal Index Additional Operations
//
// Note: the identity element is trivial, the default BasicParticle value will do.
/// Monoid binary operator for basic particle/universal index.
function mappend(BasicParticle memory a, BasicParticle memory b)
internal pure returns (BasicParticle memory c)
{
// Note that the original spec abides the monoid laws even when time value is negative.
Time t = Time.unwrap(a._settled_at) > Time.unwrap(b._settled_at) ? a._settled_at : b._settled_at;
BasicParticle memory a1 = a.settle(t);
BasicParticle memory b1 = b.settle(t);
c._settled_at = t;
c._settled_value = a1._settled_value + b1._settled_value;
c._flow_rate = a1._flow_rate + b1._flow_rate;
}
//
// Proportional Distribution Pool Index Operations
//
/// Pure data clone function.
function clone(PDPoolIndex memory a) internal pure
returns (PDPoolIndex memory b)
{
b.total_units = a.total_units;
b._wrapped_particle = a._wrapped_particle.clone();
}
function settled_at(PDPoolIndex memory a) internal pure returns (Time) {
return a._wrapped_particle.settled_at();
}
/// Monetary unit settle function for pool index.
function settle(PDPoolIndex memory a, Time t) internal pure
returns (PDPoolIndex memory m)
{
m = a.clone();
m._wrapped_particle = m._wrapped_particle.settle(t);
}
function flow_rate(PDPoolIndex memory a) internal pure returns (FlowRate) {
return a._wrapped_particle._flow_rate.mul(a.total_units);
}
function flow_rate_per_unit(PDPoolIndex memory a) internal pure returns (FlowRate) {
return a._wrapped_particle.flow_rate();
}
function shift1(PDPoolIndex memory a, Value x) internal pure
returns (PDPoolIndex memory m, Value x1)
{
m = a.clone();
if (Unit.unwrap(a.total_units) != 0) {
x1 = x.div(a.total_units).mul(a.total_units);
m._wrapped_particle = a._wrapped_particle.shift1(x1.div(a.total_units));
}
}
function flow1(PDPoolIndex memory a, FlowRate r) internal pure
returns (PDPoolIndex memory m, FlowRate r1)
{
m = a.clone();
if (Unit.unwrap(a.total_units) != 0) {
r1 = r.div(a.total_units).mul(a.total_units);
m._wrapped_particle = m._wrapped_particle.flow1(r1.div(a.total_units));
}
}
//
// Proportional Distribution Pool Member Operations
//
/// Pure data clone function.
function clone(PDPoolMember memory a) internal pure
returns (PDPoolMember memory b)
{
b.owned_units = a.owned_units;
b._settled_value = a._settled_value;
b._synced_particle = a._synced_particle.clone();
}
/// Monetary unit settle function for pool member.
function settle(PDPoolMemberMU memory a, Time t) internal pure
returns (PDPoolMemberMU memory b)
{
b.i = a.i.settle(t);
b.m = a.m.clone();
b.m._settled_value = a.rtb(t);
b.m._synced_particle = b.i._wrapped_particle;
}
/// Monetary unit rtb function for pool member.
function rtb(PDPoolMemberMU memory a, Time t) internal pure
returns (Value v)
{
return a.m._settled_value +
(a.i._wrapped_particle.rtb(t)
- a.m._synced_particle.rtb(a.m._synced_particle.settled_at())
).mul(a.m.owned_units);
}
/// Update the unit amount of the member of the pool
function pool_member_update(PDPoolMemberMU memory b1, BasicParticle memory a, Unit u, Time t) internal pure
returns (PDPoolIndex memory p, PDPoolMember memory p1, BasicParticle memory b)
{
Unit oldTotalUnit = b1.i.total_units;
Unit newTotalUnit = oldTotalUnit + u - b1.m.owned_units;
PDPoolMemberMU memory b1s = b1.settle(t);
// align "a" because of the change of total units of the pool
FlowRate nr = b1s.i._wrapped_particle._flow_rate;
FlowRate er;
if (Unit.unwrap(newTotalUnit) != 0) {
(nr, er) = nr.mul_quotrem(oldTotalUnit, newTotalUnit);
er = er;
} else {
er = nr.mul(oldTotalUnit);
nr = FlowRate.wrap(0);
}
b1s.i._wrapped_particle = b1s.i._wrapped_particle.flow1(nr);
b1s.i.total_units = newTotalUnit;
b = a.settle(t).flow1(a._flow_rate + er);
p = b1s.i;
p1 = b1s.m;
p1.owned_units = u;
p1._synced_particle = b1s.i._wrapped_particle.clone();
}
//
// Instances of 2-primitives:
//
// Applying 2-primitives:
//
// 1) shift2
// 2) flow2 (and its related: shift_flow2)
//
// over:
//
// a) Universal Index to Universal Index
// b) Universal Index to Proportional Distribution Index
//
// totals FOUR general payment primitives.
//
// NB! Some code will look very similar, since without generic programming (or some form of parametric polymorphism)
// in solidity the code duplications is inevitable.
// the identity implementations for shift2a & shift2b
function shift2(BasicParticle memory a, BasicParticle memory b, Value x) internal pure
returns (BasicParticle memory m, BasicParticle memory n)
{
m = a.shift1(-x);
n = b.shift1(x);
}
function flow2(BasicParticle memory a, BasicParticle memory b, FlowRate r, Time t) internal pure
returns (BasicParticle memory m, BasicParticle memory n)
{
m = a.settle(t).flow1(-r);
n = b.settle(t).flow1(r);
}
function shift_flow2b(BasicParticle memory a, BasicParticle memory b, FlowRate dr, Time t) internal pure
returns (BasicParticle memory m, BasicParticle memory n)
{
BasicParticle memory mempty;
BasicParticle memory a1;
BasicParticle memory a2;
FlowRate r = b.flow_rate();
(a1, ) = mempty.flow2(b, -r, t);
(a2, n) = mempty.flow2(b, r + dr, t);
m = a.mappend(a1).mappend(a2);
}
// Note: This is functionally identity to shift_flow2b for (BasicParticle, BasicParticle).
// This is a included to keep fidelity with the semantic money specification.
function shift_flow2a(BasicParticle memory a, BasicParticle memory b, FlowRate dr, Time t) internal pure
returns (BasicParticle memory m, BasicParticle memory n)
{
BasicParticle memory mempty;
BasicParticle memory b1;
BasicParticle memory b2;
FlowRate r = a.flow_rate();
( , b1) = a.flow2(mempty, r, t);
(m, b2) = a.flow2(mempty, -r + dr, t);
n = b.mappend(b1).mappend(b2);
}
function shift2b(BasicParticle memory a, PDPoolIndex memory b, Value x) internal pure
returns (BasicParticle memory m, PDPoolIndex memory n, Value x1)
{
(n, x1) = b.shift1(x);
m = a.shift1(-x1);
}
function flow2(BasicParticle memory a, PDPoolIndex memory b, FlowRate r, Time t) internal pure
returns (BasicParticle memory m, PDPoolIndex memory n, FlowRate r1)
{
(n, r1) = b.settle(t).flow1(r);
m = a.settle(t).flow1(-r1);
}
function shift_flow2b(BasicParticle memory a, PDPoolIndex memory b, FlowRate dr, Time t) internal pure
returns (BasicParticle memory m, PDPoolIndex memory n, FlowRate r1)
{
BasicParticle memory mempty;
BasicParticle memory a1;
BasicParticle memory a2;
FlowRate r = b.flow_rate();
(a1, , ) = mempty.flow2(b, -r, t);
(a2, n, r1) = mempty.flow2(b, r + dr, t);
m = a.mappend(a1).mappend(a2);
}
}
using SemanticMoney for BasicParticle global;
using SemanticMoney for PDPoolIndex global;
using SemanticMoney for PDPoolMember global;
using SemanticMoney for PDPoolMemberMU global;// 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/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// 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 (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// 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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/UpgradeableBeacon.sol)
pragma solidity ^0.8.0;
import "./IBeacon.sol";
import "../../access/Ownable.sol";
import "../../utils/Address.sol";
/**
* @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their
* implementation contract, which is where they will delegate all function calls.
*
* An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.
*/
contract UpgradeableBeacon is IBeacon, Ownable {
address private _implementation;
/**
* @dev Emitted when the implementation returned by the beacon is changed.
*/
event Upgraded(address indexed implementation);
/**
* @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the
* beacon.
*/
constructor(address implementation_) {
_setImplementation(implementation_);
}
/**
* @dev Returns the current implementation address.
*/
function implementation() public view virtual override returns (address) {
return _implementation;
}
/**
* @dev Upgrades the beacon to a new implementation.
*
* Emits an {Upgraded} event.
*
* Requirements:
*
* - msg.sender must be the owner of the contract.
* - `newImplementation` must be a contract.
*/
function upgradeTo(address newImplementation) public virtual onlyOwner {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Sets the implementation contract address for this beacon
*
* Requirements:
*
* - `newImplementation` must be a contract.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "UpgradeableBeacon: implementation is not a contract");
_implementation = newImplementation;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol)
pragma solidity ^0.8.0;
import "./IBeacon.sol";
import "../Proxy.sol";
import "../ERC1967/ERC1967Upgrade.sol";
/**
* @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.
*
* The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't
* conflict with the storage layout of the implementation behind the proxy.
*
* _Available since v3.4._
*/
contract BeaconProxy is Proxy, ERC1967Upgrade {
/**
* @dev Initializes the proxy with `beacon`.
*
* If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
* will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity
* constructor.
*
* Requirements:
*
* - `beacon` must be a contract with the interface {IBeacon}.
*/
constructor(address beacon, bytes memory data) payable {
_upgradeBeaconToAndCall(beacon, data, false);
}
/**
* @dev Returns the current beacon address.
*/
function _beacon() internal view virtual returns (address) {
return _getBeacon();
}
/**
* @dev Returns the current implementation address of the associated beacon.
*/
function _implementation() internal view virtual override returns (address) {
return IBeacon(_getBeacon()).implementation();
}
/**
* @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.
*
* If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.
*
* Requirements:
*
* - `beacon` must be a contract.
* - The implementation returned by `beacon` must be a contract.
*/
function _setBeacon(address beacon, bytes memory data) internal virtual {
_upgradeBeaconToAndCall(beacon, data, false);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
pragma solidity ^0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive() external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overridden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/IERC1967.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*/
abstract contract ERC1967Upgrade is IERC1967 {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.0;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*
* _Available since v4.8.3._
*/
interface IERC1967 {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}{
"remappings": [],
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"libraries": {},
"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":"bool","name":"nonUpgradable","type":"bool"},{"internalType":"bool","name":"appWhiteListingEnabled","type":"bool"},{"internalType":"uint64","name":"callbackGasLimit","type":"uint64"},{"internalType":"address","name":"simpleForwarderAddress","type":"address"},{"internalType":"address","name":"erc2771ForwarderAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"_code","type":"uint256"}],"name":"APP_RULE","type":"error"},{"inputs":[],"name":"HOST_AGREEMENT_ALREADY_REGISTERED","type":"error"},{"inputs":[],"name":"HOST_AGREEMENT_CALLBACK_IS_NOT_ACTION","type":"error"},{"inputs":[],"name":"HOST_AGREEMENT_IS_NOT_REGISTERED","type":"error"},{"inputs":[],"name":"HOST_CALL_AGREEMENT_WITH_CTX_FROM_WRONG_ADDRESS","type":"error"},{"inputs":[],"name":"HOST_CALL_APP_ACTION_WITH_CTX_FROM_WRONG_ADDRESS","type":"error"},{"inputs":[],"name":"HOST_CANNOT_DOWNGRADE_TO_NON_UPGRADEABLE","type":"error"},{"inputs":[],"name":"HOST_INVALID_CONFIG_WORD","type":"error"},{"inputs":[],"name":"HOST_MAX_256_AGREEMENTS","type":"error"},{"inputs":[],"name":"HOST_MUST_BE_CONTRACT","type":"error"},{"inputs":[],"name":"HOST_NEED_MORE_GAS","type":"error"},{"inputs":[],"name":"HOST_NON_UPGRADEABLE","type":"error"},{"inputs":[],"name":"HOST_NON_ZERO_LENGTH_PLACEHOLDER_CTX","type":"error"},{"inputs":[],"name":"HOST_NOT_A_SUPER_APP","type":"error"},{"inputs":[],"name":"HOST_NO_APP_REGISTRATION_PERMISSION","type":"error"},{"inputs":[],"name":"HOST_ONLY_GOVERNANCE","type":"error"},{"inputs":[],"name":"HOST_ONLY_LISTED_AGREEMENT","type":"error"},{"inputs":[],"name":"HOST_RECEIVER_IS_NOT_SUPER_APP","type":"error"},{"inputs":[],"name":"HOST_SENDER_IS_NOT_SUPER_APP","type":"error"},{"inputs":[],"name":"HOST_SOURCE_APP_NEEDS_HIGHER_APP_LEVEL","type":"error"},{"inputs":[],"name":"HOST_SUPER_APP_ALREADY_REGISTERED","type":"error"},{"inputs":[],"name":"HOST_SUPER_APP_IS_JAILED","type":"error"},{"inputs":[],"name":"HOST_UNKNOWN_BATCH_CALL_OPERATION_TYPE","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"agreementType","type":"bytes32"},{"indexed":false,"internalType":"address","name":"code","type":"address"}],"name":"AgreementClassRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"agreementType","type":"bytes32"},{"indexed":false,"internalType":"address","name":"code","type":"address"}],"name":"AgreementClassUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperApp","name":"app","type":"address"}],"name":"AppRegistered","type":"event"},{"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":false,"internalType":"contract ISuperfluidGovernance","name":"oldGov","type":"address"},{"indexed":false,"internalType":"contract ISuperfluidGovernance","name":"newGov","type":"address"}],"name":"GovernanceReplaced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperApp","name":"app","type":"address"},{"indexed":false,"internalType":"uint256","name":"reason","type":"uint256"}],"name":"Jail","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beaconProxy","type":"address"},{"indexed":false,"internalType":"address","name":"newBeaconLogic","type":"address"}],"name":"PoolBeaconLogicUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ISuperTokenFactory","name":"newFactory","type":"address"}],"name":"SuperTokenFactoryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ISuperToken","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"code","type":"address"}],"name":"SuperTokenLogicUpdated","type":"event"},{"inputs":[],"name":"APP_WHITE_LISTING_ENABLED","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CALLBACK_GAS_LIMIT","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_APP_CALLBACK_LEVEL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_NUM_AGREEMENTS","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NON_UPGRADABLE_DEPLOYMENT","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SIMPLE_FORWARDER","outputs":[{"internalType":"contract SimpleForwarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bitmap","type":"uint256"},{"internalType":"bytes32","name":"agreementType","type":"bytes32"}],"name":"addToAgreementClassesBitmap","outputs":[{"internalType":"uint256","name":"newBitmap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"targetApp","type":"address"}],"name":"allowCompositeApp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"ctx","type":"bytes"},{"internalType":"int256","name":"appCreditUsedDelta","type":"int256"}],"name":"appCallbackPop","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"ctx","type":"bytes"},{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"uint256","name":"appCreditGranted","type":"uint256"},{"internalType":"int256","name":"appCreditUsed","type":"int256"},{"internalType":"contract ISuperfluidToken","name":"appCreditToken","type":"address"}],"name":"appCallbackPush","outputs":[{"internalType":"bytes","name":"appCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"operationType","type":"uint32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ISuperfluid.Operation[]","name":"operations","type":"tuple[]"}],"name":"batchCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract ISuperAgreement","name":"agreementClass","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"callAgreement","outputs":[{"internalType":"bytes","name":"returnedData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperAgreement","name":"agreementClass","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"userData","type":"bytes"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"callAgreementWithContext","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"},{"internalType":"bytes","name":"returnedData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"callAppAction","outputs":[{"internalType":"bytes","name":"returnedData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"callAppActionWithContext","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bool","name":"isTermination","type":"bool"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"callAppAfterCallback","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bool","name":"isTermination","type":"bool"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"callAppBeforeCallback","outputs":[{"internalType":"bytes","name":"cbdata","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"castrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"token","type":"address"},{"internalType":"address","name":"newAdmin","type":"address"}],"name":"changeSuperTokenAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"ctx","type":"bytes"},{"internalType":"int256","name":"appCreditUsedMore","type":"int256"}],"name":"ctxUseCredit","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"decodeCtx","outputs":[{"components":[{"internalType":"uint8","name":"appCallbackLevel","type":"uint8"},{"internalType":"uint8","name":"callType","type":"uint8"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"address","name":"msgSender","type":"address"},{"internalType":"bytes4","name":"agreementSelector","type":"bytes4"},{"internalType":"bytes","name":"userData","type":"bytes"},{"internalType":"uint256","name":"appCreditGranted","type":"uint256"},{"internalType":"uint256","name":"appCreditWantedDeprecated","type":"uint256"},{"internalType":"int256","name":"appCreditUsed","type":"int256"},{"internalType":"address","name":"appAddress","type":"address"},{"internalType":"contract ISuperfluidToken","name":"appCreditToken","type":"address"}],"internalType":"struct ISuperfluid.Context","name":"context","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"operationType","type":"uint32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ISuperfluid.Operation[]","name":"operations","type":"tuple[]"}],"name":"forwardBatchCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"agreementType","type":"bytes32"}],"name":"getAgreementClass","outputs":[{"internalType":"contract ISuperAgreement","name":"agreementClass","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"appAddr","type":"address"}],"name":"getAppCallbackLevel","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"}],"name":"getAppManifest","outputs":[{"internalType":"bool","name":"isSuperApp","type":"bool"},{"internalType":"bool","name":"isJailed","type":"bool"},{"internalType":"uint256","name":"noopMask","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCodeAddress","outputs":[{"internalType":"address","name":"codeAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getERC2771Forwarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGovernance","outputs":[{"internalType":"contract ISuperfluidGovernance","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSuperTokenFactory","outputs":[{"internalType":"contract ISuperTokenFactory","name":"factory","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSuperTokenFactoryLogic","outputs":[{"internalType":"address","name":"logic","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidGovernance","name":"gov","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperAgreement","name":"agreementClass","type":"address"}],"name":"isAgreementClassListed","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"agreementType","type":"bytes32"}],"name":"isAgreementTypeListed","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"}],"name":"isApp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"}],"name":"isAppJailed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"contract ISuperApp","name":"targetApp","type":"address"}],"name":"isCompositeAppAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"isCtxValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"ctx","type":"bytes"},{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"uint256","name":"reason","type":"uint256"}],"name":"jailApp","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bitmap","type":"uint256"}],"name":"mapAgreementClasses","outputs":[{"internalType":"contract ISuperAgreement[]","name":"agreementClasses","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"contract ISuperAgreement","name":"agreementClassLogic","type":"address"}],"name":"registerAgreementClass","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"configWord","type":"uint256"}],"name":"registerApp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"uint256","name":"configWord","type":"uint256"}],"name":"registerApp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperApp","name":"app","type":"address"},{"internalType":"uint256","name":"configWord","type":"uint256"}],"name":"registerAppByFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"configWord","type":"uint256"},{"internalType":"string","name":"registrationKey","type":"string"}],"name":"registerAppWithKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bitmap","type":"uint256"},{"internalType":"bytes32","name":"agreementType","type":"bytes32"}],"name":"removeFromAgreementClassesBitmap","outputs":[{"internalType":"uint256","name":"newBitmap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperfluidGovernance","name":"newGov","type":"address"}],"name":"replaceGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperAgreement","name":"agreementClassLogic","type":"address"}],"name":"updateAgreementClass","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"updateCode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newLogic","type":"address"}],"name":"updatePoolBeaconLogic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperTokenFactory","name":"newFactory","type":"address"}],"name":"updateSuperTokenFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"token","type":"address"},{"internalType":"address","name":"newLogicOverride","type":"address"}],"name":"updateSuperTokenLogic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"versionRecipient","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
61012060405234801561001157600080fd5b50604051615dc8380380615dc88339810160408190526100309161008c565b93151560805291151560a0526001600160401b031660c0526001600160a01b0390811660e0521661010052610100565b8051801515811461007057600080fd5b919050565b80516001600160a01b038116811461007057600080fd5b600080600080600060a086880312156100a457600080fd5b6100ad86610060565b94506100bb60208701610060565b60408701519094506001600160401b03811681146100d857600080fd5b92506100e660608701610075565b91506100f460808701610075565b90509295509295909350565b60805160a05160c05160e05161010051615c2961019f6000396000818161045401526143dd015260008181610af601526142b50152600081816104aa0152612e6401526000818161084c015281816122be0152818161279a01528181612a450152612b8c015260008181610a5e01528181610ba801528181610ec9015281816116b1015281816117ec0152818161194b0152612ab40152615c296000f3fe6080604052600436106103505760003560e01c8063768fabb0116101c6578063bced3ddc116100f7578063cd312ec411610095578063f37330521161006f578063f373305214610ac4578063f85263b914610ae4578063f9f522f414610b18578063fa6e0cfe14610b5557600080fd5b8063cd312ec414610a4c578063e8dccb7d14610a80578063f2e55caf14610aaf57600080fd5b8063bf428734116100d1578063bf428734146109bf578063c4d66de8146109df578063c56a069d146109ff578063c60944a614610a2c57600080fd5b8063bced3ddc1461096a578063bd1c448b1461098a578063bd3252c8146109aa57600080fd5b8063a5dbbbcd11610164578063b724211e1161013e578063b724211e146108ce578063ba48b5f8146108ee578063bb84cfa11461090e578063bbe4fd501461095757600080fd5b8063a5dbbbcd1461086e578063ad3915c81461088e578063b6d200de146108ae57600080fd5b80639378fa13116101a05780639378fa13146107d3578063989b0c3e146108055780639903ad38146108255780639d297e301461083a57600080fd5b8063768fabb0146107685780638ca48484146107885780638ceddd7a146107a857600080fd5b806346951954116102a057806359a291411161023e5780636b4f3335116102185780636b4f3335146106ea5780637283100c1461070a578063731aed6e1461072a57806374041e021461074857600080fd5b806359a29141146106a4578063670e77e3146106c45780636ad3ca7d146106d757600080fd5b806352d1902d1161027a57806352d1902d1461060757806354fbc4931461064457806357121e0c14610664578063572b6c051461068457600080fd5b806346951954146105a7578063486ff0cd146105c757806350d75d25146105f257600080fd5b80632ecfbda21161030d57806339255d5b116102e757806339255d5b146104e45780633ca3ad4e146105045780633f6c923a1461054c5780634329d2931461057957600080fd5b80632ecfbda2146104455780632f89bf891461047857806333d608f11461049857600080fd5b806306cecba8146103555780630c5650751461037757806315a024e1146103975780631e6d0a84146103b75780631e855cf3146103ed578063289b3c0d1461040d575b600080fd5b34801561036157600080fd5b50610375610370366004614a41565b610b75565b005b34801561038357600080fd5b50610375610392366004614a65565b610d4c565b3480156103a357600080fd5b506103756103b2366004614a41565b610ddc565b3480156103c357600080fd5b506103d76103d2366004614af4565b61102c565b6040516103e49190614bdc565b60405180910390f35b3480156103f957600080fd5b506103d7610408366004614cb2565b611278565b34801561041957600080fd5b506000546201000090046001600160a01b03165b6040516001600160a01b0390911681526020016103e4565b34801561045157600080fd5b507f000000000000000000000000000000000000000000000000000000000000000061042d565b34801561048457600080fd5b50610375610493366004614a41565b611290565b3480156104a457600080fd5b506104cc7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160401b0390911681526020016103e4565b3480156104f057600080fd5b506103d76104ff366004614d01565b61144e565b34801561051057600080fd5b5061053c61051f366004614a41565b6001600160a01b0316600090815260046020526040902054151590565b60405190151581526020016103e4565b34801561055857600080fd5b5061056c610567366004614d7a565b611464565b6040516103e49190614dae565b34801561058557600080fd5b50610599610594366004614e8d565b611475565b6040516103e4929190614f43565b3480156105b357600080fd5b506103756105c2366004614a41565b61167e565b3480156105d357600080fd5b50604080518082019091526002815261763160f01b60208201526103d7565b3480156105fe57600080fd5b5061042d61177a565b34801561061357600080fd5b507fcd355cae2c435f8c5e0c626c4691d22fd85aa7422a424c6f0bced6e64c7aba745b6040519081526020016103e4565b34801561065057600080fd5b5061037561065f366004614a41565b6117a9565b34801561067057600080fd5b5061037561067f366004614a41565b611a2c565b34801561069057600080fd5b5061053c61069f366004614a41565b611afa565b3480156106b057600080fd5b506103d76106bf366004614f68565b611b84565b6103756106d2366004614fb3565b611c66565b6103756106e5366004614fb3565b611c7c565b3480156106f657600080fd5b5061053c610705366004614a41565b611c87565b34801561071657600080fd5b50610375610725366004614a41565b611cab565b34801561073657600080fd5b506003546001600160a01b031661042d565b34801561075457600080fd5b506103d7610763366004614af4565b611d53565b34801561077457600080fd5b506103d7610783366004615028565b611ea2565b34801561079457600080fd5b5061053c6107a3366004614a41565b61203e565b3480156107b457600080fd5b506107be61010081565b60405163ffffffff90911681526020016103e4565b3480156107df57600080fd5b506107f36107ee366004614a41565b612103565b60405160ff90911681526020016103e4565b34801561081157600080fd5b506103d7610820366004614f68565b612124565b34801561083157600080fd5b506103756121b7565b34801561084657600080fd5b5061053c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561087a57600080fd5b506106366108893660046150a3565b612272565b34801561089a57600080fd5b506103756108a93660046150c5565b6122bc565b3480156108ba57600080fd5b5061042d6108c93660046150c5565b612310565b3480156108da57600080fd5b506103d76108e93660046150de565b612377565b3480156108fa57600080fd5b506103d761090936600461513a565b612438565b34801561091a57600080fd5b5061053c610929366004614a65565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561096357600080fd5b5042610636565b34801561097657600080fd5b506106366109853660046150a3565b61274f565b34801561099657600080fd5b506103756109a53660046151c0565b612798565b3480156109b657600080fd5b50610636600181565b3480156109cb57600080fd5b5061053c6109da36600461520b565b61280e565b3480156109eb57600080fd5b506103756109fa366004614a41565b61284f565b348015610a0b57600080fd5b50610a1f610a1a3660046150c5565b612933565b6040516103e4919061524c565b348015610a3857600080fd5b50610375610a47366004615298565b612a18565b348015610a5857600080fd5b5061053c7f000000000000000000000000000000000000000000000000000000000000000081565b348015610a8c57600080fd5b5061053c610a9b3660046150c5565b600090815260026020526040902054151590565b348015610abb57600080fd5b5061042d612a97565b348015610ad057600080fd5b50610375610adf366004615298565b612b5f565b348015610af057600080fd5b5061042d7f000000000000000000000000000000000000000000000000000000000000000081565b348015610b2457600080fd5b50610b38610b33366004614a41565b612c6a565b6040805193151584529115156020840152908201526060016103e4565b348015610b6157600080fd5b50610375610b70366004614a65565b612cb9565b6000546201000090046001600160a01b03163314610ba6576040516362e9152760e11b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000015610be5576040516314f72c9f60e01b815260040160405180910390fd5b6000816001600160a01b0316637730599e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4991906152c4565b600081815260026020526040812054919250819003610c7b57604051630e4f4df560e11b815260040160405180910390fd5b60006001610c8981846152f3565b81548110610c9957610c99615306565b6000918252602090912001546040516311a5465560e21b81526001600160a01b03868116600483015290911691508190634695195490602401600060405180830381600087803b158015610cec57600080fd5b505af1158015610d00573d6000803e3d6000fd5b5050604080518681526001600160a01b03881660208201527f9279aa773f2b588996032d8de89911555039f28b13a11a7c17074330bc082d9a935001905060405180910390a150505050565b6000546201000090046001600160a01b03163314610d7d576040516362e9152760e11b815260040160405180910390fd5b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f28397090602401600060405180830381600087803b158015610dc057600080fd5b505af1158015610dd4573d6000803e3d6000fd5b505050505050565b6000546201000090046001600160a01b03163314610e0d576040516362e9152760e11b815260040160405180910390fd5b6000816001600160a01b0316637730599e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7191906152c4565b60008181526002602052604090205490915015610ea157604051631b93bb7560e31b815260040160405180910390fd5b60015461010011610ec557604051630f85034f60e31b815260040160405180910390fd5b60007f0000000000000000000000000000000000000000000000000000000000000000610f7f576000604051610efa906149c4565b604051809103906000f080158015610f16573d6000803e3d6000fd5b50604051634a0687ef60e01b81526001600160a01b03868116600483015291925090821690634a0687ef90602401600060405180830381600087803b158015610f5e57600080fd5b505af1158015610f72573d6000803e3d6000fd5b5050505080915050610f82565b50815b6001805480820182557fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0384166001600160a01b0319909116179055546000838152600260205260409081902091909155517f878135063a6cfb3bc333e534b1fdc83f4f12221cad6705c31c0567048a8bd3d19061101f90849086909182526001600160a01b0316602082015260400190565b60405180910390a1505050565b60606110373361203e565b6110545760405163619c535960e01b815260040160405180910390fd5b82828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506110969250839150612e149050565b6110a2576110a261531c565b60008061111c8a6000898c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c9081908401838280828437600092019190915250612e3492505050565b9150915081156112315761112f81612efb565b156111c957808060200190518101906111489190615377565b935061115384612e14565b6111c4578661117d5760405163a85ba64f60e01b8152601460048201526024015b60405180910390fd5b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509296506111c492508c915060149050612f4f565b61126b565b866111ea5760405163a85ba64f60e01b815260166004820152602401611174565b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509296506111c492508c915060169050612f4f565b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509296505050505b5050509695505050505050565b60606112873384600085612fd0565b90505b92915050565b6000546201000090046001600160a01b031633146112c1576040516362e9152760e11b815260040160405180910390fd5b604051635b69006f60e11b81527fdfd8ece9bfbcb8c5c540edb935641f63d67686490a1ab97f000288759f30a9466004820152600090309063b6d200de90602401602060405180830381865afa15801561131f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134391906153ab565b90506000816001600160a01b0316635437dd976040518163ffffffff1660e01b8152600401602060405180830381865afa158015611385573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113a991906153ab565b604051631b2ce7f360e11b81526001600160a01b03858116600483015291925090821690633659cfe690602401600060405180830381600087803b1580156113f057600080fd5b505af1158015611404573d6000803e3d6000fd5b50506040516001600160a01b038681168252841692507f052cea8931962dd445ef48b0b998d3056bd0705f437087d60fe3c46a3fa09e1f91506020015b60405180910390a2505050565b606061145c3385858561320d565b949350505050565b61146c6149d1565b61128a8261331e565b60608083838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506114ba9250839150612e149050565b6114da5760405163a85ba64f60e01b815260146004820152602401611174565b896114e48161203e565b6115015760405163619c535960e01b815260040160405180910390fd5b600061154287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061146492505050565b6101208101519091506001600160a01b031633146115735760405163066875e160e11b815260040160405180910390fd5b60608101805133909152604080516020601f8c018190048102820181019092528a8152908b908b908190840183828082843760009201919091525050505060a08301526115bf826133e9565b955060006116058e8e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525092508c915061351d9050565b96509050801561166457858060200190518101906116239190615377565b965061162e87612e14565b61163a5761163a61531c565b61164387611464565b6001600160a01b0383166060820152925061165d836133e9565b965061166d565b61166d866135d8565b505050505097509795505050505050565b6000546201000090046001600160a01b031633146116af576040516362e9152760e11b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000156116ee576040516314f72c9f60e01b815260040160405180910390fd5b806001600160a01b031663cd312ec46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561172c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175091906153c8565b1561176e5760405163474e764160e01b815260040160405180910390fd5b611777816136e3565b50565b60006117a47f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b905090565b6000546201000090046001600160a01b031633146117da576040516362e9152760e11b815260040160405180910390fd5b6003546001600160a01b0316611949577f00000000000000000000000000000000000000000000000000000000000000006118c057600060405161181d906149c4565b604051809103906000f080158015611839573d6000803e3d6000fd5b50604051634a0687ef60e01b81526001600160a01b03848116600483015291925090821690634a0687ef90602401600060405180830381600087803b15801561188157600080fd5b505af1158015611895573d6000803e3d6000fd5b5050600380546001600160a01b0319166001600160a01b039490941693909317909255506118dc9050565b600380546001600160a01b0319166001600160a01b0383161790555b600360009054906101000a90046001600160a01b03166001600160a01b0316638129fc1c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561192c57600080fd5b505af1158015611940573d6000803e3d6000fd5b505050506119e8565b7f000000000000000000000000000000000000000000000000000000000000000015611988576040516314f72c9f60e01b815260040160405180910390fd5b6003546040516311a5465560e21b81526001600160a01b03838116600483015290911690634695195490602401600060405180830381600087803b1580156119cf57600080fd5b505af11580156119e3573d6000803e3d6000fd5b505050505b6003546040516001600160a01b0390911681527fce13a9895a1719ad4493b2ac1a9bfb36070566161abab408e7ecbe586da8d499906020015b60405180910390a150565b33600081815260046020526040902054611a59576040516302eb3f7160e61b815260040160405180910390fd5b6001600160a01b038216600090815260046020526040902054611a8f57604051634b5518af60e11b815260040160405180910390fd5b611a9882612103565b60ff16611aa482612103565b60ff1611611ac557604051630447252760e41b815260040160405180910390fd5b6001600160a01b039081166000908152600560209081526040808320949093168252929092529020805460ff19166001179055565b600080546201000090046001600160a01b03166380f70cba3083611b1d8661391d565b6040518463ffffffff1660e01b8152600401611b3b939291906153e5565b602060405180830381865afa158015611b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b7c91906152c4565b151592915050565b6060611b8f3361203e565b611bac5760405163619c535960e01b815260040160405180910390fd5b83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611bee9250839150612e149050565b611bfa57611bfa61531c565b6000611c3b86868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061146492505050565b9050838161010001818151611c509190615409565b905250611c5c816133e9565b9695505050505050565b611c78611c716139a5565b8383613a0d565b5050565b611c78338383613a0d565b6001600160a01b03811660009081526004602052604081205461800016151561128a565b6000546201000090046001600160a01b03163314611cdc576040516362e9152760e11b815260040160405180910390fd5b600054604080516001600160a01b03620100009093048316815291831660208301527f13abda02e63c790d0e2818b251282cfe5cbe0a8abd69c54bf5d2260c0907bd2e910160405180910390a1600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6060611d5e3361203e565b611d7b5760405163619c535960e01b815260040160405180910390fd5b82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611dbd9250839150612e149050565b611dc957611dc961531c565b600080611e438a6001898c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c9081908401838280828437600092019190915250612e3492505050565b91509150811561126b57611e5681612efb565b15611e765780806020019051810190611e6f9190615377565b935061126b565b86611e975760405163a85ba64f60e01b815260166004820152602401611174565b61126b8a6016612f4f565b6060611ead3361203e565b611eca5760405163619c535960e01b815260040160405180910390fd5b86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611f0c9250839150612e149050565b611f1857611f1861531c565b6000611f5989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061146492505050565b9050611f8081606001516001600160a01b0316600090815260046020526040902054151590565b8015611f9457506001816000015160ff1610155b15611fe75760608101516001600160a01b039081166000908152600560209081526040808320938b168352929052205460ff16611fe75760405163a85ba64f60e01b8152601e6004820152602401611174565b805181611ff382615431565b60ff169052506003602082015260c0810186905261010081018590526001600160a01b038088166101208301528416610140820152612031816133e9565b9998505050505050505050565b600080826001600160a01b0316637730599e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561207f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120a391906152c4565b600081815260026020526040902054909150801580159061145c57506001600160a01b03841660016120d581846152f3565b815481106120e5576120e5615306565b6000918252602090912001546001600160a01b031614949350505050565b6001600160a01b03811660009081526004602052604081205460ff1661128a565b606061212f3361203e565b61214c5760405163619c535960e01b815260040160405180910390fd5b600061218d85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061146492505050565b90508281610100018181516121a29190615409565b9052506121ae816133e9565b95945050505050565b600054610100900460ff16158080156121d75750600054600160ff909116105b806121f15750303b1580156121f1575060005460ff166001145b61220d5760405162461bcd60e51b815260040161117490615450565b6000805460ff191660011790558015612230576000805461ff0019166101001790555b8015611777576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611a21565b6000818152600260205260408120548082036122a157604051630e4f4df560e11b815260040160405180910390fd5b6122ac6001826152f3565b6001901b19841691505092915050565b7f00000000000000000000000000000000000000000000000000000000000000001561230657612306604051806040016040528060028152602001616b3160f01b815250326144f6565b611777338261459f565b60008181526002602052604081205480820361233f57604051630e4f4df560e11b815260040160405180910390fd5b600161234b81836152f3565b8154811061235b5761235b615306565b6000918252602090912001546001600160a01b03169392505050565b60606123823361203e565b61239f5760405163619c535960e01b815260040160405180910390fd5b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506123e19250839150612e149050565b6123ed576123ed61531c565b6123f78484612f4f565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929998505050505050505050565b606082828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061247c9250839150612e149050565b61249c5760405163a85ba64f60e01b815260146004820152602401611174565b6001600160a01b03871660009081526004602052604081205488918190036124d75760405163163cbe4360e01b815260040160405180910390fd5b6180008116156124f957604051628e12d960e21b815260040160405180910390fd5b87878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250925061253a915083905061466e565b90506001600160e01b031981166330d9c91560e01b148061256b57506001600160e01b0319811663d86ed3e560e01b145b8061258657506001600160e01b03198116630221347d60e61b145b806125a157506001600160e01b0319811663230dbd2960e01b145b806125bc57506001600160e01b03198116635f9e7d7760e01b145b806125d757506001600160e01b031981166353c11f9960e01b145b156125f5576040516377a14afb60e11b815260040160405180910390fd5b600061263689898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061146492505050565b6101208101519091506001600160a01b03163314612667576040516311cfdef560e21b815260040160405180910390fd5b6060810180513390915261267a826133e9565b97506000806126c18f8f8f8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525092508f915061351d9050565b91509150811561273457808060200190518101906126df9190615377565b99506126ea8a612e14565b61270a5760405163a85ba64f60e01b815260146004820152602401611174565b6127138a611464565b6001600160a01b0384166060820152935061272d846133e9565b995061273d565b61273d816135d8565b50505050505050505095945050505050565b60008181526002602052604081205480820361277e57604051630e4f4df560e11b815260040160405180910390fd5b6127896001826152f3565b6001901b841791505092915050565b7f0000000000000000000000000000000000000000000000000000000000000000156127ff576127ff82828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152503292506144f6915050565b612809338461459f565b505050565b600061128783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612e1492505050565b600054610100900460ff161580801561286f5750600054600160ff909116105b806128895750303b158015612889575060005460ff166001145b6128a55760405162461bcd60e51b815260040161117490615450565b6000805460ff1916600117905580156128c8576000805461ff0019166101001790555b6000805462010000600160b01b031916620100006001600160a01b038516021790558015611c78576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b60606000806001805490506001600160401b0381111561295557612955614bef565b60405190808252806020026020018201604052801561297e578160200160208202803683370190505b50925060009050600091505b600154821015612a10576001821b841615612a0557600182815481106129b2576129b2615306565b6000918252602090912001546001600160a01b031683826129d28161549e565b9350815181106129e4576129e4615306565b60200260200101906001600160a01b031690816001600160a01b0316815250505b81600101915061298a565b825250919050565b816001600160a01b03163b600003612a435760405163353dacc360e21b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000015612a8d57612a8d604051806040016040528060028152602001616b3160f01b815250336144f6565b611c78828261459f565b6003546000906001600160a01b0316612ab257612ab261531c565b7f000000000000000000000000000000000000000000000000000000000000000015612ae857506003546001600160a01b031690565b600360009054906101000a90046001600160a01b03166001600160a01b03166350d75d256040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b3b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a491906153ab565b816001600160a01b03163b600003612b8a5760405163353dacc360e21b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000015612a8d576000612bbb336146ca565b6000805460405163407b865d60e11b81529293509091620100009091046001600160a01b0316906380f70cba90612bfa903090859087906004016153e5565b602060405180830381865afa158015612c17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c3b91906152c4565b600114905080612c5e57604051630b56455f60e41b815260040160405180910390fd5b5050611c78828261459f565b6001600160a01b038116600090815260046020908152604080832081519283019091525480825215801592918291612cb157805161800081161515935064ff000000001691505b509193909250565b6000546201000090046001600160a01b03163314612cea576040516362e9152760e11b815260040160405180910390fd5b60006001600160a01b038216612d7657600360009054906101000a90046001600160a01b03166001600160a01b0316639470a5b26040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d7191906153ab565b612d78565b815b6040516311a5465560e21b81526001600160a01b03808316600483015291925090841690634695195490602401600060405180830381600087803b158015612dbf57600080fd5b505af1158015612dd3573d6000803e3d6000fd5b50506040516001600160a01b038481168252861692507f840acbd291b38534819f47f875839277e502f40e1c7bfea2c5fc2c8017442cd39150602001611441565b6000815160001415801561128a5750600654825160208401201492915050565b600060606001600160a01b038716612e4e57612e4e61531c565b612e588484614744565b93506001600160401b037f000000000000000000000000000000000000000000000000000000000000000016600087612e9b57612e968987846147fb565b612ea6565b612ea689878461488c565b919550909350905083612eef5780612ed65786612ecb57612ec6836135d8565b612eef565b612ec689600a612f4f565b604051636a7aea4b60e11b815260040160405180910390fd5b50509550959350505050565b6000604082511015612f0f57506000919050565b602082810151906000908214612f29575060009392505050565b506040830151612f38816148eb565b612f439060406154b7565b84511492505050919050565b6001600160a01b038216600090815260046020526040812054618000169003611c78576001600160a01b038216600081815260046020526040908190208054618000179055517fbe3aa33bd245135e4e26b223d79d14ea479a47bff09f2b03c53838af1edbb14b90612fc49084815260200190565b60405180910390a25050565b60065460609015612ff75760405163a85ba64f60e01b815260156004820152602401611174565b6001600160a01b03841660009081526004602052604081205485918190036130325760405163163cbe4360e01b815260040160405180910390fd5b61800081161561305457604051628e12d960e21b815260040160405180910390fd5b8360006130608261466e565b90506001600160e01b031981166330d9c91560e01b148061309157506001600160e01b0319811663d86ed3e560e01b145b806130ac57506001600160e01b03198116630221347d60e61b145b806130c757506001600160e01b0319811663230dbd2960e01b145b806130e257506001600160e01b03198116635f9e7d7760e01b145b806130fd57506001600160e01b031981166353c11f9960e01b145b1561311b576040516377a14afb60e11b815260040160405180910390fd5b60408051610160810182526000808252600260208084019190915242838501526001600160a01b03808e16606085015260808401839052845191820190945281815260a083015260c0820181905260e082018190526101008201819052918a166101208201526101408101829052613192906133e9565b905060006131a28a898b8561351d565b9750905080156131f057868060200190518101906131c09190615377565b91506131cb82612e14565b6131eb5760405163a85ba64f60e01b815260146004820152602401611174565b6131f9565b6131f9876135d8565b505060006006555092979650505050505050565b600654606090156132345760405163a85ba64f60e01b815260156004820152602401611174565b8361323e8161203e565b61325b5760405163619c535960e01b815260040160405180910390fd5b60006132668561466e565b60408051610160810182526000808252600160208301529293506132e99181014281526020018a6001600160a01b03168152602001846001600160e01b031916815260200187815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b03168152506133e9565b905060006132fa888860008561351d565b955090508061330c5761330c856135d8565b50506000600655509095945050505050565b6133266149d1565b6060808380602001905181019061333d91906154ca565b8151919350915060009061335a9084016020908101908501615527565b60a08901526001600160e01b03191660808801526001600160a01b031660608701526040860152602081811c600f168187015260ff90911685528251600092506133ab9190840181019084016155ac565b6001600160a01b03908116610140890152166101208701526101008601526001600160801b03811660c086015260801c60e085015250919392505050565b60606001826000015160ff1611156134175760405163a85ba64f60e01b815260286004820152602401611174565b815160208084015160009260ff1664ff000000009190921b16179050600060806134448560e00151614924565b6001600160801b0316901b61345c8560c00151614924565b6001600160801b0316179050818460400151856060015186608001518760a001516040516020016134919594939291906155f8565b60408051601f1981840301815282825261010087015161012088015161014089015160208601879052938501919091526001600160a01b03908116606085015290911660808301529060a00160408051601f19818403018152908290526134fb9291602001614f43565b60408051601f1981840301815291905280516020820120600655949350505050565b600060606001600160a01b0386166135375761353761531c565b6135418584614744565b9450856001600160a01b0316848660405161355c9190615644565b60006040518083038185875af1925050503d8060008114613599576040519150601f19603f3d011682016040523d82523d6000602084013e61359e565b606091505b50909250905081156135cf5780516000036135cf5760405163a85ba64f60e01b815260166004820152602401611174565b94509492505050565b60048151101561362a5760405162461bcd60e51b815260206004820152601a60248201527f43616c6c5574696c733a207461726765742072657665727428290000000000006044820152606401611174565b602081015163b1b7848f60e01b6001600160e01b03198216016136da5760408051808201825260208082527f43616c6c5574696c733a207461726765742070616e69636b65643a2030785f5f90820190815260248501517f43616c6c5574696c733a207461726765742070616e69636b65643a2030780000600482811c600f908116603090810160081b918516011791909117909252925162461bcd60e51b815291929161117491849101614bdc565b81518060208401fd5b600061370d7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6001600160a01b0316036137635760405162461bcd60e51b815260206004820152601d60248201527f5555505350726f786961626c653a206e6f742075706772616461626c650000006044820152606401611174565b806001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c591906152c4565b7fcd355cae2c435f8c5e0c626c4691d22fd85aa7422a424c6f0bced6e64c7aba741461383f5760405162461bcd60e51b815260206004820152602360248201527f5555505350726f786961626c653a206e6f7420636f6d70617469626c65206c6f60448201526267696360e81b6064820152608401611174565b6001600160a01b03811630036138975760405162461bcd60e51b815260206004820152601960248201527f5555505350726f786961626c653a2070726f7879206c6f6f70000000000000006044820152606401611174565b6138bf817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b7fe011bc04c286c344a8fcbb8de77f953da762c3e25d8cdea984147fc4168a5dcc7fcd355cae2c435f8c5e0c626c4691d22fd85aa7422a424c6f0bced6e64c7aba74604080519182526001600160a01b038416602083015201611a21565b6040805160208101829052603260608201527f6f72672e7375706572666c7569642d66696e616e63652e7375706572666c756960808201527132173a393ab9ba32b22337b93bb0b93232b960711b60a08201526001600160a01b0383169181019190915260009060c0015b604051602081830303815290604052805190602001209050919050565b6000601836108015906139bc57506139bc33611afa565b613a005760405162461bcd60e51b81526020600482015260156024820152742737ba103a393ab9ba32b2103337b93bb0b93232b960591b6044820152606401611174565b5060131936013560601c90565b60005b818110156144b4576000838383818110613a2c57613a2c615306565b9050602002810190613a3e9190615660565b613a4c906020810190615676565b905060001963ffffffff821601613b4057600080858585818110613a7257613a72615306565b9050602002810190613a849190615660565b613a9290604081019061569c565b810190613a9f9190615298565b91509150858585818110613ab557613ab5615306565b9050602002810190613ac79190615660565b613ad8906040810190602001614a41565b6001600160a01b03166362aa52878884846040518463ffffffff1660e01b8152600401613b07939291906153e5565b600060405180830381600087803b158015613b2157600080fd5b505af1158015613b35573d6000803e3d6000fd5b5050505050506144ab565b60011963ffffffff821601613c4b576000806000868686818110613b6657613b66615306565b9050602002810190613b789190615660565b613b8690604081019061569c565b810190613b9391906156e2565b925092509250868686818110613bab57613bab615306565b9050602002810190613bbd9190615660565b613bce906040810190602001614a41565b604051630b682aeb60e11b81526001600160a01b038a81166004830152858116602483015284811660448301526064820184905291909116906316d055d6906084015b600060405180830381600087803b158015613c2b57600080fd5b505af1158015613c3f573d6000803e3d6000fd5b505050505050506144ab565b60021963ffffffff821601613d0a576000806000868686818110613c7157613c71615306565b9050602002810190613c839190615660565b613c9190604081019061569c565b810190613c9e9190615723565b925092509250868686818110613cb657613cb6615306565b9050602002810190613cc89190615660565b613cd9906040810190602001614a41565b6001600160a01b031663ca0c1e7f898585856040518563ffffffff1660e01b8152600401613c119493929190615765565b60031963ffffffff821601613dc357600080858585818110613d2e57613d2e615306565b9050602002810190613d409190615660565b613d4e90604081019061569c565b810190613d5b9190615298565b91509150858585818110613d7157613d71615306565b9050602002810190613d839190615660565b613d94906040810190602001614a41565b6001600160a01b0316634b2763b38884846040518463ffffffff1660e01b8152600401613b07939291906153e5565b60041963ffffffff821601613e7c57600080858585818110613de757613de7615306565b9050602002810190613df99190615660565b613e0790604081019061569c565b810190613e149190615298565b91509150858585818110613e2a57613e2a615306565b9050602002810190613e3c9190615660565b613e4d906040810190602001614a41565b6001600160a01b031663c780fd828884846040518463ffffffff1660e01b8152600401613b07939291906153e5565b60641963ffffffff821601613f7157838383818110613e9d57613e9d615306565b9050602002810190613eaf9190615660565b613ec0906040810190602001614a41565b6001600160a01b031663ca78946486868686818110613ee157613ee1615306565b9050602002810190613ef39190615660565b613f0190604081019061569c565b810190613f0e91906150c5565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015613f5457600080fd5b505af1158015613f68573d6000803e3d6000fd5b505050506144ab565b60651963ffffffff821601613fd657838383818110613f9257613f92615306565b9050602002810190613fa49190615660565b613fb5906040810190602001614a41565b6001600160a01b031663245887fc86868686818110613ee157613ee1615306565b60661963ffffffff82160161408f57600080858585818110613ffa57613ffa615306565b905060200281019061400c9190615660565b61401a90604081019061569c565b8101906140279190615298565b9150915085858581811061403d5761403d615306565b905060200281019061404f9190615660565b614060906040810190602001614a41565b6001600160a01b0316631ae88ffc8884846040518463ffffffff1660e01b8152600401613b07939291906153e5565b60671963ffffffff821601614148576000808585858181106140b3576140b3615306565b90506020028101906140c59190615660565b6140d390604081019061569c565b8101906140e09190615298565b915091508585858181106140f6576140f6615306565b90506020028101906141089190615660565b614119906040810190602001614a41565b6001600160a01b03166347ba7ad18884846040518463ffffffff1660e01b8152600401613b07939291906153e5565b60c81963ffffffff8216016141e55760008085858581811061416c5761416c615306565b905060200281019061417e9190615660565b61418c90604081019061569c565b8101906141999190615798565b915091506141dd878787878181106141b3576141b3615306565b90506020028101906141c59190615660565b6141d6906040810190602001614a41565b848461320d565b5050506144ab565b60c91963ffffffff8216016142a05761429a8585858581811061420a5761420a615306565b905060200281019061421c9190615660565b61422d906040810190602001614a41565b4787878781811061424057614240615306565b90506020028101906142529190615660565b61426090604081019061569c565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612fd092505050565b506144ab565b61012c1963ffffffff8216016143c8576000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166322bee494478888888181106142f5576142f5615306565b90506020028101906143079190615660565b614318906040810190602001614a41565b89898981811061432a5761432a615306565b905060200281019061433c9190615660565b61434a90604081019061569c565b6040518563ffffffff1660e01b815260040161436893929190615812565b60006040518083038185885af1158015614386573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526143af9190810190615837565b91509150816143c1576143c1816135d8565b50506144ab565b61012d1963ffffffff821601614492576000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663177ec5944788888881811061441d5761441d615306565b905060200281019061442f9190615660565b614440906040810190602001614a41565b8a8a8a8a81811061445357614453615306565b90506020028101906144659190615660565b61447390604081019061569c565b6040518663ffffffff1660e01b81526004016143689493929190615871565b60405163b477011560e01b815260040160405180910390fd5b50600101613a10565b504715612809576040516001600160a01b038416904780156108fc02916000818181858888f193505050501580156144f0573d6000803e3d6000fd5b50505050565b60006145028284614991565b6000805460405163407b865d60e11b81529293504292620100009091046001600160a01b0316916380f70cba9161453f91309187906004016153e5565b602060405180830381865afa15801561455c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061458091906152c4565b101561280957604051630b56455f60e41b815260040160405180910390fd5b64ff000080ff1981161515806145b6575060ff8116155b806145c45750618000811615155b156145e257604051633d3200a960e21b815260040160405180910390fd5b6001600160a01b03821660009081526004602052604090205415614619576040516301b0a93560e01b815260040160405180910390fd5b60408051602080820183528382526001600160a01b038516600081815260049092528382209251909255915190917f0d540ad8f39e07d19909687352b9fa017405d93c91a6760981fbae9cf28bfef791a25050565b60006004825110156146c25760405162461bcd60e51b815260206004820152601b60248201527f43616c6c5574696c733a20696e76616c69642063616c6c4461746100000000006044820152606401611174565b506020015190565b6040805160208101829052603960608201527f6f72672e7375706572666c7569642d66696e616e63652e7375706572666c756960808201527f642e61707057686974654c697374696e672e666163746f72790000000000000060a08201526001600160a01b0383169181019190915260009060c001613988565b81518083015160609190801561476d576040516367e9985b60e01b815260040160405180910390fd5b50601f1981018452825184908481614784816148eb565b61478e91906152f3565b6001600160401b038111156147a5576147a5614bef565b6040519080825280601f01601f1916602001820160405280156147cf576020820181803683370190505b506040516020016147e3949392919061589e565b60405160208183030381529060405291505092915050565b600080606060005a9050866001600160a01b0316858760405161481e9190615644565b60006040518083038160008787f1925050503d806000811461485c576040519150601f19603f3d011682016040523d82523d6000602084013e614861565b606091505b50909450915083614882576148776040826158ec565b5a1161488257600192505b5093509350939050565b600080606060005a9050866001600160a01b031685876040516148af9190615644565b6000604051808303818686fa925050503d806000811461485c576040519150601f19603f3d011682016040523d82523d6000602084013e614861565b60008082601f16116148fe576000614901565b60015b60ff1661490f6020846158ec565b61491991906154b7565b61128a90602061590e565b60006001600160801b0382111561498d5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401611174565b5090565b600082826040516020016149a6929190615925565b60405160208183030381529060405280519060200120905092915050565b610249806159ab83390190565b604080516101608101825260008082526020820181905291810182905260608082018390526080820183905260a082015260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b6001600160a01b038116811461177757600080fd5b600060208284031215614a5357600080fd5b8135614a5e81614a2c565b9392505050565b60008060408385031215614a7857600080fd5b8235614a8381614a2c565b91506020830135614a9381614a2c565b809150509250929050565b60008083601f840112614ab057600080fd5b5081356001600160401b03811115614ac757600080fd5b602083019150836020828501011115614adf57600080fd5b9250929050565b801515811461177757600080fd5b60008060008060008060808789031215614b0d57600080fd5b8635614b1881614a2c565b955060208701356001600160401b03811115614b3357600080fd5b614b3f89828a01614a9e565b9096509450506040870135614b5381614ae6565b925060608701356001600160401b03811115614b6e57600080fd5b614b7a89828a01614a9e565b979a9699509497509295939492505050565b60005b83811015614ba7578181015183820152602001614b8f565b50506000910152565b60008151808452614bc8816020860160208601614b8c565b601f01601f19169290920160200192915050565b6020815260006112876020830184614bb0565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614c2d57614c2d614bef565b604052919050565b60006001600160401b03821115614c4e57614c4e614bef565b50601f01601f191660200190565b600082601f830112614c6d57600080fd5b8135614c80614c7b82614c35565b614c05565b818152846020838601011115614c9557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614cc557600080fd5b8235614cd081614a2c565b915060208301356001600160401b03811115614ceb57600080fd5b614cf785828601614c5c565b9150509250929050565b600080600060608486031215614d1657600080fd5b8335614d2181614a2c565b925060208401356001600160401b03811115614d3c57600080fd5b614d4886828701614c5c565b92505060408401356001600160401b03811115614d6457600080fd5b614d7086828701614c5c565b9150509250925092565b600060208284031215614d8c57600080fd5b81356001600160401b03811115614da257600080fd5b61145c84828501614c5c565b60208152614dc260208201835160ff169052565b60006020830151614dd8604084018260ff169052565b50604083015160608301526060830151614dfd60808401826001600160a01b03169052565b5060808301516001600160e01b0319811660a08401525060a083015161016060c0840152614e2f610180840182614bb0565b905060c084015160e084015260e0840151610100840152610100840151610120840152610120840151614e6e6101408501826001600160a01b03169052565b506101408401516001600160a01b038116610160850152509392505050565b60008060008060008060006080888a031215614ea857600080fd5b8735614eb381614a2c565b965060208801356001600160401b03811115614ece57600080fd5b614eda8a828b01614a9e565b90975095505060408801356001600160401b03811115614ef957600080fd5b614f058a828b01614a9e565b90955093505060608801356001600160401b03811115614f2457600080fd5b614f308a828b01614a9e565b989b979a50959850939692959293505050565b604081526000614f566040830185614bb0565b82810360208401526121ae8185614bb0565b600080600060408486031215614f7d57600080fd5b83356001600160401b03811115614f9357600080fd5b614f9f86828701614a9e565b909790965060209590950135949350505050565b60008060208385031215614fc657600080fd5b82356001600160401b03811115614fdc57600080fd5b8301601f81018513614fed57600080fd5b80356001600160401b0381111561500357600080fd5b8560208260051b840101111561501857600080fd5b6020919091019590945092505050565b60008060008060008060a0878903121561504157600080fd5b86356001600160401b0381111561505757600080fd5b61506389828a01614a9e565b909750955050602087013561507781614a2c565b93506040870135925060608701359150608087013561509581614a2c565b809150509295509295509295565b600080604083850312156150b657600080fd5b50508035926020909101359150565b6000602082840312156150d757600080fd5b5035919050565b600080600080606085870312156150f457600080fd5b84356001600160401b0381111561510a57600080fd5b61511687828801614a9e565b909550935050602085013561512a81614a2c565b9396929550929360400135925050565b60008060008060006060868803121561515257600080fd5b853561515d81614a2c565b945060208601356001600160401b0381111561517857600080fd5b61518488828901614a9e565b90955093505060408601356001600160401b038111156151a357600080fd5b6151af88828901614a9e565b969995985093965092949392505050565b6000806000604084860312156151d557600080fd5b8335925060208401356001600160401b038111156151f257600080fd5b6151fe86828701614a9e565b9497909650939450505050565b6000806020838503121561521e57600080fd5b82356001600160401b0381111561523457600080fd5b61524085828601614a9e565b90969095509350505050565b602080825282518282018190526000918401906040840190835b8181101561528d5783516001600160a01b0316835260209384019390920191600101615266565b509095945050505050565b600080604083850312156152ab57600080fd5b82356152b681614a2c565b946020939093013593505050565b6000602082840312156152d657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561128a5761128a6152dd565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b600082601f83011261534357600080fd5b8151615351614c7b82614c35565b81815284602083860101111561536657600080fd5b61145c826020830160208701614b8c565b60006020828403121561538957600080fd5b81516001600160401b0381111561539f57600080fd5b61145c84828501615332565b6000602082840312156153bd57600080fd5b8151614a5e81614a2c565b6000602082840312156153da57600080fd5b8151614a5e81614ae6565b6001600160a01b039384168152919092166020820152604081019190915260600190565b8082018281126000831280158216821582161715615429576154296152dd565b505092915050565b600060ff821660ff8103615447576154476152dd565b60010192915050565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6000600182016154b0576154b06152dd565b5060010190565b8082018082111561128a5761128a6152dd565b600080604083850312156154dd57600080fd5b82516001600160401b038111156154f357600080fd5b6154ff85828601615332565b92505060208301516001600160401b0381111561551b57600080fd5b614cf785828601615332565b600080600080600060a0868803121561553f57600080fd5b855160208701516040880151919650945061555981614a2c565b60608701519093506001600160e01b03198116811461557757600080fd5b60808701519092506001600160401b0381111561559357600080fd5b61559f88828901615332565b9150509295509295909350565b600080600080608085870312156155c257600080fd5b84516020860151604087015191955093506155dc81614a2c565b60608601519092506155ed81614a2c565b939692955090935050565b858152602081018590526001600160a01b03841660408201526001600160e01b03198316606082015260a06080820181905260009061563990830184614bb0565b979650505050505050565b60008251615656818460208701614b8c565b9190910192915050565b60008235605e1983360301811261565657600080fd5b60006020828403121561568857600080fd5b813563ffffffff81168114614a5e57600080fd5b6000808335601e198436030181126156b357600080fd5b8301803591506001600160401b038211156156cd57600080fd5b602001915036819003821315614adf57600080fd5b6000806000606084860312156156f757600080fd5b833561570281614a2c565b9250602084013561571281614a2c565b929592945050506040919091013590565b60008060006060848603121561573857600080fd5b833561574381614a2c565b92506020840135915060408401356001600160401b03811115614d6457600080fd5b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611c5c90830184614bb0565b600080604083850312156157ab57600080fd5b82356001600160401b038111156157c157600080fd5b6157cd85828601614c5c565b92505060208301356001600160401b03811115614ceb57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b03841681526040602082018190526000906121ae90830184866157e9565b6000806040838503121561584a57600080fd5b825161585581614ae6565b60208401519092506001600160401b0381111561551b57600080fd5b6001600160a01b03858116825284166020820152606060408201819052600090611c5c90830184866157e9565b600085516158b0818460208a01614b8c565b820185815284516158c8816020808501908901614b8c565b84519101906158de816020808501908801614b8c565b016020019695505050505050565b60008261590957634e487b7160e01b600052601260045260246000fd5b500490565b808202811582820484141761128a5761128a6152dd565b60608152604160608201527f6f72672e7375706572666c7569642d66696e616e63652e7375706572666c756960808201527f642e61707057686974654c697374696e672e726567697374726174696f6e4b6560a0820152607960f81b60c082015260018060a01b038316602082015260e06040820152600061145c60e0830184614bb056fe6080604052348015600f57600080fd5b5061022a8061001f6000396000f3fe6080604052600436106100225760003560e01c80634a0687ef1461003957610031565b366100315761002f610059565b005b61002f610059565b34801561004557600080fd5b5061002f6100543660046101c4565b61006b565b610069610064610171565b6101a0565b565b6001600160a01b0381166100c65760405162461bcd60e51b815260206004820152601760248201527f5555505350726f78793a207a65726f206164647265737300000000000000000060448201526064015b60405180910390fd5b60006100f07f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6001600160a01b0316146101465760405162461bcd60e51b815260206004820152601e60248201527f5555505350726f78793a20616c726561647920696e697469616c697a6564000060448201526064016100bd565b61016e817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b50565b600061019b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b905090565b3660008037600080366000845af43d6000803e8080156101bf573d6000f35b3d6000fd5b6000602082840312156101d657600080fd5b81356001600160a01b03811681146101ed57600080fd5b939250505056fea2646970667358221220fae816317186d33a564ddff3a944af220df3c9025c6f9ffcae9cd4a4a7a4b19164736f6c634300081a0033a26469706673582212208425040ede939fa1e37874fcf0eb2a063642a433d225f2049dafaca1fe8cb4c564736f6c634300081a0033000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000e4e1c000000000000000000000000008ecf8ec4cec8a00d5460d3faf9f0719c80a35130000000000000000000000004ddb0f9a512933e3078a32130d92ea6e59f039cc
Deployed Bytecode
0x6080604052600436106103505760003560e01c8063768fabb0116101c6578063bced3ddc116100f7578063cd312ec411610095578063f37330521161006f578063f373305214610ac4578063f85263b914610ae4578063f9f522f414610b18578063fa6e0cfe14610b5557600080fd5b8063cd312ec414610a4c578063e8dccb7d14610a80578063f2e55caf14610aaf57600080fd5b8063bf428734116100d1578063bf428734146109bf578063c4d66de8146109df578063c56a069d146109ff578063c60944a614610a2c57600080fd5b8063bced3ddc1461096a578063bd1c448b1461098a578063bd3252c8146109aa57600080fd5b8063a5dbbbcd11610164578063b724211e1161013e578063b724211e146108ce578063ba48b5f8146108ee578063bb84cfa11461090e578063bbe4fd501461095757600080fd5b8063a5dbbbcd1461086e578063ad3915c81461088e578063b6d200de146108ae57600080fd5b80639378fa13116101a05780639378fa13146107d3578063989b0c3e146108055780639903ad38146108255780639d297e301461083a57600080fd5b8063768fabb0146107685780638ca48484146107885780638ceddd7a146107a857600080fd5b806346951954116102a057806359a291411161023e5780636b4f3335116102185780636b4f3335146106ea5780637283100c1461070a578063731aed6e1461072a57806374041e021461074857600080fd5b806359a29141146106a4578063670e77e3146106c45780636ad3ca7d146106d757600080fd5b806352d1902d1161027a57806352d1902d1461060757806354fbc4931461064457806357121e0c14610664578063572b6c051461068457600080fd5b806346951954146105a7578063486ff0cd146105c757806350d75d25146105f257600080fd5b80632ecfbda21161030d57806339255d5b116102e757806339255d5b146104e45780633ca3ad4e146105045780633f6c923a1461054c5780634329d2931461057957600080fd5b80632ecfbda2146104455780632f89bf891461047857806333d608f11461049857600080fd5b806306cecba8146103555780630c5650751461037757806315a024e1146103975780631e6d0a84146103b75780631e855cf3146103ed578063289b3c0d1461040d575b600080fd5b34801561036157600080fd5b50610375610370366004614a41565b610b75565b005b34801561038357600080fd5b50610375610392366004614a65565b610d4c565b3480156103a357600080fd5b506103756103b2366004614a41565b610ddc565b3480156103c357600080fd5b506103d76103d2366004614af4565b61102c565b6040516103e49190614bdc565b60405180910390f35b3480156103f957600080fd5b506103d7610408366004614cb2565b611278565b34801561041957600080fd5b506000546201000090046001600160a01b03165b6040516001600160a01b0390911681526020016103e4565b34801561045157600080fd5b507f0000000000000000000000004ddb0f9a512933e3078a32130d92ea6e59f039cc61042d565b34801561048457600080fd5b50610375610493366004614a41565b611290565b3480156104a457600080fd5b506104cc7f0000000000000000000000000000000000000000000000000000000000e4e1c081565b6040516001600160401b0390911681526020016103e4565b3480156104f057600080fd5b506103d76104ff366004614d01565b61144e565b34801561051057600080fd5b5061053c61051f366004614a41565b6001600160a01b0316600090815260046020526040902054151590565b60405190151581526020016103e4565b34801561055857600080fd5b5061056c610567366004614d7a565b611464565b6040516103e49190614dae565b34801561058557600080fd5b50610599610594366004614e8d565b611475565b6040516103e4929190614f43565b3480156105b357600080fd5b506103756105c2366004614a41565b61167e565b3480156105d357600080fd5b50604080518082019091526002815261763160f01b60208201526103d7565b3480156105fe57600080fd5b5061042d61177a565b34801561061357600080fd5b507fcd355cae2c435f8c5e0c626c4691d22fd85aa7422a424c6f0bced6e64c7aba745b6040519081526020016103e4565b34801561065057600080fd5b5061037561065f366004614a41565b6117a9565b34801561067057600080fd5b5061037561067f366004614a41565b611a2c565b34801561069057600080fd5b5061053c61069f366004614a41565b611afa565b3480156106b057600080fd5b506103d76106bf366004614f68565b611b84565b6103756106d2366004614fb3565b611c66565b6103756106e5366004614fb3565b611c7c565b3480156106f657600080fd5b5061053c610705366004614a41565b611c87565b34801561071657600080fd5b50610375610725366004614a41565b611cab565b34801561073657600080fd5b506003546001600160a01b031661042d565b34801561075457600080fd5b506103d7610763366004614af4565b611d53565b34801561077457600080fd5b506103d7610783366004615028565b611ea2565b34801561079457600080fd5b5061053c6107a3366004614a41565b61203e565b3480156107b457600080fd5b506107be61010081565b60405163ffffffff90911681526020016103e4565b3480156107df57600080fd5b506107f36107ee366004614a41565b612103565b60405160ff90911681526020016103e4565b34801561081157600080fd5b506103d7610820366004614f68565b612124565b34801561083157600080fd5b506103756121b7565b34801561084657600080fd5b5061053c7f000000000000000000000000000000000000000000000000000000000000000181565b34801561087a57600080fd5b506106366108893660046150a3565b612272565b34801561089a57600080fd5b506103756108a93660046150c5565b6122bc565b3480156108ba57600080fd5b5061042d6108c93660046150c5565b612310565b3480156108da57600080fd5b506103d76108e93660046150de565b612377565b3480156108fa57600080fd5b506103d761090936600461513a565b612438565b34801561091a57600080fd5b5061053c610929366004614a65565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561096357600080fd5b5042610636565b34801561097657600080fd5b506106366109853660046150a3565b61274f565b34801561099657600080fd5b506103756109a53660046151c0565b612798565b3480156109b657600080fd5b50610636600181565b3480156109cb57600080fd5b5061053c6109da36600461520b565b61280e565b3480156109eb57600080fd5b506103756109fa366004614a41565b61284f565b348015610a0b57600080fd5b50610a1f610a1a3660046150c5565b612933565b6040516103e4919061524c565b348015610a3857600080fd5b50610375610a47366004615298565b612a18565b348015610a5857600080fd5b5061053c7f000000000000000000000000000000000000000000000000000000000000000081565b348015610a8c57600080fd5b5061053c610a9b3660046150c5565b600090815260026020526040902054151590565b348015610abb57600080fd5b5061042d612a97565b348015610ad057600080fd5b50610375610adf366004615298565b612b5f565b348015610af057600080fd5b5061042d7f00000000000000000000000008ecf8ec4cec8a00d5460d3faf9f0719c80a351381565b348015610b2457600080fd5b50610b38610b33366004614a41565b612c6a565b6040805193151584529115156020840152908201526060016103e4565b348015610b6157600080fd5b50610375610b70366004614a65565b612cb9565b6000546201000090046001600160a01b03163314610ba6576040516362e9152760e11b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000015610be5576040516314f72c9f60e01b815260040160405180910390fd5b6000816001600160a01b0316637730599e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4991906152c4565b600081815260026020526040812054919250819003610c7b57604051630e4f4df560e11b815260040160405180910390fd5b60006001610c8981846152f3565b81548110610c9957610c99615306565b6000918252602090912001546040516311a5465560e21b81526001600160a01b03868116600483015290911691508190634695195490602401600060405180830381600087803b158015610cec57600080fd5b505af1158015610d00573d6000803e3d6000fd5b5050604080518681526001600160a01b03881660208201527f9279aa773f2b588996032d8de89911555039f28b13a11a7c17074330bc082d9a935001905060405180910390a150505050565b6000546201000090046001600160a01b03163314610d7d576040516362e9152760e11b815260040160405180910390fd5b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f28397090602401600060405180830381600087803b158015610dc057600080fd5b505af1158015610dd4573d6000803e3d6000fd5b505050505050565b6000546201000090046001600160a01b03163314610e0d576040516362e9152760e11b815260040160405180910390fd5b6000816001600160a01b0316637730599e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7191906152c4565b60008181526002602052604090205490915015610ea157604051631b93bb7560e31b815260040160405180910390fd5b60015461010011610ec557604051630f85034f60e31b815260040160405180910390fd5b60007f0000000000000000000000000000000000000000000000000000000000000000610f7f576000604051610efa906149c4565b604051809103906000f080158015610f16573d6000803e3d6000fd5b50604051634a0687ef60e01b81526001600160a01b03868116600483015291925090821690634a0687ef90602401600060405180830381600087803b158015610f5e57600080fd5b505af1158015610f72573d6000803e3d6000fd5b5050505080915050610f82565b50815b6001805480820182557fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0384166001600160a01b0319909116179055546000838152600260205260409081902091909155517f878135063a6cfb3bc333e534b1fdc83f4f12221cad6705c31c0567048a8bd3d19061101f90849086909182526001600160a01b0316602082015260400190565b60405180910390a1505050565b60606110373361203e565b6110545760405163619c535960e01b815260040160405180910390fd5b82828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506110969250839150612e149050565b6110a2576110a261531c565b60008061111c8a6000898c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c9081908401838280828437600092019190915250612e3492505050565b9150915081156112315761112f81612efb565b156111c957808060200190518101906111489190615377565b935061115384612e14565b6111c4578661117d5760405163a85ba64f60e01b8152601460048201526024015b60405180910390fd5b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509296506111c492508c915060149050612f4f565b61126b565b866111ea5760405163a85ba64f60e01b815260166004820152602401611174565b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509296506111c492508c915060169050612f4f565b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509296505050505b5050509695505050505050565b60606112873384600085612fd0565b90505b92915050565b6000546201000090046001600160a01b031633146112c1576040516362e9152760e11b815260040160405180910390fd5b604051635b69006f60e11b81527fdfd8ece9bfbcb8c5c540edb935641f63d67686490a1ab97f000288759f30a9466004820152600090309063b6d200de90602401602060405180830381865afa15801561131f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134391906153ab565b90506000816001600160a01b0316635437dd976040518163ffffffff1660e01b8152600401602060405180830381865afa158015611385573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113a991906153ab565b604051631b2ce7f360e11b81526001600160a01b03858116600483015291925090821690633659cfe690602401600060405180830381600087803b1580156113f057600080fd5b505af1158015611404573d6000803e3d6000fd5b50506040516001600160a01b038681168252841692507f052cea8931962dd445ef48b0b998d3056bd0705f437087d60fe3c46a3fa09e1f91506020015b60405180910390a2505050565b606061145c3385858561320d565b949350505050565b61146c6149d1565b61128a8261331e565b60608083838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506114ba9250839150612e149050565b6114da5760405163a85ba64f60e01b815260146004820152602401611174565b896114e48161203e565b6115015760405163619c535960e01b815260040160405180910390fd5b600061154287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061146492505050565b6101208101519091506001600160a01b031633146115735760405163066875e160e11b815260040160405180910390fd5b60608101805133909152604080516020601f8c018190048102820181019092528a8152908b908b908190840183828082843760009201919091525050505060a08301526115bf826133e9565b955060006116058e8e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525092508c915061351d9050565b96509050801561166457858060200190518101906116239190615377565b965061162e87612e14565b61163a5761163a61531c565b61164387611464565b6001600160a01b0383166060820152925061165d836133e9565b965061166d565b61166d866135d8565b505050505097509795505050505050565b6000546201000090046001600160a01b031633146116af576040516362e9152760e11b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000156116ee576040516314f72c9f60e01b815260040160405180910390fd5b806001600160a01b031663cd312ec46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561172c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175091906153c8565b1561176e5760405163474e764160e01b815260040160405180910390fd5b611777816136e3565b50565b60006117a47f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b905090565b6000546201000090046001600160a01b031633146117da576040516362e9152760e11b815260040160405180910390fd5b6003546001600160a01b0316611949577f00000000000000000000000000000000000000000000000000000000000000006118c057600060405161181d906149c4565b604051809103906000f080158015611839573d6000803e3d6000fd5b50604051634a0687ef60e01b81526001600160a01b03848116600483015291925090821690634a0687ef90602401600060405180830381600087803b15801561188157600080fd5b505af1158015611895573d6000803e3d6000fd5b5050600380546001600160a01b0319166001600160a01b039490941693909317909255506118dc9050565b600380546001600160a01b0319166001600160a01b0383161790555b600360009054906101000a90046001600160a01b03166001600160a01b0316638129fc1c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561192c57600080fd5b505af1158015611940573d6000803e3d6000fd5b505050506119e8565b7f000000000000000000000000000000000000000000000000000000000000000015611988576040516314f72c9f60e01b815260040160405180910390fd5b6003546040516311a5465560e21b81526001600160a01b03838116600483015290911690634695195490602401600060405180830381600087803b1580156119cf57600080fd5b505af11580156119e3573d6000803e3d6000fd5b505050505b6003546040516001600160a01b0390911681527fce13a9895a1719ad4493b2ac1a9bfb36070566161abab408e7ecbe586da8d499906020015b60405180910390a150565b33600081815260046020526040902054611a59576040516302eb3f7160e61b815260040160405180910390fd5b6001600160a01b038216600090815260046020526040902054611a8f57604051634b5518af60e11b815260040160405180910390fd5b611a9882612103565b60ff16611aa482612103565b60ff1611611ac557604051630447252760e41b815260040160405180910390fd5b6001600160a01b039081166000908152600560209081526040808320949093168252929092529020805460ff19166001179055565b600080546201000090046001600160a01b03166380f70cba3083611b1d8661391d565b6040518463ffffffff1660e01b8152600401611b3b939291906153e5565b602060405180830381865afa158015611b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b7c91906152c4565b151592915050565b6060611b8f3361203e565b611bac5760405163619c535960e01b815260040160405180910390fd5b83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611bee9250839150612e149050565b611bfa57611bfa61531c565b6000611c3b86868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061146492505050565b9050838161010001818151611c509190615409565b905250611c5c816133e9565b9695505050505050565b611c78611c716139a5565b8383613a0d565b5050565b611c78338383613a0d565b6001600160a01b03811660009081526004602052604081205461800016151561128a565b6000546201000090046001600160a01b03163314611cdc576040516362e9152760e11b815260040160405180910390fd5b600054604080516001600160a01b03620100009093048316815291831660208301527f13abda02e63c790d0e2818b251282cfe5cbe0a8abd69c54bf5d2260c0907bd2e910160405180910390a1600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6060611d5e3361203e565b611d7b5760405163619c535960e01b815260040160405180910390fd5b82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611dbd9250839150612e149050565b611dc957611dc961531c565b600080611e438a6001898c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c9081908401838280828437600092019190915250612e3492505050565b91509150811561126b57611e5681612efb565b15611e765780806020019051810190611e6f9190615377565b935061126b565b86611e975760405163a85ba64f60e01b815260166004820152602401611174565b61126b8a6016612f4f565b6060611ead3361203e565b611eca5760405163619c535960e01b815260040160405180910390fd5b86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611f0c9250839150612e149050565b611f1857611f1861531c565b6000611f5989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061146492505050565b9050611f8081606001516001600160a01b0316600090815260046020526040902054151590565b8015611f9457506001816000015160ff1610155b15611fe75760608101516001600160a01b039081166000908152600560209081526040808320938b168352929052205460ff16611fe75760405163a85ba64f60e01b8152601e6004820152602401611174565b805181611ff382615431565b60ff169052506003602082015260c0810186905261010081018590526001600160a01b038088166101208301528416610140820152612031816133e9565b9998505050505050505050565b600080826001600160a01b0316637730599e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561207f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120a391906152c4565b600081815260026020526040902054909150801580159061145c57506001600160a01b03841660016120d581846152f3565b815481106120e5576120e5615306565b6000918252602090912001546001600160a01b031614949350505050565b6001600160a01b03811660009081526004602052604081205460ff1661128a565b606061212f3361203e565b61214c5760405163619c535960e01b815260040160405180910390fd5b600061218d85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061146492505050565b90508281610100018181516121a29190615409565b9052506121ae816133e9565b95945050505050565b600054610100900460ff16158080156121d75750600054600160ff909116105b806121f15750303b1580156121f1575060005460ff166001145b61220d5760405162461bcd60e51b815260040161117490615450565b6000805460ff191660011790558015612230576000805461ff0019166101001790555b8015611777576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611a21565b6000818152600260205260408120548082036122a157604051630e4f4df560e11b815260040160405180910390fd5b6122ac6001826152f3565b6001901b19841691505092915050565b7f00000000000000000000000000000000000000000000000000000000000000011561230657612306604051806040016040528060028152602001616b3160f01b815250326144f6565b611777338261459f565b60008181526002602052604081205480820361233f57604051630e4f4df560e11b815260040160405180910390fd5b600161234b81836152f3565b8154811061235b5761235b615306565b6000918252602090912001546001600160a01b03169392505050565b60606123823361203e565b61239f5760405163619c535960e01b815260040160405180910390fd5b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506123e19250839150612e149050565b6123ed576123ed61531c565b6123f78484612f4f565b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929998505050505050505050565b606082828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061247c9250839150612e149050565b61249c5760405163a85ba64f60e01b815260146004820152602401611174565b6001600160a01b03871660009081526004602052604081205488918190036124d75760405163163cbe4360e01b815260040160405180910390fd5b6180008116156124f957604051628e12d960e21b815260040160405180910390fd5b87878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250925061253a915083905061466e565b90506001600160e01b031981166330d9c91560e01b148061256b57506001600160e01b0319811663d86ed3e560e01b145b8061258657506001600160e01b03198116630221347d60e61b145b806125a157506001600160e01b0319811663230dbd2960e01b145b806125bc57506001600160e01b03198116635f9e7d7760e01b145b806125d757506001600160e01b031981166353c11f9960e01b145b156125f5576040516377a14afb60e11b815260040160405180910390fd5b600061263689898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061146492505050565b6101208101519091506001600160a01b03163314612667576040516311cfdef560e21b815260040160405180910390fd5b6060810180513390915261267a826133e9565b97506000806126c18f8f8f8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525092508f915061351d9050565b91509150811561273457808060200190518101906126df9190615377565b99506126ea8a612e14565b61270a5760405163a85ba64f60e01b815260146004820152602401611174565b6127138a611464565b6001600160a01b0384166060820152935061272d846133e9565b995061273d565b61273d816135d8565b50505050505050505095945050505050565b60008181526002602052604081205480820361277e57604051630e4f4df560e11b815260040160405180910390fd5b6127896001826152f3565b6001901b841791505092915050565b7f0000000000000000000000000000000000000000000000000000000000000001156127ff576127ff82828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152503292506144f6915050565b612809338461459f565b505050565b600061128783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612e1492505050565b600054610100900460ff161580801561286f5750600054600160ff909116105b806128895750303b158015612889575060005460ff166001145b6128a55760405162461bcd60e51b815260040161117490615450565b6000805460ff1916600117905580156128c8576000805461ff0019166101001790555b6000805462010000600160b01b031916620100006001600160a01b038516021790558015611c78576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b60606000806001805490506001600160401b0381111561295557612955614bef565b60405190808252806020026020018201604052801561297e578160200160208202803683370190505b50925060009050600091505b600154821015612a10576001821b841615612a0557600182815481106129b2576129b2615306565b6000918252602090912001546001600160a01b031683826129d28161549e565b9350815181106129e4576129e4615306565b60200260200101906001600160a01b031690816001600160a01b0316815250505b81600101915061298a565b825250919050565b816001600160a01b03163b600003612a435760405163353dacc360e21b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000115612a8d57612a8d604051806040016040528060028152602001616b3160f01b815250336144f6565b611c78828261459f565b6003546000906001600160a01b0316612ab257612ab261531c565b7f000000000000000000000000000000000000000000000000000000000000000015612ae857506003546001600160a01b031690565b600360009054906101000a90046001600160a01b03166001600160a01b03166350d75d256040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b3b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a491906153ab565b816001600160a01b03163b600003612b8a5760405163353dacc360e21b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000115612a8d576000612bbb336146ca565b6000805460405163407b865d60e11b81529293509091620100009091046001600160a01b0316906380f70cba90612bfa903090859087906004016153e5565b602060405180830381865afa158015612c17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c3b91906152c4565b600114905080612c5e57604051630b56455f60e41b815260040160405180910390fd5b5050611c78828261459f565b6001600160a01b038116600090815260046020908152604080832081519283019091525480825215801592918291612cb157805161800081161515935064ff000000001691505b509193909250565b6000546201000090046001600160a01b03163314612cea576040516362e9152760e11b815260040160405180910390fd5b60006001600160a01b038216612d7657600360009054906101000a90046001600160a01b03166001600160a01b0316639470a5b26040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d7191906153ab565b612d78565b815b6040516311a5465560e21b81526001600160a01b03808316600483015291925090841690634695195490602401600060405180830381600087803b158015612dbf57600080fd5b505af1158015612dd3573d6000803e3d6000fd5b50506040516001600160a01b038481168252861692507f840acbd291b38534819f47f875839277e502f40e1c7bfea2c5fc2c8017442cd39150602001611441565b6000815160001415801561128a5750600654825160208401201492915050565b600060606001600160a01b038716612e4e57612e4e61531c565b612e588484614744565b93506001600160401b037f0000000000000000000000000000000000000000000000000000000000e4e1c016600087612e9b57612e968987846147fb565b612ea6565b612ea689878461488c565b919550909350905083612eef5780612ed65786612ecb57612ec6836135d8565b612eef565b612ec689600a612f4f565b604051636a7aea4b60e11b815260040160405180910390fd5b50509550959350505050565b6000604082511015612f0f57506000919050565b602082810151906000908214612f29575060009392505050565b506040830151612f38816148eb565b612f439060406154b7565b84511492505050919050565b6001600160a01b038216600090815260046020526040812054618000169003611c78576001600160a01b038216600081815260046020526040908190208054618000179055517fbe3aa33bd245135e4e26b223d79d14ea479a47bff09f2b03c53838af1edbb14b90612fc49084815260200190565b60405180910390a25050565b60065460609015612ff75760405163a85ba64f60e01b815260156004820152602401611174565b6001600160a01b03841660009081526004602052604081205485918190036130325760405163163cbe4360e01b815260040160405180910390fd5b61800081161561305457604051628e12d960e21b815260040160405180910390fd5b8360006130608261466e565b90506001600160e01b031981166330d9c91560e01b148061309157506001600160e01b0319811663d86ed3e560e01b145b806130ac57506001600160e01b03198116630221347d60e61b145b806130c757506001600160e01b0319811663230dbd2960e01b145b806130e257506001600160e01b03198116635f9e7d7760e01b145b806130fd57506001600160e01b031981166353c11f9960e01b145b1561311b576040516377a14afb60e11b815260040160405180910390fd5b60408051610160810182526000808252600260208084019190915242838501526001600160a01b03808e16606085015260808401839052845191820190945281815260a083015260c0820181905260e082018190526101008201819052918a166101208201526101408101829052613192906133e9565b905060006131a28a898b8561351d565b9750905080156131f057868060200190518101906131c09190615377565b91506131cb82612e14565b6131eb5760405163a85ba64f60e01b815260146004820152602401611174565b6131f9565b6131f9876135d8565b505060006006555092979650505050505050565b600654606090156132345760405163a85ba64f60e01b815260156004820152602401611174565b8361323e8161203e565b61325b5760405163619c535960e01b815260040160405180910390fd5b60006132668561466e565b60408051610160810182526000808252600160208301529293506132e99181014281526020018a6001600160a01b03168152602001846001600160e01b031916815260200187815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b03168152506133e9565b905060006132fa888860008561351d565b955090508061330c5761330c856135d8565b50506000600655509095945050505050565b6133266149d1565b6060808380602001905181019061333d91906154ca565b8151919350915060009061335a9084016020908101908501615527565b60a08901526001600160e01b03191660808801526001600160a01b031660608701526040860152602081811c600f168187015260ff90911685528251600092506133ab9190840181019084016155ac565b6001600160a01b03908116610140890152166101208701526101008601526001600160801b03811660c086015260801c60e085015250919392505050565b60606001826000015160ff1611156134175760405163a85ba64f60e01b815260286004820152602401611174565b815160208084015160009260ff1664ff000000009190921b16179050600060806134448560e00151614924565b6001600160801b0316901b61345c8560c00151614924565b6001600160801b0316179050818460400151856060015186608001518760a001516040516020016134919594939291906155f8565b60408051601f1981840301815282825261010087015161012088015161014089015160208601879052938501919091526001600160a01b03908116606085015290911660808301529060a00160408051601f19818403018152908290526134fb9291602001614f43565b60408051601f1981840301815291905280516020820120600655949350505050565b600060606001600160a01b0386166135375761353761531c565b6135418584614744565b9450856001600160a01b0316848660405161355c9190615644565b60006040518083038185875af1925050503d8060008114613599576040519150601f19603f3d011682016040523d82523d6000602084013e61359e565b606091505b50909250905081156135cf5780516000036135cf5760405163a85ba64f60e01b815260166004820152602401611174565b94509492505050565b60048151101561362a5760405162461bcd60e51b815260206004820152601a60248201527f43616c6c5574696c733a207461726765742072657665727428290000000000006044820152606401611174565b602081015163b1b7848f60e01b6001600160e01b03198216016136da5760408051808201825260208082527f43616c6c5574696c733a207461726765742070616e69636b65643a2030785f5f90820190815260248501517f43616c6c5574696c733a207461726765742070616e69636b65643a2030780000600482811c600f908116603090810160081b918516011791909117909252925162461bcd60e51b815291929161117491849101614bdc565b81518060208401fd5b600061370d7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6001600160a01b0316036137635760405162461bcd60e51b815260206004820152601d60248201527f5555505350726f786961626c653a206e6f742075706772616461626c650000006044820152606401611174565b806001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c591906152c4565b7fcd355cae2c435f8c5e0c626c4691d22fd85aa7422a424c6f0bced6e64c7aba741461383f5760405162461bcd60e51b815260206004820152602360248201527f5555505350726f786961626c653a206e6f7420636f6d70617469626c65206c6f60448201526267696360e81b6064820152608401611174565b6001600160a01b03811630036138975760405162461bcd60e51b815260206004820152601960248201527f5555505350726f786961626c653a2070726f7879206c6f6f70000000000000006044820152606401611174565b6138bf817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b7fe011bc04c286c344a8fcbb8de77f953da762c3e25d8cdea984147fc4168a5dcc7fcd355cae2c435f8c5e0c626c4691d22fd85aa7422a424c6f0bced6e64c7aba74604080519182526001600160a01b038416602083015201611a21565b6040805160208101829052603260608201527f6f72672e7375706572666c7569642d66696e616e63652e7375706572666c756960808201527132173a393ab9ba32b22337b93bb0b93232b960711b60a08201526001600160a01b0383169181019190915260009060c0015b604051602081830303815290604052805190602001209050919050565b6000601836108015906139bc57506139bc33611afa565b613a005760405162461bcd60e51b81526020600482015260156024820152742737ba103a393ab9ba32b2103337b93bb0b93232b960591b6044820152606401611174565b5060131936013560601c90565b60005b818110156144b4576000838383818110613a2c57613a2c615306565b9050602002810190613a3e9190615660565b613a4c906020810190615676565b905060001963ffffffff821601613b4057600080858585818110613a7257613a72615306565b9050602002810190613a849190615660565b613a9290604081019061569c565b810190613a9f9190615298565b91509150858585818110613ab557613ab5615306565b9050602002810190613ac79190615660565b613ad8906040810190602001614a41565b6001600160a01b03166362aa52878884846040518463ffffffff1660e01b8152600401613b07939291906153e5565b600060405180830381600087803b158015613b2157600080fd5b505af1158015613b35573d6000803e3d6000fd5b5050505050506144ab565b60011963ffffffff821601613c4b576000806000868686818110613b6657613b66615306565b9050602002810190613b789190615660565b613b8690604081019061569c565b810190613b9391906156e2565b925092509250868686818110613bab57613bab615306565b9050602002810190613bbd9190615660565b613bce906040810190602001614a41565b604051630b682aeb60e11b81526001600160a01b038a81166004830152858116602483015284811660448301526064820184905291909116906316d055d6906084015b600060405180830381600087803b158015613c2b57600080fd5b505af1158015613c3f573d6000803e3d6000fd5b505050505050506144ab565b60021963ffffffff821601613d0a576000806000868686818110613c7157613c71615306565b9050602002810190613c839190615660565b613c9190604081019061569c565b810190613c9e9190615723565b925092509250868686818110613cb657613cb6615306565b9050602002810190613cc89190615660565b613cd9906040810190602001614a41565b6001600160a01b031663ca0c1e7f898585856040518563ffffffff1660e01b8152600401613c119493929190615765565b60031963ffffffff821601613dc357600080858585818110613d2e57613d2e615306565b9050602002810190613d409190615660565b613d4e90604081019061569c565b810190613d5b9190615298565b91509150858585818110613d7157613d71615306565b9050602002810190613d839190615660565b613d94906040810190602001614a41565b6001600160a01b0316634b2763b38884846040518463ffffffff1660e01b8152600401613b07939291906153e5565b60041963ffffffff821601613e7c57600080858585818110613de757613de7615306565b9050602002810190613df99190615660565b613e0790604081019061569c565b810190613e149190615298565b91509150858585818110613e2a57613e2a615306565b9050602002810190613e3c9190615660565b613e4d906040810190602001614a41565b6001600160a01b031663c780fd828884846040518463ffffffff1660e01b8152600401613b07939291906153e5565b60641963ffffffff821601613f7157838383818110613e9d57613e9d615306565b9050602002810190613eaf9190615660565b613ec0906040810190602001614a41565b6001600160a01b031663ca78946486868686818110613ee157613ee1615306565b9050602002810190613ef39190615660565b613f0190604081019061569c565b810190613f0e91906150c5565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015613f5457600080fd5b505af1158015613f68573d6000803e3d6000fd5b505050506144ab565b60651963ffffffff821601613fd657838383818110613f9257613f92615306565b9050602002810190613fa49190615660565b613fb5906040810190602001614a41565b6001600160a01b031663245887fc86868686818110613ee157613ee1615306565b60661963ffffffff82160161408f57600080858585818110613ffa57613ffa615306565b905060200281019061400c9190615660565b61401a90604081019061569c565b8101906140279190615298565b9150915085858581811061403d5761403d615306565b905060200281019061404f9190615660565b614060906040810190602001614a41565b6001600160a01b0316631ae88ffc8884846040518463ffffffff1660e01b8152600401613b07939291906153e5565b60671963ffffffff821601614148576000808585858181106140b3576140b3615306565b90506020028101906140c59190615660565b6140d390604081019061569c565b8101906140e09190615298565b915091508585858181106140f6576140f6615306565b90506020028101906141089190615660565b614119906040810190602001614a41565b6001600160a01b03166347ba7ad18884846040518463ffffffff1660e01b8152600401613b07939291906153e5565b60c81963ffffffff8216016141e55760008085858581811061416c5761416c615306565b905060200281019061417e9190615660565b61418c90604081019061569c565b8101906141999190615798565b915091506141dd878787878181106141b3576141b3615306565b90506020028101906141c59190615660565b6141d6906040810190602001614a41565b848461320d565b5050506144ab565b60c91963ffffffff8216016142a05761429a8585858581811061420a5761420a615306565b905060200281019061421c9190615660565b61422d906040810190602001614a41565b4787878781811061424057614240615306565b90506020028101906142529190615660565b61426090604081019061569c565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612fd092505050565b506144ab565b61012c1963ffffffff8216016143c8576000807f00000000000000000000000008ecf8ec4cec8a00d5460d3faf9f0719c80a35136001600160a01b03166322bee494478888888181106142f5576142f5615306565b90506020028101906143079190615660565b614318906040810190602001614a41565b89898981811061432a5761432a615306565b905060200281019061433c9190615660565b61434a90604081019061569c565b6040518563ffffffff1660e01b815260040161436893929190615812565b60006040518083038185885af1158015614386573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526143af9190810190615837565b91509150816143c1576143c1816135d8565b50506144ab565b61012d1963ffffffff821601614492576000807f0000000000000000000000004ddb0f9a512933e3078a32130d92ea6e59f039cc6001600160a01b031663177ec5944788888881811061441d5761441d615306565b905060200281019061442f9190615660565b614440906040810190602001614a41565b8a8a8a8a81811061445357614453615306565b90506020028101906144659190615660565b61447390604081019061569c565b6040518663ffffffff1660e01b81526004016143689493929190615871565b60405163b477011560e01b815260040160405180910390fd5b50600101613a10565b504715612809576040516001600160a01b038416904780156108fc02916000818181858888f193505050501580156144f0573d6000803e3d6000fd5b50505050565b60006145028284614991565b6000805460405163407b865d60e11b81529293504292620100009091046001600160a01b0316916380f70cba9161453f91309187906004016153e5565b602060405180830381865afa15801561455c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061458091906152c4565b101561280957604051630b56455f60e41b815260040160405180910390fd5b64ff000080ff1981161515806145b6575060ff8116155b806145c45750618000811615155b156145e257604051633d3200a960e21b815260040160405180910390fd5b6001600160a01b03821660009081526004602052604090205415614619576040516301b0a93560e01b815260040160405180910390fd5b60408051602080820183528382526001600160a01b038516600081815260049092528382209251909255915190917f0d540ad8f39e07d19909687352b9fa017405d93c91a6760981fbae9cf28bfef791a25050565b60006004825110156146c25760405162461bcd60e51b815260206004820152601b60248201527f43616c6c5574696c733a20696e76616c69642063616c6c4461746100000000006044820152606401611174565b506020015190565b6040805160208101829052603960608201527f6f72672e7375706572666c7569642d66696e616e63652e7375706572666c756960808201527f642e61707057686974654c697374696e672e666163746f72790000000000000060a08201526001600160a01b0383169181019190915260009060c001613988565b81518083015160609190801561476d576040516367e9985b60e01b815260040160405180910390fd5b50601f1981018452825184908481614784816148eb565b61478e91906152f3565b6001600160401b038111156147a5576147a5614bef565b6040519080825280601f01601f1916602001820160405280156147cf576020820181803683370190505b506040516020016147e3949392919061589e565b60405160208183030381529060405291505092915050565b600080606060005a9050866001600160a01b0316858760405161481e9190615644565b60006040518083038160008787f1925050503d806000811461485c576040519150601f19603f3d011682016040523d82523d6000602084013e614861565b606091505b50909450915083614882576148776040826158ec565b5a1161488257600192505b5093509350939050565b600080606060005a9050866001600160a01b031685876040516148af9190615644565b6000604051808303818686fa925050503d806000811461485c576040519150601f19603f3d011682016040523d82523d6000602084013e614861565b60008082601f16116148fe576000614901565b60015b60ff1661490f6020846158ec565b61491991906154b7565b61128a90602061590e565b60006001600160801b0382111561498d5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401611174565b5090565b600082826040516020016149a6929190615925565b60405160208183030381529060405280519060200120905092915050565b610249806159ab83390190565b604080516101608101825260008082526020820181905291810182905260608082018390526080820183905260a082015260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b6001600160a01b038116811461177757600080fd5b600060208284031215614a5357600080fd5b8135614a5e81614a2c565b9392505050565b60008060408385031215614a7857600080fd5b8235614a8381614a2c565b91506020830135614a9381614a2c565b809150509250929050565b60008083601f840112614ab057600080fd5b5081356001600160401b03811115614ac757600080fd5b602083019150836020828501011115614adf57600080fd5b9250929050565b801515811461177757600080fd5b60008060008060008060808789031215614b0d57600080fd5b8635614b1881614a2c565b955060208701356001600160401b03811115614b3357600080fd5b614b3f89828a01614a9e565b9096509450506040870135614b5381614ae6565b925060608701356001600160401b03811115614b6e57600080fd5b614b7a89828a01614a9e565b979a9699509497509295939492505050565b60005b83811015614ba7578181015183820152602001614b8f565b50506000910152565b60008151808452614bc8816020860160208601614b8c565b601f01601f19169290920160200192915050565b6020815260006112876020830184614bb0565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614c2d57614c2d614bef565b604052919050565b60006001600160401b03821115614c4e57614c4e614bef565b50601f01601f191660200190565b600082601f830112614c6d57600080fd5b8135614c80614c7b82614c35565b614c05565b818152846020838601011115614c9557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614cc557600080fd5b8235614cd081614a2c565b915060208301356001600160401b03811115614ceb57600080fd5b614cf785828601614c5c565b9150509250929050565b600080600060608486031215614d1657600080fd5b8335614d2181614a2c565b925060208401356001600160401b03811115614d3c57600080fd5b614d4886828701614c5c565b92505060408401356001600160401b03811115614d6457600080fd5b614d7086828701614c5c565b9150509250925092565b600060208284031215614d8c57600080fd5b81356001600160401b03811115614da257600080fd5b61145c84828501614c5c565b60208152614dc260208201835160ff169052565b60006020830151614dd8604084018260ff169052565b50604083015160608301526060830151614dfd60808401826001600160a01b03169052565b5060808301516001600160e01b0319811660a08401525060a083015161016060c0840152614e2f610180840182614bb0565b905060c084015160e084015260e0840151610100840152610100840151610120840152610120840151614e6e6101408501826001600160a01b03169052565b506101408401516001600160a01b038116610160850152509392505050565b60008060008060008060006080888a031215614ea857600080fd5b8735614eb381614a2c565b965060208801356001600160401b03811115614ece57600080fd5b614eda8a828b01614a9e565b90975095505060408801356001600160401b03811115614ef957600080fd5b614f058a828b01614a9e565b90955093505060608801356001600160401b03811115614f2457600080fd5b614f308a828b01614a9e565b989b979a50959850939692959293505050565b604081526000614f566040830185614bb0565b82810360208401526121ae8185614bb0565b600080600060408486031215614f7d57600080fd5b83356001600160401b03811115614f9357600080fd5b614f9f86828701614a9e565b909790965060209590950135949350505050565b60008060208385031215614fc657600080fd5b82356001600160401b03811115614fdc57600080fd5b8301601f81018513614fed57600080fd5b80356001600160401b0381111561500357600080fd5b8560208260051b840101111561501857600080fd5b6020919091019590945092505050565b60008060008060008060a0878903121561504157600080fd5b86356001600160401b0381111561505757600080fd5b61506389828a01614a9e565b909750955050602087013561507781614a2c565b93506040870135925060608701359150608087013561509581614a2c565b809150509295509295509295565b600080604083850312156150b657600080fd5b50508035926020909101359150565b6000602082840312156150d757600080fd5b5035919050565b600080600080606085870312156150f457600080fd5b84356001600160401b0381111561510a57600080fd5b61511687828801614a9e565b909550935050602085013561512a81614a2c565b9396929550929360400135925050565b60008060008060006060868803121561515257600080fd5b853561515d81614a2c565b945060208601356001600160401b0381111561517857600080fd5b61518488828901614a9e565b90955093505060408601356001600160401b038111156151a357600080fd5b6151af88828901614a9e565b969995985093965092949392505050565b6000806000604084860312156151d557600080fd5b8335925060208401356001600160401b038111156151f257600080fd5b6151fe86828701614a9e565b9497909650939450505050565b6000806020838503121561521e57600080fd5b82356001600160401b0381111561523457600080fd5b61524085828601614a9e565b90969095509350505050565b602080825282518282018190526000918401906040840190835b8181101561528d5783516001600160a01b0316835260209384019390920191600101615266565b509095945050505050565b600080604083850312156152ab57600080fd5b82356152b681614a2c565b946020939093013593505050565b6000602082840312156152d657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561128a5761128a6152dd565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b600082601f83011261534357600080fd5b8151615351614c7b82614c35565b81815284602083860101111561536657600080fd5b61145c826020830160208701614b8c565b60006020828403121561538957600080fd5b81516001600160401b0381111561539f57600080fd5b61145c84828501615332565b6000602082840312156153bd57600080fd5b8151614a5e81614a2c565b6000602082840312156153da57600080fd5b8151614a5e81614ae6565b6001600160a01b039384168152919092166020820152604081019190915260600190565b8082018281126000831280158216821582161715615429576154296152dd565b505092915050565b600060ff821660ff8103615447576154476152dd565b60010192915050565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6000600182016154b0576154b06152dd565b5060010190565b8082018082111561128a5761128a6152dd565b600080604083850312156154dd57600080fd5b82516001600160401b038111156154f357600080fd5b6154ff85828601615332565b92505060208301516001600160401b0381111561551b57600080fd5b614cf785828601615332565b600080600080600060a0868803121561553f57600080fd5b855160208701516040880151919650945061555981614a2c565b60608701519093506001600160e01b03198116811461557757600080fd5b60808701519092506001600160401b0381111561559357600080fd5b61559f88828901615332565b9150509295509295909350565b600080600080608085870312156155c257600080fd5b84516020860151604087015191955093506155dc81614a2c565b60608601519092506155ed81614a2c565b939692955090935050565b858152602081018590526001600160a01b03841660408201526001600160e01b03198316606082015260a06080820181905260009061563990830184614bb0565b979650505050505050565b60008251615656818460208701614b8c565b9190910192915050565b60008235605e1983360301811261565657600080fd5b60006020828403121561568857600080fd5b813563ffffffff81168114614a5e57600080fd5b6000808335601e198436030181126156b357600080fd5b8301803591506001600160401b038211156156cd57600080fd5b602001915036819003821315614adf57600080fd5b6000806000606084860312156156f757600080fd5b833561570281614a2c565b9250602084013561571281614a2c565b929592945050506040919091013590565b60008060006060848603121561573857600080fd5b833561574381614a2c565b92506020840135915060408401356001600160401b03811115614d6457600080fd5b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611c5c90830184614bb0565b600080604083850312156157ab57600080fd5b82356001600160401b038111156157c157600080fd5b6157cd85828601614c5c565b92505060208301356001600160401b03811115614ceb57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b03841681526040602082018190526000906121ae90830184866157e9565b6000806040838503121561584a57600080fd5b825161585581614ae6565b60208401519092506001600160401b0381111561551b57600080fd5b6001600160a01b03858116825284166020820152606060408201819052600090611c5c90830184866157e9565b600085516158b0818460208a01614b8c565b820185815284516158c8816020808501908901614b8c565b84519101906158de816020808501908801614b8c565b016020019695505050505050565b60008261590957634e487b7160e01b600052601260045260246000fd5b500490565b808202811582820484141761128a5761128a6152dd565b60608152604160608201527f6f72672e7375706572666c7569642d66696e616e63652e7375706572666c756960808201527f642e61707057686974654c697374696e672e726567697374726174696f6e4b6560a0820152607960f81b60c082015260018060a01b038316602082015260e06040820152600061145c60e0830184614bb056fe6080604052348015600f57600080fd5b5061022a8061001f6000396000f3fe6080604052600436106100225760003560e01c80634a0687ef1461003957610031565b366100315761002f610059565b005b61002f610059565b34801561004557600080fd5b5061002f6100543660046101c4565b61006b565b610069610064610171565b6101a0565b565b6001600160a01b0381166100c65760405162461bcd60e51b815260206004820152601760248201527f5555505350726f78793a207a65726f206164647265737300000000000000000060448201526064015b60405180910390fd5b60006100f07f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6001600160a01b0316146101465760405162461bcd60e51b815260206004820152601e60248201527f5555505350726f78793a20616c726561647920696e697469616c697a6564000060448201526064016100bd565b61016e817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b50565b600061019b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b905090565b3660008037600080366000845af43d6000803e8080156101bf573d6000f35b3d6000fd5b6000602082840312156101d657600080fd5b81356001600160a01b03811681146101ed57600080fd5b939250505056fea2646970667358221220fae816317186d33a564ddff3a944af220df3c9025c6f9ffcae9cd4a4a7a4b19164736f6c634300081a0033a26469706673582212208425040ede939fa1e37874fcf0eb2a063642a433d225f2049dafaca1fe8cb4c564736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000e4e1c000000000000000000000000008ecf8ec4cec8a00d5460d3faf9f0719c80a35130000000000000000000000004ddb0f9a512933e3078a32130d92ea6e59f039cc
-----Decoded View---------------
Arg [0] : nonUpgradable (bool): False
Arg [1] : appWhiteListingEnabled (bool): True
Arg [2] : callbackGasLimit (uint64): 15000000
Arg [3] : simpleForwarderAddress (address): 0x08eCF8ec4CEc8a00D5460d3FAF9f0719C80a3513
Arg [4] : erc2771ForwarderAddress (address): 0x4ddb0f9a512933E3078A32130D92Ea6e59f039CC
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [2] : 0000000000000000000000000000000000000000000000000000000000e4e1c0
Arg [3] : 00000000000000000000000008ecf8ec4cec8a00d5460d3faf9f0719c80a3513
Arg [4] : 0000000000000000000000004ddb0f9a512933e3078a32130d92ea6e59f039cc
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.