Skip to content

Commit 9e93ba5

Browse files
committed
gas optimization
1 parent f1d3270 commit 9e93ba5

File tree

6 files changed

+103
-13
lines changed

6 files changed

+103
-13
lines changed

packages/ethereum-contracts/contracts/agreements/ConstantFlowAgreementV1.sol

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,8 +1348,7 @@ contract ConstantFlowAgreementV1 is
13481348
// do not enforce balance checks during callbacks for the appCreditToken
13491349
if (currentContext.callType != ContextDefinitions.CALL_INFO_CALL_TYPE_APP_CALLBACK ||
13501350
currentContext.appCreditToken != token) {
1351-
(int256 availableBalance,,) = token.realtimeBalanceOf(flowSender, currentContext.timestamp);
1352-
if (availableBalance < 0) {
1351+
if (! token.hasRealtimeBalanceOfAtLeast(flowSender, currentContext.timestamp, 0)) {
13531352
revert CFA_INSUFFICIENT_BALANCE();
13541353
}
13551354
}

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,38 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
150150
owedBuffer = 0;
151151
}
152152

153+
function hasRealtimeBalanceOfAtLeast(ISuperfluidToken token, address account, uint256 time, int256 minBalance)
154+
public view override returns (bool)
155+
{
156+
UniversalIndexData memory universalIndexData = _getUIndexData(abi.encode(token), account);
157+
158+
int256 balance;
159+
if (_isPool(token, account)) {
160+
balance = ISuperfluidPool(account).getDisconnectedBalance(uint32(time));
161+
} else {
162+
// this is outflow and can only be negative or 0
163+
balance = Value.unwrap(_getBasicParticleFromUIndex(universalIndexData).rtb(Time.wrap(uint32(time))));
164+
}
165+
// subtract buffer
166+
balance -= universalIndexData.totalBuffer.toInt256();
167+
168+
{
169+
if (balance >= minBalance) {
170+
return true; // it can only increase from here, so we can stop calculating
171+
}
172+
(uint32[] memory slotIds, bytes32[] memory pidList) = _listPoolConnectionIds(token, account);
173+
for (uint256 i = 0; i < slotIds.length; ++i) {
174+
address pool = address(uint160(uint256(pidList[i])));
175+
(bool exist, PoolMemberData memory poolMemberData) =
176+
_getPoolMemberData(token, account, ISuperfluidPool(pool));
177+
assert(exist);
178+
assert(poolMemberData.pool == pool);
179+
balance += ISuperfluidPool(pool).getClaimable(account, uint32(time));
180+
}
181+
}
182+
return balance >= minBalance;
183+
}
184+
153185
/// @dev ISuperAgreement.realtimeBalanceOf implementation
154186
function realtimeBalanceOfNow(ISuperfluidToken token, address account)
155187
external

packages/ethereum-contracts/contracts/interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,4 +277,17 @@ abstract contract IGeneralDistributionAgreementV1 is ISuperAgreement {
277277
view
278278
virtual
279279
returns (bool);
280+
281+
282+
function hasRealtimeBalanceOfAtLeast(
283+
ISuperfluidToken token,
284+
address account,
285+
uint256 time,
286+
int256 minAmount
287+
)
288+
external
289+
view
290+
virtual
291+
returns (bool);
292+
280293
}

packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperAgreement.sol

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,4 @@ interface ISuperAgreement {
3434
uint256 deposit,
3535
uint256 owedDeposit
3636
);
37-
3837
}

packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ interface ISuperfluidToken {
3131
/**
3232
* @dev Encoded liquidation type data mainly used for handling stack to deep errors
3333
*
34-
* @custom:note
34+
* @custom:note
3535
* - version: 1
3636
* - liquidationType key:
3737
* - 0 = reward account receives reward (PIC period)
@@ -83,6 +83,10 @@ interface ISuperfluidToken {
8383
uint256 owedDeposit,
8484
uint256 timestamp);
8585

86+
function hasRealtimeBalanceOfAtLeast(address account, uint256 timestamp, int256 minBalance)
87+
external view
88+
returns (bool);
89+
8690
/**
8791
* @notice Check if account is critical
8892
* @dev A critical account is when availableBalance < 0
@@ -231,7 +235,7 @@ interface ISuperfluidToken {
231235
* @dev Update agreement state slot
232236
* @param account Account to be updated
233237
*
234-
* @custom:note
238+
* @custom:note
235239
* - To clear the storage out, provide zero-ed array of intended length
236240
*/
237241
function updateAgreementStateSlot(
@@ -274,7 +278,7 @@ interface ISuperfluidToken {
274278
* @param account Account to query.
275279
* @param delta Amount of balance delta to be settled
276280
*
277-
* @custom:modifiers
281+
* @custom:modifiers
278282
* - onlyAgreement
279283
*/
280284
function settleBalance(
@@ -293,7 +297,7 @@ interface ISuperfluidToken {
293297
* @param rewardAmount The amount the rewarded account will receive
294298
* @param targetAccountBalanceDelta The delta amount the target account balance should change by
295299
*
296-
* @custom:note
300+
* @custom:note
297301
* - If a bailout is required (bailoutAmount > 0)
298302
* - the actual reward (single deposit) goes to the executor,
299303
* - while the reward account becomes the bailout account
@@ -303,7 +307,7 @@ interface ISuperfluidToken {
303307
* - the targetAccount will pay the rewardAmount
304308
* - the liquidator (reward account in PIC period) will receive the rewardAmount
305309
*
306-
* @custom:modifiers
310+
* @custom:modifiers
307311
* - onlyAgreement
308312
*/
309313
function makeLiquidationPayoutsV2
@@ -327,7 +331,7 @@ interface ISuperfluidToken {
327331
* @param targetAccountBalanceDelta The amount the sender account balance should change by
328332
* @param liquidationTypeData The encoded liquidation type data including the version (how to decode)
329333
*
330-
* @custom:note
334+
* @custom:note
331335
* Reward account rule:
332336
* - if the agreement is liquidated during the PIC period
333337
* - the rewardAmountReceiver will get the rewardAmount (remaining deposit), regardless of the liquidatorAccount
@@ -412,7 +416,7 @@ interface ISuperfluidToken {
412416
*
413417
* @custom:deprecated Use AgreementLiquidatedV2 instead
414418
*
415-
* @custom:note
419+
* @custom:note
416420
* Reward account rule:
417421
* - if bailout is equal to 0, then
418422
* - the bondAccount will get the rewardAmount,

packages/ethereum-contracts/contracts/superfluid/SuperfluidToken.sol

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import {
77
ISuperfluid,
88
ISuperAgreement,
99
ISuperfluidGovernance,
10-
ISuperfluidToken
10+
ISuperfluidToken,
11+
IGeneralDistributionAgreementV1
1112
} from "../interfaces/superfluid/ISuperfluid.sol";
1213
import { FixedSizeData } from "../libs/FixedSizeData.sol";
1314

@@ -105,6 +106,49 @@ abstract contract SuperfluidToken is ISuperfluidToken
105106
}
106107
}
107108

109+
function hasRealtimeBalanceOfAtLeast(
110+
address account,
111+
uint256 timestamp,
112+
int256 minBalance
113+
)
114+
public view virtual override
115+
returns (bool)
116+
{
117+
int256 availableBalance = _sharedSettledBalances[account];
118+
ISuperAgreement[] memory activeAgreements = getAccountActiveAgreements(account);
119+
IGeneralDistributionAgreementV1 gda;
120+
for (uint256 i = 0; i < activeAgreements.length; ++i) {
121+
if (activeAgreements[i].agreementType() ==
122+
keccak256("org.superfluid-finance.agreements.GeneralDistributionAgreement.v1"))
123+
{
124+
gda = IGeneralDistributionAgreementV1(address(activeAgreements[i]));
125+
continue;
126+
} else {
127+
(
128+
int256 agreementDynamicBalance,
129+
uint256 agreementDeposit,
130+
uint256 agreementOwedDeposit) = activeAgreements[i]
131+
.realtimeBalanceOf(
132+
this,
133+
account,
134+
timestamp
135+
);
136+
137+
availableBalance = availableBalance
138+
+ agreementDynamicBalance
139+
- (
140+
agreementDeposit > agreementOwedDeposit ?
141+
(agreementDeposit - agreementOwedDeposit) : 0
142+
).toInt256();
143+
}
144+
}
145+
if (address(gda) != address(0)) {
146+
return gda.hasRealtimeBalanceOfAtLeast(this, account, timestamp, minBalance - availableBalance);
147+
}
148+
149+
return availableBalance >= minBalance;
150+
}
151+
108152
/// @dev ISuperfluidToken.realtimeBalanceOfNow implementation
109153
function realtimeBalanceOfNow(
110154
address account
@@ -211,8 +255,7 @@ abstract contract SuperfluidToken is ISuperfluidToken
211255
)
212256
internal
213257
{
214-
(int256 availableBalance,,) = realtimeBalanceOf(from, _host.getNow());
215-
if (availableBalance < amount) {
258+
if (! hasRealtimeBalanceOfAtLeast(from, _host.getNow(), amount)) {
216259
revert SF_TOKEN_MOVE_INSUFFICIENT_BALANCE();
217260
}
218261
_sharedSettledBalances[from] = _sharedSettledBalances[from] - amount;

0 commit comments

Comments
 (0)