-
Notifications
You must be signed in to change notification settings - Fork 241
General Distribution Agreement
GDA (General Distribution Agreement) generalizes the Instant Distribution Agreement by offering many-to-many constant flow distributions in addition to one-to-many instant distributions.
GDA is implemented using the Superfluid agreement framework, however it currently does not provide callbacks unlike the IDA.
The code structure of the GDA deviates from the two existing agreements in that it leverages the TokenMonad
abstract contract which leverages the Semantic Money Library.
The core logic functions utilize the SemanticMoney
library and the virtual functions of TokenMonad
to enact the side effects on the state of the inheriting contract.
GeneralDistributionAgreementV1.sol
: The GDA contract inherits from ISuperAgreement
(similar to the CFA and the IDA) and TokenMonad
.
This contract can be thought of as the interface between the TokenMonad
/SemanticMoney
library and the existing Superfluid protocol and therefore the end-user. It is the contract that is responsible for sanitizing input data as TokenMonad
/SemanticMoney
offloads this to the inheriting contract.
It includes the following:
- implementation of the virtual functions in
TokenMonad.sol
- the
SuperfluidPool
creation function -
callAgreement
wrapper functions for the core logic functions inTokenMonad.sol
and someSuperfluidPool.sol
functions - encoding/decoding of arbitrary data to/from
SuperfluidToken
storage similar to the CFA and IDA
SuperfluidPool.sol
: The helper contract for GeneralDistributionAgreementV1 representing pools.
There are three primary actors within a pool:
- Pool operator
- The GDA is the sole "pool operator" (controlled by modifier
onlyGDA
). - The "pool operator" has the ability to modify the pool's
_index
and_disconnectedMembers
fields.
- The GDA is the sole "pool operator" (controlled by modifier
- Pool Admin
- The pool admin is set during pool creation as one of the parameters in the
createPool(ISuperfluidToken token, address admin, PoolConfig memory config)
function - The pool admin holds several privileges:
- the only account that can mint/burn pool units
- the recipient of the adjustment flow
- in the case where
config.distributionFromAnyAddress
isfalse
: the admin is the only account that can execute distributions
- The pool admin is set during pool creation as one of the parameters in the
- Pool Member
- A pool member is any account which holds units for a particular pool
- Pool members will receive a proportion of distributions based on their ownership of the pool (their share of the pool units) The SuperfluidPool contract is also upgradeable and utilizes the beacon proxy pattern.
Semantic money library uses [limited functional programming in solidity](Presentation functional solidity v2) to provide the core building blocks for the GDA and the future version of Superfluid.
SemanticMoney.sol
: This is a library that contains the core building blocks of the Superfluid payment primitives. That is, the data structures and the pure functions that operate on them.
TokenMonad.sol
: TokenMonad is an abstract contract that contains:
- a set of virtual getter/setter functions to be implemented by the inheriting contract:
-
_getUIndex
/_setUIndex
-
_getPDPIndex
/_setPDPIndex
_getFlowRate
_setFlowInfo
-
_getPoolAdjustmentFlowRate
/_setPoolAdjustmentFlowRate
-
- the core logic for the different types of agreement operations:
-
_doShift
(instant transfer) -
_doFlow
(1-to-1 flow) -
_doDistributeViaPool
(1-to-n instant transfer) -
_doDistributeFlowViaPool
(1-to-n flow)
-
The Superfluid Pool is a contract that is created via the GDA contract and enables the distribution of supertokens to N pool members, proportional to the pool units assigned to them. The admin of the pool can update the units of the pool members at any time, and distribute via the pool.
A happy path would look like:
- Alice creates a new pool via the GDA and sets herself as the admin
- Alice updates pool units for Bob (100 for Bob) and Carol (200 for Carol)
- Bob decides to connect to this pool (in the IDA, the corresponding concept would be approve subscription)
- Dan instantly distributes 300 POOLx tokens to the pool
- Bob now has 100 POOLx tokens
- Carol has 200 claimable POOLx tokens, she claims and now has 200 POOLx tokens
NOTE: This example showed an instant distribution. A flow distribution would look the same, the only difference being that instead of defining an amount to be distributed (here: 300 POOLx), Dan would define a flowrate to be distributed (e.g. 300 POOLx/day). The recipients (here: Bob and Carol) would then receive proportions of that flow, with the flow rate being proportional to the units assigned to them, 100 POOLx/day for Bob and 200 POOLx/day for Carol.
- In the IDA, every index is embedded in the storage of the SuperfluidToken, and it's created for via
createIndex
. - In the GDA, every index is contained in a dedicated
SuperfluidPool
contract which is created by invokingcreatePool
. - In the IDA, the index creator aka published is the only one who can distribute tokens via that index.
- In the GDA, anybody can distribute tokens via a pool (if allowed by the pool admin).
- Since the index data structure in SuperfluidPool is a mapping from addresses to uints, it's suited to implement the ERC20 interface.
The
SuperfluidPool
contains functions for the pool admin to update member units (essentially mint and burn in one, if viewed through the lens of a token interface) and for disconnected pool members to claim any tokens which have been distributed and are unclaimed.
The SuperfluidPool contract is an ERC20 contract itself where the pool units of a pool member is equivalent to their balance. The ERC20 in the SuperfluidPool does not have a lot of programmability. However, as mentioned in point 5 of the previous section, you can write an ERC20 contract on top of the SuperfluidPool to enable more functionality.
- A
SuperfluidPool
can be configured to only allow the pool admin of the pool to distribute (1-to-N), see thePoolConfig
struct inIGeneralDistributionAgreementV1.sol
. - If permission to distribute isn't restricted to the pool admin only, the GDA essentially allows many-to-many instant and flowing distributions.
Similar to how indexes work in the IDA, the SuperfluidPool
in the GDA is token-specific. That is, a SuperfluidPool
can only distribute tokens specified at creation time: createPool(ISuperfluidToken token, address admin, PoolConfig memory config)
.
Cascading Superfluid pools means one pool to distribute to another pool. However, this adds additional complexity to the system. The current implementation does not support this. However, there is an edge case that is possible with the current implementation:
- Generally, there exists a nanny-rule that one cannot update units of pool A for another existing pool. However, one can still create some units of pool A for the address of pool B before the pool B is created (counterfactual addresses).
The calculation of patrician period of 3P is related to the deposit amount of the critical account (explained in 3P).
With that deposit now potentially being split between two agreements (CFA and GDA), the calculation made in the liquidation case in order to assign rewards, gives a result specific for that agreement instead of combining them together.
This may impact the predictability of patrician period, but should not pose an issue to the solvency mechanism as a whole.
The GDA handles an edge case when there is a remainder in the amount of tokens to be streamed to the pool because solidity does not allow for floating point arithmetic. This remainder in the flow rate is the adjustment flow. This is handled with something called the adjustment flow rate which is always streamed to the pool admin, and is best explained via an example:
- Alice creates a pool and assigns 3 units each to Bob, Carol and Dave. Alice's pool has 9 total units.
- She then does a flow distribution of 100 DAIx/second. The issue here is that 100 / 9 (11.11...) is not fully divisible.
- Therefore, an adjustment flow is required. The adjustment flow rate handles the cases where the desired flow rate is not divisible by the total number of units.
- In the case of Alice's pool, the flow rate sent to the pool members is 99/s (closest divisible value without remainder, rounding down) and 1/s is the adjustment flow rate.
The current implementation opts out of callback support for now.
- In-depth overview in Superfluid developer docs.
- Presentation: Make Frictionless Money, see Streaming 1toN
- Community GDA Presentation
- Superfluid GDA Internal Review (YouTube videos):
- Governance Overview
- For Contributors
- Development Process
- Protocol EVMv1 Operations
- Protocol EVMv1 Technical Notes
- Protocol EVMv1 Core Subgraph