Skip to content

Commit f9901f4

Browse files
jflatowmaxwolffhayesgm
committed
Final polish [COMP-1037] (#74)
This patch adds some improvements based on discoveries from the testnet phase of the release. The `claimComp` function has been enhanced in several ways to make it far more gas-efficient and versatile. In particular, it no longer refreshes speeds and allows specifying multiple accounts to claim, the markets in which to claim, and whether to claim the supply side and/or the borrow side independently. The `NewCompRate` event parameter names were changed to reflect that the arguments are not actually mantissas (even though COMP per block units have 18 decimals). When we `transferComp` and check if the COMP accrued is above the threshold, we now also check if the accrued amount is exactly 0, in order to short-circuit unnecessary transfers. Finally, this patch extends the COMP Balance Metadata Lens to include COMP Allocated (that is, what is owed to you but not yet received). This is useful for showing users on an interface how much COMP they have earned, since it can be 'called' to return the differential value. A future version may implement this as a pure-view function, though it is more complex and requires detailed understanding about the way COMP is accrued, so the simpler approach is favored initially. Co-authored-by: Max Wolff <[email protected]> Co-authored-by: Geoff Hayes <[email protected]>
1 parent a0a40a7 commit f9901f4

File tree

13 files changed

+35886
-35716
lines changed

13 files changed

+35886
-35716
lines changed

contracts/Comptroller.sol

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
5151
event MarketComped(CToken cToken, bool isComped);
5252

5353
/// @notice Emitted when COMP rate is changed
54-
event NewCompRate(uint oldCompRateMantissa, uint newCompRateMantissa);
54+
event NewCompRate(uint oldCompRate, uint newCompRate);
5555

5656
/// @notice Emitted when a new COMP speed is calculated for a market
5757
event CompSpeedUpdated(CToken indexed cToken, uint newSpeed);
@@ -247,7 +247,7 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
247247

248248
// Keep the flywheel moving
249249
updateCompSupplyIndex(cToken);
250-
distributeSupplierComp(cToken, minter);
250+
distributeSupplierComp(cToken, minter, false);
251251

252252
return uint(Error.NO_ERROR);
253253
}
@@ -287,7 +287,7 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
287287

288288
// Keep the flywheel moving
289289
updateCompSupplyIndex(cToken);
290-
distributeSupplierComp(cToken, redeemer);
290+
distributeSupplierComp(cToken, redeemer, false);
291291

292292
return uint(Error.NO_ERROR);
293293
}
@@ -376,7 +376,7 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
376376
// Keep the flywheel moving
377377
Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()});
378378
updateCompBorrowIndex(cToken, borrowIndex);
379-
distributeBorrowerComp(cToken, borrower, borrowIndex);
379+
distributeBorrowerComp(cToken, borrower, borrowIndex, false);
380380

381381
return uint(Error.NO_ERROR);
382382
}
@@ -424,7 +424,7 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
424424
// Keep the flywheel moving
425425
Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()});
426426
updateCompBorrowIndex(cToken, borrowIndex);
427-
distributeBorrowerComp(cToken, borrower, borrowIndex);
427+
distributeBorrowerComp(cToken, borrower, borrowIndex, false);
428428

429429
return uint(Error.NO_ERROR);
430430
}
@@ -557,8 +557,8 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
557557

558558
// Keep the flywheel moving
559559
updateCompSupplyIndex(cTokenCollateral);
560-
distributeSupplierComp(cTokenCollateral, borrower);
561-
distributeSupplierComp(cTokenCollateral, liquidator);
560+
distributeSupplierComp(cTokenCollateral, borrower, false);
561+
distributeSupplierComp(cTokenCollateral, liquidator, false);
562562

563563
return uint(Error.NO_ERROR);
564564
}
@@ -611,8 +611,8 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
611611

612612
// Keep the flywheel moving
613613
updateCompSupplyIndex(cToken);
614-
distributeSupplierComp(cToken, src);
615-
distributeSupplierComp(cToken, dst);
614+
distributeSupplierComp(cToken, src, false);
615+
distributeSupplierComp(cToken, dst, false);
616616

617617
return uint(Error.NO_ERROR);
618618
}
@@ -1110,7 +1110,7 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
11101110
return msg.sender == admin || msg.sender == comptrollerImplementation;
11111111
}
11121112

1113-
/*** Comp Flywheel Distribution ***/
1113+
/*** Comp Distribution ***/
11141114

11151115
/**
11161116
* @notice Recalculate and update COMP speeds for all COMP markets
@@ -1197,7 +1197,7 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
11971197
* @param cToken The market in which the supplier is interacting
11981198
* @param supplier The address of the supplier to distribute COMP to
11991199
*/
1200-
function distributeSupplierComp(address cToken, address supplier) internal {
1200+
function distributeSupplierComp(address cToken, address supplier, bool distributeAll) internal {
12011201
CompMarketState storage supplyState = compSupplyState[cToken];
12021202
Double memory supplyIndex = Double({mantissa: supplyState.index});
12031203
Double memory supplierIndex = Double({mantissa: compSupplierIndex[cToken][supplier]});
@@ -1211,7 +1211,7 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
12111211
uint supplierTokens = CToken(cToken).balanceOf(supplier);
12121212
uint supplierDelta = mul_(supplierTokens, deltaIndex);
12131213
uint supplierAccrued = add_(compAccrued[supplier], supplierDelta);
1214-
compAccrued[supplier] = transferComp(supplier, supplierAccrued, compClaimThreshold);
1214+
compAccrued[supplier] = transferComp(supplier, supplierAccrued, distributeAll ? 0 : compClaimThreshold);
12151215
emit DistributedSupplierComp(CToken(cToken), supplier, supplierDelta, supplyIndex.mantissa);
12161216
}
12171217

@@ -1221,7 +1221,7 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
12211221
* @param cToken The market in which the borrower is interacting
12221222
* @param borrower The address of the borrower to distribute COMP to
12231223
*/
1224-
function distributeBorrowerComp(address cToken, address borrower, Exp memory marketBorrowIndex) internal {
1224+
function distributeBorrowerComp(address cToken, address borrower, Exp memory marketBorrowIndex, bool distributeAll) internal {
12251225
CompMarketState storage borrowState = compBorrowState[cToken];
12261226
Double memory borrowIndex = Double({mantissa: borrowState.index});
12271227
Double memory borrowerIndex = Double({mantissa: compBorrowerIndex[cToken][borrower]});
@@ -1232,7 +1232,7 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
12321232
uint borrowerAmount = div_(CToken(cToken).borrowBalanceStored(borrower), marketBorrowIndex);
12331233
uint borrowerDelta = mul_(borrowerAmount, deltaIndex);
12341234
uint borrowerAccrued = add_(compAccrued[borrower], borrowerDelta);
1235-
compAccrued[borrower] = transferComp(borrower, borrowerAccrued, compClaimThreshold);
1235+
compAccrued[borrower] = transferComp(borrower, borrowerAccrued, distributeAll ? 0 : compClaimThreshold);
12361236
emit DistributedBorrowerComp(CToken(cToken), borrower, borrowerDelta, borrowIndex.mantissa);
12371237
}
12381238
}
@@ -1245,7 +1245,7 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
12451245
* @return The amount of COMP which was NOT transferred to the user
12461246
*/
12471247
function transferComp(address user, uint userAccrued, uint threshold) internal returns (uint) {
1248-
if (userAccrued >= threshold) {
1248+
if (userAccrued >= threshold && userAccrued > 0) {
12491249
Comp comp = Comp(getCompAddress());
12501250
uint compRemaining = comp.balanceOf(address(this));
12511251
if (userAccrued <= compRemaining) {
@@ -1257,24 +1257,52 @@ contract Comptroller is ComptrollerV3Storage, ComptrollerInterface, ComptrollerE
12571257
}
12581258

12591259
/**
1260-
* @notice Claim all the comp accrued by holder
1261-
* @param holder The address to claim comp for
1260+
* @notice Claim all the comp accrued by holder in all markets
1261+
* @param holder The address to claim COMP for
12621262
*/
12631263
function claimComp(address holder) public {
1264-
refreshCompSpeeds();
1264+
return claimComp(holder, allMarkets);
1265+
}
12651266

1266-
CToken[] memory allMarkets_ = allMarkets;
1267-
for (uint i = 0; i < allMarkets_.length; i++) {
1268-
CToken cToken = allMarkets_[i];
1269-
Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});
1270-
distributeSupplierComp(address(cToken), holder);
1271-
distributeBorrowerComp(address(cToken), holder, borrowIndex);
1272-
}
1267+
/**
1268+
* @notice Claim all the comp accrued by holder in the specified markets
1269+
* @param holder The address to claim COMP for
1270+
* @param cTokens The list of markets to claim COMP in
1271+
*/
1272+
function claimComp(address holder, CToken[] memory cTokens) public {
1273+
address[] memory holders = new address[](1);
1274+
holders[0] = holder;
1275+
claimComp(holders, cTokens, true, true);
1276+
}
12731277

1274-
compAccrued[holder] = transferComp(holder, compAccrued[holder], 0);
1278+
/**
1279+
* @notice Claim all comp accrued by the holders
1280+
* @param holders The addresses to claim COMP for
1281+
* @param cTokens The list of markets to claim COMP in
1282+
* @param borrowers Whether or not to claim COMP earned by borrowing
1283+
* @param suppliers Whether or not to claim COMP earned by supplying
1284+
*/
1285+
function claimComp(address[] memory holders, CToken[] memory cTokens, bool borrowers, bool suppliers) public {
1286+
for (uint i = 0; i < cTokens.length; i++) {
1287+
CToken cToken = cTokens[i];
1288+
require(markets[address(cToken)].isListed, "market must be listed");
1289+
if (borrowers == true) {
1290+
Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});
1291+
updateCompBorrowIndex(address(cToken), borrowIndex);
1292+
for (uint j = 0; j < holders.length; j++) {
1293+
distributeBorrowerComp(address(cToken), holders[j], borrowIndex, true);
1294+
}
1295+
}
1296+
if (suppliers == true) {
1297+
updateCompSupplyIndex(address(cToken));
1298+
for (uint j = 0; j < holders.length; j++) {
1299+
distributeSupplierComp(address(cToken), holders[j], true);
1300+
}
1301+
}
1302+
}
12751303
}
12761304

1277-
/*** Comp Flyhwheel Admin ***/
1305+
/*** Comp Distribution Admin ***/
12781306

12791307
/**
12801308
* @notice Set the amount of COMP distributed per block

contracts/Lens/CompoundLens.sol

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,29 @@ contract CompoundLens {
259259
});
260260
}
261261

262+
struct CompBalanceMetadataExt {
263+
uint balance;
264+
uint votes;
265+
address delegate;
266+
uint allocated;
267+
}
268+
269+
function getCompBalanceMetadataExt(Comp comp, Comptroller comptroller, address account) external returns (CompBalanceMetadataExt memory) {
270+
uint balance = comp.balanceOf(account);
271+
comptroller.claimComp(account);
272+
uint newBalance = comp.balanceOf(account);
273+
uint accrued = comptroller.compAccrued(account);
274+
uint total = add(accrued, newBalance, "sum comp total");
275+
uint allocated = sub(total, balance, "sub allocated");
276+
277+
return CompBalanceMetadataExt({
278+
balance: balance,
279+
votes: uint256(comp.getCurrentVotes(account)),
280+
delegate: comp.delegates(account),
281+
allocated: allocated
282+
});
283+
}
284+
262285
struct CompVotes {
263286
uint blockNumber;
264287
uint votes;
@@ -278,4 +301,16 @@ contract CompoundLens {
278301
function compareStrings(string memory a, string memory b) internal pure returns (bool) {
279302
return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))));
280303
}
304+
305+
function add(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
306+
uint c = a + b;
307+
require(c >= a, errorMessage);
308+
return c;
309+
}
310+
311+
function sub(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
312+
require(b <= a, errorMessage);
313+
uint c = a - b;
314+
return c;
315+
}
281316
}

contracts/Flywheel/Reservoir.sol renamed to contracts/Reservoir.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,4 @@ contract Reservoir {
9797
}
9898
}
9999

100-
import "../EIP20Interface.sol";
100+
import "./EIP20Interface.sol";

0 commit comments

Comments
 (0)