Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 16696553 | 569 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Torex
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {
ISuperfluid, ISuperToken, ISuperfluidPool, PoolConfig
} from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol";
import { CFASuperAppBase } from "@superfluid-finance/ethereum-contracts/contracts/apps/CFASuperAppBase.sol";
import { CallbackUtils } from "@superfluid-finance/ethereum-contracts/contracts/libs/CallbackUtils.sol";
import { SuperTokenV1Library } from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol";
import { ITwapObserver } from "./interfaces/torex/ITwapObserver.sol";
import {
LiquidityMoveResult, ITorexController, ITorex
} from "./interfaces/torex/ITorex.sol";
import { DiscountFactor } from "./libs/DiscountFactor.sol";
import { toInt96, UINT_100PCT_PM, INT_100PCT_PM } from "../src/libs/MathExtra.sol";
import { Scaler } from "./libs/Scaler.sol";
import { TorexCore } from "./TorexCore.sol";
/**
* @title A TOREX that is a super app, distributes fees, and has a controller.
*
* @notice Notes:
*
* - In addition to the TOREX core logic, this implementation uses super app framework to support cash flow automation.
*
* - It has hooks for flow update events and liquidity moved events, where its controller (ITorexController) can use to
* implement additional logic.
*
* - Further more, it has its own Superfluid pool for distributing fees. The admin of the pool is the controller and the
* controller controls the fee percent. Notably though, the TOREX protects its traders from rouge controller by having
* an immutable configuration of max allowed fee percent.
*
* CHANGELOG:
*
* [1.0.0-rc3] - 2024-06-25
*
* Added:
*
* - Controller hooks error handling with "safe callback" technique.
*
* Changes:
*
* - maxAllowedFeePM is now unsigned.
*
* [1.0.0-rc2] - 2024-04-12
*
* First tagged version.
*
* Fixes:
* - Added TorexCore.availableInTokens in order to allow Torex implementation to reserve in-tokens in its discretion.
* - Torex.availableInTokens to reserve minimum buffer requirement for _requestedFeeDistFlowRate.
* - Torex stores _feeDistBuffer, in order to make better fee back adjustment.
* - Torex uses SuperTokenV1Library.getGDAFlowInfo in _onInFlowChanged.
*/
contract Torex is TorexCore, CFASuperAppBase, ITorex {
string public constant VERSION = "1.0.0-rc3";
using SuperTokenV1Library for ISuperToken;
/*******************************************************************************************************************
* Definitions
******************************************************************************************************************/
/// Configuration of the torex.
struct Config {
ISuperToken inToken;
ISuperToken outToken;
ITwapObserver observer;
DiscountFactor discountFactor;
Scaler twapScaler;
Scaler outTokenDistributionPoolScaler;
ITorexController controller;
uint256 controllerSafeCallbackGasLimit;
uint256 maxAllowedFeePM;
}
/// Trader state.
struct TraderState {
/// A contribution flow is the flow rate that is accounted by the TOREX core logic.
int96 contribFlowRate;
/// A fee flow is the flow rate that is distributed through the `feeDistributionPool`.
int96 feeFlowRate;
}
/// Context for the liquidity moved event.
event LiquidityMoved(address indexed liquidityMover,
uint256 durationSinceLastLME, uint256 twapSinceLastLME,
uint256 inAmount, uint256 minOutAmount,
uint256 outAmount, uint256 actualOutAmount);
/// Context for Torex flow updated event.
event TorexFlowUpdated(address indexed sender,
int96 newFlowRate, int96 newContribFlowRate, int256 backAdjustment,
int96 requestedFeeDistFlowRate, int96 actualFeeDistFlowRate);
/// Controller error event.
event ControllerError(bytes reason);
/*******************************************************************************************************************
* Configurations and Constructor
******************************************************************************************************************/
/// Gas limit used for safe callbacks to the controller.
uint256 public immutable CONTROLLER_SAFE_CALLBACK_GAS_LIMIT;
/// Maximum fee (in Per Millions) allowed from the controller, in case of rogue controller.
uint256 public immutable MAX_ALLOWED_FEE_PM;
/// @inheritdoc ITorex
ITorexController public override immutable controller;
/// @inheritdoc ITorex
ISuperfluidPool public override immutable feeDistributionPool;
/// View configuration.
function getConfig() public view returns (Config memory) {
return Config({
controller: controller,
inToken: _inToken,
outToken: _outToken,
observer: _observer,
twapScaler: _twapScaler,
discountFactor: _discountFactor,
outTokenDistributionPoolScaler: _outTokenDistributionPoolScaler,
controllerSafeCallbackGasLimit: CONTROLLER_SAFE_CALLBACK_GAS_LIMIT,
maxAllowedFeePM: MAX_ALLOWED_FEE_PM
});
}
constructor(Config memory config)
CFASuperAppBase(ISuperfluid(config.inToken.getHost()))
TorexCore(config.inToken, config.outToken,
config.observer, config.twapScaler, config.discountFactor,
config.outTokenDistributionPoolScaler) {
assert(config.inToken.getHost() == config.outToken.getHost());
assert(address(config.observer) != address(0));
assert(config.maxAllowedFeePM <= UINT_100PCT_PM);
controller = config.controller;
CONTROLLER_SAFE_CALLBACK_GAS_LIMIT = config.controllerSafeCallbackGasLimit;
MAX_ALLOWED_FEE_PM = config.maxAllowedFeePM;
feeDistributionPool = _inToken.createPool(address(controller), PoolConfig({
transferabilityForUnitsOwner: false,
distributionFromAnyAddress: true
}));
}
/*******************************************************************************************************************
* States
******************************************************************************************************************/
/// Tracking current contribution flow rates of traders.
mapping(address => TraderState) private traderStates;
/// A view function for trader states that is struct-ABI-friendly.
function getTraderState(address a) external view returns (TraderState memory) { return traderStates[a]; }
/// Tracking current fee distribution flow rate requested.
int96 private _requestedFeeDistFlowRate;
/// Tracking the actual fee distribution rate.
int96 private _actualFeeDistFlowRate;
/// Buffer used by the fee flow distribution.
uint256 private _feeDistBuffer;
/// Counter of internal errors of the controller.
uint256 public controllerInternalErrorCounter;
/*******************************************************************************************************************
* Super App Hooks for Flow Life-Cycles
******************************************************************************************************************/
/// @inheritdoc CFASuperAppBase
function onFlowCreated(ISuperToken superToken, address sender, bytes calldata ctx) internal override
returns (bytes memory newCtx)
{
return _onInFlowChanged(superToken, sender, 0, 0 /* lastUpdated */, ctx);
}
/// @inheritdoc CFASuperAppBase
function onFlowUpdated(ISuperToken superToken, address sender,
int96 prevFlowRate, uint256 lastUpdated,
bytes calldata ctx) internal override
returns (bytes memory newCtx)
{
return _onInFlowChanged(superToken, sender, prevFlowRate, lastUpdated, ctx);
}
/// @inheritdoc CFASuperAppBase
function onFlowDeleted(ISuperToken superToken, address sender, address /*receiver*/,
int96 prevFlowRate, uint256 lastUpdated,
bytes calldata ctx) internal override
returns (bytes memory newCtx)
{
return _onInFlowChanged(superToken, sender, prevFlowRate, lastUpdated, ctx);
}
function isAcceptedSuperToken(ISuperToken superToken) public view override returns (bool) {
// We don't handle other token flows.
return superToken == _inToken;
}
function availableInTokens() override internal view returns (uint256 amount) {
uint256 minimumDeposit = _inToken.getBufferAmountByFlowRate(_requestedFeeDistFlowRate);
amount = _inToken.balanceOf(address(this));
if (amount >= minimumDeposit) return amount - minimumDeposit; else return 0;
}
function _onInFlowChanged(ISuperToken superToken, address sender, int96 prevFlowRate, uint256 lastUpdated,
bytes memory ctx) internal
returns (bytes memory newCtx)
{
newCtx = ctx;
ISuperfluid.Context memory context = HOST.decodeCtx(ctx);
TraderState storage senderState = traderStates[sender];
// Note: a lot of nested brackets to fight the stack too deep trite
int96 newFlowRate;
int96 newContribFlowRate;
int96 newFeeFlowRate;
{
newFlowRate = superToken.getFlowRate(sender, address(this));
{
bool requireSafeCallback = newFlowRate == 0; // do not revert in deleteFlow
bytes memory callData = abi.encodeCall(controller.onInFlowChanged,
(sender,
prevFlowRate, senderState.feeFlowRate, lastUpdated,
newFlowRate, context.timestamp,
context.userData));
(bool success, bytes memory returnedData) = _callControllerHook(requireSafeCallback, callData);
if (success) {
newFeeFlowRate = _safeDecodeFeeFlowRate(requireSafeCallback, returnedData);
}
}
// protect traders from rogue controllers.
if (newFeeFlowRate > newFlowRate * int256(MAX_ALLOWED_FEE_PM) / INT_100PCT_PM) {
newFeeFlowRate = 0;
}
newContribFlowRate = newFlowRate - newFeeFlowRate;
}
_requestedFeeDistFlowRate = _requestedFeeDistFlowRate + newFeeFlowRate - senderState.feeFlowRate;
// back adjustments (back charge and back refund)
int256 backAdjustment;
{
// invoke core logic to calculate back charge/refund
uint256 durationSinceLastLME;
(durationSinceLastLME, backAdjustment) =
_onInFlowChanged(sender, senderState.contribFlowRate, newContribFlowRate);
// in case of the flow rate going up
if (newFlowRate > prevFlowRate) {
// add back charge of fees
if (newFeeFlowRate > senderState.feeFlowRate) {
int96 deltaFeeFlowRate = newFeeFlowRate - senderState.feeFlowRate;
backAdjustment += deltaFeeFlowRate * SafeCast.toInt256(durationSinceLastLME);
}
// fee distribution pool buffer is paid by the sender too
uint256 feeDistBufferNew = _inToken.getBufferAmountByFlowRate(_requestedFeeDistFlowRate);
if (feeDistBufferNew > _feeDistBuffer) {
backAdjustment += SafeCast.toInt256(feeDistBufferNew - _feeDistBuffer);
}
} // else:
// however, in case of the flow rate going down, there is no refund for back charged fees.
// this is due to that the fees is being distributed continuously.
}
// update sender states
senderState.contribFlowRate = newContribFlowRate;
senderState.feeFlowRate = newFeeFlowRate;
// do back charge
if (backAdjustment > 0) {
// Under this branch, this should be true: newFlowRate > prevFlowRate >= 0
// This could revert, if approvals not available.
// However, due to newFlowRate > 0, the revert should never jail the app.
_inToken.transferFrom(sender, address(this), SafeCast.toUint256(backAdjustment));
}
// update fee distribution flow rate, this requires the buffer cost taken as part of back adjustment.
newCtx = _inToken.distributeFlowWithCtx(address(this), feeDistributionPool, _requestedFeeDistFlowRate, newCtx);
(, _actualFeeDistFlowRate, _feeDistBuffer) = _inToken.getGDAFlowInfo(address(this), feeDistributionPool);
// do back refund
if (backAdjustment < 0) {
// this should never revert
_inToken.transfer(sender, SafeCast.toUint256(-backAdjustment));
}
emit TorexFlowUpdated(sender,
newFlowRate, newContribFlowRate, backAdjustment,
_requestedFeeDistFlowRate, _actualFeeDistFlowRate);
}
/*******************************************************************************************************************
* Torex Interfaces
`******************************************************************************************************************/
/// @inheritdoc ITorex
function getPairedTokens() external override view returns (ISuperToken inToken, ISuperToken outToken) {
return (_inToken, _outToken);
}
/// @inheritdoc ITorex
function outTokenDistributionPool() external override view returns (ISuperfluidPool) {
return _outTokenDistributionPool;
}
/// @inheritdoc ITorex
function estimateApprovalRequired(int96 flowRate) external override view returns (uint256 requiredApproval) {
// We make the best effort of estimating the approvals required to create the torex flow of the required flow
// rate. However, in order to keep things simple, extra approvals is always requested. Front-end may zero the
// approval at the end of the batch call.
(, int256 maxCoreBackAdjustment) = _requiredBackAdjustment(0, flowRate);
int96 maxFeeDistRate = _requestedFeeDistFlowRate +
toInt96(int256(flowRate) * int256(MAX_ALLOWED_FEE_PM) / INT_100PCT_PM);
uint256 feeDistBufferNew = _inToken.getBufferAmountByFlowRate(maxFeeDistRate);
return SafeCast.toUint256(maxCoreBackAdjustment) +
(feeDistBufferNew > _feeDistBuffer ? feeDistBufferNew - _feeDistBuffer : 0);
}
/// @inheritdoc ITorex
function moveLiquidity(bytes calldata moverData) external override returns (LiquidityMoveResult memory result) {
result = _moveLiquidity(moverData);
assert(controller.onLiquidityMoved(result));
{
bool requireSafeCallback = true; // always require safe callback to not block liquidity movements
bytes memory callData = abi.encodeCall(controller.onLiquidityMoved, (result));
_callControllerHook(requireSafeCallback, callData);
}
emit LiquidityMoved(msg.sender,
result.durationSinceLastLME, result.twapSinceLastLME,
result.inAmount, result.minOutAmount,
result.outAmount, result.actualOutAmount);
}
/*******************************************************************************************************************
* Misc
******************************************************************************************************************/
/// Additional debuggin details
function debugCurrentDetails() external view
returns (int96 requestedFeeDistFlowRate, int96 actualFeeDistFlowRate, uint256 feeDistBuffer)
{
return (_requestedFeeDistFlowRate, _actualFeeDistFlowRate, _feeDistBuffer);
}
/*******************************************************************************************************************
* Safe Controller Hook Functions
******************************************************************************************************************/
/// Call controller hook and handle its potential errors.
function _callControllerHook(bool safeCallback, bytes memory callData) internal
returns (bool success, bytes memory returnedData)
{
if (safeCallback) {
bool insufficientCallbackGasProvided;
(success, insufficientCallbackGasProvided, returnedData) =
CallbackUtils.externalCall(address(controller), callData, CONTROLLER_SAFE_CALLBACK_GAS_LIMIT);
if (!success) {
if (insufficientCallbackGasProvided) {
// This will consume all the reset of the gas, propagating the callback's out-of-gas error up.
CallbackUtils.consumeAllGas();
} else {
_emitControllerError(returnedData);
}
}
} else {
// solhint-disable-next-line avoid-low-level-calls
(success, returnedData) = address(controller).call(callData);
if (!success) {
revert(string(returnedData));
}
}
}
/// Safely decode onInFlowChanged hook result without reverting.
function _safeDecodeFeeFlowRate(bool requireSafeCallback, bytes memory data) internal
returns (int96 v)
{
if (requireSafeCallback) {
if (data.length != 32) _emitControllerError("safeDecodeFeeFlowRate: 1");
else {
(uint256 vv) = abi.decode(data, (uint256));
if (vv > uint256(int256(type(int96).max))) _emitControllerError("safeDecodeFeeFlowRate: 2");
else v = int96(uint96(vv));
}
} else {
return abi.decode(data, (int96));
}
}
function _emitControllerError(bytes memory reason) internal {
emit ControllerError(reason);
++controllerInternalErrorCounter;
}
}// 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
pragma solidity >= 0.8.11;
// ISuperfluid.sol can also be used as an umbrella-import for everything Superfluid, hence we should have these unused
// import.
//
// solhint-disable no-unused-import
/// Global definitions
import {
SuperAppDefinitions,
ContextDefinitions,
FlowOperatorDefinitions,
BatchOperation,
SuperfluidGovernanceConfigs
} from "./Definitions.sol";
/// Super token related interfaces:
/// Note: CustomSuperTokenBase is not included for people building CustomSuperToken.
import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.sol";
import { ISuperfluidToken } from "./ISuperfluidToken.sol";
import { ISuperToken } from "./ISuperToken.sol";
import { ISuperTokenFactory } from "./ISuperTokenFactory.sol";
import { ISETH } from "../tokens/ISETH.sol";
/// Superfluid/ERC20x NFTs
import { IFlowNFTBase } from "./IFlowNFTBase.sol";
import { IConstantOutflowNFT } from "./IConstantOutflowNFT.sol";
import { IConstantInflowNFT } from "./IConstantInflowNFT.sol";
import { IPoolAdminNFT } from "../agreements/gdav1/IPoolAdminNFT.sol";
import { IPoolMemberNFT } from "../agreements/gdav1/IPoolMemberNFT.sol";
/// Superfluid agreement interfaces:
import { ISuperAgreement } from "./ISuperAgreement.sol";
import { IConstantFlowAgreementV1 } from "../agreements/IConstantFlowAgreementV1.sol";
import { IInstantDistributionAgreementV1 } from "../agreements/IInstantDistributionAgreementV1.sol";
import { IGeneralDistributionAgreementV1, PoolConfig } from "../agreements/gdav1/IGeneralDistributionAgreementV1.sol";
import { ISuperfluidPool } from "../agreements/gdav1/ISuperfluidPool.sol";
/// Superfluid App interfaces:
import { ISuperApp } from "./ISuperApp.sol";
/// Superfluid governance
import { ISuperfluidGovernance } from "./ISuperfluidGovernance.sol";
/**
* @title Host interface
* @author Superfluid
* @notice This is the central contract of the system where super agreement, super app
* and super token features are connected.
*
* The Superfluid host contract is also the entry point for the protocol users,
* where batch call and meta transaction are provided for UX improvements.
*
*/
interface ISuperfluid {
/**************************************************************************
* Errors
*************************************************************************/
// Superfluid Custom Errors
error HOST_AGREEMENT_CALLBACK_IS_NOT_ACTION(); // 0xef4295f6
error HOST_CANNOT_DOWNGRADE_TO_NON_UPGRADEABLE(); // 0x474e7641
error HOST_CALL_AGREEMENT_WITH_CTX_FROM_WRONG_ADDRESS(); // 0x0cd0ebc2
error HOST_CALL_APP_ACTION_WITH_CTX_FROM_WRONG_ADDRESS(); // 0x473f7bd4
error HOST_INVALID_CONFIG_WORD(); // 0xf4c802a4
error HOST_MAX_256_AGREEMENTS(); // 0x7c281a78
error HOST_NON_UPGRADEABLE(); // 0x14f72c9f
error HOST_NON_ZERO_LENGTH_PLACEHOLDER_CTX(); // 0x67e9985b
error HOST_ONLY_GOVERNANCE(); // 0xc5d22a4e
error HOST_UNKNOWN_BATCH_CALL_OPERATION_TYPE(); // 0xb4770115
error HOST_AGREEMENT_ALREADY_REGISTERED(); // 0xdc9ddba8
error HOST_AGREEMENT_IS_NOT_REGISTERED(); // 0x1c9e9bea
error HOST_MUST_BE_CONTRACT(); // 0xd4f6b30c
error HOST_ONLY_LISTED_AGREEMENT(); // 0x619c5359
error HOST_NEED_MORE_GAS(); // 0xd4f5d496
// App Related Custom Errors
// uses SuperAppDefinitions' App Jail Reasons as _code
error APP_RULE(uint256 _code); // 0xa85ba64f
error HOST_NOT_A_SUPER_APP(); // 0x163cbe43
error HOST_NO_APP_REGISTRATION_PERMISSION(); // 0xb56455f0
error HOST_RECEIVER_IS_NOT_SUPER_APP(); // 0x96aa315e
error HOST_SENDER_IS_NOT_SUPER_APP(); // 0xbacfdc40
error HOST_SOURCE_APP_NEEDS_HIGHER_APP_LEVEL(); // 0x44725270
error HOST_SUPER_APP_IS_JAILED(); // 0x02384b64
error HOST_SUPER_APP_ALREADY_REGISTERED(); // 0x01b0a935
/**************************************************************************
* Time
*
* > The Oracle: You have the sight now, Neo. You are looking at the world without time.
* > Neo: Then why can't I see what happens to her?
* > The Oracle: We can never see past the choices we don't understand.
* > - The Oracle and Neo conversing about the future of Trinity and the effects of Neo's choices
*************************************************************************/
function getNow() external view returns (uint256);
/**************************************************************************
* Governance
*************************************************************************/
/**
* @dev Get the current governance address of the Superfluid host
*/
function getGovernance() external view returns(ISuperfluidGovernance governance);
/**
* @dev Replace the current governance with a new one
*/
function replaceGovernance(ISuperfluidGovernance newGov) external;
/**
* @dev Governance replaced event
* @param oldGov Address of the old governance contract
* @param newGov Address of the new governance contract
*/
event GovernanceReplaced(ISuperfluidGovernance oldGov, ISuperfluidGovernance newGov);
/**************************************************************************
* Agreement Whitelisting
*************************************************************************/
/**
* @dev Register a new agreement class to the system
* @param agreementClassLogic Initial agreement class code
*
* @custom:modifiers
* - onlyGovernance
*/
function registerAgreementClass(ISuperAgreement agreementClassLogic) external;
/**
* @notice Agreement class registered event
* @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
* @param agreementType The agreement type registered
* @param code Address of the new agreement
*/
event AgreementClassRegistered(bytes32 agreementType, address code);
/**
* @dev Update code of an agreement class
* @param agreementClassLogic New code for the agreement class
*
* @custom:modifiers
* - onlyGovernance
*/
function updateAgreementClass(ISuperAgreement agreementClassLogic) external;
/**
* @notice Agreement class updated event
* @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
* @param agreementType The agreement type updated
* @param code Address of the new agreement
*/
event AgreementClassUpdated(bytes32 agreementType, address code);
/**
* @notice Check if the agreement type is whitelisted
* @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
*/
function isAgreementTypeListed(bytes32 agreementType) external view returns(bool yes);
/**
* @dev Check if the agreement class is whitelisted
*/
function isAgreementClassListed(ISuperAgreement agreementClass) external view returns(bool yes);
/**
* @notice Get agreement class
* @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
*/
function getAgreementClass(bytes32 agreementType) external view returns(ISuperAgreement agreementClass);
/**
* @dev Map list of the agreement classes using a bitmap
* @param bitmap Agreement class bitmap
*/
function mapAgreementClasses(uint256 bitmap)
external view
returns (ISuperAgreement[] memory agreementClasses);
/**
* @notice Create a new bitmask by adding a agreement class to it
* @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
* @param bitmap Agreement class bitmap
*/
function addToAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType)
external view
returns (uint256 newBitmap);
/**
* @notice Create a new bitmask by removing a agreement class from it
* @dev agreementType is the keccak256 hash of: "org.superfluid-finance.agreements.<AGREEMENT_NAME>.<VERSION>"
* @param bitmap Agreement class bitmap
*/
function removeFromAgreementClassesBitmap(uint256 bitmap, bytes32 agreementType)
external view
returns (uint256 newBitmap);
/**************************************************************************
* Super Token Factory
**************************************************************************/
/**
* @dev Get the super token factory
* @return factory The factory
*/
function getSuperTokenFactory() external view returns (ISuperTokenFactory factory);
/**
* @dev Get the super token factory logic (applicable to upgradable deployment)
* @return logic The factory logic
*/
function getSuperTokenFactoryLogic() external view returns (address logic);
/**
* @dev Update super token factory
* @param newFactory New factory logic
*/
function updateSuperTokenFactory(ISuperTokenFactory newFactory) external;
/**
* @dev SuperToken factory updated event
* @param newFactory Address of the new factory
*/
event SuperTokenFactoryUpdated(ISuperTokenFactory newFactory);
/**
* @notice Update the super token logic to the latest (canonical) implementation
* if `newLogicOverride` is zero, or to `newLogicOverride` otherwise.
* or to the provided implementation `.
* @dev Refer to ISuperTokenFactory.Upgradability for expected behaviours
*/
function updateSuperTokenLogic(ISuperToken token, address newLogicOverride) external;
/**
* @notice Update the super token logic to the provided one
* @dev newLogic must implement UUPSProxiable with matching proxiableUUID
*/
event SuperTokenLogicUpdated(ISuperToken indexed token, address code);
/**
* @notice Change the SuperToken admin address
* @dev The admin is the only account allowed to update the token logic
* For backward compatibility, the "host" is the default "admin" if unset (address(0)).
*/
function changeSuperTokenAdmin(ISuperToken token, address newAdmin) external;
/**
* @notice Change the implementation address the pool beacon points to
* @dev Updating the logic the beacon points to will update the logic of all the Pool BeaconProxy instances
*/
function updatePoolBeaconLogic(address newBeaconLogic) external;
/**
* @dev Pool Beacon logic updated event
* @param beaconProxy addrss of the beacon proxy
* @param newBeaconLogic address of the new beacon logic
*/
event PoolBeaconLogicUpdated(address indexed beaconProxy, address newBeaconLogic);
/**************************************************************************
* App Registry
*************************************************************************/
/**
* @dev Message sender (must be a contract) registers itself as a super app.
* @param configWord The super app manifest configuration, flags are defined in
* `SuperAppDefinitions`
* @notice On some mainnet deployments, pre-authorization by governance may be needed for this to succeed.
* See https://github.com/superfluid-finance/protocol-monorepo/wiki/Super-App-White-listing-Guide
*/
function registerApp(uint256 configWord) external;
/**
* @dev Registers an app (must be a contract) as a super app.
* @param app The super app address
* @param configWord The super app manifest configuration, flags are defined in
* `SuperAppDefinitions`
* @notice On some mainnet deployments, pre-authorization by governance may be needed for this to succeed.
* See https://github.com/superfluid-finance/protocol-monorepo/wiki/Super-App-White-listing-Guide
*/
function registerApp(ISuperApp app, uint256 configWord) external;
/**
* @dev App registered event
* @param app Address of jailed app
*/
event AppRegistered(ISuperApp indexed app);
/**
* @dev DO NOT USE for new deployments
* @custom:deprecated you should use `registerApp(uint256 configWord) instead.
*/
function registerAppWithKey(uint256 configWord, string calldata registrationKey) external;
/**
* @dev DO NOT USE for new deployments
* @custom:deprecated you should use `registerApp(ISuperApp app, uint256 configWord) instead.
*/
function registerAppByFactory(ISuperApp app, uint256 configWord) external;
/**
* @dev Query if the app is registered
* @param app Super app address
*/
function isApp(ISuperApp app) external view returns(bool);
/**
* @dev Query app callbacklevel
* @param app Super app address
*/
function getAppCallbackLevel(ISuperApp app) external view returns(uint8 appCallbackLevel);
/**
* @dev Get the manifest of the super app
* @param app Super app address
*/
function getAppManifest(
ISuperApp app
)
external view
returns (
bool isSuperApp,
bool isJailed,
uint256 noopMask
);
/**
* @dev Query if the app has been jailed
* @param app Super app address
*/
function isAppJailed(ISuperApp app) external view returns (bool isJail);
/**
* @dev Whitelist the target app for app composition for the source app (msg.sender)
* @param targetApp The target super app address
*/
function allowCompositeApp(ISuperApp targetApp) external;
/**
* @dev Query if source app is allowed to call the target app as downstream app
* @param app Super app address
* @param targetApp The target super app address
*/
function isCompositeAppAllowed(
ISuperApp app,
ISuperApp targetApp
)
external view
returns (bool isAppAllowed);
/**************************************************************************
* Agreement Framework
*
* Agreements use these function to trigger super app callbacks, updates
* app credit and charge gas fees.
*
* These functions can only be called by registered agreements.
*************************************************************************/
/**
* @dev (For agreements) StaticCall the app before callback
* @param app The super app.
* @param callData The call data sending to the super app.
* @param isTermination Is it a termination callback?
* @param ctx Current ctx, it will be validated.
* @return cbdata Data returned from the callback.
*/
function callAppBeforeCallback(
ISuperApp app,
bytes calldata callData,
bool isTermination,
bytes calldata ctx
)
external
// onlyAgreement
// assertValidCtx(ctx)
returns(bytes memory cbdata);
/**
* @dev (For agreements) Call the app after callback
* @param app The super app.
* @param callData The call data sending to the super app.
* @param isTermination Is it a termination callback?
* @param ctx Current ctx, it will be validated.
* @return newCtx The current context of the transaction.
*/
function callAppAfterCallback(
ISuperApp app,
bytes calldata callData,
bool isTermination,
bytes calldata ctx
)
external
// onlyAgreement
// assertValidCtx(ctx)
returns(bytes memory newCtx);
/**
* @dev (For agreements) Create a new callback stack
* @param ctx The current ctx, it will be validated.
* @param app The super app.
* @param appCreditGranted App credit granted so far.
* @param appCreditUsed App credit used so far.
* @return newCtx The current context of the transaction.
*/
function appCallbackPush(
bytes calldata ctx,
ISuperApp app,
uint256 appCreditGranted,
int256 appCreditUsed,
ISuperfluidToken appCreditToken
)
external
// onlyAgreement
// assertValidCtx(ctx)
returns (bytes memory newCtx);
/**
* @dev (For agreements) Pop from the current app callback stack
* @param ctx The ctx that was pushed before the callback stack.
* @param appCreditUsedDelta App credit used by the app.
* @return newCtx The current context of the transaction.
*
* @custom:security
* - Here we cannot do assertValidCtx(ctx), since we do not really save the stack in memory.
* - Hence there is still implicit trust that the agreement handles the callback push/pop pair correctly.
*/
function appCallbackPop(
bytes calldata ctx,
int256 appCreditUsedDelta
)
external
// onlyAgreement
returns (bytes memory newCtx);
/**
* @dev (For agreements) Use app credit.
* @param ctx The current ctx, it will be validated.
* @param appCreditUsedMore See app credit for more details.
* @return newCtx The current context of the transaction.
*/
function ctxUseCredit(
bytes calldata ctx,
int256 appCreditUsedMore
)
external
// onlyAgreement
// assertValidCtx(ctx)
returns (bytes memory newCtx);
/**
* @dev (For agreements) Jail the app.
* @param app The super app.
* @param reason Jail reason code.
* @return newCtx The current context of the transaction.
*/
function jailApp(
bytes calldata ctx,
ISuperApp app,
uint256 reason
)
external
// onlyAgreement
// assertValidCtx(ctx)
returns (bytes memory newCtx);
/**
* @dev Jail event for the app
* @param app Address of jailed app
* @param reason Reason the app is jailed (see Definitions.sol for the full list)
*/
event Jail(ISuperApp indexed app, uint256 reason);
/**************************************************************************
* Contextless Call Proxies
*
* NOTE: For EOAs or non-app contracts, they are the entry points for interacting
* with agreements or apps.
*
* NOTE: The contextual call data should be generated using
* abi.encodeWithSelector. The context parameter should be set to "0x",
* an empty bytes array as a placeholder to be replaced by the host
* contract.
*************************************************************************/
/**
* @dev Call agreement function
* @param agreementClass The agreement address you are calling
* @param callData The contextual call data with placeholder ctx
* @param userData Extra user data being sent to the super app callbacks
*/
function callAgreement(
ISuperAgreement agreementClass,
bytes calldata callData,
bytes calldata userData
)
external
//cleanCtx
//isAgreement(agreementClass)
returns(bytes memory returnedData);
/**
* @notice Call app action
* @dev Main use case is calling app action in a batch call via the host
* @param callData The contextual call data
*
* @custom:note See "Contextless Call Proxies" above for more about contextual call data.
*/
function callAppAction(
ISuperApp app,
bytes calldata callData
)
external
//cleanCtx
//isAppActive(app)
//isValidAppAction(callData)
returns(bytes memory returnedData);
/**************************************************************************
* Contextual Call Proxies and Context Utilities
*
* For apps, they must use context they receive to interact with
* agreements or apps.
*
* The context changes must be saved and returned by the apps in their
* callbacks always, any modification to the context will be detected and
* the violating app will be jailed.
*************************************************************************/
/**
* @dev Context Struct
*
* @custom:note on backward compatibility:
* - Non-dynamic fields are padded to 32bytes and packed
* - Dynamic fields are referenced through a 32bytes offset to their "parents" field (or root)
* - The order of the fields hence should not be rearranged in order to be backward compatible:
* - non-dynamic fields will be parsed at the same memory location,
* - and dynamic fields will simply have a greater offset than it was.
* - We cannot change the structure of the Context struct because of ABI compatibility requirements
*/
struct Context {
//
// Call context
//
// app callback level
uint8 appCallbackLevel;
// type of call
uint8 callType;
// the system timestamp
uint256 timestamp;
// The intended message sender for the call
address msgSender;
//
// Callback context
//
// For callbacks it is used to know which agreement function selector is called
bytes4 agreementSelector;
// User provided data for app callbacks
bytes userData;
//
// App context
//
// app credit granted
uint256 appCreditGranted;
// app credit wanted by the app callback
uint256 appCreditWantedDeprecated;
// app credit used, allowing negative values over a callback session
// the appCreditUsed value over a callback sessions is calculated with:
// existing flow data owed deposit + sum of the callback agreements
// deposit deltas
// the final value used to modify the state is determined by the
// _adjustNewAppCreditUsed function (in AgreementLibrary.sol) which takes
// the appCreditUsed value reached in the callback session and the app
// credit granted
int256 appCreditUsed;
// app address
address appAddress;
// app credit in super token
ISuperfluidToken appCreditToken;
}
function callAgreementWithContext(
ISuperAgreement agreementClass,
bytes calldata callData,
bytes calldata userData,
bytes calldata ctx
)
external
// requireValidCtx(ctx)
// onlyAgreement(agreementClass)
returns (bytes memory newCtx, bytes memory returnedData);
function callAppActionWithContext(
ISuperApp app,
bytes calldata callData,
bytes calldata ctx
)
external
// requireValidCtx(ctx)
// isAppActive(app)
returns (bytes memory newCtx);
function decodeCtx(bytes memory ctx)
external pure
returns (Context memory context);
function isCtxValid(bytes calldata ctx) external view returns (bool);
/**************************************************************************
* Batch call
**************************************************************************/
/**
* @dev Batch operation data
*/
struct Operation {
// Operation type. Defined in BatchOperation (Definitions.sol)
uint32 operationType;
// Operation target
address target;
// Data specific to the operation
bytes data;
}
/**
* @dev Batch call function
* @param operations Array of batch operations
*
* 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;
/**************************************************************************
* 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 { ISuperfluid, ISuperToken, ISuperApp, SuperAppDefinitions } from "../interfaces/superfluid/ISuperfluid.sol";
import { SuperTokenV1Library } from "./SuperTokenV1Library.sol";
/**
* @title abstract base contract for SuperApps using CFA callbacks
* @author Superfluid
* @dev This contract provides a more convenient API for implementing CFA callbacks.
* It allows to write more concise and readable SuperApps when the full flexibility
* of the low-level agreement callbacks isn't needed.
* The API is tailored for the most common use cases, with the "beforeX" and "afterX" callbacks being
* abstrated into a single "onX" callback for create|update|delete flows.
* For use cases requiring more flexibility (specifically if more data needs to be provided by the before callbacks)
* it's recommended to implement the low-level callbacks directly instead of using this base contract.
*/
abstract contract CFASuperAppBase is ISuperApp {
using SuperTokenV1Library for ISuperToken;
bytes32 public constant CFAV1_TYPE = keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1");
ISuperfluid public immutable HOST;
/// @dev Thrown when the callback caller is not the host.
error UnauthorizedHost();
/// @dev Thrown if a required callback wasn't implemented (overridden by the SuperApp)
error NotImplemented();
/// @dev Thrown when SuperTokens not accepted by the SuperApp are streamed to it
error NotAcceptedSuperToken();
/**
* @dev Creates the contract tied to the provided Superfluid host
* @param host_ the Superfluid host the SuperApp belongs to
* @notice You also need to register the app with the host in order to enable callbacks.
* This can be done either by calling `selfRegister()` or by calling `host.registerApp()`.
*/
constructor(ISuperfluid host_) {
HOST = host_;
}
/**
* @dev Registers the SuperApp with its Superfluid host contract (self-registration)
* @param activateOnCreated if true, callbacks for `createFlow` will be activated
* @param activateOnUpdated if true, callbacks for `updateFlow` will be activated
* @param activateOnDeleted if true, callbacks for `deleteFlow` will be activated
*
* Note: if the App self-registers on a network with permissioned SuperApp registration,
* self-registration can be used only if the tx.origin (EOA) is whitelisted as deployer.
* If a whitelisted factory is used, it needs to call `host.registerApp()` itself.
* For more details, see https://github.com/superfluid-finance/protocol-monorepo/wiki/Super-App-White-listing-Guide
*/
function selfRegister(
bool activateOnCreated,
bool activateOnUpdated,
bool activateOnDeleted
) public {
HOST.registerApp(getConfigWord(activateOnCreated, activateOnUpdated, activateOnDeleted));
}
/**
* @dev Convenience function to get the `configWord` for app registration when not using self-registration
* @param activateOnCreated if true, callbacks for `createFlow` will be activated
* @param activateOnUpdated if true, callbacks for `updateFlow` will be activated
* @param activateOnDeleted if true, callbacks for `deleteFlow` will be activated
* @return configWord the `configWord` encoding the provided settings
*/
function getConfigWord(
bool activateOnCreated,
bool activateOnUpdated,
bool activateOnDeleted
) public pure returns (uint256 configWord) {
configWord = SuperAppDefinitions.APP_LEVEL_FINAL
| SuperAppDefinitions.BEFORE_AGREEMENT_CREATED_NOOP;
if (!activateOnCreated) {
configWord |= SuperAppDefinitions.AFTER_AGREEMENT_CREATED_NOOP;
}
if (!activateOnUpdated) {
configWord |= SuperAppDefinitions.BEFORE_AGREEMENT_UPDATED_NOOP
| SuperAppDefinitions.AFTER_AGREEMENT_UPDATED_NOOP;
}
if (!activateOnDeleted) {
configWord |= SuperAppDefinitions.BEFORE_AGREEMENT_TERMINATED_NOOP
| SuperAppDefinitions.AFTER_AGREEMENT_TERMINATED_NOOP;
}
}
/**
* @dev Optional (positive) filter for accepting only specific SuperTokens.
* The default implementation accepts all SuperTokens.
* Can be overridden by the SuperApp in order to apply arbitrary filters.
*/
function isAcceptedSuperToken(ISuperToken /*superToken*/) public view virtual returns (bool) {
return true;
}
// ---------------------------------------------------------------------------------------------
// CFA specific convenience callbacks
// to be overridden and implemented by inheriting SuperApps
/// @dev override if the SuperApp shall have custom logic invoked when a new flow
/// to it is created.
function onFlowCreated(
ISuperToken /*superToken*/,
address /*sender*/,
bytes calldata ctx
) internal virtual returns (bytes memory /*newCtx*/) {
return ctx;
}
/// @dev override if the SuperApp shall have custom logic invoked when an existing flow
/// to it is updated (flowrate change).
function onFlowUpdated(
ISuperToken /*superToken*/,
address /*sender*/,
int96 /*previousFlowRate*/,
uint256 /*lastUpdated*/,
bytes calldata ctx
) internal virtual returns (bytes memory /*newCtx*/) {
return ctx;
}
/// @dev override if the SuperApp shall have custom logic invoked when an existing flow
/// to it is deleted (flowrate set to 0).
/// Unlike the other callbacks, this method is NOT allowed to revert.
/// Failing to satisfy that requirement leads to jailing (defunct SuperApp).
function onFlowDeleted(
ISuperToken /*superToken*/,
address /*sender*/,
address /*receiver*/,
int96 /*previousFlowRate*/,
uint256 /*lastUpdated*/,
bytes calldata ctx
) internal virtual returns (bytes memory /*newCtx*/) {
return ctx;
}
// ---------------------------------------------------------------------------------------------
// Low-level callbacks
// Shall NOT be overriden by SuperApps when inheriting from this contract.
// The before-callbacks are implemented to forward data (flowrate, timestamp),
// the after-callbacks invoke the CFA specific specific convenience callbacks.
// CREATED callback
// Empty implementation to fulfill the interface - is never called because disabled in the app manifest.
function beforeAgreementCreated(
ISuperToken /*superToken*/,
address /*agreementClass*/,
bytes32 /*agreementId*/,
bytes calldata /*agreementData*/,
bytes calldata /*ctx*/
) external pure override returns (bytes memory /*beforeData*/) {
return "0x";
}
function afterAgreementCreated(
ISuperToken superToken,
address agreementClass,
bytes32 /*agreementId*/,
bytes calldata agreementData,
bytes calldata /*cbdata*/,
bytes calldata ctx
) external override returns (bytes memory newCtx) {
if (msg.sender != address(HOST)) revert UnauthorizedHost();
if (!isAcceptedAgreement(agreementClass)) return ctx;
if (!isAcceptedSuperToken(superToken)) revert NotAcceptedSuperToken();
(address sender, ) = abi.decode(agreementData, (address, address));
return
onFlowCreated(
superToken,
sender,
ctx // userData can be acquired with `host.decodeCtx(ctx).userData`
);
}
// UPDATED callbacks
function beforeAgreementUpdated(
ISuperToken superToken,
address agreementClass,
bytes32 /*agreementId*/,
bytes calldata agreementData,
bytes calldata /*ctx*/
) external view override returns (bytes memory /*beforeData*/) {
if (msg.sender != address(HOST)) revert UnauthorizedHost();
if (!isAcceptedAgreement(agreementClass)) return "0x";
if (!isAcceptedSuperToken(superToken)) revert NotAcceptedSuperToken();
(address sender, ) = abi.decode(agreementData, (address, address));
(uint256 lastUpdated, int96 flowRate,,) = superToken.getFlowInfo(sender, address(this));
return abi.encode(
flowRate,
lastUpdated
);
}
function afterAgreementUpdated(
ISuperToken superToken,
address agreementClass,
bytes32 /*agreementId*/,
bytes calldata agreementData,
bytes calldata cbdata,
bytes calldata ctx
) external override returns (bytes memory newCtx) {
if (msg.sender != address(HOST)) revert UnauthorizedHost();
if (!isAcceptedAgreement(agreementClass)) return ctx;
if (!isAcceptedSuperToken(superToken)) revert NotAcceptedSuperToken();
(address sender, ) = abi.decode(agreementData, (address, address));
(int96 previousFlowRate, uint256 lastUpdated) = abi.decode(cbdata, (int96, uint256));
return
onFlowUpdated(
superToken,
sender,
previousFlowRate,
lastUpdated,
ctx // userData can be acquired with `host.decodeCtx(ctx).userData`
);
}
// DELETED callbacks
function beforeAgreementTerminated(
ISuperToken superToken,
address agreementClass,
bytes32 /*agreementId*/,
bytes calldata agreementData,
bytes calldata /*ctx*/
) external view override returns (bytes memory /*beforeData*/) {
// we're not allowed to revert in this callback, thus just return empty beforeData on failing checks
if (msg.sender != address(HOST)
|| !isAcceptedAgreement(agreementClass)
|| !isAcceptedSuperToken(superToken))
{
return "0x";
}
(address sender, address receiver) = abi.decode(agreementData, (address, address));
(uint256 lastUpdated, int96 flowRate,,) = superToken.getFlowInfo(sender, receiver);
return abi.encode(
lastUpdated,
flowRate
);
}
function afterAgreementTerminated(
ISuperToken superToken,
address agreementClass,
bytes32 /*agreementId*/,
bytes calldata agreementData,
bytes calldata cbdata,
bytes calldata ctx
) external override returns (bytes memory newCtx) {
// we're not allowed to revert in this callback, thus just return ctx on failing checks
if (msg.sender != address(HOST)
|| !isAcceptedAgreement(agreementClass)
|| !isAcceptedSuperToken(superToken))
{
return ctx;
}
(address sender, address receiver) = abi.decode(agreementData, (address, address));
(uint256 lastUpdated, int96 previousFlowRate) = abi.decode(cbdata, (uint256, int96));
return
onFlowDeleted(
superToken,
sender,
receiver,
previousFlowRate,
lastUpdated,
ctx
);
}
// ---------------------------------------------------------------------------------------------
// HELPERS
/**
* @dev Expect Super Agreement involved in callback to be an accepted one
* This function can be overridden with custom logic and to revert if desired
* Current implementation expects ConstantFlowAgreement
*/
function isAcceptedAgreement(address agreementClass) internal view virtual returns (bool) {
return agreementClass == address(HOST.getAgreementClass(CFAV1_TYPE));
}
}// SPDX-License-Identifier: 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: MIT
pragma solidity >= 0.8.11;
import {
ISuperfluid,
ISuperToken,
IConstantFlowAgreementV1,
IInstantDistributionAgreementV1
} from "../interfaces/superfluid/ISuperfluid.sol";
import {
IGeneralDistributionAgreementV1,
ISuperfluidPool,
PoolConfig
} from "../interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol";
/**
* @title Library for Token Centric Interface
* @author Superfluid
* @dev Set `using for ISuperToken` in including file, and call any of these functions on an instance
* of ISuperToken.
* Note that it is important to "warm up" the cache and cache the host, cfa, ida before calling,
* this is only applicable to Foundry tests where the vm.expectRevert() will not work as expected.
* You must use vm.startPrank(account) instead of vm.prank when executing functions if the cache
* isn't "warmed up" yet. vm.prank impersonates the account only for the first call, which will be
* used for caching.
*/
library SuperTokenV1Library {
/** CFA BASE CRUD ************************************* */
/**
* @dev Create flow without userData
* @param token The token used in flow
* @param receiver The receiver of the flow
* @param flowRate The desired flowRate
*/
function createFlow(ISuperToken token, address receiver, int96 flowRate)
internal returns (bool)
{
return createFlow(token, receiver, flowRate, new bytes(0));
}
/**
* @dev Create flow with userData
* @param token The token used in flow
* @param receiver The receiver of the flow
* @param flowRate The desired flowRate
* @param userData The userdata passed along with call
*/
function createFlow(ISuperToken token, address receiver, int96 flowRate, bytes memory userData)
internal returns (bool)
{
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
host.callAgreement(
cfa,
abi.encodeCall(
cfa.createFlow,
(token, receiver, flowRate, new bytes(0))
),
userData // userData
);
return true;
}
/**
* @dev Update flow without userData
* @param token The token used in flow
* @param receiver The receiver of the flow
* @param flowRate The desired flowRate
*/
function updateFlow(ISuperToken token, address receiver, int96 flowRate)
internal returns (bool)
{
return updateFlow(token, receiver, flowRate, new bytes(0));
}
/**
* @dev Update flow with userData
* @param token The token used in flow
* @param receiver The receiver of the flow
* @param flowRate The desired flowRate
* @param userData The userdata passed along with call
*/
function updateFlow(ISuperToken token, address receiver, int96 flowRate, bytes memory userData)
internal returns (bool)
{
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
host.callAgreement(
cfa,
abi.encodeCall(
cfa.updateFlow,
(token, receiver, flowRate, new bytes(0))
),
userData
);
return true;
}
/**
* @dev Delete flow without userData
* @param token The token used in flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
*/
function deleteFlow(ISuperToken token, address sender, address receiver)
internal returns (bool)
{
return deleteFlow(token, sender, receiver, new bytes(0));
}
/**
* @dev Delete flow with userData
* @param token The token used in flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
* @param userData The userdata passed along with call
*/
function deleteFlow(ISuperToken token, address sender, address receiver, bytes memory userData)
internal returns (bool)
{
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
host.callAgreement(
cfa,
abi.encodeCall(
cfa.deleteFlow,
(token, sender, receiver, new bytes(0))
),
userData
);
return true;
}
/** CFA ACL ************************************* */
/**
* @dev Update permissions for flow operator
* @param token The token used in flow
* @param flowOperator The address given flow permissions
* @param allowCreate creation permissions
* @param allowCreate update permissions
* @param allowCreate deletion permissions
* @param flowRateAllowance The allowance provided to flowOperator
*/
function setFlowPermissions(
ISuperToken token,
address flowOperator,
bool allowCreate,
bool allowUpdate,
bool allowDelete,
int96 flowRateAllowance
) internal returns (bool) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
uint8 permissionsBitmask = (allowCreate ? 1 : 0)
| (allowUpdate ? 1 : 0) << 1
| (allowDelete ? 1 : 0) << 2;
host.callAgreement(
cfa,
abi.encodeCall(
cfa.updateFlowOperatorPermissions,
(token, flowOperator, permissionsBitmask, flowRateAllowance, new bytes(0))
),
new bytes(0)
);
return true;
}
/**
* @dev Update permissions for flow operator - give operator max permissions
* @param token The token used in flow
* @param flowOperator The address given flow permissions
*/
function setMaxFlowPermissions(
ISuperToken token,
address flowOperator
) internal returns (bool) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
host.callAgreement(
cfa,
abi.encodeCall(
cfa.authorizeFlowOperatorWithFullControl,
(token, flowOperator, new bytes(0))
),
new bytes(0)
);
return true;
}
/**
* @dev Update permissions for flow operator - revoke all permission
* @param token The token used in flow
* @param flowOperator The address given flow permissions
*/
function revokeFlowPermissions(
ISuperToken token,
address flowOperator
) internal returns (bool) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
host.callAgreement(
cfa,
abi.encodeCall(
cfa.revokeFlowOperatorWithFullControl,
(token, flowOperator, new bytes(0))
),
new bytes(0)
);
return true;
}
/**
* @dev Increases the flow rate allowance for flow operator
* @notice allowing userData to be a parameter here triggered stack too deep error
* @param token The token used in flow
* @param flowOperator The address whose flow rate allowance is increased
* @param addedFlowRateAllowance amount to increase allowance by
*/
function increaseFlowRateAllowance(ISuperToken token, address flowOperator, int96 addedFlowRateAllowance)
internal
returns (bool)
{
return increaseFlowRateAllowance(token, flowOperator, addedFlowRateAllowance, new bytes(0));
}
/**
* @dev Increases the flow rate allowance for flow operator
* @notice allowing userData to be a parameter here triggered stack too deep error
* @param token The token used in flow
* @param flowOperator The address whose flow rate allowance is increased
* @param addedFlowRateAllowance amount to increase allowance by
* @param userData The userdata passed along with call
*/
function increaseFlowRateAllowance(
ISuperToken token,
address flowOperator,
int96 addedFlowRateAllowance,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
host.callAgreement(
cfa,
abi.encodeCall(cfa.increaseFlowRateAllowance, (token, flowOperator, addedFlowRateAllowance, new bytes(0))),
userData
);
return true;
}
/**
* @dev Decreases the flow rate allowance for flow operator
* @notice allowing userData to be a parameter here triggered stack too deep error
* @param token The token used in flow
* @param flowOperator The address whose flow rate allowance is decreased
* @param subtractedFlowRateAllowance amount to decrease allowance by
*/
function decreaseFlowRateAllowance(ISuperToken token, address flowOperator, int96 subtractedFlowRateAllowance)
internal
returns (bool)
{
return decreaseFlowRateAllowance(token, flowOperator, subtractedFlowRateAllowance, new bytes(0));
}
/**
* @dev Decreases the flow rate allowance for flow operator
* @notice allowing userData to be a parameter here triggered stack too deep error
* @param token The token used in flow
* @param flowOperator The address whose flow rate allowance is decreased
* @param subtractedFlowRateAllowance amount to decrease allowance by
* @param userData The userdata passed along with call
*/
function decreaseFlowRateAllowance(
ISuperToken token,
address flowOperator,
int96 subtractedFlowRateAllowance,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
host.callAgreement(
cfa,
abi.encodeCall(
cfa.decreaseFlowRateAllowance, (token, flowOperator, subtractedFlowRateAllowance, new bytes(0))
),
userData
);
return true;
}
/**
* @dev Increases the flow rate allowance for flow operator and adds the permissions
* @notice allowing userData to be a parameter here triggered stack too deep error
* @param token The token used in flow
* @param flowOperator The address whose flow rate allowance is increased
* @param permissionsToAdd The permissions to add for the flow operator
* @param addedFlowRateAllowance amount to increase allowance by
*/
function increaseFlowRateAllowanceWithPermissions(
ISuperToken token,
address flowOperator,
uint8 permissionsToAdd,
int96 addedFlowRateAllowance
) internal returns (bool) {
return
increaseFlowRateAllowanceWithPermissions(
token,
flowOperator,
permissionsToAdd,
addedFlowRateAllowance,
new bytes(0)
);
}
/**
* @dev Increases the flow rate allowance for flow operator and adds the permissions
* @notice allowing userData to be a parameter here triggered stack too deep error
* @param token The token used in flow
* @param flowOperator The address whose flow rate allowance is increased
* @param permissionsToAdd The permissions to add for the flow operator
* @param addedFlowRateAllowance amount to increase allowance by
* @param userData The userdata passed along with call
*/
function increaseFlowRateAllowanceWithPermissions(
ISuperToken token,
address flowOperator,
uint8 permissionsToAdd,
int96 addedFlowRateAllowance,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
host.callAgreement(
cfa,
abi.encodeCall(
cfa.increaseFlowRateAllowanceWithPermissions,
(token, flowOperator, permissionsToAdd, addedFlowRateAllowance, new bytes(0))
),
userData
);
return true;
}
/**
* @dev Decreases the flow rate allowance for flow operator and removes the permissions
* @notice allowing userData to be a parameter here triggered stack too deep error
* @param token The token used in flow
* @param flowOperator The address whose flow rate allowance is subtracted
* @param permissionsToRemove The permissions to remove for the flow operator
* @param subtractedFlowRateAllowance amount to subtract allowance by
*/
function decreaseFlowRateAllowanceWithPermissions(
ISuperToken token,
address flowOperator,
uint8 permissionsToRemove,
int96 subtractedFlowRateAllowance
) internal returns (bool) {
return decreaseFlowRateAllowanceWithPermissions(
token, flowOperator, permissionsToRemove, subtractedFlowRateAllowance, new bytes(0)
);
}
/**
* @dev Decreases the flow rate allowance for flow operator and removes the permissions
* @notice allowing userData to be a parameter here triggered stack too deep error
* @param token The token used in flow
* @param flowOperator The address whose flow rate allowance is subtracted
* @param permissionsToRemove The permissions to remove for the flow operator
* @param subtractedFlowRateAllowance amount to subtract allowance by
* @param userData The userdata passed along with call
*/
function decreaseFlowRateAllowanceWithPermissions(
ISuperToken token,
address flowOperator,
uint8 permissionsToRemove,
int96 subtractedFlowRateAllowance,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
host.callAgreement(
cfa,
abi.encodeCall(
cfa.decreaseFlowRateAllowanceWithPermissions,
(token, flowOperator, permissionsToRemove, subtractedFlowRateAllowance, new bytes(0))
),
userData
);
return true;
}
/**
* @dev Update permissions for flow operator in callback
* @notice allowing userData to be a parameter here triggered stack too deep error
* @param token The token used in flow
* @param flowOperator The address given flow permissions
* @param allowCreate creation permissions
* @param allowCreate update permissions
* @param allowCreate deletion permissions
* @param flowRateAllowance The allowance provided to flowOperator
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function setFlowPermissionsWithCtx(
ISuperToken token,
address flowOperator,
bool allowCreate,
bool allowUpdate,
bool allowDelete,
int96 flowRateAllowance,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
uint8 permissionsBitmask = (allowCreate ? 1 : 0)
| (allowUpdate ? 1 : 0) << 1
| (allowDelete ? 1 : 0) << 2;
(newCtx, ) = host.callAgreementWithContext(
cfa,
abi.encodeCall(
cfa.updateFlowOperatorPermissions,
(
token,
flowOperator,
permissionsBitmask,
flowRateAllowance,
new bytes(0)
)
),
"0x",
ctx
);
}
/**
* @dev Update permissions for flow operator - give operator max permissions
* @param token The token used in flow
* @param flowOperator The address given flow permissions
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function setMaxFlowPermissionsWithCtx(
ISuperToken token,
address flowOperator,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
(newCtx, ) = host.callAgreementWithContext(
cfa,
abi.encodeCall(
cfa.authorizeFlowOperatorWithFullControl,
(
token,
flowOperator,
new bytes(0)
)
),
"0x",
ctx
);
}
/**
* @dev Update permissions for flow operator - revoke all permission
* @param token The token used in flow
* @param flowOperator The address given flow permissions
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function revokeFlowPermissionsWithCtx(
ISuperToken token,
address flowOperator,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
(newCtx, ) = host.callAgreementWithContext(
cfa,
abi.encodeCall(
cfa.revokeFlowOperatorWithFullControl,
(token, flowOperator, new bytes(0))
),
"0x",
ctx
);
}
/**
* @dev Creates flow as an operator without userData
* @param token The token to flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
* @param flowRate The desired flowRate
*/
function createFlowFrom(
ISuperToken token,
address sender,
address receiver,
int96 flowRate
) internal returns (bool) {
return createFlowFrom(token, sender, receiver, flowRate, new bytes(0));
}
/**
* @dev Creates flow as an operator with userData
* @param token The token to flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
* @param flowRate The desired flowRate
* @param userData The user provided data
*/
function createFlowFrom(
ISuperToken token,
address sender,
address receiver,
int96 flowRate,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
host.callAgreement(
cfa,
abi.encodeCall(
cfa.createFlowByOperator,
(token, sender, receiver, flowRate, new bytes(0))
),
userData
);
return true;
}
/**
* @dev Updates flow as an operator without userData
* @param token The token to flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
* @param flowRate The desired flowRate
*/
function updateFlowFrom(
ISuperToken token,
address sender,
address receiver,
int96 flowRate
) internal returns (bool) {
return updateFlowFrom(token, sender, receiver, flowRate, new bytes(0));
}
/**
* @dev Updates flow as an operator with userData
* @param token The token to flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
* @param flowRate The desired flowRate
* @param userData The user provided data
*/
function updateFlowFrom(
ISuperToken token,
address sender,
address receiver,
int96 flowRate,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
host.callAgreement(
cfa,
abi.encodeCall(
cfa.updateFlowByOperator,
(token, sender, receiver, flowRate, new bytes(0))
),
userData
);
return true;
}
/**
* @dev Deletes flow as an operator without userData
* @param token The token to flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
*/
function deleteFlowFrom(
ISuperToken token,
address sender,
address receiver
) internal returns (bool) {
return deleteFlowFrom(token, sender, receiver, new bytes(0));
}
/**
* @dev Deletes flow as an operator with userData
* @param token The token to flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
* @param userData The user provided data
*/
function deleteFlowFrom(
ISuperToken token,
address sender,
address receiver,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
host.callAgreement(
cfa,
abi.encodeCall(
cfa.deleteFlowByOperator,
(token, sender, receiver, new bytes(0))
),
userData
);
return true;
}
/** CFA With CTX FUNCTIONS ************************************* */
/**
* @dev Create flow with context and userData
* @param token The token to flow
* @param receiver The receiver of the flow
* @param flowRate The desired flowRate
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function createFlowWithCtx(
ISuperToken token,
address receiver,
int96 flowRate,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
(newCtx, ) = host.callAgreementWithContext(
cfa,
abi.encodeCall(
cfa.createFlow,
(
token,
receiver,
flowRate,
new bytes(0) // placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Create flow by operator with context
* @param token The token to flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
* @param flowRate The desired flowRate
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function createFlowFromWithCtx(
ISuperToken token,
address sender,
address receiver,
int96 flowRate,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
(newCtx, ) = host.callAgreementWithContext(
cfa,
abi.encodeCall(
cfa.createFlowByOperator,
(
token,
sender,
receiver,
flowRate,
new bytes(0) // placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Update flow with context
* @param token The token to flow
* @param receiver The receiver of the flow
* @param flowRate The desired flowRate
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function updateFlowWithCtx(
ISuperToken token,
address receiver,
int96 flowRate,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
(newCtx, ) = host.callAgreementWithContext(
cfa,
abi.encodeCall(
cfa.updateFlow,
(
token,
receiver,
flowRate,
new bytes(0) // placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Update flow by operator with context
* @param token The token to flow
* @param sender The receiver of the flow
* @param receiver The receiver of the flow
* @param flowRate The desired flowRate
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function updateFlowFromWithCtx(
ISuperToken token,
address sender,
address receiver,
int96 flowRate,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
(newCtx, ) = host.callAgreementWithContext(
cfa,
abi.encodeCall(
cfa.updateFlowByOperator,
(
token,
sender,
receiver,
flowRate,
new bytes(0) // placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Delete flow with context
* @param token The token to flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function deleteFlowWithCtx(
ISuperToken token,
address sender,
address receiver,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
(newCtx, ) = host.callAgreementWithContext(
cfa,
abi.encodeCall(
cfa.deleteFlow,
(
token,
sender,
receiver,
new bytes(0) // placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Delete flow by operator with context
* @param token The token to flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function deleteFlowFromWithCtx(
ISuperToken token,
address sender,
address receiver,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IConstantFlowAgreementV1 cfa) = _getAndCacheHostAndCFA(token);
(newCtx, ) = host.callAgreementWithContext(
cfa,
abi.encodeCall(
cfa.deleteFlowByOperator,
(
token,
sender,
receiver,
new bytes(0) // placeholder
)
),
"0x",
ctx
);
}
/** CFA VIEW FUNCTIONS ************************************* */
/**
* @dev get flow rate between two accounts for given token
* @param token The token used in flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
* @return flowRate The flow rate
*/
function getFlowRate(ISuperToken token, address sender, address receiver)
internal view returns(int96 flowRate)
{
(, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token);
(, flowRate, , ) = cfa.getFlow(token, sender, receiver);
}
/**
* @dev get flow info between two accounts for given token
* @param token The token used in flow
* @param sender The sender of the flow
* @param receiver The receiver of the flow
* @return lastUpdated Timestamp of flow creation or last flowrate change
* @return flowRate The flow rate
* @return deposit The amount of deposit the flow
* @return owedDeposit The amount of owed deposit of the flow
*/
function getFlowInfo(ISuperToken token, address sender, address receiver)
internal view
returns(uint256 lastUpdated, int96 flowRate, uint256 deposit, uint256 owedDeposit)
{
(, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token);
(lastUpdated, flowRate, deposit, owedDeposit) = cfa.getFlow(token, sender, receiver);
}
/**
* @dev get flow info of a distributor to a pool for given token
* @param token The token used in flow
* @param distributor The sitributor of the flow
* @param pool The GDA pool
* @return lastUpdated Timestamp of flow creation or last flowrate change
* @return flowRate The flow rate
* @return deposit The amount of deposit the flow
*/
function getGDAFlowInfo(ISuperToken token, address distributor, ISuperfluidPool pool)
internal view
returns(uint256 lastUpdated, int96 flowRate, uint256 deposit)
{
(, IGeneralDistributionAgreementV1 gda) = _getHostAndGDA(token);
return gda.getFlow(token, distributor, pool);
}
/* function getGDAFlowInfo(ISuperToken token, address distributor, ISuperfluidPool pool) */
/* { */
/* } */
/**
* @dev get net flow rate for given account for given token (CFA + GDA)
* @param token Super token address
* @param account Account to query
* @return flowRate The net flow rate of the account
*/
function getNetFlowRate(ISuperToken token, address account)
internal view returns (int96 flowRate)
{
(, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token);
(, IGeneralDistributionAgreementV1 gda) = _getHostAndGDA(token);
int96 cfaNetFlow = cfa.getNetFlow(token, account);
int96 gdaNetFlow = gda.getNetFlow(token, account);
return cfaNetFlow + gdaNetFlow;
}
/**
* @dev get CFA net flow rate for given account for given token
* @param token Super token address
* @param account Account to query
* @return flowRate The net flow rate of the account
*/
function getCFANetFlowRate(ISuperToken token, address account)
internal view returns (int96 flowRate)
{
(, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token);
return cfa.getNetFlow(token, account);
}
/**
* @dev get GDA net flow rate for given account for given token
* @param token Super token address
* @param account Account to query
* @return flowRate The net flow rate of the account
*/
function getGDANetFlowRate(ISuperToken token, address account)
internal view returns (int96 flowRate)
{
(, IGeneralDistributionAgreementV1 gda) = _getHostAndGDA(token);
return gda.getNetFlow(token, account);
}
/**
* @dev get the aggregated flow info of the account (CFA + GDA)
* @param token Super token address
* @param account Account to query
* @return lastUpdated Timestamp of the last change of the net flow
* @return flowRate The net flow rate of token for account
* @return deposit The sum of all deposits for account's flows
* @return owedDeposit The sum of all owed deposits for account's flows
*/
function getNetFlowInfo(ISuperToken token, address account)
internal
view
returns (uint256 lastUpdated, int96 flowRate, uint256 deposit, uint256 owedDeposit)
{
(, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token);
(, IGeneralDistributionAgreementV1 gda) = _getHostAndGDA(token);
{
(uint256 lastUpdatedCFA, int96 cfaNetFlowRate, uint256 cfaDeposit, uint256 cfaOwedDeposit) =
cfa.getAccountFlowInfo(token, account);
lastUpdated = lastUpdatedCFA;
flowRate += cfaNetFlowRate;
deposit += cfaDeposit;
owedDeposit += cfaOwedDeposit;
}
{
(uint256 lastUpdatedGDA, int96 gdaNetFlowRate, uint256 gdaDeposit) = gda.getAccountFlowInfo(token, account);
if (lastUpdatedGDA > lastUpdated) {
lastUpdated = lastUpdatedGDA;
}
flowRate += gdaNetFlowRate;
deposit += gdaDeposit;
}
}
/**
* @dev get the aggregated CFA flow info of the account
* @param token Super token address
* @param account Account to query
* @return lastUpdated Timestamp of the last change of the net flow
* @return flowRate The net flow rate of token for account
* @return deposit The sum of all deposits for account's flows
* @return owedDeposit The sum of all owed deposits for account's flows
*/
function getCFANetFlowInfo(ISuperToken token, address account)
internal
view
returns (uint256 lastUpdated, int96 flowRate, uint256 deposit, uint256 owedDeposit)
{
(, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token);
return cfa.getAccountFlowInfo(token, account);
}
/**
* @dev get the aggregated GDA flow info of the account
* @param token Super token address
* @param account Account to query
* @return lastUpdated Timestamp of the last change of the net flow
* @return flowRate The net flow rate of token for account
* @return deposit The sum of all deposits for account's flows
* @return owedDeposit The sum of all owed deposits for account's flows
*/
function getGDANetFlowInfo(ISuperToken token, address account)
internal
view
returns (uint256 lastUpdated, int96 flowRate, uint256 deposit, uint256 owedDeposit)
{
(, IGeneralDistributionAgreementV1 gda) = _getHostAndGDA(token);
(lastUpdated, flowRate, deposit) = gda.getAccountFlowInfo(token, account);
owedDeposit = 0; // unused in GDA
}
/**
* @dev get the adjustment flow rate for a pool
* @param token Super token address
* @param pool The pool to query
* @return poolAdjustmentFlowRate The adjustment flow rate of the pool
*/
function getPoolAdjustmentFlowRate(ISuperToken token, ISuperfluidPool pool)
internal
view
returns (int96 poolAdjustmentFlowRate)
{
(, IGeneralDistributionAgreementV1 gda) = _getHostAndGDA(token);
return gda.getPoolAdjustmentFlowRate(address(pool));
}
/**
* @dev Get the total amount of tokens received by a member via instant and flowing distributions
* @param pool The pool to query
* @param memberAddr The member to query
* @return totalAmountReceived The total amount received by the member
*/
function getTotalAmountReceivedByMember(ISuperfluidPool pool, address memberAddr)
internal
view
returns (uint256 totalAmountReceived)
{
return pool.getTotalAmountReceivedByMember(memberAddr);
}
/**
* @notice calculate buffer for a CFA/GDA flow rate
* @dev Even though we are using the CFA, the logic for calculating buffer is the same in the GDA
* and a change in the buffer logic in either means it is a BREAKING change
* @param token The token used in flow
* @param flowRate The flowrate to calculate the needed buffer for
* @return bufferAmount The buffer amount based on flowRate, liquidationPeriod and minimum deposit
*/
function getBufferAmountByFlowRate(ISuperToken token, int96 flowRate) internal view
returns (uint256 bufferAmount)
{
(, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token);
return cfa.getDepositRequiredForFlowRate(token, flowRate);
}
/**
* @dev get existing flow permissions
* @param token The token used in flow
* @param sender sender of a flow
* @param flowOperator the address we are checking permissions of for sender & token
* @return allowCreate is true if the flowOperator can create flows
* @return allowUpdate is true if the flowOperator can update flows
* @return allowDelete is true if the flowOperator can delete flows
* @return flowRateAllowance The flow rate allowance the flowOperator is granted (only goes down)
*/
function getFlowPermissions(ISuperToken token, address sender, address flowOperator)
internal view
returns (bool allowCreate, bool allowUpdate, bool allowDelete, int96 flowRateAllowance)
{
(, IConstantFlowAgreementV1 cfa) = _getHostAndCFA(token);
uint8 permissionsBitmask;
(, permissionsBitmask, flowRateAllowance) = cfa.getFlowOperatorData(token, sender, flowOperator);
allowCreate = permissionsBitmask & 1 == 1;
allowUpdate = permissionsBitmask >> 1 & 1 == 1;
allowDelete = permissionsBitmask >> 2 & 1 == 1;
}
/** IDA VIEW FUNCTIONS ************************************* */
/**
* @dev Gets an index by its ID and publisher.
* @param token Super token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @return exist True if the index exists.
* @return indexValue Total value of the index.
* @return totalUnitsApproved Units of the index approved by subscribers.
* @return totalUnitsPending Units of teh index not yet approved by subscribers.
*/
function getIndex(ISuperToken token, address publisher, uint32 indexId)
internal view
returns (bool exist, uint128 indexValue, uint128 totalUnitsApproved, uint128 totalUnitsPending)
{
(, IInstantDistributionAgreementV1 ida) = _getHostAndIDA(token);
return ida.getIndex(token, publisher, indexId);
}
/**
* @dev Calculates the distribution amount based on the amount of tokens desired to distribute.
* @param token Super token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @param amount Amount of tokens desired to distribute.
* @return actualAmount Amount to be distributed with correct rounding.
* @return newIndexValue The index value after the distribution would be called.
*/
function calculateDistribution(ISuperToken token, address publisher, uint32 indexId, uint256 amount)
internal view
returns (uint256 actualAmount, uint128 newIndexValue)
{
(, IInstantDistributionAgreementV1 ida) = _getHostAndIDA(token);
return ida.calculateDistribution(token, publisher, indexId, amount);
}
/**
* @dev List all subscriptions of an address
* @param token Super token used in the indexes listed.
* @param subscriber Subscriber address.
* @return publishers Publishers of the indices.
* @return indexIds IDs of the indices.
* @return unitsList Units owned of the indices.
*/
function listSubscriptions(
ISuperToken token,
address subscriber
)
internal view
returns (
address[] memory publishers,
uint32[] memory indexIds,
uint128[] memory unitsList
)
{
(, IInstantDistributionAgreementV1 ida) = _getHostAndIDA(token);
return ida.listSubscriptions(token, subscriber);
}
/**
* @dev Gets subscription by publisher, index id, and subscriber.
* @param token Super token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @param subscriber Subscriber to the index.
* @return exist True if the subscription exists.
* @return approved True if the subscription has been approved by the subscriber.
* @return units Units held by the subscriber
* @return pendingDistribution If not approved, the amount to be claimed on approval.
*/
function getSubscription(ISuperToken token, address publisher, uint32 indexId, address subscriber)
internal view
returns (bool exist, bool approved, uint128 units, uint256 pendingDistribution)
{
(, IInstantDistributionAgreementV1 ida) = _getHostAndIDA(token);
return ida.getSubscription(token, publisher, indexId, subscriber);
}
/*
* @dev Gets subscription by the agreement ID.
* @param token Super Token used with the index.
* @param agreementId Agreement ID, unique to the subscriber and index ID.
* @return publisher Publisher of the index.
* @return indexId ID of the index.
* @return approved True if the subscription has been approved by the subscriber.
* @return units Units held by the subscriber
* @return pendingDistribution If not approved, the amount to be claimed on approval.
*/
function getSubscriptionByID(ISuperToken token, bytes32 agreementId)
internal view
returns (
address publisher,
uint32 indexId,
bool approved,
uint128 units,
uint256 pendingDistribution
)
{
(, IInstantDistributionAgreementV1 ida) = _getHostAndIDA(token);
return ida.getSubscriptionByID(token, agreementId);
}
/** GDA VIEW FUNCTIONS ************************************* */
function getFlowDistributionFlowRate(ISuperToken token, address from, ISuperfluidPool to)
internal
view
returns (int96)
{
(, IGeneralDistributionAgreementV1 gda) = _getHostAndGDA(token);
return gda.getFlowRate(token, from, to);
}
function estimateFlowDistributionActualFlowRate(
ISuperToken token,
address from,
ISuperfluidPool to,
int96 requestedFlowRate
) internal view returns (int96 actualFlowRate, int96 totalDistributionFlowRate) {
(, IGeneralDistributionAgreementV1 gda) = _getHostAndGDA(token);
return gda.estimateFlowDistributionActualFlowRate(token, from, to, requestedFlowRate);
}
function estimateDistributionActualAmount(
ISuperToken token,
address from,
ISuperfluidPool to,
uint256 requestedAmount
) internal view returns (uint256 actualAmount) {
(, IGeneralDistributionAgreementV1 gda) = _getHostAndGDA(token);
return gda.estimateDistributionActualAmount(token, from, to, requestedAmount);
}
function isMemberConnected(ISuperToken token, address pool, address member) internal view returns (bool) {
(, IGeneralDistributionAgreementV1 gda) = _getHostAndGDA(token);
return gda.isMemberConnected(ISuperfluidPool(pool), member);
}
/** IDA BASE FUNCTIONS ************************************* */
/**
* @dev Creates a new index.
* @param token Super Token used with the index.
* @param indexId ID of the index.
*/
function createIndex(
ISuperToken token,
uint32 indexId
) internal returns (bool) {
return createIndex(token, indexId, new bytes(0));
}
/**
* @dev Creates a new index with userData.
* @param token Super Token used with the index.
* @param indexId ID of the index.
* @param userData Arbitrary user data field.
*/
function createIndex(
ISuperToken token,
uint32 indexId,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
host.callAgreement(
ida,
abi.encodeCall(
ida.createIndex,
(
token,
indexId,
new bytes(0) // ctx placeholder
)
),
userData
);
return true;
}
/**
* @dev Updates an index value. This distributes an amount of tokens equal to
* `indexValue - lastIndexValue`. See `distribute` for another way to distribute.
* @param token Super Token used with the index.
* @param indexId ID of the index.
* @param indexValue New TOTAL index value, this will equal the total amount distributed.
*/
function updateIndexValue(
ISuperToken token,
uint32 indexId,
uint128 indexValue
) internal returns (bool) {
return updateIndexValue(token, indexId, indexValue, new bytes(0));
}
/**
* @dev Updates an index value with userData. This distributes an amount of tokens equal to
* `indexValue - lastIndexValue`. See `distribute` for another way to distribute.
* @param token Super Token used with the index.
* @param indexId ID of the index.
* @param indexValue New TOTAL index value, this will equal the total amount distributed.
* @param userData Arbitrary user data field.
*/
function updateIndexValue(
ISuperToken token,
uint32 indexId,
uint128 indexValue,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
host.callAgreement(
ida,
abi.encodeCall(
ida.updateIndex,
(
token,
indexId,
indexValue,
new bytes(0) // ctx placeholder
)
),
userData
);
return true;
}
/**
* @dev Distributes tokens in a more developer friendly way than `updateIndex`. Instead of
* passing the new total index value, you pass the amount of tokens desired to be distributed.
* @param token Super Token used with the index.
* @param indexId ID of the index.
* @param amount - total number of tokens desired to be distributed
* NOTE in many cases, there can be some precision loss
This may cause a slight difference in the amount param specified and the actual amount distributed.
See below for math:
//indexDelta = amount the index will be updated by during an internal call to _updateIndex().
It is calculated like so:
indexDelta = amount / totalUnits
(see the distribute() implementatation in ./agreements/InstantDistributionAgreement.sol)
* NOTE Solidity does not support floating point numbers
So the indexDelta will be rounded down to the nearest integer.
This will create a 'remainder' amount of tokens that will not be distributed
(we'll call this the 'distribution modulo')
distributionModulo = amount - indexDelta * totalUnits
* NOTE due to rounding, there may be a small amount of tokens left in the publisher's account
This amount is equal to the 'distributionModulo' value
//
*/
function distribute(
ISuperToken token,
uint32 indexId,
uint256 amount
) internal returns (bool) {
return distribute(token, indexId, amount, new bytes(0));
}
/**
* @dev Distributes tokens in a more developer friendly way than `updateIndex` (w user data). Instead of
* passing the new total index value, this function will increase the index value by `amount`.
* This takes arbitrary user data.
* @param token Super Token used with the index.
* @param indexId ID of the index.
* @param amount Amount by which the index value should increase.
* @param userData Arbitrary user data field.
*/
function distribute(
ISuperToken token,
uint32 indexId,
uint256 amount,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
host.callAgreement(
ida,
abi.encodeCall(
ida.distribute,
(
token,
indexId,
amount,
new bytes(0) // ctx placeholder
)
),
userData
);
return true;
}
/**
* @dev Approves a subscription to an index. The subscriber's real time balance will not update
* until the subscription is approved, but once approved, the balance will be updated with
* prior distributions.
* @param token Super Token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
*/
function approveSubscription(
ISuperToken token,
address publisher,
uint32 indexId
) internal returns (bool) {
return approveSubscription(token, publisher, indexId, new bytes(0));
}
/**
* @dev Approves a subscription to an index with user data. The subscriber's real time balance will not update
* until the subscription is approved, but once approved, the balance will be updated with
* prior distributions.
* @param token Super Token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @param userData Arbitrary user data field.
*/
function approveSubscription(
ISuperToken token,
address publisher,
uint32 indexId,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
host.callAgreement(
ida,
abi.encodeCall(
ida.approveSubscription,
(
token,
publisher,
indexId,
new bytes(0) // ctx placeholder
)
),
userData
);
return true;
}
/**
* @dev Revokes a previously approved subscription.
* @param token Super Token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
*/
function revokeSubscription(
ISuperToken token,
address publisher,
uint32 indexId
) internal returns (bool) {
return revokeSubscription(token, publisher, indexId, new bytes(0));
}
/**
* @dev Revokes a previously approved subscription. This takes arbitrary user data.
* @param token Super Token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @param userData Arbitrary user data field.
*/
function revokeSubscription(
ISuperToken token,
address publisher,
uint32 indexId,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
host.callAgreement(
ida,
abi.encodeCall(
ida.revokeSubscription,
(
token,
publisher,
indexId,
new bytes(0) // ctx placeholder
)
),
userData
);
return true;
}
/**
* @dev Updates the units of a subscription. This changes the number of shares the subscriber holds
* @param token Super Token used with the index.
* @param indexId ID of the index.
* @param subscriber Subscriber address whose units are to be updated.
* @param units New number of units the subscriber holds.
*/
function updateSubscriptionUnits(
ISuperToken token,
uint32 indexId,
address subscriber,
uint128 units
) internal returns (bool) {
return updateSubscriptionUnits(token, indexId, subscriber, units, new bytes(0));
}
/**
* @dev Updates the units of a subscription. This changes the number of shares the subscriber
* holds. This takes arbitrary user data.
* @param token Super Token used with the index.
* @param indexId ID of the index.
* @param subscriber Subscriber address whose units are to be updated.
* @param units New number of units the subscriber holds.
* @param userData Arbitrary user data field.
*/
function updateSubscriptionUnits(
ISuperToken token,
uint32 indexId,
address subscriber,
uint128 units,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
host.callAgreement(
ida,
abi.encodeCall(
ida.updateSubscription,
(
token,
indexId,
subscriber,
units,
new bytes(0) // ctx placeholder
)
),
userData
);
return true;
}
/**
* @dev Deletes a subscription, setting a subcriber's units to zero
* @param token Super Token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @param subscriber Subscriber address whose units are to be deleted.
*/
function deleteSubscription(
ISuperToken token,
address publisher,
uint32 indexId,
address subscriber
) internal returns (bool) {
return deleteSubscription(token, publisher, indexId, subscriber, new bytes(0));
}
/**
* @dev Deletes a subscription, setting a subcriber's units to zero. This takes arbitrary userdata.
* @param token Super Token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @param subscriber Subscriber address whose units are to be deleted.
* @param userData Arbitrary user data field.
*/
function deleteSubscription(
ISuperToken token,
address publisher,
uint32 indexId,
address subscriber,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
host.callAgreement(
ida,
abi.encodeCall(
ida.deleteSubscription,
(
token,
publisher,
indexId,
subscriber,
new bytes(0) // ctx placeholder
)
),
userData
);
return true;
}
/**
* @dev Claims pending distribution. Subscription should not be approved
* @param token Super Token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @param subscriber Subscriber address that receives the claim.
*/
function claim(
ISuperToken token,
address publisher,
uint32 indexId,
address subscriber
) internal returns (bool) {
return claim(token, publisher, indexId, subscriber, new bytes(0));
}
/**
* @dev Claims pending distribution. Subscription should not be approved. This takes arbitrary user data.
* @param token Super Token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @param subscriber Subscriber address that receives the claim.
* @param userData Arbitrary user data field.
*/
function claim(
ISuperToken token,
address publisher,
uint32 indexId,
address subscriber,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
host.callAgreement(
ida,
abi.encodeCall(
ida.claim,
(
token,
publisher,
indexId,
subscriber,
new bytes(0) // ctx placeholder
)
),
userData
);
return true;
}
/** IDA WITH CTX FUNCTIONS ************************************* */
/**
* @dev Creates a new index with ctx.
* Meant for usage in super app callbacks
* @param token Super Token used with the index.
* @param indexId ID of the index.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function createIndexWithCtx(
ISuperToken token,
uint32 indexId,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
(newCtx, ) = host.callAgreementWithContext(
ida,
abi.encodeCall(
ida.createIndex,
(
token,
indexId,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Updates an index value with ctx. This distributes an amount of tokens equal to
* `indexValue - lastIndexValue`. See `distribute` for another way to distribute.
* Meant for usage in super app callbakcs
* @param token Super Token used with the index.
* @param indexId ID of the index.
* @param indexValue New TOTAL index value, this will equal the total amount distributed.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function updateIndexValueWithCtx(
ISuperToken token,
uint32 indexId,
uint128 indexValue,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
(newCtx, ) = host.callAgreementWithContext(
ida,
abi.encodeCall(
ida.updateIndex,
(
token,
indexId,
indexValue,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Distributes tokens in a more developer friendly way than `updateIndex`.Instead of
* passing the new total index value, this function will increase the index value by `amount`.
* @param token Super Token used with the index.
* @param indexId ID of the index.
* @param amount Amount by which the index value should increase.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function distributeWithCtx(
ISuperToken token,
uint32 indexId,
uint256 amount,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
(newCtx, ) = host.callAgreementWithContext(
ida,
abi.encodeCall(
ida.distribute,
(
token,
indexId,
amount,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Approves a subscription to an index. The subscriber's real time balance will not update
* until the subscription is approved, but once approved, the balance will be updated with
* prior distributions.
* @param token Super Token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function approveSubscriptionWithCtx(
ISuperToken token,
address publisher,
uint32 indexId,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
(newCtx, ) = host.callAgreementWithContext(
ida,
abi.encodeCall(
ida.approveSubscription,
(
token,
publisher,
indexId,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Revokes a previously approved subscription. Meant for usage in super apps
* @param token Super Token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function revokeSubscriptionWithCtx(
ISuperToken token,
address publisher,
uint32 indexId,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
(newCtx, ) = host.callAgreementWithContext(
ida,
abi.encodeCall(
ida.revokeSubscription,
(
token,
publisher,
indexId,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Updates the units of a subscription. This changes the number of shares the subscriber
* holds. Meant for usage in super apps
* @param token Super Token used with the index.
* @param indexId ID of the index.
* @param subscriber Subscriber address whose units are to be updated.
* @param units New number of units the subscriber holds.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function updateSubscriptionUnitsWithCtx(
ISuperToken token,
uint32 indexId,
address subscriber,
uint128 units,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
(newCtx, ) = host.callAgreementWithContext(
ida,
abi.encodeCall(
ida.updateSubscription,
(
token,
indexId,
subscriber,
units,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Deletes a subscription, setting a subcriber's units to zero.
* Meant for usage in super apps
* @param token Super Token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @param subscriber Subscriber address whose units are to be deleted.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function deleteSubscriptionWithCtx(
ISuperToken token,
address publisher,
uint32 indexId,
address subscriber,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
(newCtx, ) = host.callAgreementWithContext(
ida,
abi.encodeCall(
ida.deleteSubscription,
(
token,
publisher,
indexId,
subscriber,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Claims pending distribution. Subscription should not be approved.
* Meant for usage in super app callbacks
* @param token Super Token used with the index.
* @param publisher Publisher of the index.
* @param indexId ID of the index.
* @param subscriber Subscriber address that receives the claim.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function claimWithCtx(
ISuperToken token,
address publisher,
uint32 indexId,
address subscriber,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IInstantDistributionAgreementV1 ida) = _getAndCacheHostAndIDA(token);
(newCtx, ) = host.callAgreementWithContext(
ida,
abi.encodeCall(
ida.claim,
(
token,
publisher,
indexId,
subscriber,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/** GDA BASE FUNCTIONS ************************************* */
/**
* @dev Creates a new Superfluid Pool.
* @param token The Super Token address.
* @param admin The pool admin address.
* @param poolConfig The pool configuration (see PoolConfig in IGeneralDistributionAgreementV1.sol)
* @return pool The address of the deployed Superfluid Pool
*/
function createPool(ISuperToken token, address admin, PoolConfig memory poolConfig)
internal
returns (ISuperfluidPool pool)
{
(, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
pool = gda.createPool(token, admin, poolConfig);
}
/**
* @dev Updates the units of a pool member.
* @param token The Super Token address.
* @param pool The Superfluid Pool to update.
* @param memberAddress The address of the member to update.
* @param newUnits The new units of the member.
* @return bool A boolean value indicating whether the pool was created successfully.
*/
function updateMemberUnits(ISuperToken token, ISuperfluidPool pool, address memberAddress, uint128 newUnits)
internal
returns (bool)
{
return updateMemberUnits(token, pool, memberAddress, newUnits, new bytes(0));
}
/**
* @dev Updates the units of a pool member.
* @param token The Super Token address.
* @param pool The Superfluid Pool to update.
* @param memberAddress The address of the member to update.
* @param newUnits The new units of the member.
* @param userData User-specific data.
* @return A boolean value indicating whether the pool was created successfully.
*/
function updateMemberUnits(
ISuperToken token,
ISuperfluidPool pool,
address memberAddress,
uint128 newUnits,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
host.callAgreement(
gda, abi.encodeCall(gda.updateMemberUnits, (pool, memberAddress, newUnits, new bytes(0))), userData
);
return true;
}
/**
* @dev Claims all tokens from the pool.
* @param token The Super Token address.
* @param pool The Superfluid Pool to claim from.
* @param memberAddress The address of the member to claim for.
* @return A boolean value indicating whether the claim was successful.
*/
function claimAll(ISuperToken token, ISuperfluidPool pool, address memberAddress) internal returns (bool) {
return claimAll(token, pool, memberAddress, new bytes(0));
}
/**
* @dev Claims all tokens from the pool.
* @param token The Super Token address.
* @param pool The Superfluid Pool to claim from.
* @param memberAddress The address of the member to claim for.
* @param userData User-specific data.
* @return A boolean value indicating whether the claim was successful.
*/
function claimAll(ISuperToken token, ISuperfluidPool pool, address memberAddress, bytes memory userData)
internal
returns (bool)
{
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
host.callAgreement(gda, abi.encodeCall(gda.claimAll, (pool, memberAddress, new bytes(0))), userData);
return true;
}
/**
* @dev Connects a pool member to `pool`.
* @param token The Super Token address.
* @param pool The Superfluid Pool to connect.
* @return A boolean value indicating whether the connection was successful.
*/
function connectPool(ISuperToken token, ISuperfluidPool pool) internal returns (bool) {
return connectPool(token, pool, new bytes(0));
}
/**
* @dev Connects a pool member to `pool`.
* @param token The Super Token address.
* @param pool The Superfluid Pool to connect.
* @param userData User-specific data.
* @return A boolean value indicating whether the connection was successful.
*/
function connectPool(ISuperToken token, ISuperfluidPool pool, bytes memory userData) internal returns (bool) {
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
host.callAgreement(gda, abi.encodeCall(gda.connectPool, (pool, new bytes(0))), userData);
return true;
}
/**
* @dev Disconnects a pool member from `pool`.
* @param token The Super Token address.
* @param pool The Superfluid Pool to disconnect.
* @return A boolean value indicating whether the disconnection was successful.
*/
function disconnectPool(ISuperToken token, ISuperfluidPool pool) internal returns (bool) {
return disconnectPool(token, pool, new bytes(0));
}
/**
* @dev Disconnects a pool member from `pool`.
* @param token The Super Token address.
* @param pool The Superfluid Pool to disconnect.
* @param userData User-specific data.
* @return A boolean value indicating whether the disconnection was successful.
*/
function disconnectPool(ISuperToken token, ISuperfluidPool pool, bytes memory userData) internal returns (bool) {
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
host.callAgreement(gda, abi.encodeCall(gda.disconnectPool, (pool, new bytes(0))), userData);
return true;
}
/**
* @dev Tries to distribute `requestedAmount` amount of `token` from `from` to `pool`.
* @param token The Super Token address.
* @param from The address from which to distribute tokens.
* @param pool The Superfluid Pool address.
* @param requestedAmount The amount of tokens to distribute.
* @return A boolean value indicating whether the distribution was successful.
*/
function distributeToPool(ISuperToken token, address from, ISuperfluidPool pool, uint256 requestedAmount)
internal
returns (bool)
{
return distribute(token, from, pool, requestedAmount, new bytes(0));
}
/**
* @dev Tries to distribute `requestedAmount` amount of `token` from `from` to `pool`.
* @param token The Super Token address.
* @param from The address from which to distribute tokens.
* @param pool The Superfluid Pool address.
* @param requestedAmount The amount of tokens to distribute.
* @param userData User-specific data.
* @return A boolean value indicating whether the distribution was successful.
*/
function distribute(
ISuperToken token,
address from,
ISuperfluidPool pool,
uint256 requestedAmount,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
host.callAgreement(
gda, abi.encodeCall(gda.distribute, (token, from, pool, requestedAmount, new bytes(0))), userData
);
return true;
}
/**
* @dev Tries to distribute flow at `requestedFlowRate` of `token` from `from` to `pool`.
* @param token The Super Token address.
* @param from The address from which to distribute tokens.
* @param pool The Superfluid Pool address.
* @param requestedFlowRate The flow rate of tokens to distribute.
* @return A boolean value indicating whether the distribution was successful.
*/
function distributeFlow(ISuperToken token, address from, ISuperfluidPool pool, int96 requestedFlowRate)
internal
returns (bool)
{
return distributeFlow(token, from, pool, requestedFlowRate, new bytes(0));
}
/**
* @dev Tries to distribute flow at `requestedFlowRate` of `token` from `from` to `pool`.
* @param token The Super Token address.
* @param from The address from which to distribute tokens.
* @param pool The Superfluid Pool address.
* @param requestedFlowRate The flow rate of tokens to distribute.
* @param userData User-specific data.
* @return A boolean value indicating whether the distribution was successful.
*/
function distributeFlow(
ISuperToken token,
address from,
ISuperfluidPool pool,
int96 requestedFlowRate,
bytes memory userData
) internal returns (bool) {
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
host.callAgreement(
gda, abi.encodeCall(gda.distributeFlow, (token, from, pool, requestedFlowRate, new bytes(0))), userData
);
return true;
}
/** GDA WITH CTX FUNCTIONS ************************************* */
/**
* @dev Updates the units of a pool member.
* @param token The Super Token address.
* @param pool The Superfluid Pool to update.
* @param memberAddress The address of the member to update.
* @param newUnits The new units of the member.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function updateMemberUnitsWithCtx(
ISuperToken token,
ISuperfluidPool pool,
address memberAddress,
uint128 newUnits,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
(newCtx,) = host.callAgreementWithContext(
gda,
abi.encodeCall(
gda.updateMemberUnits,
(
pool,
memberAddress,
newUnits,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Claims all tokens from the pool.
* @param token The Super Token address.
* @param pool The Superfluid Pool to claim from.
* @param memberAddress The address of the member to claim for.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function claimAllWithCtx(ISuperToken token, ISuperfluidPool pool, address memberAddress, bytes memory ctx)
internal
returns (bytes memory newCtx)
{
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
(newCtx,) = host.callAgreementWithContext(
gda,
abi.encodeCall(
gda.claimAll,
(
pool,
memberAddress,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Connects a pool member to `pool`.
* @param token The Super Token address.
* @param pool The Superfluid Pool to connect.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function connectPoolWithCtx(ISuperToken token, ISuperfluidPool pool, bytes memory ctx)
internal
returns (bytes memory newCtx)
{
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
(newCtx,) = host.callAgreementWithContext(
gda,
abi.encodeCall(
gda.connectPool,
(
pool,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Disconnects a pool member from `pool`.
* @param token The Super Token address.
* @param pool The Superfluid Pool to disconnect.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function disconnectPoolWithCtx(ISuperToken token, ISuperfluidPool pool, bytes memory ctx)
internal
returns (bytes memory newCtx)
{
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
(newCtx,) = host.callAgreementWithContext(
gda,
abi.encodeCall(
gda.disconnectPool,
(
pool,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Tries to distribute `requestedAmount` amount of `token` from `from` to `pool`.
* @param token The Super Token address.
* @param from The address from which to distribute tokens.
* @param pool The Superfluid Pool address.
* @param requestedAmount The amount of tokens to distribute.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function distributeWithCtx(
ISuperToken token,
address from,
ISuperfluidPool pool,
uint256 requestedAmount,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
(newCtx,) = host.callAgreementWithContext(
gda,
abi.encodeCall(
gda.distribute,
(
token,
from,
pool,
requestedAmount,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
/**
* @dev Tries to distribute flow at `requestedFlowRate` of `token` from `from` to `pool`.
* @param token The Super Token address.
* @param from The address from which to distribute tokens.
* @param pool The Superfluid Pool address.
* @param requestedFlowRate The flow rate of tokens to distribute.
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
* @return newCtx The updated context after the execution of the agreement function
*/
function distributeFlowWithCtx(
ISuperToken token,
address from,
ISuperfluidPool pool,
int96 requestedFlowRate,
bytes memory ctx
) internal returns (bytes memory newCtx) {
(ISuperfluid host, IGeneralDistributionAgreementV1 gda) = _getAndCacheHostAndGDA(token);
(newCtx,) = host.callAgreementWithContext(
gda,
abi.encodeCall(
gda.distributeFlow,
(
token,
from,
pool,
requestedFlowRate,
new bytes(0) // ctx placeholder
)
),
"0x",
ctx
);
}
// ************** private helpers **************
// @note We must use hardcoded constants here because:
// Only direct number constants and references to such constants are supported by inline assembly.
// keccak256("org.superfluid-finance.apps.SuperTokenLibrary.v1.host")
bytes32 private constant _HOST_SLOT = 0x65599bf746e17a00ea62e3610586992d88101b78eec3cf380706621fb97ea837;
// keccak256("org.superfluid-finance.apps.SuperTokenLibrary.v1.cfa")
bytes32 private constant _CFA_SLOT = 0xb969d79d88acd02d04ed7ee7d43b949e7daf093d363abcfbbc43dfdfd1ce969a;
// keccak256("org.superfluid-finance.apps.SuperTokenLibrary.v1.ida");
bytes32 private constant _IDA_SLOT = 0xa832ee1924ea960211af2df07d65d166232018f613ac6708043cd8f8773eddeb;
// keccak256("org.superfluid-finance.apps.SuperTokenLibrary.v1.gda");
bytes32 private constant _GDA_SLOT = 0xc36f6c05164a669ecb6da53e218d77ae44d51cfc99f91e5a125a18de0949bee4;
// gets the host and cfa addrs for the token and caches it in storage for gas efficiency
// to be used in state changing methods
function _getAndCacheHostAndCFA(ISuperToken token)
private
returns (ISuperfluid host, IConstantFlowAgreementV1 cfa)
{
// check if already in contract storage...
assembly {
// solium-disable-line
host := sload(_HOST_SLOT)
cfa := sload(_CFA_SLOT)
}
if (address(cfa) == address(0)) {
// framework contract addrs not yet cached, retrieving now...
if (address(host) == address(0)) {
host = ISuperfluid(token.getHost());
}
cfa = IConstantFlowAgreementV1(address(ISuperfluid(host).getAgreementClass(
keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1"))));
// now that we got them and are in a transaction context, persist in storage
assembly {
// solium-disable-line
sstore(_HOST_SLOT, host)
sstore(_CFA_SLOT, cfa)
}
}
assert(address(host) != address(0));
assert(address(cfa) != address(0));
}
// gets the host and ida addrs for the token and caches it in storage for gas efficiency
// to be used in state changing methods
function _getAndCacheHostAndIDA(ISuperToken token)
private
returns (ISuperfluid host, IInstantDistributionAgreementV1 ida)
{
// check if already in contract storage...
assembly {
// solium-disable-line
host := sload(_HOST_SLOT)
ida := sload(_IDA_SLOT)
}
if (address(ida) == address(0)) {
// framework contract addrs not yet cached, retrieving now...
if (address(host) == address(0)) {
host = ISuperfluid(token.getHost());
}
ida = IInstantDistributionAgreementV1(address(ISuperfluid(host).getAgreementClass(
keccak256("org.superfluid-finance.agreements.InstantDistributionAgreement.v1"))));
// now that we got them and are in a transaction context, persist in storage
assembly {
// solium-disable-line
sstore(_HOST_SLOT, host)
sstore(_IDA_SLOT, ida)
}
}
assert(address(host) != address(0));
assert(address(ida) != address(0));
}
// gets the host and gda addrs for the token and caches it in storage for gas efficiency
// to be used in state changing methods
function _getAndCacheHostAndGDA(ISuperToken token)
private
returns (ISuperfluid host, IGeneralDistributionAgreementV1 gda)
{
// check if already in contract storage...
assembly {
// solium-disable-line
host := sload(_HOST_SLOT)
gda := sload(_GDA_SLOT)
}
if (address(gda) == address(0)) {
// framework contract addrs not yet cached, retrieving now...
if (address(host) == address(0)) {
host = ISuperfluid(token.getHost());
}
gda = IGeneralDistributionAgreementV1(
address(
ISuperfluid(host).getAgreementClass(
keccak256("org.superfluid-finance.agreements.GeneralDistributionAgreement.v1")
)
)
);
// now that we got them and are in a transaction context, persist in storage
assembly {
// solium-disable-line
sstore(_HOST_SLOT, host)
sstore(_GDA_SLOT, gda)
}
}
assert(address(host) != address(0));
assert(address(gda) != address(0));
}
// gets the host and cfa addrs for the token
// to be used in non-state changing methods (view functions)
function _getHostAndCFA(ISuperToken token) private view returns (ISuperfluid host, IConstantFlowAgreementV1 cfa) {
// check if already in contract storage...
assembly {
// solium-disable-line
host := sload(_HOST_SLOT)
cfa := sload(_CFA_SLOT)
}
if (address(cfa) == address(0)) {
// framework contract addrs not yet cached in storage, retrieving now...
if (address(host) == address(0)) {
host = ISuperfluid(token.getHost());
}
cfa = IConstantFlowAgreementV1(address(ISuperfluid(host).getAgreementClass(
keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1"))));
}
assert(address(host) != address(0));
assert(address(cfa) != address(0));
}
// gets the host and ida addrs for the token
// to be used in non-state changing methods (view functions)
function _getHostAndIDA(ISuperToken token)
private
view
returns (ISuperfluid host, IInstantDistributionAgreementV1 ida)
{
// check if already in contract storage...
assembly {
// solium-disable-line
host := sload(_HOST_SLOT)
ida := sload(_IDA_SLOT)
}
if (address(ida) == address(0)) {
// framework contract addrs not yet cached in storage, retrieving now...
if (address(host) == address(0)) {
host = ISuperfluid(token.getHost());
}
ida = IInstantDistributionAgreementV1(address(ISuperfluid(host).getAgreementClass(
keccak256("org.superfluid-finance.agreements.InstantDistributionAgreement.v1"))));
}
assert(address(host) != address(0));
assert(address(ida) != address(0));
}
// gets the host and gda addrs for the token
// to be used in non-state changing methods (view functions)
function _getHostAndGDA(ISuperToken token)
private
view
returns (ISuperfluid host, IGeneralDistributionAgreementV1 gda)
{
// check if already in contract storage...
assembly {
// solium-disable-line
host := sload(_HOST_SLOT)
gda := sload(_GDA_SLOT)
}
if (address(gda) == address(0)) {
// framework contract addrs not yet cached in storage, retrieving now...
if (address(host) == address(0)) {
host = ISuperfluid(token.getHost());
}
gda = IGeneralDistributionAgreementV1(
address(
ISuperfluid(host).getAgreementClass(
keccak256("org.superfluid-finance.agreements.GeneralDistributionAgreement.v1")
)
)
);
}
assert(address(host) != address(0));
assert(address(gda) != address(0));
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;
/**
* @title Interface for TWAP observers
* @notice TWAP observers can create check points and track the TWAP of since last check point.
*/
interface ITwapObserver {
/**
* @notice Get the type id of the observer.
* @dev This is useful for safe down-casting to the actual implementation.
*/
function getTypeId() external view returns (bytes32);
/**
* @notice Get the time of the check point.
* @param time Current block timestamp.
* @return duration The time duration since the last check point.
*/
function getDurationSinceLastCheckpoint(uint256 time) external view returns (uint256 duration);
/**
* @notice Create a checkpoint for the next TWAP calculation.
* @param time Current block timestamp.
* @return true.
*/
function createCheckpoint(uint256 time) external returns (bool);
/**
* @notice Calculate the TWAP since the last checkpoint.
* @param time Current block timestamp.
* @param inAmount The amount of in token used for quote.
* @return outAmount The amount of out token quoted for `inAmount` of inToken.
* @return duration The time duration since the last check point.
*/
function getTwapSinceLastCheckpoint(uint256 time, uint256 inAmount) external view
returns (uint256 outAmount, uint256 duration);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;
import {
ISuperToken, ISuperfluidPool
} from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol";
/// @title Result of a liquidity move
struct LiquidityMoveResult {
uint256 durationSinceLastLME;
uint256 twapSinceLastLME;
uint256 inAmount;
uint256 minOutAmount;
uint256 outAmount;
uint256 actualOutAmount;
}
/**
* @title Interface of torex controllers
* @dev A Torex controller provides hooks to the Torex so that additional functionalities could be added.
*/
interface ITorexController {
/// Get the type id of the controller.
function getTypeId() external view returns (bytes32);
/// A hook for in-token flow changed reported by torex.
function onInFlowChanged(address flowUpdater,
int96 prevFlowRate, int96 preFeeFlowRate, uint256 lastUpdated,
int96 newFlowRate, uint256 now,
bytes calldata userData) external
returns (int96 newFeeFlowRate);
/// A hook for liquidity moved reported by torex.
function onLiquidityMoved(LiquidityMoveResult calldata result) external returns (bool);
}
/**
* @title Interface for torex
*/
interface ITorex {
/// Torex controller that controls this torex.
function controller() external view returns (ITorexController);
/// Get token pairs of the Torex.
function getPairedTokens() external view returns (ISuperToken inToken, ISuperToken outToken);
/// GDA pool for distributing fees denominated in inTokens.
function feeDistributionPool() external view returns (ISuperfluidPool);
/// GDA pool for distributing out tokens.
function outTokenDistributionPool() external view returns (ISuperfluidPool);
/// Estimate amount of approval required for creating the torex flow.
function estimateApprovalRequired(int96 flowRate) external view returns (uint256 requiredApproval);
/// Let liquidity mover (contracts with ILiquidityMover interface) trigger a liquidity movement.
function moveLiquidity(bytes calldata moverData) external returns (LiquidityMoveResult memory result);
}
/**
* @title Metadata for a torex
*/
struct TorexMetadata {
address torexAddr;
ISuperToken inToken;
ISuperToken outToken;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import { UINT_100PCT_PM } from "./MathExtra.sol";
/*
* About TOREX Discount Model
* ==========================
*
* We need to solve the issue that benchmark price without discount over time may stall the exchanges over time.
*
* - TOREX's Max TWAP Time Window: due to int24 tick limitation of Uniswap V3 pool, we cannot have such time window more
* than, say, around 1 day or 2 days.
*
* - Initial Benchmark price: The TOREX TWAP Reading without applying any discount. Time window is the time since last
* LME until max TWAP Time Window is applicable.
*
* - Discount model: A function of time since last LME, that discounts the initial bench mark price.
*
* So the discount model has such properties:
*
* 1. When timeSinceLastLME is 0, the discount is 0%.
*
* 2. Predictably, at certain time in the future, say, τ seconds, the discount is ε.
*
* 3. Over time the discount monotonically grows, in another word, the discount number goes up, until but never
* reaches 100%.
*
* A curve that can fit the above properties perfectly is a "shifted reciprocal function". An example:If we want a
* discount model that after 8 hours, it's 10% discount, then such a function is: discount(t) = 1 - 1 / (1 + t /
* 259200). In this case τ is 8 * 3600 and ε is 10%, and when t is 0, discount is 0% t is 8*3600 (8 hours), the
* discount is 10%.
*
* Read more about discount model from the Torex whitepaper.
*/
/// Discount factor custom type.
type DiscountFactor is uint256;
/**
* @notice Get such discount factor, where at certain time in the future, say, τ seconds, the discount is ε.
* @param tau The τ seconds component of the discount model factor.
* @param epsilonPM The ε component of the discount model factor, in per million (PM) unit.
* @return The discount model factor.
*/
function getDiscountFactor(uint32 tau, uint32 epsilonPM) pure returns (DiscountFactor) {
return DiscountFactor.wrap(uint256(tau) * uint256(UINT_100PCT_PM - epsilonPM) / uint256(epsilonPM));
}
/**
* @notice Applying discount model to the full value at the relative time t.
*/
function getDiscountedValue(DiscountFactor factor, uint256 fullValue, uint256 t) pure
returns (uint256 discountedValue)
{
uint256 fv = DiscountFactor.unwrap(factor);
if (fullValue == 0) {
return 0;
} else if (fv != 0) {
return fullValue * fv / (fv + t);
} else {
return fullValue;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
/// @dev 100% in per-million
int256 constant INT_100PCT_PM = 100_0000;
/// @dev 100% in per-million
uint256 constant UINT_100PCT_PM = 100_0000;
/**
* Extra SafeCast
* ==============
*
* Here is the extra SafeCast functions that is not available from openzeppelin.
*
* Naming convention is consistent with openzeppelin, but using "free-range" functions.
*/
function toUint128(int96 value) pure returns (uint128) {
require(value >= 0, "toUint128(int96)");
return uint128(uint96(value));
}
function toUint256(int96 value) pure returns (uint256) {
require(value >= 0, "toUint256(int96)");
return uint256(uint96(value));
}
function toInt96(int256 value) pure returns (int96) {
require(value <= int256(type(int96).max), "toInt96(int256)");
return int96(value);
}
function toInt96(uint256 value) pure returns (int96) {
require(value <= uint256(uint96(type(int96).max)), "toInt96(uint256)");
return int96(uint96(value));
}
function toUint96(uint256 value) pure returns (uint96) {
require(value <= uint256(type(uint96).max), "toUint96(uint256)");
return uint96(value);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
/**
* @notice A custom type of a scaler value, where negative value is for downscaling and positive value is for
* upscaling. Trvially, zaero makes all value zeros.
*/
type Scaler is int256;
/**
* @notice Get a downscaler or an upscaler that is a power of 10.
* @param n Positive value for upscalers of 10^n, negative for downscalers of 10^(-n).
* @return scaler The scaler.
*/
function getScaler10Pow(int8 n) pure returns (Scaler scaler) {
if (n >= 0) {
return Scaler.wrap(SafeCast.toInt256(10**uint8(n)));
} else {
return Scaler.wrap(-SafeCast.toInt256(10**uint8(-n)));
}
}
library LibScaler {
/**
* @notice Scale a uint256 value.
* @param s The scaler.
* @param v The full value.
* @param scaledValue Scaled value.
*/
function scaleValue(Scaler s, uint256 v) internal pure returns (uint256 scaledValue) {
int256 ss = Scaler.unwrap(s);
if (ss >= 0) return v * uint256(ss); else return v / uint256(-ss);
}
/**
* @notice Scale a int256 value.
* @param s The scaler.
* @param v The full value.
* @param scaledValue Scaled value.
*/
function scaleValue(Scaler s, int256 v) internal pure returns (int256 scaledValue) {
int256 ss = Scaler.unwrap(s);
if (ss >= 0) return v * ss; else return v / -ss;
}
/// Inverse the scaler
function inverse(Scaler s) internal pure returns (Scaler inverseScaler) {
return Scaler.wrap(-Scaler.unwrap(s));
}
}
using LibScaler for Scaler global;// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {
ISuperToken, ISuperfluidPool, PoolConfig
} from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol";
import { SuperTokenV1Library } from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol";
import { ILiquidityMover } from "./interfaces/torex/ILiquidityMover.sol";
import { ITwapObserver } from "./interfaces/torex/ITwapObserver.sol";
import { LiquidityMoveResult } from "./interfaces/torex/ITorex.sol";
import { DiscountFactor, getDiscountedValue } from "./libs/DiscountFactor.sol";
import { Scaler } from "./libs/Scaler.sol";
/**
* @title Abstract contract for the core logic of TOREX
*
* @notice A TOREX swaps liquidity of *in-tokens* for liquidity of *out-tokens* for traders.
*
* To do so, each TOREX book keeps money streams from traders at *money flow events*, maintains a temporary liquidity
* pool of in-tokens, and offers the liquidity to *liquidity movers* at a *benchmark quote* for an amount of out-tokens.
*
* At a *liquidity movement event*, the TOREX receives the quoted amount of out-tokens and distributes them to the
* traders through Superfluid money distribution.
*
* Each TOREX is configured with a dedicated TWAP observer, through which TOREX can create checkpoints and query TWAP
* since the last checkpoint. TOREX then discounts this TWAP through a discount model that ensures that TOREX should
* never stall by offering the liquidity movers ever-greater incentives over time.
*
* For more details about torex core logic, read the Torex whitepaper.
*/
abstract contract TorexCore is ReentrancyGuard {
using SuperTokenV1Library for ISuperToken;
/*******************************************************************************************************************
* Definitions
******************************************************************************************************************/
error LIQUIDITY_MOVER_SENT_INSUFFICIENT_OUT_TOKENS();
/*******************************************************************************************************************
* Configurations and Constructor
******************************************************************************************************************/
/// In token of the Torex.
ISuperToken internal immutable _inToken;
/// Out token of the Torex.
ISuperToken internal immutable _outToken;
/// Observer of the twap.
ITwapObserver internal immutable _observer;
/// Scaler for the twap observed.
Scaler internal immutable _twapScaler;
/// Discount factor for the twap.
DiscountFactor internal immutable _discountFactor;
/// Scaler for the out token distribution pool units.
Scaler internal immutable _outTokenDistributionPoolScaler;
/// Out token distribution pool.
ISuperfluidPool internal immutable _outTokenDistributionPool;
constructor(ISuperToken inToken, ISuperToken outToken,
ITwapObserver observer, Scaler twapScaler, DiscountFactor discountFactor,
Scaler outTokenDistributionPoolScaler) {
_inToken = inToken;
_outToken = outToken;
_observer = observer;
_twapScaler = twapScaler;
_discountFactor = discountFactor;
_outTokenDistributionPoolScaler = outTokenDistributionPoolScaler;
_outTokenDistributionPool = _outToken.createPool(address(this), PoolConfig({
transferabilityForUnitsOwner: false,
distributionFromAnyAddress: true
}));
}
/*******************************************************************************************************************
* Core Logic
******************************************************************************************************************/
/**
* @notice Calculate the required amount of in tokens for liquidity movement.
*/
function availableInTokens() virtual internal view returns (uint256);
/**
* @notice Calculate required back adjustment for in-token flow rate change.
*/
function _requiredBackAdjustment(int96 prevFlowRate, int96 newFlowRate) internal view
returns (uint256 durationSinceLastLME, int256 backAdjustment)
{
durationSinceLastLME = getDurationSinceLastLME();
backAdjustment = SafeCast.toInt256(durationSinceLastLME) * (newFlowRate - prevFlowRate);
}
/**
* @notice Upon in-token flow changed from sender, calculate the required back adjustment and update the out-token
* distribution pool units for the sender.
*/
function _onInFlowChanged(address sender, int96 prevFlowRate, int96 newFlowRate) internal
returns (uint256 durationSinceLastLME, int256 backAdjustment)
{
// Take back charge from the sender is required so that the new units that we are about to give to the sender is
// fair one everyone. Without it, attackers may game the system.
//
// Similar to the back charge on flow creation, we do a back refund. After that, we can then set the units to 0
// fairly. This can also act as escape hatch in case a Torex for any reason gets stuck in the sense that no
// liquidity moving takes place anymore. In that case, flow deletion auto-withdraws accumulated inTokens.
(durationSinceLastLME, backAdjustment) = _requiredBackAdjustment(prevFlowRate, newFlowRate);
// assigning new units
uint128 newUnits = uint128(SafeCast.toInt128(_outTokenDistributionPoolScaler.scaleValue(newFlowRate)));
_outTokenDistributionPool.updateMemberUnits(sender, newUnits);
}
/**
* @notice Move liquidity, called by a liquidity mover.
*
* Note:
* - The amount of in token disposable by the contract is called inAmount.
* - Send inAmount inToken to msg.sender and request outAmount of out token from the msg.sender.
* - The outAmount need to be satisfy the price threshold defined by getBenchmarkQuote(inAmount).
*/
function _moveLiquidity(bytes memory moverData) internal
nonReentrant
returns (LiquidityMoveResult memory result)
{
(result.inAmount, result.minOutAmount, result.durationSinceLastLME, result.twapSinceLastLME) =
getLiquidityEstimations();
// Step 1: Transfer the inAmount of inToken liquidity to the liquidity mover.
_inToken.transfer(msg.sender, result.inAmount);
// Step 2: Ask liquidity mover to provide outAmount of outToken liquidity in exchange.
assert((ILiquidityMover(msg.sender))
.moveLiquidityCallback(_inToken, _outToken, result.inAmount, result.minOutAmount, moverData));
// We distribute everything the contract has got from liquidity mover.
result.outAmount = _outToken.balanceOf(address(this));
if (result.outAmount < result.minOutAmount) revert LIQUIDITY_MOVER_SENT_INSUFFICIENT_OUT_TOKENS();
// Step 3: Create new torex observer check point
_observer.createCheckpoint(block.timestamp);
// Step 4: Distribute all outToken liquidity to degens.
// NOTE: This could be more than outAmount.
result.actualOutAmount = _outToken
.estimateDistributionActualAmount(address(this), _outTokenDistributionPool, result.outAmount);
_outToken.distributeToPool(address(this), _outTokenDistributionPool, result.actualOutAmount);
}
/*******************************************************************************************************************
* View Functions
******************************************************************************************************************/
/**
* @dev Get the benchmark price.
* @param inAmount In token amount provided in 18 decimals.
* @return minOutAmount Minimum out token discounting twapSinceLastLME.
* @return durationSinceLastLME Result from `getDurationSinceLastLME()`.
* @return twapSinceLastLME Result from `getTwapSinceLastLME(inAmount)`.
*
* Notes:
*
* - A benchmark price is discounted of the full price returned by `getTwapSinceLastCheckpoint`.
*/
function getBenchmarkQuote(uint256 inAmount) public view
returns (uint256 minOutAmount, uint256 durationSinceLastLME, uint256 twapSinceLastLME)
{
(twapSinceLastLME, durationSinceLastLME) = _observer.getTwapSinceLastCheckpoint(block.timestamp, inAmount);
twapSinceLastLME = _twapScaler.scaleValue(twapSinceLastLME);
minOutAmount = getDiscountedValue(_discountFactor, twapSinceLastLME, durationSinceLastLME);
}
/**
* @dev Get the time duration since last LME until now. Synonym to getDurationSinceLastCheckpoint.
*/
function getDurationSinceLastLME() public view returns (uint256) {
return _observer.getDurationSinceLastCheckpoint(block.timestamp);
}
/**
* @dev Estimate amount of tokens involved in the next liquidity movement.
*/
function getLiquidityEstimations() public view
returns (uint256 inAmount, uint256 minOutAmount, uint256 durationSinceLastLME, uint256 twapSinceLastLME)
{
inAmount = availableInTokens();
(minOutAmount, durationSinceLastLME, twapSinceLastLME) = getBenchmarkQuote(inAmount);
}
}// 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 DMZForwarder.forwardCall batch operation type
*
* Call spec:
* forwardCall(
* target,
* data
* )
*/
uint32 constant internal OPERATION_TYPE_SIMPLE_FORWARD_CALL = 1 + 300;
/**
* @dev DMZForwarder.forward2771Call batch operation type
*
* Call spec:
* forward2771Call(
* target,
* msgSender,
* data
* )
*
* NOTE: In the context of this operation, the `DZMForwarder` 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 DMZForwarder used by the host, like this:
*
* function isTrustedForwarder(address forwarder) public view returns(bool) {
* return forwarder == address(host.DMZ_FORWARDER());
* }
*
* 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 DMZForwarder 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: 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/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
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 { ISuperfluidToken } from "./ISuperfluidToken.sol";
import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.sol";
import { IConstantOutflowNFT } from "./IConstantOutflowNFT.sol";
import { IConstantInflowNFT } from "./IConstantInflowNFT.sol";
import { IPoolAdminNFT } from "../agreements/gdav1/IPoolAdminNFT.sol";
import { IPoolMemberNFT } from "../agreements/gdav1/IPoolMemberNFT.sol";
/**
* @title Super token (Superfluid Token + ERC20 + ERC777) interface
* @author Superfluid
*/
interface ISuperToken is ISuperfluidToken, IERC20Metadata, IERC777 {
/**************************************************************************
* Errors
*************************************************************************/
error SUPER_TOKEN_CALLER_IS_NOT_OPERATOR_FOR_HOLDER(); // 0xf7f02227
error SUPER_TOKEN_NOT_ERC777_TOKENS_RECIPIENT(); // 0xfe737d05
error SUPER_TOKEN_INFLATIONARY_DEFLATIONARY_NOT_SUPPORTED(); // 0xe3e13698
error SUPER_TOKEN_NO_UNDERLYING_TOKEN(); // 0xf79cf656
error SUPER_TOKEN_ONLY_SELF(); // 0x7ffa6648
error SUPER_TOKEN_ONLY_ADMIN(); // 0x0484acab
error SUPER_TOKEN_ONLY_GOV_OWNER(); // 0xd9c7ed08
error SUPER_TOKEN_APPROVE_FROM_ZERO_ADDRESS(); // 0x81638627
error SUPER_TOKEN_APPROVE_TO_ZERO_ADDRESS(); // 0xdf070274
error SUPER_TOKEN_BURN_FROM_ZERO_ADDRESS(); // 0xba2ab184
error SUPER_TOKEN_MINT_TO_ZERO_ADDRESS(); // 0x0d243157
error SUPER_TOKEN_TRANSFER_FROM_ZERO_ADDRESS(); // 0xeecd6c9b
error SUPER_TOKEN_TRANSFER_TO_ZERO_ADDRESS(); // 0xe219bd39
error SUPER_TOKEN_NFT_PROXY_ADDRESS_CHANGED(); // 0x6bef249d
/**
* @dev Initialize the contract
*/
function initialize(
IERC20 underlyingToken,
uint8 underlyingDecimals,
string calldata n,
string calldata s
) external;
/**
* @dev Initialize the contract with an admin
*/
function initializeWithAdmin(
IERC20 underlyingToken,
uint8 underlyingDecimals,
string calldata n,
string calldata s,
address admin
) external;
/**
* @notice Changes the admin for the SuperToken
* @dev Only the current admin can call this function
* if admin is address(0), it is implicitly the host address
* @param newAdmin New admin address
*/
function changeAdmin(address newAdmin) external;
event AdminChanged(address indexed oldAdmin, address indexed newAdmin);
/**
* @dev Returns the admin address for the SuperToken
*/
function getAdmin() external view returns (address admin);
/**************************************************************************
* Immutable variables
*************************************************************************/
// solhint-disable-next-line func-name-mixedcase
function CONSTANT_OUTFLOW_NFT() external view returns (IConstantOutflowNFT);
// solhint-disable-next-line func-name-mixedcase
function CONSTANT_INFLOW_NFT() external view returns (IConstantInflowNFT);
// solhint-disable-next-line func-name-mixedcase
function POOL_ADMIN_NFT() external view returns (IPoolAdminNFT);
// solhint-disable-next-line func-name-mixedcase
function POOL_MEMBER_NFT() external view returns (IPoolMemberNFT);
/**************************************************************************
* IERC20Metadata & ERC777
*************************************************************************/
/**
* @dev Returns the name of the token.
*/
function name() external view override(IERC777, IERC20Metadata) returns (string memory);
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() external view override(IERC777, IERC20Metadata) returns (string memory);
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5,05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
* called.
*
* @custom:note SuperToken always uses 18 decimals.
*
* This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() external view override(IERC20Metadata) returns (uint8);
/**************************************************************************
* ERC20 & ERC777
*************************************************************************/
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() external view override(IERC777, IERC20) returns (uint256);
/**
* @dev Returns the amount of tokens owned by an account (`owner`).
*/
function balanceOf(address account) external view override(IERC777, IERC20) returns(uint256 balance);
/**************************************************************************
* ERC20
*************************************************************************/
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* @return Returns Success a boolean value indicating whether the operation succeeded.
*
* @custom:emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external override(IERC20) returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* @notice This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external override(IERC20) view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* @return Returns Success a boolean value indicating whether the operation succeeded.
*
* @custom:note Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* @custom:emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external override(IERC20) returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* @return Returns Success a boolean value indicating whether the operation succeeded.
*
* @custom:emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external override(IERC20) returns (bool);
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* @custom:emits an {Approval} event indicating the updated allowance.
*
* @custom:requirements
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* @custom:emits an {Approval} event indicating the updated allowance.
*
* @custom:requirements
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
/**************************************************************************
* ERC777
*************************************************************************/
/**
* @dev Returns the smallest part of the token that is not divisible. This
* means all token operations (creation, movement and destruction) must have
* amounts that are a multiple of this number.
*
* @custom:note For super token contracts, this value is always 1
*/
function granularity() external view override(IERC777) returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* @dev If send or receive hooks are registered for the caller and `recipient`,
* the corresponding functions will be called with `userData` and empty
* `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
*
* @custom:emits a {Sent} event.
*
* @custom:requirements
* - the caller must have at least `amount` tokens.
* - `recipient` cannot be the zero address.
* - if `recipient` is a contract, it must implement the {IERC777Recipient}
* interface.
*/
function send(address recipient, uint256 amount, bytes calldata userData) external override(IERC777);
/**
* @dev Destroys `amount` tokens from the caller's account, reducing the
* total supply and transfers the underlying token to the caller's account.
*
* If a send hook is registered for the caller, the corresponding function
* will be called with `userData` and empty `operatorData`. See {IERC777Sender}.
*
* @custom:emits a {Burned} event.
*
* @custom:requirements
* - the caller must have at least `amount` tokens.
*/
function burn(uint256 amount, bytes calldata userData) external override(IERC777);
/**
* @dev Returns true if an account is an operator of `tokenHolder`.
* Operators can send and burn tokens on behalf of their owners. All
* accounts are their own operator.
*
* See {operatorSend} and {operatorBurn}.
*/
function isOperatorFor(address operator, address tokenHolder) external override(IERC777) view returns (bool);
/**
* @dev Make an account an operator of the caller.
*
* See {isOperatorFor}.
*
* @custom:emits an {AuthorizedOperator} event.
*
* @custom:requirements
* - `operator` cannot be calling address.
*/
function authorizeOperator(address operator) external override(IERC777);
/**
* @dev Revoke an account's operator status for the caller.
*
* See {isOperatorFor} and {defaultOperators}.
*
* @custom:emits a {RevokedOperator} event.
*
* @custom:requirements
* - `operator` cannot be calling address.
*/
function revokeOperator(address operator) external override(IERC777);
/**
* @dev Returns the list of default operators. These accounts are operators
* for all token holders, even if {authorizeOperator} was never called on
* them.
*
* This list is immutable, but individual holders may revoke these via
* {revokeOperator}, in which case {isOperatorFor} will return false.
*/
function defaultOperators() external override(IERC777) view returns (address[] memory);
/**
* @dev Moves `amount` tokens from `sender` to `recipient`. The caller must
* be an operator of `sender`.
*
* If send or receive hooks are registered for `sender` and `recipient`,
* the corresponding functions will be called with `userData` and
* `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
*
* @custom:emits a {Sent} event.
*
* @custom:requirements
* - `sender` cannot be the zero address.
* - `sender` must have at least `amount` tokens.
* - the caller must be an operator for `sender`.
* - `recipient` cannot be the zero address.
* - if `recipient` is a contract, it must implement the {IERC777Recipient}
* interface.
*/
function operatorSend(
address sender,
address recipient,
uint256 amount,
bytes calldata userData,
bytes calldata operatorData
) external override(IERC777);
/**
* @dev Destroys `amount` tokens from `account`, reducing the total supply.
* The caller must be an operator of `account`.
*
* If a send hook is registered for `account`, the corresponding function
* will be called with `userData` and `operatorData`. See {IERC777Sender}.
*
* @custom:emits a {Burned} event.
*
* @custom:requirements
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
* - the caller must be an operator for `account`.
*/
function operatorBurn(
address account,
uint256 amount,
bytes calldata userData,
bytes calldata operatorData
) external override(IERC777);
/**************************************************************************
* SuperToken custom token functions
*************************************************************************/
/**
* @dev Mint new tokens for the account
* If `userData` is not empty, the `tokensReceived` hook is invoked according to ERC777 semantics.
*
* @custom:modifiers
* - onlySelf
*/
function selfMint(
address account,
uint256 amount,
bytes memory userData
) external;
/**
* @dev Burn existing tokens for the account
* If `userData` is not empty, the `tokensToSend` hook is invoked according to ERC777 semantics.
*
* @custom:modifiers
* - onlySelf
*/
function selfBurn(
address account,
uint256 amount,
bytes memory userData
) external;
/**
* @dev Transfer `amount` tokens from the `sender` to `recipient`.
* If `spender` isn't the same as `sender`, checks if `spender` has allowance to
* spend tokens of `sender`.
*
* @custom:modifiers
* - onlySelf
*/
function selfTransferFrom(
address sender,
address spender,
address recipient,
uint256 amount
) external;
/**
* @dev Give `spender`, `amount` allowance to spend the tokens of
* `account`.
*
* @custom:modifiers
* - onlySelf
*/
function selfApproveFor(
address account,
address spender,
uint256 amount
) external;
/**************************************************************************
* SuperToken extra functions
*************************************************************************/
/**
* @dev Transfer all available balance from `msg.sender` to `recipient`
*/
function transferAll(address recipient) external;
/**************************************************************************
* ERC20 wrapping
*************************************************************************/
/**
* @dev Return the underlying token contract
* @return tokenAddr Underlying token address
*/
function getUnderlyingToken() external view returns(address tokenAddr);
/**
* @dev Return the underlying token decimals
* @return underlyingDecimals Underlying token decimals
*/
function getUnderlyingDecimals() external view returns (uint8 underlyingDecimals);
/**
* @dev Return the underlying token conversion rate
* @param amount Number of tokens to be upgraded (in 18 decimals)
* @return underlyingAmount The underlying token amount after scaling
* @return adjustedAmount The super token amount after scaling
*/
function toUnderlyingAmount(uint256 amount)
external
view
returns (uint256 underlyingAmount, uint256 adjustedAmount);
/**
* @dev Upgrade ERC20 to SuperToken.
* @param amount Number of tokens to be upgraded (in 18 decimals)
*
* @custom:note It will use `transferFrom` to get tokens. Before calling this
* function you should `approve` this contract
*/
function upgrade(uint256 amount) external;
/**
* @dev Upgrade ERC20 to SuperToken and transfer immediately
* @param to The account to receive upgraded tokens
* @param amount Number of tokens to be upgraded (in 18 decimals)
* @param userData User data for the TokensRecipient callback
*
* @custom:note It will use `transferFrom` to get tokens. Before calling this
* function you should `approve` this contract
*
* @custom:warning
* - there is potential of reentrancy IF the "to" account is a registered ERC777 recipient.
* @custom:requirements
* - if `userData` is NOT empty AND `to` is a contract, it MUST be a registered ERC777 recipient
* otherwise it reverts.
*/
function upgradeTo(address to, uint256 amount, bytes calldata userData) external;
/**
* @dev Token upgrade event
* @param account Account where tokens are upgraded to
* @param amount Amount of tokens upgraded (in 18 decimals)
*/
event TokenUpgraded(
address indexed account,
uint256 amount
);
/**
* @dev Downgrade SuperToken to ERC20.
* @dev It will call transfer to send tokens
* @param amount Number of tokens to be downgraded
*/
function downgrade(uint256 amount) external;
/**
* @dev Downgrade SuperToken to ERC20 and transfer immediately
* @param to The account to receive downgraded tokens
* @param amount Number of tokens to be downgraded (in 18 decimals)
*/
function downgradeTo(address to, uint256 amount) external;
/**
* @dev Token downgrade event
* @param account Account whose tokens are downgraded
* @param amount Amount of tokens downgraded
*/
event TokenDowngraded(
address indexed account,
uint256 amount
);
/**************************************************************************
* Batch Operations
*************************************************************************/
/**
* @dev Perform ERC20 approve by host contract.
* @param account The account owner to be approved.
* @param spender The spender of account owner's funds.
* @param amount Number of tokens to be approved.
*
* @custom:modifiers
* - onlyHost
*/
function operationApprove(
address account,
address spender,
uint256 amount
) external;
function operationIncreaseAllowance(
address account,
address spender,
uint256 addedValue
) external;
function operationDecreaseAllowance(
address account,
address spender,
uint256 subtractedValue
) external;
/**
* @dev Perform ERC20 transferFrom by host contract.
* @param account The account to spend sender's funds.
* @param spender The account where the funds is sent from.
* @param recipient The recipient of the funds.
* @param amount Number of tokens to be transferred.
*
* @custom:modifiers
* - onlyHost
*/
function operationTransferFrom(
address account,
address spender,
address recipient,
uint256 amount
) external;
/**
* @dev Perform ERC777 send by host contract.
* @param spender The account where the funds is sent from.
* @param recipient The recipient of the funds.
* @param amount Number of tokens to be transferred.
* @param userData Arbitrary user inputted data
*
* @custom:modifiers
* - onlyHost
*/
function operationSend(
address spender,
address recipient,
uint256 amount,
bytes memory userData
) external;
/**
* @dev Upgrade ERC20 to SuperToken by host contract.
* @param account The account to be changed.
* @param amount Number of tokens to be upgraded (in 18 decimals)
*
* @custom:modifiers
* - onlyHost
*/
function operationUpgrade(address account, uint256 amount) external;
/**
* @dev Downgrade ERC20 to SuperToken by host contract.
* @param account The account to be changed.
* @param amount Number of tokens to be downgraded (in 18 decimals)
*
* @custom:modifiers
* - onlyHost
*/
function operationDowngrade(address account, uint256 amount) external;
/**
* @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;
// Flow NFT events
/**
* @dev Constant Outflow NFT proxy created event
* @param constantOutflowNFT constant outflow nft address
*/
event ConstantOutflowNFTCreated(
IConstantOutflowNFT indexed constantOutflowNFT
);
/**
* @dev Constant Inflow NFT proxy created event
* @param constantInflowNFT constant inflow nft address
*/
event ConstantInflowNFTCreated(
IConstantInflowNFT indexed constantInflowNFT
);
/**
* @dev Pool Admin NFT proxy created event
* @param poolAdminNFT pool admin nft address
*/
event PoolAdminNFTCreated(
IPoolAdminNFT indexed poolAdminNFT
);
/**
* @dev Pool Member NFT proxy created event
* @param poolMemberNFT pool member nft address
*/
event PoolMemberNFTCreated(
IPoolMemberNFT indexed poolMemberNFT
);
/**************************************************************************
* Function modifiers for access control and parameter validations
*
* While they cannot be explicitly stated in function definitions, they are
* listed in function definition comments instead for clarity.
*
* NOTE: solidity-coverage not supporting it
*************************************************************************/
/// @dev The msg.sender must be the contract itself
//modifier onlySelf() virtual
}// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;
import { 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 { 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 { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
interface IFlowNFTBase is IERC721Metadata {
// FlowNFTData struct storage packing:
// b = bits
// WORD 1: | superToken | FREE
// | 160b | 96b
// WORD 2: | flowSender | FREE
// | 160b | 96b
// WORD 3: | flowReceiver | flowStartDate | FREE
// | 160b | 32b | 64b
struct FlowNFTData {
address superToken;
address flowSender;
address flowReceiver;
uint32 flowStartDate;
}
/**************************************************************************
* Custom Errors
*************************************************************************/
error CFA_NFT_APPROVE_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); // 0xa3352582
error CFA_NFT_APPROVE_TO_CALLER(); // 0xd3c77329
error CFA_NFT_APPROVE_TO_CURRENT_OWNER(); // 0xe4790b25
error CFA_NFT_INVALID_TOKEN_ID(); // 0xeab95e3b
error CFA_NFT_ONLY_SUPER_TOKEN_FACTORY(); // 0xebb7505b
error CFA_NFT_TRANSFER_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); // 0x2551d606
error CFA_NFT_TRANSFER_FROM_INCORRECT_OWNER(); // 0x5a26c744
error CFA_NFT_TRANSFER_IS_NOT_ALLOWED(); // 0xaa747eca
error CFA_NFT_TRANSFER_TO_ZERO_ADDRESS(); // 0xde06d21e
/**************************************************************************
* Events
*************************************************************************/
/// @notice Informs third-party platforms that NFT metadata should be updated
/// @dev This event comes from https://eips.ethereum.org/EIPS/eip-4906
/// @param tokenId the id of the token that should have its metadata updated
event MetadataUpdate(uint256 tokenId);
/**************************************************************************
* View
*************************************************************************/
/// @notice An external function for querying flow data by `tokenId``
/// @param tokenId the token id
/// @return flowData the flow data associated with `tokenId`
function flowDataByTokenId(
uint256 tokenId
) external view returns (FlowNFTData memory flowData);
/// @notice An external function for computing the deterministic tokenId
/// @dev tokenId = uint256(keccak256(abi.encode(block.chainId, superToken, flowSender, flowReceiver)))
/// @param superToken the super token
/// @param flowSender the flow sender
/// @param flowReceiver the flow receiver
/// @return tokenId the tokenId
function getTokenId(
address superToken,
address flowSender,
address flowReceiver
) external view returns (uint256);
/**************************************************************************
* Write
*************************************************************************/
function initialize(
string memory nftName,
string memory nftSymbol
) external; // initializer;
function triggerMetadataUpdate(uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;
import { ISuperfluidToken } from "./ISuperfluidToken.sol";
import { IFlowNFTBase } from "./IFlowNFTBase.sol";
interface IConstantOutflowNFT is IFlowNFTBase {
/**************************************************************************
* Custom Errors
*************************************************************************/
error COF_NFT_INVALID_SUPER_TOKEN(); // 0x6de98774
error COF_NFT_MINT_TO_AND_FLOW_RECEIVER_SAME(); // 0x0d1d1161
error COF_NFT_MINT_TO_ZERO_ADDRESS(); // 0x43d05e51
error COF_NFT_ONLY_CONSTANT_INFLOW(); // 0xa495a718
error COF_NFT_ONLY_FLOW_AGREEMENTS(); // 0xd367b64f
error COF_NFT_TOKEN_ALREADY_EXISTS(); // 0xe2480183
/**************************************************************************
* Write Functions
*************************************************************************/
/// @notice The onCreate function is called when a new flow is created.
/// @param token the super token passed from the CFA (flowVars)
/// @param flowSender the flow sender
/// @param flowReceiver the flow receiver
function onCreate(ISuperfluidToken token, address flowSender, address flowReceiver) external;
/// @notice The onUpdate function is called when a flow is updated.
/// @param token the super token passed from the CFA (flowVars)
/// @param flowSender the flow sender
/// @param flowReceiver the flow receiver
function onUpdate(ISuperfluidToken token, address flowSender, address flowReceiver) external;
/// @notice The onDelete function is called when a flow is deleted.
/// @param token the super token passed from the CFA (flowVars)
/// @param flowSender the flow sender
/// @param flowReceiver the flow receiver
function onDelete(ISuperfluidToken token, address flowSender, address flowReceiver) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;
import { IFlowNFTBase } from "./IFlowNFTBase.sol";
interface IConstantInflowNFT is IFlowNFTBase {
/**************************************************************************
* Custom Errors
*************************************************************************/
error CIF_NFT_ONLY_CONSTANT_OUTFLOW(); // 0xe81ef57a
/**************************************************************************
* Write Functions
*************************************************************************/
/// @notice The mint function emits the "mint" `Transfer` event.
/// @dev We don't modify storage as this is handled in ConstantOutflowNFT.sol and this function's sole purpose
/// is to inform clients that search for events.
/// @param to the flow receiver (inflow NFT receiver)
/// @param newTokenId the new token id
function mint(address to, uint256 newTokenId) external;
/// @notice This burn function emits the "burn" `Transfer` event.
/// @dev We don't modify storage as this is handled in ConstantOutflowNFT.sol and this function's sole purpose
/// is to inform clients that search for events.
/// @param tokenId desired token id to burn
function burn(uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;
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: 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 { ISuperfluidToken } from "./ISuperfluidToken.sol";
/**
* @title Super agreement interface
* @author Superfluid
*/
interface ISuperAgreement {
/**
* @dev Get the type of the agreement class
*/
function agreementType() external view returns (bytes32);
/**
* @dev Calculate the real-time balance for the account of this agreement class
* @param account Account the state belongs to
* @param time Time used for the calculation
* @return dynamicBalance Dynamic balance portion of real-time balance of this agreement
* @return deposit Account deposit amount of this agreement
* @return owedDeposit Account owed deposit amount of this agreement
*/
function realtimeBalanceOf(
ISuperfluidToken token,
address account,
uint256 time
)
external
view
returns (
int256 dynamicBalance,
uint256 deposit,
uint256 owedDeposit
);
}// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.11;
import { 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: MIT
pragma solidity >= 0.8.11;
import { ISuperAgreement } from "../superfluid/ISuperAgreement.sol";
import { ISuperfluidToken } from "../superfluid/ISuperfluidToken.sol";
/**
* @title Instant Distribution Agreement interface
* @author Superfluid
*
* @notice
* - A publisher can create as many as indices as possibly identifiable with `indexId`.
* - `indexId` is deliberately limited to 32 bits, to avoid the chance for sha-3 collision.
* Despite knowing sha-3 collision is only theoretical.
* - A publisher can create a subscription to an index for any subscriber.
* - A subscription consists of:
* - The index it subscribes to.
* - Number of units subscribed.
* - An index consists of:
* - Current value as `uint128 indexValue`.
* - Total units of the approved subscriptions as `uint128 totalUnitsApproved`.
* - Total units of the non approved subscription as `uint128 totalUnitsPending`.
* - A publisher can update an index with a new value that doesn't decrease.
* - A publisher can update a subscription with any number of units.
* - A publisher or a subscriber can delete a subscription and reset its units to zero.
* - A subscriber must approve the index in order to receive distributions from the publisher
* each time the index is updated.
* - The amount distributed is $$\Delta{index} * units$$
* - Distributions to a non approved subscription stays in the publisher's deposit until:
* - the subscriber approves the subscription (side effect),
* - the publisher updates the subscription (side effect),
* - the subscriber deletes the subscription even if it is never approved (side effect),
* - or the subscriber can explicitly claim them.
*/
abstract contract IInstantDistributionAgreementV1 is ISuperAgreement {
/**************************************************************************
* Errors
*************************************************************************/
error IDA_INDEX_SHOULD_GROW(); // 0xcfdca725
error IDA_OPERATION_NOT_ALLOWED(); // 0x92da6d17
error IDA_INDEX_ALREADY_EXISTS(); // 0x5c02a517
error IDA_INDEX_DOES_NOT_EXIST(); // 0xedeaa63b
error IDA_SUBSCRIPTION_DOES_NOT_EXIST(); // 0xb6c8c980
error IDA_SUBSCRIPTION_ALREADY_APPROVED(); // 0x3eb2f849
error IDA_SUBSCRIPTION_IS_NOT_APPROVED(); // 0x37412573
error IDA_INSUFFICIENT_BALANCE(); // 0x16e759bb
error IDA_ZERO_ADDRESS_SUBSCRIBER(); // 0xc90a4674
/// @dev ISuperAgreement.agreementType implementation
function agreementType() external override pure returns (bytes32) {
return keccak256("org.superfluid-finance.agreements.InstantDistributionAgreement.v1");
}
/**************************************************************************
* Index operations
*************************************************************************/
/**
* @dev Create a new index for the publisher
* @param token Super token address
* @param indexId Id of the index
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* None
*/
function createIndex(
ISuperfluidToken token,
uint32 indexId,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Index created event
* @param token Super token address
* @param publisher Index creator and publisher
* @param indexId The specified indexId of the newly created index
* @param userData The user provided data
*/
event IndexCreated(
ISuperfluidToken indexed token,
address indexed publisher,
uint32 indexed indexId,
bytes userData);
/**
* @dev Query the data of a index
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @return exist Does the index exist
* @return indexValue Value of the current index
* @return totalUnitsApproved Total units approved for the index
* @return totalUnitsPending Total units pending approval for the index
*/
function getIndex(
ISuperfluidToken token,
address publisher,
uint32 indexId)
external
view
virtual
returns(
bool exist,
uint128 indexValue,
uint128 totalUnitsApproved,
uint128 totalUnitsPending);
/**
* @dev Calculate actual distribution amount
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @param amount The amount of tokens desired to be distributed
* @return actualAmount The amount to be distributed after ensuring no rounding errors
* @return newIndexValue The index value given the desired amount of tokens to be distributed
*/
function calculateDistribution(
ISuperfluidToken token,
address publisher,
uint32 indexId,
uint256 amount)
external view
virtual
returns(
uint256 actualAmount,
uint128 newIndexValue);
/**
* @dev Update index value of an index
* @param token Super token address
* @param indexId Id of the index
* @param indexValue Value of the index
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* None
*/
function updateIndex(
ISuperfluidToken token,
uint32 indexId,
uint128 indexValue,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Index updated event
* @param token Super token address
* @param publisher Index updater and publisher
* @param indexId The specified indexId of the updated index
* @param oldIndexValue The previous index value
* @param newIndexValue The updated index value
* @param totalUnitsPending The total units pending when the indexValue was updated
* @param totalUnitsApproved The total units approved when the indexValue was updated
* @param userData The user provided data
*/
event IndexUpdated(
ISuperfluidToken indexed token,
address indexed publisher,
uint32 indexed indexId,
uint128 oldIndexValue,
uint128 newIndexValue,
uint128 totalUnitsPending,
uint128 totalUnitsApproved,
bytes userData);
/**
* @dev Distribute tokens through the index
* @param token Super token address
* @param indexId Id of the index
* @param amount The amount of tokens desired to be distributed
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:note
* - This is a convenient version of updateIndex. It adds to the index
* a delta that equals to `amount / totalUnits`
* - The actual amount distributed could be obtained via
* `calculateDistribution`. This is due to precision error with index
* value and units data range
*
* @custom:callbacks
* None
*/
function distribute(
ISuperfluidToken token,
uint32 indexId,
uint256 amount,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**************************************************************************
* Subscription operations
*************************************************************************/
/**
* @dev Approve the subscription of an index
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* - if subscription exist
* - AgreementCreated callback to the publisher:
* - agreementId is for the subscription
* - if subscription does not exist
* - AgreementUpdated callback to the publisher:
* - agreementId is for the subscription
*/
function approveSubscription(
ISuperfluidToken token,
address publisher,
uint32 indexId,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Index subscribed event
* @param token Super token address
* @param publisher Index publisher
* @param indexId The specified indexId
* @param subscriber The approved subscriber
* @param userData The user provided data
*/
event IndexSubscribed(
ISuperfluidToken indexed token,
address indexed publisher,
uint32 indexed indexId,
address subscriber,
bytes userData);
/**
* @dev Subscription approved event
* @param token Super token address
* @param subscriber The approved subscriber
* @param publisher Index publisher
* @param indexId The specified indexId
* @param userData The user provided data
*/
event SubscriptionApproved(
ISuperfluidToken indexed token,
address indexed subscriber,
address publisher,
uint32 indexId,
bytes userData);
/**
* @notice Revoke the subscription of an index
* @dev "Unapproves" the subscription and moves approved units to pending
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* - AgreementUpdated callback to the publisher:
* - agreementId is for the subscription
*/
function revokeSubscription(
ISuperfluidToken token,
address publisher,
uint32 indexId,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Index unsubscribed event
* @param token Super token address
* @param publisher Index publisher
* @param indexId The specified indexId
* @param subscriber The unsubscribed subscriber
* @param userData The user provided data
*/
event IndexUnsubscribed(
ISuperfluidToken indexed token,
address indexed publisher,
uint32 indexed indexId,
address subscriber,
bytes userData);
/**
* @dev Subscription approved event
* @param token Super token address
* @param subscriber The approved subscriber
* @param publisher Index publisher
* @param indexId The specified indexId
* @param userData The user provided data
*/
event SubscriptionRevoked(
ISuperfluidToken indexed token,
address indexed subscriber,
address publisher,
uint32 indexId,
bytes userData);
/**
* @dev Update the nuber of units of a subscription
* @param token Super token address
* @param indexId Id of the index
* @param subscriber The subscriber of the index
* @param units Number of units of the subscription
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* - if subscription exist
* - AgreementCreated callback to the subscriber:
* - agreementId is for the subscription
* - if subscription does not exist
* - AgreementUpdated callback to the subscriber:
* - agreementId is for the subscription
*/
function updateSubscription(
ISuperfluidToken token,
uint32 indexId,
address subscriber,
uint128 units,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Index units updated event
* @param token Super token address
* @param publisher Index publisher
* @param indexId The specified indexId
* @param subscriber The subscriber units updated
* @param units The new units amount
* @param userData The user provided data
*/
event IndexUnitsUpdated(
ISuperfluidToken indexed token,
address indexed publisher,
uint32 indexed indexId,
address subscriber,
uint128 units,
bytes userData);
/**
* @dev Subscription units updated event
* @param token Super token address
* @param subscriber The subscriber units updated
* @param indexId The specified indexId
* @param publisher Index publisher
* @param units The new units amount
* @param userData The user provided data
*/
event SubscriptionUnitsUpdated(
ISuperfluidToken indexed token,
address indexed subscriber,
address publisher,
uint32 indexId,
uint128 units,
bytes userData);
/**
* @dev Get data of a subscription
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @param subscriber The subscriber of the index
* @return exist Does the subscription exist?
* @return approved Is the subscription approved?
* @return units Units of the suscription
* @return pendingDistribution Pending amount of tokens to be distributed for unapproved subscription
*/
function getSubscription(
ISuperfluidToken token,
address publisher,
uint32 indexId,
address subscriber)
external
view
virtual
returns(
bool exist,
bool approved,
uint128 units,
uint256 pendingDistribution
);
/**
* @notice Get data of a subscription by agreement ID
* @dev indexId (agreementId) is the keccak256 hash of encodePacked("publisher", publisher, indexId)
* @param token Super token address
* @param agreementId The agreement ID
* @return publisher The publisher of the index
* @return indexId Id of the index
* @return approved Is the subscription approved?
* @return units Units of the suscription
* @return pendingDistribution Pending amount of tokens to be distributed for unapproved subscription
*/
function getSubscriptionByID(
ISuperfluidToken token,
bytes32 agreementId)
external
view
virtual
returns(
address publisher,
uint32 indexId,
bool approved,
uint128 units,
uint256 pendingDistribution
);
/**
* @dev List subscriptions of an user
* @param token Super token address
* @param subscriber The subscriber's address
* @return publishers Publishers of the subcriptions
* @return indexIds Indexes of the subscriptions
* @return unitsList Units of the subscriptions
*/
function listSubscriptions(
ISuperfluidToken token,
address subscriber)
external
view
virtual
returns(
address[] memory publishers,
uint32[] memory indexIds,
uint128[] memory unitsList);
/**
* @dev Delete the subscription of an user
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @param subscriber The subscriber's address
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:callbacks
* - if the subscriber called it
* - AgreementTerminated callback to the publsiher:
* - agreementId is for the subscription
* - if the publisher called it
* - AgreementTerminated callback to the subscriber:
* - agreementId is for the subscription
*/
function deleteSubscription(
ISuperfluidToken token,
address publisher,
uint32 indexId,
address subscriber,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Claim pending distributions
* @param token Super token address
* @param publisher The publisher of the index
* @param indexId Id of the index
* @param subscriber The subscriber's address
* @param ctx Context bytes (see ISuperfluid.sol for Context struct)
*
* @custom:note The subscription should not be approved yet
*
* @custom:callbacks
* - AgreementUpdated callback to the publisher:
* - agreementId is for the subscription
*/
function claim(
ISuperfluidToken token,
address publisher,
uint32 indexId,
address subscriber,
bytes calldata ctx)
external
virtual
returns(bytes memory newCtx);
/**
* @dev Index distribution claimed event
* @param token Super token address
* @param publisher Index publisher
* @param indexId The specified indexId
* @param subscriber The subscriber units updated
* @param amount The pending amount claimed
*/
event IndexDistributionClaimed(
ISuperfluidToken indexed token,
address indexed publisher,
uint32 indexed indexId,
address subscriber,
uint256 amount);
/**
* @dev Subscription distribution claimed event
* @param token Super token address
* @param subscriber The subscriber units updated
* @param publisher Index publisher
* @param indexId The specified indexId
* @param amount The pending amount claimed
*/
event SubscriptionDistributionClaimed(
ISuperfluidToken indexed token,
address indexed subscriber,
address publisher,
uint32 indexId,
uint256 amount);
}// SPDX-License-Identifier: AGPLv3
pragma solidity >=0.8.4;
import { ISuperAgreement } from "../../superfluid/ISuperAgreement.sol";
import { ISuperfluidToken } from "../../superfluid/ISuperfluidToken.sol";
import { ISuperfluidPool } from "../../agreements/gdav1/ISuperfluidPool.sol";
struct PoolConfig {
/// @dev if true, the pool members can transfer their owned units
/// else, only the pool admin can manipulate the units for pool members
bool transferabilityForUnitsOwner;
/// @dev if true, anyone can execute distributions via the pool
/// else, only the pool admin can execute distributions via the pool
bool distributionFromAnyAddress;
}
/**
* @title General Distribution Agreement interface
* @author Superfluid
*/
abstract contract IGeneralDistributionAgreementV1 is ISuperAgreement {
// 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);
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: AGPLv3
pragma solidity >=0.8.4;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ISuperfluidToken } from "../../superfluid/ISuperfluidToken.sol";
/**
* @dev The interface for any super token pool regardless of the distribution schemes.
*/
interface ISuperfluidPool is IERC20 {
// 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: 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 { 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
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.11;
import { ISuperToken } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol";
/**
* @title Interface for the liquidity mover contract
*/
interface ILiquidityMover {
/**
* @notice A callback from torex requesting out token liquidity with in-token liquidity transferred.
* @param inToken The in token transferred to the contract.
* @param outToken The out token that is requested.
* @param inAmount The amount of in token that has been transferred to the contract.
* @param minOutAmount The amount of out token that is requested.
* @param moverData The data that liquidity mover passes through `ITorex.moveLiquidity`.
* @return It must always be true.
*/
function moveLiquidityCallback(ISuperToken inToken, ISuperToken outToken,
uint256 inAmount, uint256 minOutAmount,
bytes calldata moverData)
external returns (bool);
}// 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 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: 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
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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);
}{
"remappings": [
"@uniswap/v3-core/=lib/uniswap-v3-core/",
"@uniswap/v3-periphery/=lib/uniswap-v3-periphery/",
"@superfluid-finance/ethereum-contracts/=lib/superfluid-protocol-monorepo/packages/ethereum-contracts/",
"@superfluid-finance/solidity-semantic-money/=lib/superfluid-protocol-monorepo/packages/solidity-semantic-money/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts/contracts/",
"superfluid-protocol-monorepo/=lib/superfluid-protocol-monorepo/packages/solidity-semantic-money/src/",
"uniswap-v3-core/=lib/uniswap-v3-core/contracts/",
"uniswap-v3-periphery/=lib/uniswap-v3-periphery/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"components":[{"internalType":"contract ISuperToken","name":"inToken","type":"address"},{"internalType":"contract ISuperToken","name":"outToken","type":"address"},{"internalType":"contract ITwapObserver","name":"observer","type":"address"},{"internalType":"DiscountFactor","name":"discountFactor","type":"uint256"},{"internalType":"Scaler","name":"twapScaler","type":"int256"},{"internalType":"Scaler","name":"outTokenDistributionPoolScaler","type":"int256"},{"internalType":"contract ITorexController","name":"controller","type":"address"},{"internalType":"uint256","name":"controllerSafeCallbackGasLimit","type":"uint256"},{"internalType":"uint256","name":"maxAllowedFeePM","type":"uint256"}],"internalType":"struct Torex.Config","name":"config","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"LIQUIDITY_MOVER_SENT_INSUFFICIENT_OUT_TOKENS","type":"error"},{"inputs":[],"name":"NotAcceptedSuperToken","type":"error"},{"inputs":[],"name":"NotImplemented","type":"error"},{"inputs":[],"name":"UnauthorizedHost","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"reason","type":"bytes"}],"name":"ControllerError","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidityMover","type":"address"},{"indexed":false,"internalType":"uint256","name":"durationSinceLastLME","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"twapSinceLastLME","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"inAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minOutAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"actualOutAmount","type":"uint256"}],"name":"LiquidityMoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"int96","name":"newFlowRate","type":"int96"},{"indexed":false,"internalType":"int96","name":"newContribFlowRate","type":"int96"},{"indexed":false,"internalType":"int256","name":"backAdjustment","type":"int256"},{"indexed":false,"internalType":"int96","name":"requestedFeeDistFlowRate","type":"int96"},{"indexed":false,"internalType":"int96","name":"actualFeeDistFlowRate","type":"int96"}],"name":"TorexFlowUpdated","type":"event"},{"inputs":[],"name":"CFAV1_TYPE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONTROLLER_SAFE_CALLBACK_GAS_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HOST","outputs":[{"internalType":"contract ISuperfluid","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ALLOWED_FEE_PM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"internalType":"address","name":"agreementClass","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"agreementData","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"afterAgreementCreated","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"internalType":"address","name":"agreementClass","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"agreementData","type":"bytes"},{"internalType":"bytes","name":"cbdata","type":"bytes"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"afterAgreementTerminated","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"internalType":"address","name":"agreementClass","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"agreementData","type":"bytes"},{"internalType":"bytes","name":"cbdata","type":"bytes"},{"internalType":"bytes","name":"ctx","type":"bytes"}],"name":"afterAgreementUpdated","outputs":[{"internalType":"bytes","name":"newCtx","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"beforeAgreementCreated","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"internalType":"address","name":"agreementClass","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"agreementData","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"beforeAgreementTerminated","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"superToken","type":"address"},{"internalType":"address","name":"agreementClass","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"agreementData","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"beforeAgreementUpdated","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract ITorexController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controllerInternalErrorCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"debugCurrentDetails","outputs":[{"internalType":"int96","name":"requestedFeeDistFlowRate","type":"int96"},{"internalType":"int96","name":"actualFeeDistFlowRate","type":"int96"},{"internalType":"uint256","name":"feeDistBuffer","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int96","name":"flowRate","type":"int96"}],"name":"estimateApprovalRequired","outputs":[{"internalType":"uint256","name":"requiredApproval","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeDistributionPool","outputs":[{"internalType":"contract ISuperfluidPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"inAmount","type":"uint256"}],"name":"getBenchmarkQuote","outputs":[{"internalType":"uint256","name":"minOutAmount","type":"uint256"},{"internalType":"uint256","name":"durationSinceLastLME","type":"uint256"},{"internalType":"uint256","name":"twapSinceLastLME","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"components":[{"internalType":"contract ISuperToken","name":"inToken","type":"address"},{"internalType":"contract ISuperToken","name":"outToken","type":"address"},{"internalType":"contract ITwapObserver","name":"observer","type":"address"},{"internalType":"DiscountFactor","name":"discountFactor","type":"uint256"},{"internalType":"Scaler","name":"twapScaler","type":"int256"},{"internalType":"Scaler","name":"outTokenDistributionPoolScaler","type":"int256"},{"internalType":"contract ITorexController","name":"controller","type":"address"},{"internalType":"uint256","name":"controllerSafeCallbackGasLimit","type":"uint256"},{"internalType":"uint256","name":"maxAllowedFeePM","type":"uint256"}],"internalType":"struct Torex.Config","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"activateOnCreated","type":"bool"},{"internalType":"bool","name":"activateOnUpdated","type":"bool"},{"internalType":"bool","name":"activateOnDeleted","type":"bool"}],"name":"getConfigWord","outputs":[{"internalType":"uint256","name":"configWord","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getDurationSinceLastLME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLiquidityEstimations","outputs":[{"internalType":"uint256","name":"inAmount","type":"uint256"},{"internalType":"uint256","name":"minOutAmount","type":"uint256"},{"internalType":"uint256","name":"durationSinceLastLME","type":"uint256"},{"internalType":"uint256","name":"twapSinceLastLME","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPairedTokens","outputs":[{"internalType":"contract ISuperToken","name":"inToken","type":"address"},{"internalType":"contract ISuperToken","name":"outToken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"getTraderState","outputs":[{"components":[{"internalType":"int96","name":"contribFlowRate","type":"int96"},{"internalType":"int96","name":"feeFlowRate","type":"int96"}],"internalType":"struct Torex.TraderState","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISuperToken","name":"superToken","type":"address"}],"name":"isAcceptedSuperToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"moverData","type":"bytes"}],"name":"moveLiquidity","outputs":[{"components":[{"internalType":"uint256","name":"durationSinceLastLME","type":"uint256"},{"internalType":"uint256","name":"twapSinceLastLME","type":"uint256"},{"internalType":"uint256","name":"inAmount","type":"uint256"},{"internalType":"uint256","name":"minOutAmount","type":"uint256"},{"internalType":"uint256","name":"outAmount","type":"uint256"},{"internalType":"uint256","name":"actualOutAmount","type":"uint256"}],"internalType":"struct LiquidityMoveResult","name":"result","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"outTokenDistributionPool","outputs":[{"internalType":"contract ISuperfluidPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"activateOnCreated","type":"bool"},{"internalType":"bool","name":"activateOnUpdated","type":"bool"},{"internalType":"bool","name":"activateOnDeleted","type":"bool"}],"name":"selfRegister","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6102006040523480156200001257600080fd5b506040516200428938038062004289833981016040819052620000359162000580565b80600001516001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000078573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009e919062000620565b8151602080840151604080860151608080880151606089015160a0808b0151600160008181556001600160a01b03808d16909752868a16845286881660c05260e08690526101008590526101208390528851808a0190995288529887019890985251959693959194909392620001189216903090620002c2565b6001600160a01b03908116610140529687166101605250505050602084810151604080516320bc442560e01b8152905191909516946320bc4425945060048082019450908290030181865afa15801562000176573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200019c919062000620565b6001600160a01b031681600001516001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001e8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200020e919062000620565b6001600160a01b03161462000227576200022762000647565b60408101516001600160a01b031662000244576200024462000647565b620f424081610100015111156200025f576200025f62000647565b60c08101516001600160a01b039081166101c081905260e0830151610180526101008301516101a052604080518082019091526000815260016020820152608051620002ae93169190620002c2565b6001600160a01b03166101e052506200065d565b600080620002d0856200036a565b604051630779d36560e01b81526001600160a01b03888116600483015287811660248301528651151560448301526020870151151560648301529193509083169150630779d365906084016020604051808303816000875af11580156200033b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000361919062000620565b95945050505050565b7f65599bf746e17a00ea62e3610586992d88101b78eec3cf380706621fb97ea8375460008051602062004269833981519152546001600160a01b038116620004e6576001600160a01b0382166200042357826001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa158015620003fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000420919062000620565b91505b604051635b69006f60e11b81527fdfd8ece9bfbcb8c5c540edb935641f63d67686490a1ab97f000288759f30a94660048201526001600160a01b0383169063b6d200de90602401602060405180830381865afa15801562000488573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004ae919062000620565b9050817f65599bf746e17a00ea62e3610586992d88101b78eec3cf380706621fb97ea837558060008051602062004269833981519152555b6001600160a01b038216620004ff57620004ff62000647565b6001600160a01b03811662000518576200051862000647565b915091565b60405161012081016001600160401b03811182821017156200054f57634e487b7160e01b600052604160045260246000fd5b60405290565b6001600160a01b03811681146200056b57600080fd5b50565b80516200057b8162000555565b919050565b600061012082840312156200059457600080fd5b6200059e6200051d565b620005a9836200056e565b8152620005b9602084016200056e565b6020820152620005cc604084016200056e565b6040820152606083015160608201526080830151608082015260a083015160a0820152620005fd60c084016200056e565b60c082015260e08381015190820152610100928301519281019290925250919050565b6000602082840312156200063357600080fd5b8151620006408162000555565b9392505050565b634e487b7160e01b600052600160045260246000fd5b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e051613a31620008386000396000818161021701528181612024015261207f01526000818161054601528181610ded015281816110730152818161110101528181611ace01528181611b420152611cbb01526000818161043b01528181610a7e01528181610e420152611d7b0152600081816104af01528181610e1c0152611af0015260008181610282015281816105a6015281816106f3015281816108c801528181610b4901528181610e7601528181610f54015281816112260152611c0201526000818161045f01528181611a2901528181611a8801526127d8015260008181610dc7015261277001526000818161088d0152610d7b0152600081816108610152610da10152600081816107ee015281816109b801528181610d4c015261197b0152600081816102d701528181610d1d01528181611839015281816118c801528181611a040152611a630152600081816102b201528181610a3201528181610adb01528181610cee0152818161130f015281816113500152818161177c0152818161181701528181611eb001528181611f3c01528181611fff0152818161205c01526120e90152613a316000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c80638413a40e116100f9578063c3f909d411610097578063e4fe205611610071578063e4fe205614610521578063f77c479114610541578063faf3dab314610568578063ffa1ad741461057157600080fd5b8063c3f909d4146104e4578063d86ed3e5146104f9578063dc7316e81461050c57600080fd5b8063b3bce9b1116100d3578063b3bce9b11461045d578063bcb4546f14610483578063c033dd42146104aa578063c0968ca4146104d157600080fd5b80638413a40e14610410578063884d1f40146104235780639b59757f1461043657600080fd5b806351f6511f116101665780635f9e7d77116101405780635f9e7d771461034357806360de29091461035657806368e2fe8e146103d757806372ca8a3e146103ed57600080fd5b806351f6511f146102a457806353c11f99146103025780635ce9d0ed1461031557600080fd5b8063230dbd29146101ae57806330d9c915146101d7578063406ba646146101ea57806348c52a0114610212578063490972c11461025157806349f289dc1461027d575b600080fd5b6101c16101bc366004612eb6565b610599565b6040516101ce9190612fd1565b60405180910390f35b6101c16101e5366004612fe4565b61069b565b6101f26106c0565b6040805194855260208501939093529183015260608201526080016101ce565b6102397f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101ce565b60025460035460408051600b84810b8252600160601b90940490930b60208401528201526060016101ce565b6102397f000000000000000000000000000000000000000000000000000000000000000081565b604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f0000000000000000000000000000000000000000000000000000000000000000166020820152016101ce565b6101c1610310366004612eb6565b6106e6565b610328610323366004613083565b6107c3565b604080519384526020840192909252908201526060016101ce565b6101c1610351366004612fe4565b6108bb565b6103b561036436600461309c565b6040805180820190915260008082526020820152506001600160a01b0316600090815260016020908152604091829020825180840190935254600b81810b8452600160601b909104900b9082015290565b604080518251600b90810b8252602093840151900b92810192909252016101ce565b6103df6109a0565b6040519081526020016101ce565b6104006103fb36600461309c565b610a30565b60405190151581526020016101ce565b6103df61041e3660046130c8565b610a62565b6101c1610431366004612fe4565b610b3c565b6103df7f000000000000000000000000000000000000000000000000000000000000000081565b7f0000000000000000000000000000000000000000000000000000000000000000610239565b6103df7fa9214cc96615e0085d3bb077758db69497dc2dce3b2b1e97bc93c3d18d83efd381565b6103df7f000000000000000000000000000000000000000000000000000000000000000081565b6103df6104df3660046130f3565b610c39565b6104ec610c6d565b6040516101ce919061313e565b6101c1610507366004612eb6565b610e69565b61051f61051a3660046130f3565b610f52565b005b61053461052f3660046131dc565b610fe1565b6040516101ce919061321e565b6102397f000000000000000000000000000000000000000000000000000000000000000081565b6103df60045481565b6101c160405180604001604052806009815260200168312e302e302d72633360b81b81525081565b6060336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105e457604051632f2d36a760e01b815260040160405180910390fd5b6105ed896111ee565b6106305782828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092935061068e92505050565b6106398a610a30565b61065657604051631ea25bab60e31b815260040160405180910390fd5b600061066487890189613262565b5090506000806106768789018961329b565b915091506106888d8484848a8a6112b4565b93505050505b9998505050505050505050565b604080518082019091526002815261060f60f31b60208201525b979650505050505050565b6000806000806106ce6112f9565b93506106d9846107c3565b9596919590945092509050565b6060336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415806107265750610724896111ee565b155b8061073757506107358a610a30565b155b1561077b5782828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092935061068e92505050565b60008061078a888a018a613262565b909250905060008061079e888a018a6132c7565b915091506107b18e858584868c8c6113e4565b9e9d5050505050505050505050505050565b60405163010b31c760e11b815242600482015260248101829052600090819081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630216638e906044016040805180830381865afa158015610834573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085891906132ec565b925090506108867f000000000000000000000000000000000000000000000000000000000000000082611435565b90506108b37f0000000000000000000000000000000000000000000000000000000000000000828461146a565b949193509150565b6060336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415806108fb57506108f9876111ee565b155b8061090c575061090a88610a30565b155b156109305750604080518082019091526002815261060f60f31b60208201526106b5565b60008061093f86880188613262565b909250905060008061095b6001600160a01b038d1685856114b3565b5050915091508181604051602001610980929190918252600b0b602082015260400190565b604051602081830303815290604052945050505050979650505050505050565b604051630907402360e01b81524260048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630907402390602401602060405180830381865afa158015610a07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2b9190613310565b905090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b600080610a70600084611555565b9150506000610aba620f42407f000000000000000000000000000000000000000000000000000000000000000086600b0b610aab919061333f565b610ab59190613385565b61158b565b600254610aca9190600b0b6133b3565b90506000610b016001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016836115df565b90506003548111610b13576000610b20565b600354610b2090826133e5565b610b298461166c565b610b3391906133f8565b95945050505050565b6060336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b8757604051632f2d36a760e01b815260040160405180910390fd5b610b90876111ee565b610bb35750604080518082019091526002815261060f60f31b60208201526106b5565b610bbc88610a30565b610bd957604051631ea25bab60e31b815260040160405180910390fd5b6000610be785870187613262565b509050600080610c016001600160a01b038c1684306114b3565b505060408051600b9290920b60208301528181019290925281518082038301815260609091019091529b9a5050505050505050505050565b64010000000183610c4c57640200000000175b82610c5957640c00000000175b81610c6657643000000000175b9392505050565b610ce060405180610120016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001600081525090565b6040518061012001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f0000000000000000000000000000000000000000000000000000000000000000815250905090565b6060336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610eb457604051632f2d36a760e01b815260040160405180910390fd5b610ebd896111ee565b610f005782828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092935061068e92505050565b610f098a610a30565b610f2657604051631ea25bab60e31b815260040160405180910390fd5b6000610f3487890189613262565b509050610f438b8286866116be565b9b9a5050505050505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ad3915c8610f8c858585610c39565b6040518263ffffffff1660e01b8152600401610faa91815260200190565b600060405180830381600087803b158015610fc457600080fd5b505af1158015610fd8573d6000803e3d6000fd5b50505050505050565b61101a6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b61105983838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061170492505050565b6040516318cb56bf60e01b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906318cb56bf906110a890849060040161321e565b6020604051808303816000875af11580156110c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110eb919061340b565b6110f7576110f7613428565b60006001905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318cb56bf8460405160240161113f919061321e565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505090506111788282611abd565b505082516020808501516040808701516060808901516080808b015160a0808d015187519a8b52988a019790975294880193909352908601528401528201523392507fc8333a73e4a1a16672a2dcb538b636e96b98466bfa9b61307c9860c9a94c608a915060c00160405180910390a292915050565b604051635b69006f60e11b81527fa9214cc96615e0085d3bb077758db69497dc2dce3b2b1e97bc93c3d18d83efd360048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b6d200de90602401602060405180830381865afa158015611275573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611299919061343e565b6001600160a01b0316826001600160a01b0316149050919050565b60606106b58787878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611be692505050565b6002546000908190611338906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690600b0b6115df565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561139f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c39190613310565b91508082106113dc576113d681836133e5565b91505090565b600091505090565b60606114298888878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611be692505050565b98975050505050505050565b60008281811261145157611449818461345b565b915050611464565b61145a81613472565b611449908461348e565b92915050565b60008383820361147e576000915050610c66565b80156114aa5761148e83826133f8565b611498828661345b565b6114a2919061348e565b915050610c66565b83915050610c66565b60008060008060006114c48861220b565b604051631cd43d1160e31b81526001600160a01b038b811660048301528a811660248301528981166044830152919350908316915063e6a1e88890606401608060405180830381865afa15801561151f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154391906134a2565b929b919a509850909650945050505050565b6000806115606109a0565b915061156c84846134e0565b600b0b6115788361237b565b611582919061333f565b90509250929050565b600060016001605f1b038213156115db5760405162461bcd60e51b815260206004820152600f60248201526e746f496e74393628696e743235362960881b60448201526064015b60405180910390fd5b5090565b6000806115eb8461220b565b6040516346ccbfb760e11b81526001600160a01b038781166004830152600b87900b60248301529193509083169150638d997f6e90604401602060405180830381865afa158015611640573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116649190613310565b949350505050565b6000808212156115db5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f73697469766560448201526064016115d2565b6060610b33858560008087878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611be692505050565b61173d6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6117456123e5565b61174d6106c0565b60208501528352606083015260408083018290525163a9059cbb60e01b815233600482015260248101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af11580156117cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f1919061340b565b50604080820151606083015191516369c9922960e11b8152339263d393245292611864927f0000000000000000000000000000000000000000000000000000000000000000927f000000000000000000000000000000000000000000000000000000000000000092918990600401613512565b6020604051808303816000875af1158015611883573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118a7919061340b565b6118b3576118b3613428565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611917573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193b9190613310565b6080820181905260608201511115611966576040516318b396c960e21b815260040160405180910390fd5b604051639af0a51d60e01b81524260048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639af0a51d906024016020604051808303816000875af11580156119cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f0919061340b565b506080810151611a4e906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169030907f00000000000000000000000000000000000000000000000000000000000000009061243e565b60a08201819052611aad906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169030907f0000000000000000000000000000000000000000000000000000000000000000906124da565b50611ab86001600055565b919050565b600060608315611b40576000611b147f0000000000000000000000000000000000000000000000000000000000000000857f00000000000000000000000000000000000000000000000000000000000000006124fb565b919450909250905082611b3a578015611b3157611b2cfe5b611b3a565b611b3a8261258c565b50611bdf565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031683604051611b78919061354c565b6000604051808303816000865af19150503d8060008114611bb5576040519150601f19603f3d011682016040523d82523d6000602084013e611bba565b606091505b50909250905081611bdf578060405162461bcd60e51b81526004016115d29190612fd1565b9250929050565b604051631fb6491d60e11b815281906000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633f6c923a90611c37908590600401612fd1565b600060405180830381865afa158015611c54573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c7c919081019061365a565b6001600160a01b0380881660009081526001602052604081209293509081908190611caa908c168b306125d9565b9250600083600b0b600014905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663064cb4958d8d89600001600c9054906101000a9004600b0b8e8a8d604001518e60a00151604051602401611d1e9796959493929190613761565b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050509050600080611d5a8484611abd565b915091508115611d7157611d6e8482612671565b94505b50505050620f42407f000000000000000000000000000000000000000000000000000000000000000084600b0b611da8919061333f565b611db29190613385565b81600b0b1315611dc0575060005b611dca81846134e0565b8454600254919350600160601b9004600b90810b91611dec918491900b6133b3565b611df691906134e0565b600280546bffffffffffffffffffffffff19166001600160601b039290921691909117905583546000908190611e31908d90600b0b86612754565b92509050600b8b810b9086900b1315611f0a578554600160601b9004600b90810b9084900b1315611e9c578554600090611e7590600160601b9004600b0b856134e0565b9050611e808261237b565b81600b0b611e8e919061333f565b611e9890846137a9565b9250505b600254600090611ed9906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690600b0b6115df565b9050600354811115611f0857611efb60035482611ef691906133e5565b61237b565b611f0590846137a9565b92505b505b5084546001600160601b03838116600160601b026001600160c01b0319909216908516171785556000811315611fee577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd8c30611f748561166c565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015611fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fec919061340b565b505b60025461204d906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169030907f000000000000000000000000000000000000000000000000000000000000000090600b0b8b612851565b96506120a36001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016307f000000000000000000000000000000000000000000000000000000000000000061297e565b600355600280546001600160601b03909216600160601b026bffffffffffffffffffffffff60601b19909216919091179055506000811215612191576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663a9059cbb8c61212061211b85613472565b61166c565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801561216b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218f919061340b565b505b60025460408051600b87810b825286810b602083015291810184905282820b6060820152600160601b909204900b60808201526001600160a01b038c16907fd34b18010403577a1e7acf8488ab14532641b98ae2329f3893066a56a44d8e919060a00160405180910390a250505050505095945050505050565b6000805160206139dc833981519152547fb969d79d88acd02d04ed7ee7d43b949e7daf093d363abcfbbc43dfdfd1ce969a546001600160a01b03811661234a576001600160a01b0382166122be57826001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa158015612297573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122bb919061343e565b91505b604051635b69006f60e11b81527fa9214cc96615e0085d3bb077758db69497dc2dce3b2b1e97bc93c3d18d83efd360048201526001600160a01b0383169063b6d200de906024015b602060405180830381865afa158015612323573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612347919061343e565b90505b6001600160a01b03821661236057612360613428565b6001600160a01b03811661237657612376613428565b915091565b60006001600160ff1b038211156115db5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b60648201526084016115d2565b6002600054036124375760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016115d2565b6002600055565b60008061244a86612a1c565b60405163eccfc6a560e01b81526001600160a01b0389811660048301528881166024830152878116604483015260648201879052919350908316915063eccfc6a590608401602060405180830381865afa1580156124ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124d09190613310565b9695505050505050565b60408051600080825260208201909252610b33908690869086908690612b1b565b600080606060005a9050866001600160a01b0316858760405161251e919061354c565b60006040518083038160008787f1925050503d806000811461255c576040519150601f19603f3d011682016040523d82523d6000602084013e612561565b606091505b509094509150836125825761257760408261348e565b5a1161258257600192505b5093509350939050565b7fe8c3b3ea3c282ddb0957d4765095bff9515fdb2c678014c641321a7f8a6a3307816040516125bb9190612fd1565b60405180910390a16004600081546125d2906137d1565b9091555050565b6000806125e58561220b565b604051631cd43d1160e31b81526001600160a01b03888116600483015287811660248301528681166044830152919350908316915063e6a1e88890606401608060405180830381865afa158015612640573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266491906134a2565b5090979650505050505050565b600082156127395781516020146126c5576126c06040518060400160405280601881526020017f736166654465636f6465466565466c6f77526174653a2031000000000000000081525061258c565b611464565b6000828060200190518101906126db9190613310565b905060016001605f1b0381111561272f5761272a6040518060400160405280601881526020017f736166654465636f6465466565466c6f77526174653a2032000000000000000081525061258c565b612733565b8091505b50611464565b8180602001905181019061274d91906137ea565b9050611464565b6000806127618484611555565b9092509050600061279e6127997f0000000000000000000000000000000000000000000000000000000000000000600b87900b612c4a565b612c71565b604051631b16777760e01b81526001600160a01b0388811660048301526fffffffffffffffffffffffffffffffff831660248301529192507f000000000000000000000000000000000000000000000000000000000000000090911690631b167777906044016020604051808303816000875af1158015612823573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612847919061340b565b5050935093915050565b606060008061285f88612cd5565b91509150816001600160a01b0316634329d29382836001600160a01b0316635a6c6dbc8c8c8c8c600067ffffffffffffffff8111156128a0576128a0613568565b6040519080825280601f01601f1916602001820160405280156128ca576020820181803683370190505b506040516024016128df959493929190613807565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261292a939250908990600401613845565b6000604051808303816000875af1158015612949573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129719190810190613898565b5098975050505050505050565b60008060008061298d87612a1c565b604051631cd43d1160e31b81526001600160a01b038a8116600483015289811660248301528881166044830152919350908316915063e6a1e88890606401606060405180830381865afa1580156129e8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0c91906138fc565b9350935093505093509350939050565b6000805160206139dc833981519152547fc36f6c05164a669ecb6da53e218d77ae44d51cfc99f91e5a125a18de0949bee4546001600160a01b03811661234a576001600160a01b038216612acf57826001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa158015612aa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612acc919061343e565b91505b604051635b69006f60e11b81527fdfd8ece9bfbcb8c5c540edb935641f63d67686490a1ab97f000288759f30a94660048201526001600160a01b0383169063b6d200de90602401612306565b6000806000612b2988612cd5565b91509150816001600160a01b03166339255d5b82836001600160a01b0316636d1007a68c8c8c8c600067ffffffffffffffff811115612b6a57612b6a613568565b6040519080825280601f01601f191660200182016040528015612b94576020820181803683370190505b50604051602401612ba9959493929190613935565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252612bf4939250908990600401613970565b6000604051808303816000875af1158015612c13573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612c3b91908101906139a6565b50600198975050505050505050565b600082818112612c5e57611449818461333f565b612c6781613472565b6114499084613385565b80600f81900b8114611ab85760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b60648201526084016115d2565b6000805160206139dc833981519152547fc36f6c05164a669ecb6da53e218d77ae44d51cfc99f91e5a125a18de0949bee4546001600160a01b03811661234a576001600160a01b038216612d8857826001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d85919061343e565b91505b604051635b69006f60e11b81527fdfd8ece9bfbcb8c5c540edb935641f63d67686490a1ab97f000288759f30a94660048201526001600160a01b0383169063b6d200de90602401602060405180830381865afa158015612dec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e10919061343e565b9050816000805160206139dc83398151915255807fc36f6c05164a669ecb6da53e218d77ae44d51cfc99f91e5a125a18de0949bee4556001600160a01b03821661236057612360613428565b6001600160a01b0381168114612e7157600080fd5b50565b60008083601f840112612e8657600080fd5b50813567ffffffffffffffff811115612e9e57600080fd5b602083019150836020828501011115611bdf57600080fd5b600080600080600080600080600060c08a8c031215612ed457600080fd5b8935612edf81612e5c565b985060208a0135612eef81612e5c565b975060408a0135965060608a013567ffffffffffffffff80821115612f1357600080fd5b612f1f8d838e01612e74565b909850965060808c0135915080821115612f3857600080fd5b612f448d838e01612e74565b909650945060a08c0135915080821115612f5d57600080fd5b50612f6a8c828d01612e74565b915080935050809150509295985092959850929598565b60005b83811015612f9c578181015183820152602001612f84565b50506000910152565b60008151808452612fbd816020860160208601612f81565b601f01601f19169290920160200192915050565b602081526000610c666020830184612fa5565b600080600080600080600060a0888a031215612fff57600080fd5b873561300a81612e5c565b9650602088013561301a81612e5c565b955060408801359450606088013567ffffffffffffffff8082111561303e57600080fd5b61304a8b838c01612e74565b909650945060808a013591508082111561306357600080fd5b506130708a828b01612e74565b989b979a50959850939692959293505050565b60006020828403121561309557600080fd5b5035919050565b6000602082840312156130ae57600080fd5b8135610c6681612e5c565b80600b0b8114612e7157600080fd5b6000602082840312156130da57600080fd5b8135610c66816130b9565b8015158114612e7157600080fd5b60008060006060848603121561310857600080fd5b8335613113816130e5565b92506020840135613123816130e5565b91506040840135613133816130e5565b809150509250925092565b81516001600160a01b0316815260208083015161012083019161316b908401826001600160a01b03169052565b50604083015161318660408401826001600160a01b03169052565b50606083015160608301526080830151608083015260a083015160a083015260c08301516131bf60c08401826001600160a01b03169052565b5060e083015160e083015261010080840151818401525092915050565b600080602083850312156131ef57600080fd5b823567ffffffffffffffff81111561320657600080fd5b61321285828601612e74565b90969095509350505050565b600060c082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b6000806040838503121561327557600080fd5b823561328081612e5c565b9150602083013561329081612e5c565b809150509250929050565b600080604083850312156132ae57600080fd5b82356132b9816130b9565b946020939093013593505050565b600080604083850312156132da57600080fd5b823591506020830135613290816130b9565b600080604083850312156132ff57600080fd5b505080516020909101519092909150565b60006020828403121561332257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820260008212600160ff1b8414161561335b5761335b613329565b818105831482151761146457611464613329565b634e487b7160e01b600052601260045260246000fd5b6000826133945761339461336f565b600160ff1b8214600019841416156133ae576133ae613329565b500590565b600b81810b9083900b0160016001605f1b0381136b7fffffffffffffffffffffff198212171561146457611464613329565b8181038181111561146457611464613329565b8082018082111561146457611464613329565b60006020828403121561341d57600080fd5b8151610c66816130e5565b634e487b7160e01b600052600160045260246000fd5b60006020828403121561345057600080fd5b8151610c6681612e5c565b808202811582820484141761146457611464613329565b6000600160ff1b820161348757613487613329565b5060000390565b60008261349d5761349d61336f565b500490565b600080600080608085870312156134b857600080fd5b8451935060208501516134ca816130b9565b6040860151606090960151949790965092505050565b600b82810b9082900b036b7fffffffffffffffffffffff19811260016001605f1b038213171561146457611464613329565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190526000906106b590830184612fa5565b6000825161355e818460208701612f81565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b604051610160810167ffffffffffffffff811182821017156135a2576135a2613568565b60405290565b805160ff81168114611ab857600080fd5b8051611ab881612e5c565b80516001600160e01b031981168114611ab857600080fd5b600082601f8301126135ed57600080fd5b815167ffffffffffffffff8082111561360857613608613568565b604051601f8301601f19908116603f0116810190828211818310171561363057613630613568565b8160405283815286602085880101111561364957600080fd5b6124d0846020830160208901612f81565b60006020828403121561366c57600080fd5b815167ffffffffffffffff8082111561368457600080fd5b90830190610160828603121561369957600080fd5b6136a161357e565b6136aa836135a8565b81526136b8602084016135a8565b6020820152604083015160408201526136d3606084016135b9565b60608201526136e4608084016135c4565b608082015260a0830151828111156136fb57600080fd5b613707878286016135dc565b60a08301525060c083015160c082015260e083015160e082015261010091508183015182820152610120915061373e8284016135b9565b8282015261014091506137528284016135b9565b91810191909152949350505050565b60018060a01b038816815286600b0b602082015285600b0b604082015284606082015283600b0b60808201528260a082015260e060c0820152600061068e60e0830184612fa5565b80820182811260008312801582168215821617156137c9576137c9613329565b505092915050565b6000600182016137e3576137e3613329565b5060010190565b6000602082840312156137fc57600080fd5b8151610c66816130b9565b6001600160a01b038681168252858116602083015284166040820152600b83900b606082015260a0608082018190526000906106b590830184612fa5565b6001600160a01b038416815260806020820181905260009061386990830185612fa5565b8281038060408501526002825261060f60f31b6020830152604081016060850152506124d06040820185612fa5565b600080604083850312156138ab57600080fd5b825167ffffffffffffffff808211156138c357600080fd5b6138cf868387016135dc565b935060208501519150808211156138e557600080fd5b506138f2858286016135dc565b9150509250929050565b60008060006060848603121561391157600080fd5b835192506020840151613923816130b9565b80925050604084015190509250925092565b6001600160a01b0386811682528581166020830152841660408201526060810183905260a0608082018190526000906106b590830184612fa5565b6001600160a01b038416815260606020820181905260009061399490830185612fa5565b82810360408401526124d08185612fa5565b6000602082840312156139b857600080fd5b815167ffffffffffffffff8111156139cf57600080fd5b611664848285016135dc56fe65599bf746e17a00ea62e3610586992d88101b78eec3cf380706621fb97ea837a26469706673582212202ef4cc43e625d53f735f5b282a4ab70d5ce51bd6ca646101a24f59fdbc20c60064736f6c63430008170033c36f6c05164a669ecb6da53e218d77ae44d51cfc99f91e5a125a18de0949bee40000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b3052900000000000000000000000046fd5cfb4c12d87acd3a13e92baa53240c661d93000000000000000000000000fa3c3e1882408570b49566e97263c643c6642de300000000000000000000000000000000000000000000000000000000000570300000000000000000000000000000000000000000000000000000000000000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffdabf41c0000000000000000000000000037d607bd9dfff80acf37184c1f27e8838891426200000000000000000000000000000000000000000000000000000000001e84800000000000000000000000000000000000000000000000000000000000007530
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101a95760003560e01c80638413a40e116100f9578063c3f909d411610097578063e4fe205611610071578063e4fe205614610521578063f77c479114610541578063faf3dab314610568578063ffa1ad741461057157600080fd5b8063c3f909d4146104e4578063d86ed3e5146104f9578063dc7316e81461050c57600080fd5b8063b3bce9b1116100d3578063b3bce9b11461045d578063bcb4546f14610483578063c033dd42146104aa578063c0968ca4146104d157600080fd5b80638413a40e14610410578063884d1f40146104235780639b59757f1461043657600080fd5b806351f6511f116101665780635f9e7d77116101405780635f9e7d771461034357806360de29091461035657806368e2fe8e146103d757806372ca8a3e146103ed57600080fd5b806351f6511f146102a457806353c11f99146103025780635ce9d0ed1461031557600080fd5b8063230dbd29146101ae57806330d9c915146101d7578063406ba646146101ea57806348c52a0114610212578063490972c11461025157806349f289dc1461027d575b600080fd5b6101c16101bc366004612eb6565b610599565b6040516101ce9190612fd1565b60405180910390f35b6101c16101e5366004612fe4565b61069b565b6101f26106c0565b6040805194855260208501939093529183015260608201526080016101ce565b6102397f0000000000000000000000006f5c3c93ffba43f6cd871f88a9eff2ba71fd2dbf81565b6040516001600160a01b0390911681526020016101ce565b60025460035460408051600b84810b8252600160601b90940490930b60208401528201526060016101ce565b6102397f0000000000000000000000004c073b3bab6d8826b8c5b229f3cfdc1ec6e47e7481565b604080516001600160a01b037f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b30529811682527f00000000000000000000000046fd5cfb4c12d87acd3a13e92baa53240c661d93166020820152016101ce565b6101c1610310366004612eb6565b6106e6565b610328610323366004613083565b6107c3565b604080519384526020840192909252908201526060016101ce565b6101c1610351366004612fe4565b6108bb565b6103b561036436600461309c565b6040805180820190915260008082526020820152506001600160a01b0316600090815260016020908152604091829020825180840190935254600b81810b8452600160601b909104900b9082015290565b604080518251600b90810b8252602093840151900b92810192909252016101ce565b6103df6109a0565b6040519081526020016101ce565b6104006103fb36600461309c565b610a30565b60405190151581526020016101ce565b6103df61041e3660046130c8565b610a62565b6101c1610431366004612fe4565b610b3c565b6103df7f000000000000000000000000000000000000000000000000000000000000753081565b7f000000000000000000000000271daa9826b306a9f45dea7312f567f12c4e5314610239565b6103df7fa9214cc96615e0085d3bb077758db69497dc2dce3b2b1e97bc93c3d18d83efd381565b6103df7f00000000000000000000000000000000000000000000000000000000001e848081565b6103df6104df3660046130f3565b610c39565b6104ec610c6d565b6040516101ce919061313e565b6101c1610507366004612eb6565b610e69565b61051f61051a3660046130f3565b610f52565b005b61053461052f3660046131dc565b610fe1565b6040516101ce919061321e565b6102397f00000000000000000000000037d607bd9dfff80acf37184c1f27e8838891426281565b6103df60045481565b6101c160405180604001604052806009815260200168312e302e302d72633360b81b81525081565b6060336001600160a01b037f0000000000000000000000004c073b3bab6d8826b8c5b229f3cfdc1ec6e47e7416146105e457604051632f2d36a760e01b815260040160405180910390fd5b6105ed896111ee565b6106305782828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092935061068e92505050565b6106398a610a30565b61065657604051631ea25bab60e31b815260040160405180910390fd5b600061066487890189613262565b5090506000806106768789018961329b565b915091506106888d8484848a8a6112b4565b93505050505b9998505050505050505050565b604080518082019091526002815261060f60f31b60208201525b979650505050505050565b6000806000806106ce6112f9565b93506106d9846107c3565b9596919590945092509050565b6060336001600160a01b037f0000000000000000000000004c073b3bab6d8826b8c5b229f3cfdc1ec6e47e74161415806107265750610724896111ee565b155b8061073757506107358a610a30565b155b1561077b5782828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092935061068e92505050565b60008061078a888a018a613262565b909250905060008061079e888a018a6132c7565b915091506107b18e858584868c8c6113e4565b9e9d5050505050505050505050505050565b60405163010b31c760e11b815242600482015260248101829052600090819081906001600160a01b037f000000000000000000000000fa3c3e1882408570b49566e97263c643c6642de31690630216638e906044016040805180830381865afa158015610834573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085891906132ec565b925090506108867f000000000000000000000000000000000000000000000000000000000000000182611435565b90506108b37f0000000000000000000000000000000000000000000000000000000000057030828461146a565b949193509150565b6060336001600160a01b037f0000000000000000000000004c073b3bab6d8826b8c5b229f3cfdc1ec6e47e74161415806108fb57506108f9876111ee565b155b8061090c575061090a88610a30565b155b156109305750604080518082019091526002815261060f60f31b60208201526106b5565b60008061093f86880188613262565b909250905060008061095b6001600160a01b038d1685856114b3565b5050915091508181604051602001610980929190918252600b0b602082015260400190565b604051602081830303815290604052945050505050979650505050505050565b604051630907402360e01b81524260048201526000907f000000000000000000000000fa3c3e1882408570b49566e97263c643c6642de36001600160a01b031690630907402390602401602060405180830381865afa158015610a07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2b9190613310565b905090565b7f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b305296001600160a01b0390811691161490565b600080610a70600084611555565b9150506000610aba620f42407f000000000000000000000000000000000000000000000000000000000000753086600b0b610aab919061333f565b610ab59190613385565b61158b565b600254610aca9190600b0b6133b3565b90506000610b016001600160a01b037f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b3052916836115df565b90506003548111610b13576000610b20565b600354610b2090826133e5565b610b298461166c565b610b3391906133f8565b95945050505050565b6060336001600160a01b037f0000000000000000000000004c073b3bab6d8826b8c5b229f3cfdc1ec6e47e741614610b8757604051632f2d36a760e01b815260040160405180910390fd5b610b90876111ee565b610bb35750604080518082019091526002815261060f60f31b60208201526106b5565b610bbc88610a30565b610bd957604051631ea25bab60e31b815260040160405180910390fd5b6000610be785870187613262565b509050600080610c016001600160a01b038c1684306114b3565b505060408051600b9290920b60208301528181019290925281518082038301815260609091019091529b9a5050505050505050505050565b64010000000183610c4c57640200000000175b82610c5957640c00000000175b81610c6657643000000000175b9392505050565b610ce060405180610120016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001600081525090565b6040518061012001604052807f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b305296001600160a01b031681526020017f00000000000000000000000046fd5cfb4c12d87acd3a13e92baa53240c661d936001600160a01b031681526020017f000000000000000000000000fa3c3e1882408570b49566e97263c643c6642de36001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000005703081526020017f000000000000000000000000000000000000000000000000000000000000000181526020017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdabf41c0081526020017f00000000000000000000000037d607bd9dfff80acf37184c1f27e883889142626001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000001e848081526020017f0000000000000000000000000000000000000000000000000000000000007530815250905090565b6060336001600160a01b037f0000000000000000000000004c073b3bab6d8826b8c5b229f3cfdc1ec6e47e741614610eb457604051632f2d36a760e01b815260040160405180910390fd5b610ebd896111ee565b610f005782828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092935061068e92505050565b610f098a610a30565b610f2657604051631ea25bab60e31b815260040160405180910390fd5b6000610f3487890189613262565b509050610f438b8286866116be565b9b9a5050505050505050505050565b7f0000000000000000000000004c073b3bab6d8826b8c5b229f3cfdc1ec6e47e746001600160a01b031663ad3915c8610f8c858585610c39565b6040518263ffffffff1660e01b8152600401610faa91815260200190565b600060405180830381600087803b158015610fc457600080fd5b505af1158015610fd8573d6000803e3d6000fd5b50505050505050565b61101a6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b61105983838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061170492505050565b6040516318cb56bf60e01b81529091506001600160a01b037f00000000000000000000000037d607bd9dfff80acf37184c1f27e8838891426216906318cb56bf906110a890849060040161321e565b6020604051808303816000875af11580156110c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110eb919061340b565b6110f7576110f7613428565b60006001905060007f00000000000000000000000037d607bd9dfff80acf37184c1f27e883889142626001600160a01b03166318cb56bf8460405160240161113f919061321e565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505090506111788282611abd565b505082516020808501516040808701516060808901516080808b015160a0808d015187519a8b52988a019790975294880193909352908601528401528201523392507fc8333a73e4a1a16672a2dcb538b636e96b98466bfa9b61307c9860c9a94c608a915060c00160405180910390a292915050565b604051635b69006f60e11b81527fa9214cc96615e0085d3bb077758db69497dc2dce3b2b1e97bc93c3d18d83efd360048201526000907f0000000000000000000000004c073b3bab6d8826b8c5b229f3cfdc1ec6e47e746001600160a01b03169063b6d200de90602401602060405180830381865afa158015611275573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611299919061343e565b6001600160a01b0316826001600160a01b0316149050919050565b60606106b58787878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611be692505050565b6002546000908190611338906001600160a01b037f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b305291690600b0b6115df565b6040516370a0823160e01b81523060048201529091507f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b305296001600160a01b0316906370a0823190602401602060405180830381865afa15801561139f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c39190613310565b91508082106113dc576113d681836133e5565b91505090565b600091505090565b60606114298888878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611be692505050565b98975050505050505050565b60008281811261145157611449818461345b565b915050611464565b61145a81613472565b611449908461348e565b92915050565b60008383820361147e576000915050610c66565b80156114aa5761148e83826133f8565b611498828661345b565b6114a2919061348e565b915050610c66565b83915050610c66565b60008060008060006114c48861220b565b604051631cd43d1160e31b81526001600160a01b038b811660048301528a811660248301528981166044830152919350908316915063e6a1e88890606401608060405180830381865afa15801561151f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154391906134a2565b929b919a509850909650945050505050565b6000806115606109a0565b915061156c84846134e0565b600b0b6115788361237b565b611582919061333f565b90509250929050565b600060016001605f1b038213156115db5760405162461bcd60e51b815260206004820152600f60248201526e746f496e74393628696e743235362960881b60448201526064015b60405180910390fd5b5090565b6000806115eb8461220b565b6040516346ccbfb760e11b81526001600160a01b038781166004830152600b87900b60248301529193509083169150638d997f6e90604401602060405180830381865afa158015611640573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116649190613310565b949350505050565b6000808212156115db5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f73697469766560448201526064016115d2565b6060610b33858560008087878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611be692505050565b61173d6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6117456123e5565b61174d6106c0565b60208501528352606083015260408083018290525163a9059cbb60e01b815233600482015260248101919091527f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b305296001600160a01b03169063a9059cbb906044016020604051808303816000875af11580156117cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f1919061340b565b50604080820151606083015191516369c9922960e11b8152339263d393245292611864927f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b30529927f00000000000000000000000046fd5cfb4c12d87acd3a13e92baa53240c661d9392918990600401613512565b6020604051808303816000875af1158015611883573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118a7919061340b565b6118b3576118b3613428565b6040516370a0823160e01b81523060048201527f00000000000000000000000046fd5cfb4c12d87acd3a13e92baa53240c661d936001600160a01b0316906370a0823190602401602060405180830381865afa158015611917573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193b9190613310565b6080820181905260608201511115611966576040516318b396c960e21b815260040160405180910390fd5b604051639af0a51d60e01b81524260048201527f000000000000000000000000fa3c3e1882408570b49566e97263c643c6642de36001600160a01b031690639af0a51d906024016020604051808303816000875af11580156119cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f0919061340b565b506080810151611a4e906001600160a01b037f00000000000000000000000046fd5cfb4c12d87acd3a13e92baa53240c661d93169030907f000000000000000000000000271daa9826b306a9f45dea7312f567f12c4e53149061243e565b60a08201819052611aad906001600160a01b037f00000000000000000000000046fd5cfb4c12d87acd3a13e92baa53240c661d93169030907f000000000000000000000000271daa9826b306a9f45dea7312f567f12c4e5314906124da565b50611ab86001600055565b919050565b600060608315611b40576000611b147f00000000000000000000000037d607bd9dfff80acf37184c1f27e88388914262857f00000000000000000000000000000000000000000000000000000000001e84806124fb565b919450909250905082611b3a578015611b3157611b2cfe5b611b3a565b611b3a8261258c565b50611bdf565b7f00000000000000000000000037d607bd9dfff80acf37184c1f27e883889142626001600160a01b031683604051611b78919061354c565b6000604051808303816000865af19150503d8060008114611bb5576040519150601f19603f3d011682016040523d82523d6000602084013e611bba565b606091505b50909250905081611bdf578060405162461bcd60e51b81526004016115d29190612fd1565b9250929050565b604051631fb6491d60e11b815281906000906001600160a01b037f0000000000000000000000004c073b3bab6d8826b8c5b229f3cfdc1ec6e47e741690633f6c923a90611c37908590600401612fd1565b600060405180830381865afa158015611c54573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c7c919081019061365a565b6001600160a01b0380881660009081526001602052604081209293509081908190611caa908c168b306125d9565b9250600083600b0b600014905060007f00000000000000000000000037d607bd9dfff80acf37184c1f27e883889142626001600160a01b031663064cb4958d8d89600001600c9054906101000a9004600b0b8e8a8d604001518e60a00151604051602401611d1e9796959493929190613761565b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050509050600080611d5a8484611abd565b915091508115611d7157611d6e8482612671565b94505b50505050620f42407f000000000000000000000000000000000000000000000000000000000000753084600b0b611da8919061333f565b611db29190613385565b81600b0b1315611dc0575060005b611dca81846134e0565b8454600254919350600160601b9004600b90810b91611dec918491900b6133b3565b611df691906134e0565b600280546bffffffffffffffffffffffff19166001600160601b039290921691909117905583546000908190611e31908d90600b0b86612754565b92509050600b8b810b9086900b1315611f0a578554600160601b9004600b90810b9084900b1315611e9c578554600090611e7590600160601b9004600b0b856134e0565b9050611e808261237b565b81600b0b611e8e919061333f565b611e9890846137a9565b9250505b600254600090611ed9906001600160a01b037f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b305291690600b0b6115df565b9050600354811115611f0857611efb60035482611ef691906133e5565b61237b565b611f0590846137a9565b92505b505b5084546001600160601b03838116600160601b026001600160c01b0319909216908516171785556000811315611fee577f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b305296001600160a01b03166323b872dd8c30611f748561166c565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015611fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fec919061340b565b505b60025461204d906001600160a01b037f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b30529169030907f0000000000000000000000006f5c3c93ffba43f6cd871f88a9eff2ba71fd2dbf90600b0b8b612851565b96506120a36001600160a01b037f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b3052916307f0000000000000000000000006f5c3c93ffba43f6cd871f88a9eff2ba71fd2dbf61297e565b600355600280546001600160601b03909216600160601b026bffffffffffffffffffffffff60601b19909216919091179055506000811215612191576001600160a01b037f0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b305291663a9059cbb8c61212061211b85613472565b61166c565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801561216b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218f919061340b565b505b60025460408051600b87810b825286810b602083015291810184905282820b6060820152600160601b909204900b60808201526001600160a01b038c16907fd34b18010403577a1e7acf8488ab14532641b98ae2329f3893066a56a44d8e919060a00160405180910390a250505050505095945050505050565b6000805160206139dc833981519152547fb969d79d88acd02d04ed7ee7d43b949e7daf093d363abcfbbc43dfdfd1ce969a546001600160a01b03811661234a576001600160a01b0382166122be57826001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa158015612297573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122bb919061343e565b91505b604051635b69006f60e11b81527fa9214cc96615e0085d3bb077758db69497dc2dce3b2b1e97bc93c3d18d83efd360048201526001600160a01b0383169063b6d200de906024015b602060405180830381865afa158015612323573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612347919061343e565b90505b6001600160a01b03821661236057612360613428565b6001600160a01b03811661237657612376613428565b915091565b60006001600160ff1b038211156115db5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b60648201526084016115d2565b6002600054036124375760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016115d2565b6002600055565b60008061244a86612a1c565b60405163eccfc6a560e01b81526001600160a01b0389811660048301528881166024830152878116604483015260648201879052919350908316915063eccfc6a590608401602060405180830381865afa1580156124ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124d09190613310565b9695505050505050565b60408051600080825260208201909252610b33908690869086908690612b1b565b600080606060005a9050866001600160a01b0316858760405161251e919061354c565b60006040518083038160008787f1925050503d806000811461255c576040519150601f19603f3d011682016040523d82523d6000602084013e612561565b606091505b509094509150836125825761257760408261348e565b5a1161258257600192505b5093509350939050565b7fe8c3b3ea3c282ddb0957d4765095bff9515fdb2c678014c641321a7f8a6a3307816040516125bb9190612fd1565b60405180910390a16004600081546125d2906137d1565b9091555050565b6000806125e58561220b565b604051631cd43d1160e31b81526001600160a01b03888116600483015287811660248301528681166044830152919350908316915063e6a1e88890606401608060405180830381865afa158015612640573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266491906134a2565b5090979650505050505050565b600082156127395781516020146126c5576126c06040518060400160405280601881526020017f736166654465636f6465466565466c6f77526174653a2031000000000000000081525061258c565b611464565b6000828060200190518101906126db9190613310565b905060016001605f1b0381111561272f5761272a6040518060400160405280601881526020017f736166654465636f6465466565466c6f77526174653a2032000000000000000081525061258c565b612733565b8091505b50611464565b8180602001905181019061274d91906137ea565b9050611464565b6000806127618484611555565b9092509050600061279e6127997ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdabf41c00600b87900b612c4a565b612c71565b604051631b16777760e01b81526001600160a01b0388811660048301526fffffffffffffffffffffffffffffffff831660248301529192507f000000000000000000000000271daa9826b306a9f45dea7312f567f12c4e531490911690631b167777906044016020604051808303816000875af1158015612823573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612847919061340b565b5050935093915050565b606060008061285f88612cd5565b91509150816001600160a01b0316634329d29382836001600160a01b0316635a6c6dbc8c8c8c8c600067ffffffffffffffff8111156128a0576128a0613568565b6040519080825280601f01601f1916602001820160405280156128ca576020820181803683370190505b506040516024016128df959493929190613807565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261292a939250908990600401613845565b6000604051808303816000875af1158015612949573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129719190810190613898565b5098975050505050505050565b60008060008061298d87612a1c565b604051631cd43d1160e31b81526001600160a01b038a8116600483015289811660248301528881166044830152919350908316915063e6a1e88890606401606060405180830381865afa1580156129e8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0c91906138fc565b9350935093505093509350939050565b6000805160206139dc833981519152547fc36f6c05164a669ecb6da53e218d77ae44d51cfc99f91e5a125a18de0949bee4546001600160a01b03811661234a576001600160a01b038216612acf57826001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa158015612aa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612acc919061343e565b91505b604051635b69006f60e11b81527fdfd8ece9bfbcb8c5c540edb935641f63d67686490a1ab97f000288759f30a94660048201526001600160a01b0383169063b6d200de90602401612306565b6000806000612b2988612cd5565b91509150816001600160a01b03166339255d5b82836001600160a01b0316636d1007a68c8c8c8c600067ffffffffffffffff811115612b6a57612b6a613568565b6040519080825280601f01601f191660200182016040528015612b94576020820181803683370190505b50604051602401612ba9959493929190613935565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252612bf4939250908990600401613970565b6000604051808303816000875af1158015612c13573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612c3b91908101906139a6565b50600198975050505050505050565b600082818112612c5e57611449818461333f565b612c6781613472565b6114499084613385565b80600f81900b8114611ab85760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b60648201526084016115d2565b6000805160206139dc833981519152547fc36f6c05164a669ecb6da53e218d77ae44d51cfc99f91e5a125a18de0949bee4546001600160a01b03811661234a576001600160a01b038216612d8857826001600160a01b03166320bc44256040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d85919061343e565b91505b604051635b69006f60e11b81527fdfd8ece9bfbcb8c5c540edb935641f63d67686490a1ab97f000288759f30a94660048201526001600160a01b0383169063b6d200de90602401602060405180830381865afa158015612dec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e10919061343e565b9050816000805160206139dc83398151915255807fc36f6c05164a669ecb6da53e218d77ae44d51cfc99f91e5a125a18de0949bee4556001600160a01b03821661236057612360613428565b6001600160a01b0381168114612e7157600080fd5b50565b60008083601f840112612e8657600080fd5b50813567ffffffffffffffff811115612e9e57600080fd5b602083019150836020828501011115611bdf57600080fd5b600080600080600080600080600060c08a8c031215612ed457600080fd5b8935612edf81612e5c565b985060208a0135612eef81612e5c565b975060408a0135965060608a013567ffffffffffffffff80821115612f1357600080fd5b612f1f8d838e01612e74565b909850965060808c0135915080821115612f3857600080fd5b612f448d838e01612e74565b909650945060a08c0135915080821115612f5d57600080fd5b50612f6a8c828d01612e74565b915080935050809150509295985092959850929598565b60005b83811015612f9c578181015183820152602001612f84565b50506000910152565b60008151808452612fbd816020860160208601612f81565b601f01601f19169290920160200192915050565b602081526000610c666020830184612fa5565b600080600080600080600060a0888a031215612fff57600080fd5b873561300a81612e5c565b9650602088013561301a81612e5c565b955060408801359450606088013567ffffffffffffffff8082111561303e57600080fd5b61304a8b838c01612e74565b909650945060808a013591508082111561306357600080fd5b506130708a828b01612e74565b989b979a50959850939692959293505050565b60006020828403121561309557600080fd5b5035919050565b6000602082840312156130ae57600080fd5b8135610c6681612e5c565b80600b0b8114612e7157600080fd5b6000602082840312156130da57600080fd5b8135610c66816130b9565b8015158114612e7157600080fd5b60008060006060848603121561310857600080fd5b8335613113816130e5565b92506020840135613123816130e5565b91506040840135613133816130e5565b809150509250925092565b81516001600160a01b0316815260208083015161012083019161316b908401826001600160a01b03169052565b50604083015161318660408401826001600160a01b03169052565b50606083015160608301526080830151608083015260a083015160a083015260c08301516131bf60c08401826001600160a01b03169052565b5060e083015160e083015261010080840151818401525092915050565b600080602083850312156131ef57600080fd5b823567ffffffffffffffff81111561320657600080fd5b61321285828601612e74565b90969095509350505050565b600060c082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b6000806040838503121561327557600080fd5b823561328081612e5c565b9150602083013561329081612e5c565b809150509250929050565b600080604083850312156132ae57600080fd5b82356132b9816130b9565b946020939093013593505050565b600080604083850312156132da57600080fd5b823591506020830135613290816130b9565b600080604083850312156132ff57600080fd5b505080516020909101519092909150565b60006020828403121561332257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820260008212600160ff1b8414161561335b5761335b613329565b818105831482151761146457611464613329565b634e487b7160e01b600052601260045260246000fd5b6000826133945761339461336f565b600160ff1b8214600019841416156133ae576133ae613329565b500590565b600b81810b9083900b0160016001605f1b0381136b7fffffffffffffffffffffff198212171561146457611464613329565b8181038181111561146457611464613329565b8082018082111561146457611464613329565b60006020828403121561341d57600080fd5b8151610c66816130e5565b634e487b7160e01b600052600160045260246000fd5b60006020828403121561345057600080fd5b8151610c6681612e5c565b808202811582820484141761146457611464613329565b6000600160ff1b820161348757613487613329565b5060000390565b60008261349d5761349d61336f565b500490565b600080600080608085870312156134b857600080fd5b8451935060208501516134ca816130b9565b6040860151606090960151949790965092505050565b600b82810b9082900b036b7fffffffffffffffffffffff19811260016001605f1b038213171561146457611464613329565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190526000906106b590830184612fa5565b6000825161355e818460208701612f81565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b604051610160810167ffffffffffffffff811182821017156135a2576135a2613568565b60405290565b805160ff81168114611ab857600080fd5b8051611ab881612e5c565b80516001600160e01b031981168114611ab857600080fd5b600082601f8301126135ed57600080fd5b815167ffffffffffffffff8082111561360857613608613568565b604051601f8301601f19908116603f0116810190828211818310171561363057613630613568565b8160405283815286602085880101111561364957600080fd5b6124d0846020830160208901612f81565b60006020828403121561366c57600080fd5b815167ffffffffffffffff8082111561368457600080fd5b90830190610160828603121561369957600080fd5b6136a161357e565b6136aa836135a8565b81526136b8602084016135a8565b6020820152604083015160408201526136d3606084016135b9565b60608201526136e4608084016135c4565b608082015260a0830151828111156136fb57600080fd5b613707878286016135dc565b60a08301525060c083015160c082015260e083015160e082015261010091508183015182820152610120915061373e8284016135b9565b8282015261014091506137528284016135b9565b91810191909152949350505050565b60018060a01b038816815286600b0b602082015285600b0b604082015284606082015283600b0b60808201528260a082015260e060c0820152600061068e60e0830184612fa5565b80820182811260008312801582168215821617156137c9576137c9613329565b505092915050565b6000600182016137e3576137e3613329565b5060010190565b6000602082840312156137fc57600080fd5b8151610c66816130b9565b6001600160a01b038681168252858116602083015284166040820152600b83900b606082015260a0608082018190526000906106b590830184612fa5565b6001600160a01b038416815260806020820181905260009061386990830185612fa5565b8281038060408501526002825261060f60f31b6020830152604081016060850152506124d06040820185612fa5565b600080604083850312156138ab57600080fd5b825167ffffffffffffffff808211156138c357600080fd5b6138cf868387016135dc565b935060208501519150808211156138e557600080fd5b506138f2858286016135dc565b9150509250929050565b60008060006060848603121561391157600080fd5b835192506020840151613923816130b9565b80925050604084015190509250925092565b6001600160a01b0386811682528581166020830152841660408201526060810183905260a0608082018190526000906106b590830184612fa5565b6001600160a01b038416815260606020820181905260009061399490830185612fa5565b82810360408401526124d08185612fa5565b6000602082840312156139b857600080fd5b815167ffffffffffffffff8111156139cf57600080fd5b611664848285016135dc56fe65599bf746e17a00ea62e3610586992d88101b78eec3cf380706621fb97ea837a26469706673582212202ef4cc43e625d53f735f5b282a4ab70d5ce51bd6ca646101a24f59fdbc20c60064736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b3052900000000000000000000000046fd5cfb4c12d87acd3a13e92baa53240c661d93000000000000000000000000fa3c3e1882408570b49566e97263c643c6642de300000000000000000000000000000000000000000000000000000000000570300000000000000000000000000000000000000000000000000000000000000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffdabf41c0000000000000000000000000037d607bd9dfff80acf37184c1f27e8838891426200000000000000000000000000000000000000000000000000000000001e84800000000000000000000000000000000000000000000000000000000000007530
-----Decoded View---------------
Arg [0] : config (tuple):
Arg [1] : inToken (address): 0x1efF3Dd78F4A14aBfa9Fa66579bD3Ce9E1B30529
Arg [2] : outToken (address): 0x46fd5cfB4c12D87acD3a13e92BAa53240C661D93
Arg [3] : observer (address): 0xfA3c3e1882408570b49566E97263c643C6642dE3
Arg [4] : discountFactor (uint256): 356400
Arg [5] : twapScaler (int256): 1
Arg [6] : outTokenDistributionPoolScaler (int256): -10000000000
Arg [7] : controller (address): 0x37D607BD9dfFf80acf37184c1F27E88388914262
Arg [8] : controllerSafeCallbackGasLimit (uint256): 2000000
Arg [9] : maxAllowedFeePM (uint256): 30000
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 0000000000000000000000001eff3dd78f4a14abfa9fa66579bd3ce9e1b30529
Arg [1] : 00000000000000000000000046fd5cfb4c12d87acd3a13e92baa53240c661d93
Arg [2] : 000000000000000000000000fa3c3e1882408570b49566e97263c643c6642de3
Arg [3] : 0000000000000000000000000000000000000000000000000000000000057030
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [5] : fffffffffffffffffffffffffffffffffffffffffffffffffffffffdabf41c00
Arg [6] : 00000000000000000000000037d607bd9dfff80acf37184c1f27e88388914262
Arg [7] : 00000000000000000000000000000000000000000000000000000000001e8480
Arg [8] : 0000000000000000000000000000000000000000000000000000000000007530
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
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.