Skip to content

Commit 3647c07

Browse files
committed
WIP: refactor FlowInfo reader/writer
1 parent d24a9ee commit 3647c07

File tree

3 files changed

+103
-86
lines changed

3 files changed

+103
-86
lines changed

packages/ethereum-contracts/contracts/agreements/gdav1/GDAv1StorageLayout.sol

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ import { ISuperfluidPool } from "../../interfaces/agreements/gdav1/ISuperfluidPo
5959
* PoolMemberId stores PoolMemberData for a member at a pool.
6060
*/
6161
library GDAv1StorageReader {
62-
uint256 internal constant ACCOUNT_DATA_STATE_SLOT_ID = 0;
6362

6463
// # Account Data Operations
6564
//
@@ -78,10 +77,12 @@ library GDAv1StorageReader {
7877
// | 256b |
7978
// --------+------------------+------------------+------------------+------------------+
8079

80+
uint256 internal constant ACCOUNT_DATA_STATE_SLOT_ID = 0;
81+
8182
struct AccountData {
8283
int96 flowRate;
8384
uint32 settledAt;
84-
uint256 totalBuffer;
85+
uint256 totalBuffer; // stored as uint96
8586
bool isPool;
8687
int256 settledValue;
8788
}
@@ -165,6 +166,70 @@ library GDAv1StorageReader {
165166
uIndex._settled_at = Time.wrap(accountData.settledAt);
166167
uIndex._settled_value = Value.wrap(accountData.settledValue);
167168
}
169+
170+
// FlowDistributionData data packing:
171+
// --------+----------+-------------+----------+--------+
172+
// WORD A: | reserved | lastUpdated | flowRate | buffer |
173+
// --------+----------+-------------+----------+--------+
174+
// | 32 | 32 | 96 | 96 |
175+
// --------+----------+-------------+----------+--------+
176+
177+
struct FlowDistributionData {
178+
uint32 lastUpdated;
179+
int96 flowRate;
180+
uint256 buffer; // stored as uint96
181+
}
182+
183+
function getFlowDistributionHash(address from, ISuperfluidPool to) internal view returns (bytes32) {
184+
return keccak256(abi.encode(block.chainid, "distributionFlow", from, to));
185+
}
186+
187+
function encodeFlowDistributionData(FlowDistributionData memory flowDistributionData)
188+
internal pure
189+
returns (bytes32[] memory data)
190+
{
191+
data = new bytes32[](1);
192+
data[0] = bytes32(
193+
(uint256(uint32(flowDistributionData.lastUpdated)) << 192) |
194+
(uint256(uint96(flowDistributionData.flowRate)) << 96) |
195+
uint256(flowDistributionData.buffer)
196+
);
197+
}
198+
199+
function decodeFlowDistributionData(uint256 data)
200+
internal pure
201+
returns (FlowDistributionData memory flowDistributionData)
202+
{
203+
if (data > 0) {
204+
flowDistributionData.lastUpdated = uint32((data >> 192) & uint256(type(uint32).max));
205+
flowDistributionData.flowRate = int96(int256(data >> 96));
206+
flowDistributionData.buffer = uint96(data & uint256(type(uint96).max));
207+
}
208+
}
209+
210+
function getFlowDistributionDataWithKnownHash(
211+
ISuperfluidToken token,
212+
IGeneralDistributionAgreementV1 gda,
213+
bytes32 flowDistributionHash
214+
)
215+
internal view
216+
returns (FlowDistributionData memory flowDistributionData)
217+
{
218+
uint256 data = uint256(token.getAgreementData(address(gda), flowDistributionHash, 1)[0]);
219+
return decodeFlowDistributionData(data);
220+
}
221+
222+
function getFlowDistributionData(
223+
ISuperfluidToken token,
224+
IGeneralDistributionAgreementV1 gda,
225+
address from,
226+
ISuperfluidPool to
227+
)
228+
internal view
229+
returns (FlowDistributionData memory flowDistributionData)
230+
{
231+
return getFlowDistributionDataWithKnownHash(token, gda, getFlowDistributionHash(from, to));
232+
}
168233
}
169234

170235

@@ -187,7 +252,7 @@ library GDAv1StorageWriter {
187252
);
188253
}
189254

190-
function setPool(ISuperfluidToken token, ISuperfluidPool pool)
255+
function setIsPoolFlag(ISuperfluidToken token, ISuperfluidPool pool)
191256
internal
192257
{
193258
bytes32[] memory data = new bytes32[](1);

packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol

Lines changed: 23 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,6 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
4949
uint32 poolID; // the slot id in the pool's subs bitmap
5050
}
5151

52-
struct FlowDistributionData {
53-
uint32 lastUpdated;
54-
int96 flowRate;
55-
uint256 buffer; // stored as uint96
56-
}
57-
5852
address public constant SLOTS_BITMAP_LIBRARY_ADDRESS = address(SlotsBitmapLibrary);
5953

6054
address public constant SUPERFLUID_POOL_DEPLOYER_ADDRESS = address(SuperfluidPoolDeployerLibrary);
@@ -141,7 +135,7 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
141135
override
142136
returns (int96)
143137
{
144-
(, FlowDistributionData memory data) = _getFlowDistributionData(token, _getFlowDistributionHash(from, to));
138+
GDAv1StorageReader.FlowDistributionData memory data = token.getFlowDistributionData(this, from, to);
145139
return data.flowRate;
146140
}
147141

@@ -152,7 +146,7 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
152146
override
153147
returns (uint256 lastUpdated, int96 flowRate, uint256 deposit)
154148
{
155-
(, FlowDistributionData memory data) = _getFlowDistributionData(token, _getFlowDistributionHash(from, to));
149+
GDAv1StorageReader.FlowDistributionData memory data = token.getFlowDistributionData(this, from, to);
156150
lastUpdated = data.lastUpdated;
157151
flowRate = data.flowRate;
158152
deposit = data.buffer;
@@ -179,7 +173,7 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
179173
int96 requestedFlowRate
180174
) external view override returns (int96 actualFlowRate, int96 totalDistributionFlowRate) {
181175
bytes memory eff = abi.encode(token);
182-
bytes32 distributionFlowHash = _getFlowDistributionHash(from, to);
176+
bytes32 distributionFlowHash = GDAv1StorageReader.getFlowDistributionHash(from, to);
183177

184178
BasicParticle memory fromUIndexData = _getUIndex(eff, from);
185179

@@ -240,7 +234,7 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
240234
)
241235
);
242236

243-
token.setPool(pool);
237+
token.setIsPoolFlag(pool);
244238

245239
IPoolAdminNFT poolAdminNFT = IPoolAdminNFT(_getPoolAdminNFTAddress(token));
246240

@@ -473,7 +467,7 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
473467
_StackVars_DistributeFlow memory flowVars;
474468
{
475469
flowVars.currentContext = AgreementLibrary.authorizeTokenAccess(token, ctx);
476-
flowVars.distributionFlowHash = _getFlowDistributionHash(from, pool);
470+
flowVars.distributionFlowHash = GDAv1StorageReader.getFlowDistributionHash(from, pool);
477471
flowVars.oldFlowRate = _getFlowRate(abi.encode(token), flowVars.distributionFlowHash);
478472
}
479473

@@ -577,8 +571,8 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
577571
}
578572

579573
function _makeLiquidationPayouts(_StackVars_Liquidation memory data) internal {
580-
(, FlowDistributionData memory flowDistributionData) =
581-
_getFlowDistributionData(ISuperfluidToken(data.token), data.distributionFlowHash);
574+
GDAv1StorageReader.FlowDistributionData memory flowDistributionData =
575+
data.token.getFlowDistributionDataWithKnownHash(this, data.distributionFlowHash);
582576
int256 signedSingleDeposit = flowDistributionData.buffer.toInt256();
583577

584578
bool isCurrentlyPatricianPeriod;
@@ -631,8 +625,8 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
631625

632626
(uint256 liquidationPeriod,) = SolvencyHelperLibrary.decode3PsData(ISuperfluid(_host), ISuperfluidToken(token));
633627

634-
(, FlowDistributionData memory flowDistributionData) =
635-
_getFlowDistributionData(ISuperfluidToken(token), flowHash);
628+
GDAv1StorageReader.FlowDistributionData memory flowDistributionData =
629+
token.getFlowDistributionDataWithKnownHash(this, flowHash);
636630

637631
// @note downcasting from uint256 -> uint32 for liquidation period
638632
Value newBufferAmount = newFlowRate.mul(Time.wrap(uint32(liquidationPeriod)));
@@ -644,8 +638,8 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
644638
Value bufferDelta = newBufferAmount - Value.wrap(uint256(flowDistributionData.buffer).toInt256());
645639

646640
{
647-
bytes32[] memory data = _encodeFlowDistributionData(
648-
FlowDistributionData({
641+
bytes32[] memory data = GDAv1StorageReader.encodeFlowDistributionData(
642+
GDAv1StorageReader.FlowDistributionData({
649643
lastUpdated: uint32(block.timestamp),
650644
flowRate: int256(FlowRate.unwrap(newFlowRate)).toInt96(),
651645
buffer: uint256(Value.unwrap(newBufferAmount)) // upcast to uint256 is safe
@@ -756,19 +750,15 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
756750

757751
// Hash Getters
758752

759-
function _getPoolMemberHash(address poolMember, ISuperfluidPool pool) internal view returns (bytes32) {
760-
return keccak256(abi.encode(block.chainid, "poolMember", poolMember, address(pool)));
761-
}
762-
763-
function _getFlowDistributionHash(address from, ISuperfluidPool to) internal view returns (bytes32) {
764-
return keccak256(abi.encode(block.chainid, "distributionFlow", from, to));
765-
}
766-
767753
function _getPoolAdjustmentFlowHash(address from, address to) internal view returns (bytes32) {
768754
// this will never be in conflict with other flow has types
769755
return keccak256(abi.encode(block.chainid, "poolAdjustmentFlow", from, to));
770756
}
771757

758+
function _getPoolMemberHash(address poolMember, ISuperfluidPool pool) internal view returns (bytes32) {
759+
return keccak256(abi.encode(block.chainid, "poolMember", poolMember, address(pool)));
760+
}
761+
772762
//
773763
// TokenMonad virtual functions
774764
//
@@ -824,8 +814,9 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
824814
override
825815
returns (FlowRate)
826816
{
827-
(, FlowDistributionData memory data) =
828-
_getFlowDistributionData(ISuperfluidToken(abi.decode(eff, (address))), distributionFlowHash);
817+
ISuperfluidToken token = ISuperfluidToken(abi.decode(eff, (address)));
818+
GDAv1StorageReader.FlowDistributionData memory data =
819+
token.getFlowDistributionDataWithKnownHash(this, distributionFlowHash);
829820
return FlowRate.wrap(data.flowRate);
830821
}
831822

@@ -842,14 +833,14 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
842833
override
843834
returns (bytes memory)
844835
{
845-
address token = abi.decode(eff, (address));
846-
(, FlowDistributionData memory flowDistributionData) =
847-
_getFlowDistributionData(ISuperfluidToken(token), flowHash);
836+
ISuperfluidToken token = ISuperfluidToken(abi.decode(eff, (address)));
837+
GDAv1StorageReader.FlowDistributionData memory flowDistributionData =
838+
token.getFlowDistributionDataWithKnownHash(this, flowHash);
848839

849840
ISuperfluidToken(token).updateAgreementData(
850841
flowHash,
851-
_encodeFlowDistributionData(
852-
FlowDistributionData({
842+
GDAv1StorageReader.encodeFlowDistributionData(
843+
GDAv1StorageReader.FlowDistributionData({
853844
lastUpdated: uint32(block.timestamp),
854845
flowRate: int256(FlowRate.unwrap(newFlowRate)).toInt96(),
855846
buffer: flowDistributionData.buffer
@@ -879,47 +870,6 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
879870
return _setPoolAdjustmentFlowRate(eff, pool, false, /* doShift? */ flowRate, t);
880871
}
881872

882-
// FlowDistributionData data packing:
883-
// -------- ---------- ------------- ---------- --------
884-
// WORD A: | reserved | lastUpdated | flowRate | buffer |
885-
// -------- ---------- ------------- ---------- --------
886-
// | 32 | 32 | 96 | 96 |
887-
// -------- ---------- ------------- ---------- --------
888-
889-
function _encodeFlowDistributionData(FlowDistributionData memory flowDistributionData)
890-
internal
891-
pure
892-
returns (bytes32[] memory data)
893-
{
894-
data = new bytes32[](1);
895-
data[0] = bytes32(
896-
(uint256(uint32(flowDistributionData.lastUpdated)) << 192)
897-
| (uint256(uint96(flowDistributionData.flowRate)) << 96) | uint256(flowDistributionData.buffer)
898-
);
899-
}
900-
901-
function _decodeFlowDistributionData(uint256 data)
902-
internal
903-
pure
904-
returns (bool exist, FlowDistributionData memory flowDistributionData)
905-
{
906-
exist = data > 0;
907-
if (exist) {
908-
flowDistributionData.lastUpdated = uint32((data >> 192) & uint256(type(uint32).max));
909-
flowDistributionData.flowRate = int96(int256(data >> 96));
910-
flowDistributionData.buffer = uint96(data & uint256(type(uint96).max));
911-
}
912-
}
913-
914-
function _getFlowDistributionData(ISuperfluidToken token, bytes32 distributionFlowHash)
915-
internal
916-
view
917-
returns (bool exist, FlowDistributionData memory flowDistributionData)
918-
{
919-
(exist, flowDistributionData) =
920-
_decodeFlowDistributionData(uint256(token.getAgreementData(address(this), distributionFlowHash, 1)[0]));
921-
}
922-
923873
// PoolMemberData data packing:
924874
// -------- ---------- -------- -------------
925875
// WORD A: | reserved | poolID | poolAddress |

packages/ethereum-contracts/test/foundry/agreements/gdav1/GeneralDistributionAgreementV1.prop.t.sol

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ contract GeneralDistributionAgreementV1Properties is GeneralDistributionAgreemen
110110
) public {
111111
uint256 lastUpdated = block.timestamp;
112112

113-
bytes32 flowHash = _getFlowDistributionHash(from, to);
113+
bytes32 flowHash = GDAv1StorageReader.getFlowDistributionHash(from, to);
114114

115115
_setFlowInfo(
116116
abi.encode(superToken),
@@ -122,11 +122,8 @@ contract GeneralDistributionAgreementV1Properties is GeneralDistributionAgreemen
122122
);
123123

124124
vm.warp(1000);
125-
126-
(bool exist, FlowDistributionData memory setFlowDistributionData) =
127-
_getFlowDistributionData(superToken, flowHash);
128-
129-
assertEq(true, exist, "flow distribution data does not exist");
125+
GDAv1StorageReader.FlowDistributionData memory setFlowDistributionData =
126+
superToken.getFlowDistributionDataWithKnownHash(this, flowHash);
130127

131128
assertEq(int96(uint96(newFlowRate)), setFlowDistributionData.flowRate, "flowRate not equal");
132129

@@ -342,10 +339,15 @@ contract GeneralDistributionAgreementV1Properties is GeneralDistributionAgreemen
342339
function testEncodeDecodeFlowDistributionData(int96 flowRate, uint96 buffer) public view {
343340
vm.assume(flowRate >= 0);
344341
vm.assume(buffer >= 0);
345-
FlowDistributionData memory original =
346-
FlowDistributionData({ flowRate: flowRate, lastUpdated: uint32(block.timestamp), buffer: buffer });
347-
bytes32[] memory encoded = _encodeFlowDistributionData(original);
348-
(, FlowDistributionData memory decoded) = _decodeFlowDistributionData(uint256(encoded[0]));
342+
GDAv1StorageReader.FlowDistributionData memory original =
343+
GDAv1StorageReader.FlowDistributionData({
344+
flowRate: flowRate,
345+
lastUpdated: uint32(block.timestamp),
346+
buffer: buffer
347+
});
348+
bytes32[] memory encoded = GDAv1StorageReader.encodeFlowDistributionData(original);
349+
GDAv1StorageReader.FlowDistributionData memory decoded =
350+
GDAv1StorageReader.decodeFlowDistributionData(uint256(encoded[0]));
349351

350352
assertEq(original.flowRate, decoded.flowRate, "flowRate not equal");
351353
assertEq(original.buffer, decoded.buffer, "buffer not equal");

0 commit comments

Comments
 (0)