diff --git a/contracts/Comptroller.sol b/contracts/Comptroller.sol index 13ddf7b79..4399c3f61 100644 --- a/contracts/Comptroller.sol +++ b/contracts/Comptroller.sol @@ -12,7 +12,7 @@ import "./Governance/Comp.sol"; * @title Compound's Comptroller Contract * @author Compound */ -contract Comptroller is ComptrollerV6Storage, ComptrollerInterface, ComptrollerErrorReporter, ExponentialNoError { +contract Comptroller is ComptrollerV7Storage, ComptrollerInterface, ComptrollerErrorReporter, ExponentialNoError { /// @notice Emitted when an admin supports a market event MarketListed(CToken cToken); @@ -67,6 +67,12 @@ contract Comptroller is ComptrollerV6Storage, ComptrollerInterface, ComptrollerE /// @notice Emitted when COMP is granted by admin event CompGranted(address recipient, uint amount); + /// @notice Emitted when COMP accrued for a user has been manually adjusted. + event CompAccruedAdjusted(address indexed user, uint oldCompAccrued, uint newCompAccrued); + + /// @notice Emitted when COMP receivable for a user has been updated. + event CompReceivableUpdated(address indexed user, uint oldCompReceivable, uint newCompReceivable); + /// @notice The initial COMP index for a market uint224 public constant compInitialIndex = 1e36; @@ -1079,6 +1085,54 @@ contract Comptroller is ComptrollerV6Storage, ComptrollerInterface, ComptrollerE require(unitroller._acceptImplementation() == 0, "change not authorized"); } + /// @notice Delete this function after proposal 65 is executed + function fixBadAccruals(address[] calldata affectedUsers, uint[] calldata amounts) external { + require(msg.sender == admin, "Only admin can call this function"); // Only the timelock can call this function + require(!proposal65FixExecuted, "Already executed this one-off function"); // Require that this function is only called once + require(affectedUsers.length == amounts.length, "Invalid input"); + + // Loop variables + address user; + uint currentAccrual; + uint amountToSubtract; + uint newAccrual; + + // Iterate through all affected users + for (uint i = 0; i < affectedUsers.length; ++i) { + user = affectedUsers[i]; + currentAccrual = compAccrued[user]; + + amountToSubtract = amounts[i]; + + // The case where the user has claimed and received an incorrect amount of COMP. + // The user has less currently accrued than the amount they incorrectly received. + if (amountToSubtract > currentAccrual) { + // Amount of COMP the user owes the protocol + uint accountReceivable = amountToSubtract - currentAccrual; // Underflow safe since amountToSubtract > currentAccrual + + uint oldReceivable = compReceivable[user]; + uint newReceivable = add_(oldReceivable, accountReceivable); + + // Accounting: record the COMP debt for the user + compReceivable[user] = newReceivable; + + emit CompReceivableUpdated(user, oldReceivable, newReceivable); + + amountToSubtract = currentAccrual; + } + + if (amountToSubtract > 0) { + // Subtract the bad accrual amount from what they have accrued. + // Users will keep whatever they have correctly accrued. + compAccrued[user] = newAccrual = sub_(currentAccrual, amountToSubtract); + + emit CompAccruedAdjusted(user, currentAccrual, newAccrual); + } + } + + proposal65FixExecuted = true; // Makes it so that this function cannot be called again + } + /** * @notice Checks caller is admin, or this contract is becoming the new implementation */ @@ -1315,18 +1369,6 @@ contract Comptroller is ComptrollerV6Storage, ComptrollerInterface, ComptrollerE * @return The amount of COMP which was NOT transferred to the user */ function grantCompInternal(address user, uint amount) internal returns (uint) { - for (uint i = 0; i < allMarkets.length; ++i) { - address market = address(allMarkets[i]); - - bool noOriginalSpeed = compBorrowSpeeds[market] == 0; - bool invalidSupply = noOriginalSpeed && compSupplierIndex[market][user] > 0; - bool invalidBorrow = noOriginalSpeed && compBorrowerIndex[market][user] > 0; - - if (invalidSupply || invalidBorrow) { - return amount; - } - } - Comp comp = Comp(getCompAddress()); uint compRemaining = comp.balanceOf(address(this)); if (amount > 0 && amount <= compRemaining) { diff --git a/contracts/ComptrollerStorage.sol b/contracts/ComptrollerStorage.sol index fdf1eed8c..b74db651e 100644 --- a/contracts/ComptrollerStorage.sol +++ b/contracts/ComptrollerStorage.sol @@ -151,3 +151,11 @@ contract ComptrollerV6Storage is ComptrollerV5Storage { /// @notice The rate at which comp is distributed to the corresponding supply market (per block) mapping(address => uint) public compSupplySpeeds; } + +contract ComptrollerV7Storage is ComptrollerV6Storage { + /// @notice Flag indicating whether the function to fix COMP accruals has been executed (RE: proposal 62 bug) + bool public proposal65FixExecuted; + + /// @notice Accounting storage mapping account addresses to how much COMP they owe the protocol. + mapping(address => uint) public compReceivable; +} diff --git a/scenario/src/Contract/Comptroller.ts b/scenario/src/Contract/Comptroller.ts index 385faad89..b31bdb83a 100644 --- a/scenario/src/Contract/Comptroller.ts +++ b/scenario/src/Contract/Comptroller.ts @@ -53,6 +53,7 @@ interface ComptrollerMethods { compSupplyState(string): Callable compBorrowState(string): Callable compAccrued(string): Callable + compReceivable(string): Callable compSupplierIndex(market: string, account: string): Callable compBorrowerIndex(market: string, account: string): Callable compSpeeds(string): Callable diff --git a/scenario/src/CoreEvent.ts b/scenario/src/CoreEvent.ts index ec6b10741..7693a9153 100644 --- a/scenario/src/CoreEvent.ts +++ b/scenario/src/CoreEvent.ts @@ -244,6 +244,17 @@ export const commands: (View | ((world: World) => Promise>))[] = [new Arg('message', getStringV)], async (world, { message }) => print(world, message.val) ), + new View<{ num: NumberV }>( + ` + #### PrintNumber + + * "Print ..." - Prints given number + * E.g. "Print \"Hello there\"" + `, + 'PrintNumber', + [new Arg('num', getNumberV)], + async (world, { num }) => print(world, num.toString()) + ), new View<{}>( ` #### PrintTransactionLogs @@ -487,6 +498,17 @@ export const commands: (View | ((world: World) => Promise>))[] = async (world, { message }) => inspect(world, message.val) ), + new View<{ num: NumberV }>( + ` + #### DebugNumber + + * "Debug num:" - Same as inspect but prepends with a number + `, + 'DebugNumber', + [new Arg('num', getNumberV)], + async (world, { num }) => inspect(world, num.toString()) + ), + new View<{ account: AddressV; event: EventV }>( ` #### From diff --git a/scenario/src/Value/ComptrollerValue.ts b/scenario/src/Value/ComptrollerValue.ts index 684cbcc9f..90e4aa57a 100644 --- a/scenario/src/Value/ComptrollerValue.ts +++ b/scenario/src/Value/ComptrollerValue.ts @@ -504,6 +504,21 @@ export function comptrollerFetchers() { return new NumberV(result); } ), + new Fetcher<{comptroller: Comptroller, account: AddressV, key: StringV}, NumberV>(` + #### CompReceivable(address) + + * "Comptroller CompReceivable Coburn + `, + "CompReceivable", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("account", getAddressV), + ], + async (world, {comptroller,account}) => { + const result = await comptroller.methods.compReceivable(account.val).call(); + return new NumberV(result); + } + ), new Fetcher<{comptroller: Comptroller, CToken: CToken, account: AddressV}, NumberV>(` #### compSupplierIndex diff --git a/spec/sim/0065-correct-bad-comp-accruals/hypothetical_mainnet_upgrade.scen b/spec/sim/0065-correct-bad-comp-accruals/hypothetical_mainnet_upgrade.scen new file mode 100755 index 000000000..4c85729e2 --- /dev/null +++ b/spec/sim/0065-correct-bad-comp-accruals/hypothetical_mainnet_upgrade.scen @@ -0,0 +1,97 @@ +#!/usr/bin/env -S yarn repl -s + +PrintTransactionLogs + +-- Token holder addresses for mocking +Alias CompHolder "0x7587caefc8096f5f40acb83a09df031a018c66ec" + +Alias AffectedUser1 "0xb3bd459e0598dde1fe84b1d0a1430be175b5d5be" +Alias AffectedUser2 "0xc5119db28adde44a8e1453e733381025a2910f7d" +Alias AffectedUser3 "0x309d413391e975b553b7b8d19bc11f8a6c2eb889" +Alias AffectedUser4 "0x261fe0fc430c4ce4158ebe9258e7f9c646fea448" +Alias AffectedUser54 "0xb265ac5bc12a97bc359b0ca0870f8b1cec6369e9" +Alias AffectedUser74 "0xde122ae193f46d67c239ae0c7dae644f9931a772" -- The last affected user + +Web3Fork "https://mainnet-eth.compound.finance/@13380217" (CompHolder) +UseConfigs mainnet + +-- Execute proposal 64 +IncreaseTime 604910 +GovernorBravo GovernorBravo Proposal LastProposal Execute + +-- Verify compAccrued for select affected users +Assert Equal (Comptroller CompAccrued AffectedUser1) (70026235599882059838229769) +Assert Equal (Comptroller CompAccrued AffectedUser2) (99436286923591330401865) +Assert Equal (Comptroller CompAccrued AffectedUser3) (0343336911491348169) +Assert Equal (Comptroller CompAccrued AffectedUser4) (0) +Assert Equal (Comptroller CompAccrued AffectedUser54) (4989881308103) +Assert Equal (Comptroller CompAccrued AffectedUser74) (934955697489397386) + +-- Deploy latest Comptroller +ComptrollerImpl Deploy Standard NewComptroller + +-- Delegate and propose - proposal 65 +From CompHolder (Comp Delegate CompHolder) +From CompHolder (GovernorBravo GovernorBravo Propose "Upgrade Comptroller" [(Address Unitroller) (Address NewComptroller) (Address Unitroller)] [0 0 0] ["_setPendingImplementation(address)" "_become(address)" "fixBadAccruals(address[],uint256[])"] [[(Address NewComptroller)] [(Address Unitroller)] [[0xb3bd459e0598dde1fe84b1d0a1430be175b5d5be 0xc5119db28adde44a8e1453e733381025a2910f7d 0x309d413391e975b553b7b8d19bc11f8a6c2eb889 0x261fe0fc430c4ce4158ebe9258e7f9c646fea448 0xdf6fada48f5963a8977ec2bcd7b264434ce294f6 0x2e4ae4d3bd0af45040b4f17e0bb7e6dc548626b1 0x3af015f6e3ac79d217198f00ef36af099d223e29 0xab5a193a11f779fe105e8edf9815a0b514b013ca 0xf3f5c252e8acd60671f92c7f72cf33661221ef42 0x01b037084eba7e4519dbfc9ba026ae696746e033 0x9657bd100802434797d0fb21c356b0871c24485b 0x712d0f306956a6a4b4f9319ad9b9de48c5345996 0x98d105874052ddef7150afb661190df5f8c3a719 0xf946cdaecf5a15440e500e61a0c1d179a93652ad 0x8e9c0ea7e72531ba2f7014f3b39783ac4a26e34a 0xa7b95d2a2d10028cc4450e453151181cbcac74fc 0x3b3f3ea865293f004e01c35b9e8ba80daabc8a72 0x0246c1e74ee54af89c50bfeffdddbad0f0d63da2 0xe68176a9d8a4323ea3fab649b30e00d0a6a87d15 0xfa24de5410581625ca749d615191bd33e0366a8f 0x75e4c0ffb05c07798e22605b607e2c8717a1e885 0x26a6dc267e276fded7b40251c8fc08b1b40df367 0x621ec0b18317049583ac828461cdb4031ad2a76a 0x8f4138b15a1eb898380d29b677b417dcafd2bbfe 0x34bbc9a46b09283698ba7aa1c273e8b4e9f7bcc3 0x25b651a210f0cd42d1540f885489cae8c9ff0fcc 0xff628b747c4e70825af24e3d59748bac477dcbf6 0x5d6dc617d38655254ea718044d37451e75144357 0x10bf1dcb5ab7860bab1c3320163c6dddf8dcc0e4 0x60a71287353f3ac632f3e75fd1be532850aa5f4d 0x53f79a391c638d03e9ed0823df82e1e72e5f616a 0x90f7fe74192f18e0020eb04de550cb2bdbc7cd4f 0x093599e111a14aaefef98573f26a7aa2cc58ebff 0xa5d223c176daab154a3134369d1c0478c5e6fecf 0x6c9eda0c8ce90ccaf6f88c0fb7511447fb92b3fe 0x7f9d39de53a3036463146e91e921cc9fbfcb2de4 0x8fd2515a5b29e61220ee080d484d1f2ea4c46e6b 0xb35e71b6a5aebb07dfc3aa705968411ebdbc003f 0x107e78d87005a76b1dc787c2e3dd7986bb47568b 0x94aaf5ceb457057ac4d1588257988d487272984f 0x3ddfa8ec3052539b6c9549f12cea2c295cff5296 0xe03ffe4cce71b39ae1a8580aa94aa40ba611c820 0x11690b00fef3091f37dd0f88e36c838cd344547f 0x7d6149ad9a573a6e2ca6ebf7d4897c1b766841b4 0xf6c3c3621f42ec1f1cd1207bb1571d93646ab29a 0xd19b7946621fe75ba15ce23ed90d0af8c962e6d8 0x8de962fdc6521a426389aad89e1c067c8f816004 0x212d3c9ad48926ed3e7ef538caaddb5d10e8eb9e 0xa92766340b0742d4af8c065443640efdfd18a9a3 0x6ddca709e0d29fdd03be35553c77c08f81a3f9e1 0x83b8987b2f48b6b7220ffc6e83fa0f129b9d5149 0x9c84be7ba23a5034c56d0289eefb6c083e96dd94 0xd2e7d58850d058668ee67fad262760e5b05ed2a4 0xb265ac5bc12a97bc359b0ca0870f8b1cec6369e9 0xba2ef5189b762bd4c9e7f0b50fbbab65193935e8 0xe095de809090531d343d046b2fd3abf28419d3d0 0x99265b66461539efd0334901dbb5a2d7f082687a 0x86bbc49a00bde4d64cde650f6ca8cc0f138fd344 0x87279585d52f534a2d2e453518cd7890c5762d19 0x2ecdc1191514b7e1ed44587822dffaf7c670d6ae 0x138f85de34ec8057ec206788a064f842cd64ce9e 0xc63fc0ae83555e2553762edd887433573f77cfc2 0x2b3b15cb2304223d1a8ca28c17258775bd5b0826 0x8c1a4c98c470900567fb9e764243c89cda79400c 0xf8d9ecfb5ddd99a6e0ccabc54a440205cd40e448 0x728e7f512e01e7811037985ddfb15f9bfef517a8 0x6e13be05021e83318fae9f29f2f57cacaccb62a3 0x124e1fafcadc2c017a17b4bbbbfff3867b7dee35 0x0006e4548aed4502ec8c844567840ce6ef1013f5 0x82a726178ab68d446e079901f2ca95f83dde37d4 0x339b00277f32265b5a46599ad30495b0e921eb6f 0xebe5c14f6ac0ce53640cebfe6d213674dc08d440 0x0730fd7d15fa9a40a6c7b2bbb4b8ce9ee6e6d08b 0xde122ae193f46d67c239ae0c7dae644f9931a772] [70024581827215461300286636 99434542520051820798713 91168628321892518528194 65253893519524513427603 37504914534703867310656 29991222921414803034064 29664092163099163866723 22995425435193061317525 18977306140567618322762 16153770461869763337554 14995552017332537907240 11518530074563941561647 9499196713099819935841 7212224879583644596449 7038803948830987770903 4465995783400342603801 3476860522368145404076 2999525712631519714571 2976977462986329769345 1881718446191311189927 1699235799386422007751 1577018231157018115140 1499788428567608763699 1278642977639309919583 1247907251007203364606 998601466881096599093 791579317801755286963 773933487859775608904 762430378814137892973 505305506641181113258 499866820508711159523 491351929276724469475 187011763377256292965 95880194615183341505 35906565779719826718 34940732225857751281 25099485956367649889 19778101924102624863 19505161319578397635 2968804004067920724 432423944715881797 100905201500492779 99856604811161355 49962015092674176 9951593329323840 6757459496349902 5597019815253533 476759772220656 200024507662316 33277774577726 14611468777911 5014905724070 4997677706137 4989881308103 2419923659650 1486146270087 496946680063 349870854800 152196995332 147008249887 104317366337 99993707875 47972588242 44234730265 12031544568 10541282903 8594826060 5000000000 1617031777 1324963912 751720862 293454410 171168761 1549831]]]) +PrintNumber LastGas + +-- Fast forward, vote, queue, execute +MineBlock +AdvanceBlocks 14000 +From CompHolder (GovernorBravo GovernorBravo Proposal LastProposal Vote For) +AdvanceBlocks 20000 +GovernorBravo GovernorBravo Proposal LastProposal Queue +IncreaseTime 604910 +GovernorBravo GovernorBravo Proposal LastProposal Execute +PrintNumber LastGas +MineBlock + +-- Merge ABIs so that we can call the newly compReceivable without an error +ComptrollerImpl NewComptroller MergeABI + +-- Inflection points to test: +-- compOverAccrued < compAccrued -- AffectedUser1, AffectedUser2, AffectedUser74 +-- compOverAccrued > compAccrued -- AffectedUser3, AffectedUser4 +-- compAccrued == 0 -- AffectedUser4 +-- compAccrued == compOverAccrued -- AffectedUser54 +-- first affected user -- AffectedUser1 +-- last affected user -- AffectedUser74 + +Assert Equal (Comptroller CompAccrued AffectedUser1) (1653772666598537943133) -- 70026235599882059838229769 - 70024581827215461300286636 +Assert Equal (Comptroller CompReceivable AffectedUser1) (0) -- compAccrued > compOverAccrued => compReceivable = 0 + +Assert Equal (Comptroller CompAccrued AffectedUser2) (1744403539509603152) -- 99436286923591330401865 - 99434542520051820798713 +Assert Equal (Comptroller CompReceivable AffectedUser2) (0) -- compAccrued > compOverAccrued => compReceivable = 0 + +Assert Equal (Comptroller CompAccrued AffectedUser3) (0) -- compOverAccrued > compAccrued => compAccrued = 0 +Assert Equal (Comptroller CompReceivable AffectedUser3) (91168284984981027180025) -- 91168628321892518528194 - 343336911491348169 + +Assert Equal (Comptroller CompAccrued AffectedUser4) (0) -- compOverAccrued > compAccrued => compAccrued = 0 +Assert Equal (Comptroller CompReceivable AffectedUser4) (65253893519524513427603) -- 65253893519524513427603 - 0 + +Assert Equal (Comptroller CompAccrued AffectedUser54) (0) -- compOverAccrued == compAccrued => compAccrued = 0 +Assert Equal (Comptroller CompReceivable AffectedUser54) (0) -- compOverAccrued == compAccrued => compReceivable = 0 + +Assert Equal (Comptroller CompAccrued AffectedUser74) (934955697487847555) -- 934955697489397386 - 1549831 +Assert Equal (Comptroller CompReceivable AffectedUser74) (0) -- compAccrued > compOverAccrued => compReceivable = 0 + +-- Ensure that claimComp functionality has been restored and works as expected +-- From 70M COMP accrued to 1955 - looks good +Expect Changes (Erc20 Comp TokenBalance AffectedUser1) +1955396565201585496359 -- 1653772666598537943133 + newly accrued COMP +Comptroller ClaimComp AffectedUser1 +Assert Equal (Comptroller CompAccrued AffectedUser1) (0) + +-- Ensure calling fixBadAccruals again reverts +From CompHolder (GovernorBravo GovernorBravo Propose "Call fixBadAccruals for a second time" [(Address Unitroller)] [0] ["fixBadAccruals(address[],uint256[])"] [[[0xb3bd459e0598dde1fe84b1d0a1430be175b5d5be 0xc5119db28adde44a8e1453e733381025a2910f7d 0x309d413391e975b553b7b8d19bc11f8a6c2eb889 0x261fe0fc430c4ce4158ebe9258e7f9c646fea448 0xdf6fada48f5963a8977ec2bcd7b264434ce294f6 0x2e4ae4d3bd0af45040b4f17e0bb7e6dc548626b1 0x3af015f6e3ac79d217198f00ef36af099d223e29 0xab5a193a11f779fe105e8edf9815a0b514b013ca 0xf3f5c252e8acd60671f92c7f72cf33661221ef42 0x01b037084eba7e4519dbfc9ba026ae696746e033 0x9657bd100802434797d0fb21c356b0871c24485b 0x712d0f306956a6a4b4f9319ad9b9de48c5345996 0x98d105874052ddef7150afb661190df5f8c3a719 0xf946cdaecf5a15440e500e61a0c1d179a93652ad 0x8e9c0ea7e72531ba2f7014f3b39783ac4a26e34a 0xa7b95d2a2d10028cc4450e453151181cbcac74fc 0x3b3f3ea865293f004e01c35b9e8ba80daabc8a72 0x0246c1e74ee54af89c50bfeffdddbad0f0d63da2 0xe68176a9d8a4323ea3fab649b30e00d0a6a87d15 0xfa24de5410581625ca749d615191bd33e0366a8f 0x75e4c0ffb05c07798e22605b607e2c8717a1e885 0x26a6dc267e276fded7b40251c8fc08b1b40df367 0x621ec0b18317049583ac828461cdb4031ad2a76a 0x8f4138b15a1eb898380d29b677b417dcafd2bbfe 0x34bbc9a46b09283698ba7aa1c273e8b4e9f7bcc3 0x25b651a210f0cd42d1540f885489cae8c9ff0fcc 0xff628b747c4e70825af24e3d59748bac477dcbf6 0x5d6dc617d38655254ea718044d37451e75144357 0x10bf1dcb5ab7860bab1c3320163c6dddf8dcc0e4 0x60a71287353f3ac632f3e75fd1be532850aa5f4d 0x53f79a391c638d03e9ed0823df82e1e72e5f616a 0x90f7fe74192f18e0020eb04de550cb2bdbc7cd4f 0x093599e111a14aaefef98573f26a7aa2cc58ebff 0xa5d223c176daab154a3134369d1c0478c5e6fecf 0x6c9eda0c8ce90ccaf6f88c0fb7511447fb92b3fe 0x7f9d39de53a3036463146e91e921cc9fbfcb2de4 0x8fd2515a5b29e61220ee080d484d1f2ea4c46e6b 0xb35e71b6a5aebb07dfc3aa705968411ebdbc003f 0x107e78d87005a76b1dc787c2e3dd7986bb47568b 0x94aaf5ceb457057ac4d1588257988d487272984f 0x3ddfa8ec3052539b6c9549f12cea2c295cff5296 0xe03ffe4cce71b39ae1a8580aa94aa40ba611c820 0x11690b00fef3091f37dd0f88e36c838cd344547f 0x7d6149ad9a573a6e2ca6ebf7d4897c1b766841b4 0xf6c3c3621f42ec1f1cd1207bb1571d93646ab29a 0xd19b7946621fe75ba15ce23ed90d0af8c962e6d8 0x8de962fdc6521a426389aad89e1c067c8f816004 0x212d3c9ad48926ed3e7ef538caaddb5d10e8eb9e 0xa92766340b0742d4af8c065443640efdfd18a9a3 0x6ddca709e0d29fdd03be35553c77c08f81a3f9e1 0x83b8987b2f48b6b7220ffc6e83fa0f129b9d5149 0x9c84be7ba23a5034c56d0289eefb6c083e96dd94 0xd2e7d58850d058668ee67fad262760e5b05ed2a4 0xb265ac5bc12a97bc359b0ca0870f8b1cec6369e9 0xba2ef5189b762bd4c9e7f0b50fbbab65193935e8 0xe095de809090531d343d046b2fd3abf28419d3d0 0x99265b66461539efd0334901dbb5a2d7f082687a 0x86bbc49a00bde4d64cde650f6ca8cc0f138fd344 0x87279585d52f534a2d2e453518cd7890c5762d19 0x2ecdc1191514b7e1ed44587822dffaf7c670d6ae 0x138f85de34ec8057ec206788a064f842cd64ce9e 0xc63fc0ae83555e2553762edd887433573f77cfc2 0x2b3b15cb2304223d1a8ca28c17258775bd5b0826 0x8c1a4c98c470900567fb9e764243c89cda79400c 0xf8d9ecfb5ddd99a6e0ccabc54a440205cd40e448 0x728e7f512e01e7811037985ddfb15f9bfef517a8 0x6e13be05021e83318fae9f29f2f57cacaccb62a3 0x124e1fafcadc2c017a17b4bbbbfff3867b7dee35 0x0006e4548aed4502ec8c844567840ce6ef1013f5 0x82a726178ab68d446e079901f2ca95f83dde37d4 0x339b00277f32265b5a46599ad30495b0e921eb6f 0xebe5c14f6ac0ce53640cebfe6d213674dc08d440 0x0730fd7d15fa9a40a6c7b2bbb4b8ce9ee6e6d08b 0xde122ae193f46d67c239ae0c7dae644f9931a772] [70024581827215461300286636 99434542520051820798713 91168628321892518528194 65253893519524513427603 37504914534703867310656 29991222921414803034064 29664092163099163866723 22995425435193061317525 18977306140567618322762 16153770461869763337554 14995552017332537907240 11518530074563941561647 9499196713099819935841 7212224879583644596449 7038803948830987770903 4465995783400342603801 3476860522368145404076 2999525712631519714571 2976977462986329769345 1881718446191311189927 1699235799386422007751 1577018231157018115140 1499788428567608763699 1278642977639309919583 1247907251007203364606 998601466881096599093 791579317801755286963 773933487859775608904 762430378814137892973 505305506641181113258 499866820508711159523 491351929276724469475 187011763377256292965 95880194615183341505 35906565779719826718 34940732225857751281 25099485956367649889 19778101924102624863 19505161319578397635 2968804004067920724 432423944715881797 100905201500492779 99856604811161355 49962015092674176 9951593329323840 6757459496349902 5597019815253533 476759772220656 200024507662316 33277774577726 14611468777911 5014905724070 4997677706137 4989881308103 2419923659650 1486146270087 496946680063 349870854800 152196995332 147008249887 104317366337 99993707875 47972588242 44234730265 12031544568 10541282903 8594826060 5000000000 1617031777 1324963912 751720862 293454410 171168761 1549831]]]) +MineBlock +AdvanceBlocks 14000 +From CompHolder (GovernorBravo GovernorBravo Proposal LastProposal Vote For) +AdvanceBlocks 20000 +GovernorBravo GovernorBravo Proposal LastProposal Queue +IncreaseTime 604910 +AllowFailures +GovernorBravo GovernorBravo Proposal LastProposal Execute +Assert Revert +Successfully + +Print "Done" \ No newline at end of file diff --git a/spec/sim/0065-correct-bad-comp-accruals/mainnet_upgrade.scen b/spec/sim/0065-correct-bad-comp-accruals/mainnet_upgrade.scen new file mode 100755 index 000000000..65908f3eb --- /dev/null +++ b/spec/sim/0065-correct-bad-comp-accruals/mainnet_upgrade.scen @@ -0,0 +1,89 @@ +#!/usr/bin/env -S yarn repl -s + +PrintTransactionLogs + +-- Token holder addresses for mocking +Alias CompHolder "0x7587caefc8096f5f40acb83a09df031a018c66ec" + +Alias AffectedUser1 "0xb3bd459e0598dde1fe84b1d0a1430be175b5d5be" +Alias AffectedUser2 "0xc5119db28adde44a8e1453e733381025a2910f7d" +Alias AffectedUser3 "0x309d413391e975b553b7b8d19bc11f8a6c2eb889" +Alias AffectedUser4 "0x261fe0fc430c4ce4158ebe9258e7f9c646fea448" +Alias AffectedUser54 "0xb265ac5bc12a97bc359b0ca0870f8b1cec6369e9" +Alias AffectedUser74 "0xde122ae193f46d67c239ae0c7dae644f9931a772" -- The last affected user + +Web3Fork "https://mainnet-eth.compound.finance/@13400300" (CompHolder) +UseConfigs mainnet + +-- Deploy latest Comptroller (needed for ABI merge) +ComptrollerImpl Deploy Standard NewComptroller + +-- Merge ABIs so that we can call the newly compReceivable without an error +ComptrollerImpl NewComptroller MergeABI + +-- Verify compAccrued for select affected users +Assert Equal (Comptroller CompAccrued AffectedUser1) (70026235599882059838229769) +Assert Equal (Comptroller CompAccrued AffectedUser2) (99436286923591330401865) +Assert Equal (Comptroller CompAccrued AffectedUser3) (0343336911491348169) +Assert Equal (Comptroller CompAccrued AffectedUser4) (0) +Assert Equal (Comptroller CompAccrued AffectedUser54) (4989881308103) +Assert Equal (Comptroller CompAccrued AffectedUser74) (934955697489397386) + +-- Delegate and execute proposal 65 +From CompHolder (Comp Delegate CompHolder) +MineBlock +AdvanceBlocks 14000 +From CompHolder (GovernorBravo GovernorBravo Proposal LastProposal Vote For) +AdvanceBlocks 20000 +GovernorBravo GovernorBravo Proposal LastProposal Queue +IncreaseTime 604910 +GovernorBravo GovernorBravo Proposal LastProposal Execute +PrintNumber LastGas +MineBlock + +-- Inflection points to test: +-- compOverAccrued < compAccrued -- AffectedUser1, AffectedUser2, AffectedUser74 +-- compOverAccrued > compAccrued -- AffectedUser3, AffectedUser4 +-- compAccrued == 0 -- AffectedUser4 +-- compAccrued == compOverAccrued -- AffectedUser54 +-- first affected user -- AffectedUser1 +-- last affected user -- AffectedUser74 + +Assert Equal (Comptroller CompAccrued AffectedUser1) (1653772666598537943133) -- 70026235599882059838229769 - 70024581827215461300286636 +Assert Equal (Comptroller CompReceivable AffectedUser1) (0) -- compAccrued > compOverAccrued => compReceivable = 0 + +Assert Equal (Comptroller CompAccrued AffectedUser2) (1744403539509603152) -- 99436286923591330401865 - 99434542520051820798713 +Assert Equal (Comptroller CompReceivable AffectedUser2) (0) -- compAccrued > compOverAccrued => compReceivable = 0 + +Assert Equal (Comptroller CompAccrued AffectedUser3) (0) -- compOverAccrued > compAccrued => compAccrued = 0 +Assert Equal (Comptroller CompReceivable AffectedUser3) (91168284984981027180025) -- 91168628321892518528194 - 343336911491348169 + +Assert Equal (Comptroller CompAccrued AffectedUser4) (0) -- compOverAccrued > compAccrued => compAccrued = 0 +Assert Equal (Comptroller CompReceivable AffectedUser4) (65253893519524513427603) -- 65253893519524513427603 - 0 + +Assert Equal (Comptroller CompAccrued AffectedUser54) (0) -- compOverAccrued == compAccrued => compAccrued = 0 +Assert Equal (Comptroller CompReceivable AffectedUser54) (0) -- compOverAccrued == compAccrued => compReceivable = 0 + +Assert Equal (Comptroller CompAccrued AffectedUser74) (934955697487847555) -- 934955697489397386 - 1549831 +Assert Equal (Comptroller CompReceivable AffectedUser74) (0) -- compAccrued > compOverAccrued => compReceivable = 0 + +-- Ensure that claimComp functionality has been restored and works as expected +-- From 70M COMP accrued to 2055 - looks good +Expect Changes (Erc20 Comp TokenBalance AffectedUser1) +2055078988438040858099 -- 1653772666598537943133 + newly accrued COMP +Comptroller ClaimComp AffectedUser1 +Assert Equal (Comptroller CompAccrued AffectedUser1) (0) + +-- Ensure calling fixBadAccruals again reverts +From CompHolder (GovernorBravo GovernorBravo Propose "Call fixBadAccruals for a second time" [(Address Unitroller)] [0] ["fixBadAccruals(address[],uint256[])"] [[[0xb3bd459e0598dde1fe84b1d0a1430be175b5d5be 0xc5119db28adde44a8e1453e733381025a2910f7d 0x309d413391e975b553b7b8d19bc11f8a6c2eb889 0x261fe0fc430c4ce4158ebe9258e7f9c646fea448 0xdf6fada48f5963a8977ec2bcd7b264434ce294f6 0x2e4ae4d3bd0af45040b4f17e0bb7e6dc548626b1 0x3af015f6e3ac79d217198f00ef36af099d223e29 0xab5a193a11f779fe105e8edf9815a0b514b013ca 0xf3f5c252e8acd60671f92c7f72cf33661221ef42 0x01b037084eba7e4519dbfc9ba026ae696746e033 0x9657bd100802434797d0fb21c356b0871c24485b 0x712d0f306956a6a4b4f9319ad9b9de48c5345996 0x98d105874052ddef7150afb661190df5f8c3a719 0xf946cdaecf5a15440e500e61a0c1d179a93652ad 0x8e9c0ea7e72531ba2f7014f3b39783ac4a26e34a 0xa7b95d2a2d10028cc4450e453151181cbcac74fc 0x3b3f3ea865293f004e01c35b9e8ba80daabc8a72 0x0246c1e74ee54af89c50bfeffdddbad0f0d63da2 0xe68176a9d8a4323ea3fab649b30e00d0a6a87d15 0xfa24de5410581625ca749d615191bd33e0366a8f 0x75e4c0ffb05c07798e22605b607e2c8717a1e885 0x26a6dc267e276fded7b40251c8fc08b1b40df367 0x621ec0b18317049583ac828461cdb4031ad2a76a 0x8f4138b15a1eb898380d29b677b417dcafd2bbfe 0x34bbc9a46b09283698ba7aa1c273e8b4e9f7bcc3 0x25b651a210f0cd42d1540f885489cae8c9ff0fcc 0xff628b747c4e70825af24e3d59748bac477dcbf6 0x5d6dc617d38655254ea718044d37451e75144357 0x10bf1dcb5ab7860bab1c3320163c6dddf8dcc0e4 0x60a71287353f3ac632f3e75fd1be532850aa5f4d 0x53f79a391c638d03e9ed0823df82e1e72e5f616a 0x90f7fe74192f18e0020eb04de550cb2bdbc7cd4f 0x093599e111a14aaefef98573f26a7aa2cc58ebff 0xa5d223c176daab154a3134369d1c0478c5e6fecf 0x6c9eda0c8ce90ccaf6f88c0fb7511447fb92b3fe 0x7f9d39de53a3036463146e91e921cc9fbfcb2de4 0x8fd2515a5b29e61220ee080d484d1f2ea4c46e6b 0xb35e71b6a5aebb07dfc3aa705968411ebdbc003f 0x107e78d87005a76b1dc787c2e3dd7986bb47568b 0x94aaf5ceb457057ac4d1588257988d487272984f 0x3ddfa8ec3052539b6c9549f12cea2c295cff5296 0xe03ffe4cce71b39ae1a8580aa94aa40ba611c820 0x11690b00fef3091f37dd0f88e36c838cd344547f 0x7d6149ad9a573a6e2ca6ebf7d4897c1b766841b4 0xf6c3c3621f42ec1f1cd1207bb1571d93646ab29a 0xd19b7946621fe75ba15ce23ed90d0af8c962e6d8 0x8de962fdc6521a426389aad89e1c067c8f816004 0x212d3c9ad48926ed3e7ef538caaddb5d10e8eb9e 0xa92766340b0742d4af8c065443640efdfd18a9a3 0x6ddca709e0d29fdd03be35553c77c08f81a3f9e1 0x83b8987b2f48b6b7220ffc6e83fa0f129b9d5149 0x9c84be7ba23a5034c56d0289eefb6c083e96dd94 0xd2e7d58850d058668ee67fad262760e5b05ed2a4 0xb265ac5bc12a97bc359b0ca0870f8b1cec6369e9 0xba2ef5189b762bd4c9e7f0b50fbbab65193935e8 0xe095de809090531d343d046b2fd3abf28419d3d0 0x99265b66461539efd0334901dbb5a2d7f082687a 0x86bbc49a00bde4d64cde650f6ca8cc0f138fd344 0x87279585d52f534a2d2e453518cd7890c5762d19 0x2ecdc1191514b7e1ed44587822dffaf7c670d6ae 0x138f85de34ec8057ec206788a064f842cd64ce9e 0xc63fc0ae83555e2553762edd887433573f77cfc2 0x2b3b15cb2304223d1a8ca28c17258775bd5b0826 0x8c1a4c98c470900567fb9e764243c89cda79400c 0xf8d9ecfb5ddd99a6e0ccabc54a440205cd40e448 0x728e7f512e01e7811037985ddfb15f9bfef517a8 0x6e13be05021e83318fae9f29f2f57cacaccb62a3 0x124e1fafcadc2c017a17b4bbbbfff3867b7dee35 0x0006e4548aed4502ec8c844567840ce6ef1013f5 0x82a726178ab68d446e079901f2ca95f83dde37d4 0x339b00277f32265b5a46599ad30495b0e921eb6f 0xebe5c14f6ac0ce53640cebfe6d213674dc08d440 0x0730fd7d15fa9a40a6c7b2bbb4b8ce9ee6e6d08b 0xde122ae193f46d67c239ae0c7dae644f9931a772] [70024581827215461300286636 99434542520051820798713 91168628321892518528194 65253893519524513427603 37504914534703867310656 29991222921414803034064 29664092163099163866723 22995425435193061317525 18977306140567618322762 16153770461869763337554 14995552017332537907240 11518530074563941561647 9499196713099819935841 7212224879583644596449 7038803948830987770903 4465995783400342603801 3476860522368145404076 2999525712631519714571 2976977462986329769345 1881718446191311189927 1699235799386422007751 1577018231157018115140 1499788428567608763699 1278642977639309919583 1247907251007203364606 998601466881096599093 791579317801755286963 773933487859775608904 762430378814137892973 505305506641181113258 499866820508711159523 491351929276724469475 187011763377256292965 95880194615183341505 35906565779719826718 34940732225857751281 25099485956367649889 19778101924102624863 19505161319578397635 2968804004067920724 432423944715881797 100905201500492779 99856604811161355 49962015092674176 9951593329323840 6757459496349902 5597019815253533 476759772220656 200024507662316 33277774577726 14611468777911 5014905724070 4997677706137 4989881308103 2419923659650 1486146270087 496946680063 349870854800 152196995332 147008249887 104317366337 99993707875 47972588242 44234730265 12031544568 10541282903 8594826060 5000000000 1617031777 1324963912 751720862 293454410 171168761 1549831]]]) +MineBlock +AdvanceBlocks 14000 +From CompHolder (GovernorBravo GovernorBravo Proposal LastProposal Vote For) +AdvanceBlocks 20000 +GovernorBravo GovernorBravo Proposal LastProposal Queue +IncreaseTime 604910 +AllowFailures +GovernorBravo GovernorBravo Proposal LastProposal Execute +Assert Revert +Successfully + +Print "Done" \ No newline at end of file