diff --git a/packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol b/packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol index 1f7f32f5ee..8e1eb1f1f5 100644 --- a/packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol +++ b/packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol @@ -32,6 +32,7 @@ import { SafeGasLibrary } from "../../libs/SafeGasLibrary.sol"; import { AgreementBase } from "../AgreementBase.sol"; import { AgreementLibrary } from "../AgreementLibrary.sol"; + /** * @title General Distribution Agreement * @author Superfluid @@ -80,6 +81,25 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi using SafeCast for int256; using SemanticMoney for BasicParticle; + struct UniversalIndexData { + int96 flowRate; + uint32 settledAt; + uint256 totalBuffer; + bool isPool; + int256 settledValue; + } + + struct PoolMemberData { + address pool; + uint32 poolID; // the slot id in the pool's subs bitmap + } + + struct FlowDistributionData { + uint32 lastUpdated; + int96 flowRate; + uint256 buffer; // stored as uint96 + } + address public constant SLOTS_BITMAP_LIBRARY_ADDRESS = address(SlotsBitmapLibrary); address public constant SUPERFLUID_POOL_DEPLOYER_ADDRESS = address(SuperfluidPoolDeployerLibrary); @@ -170,6 +190,18 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi return data.flowRate; } + function getFlow(ISuperfluidToken token, address from, ISuperfluidPool to) + external + view + override + returns (uint256 lastUpdated, int96 flowRate, uint256 deposit) + { + (, FlowDistributionData memory data) = _getFlowDistributionData(token, _getFlowDistributionHash(from, to)); + lastUpdated = data.lastUpdated; + flowRate = data.flowRate; + deposit = data.buffer; + } + /// @inheritdoc IGeneralDistributionAgreementV1 function estimateFlowDistributionActualFlowRate( ISuperfluidToken token, @@ -428,6 +460,15 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi FlowRate oldFlowRate; } + struct _StackVars_Liquidation { + ISuperfluidToken token; + int256 availableBalance; + address sender; + bytes32 distributionFlowHash; + int256 signedTotalGDADeposit; + address liquidator; + } + /// @inheritdoc IGeneralDistributionAgreementV1 function distributeFlow( ISuperfluidToken token, @@ -482,7 +523,7 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi // liquidation case, requestedFlowRate == 0 (int256 availableBalance,,) = token.realtimeBalanceOf(from, flowVars.currentContext.timestamp); // StackVarsLiquidation used to handle good ol' stack too deep - StackVarsLiquidation memory liquidationData; + _StackVars_Liquidation memory liquidationData; { liquidationData.token = token; liquidationData.sender = from; @@ -612,7 +653,7 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi } } - function _makeLiquidationPayouts(StackVarsLiquidation memory data) internal { + function _makeLiquidationPayouts(_StackVars_Liquidation memory data) internal { (, FlowDistributionData memory flowDistributionData) = _getFlowDistributionData(ISuperfluidToken(data.token), data.distributionFlowHash); int256 signedSingleDeposit = flowDistributionData.buffer.toInt256(); diff --git a/packages/ethereum-contracts/contracts/agreements/gdav1/SuperfluidPool.sol b/packages/ethereum-contracts/contracts/agreements/gdav1/SuperfluidPool.sol index 2be38c3b6e..3a82f9e85b 100644 --- a/packages/ethereum-contracts/contracts/agreements/gdav1/SuperfluidPool.sol +++ b/packages/ethereum-contracts/contracts/agreements/gdav1/SuperfluidPool.sol @@ -37,6 +37,23 @@ contract SuperfluidPool is ISuperfluidPool, BeaconProxiable { using SafeCast for uint256; using SafeCast for int256; + // Structs + struct PoolIndexData { + uint128 totalUnits; + uint32 wrappedSettledAt; + int96 wrappedFlowRate; + int256 wrappedSettledValue; + } + + struct MemberData { + uint128 ownedUnits; + uint32 syncedSettledAt; + int96 syncedFlowRate; + int256 syncedSettledValue; + int256 settledValue; + int256 claimedValue; + } + GeneralDistributionAgreementV1 public immutable GDA; ISuperfluidToken public superToken; diff --git a/packages/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol b/packages/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol index ee6f1ee95b..5f41243117 100644 --- a/packages/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol +++ b/packages/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol @@ -833,6 +833,10 @@ library SuperTokenV1Library { (lastUpdated, flowRate, deposit, owedDeposit) = cfa.getFlow(token, sender, receiver); } + /* 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 diff --git a/packages/ethereum-contracts/contracts/interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol b/packages/ethereum-contracts/contracts/interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol index 5b4e1fdb3b..8fde0bb732 100644 --- a/packages/ethereum-contracts/contracts/interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol +++ b/packages/ethereum-contracts/contracts/interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol @@ -19,35 +19,6 @@ struct PoolConfig { * @author Superfluid */ abstract contract IGeneralDistributionAgreementV1 is ISuperAgreement { - // Structs - struct UniversalIndexData { - int96 flowRate; - uint32 settledAt; - uint256 totalBuffer; - bool isPool; - int256 settledValue; - } - - struct FlowDistributionData { - uint32 lastUpdated; - int96 flowRate; - uint256 buffer; // stored as uint96 - } - - struct PoolMemberData { - address pool; - uint32 poolID; // the slot id in the pool's subs bitmap - } - - struct StackVarsLiquidation { - ISuperfluidToken token; - int256 availableBalance; - address sender; - bytes32 distributionFlowHash; - int256 signedTotalGDADeposit; - address liquidator; - } - // Custom Errors error GDA_DISTRIBUTE_FOR_OTHERS_NOT_ALLOWED(); // 0xf67d263e @@ -131,6 +102,18 @@ abstract contract IGeneralDistributionAgreementV1 is ISuperAgreement { virtual returns (int96); + function getFlow(ISuperfluidToken token, address from, ISuperfluidPool to) + external + view + virtual + returns (uint256 lastUpdated, int96 flowRate, uint256 deposit); + + function getAccountFlow(ISuperfluidPool 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. diff --git a/packages/ethereum-contracts/test/foundry/agreements/gdav1/GeneralDistributionAgreementV1.prop.sol b/packages/ethereum-contracts/test/foundry/agreements/gdav1/GeneralDistributionAgreementV1.prop.sol index f5bd9d89ad..a1901cbba0 100644 --- a/packages/ethereum-contracts/test/foundry/agreements/gdav1/GeneralDistributionAgreementV1.prop.sol +++ b/packages/ethereum-contracts/test/foundry/agreements/gdav1/GeneralDistributionAgreementV1.prop.sol @@ -12,9 +12,7 @@ import { SuperfluidUpgradeableBeacon } from "../../../../contracts/upgradability import { ISuperToken, SuperToken } from "../../../../contracts/superfluid/SuperToken.sol"; import { ISuperAgreement } from "../../../../contracts/interfaces/superfluid/ISuperAgreement.sol"; import { - GeneralDistributionAgreementV1, - ISuperfluid, - ISuperfluidPool + GeneralDistributionAgreementV1, ISuperfluid, ISuperfluidPool } from "../../../../contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol"; import { IGeneralDistributionAgreementV1, @@ -124,7 +122,7 @@ contract GeneralDistributionAgreementV1Properties is GeneralDistributionAgreemen vm.warp(1000); - (bool exist, IGeneralDistributionAgreementV1.FlowDistributionData memory setFlowDistributionData) = + (bool exist, FlowDistributionData memory setFlowDistributionData) = _getFlowDistributionData(superToken, flowHash); assertEq(true, exist, "flow distribution data does not exist"); @@ -156,14 +154,11 @@ contract GeneralDistributionAgreementV1Properties is GeneralDistributionAgreemen vm.startPrank(address(this)); superToken.updateAgreementData( poolMemberId, - _encodePoolMemberData( - IGeneralDistributionAgreementV1.PoolMemberData({ poolID: poolID, pool: address(_pool) }) - ) + _encodePoolMemberData(PoolMemberData({ poolID: poolID, pool: address(_pool) })) ); vm.stopPrank(); - (bool exist, IGeneralDistributionAgreementV1.PoolMemberData memory setPoolMemberData) = - _getPoolMemberData(superToken, poolMember, _pool); + (bool exist, PoolMemberData memory setPoolMemberData) = _getPoolMemberData(superToken, poolMember, _pool); assertEq(true, exist, "pool member data does not exist"); assertEq(poolID, setPoolMemberData.poolID, "poolID not equal"); @@ -333,11 +328,10 @@ contract GeneralDistributionAgreementV1Properties is GeneralDistributionAgreemen function testEncodeDecodeFlowDistributionData(int96 flowRate, uint96 buffer) public { vm.assume(flowRate >= 0); vm.assume(buffer >= 0); - IGeneralDistributionAgreementV1.FlowDistributionData memory original = IGeneralDistributionAgreementV1 - .FlowDistributionData({ flowRate: flowRate, lastUpdated: uint32(block.timestamp), buffer: buffer }); + FlowDistributionData memory original = + FlowDistributionData({ flowRate: flowRate, lastUpdated: uint32(block.timestamp), buffer: buffer }); bytes32[] memory encoded = _encodeFlowDistributionData(original); - (, IGeneralDistributionAgreementV1.FlowDistributionData memory decoded) = - _decodeFlowDistributionData(uint256(encoded[0])); + (, FlowDistributionData memory decoded) = _decodeFlowDistributionData(uint256(encoded[0])); assertEq(original.flowRate, decoded.flowRate, "flowRate not equal"); assertEq(original.buffer, decoded.buffer, "buffer not equal"); @@ -346,10 +340,9 @@ contract GeneralDistributionAgreementV1Properties is GeneralDistributionAgreemen function testEncodeDecodePoolMemberData(address pool, uint32 poolID) public { vm.assume(pool != address(0)); - IGeneralDistributionAgreementV1.PoolMemberData memory original = - IGeneralDistributionAgreementV1.PoolMemberData({ pool: pool, poolID: poolID }); + PoolMemberData memory original = PoolMemberData({ pool: pool, poolID: poolID }); bytes32[] memory encoded = _encodePoolMemberData(original); - (, IGeneralDistributionAgreementV1.PoolMemberData memory decoded) = _decodePoolMemberData(uint256(encoded[0])); + (, PoolMemberData memory decoded) = _decodePoolMemberData(uint256(encoded[0])); assertEq(original.pool, decoded.pool, "pool not equal"); assertEq(original.poolID, decoded.poolID, "poolID not equal");