From ff17af5e9d1a44158a9ecf2228674db5d1b7f44b Mon Sep 17 00:00:00 2001 From: Mojtaba Eshghie Date: Wed, 4 Sep 2024 19:52:17 +0200 Subject: [PATCH] #5 Batch 49 --- .../mutants/BackedToken/1/BLR/BackedToken.sol | 32 + .../mutants/BackedToken/1/BOR/BackedToken.sol | 32 + .../mutants/BackedToken/1/CCD/BackedToken.sol | 29 + .../mutants/BackedToken/1/EHC/BackedToken.sol | 32 + .../mutants/BackedToken/1/FVR/BackedToken.sol | 32 + .../mutants/BackedToken/1/ILR/BackedToken.sol | 32 + .../mutants/BackedToken/1/MOC/BackedToken.sol | 32 + .../mutants/BackedToken/1/MOD/BackedToken.sol | 32 + .../mutants/BackedToken/1/MOI/BackedToken.sol | 32 + .../mutants/BackedToken/1/MOR/BackedToken.sol | 32 + .../mutants/BackedToken/1/SKD/BackedToken.sol | 32 + .../mutants/BackedToken/1/SLR/BackedToken.sol | 32 + .../mutants/BackedToken/1/TOR/BackedToken.sol | 32 + .../mutants/BackedToken/1/VVR/BackedToken.sol | 32 + .../mutants/BackedToken/2/BOR/BackedToken.sol | 32 + .../mutants/BackedToken/2/FVR/BackedToken.sol | 32 + .../mutants/BackedToken/2/ILR/BackedToken.sol | 32 + .../mutants/BackedToken/2/SLR/BackedToken.sol | 32 + .../mutants/BackedToken/2/TOR/BackedToken.sol | 32 + .../mutants/BackedToken/2/VVR/BackedToken.sol | 32 + .../mutants/BackedToken/3/BOR/BackedToken.sol | 32 + .../mutants/BackedToken/3/FVR/BackedToken.sol | 32 + .../mutants/BackedToken/3/ILR/BackedToken.sol | 32 + .../mutants/BackedToken/4/BOR/BackedToken.sol | 32 + .../mutants/BackedToken/4/ILR/BackedToken.sol | 32 + .../BackedToken/original/BackedToken.sol | 32 + .../mutants/BadBeacon/1/EHC/BadBeacon.sol | 11 + .../BadBeacon/1/EHC/diff_result_difft.json | 50 ++ .../mutants/BadBeacon/original/BadBeacon.sol | 11 + .../BadBeaconTwo/1/BOR/BadBeaconTwo.sol | 19 + .../BadBeaconTwo/1/CSC/BadBeaconTwo.sol | 19 + .../BadBeaconTwo/1/EHC/BadBeaconTwo.sol | 19 + .../BadBeaconTwo/1/ILR/BadBeaconTwo.sol | 19 + .../BadBeaconTwo/2/ILR/BadBeaconTwo.sol | 19 + .../BadBeaconTwo/original/BadBeaconTwo.sol | 19 + .../1/FVR/BadBeaconUpgradeable.sol | 36 ++ .../1/FVR/diff_result_difft.json | 32 + .../1/ILR/BadBeaconUpgradeable.sol | 36 ++ .../1/ILR/diff_result_difft.json | 32 + .../1/MOD/BadBeaconUpgradeable.sol | 36 ++ .../1/MOD/diff_result_difft.json | 25 + .../1/RSD/BadBeaconUpgradeable.sol | 36 ++ .../1/RSD/diff_result_difft.json | 56 ++ .../1/VVR/BadBeaconUpgradeable.sol | 36 ++ .../1/VVR/diff_result_difft.json | 32 + .../2/FVR/BadBeaconUpgradeable.sol | 36 ++ .../2/FVR/diff_result_difft.json | 56 ++ .../2/ILR/BadBeaconUpgradeable.sol | 36 ++ .../2/ILR/diff_result_difft.json | 58 ++ .../2/MOD/BadBeaconUpgradeable.sol | 36 ++ .../2/MOD/diff_result_difft.json | 42 ++ .../2/VVR/BadBeaconUpgradeable.sol | 36 ++ .../2/VVR/diff_result_difft.json | 58 ++ .../3/FVR/BadBeaconUpgradeable.sol | 36 ++ .../3/FVR/diff_result_difft.json | 82 +++ .../3/MOD/BadBeaconUpgradeable.sol | 36 ++ .../3/MOD/diff_result_difft.json | 61 ++ .../4/FVR/BadBeaconUpgradeable.sol | 36 ++ .../4/FVR/diff_result_difft.json | 106 ++++ .../4/MOD/BadBeaconUpgradeable.sol | 36 ++ .../4/MOD/diff_result_difft.json | 78 +++ .../5/FVR/BadBeaconUpgradeable.sol | 36 ++ .../5/FVR/diff_result_difft.json | 130 ++++ .../original/BadBeaconUpgradeable.sol | 36 ++ contracts/mutants/BadToken/1/CCD/BadToken.sol | 13 + .../BadToken/1/CCD/diff_result_difft.json | 355 +++++++++++ contracts/mutants/BadToken/1/FVR/BadToken.sol | 26 + .../BadToken/1/FVR/diff_result_difft.json | 32 + contracts/mutants/BadToken/1/ILR/BadToken.sol | 26 + .../BadToken/1/ILR/diff_result_difft.json | 32 + contracts/mutants/BadToken/1/RSD/BadToken.sol | 26 + .../BadToken/1/RSD/diff_result_difft.json | 38 ++ contracts/mutants/BadToken/2/FVR/BadToken.sol | 26 + .../BadToken/2/FVR/diff_result_difft.json | 58 ++ .../mutants/BadToken/original/BadToken.sol | 26 + .../BadTokenMock/1/BLR/BadTokenMock.sol | 39 ++ .../BadTokenMock/1/BLR/diff_result_difft.json | 32 + .../BadTokenMock/1/BOR/BadTokenMock.sol | 39 ++ .../BadTokenMock/1/BOR/diff_result_difft.json | 32 + .../BadTokenMock/1/CCD/BadTokenMock.sol | 29 + .../BadTokenMock/1/CCD/diff_result_difft.json | 275 ++++++++ .../BadTokenMock/1/DLR/BadTokenMock.sol | 39 ++ .../BadTokenMock/1/DLR/diff_result_difft.json | 32 + .../BadTokenMock/1/EED/BadTokenMock.sol | 39 ++ .../BadTokenMock/1/EED/diff_result_difft.json | 92 +++ .../BadTokenMock/1/EHC/BadTokenMock.sol | 39 ++ .../BadTokenMock/1/EHC/diff_result_difft.json | 80 +++ .../BadTokenMock/1/FVR/BadTokenMock.sol | 39 ++ .../BadTokenMock/1/FVR/diff_result_difft.json | 32 + .../BadTokenMock/1/ILR/BadTokenMock.sol | 39 ++ .../BadTokenMock/1/ILR/diff_result_difft.json | 32 + .../BadTokenMock/1/RSD/BadTokenMock.sol | 39 ++ .../BadTokenMock/1/RSD/diff_result_difft.json | 38 ++ .../BadTokenMock/1/TOR/BadTokenMock.sol | 39 ++ .../BadTokenMock/1/TOR/diff_result_difft.json | 44 ++ .../BadTokenMock/1/VVR/BadTokenMock.sol | 39 ++ .../BadTokenMock/1/VVR/diff_result_difft.json | 0 .../BadTokenMock/2/BOR/BadTokenMock.sol | 39 ++ .../BadTokenMock/2/BOR/diff_result_difft.json | 56 ++ .../BadTokenMock/2/DLR/BadTokenMock.sol | 39 ++ .../BadTokenMock/2/DLR/diff_result_difft.json | 56 ++ .../BadTokenMock/2/EHC/BadTokenMock.sol | 39 ++ .../BadTokenMock/2/EHC/diff_result_difft.json | 164 +++++ .../BadTokenMock/2/FVR/BadTokenMock.sol | 39 ++ .../BadTokenMock/2/FVR/diff_result_difft.json | 58 ++ .../BadTokenMock/2/ILR/BadTokenMock.sol | 39 ++ .../BadTokenMock/2/ILR/diff_result_difft.json | 58 ++ .../BadTokenMock/2/TOR/BadTokenMock.sol | 39 ++ .../BadTokenMock/2/TOR/diff_result_difft.json | 80 +++ .../BadTokenMock/2/VVR/BadTokenMock.sol | 39 ++ .../BadTokenMock/2/VVR/diff_result_difft.json | 56 ++ .../BadTokenMock/3/VVR/BadTokenMock.sol | 39 ++ .../BadTokenMock/3/VVR/diff_result_difft.json | 80 +++ .../BadTokenMock/original/BadTokenMock.sol | 39 ++ .../1/AOR/BalanceAccounting.sol | 31 + .../1/AVR/BalanceAccounting.sol | 31 + .../1/FVR/BalanceAccounting.sol | 31 + .../1/ICM/BalanceAccounting.sol | 31 + .../1/LSC/BalanceAccounting.sol | 31 + .../1/RSD/BalanceAccounting.sol | 31 + .../1/VVR/BalanceAccounting.sol | 31 + .../2/AOR/BalanceAccounting.sol | 31 + .../2/AVR/BalanceAccounting.sol | 31 + .../2/FVR/BalanceAccounting.sol | 31 + .../2/ICM/BalanceAccounting.sol | 31 + .../2/LSC/BalanceAccounting.sol | 31 + .../2/RSD/BalanceAccounting.sol | 31 + .../3/AOR/BalanceAccounting.sol | 31 + .../3/AVR/BalanceAccounting.sol | 31 + .../4/AOR/BalanceAccounting.sol | 31 + .../4/AVR/BalanceAccounting.sol | 31 + .../original/BalanceAccounting.sol | 31 + .../1/BOR/BalanceAllocation.sol | 275 ++++++++ .../1/DLR/BalanceAllocation.sol | 275 ++++++++ .../1/ECS/BalanceAllocation.sol | 275 ++++++++ .../1/EHC/BalanceAllocation.sol | 275 ++++++++ .../1/FVR/BalanceAllocation.sol | 275 ++++++++ .../1/GVR/BalanceAllocation.sol | 275 ++++++++ .../1/ILR/BalanceAllocation.sol | 275 ++++++++ .../1/LSC/BalanceAllocation.sol | 275 ++++++++ .../1/RSD/BalanceAllocation.sol | 275 ++++++++ .../1/UORD/BalanceAllocation.sol | 275 ++++++++ .../10/BOR/BalanceAllocation.sol | 275 ++++++++ .../10/FVR/BalanceAllocation.sol | 275 ++++++++ .../10/ILR/BalanceAllocation.sol | 275 ++++++++ .../10/RSD/BalanceAllocation.sol | 275 ++++++++ .../2/BOR/BalanceAllocation.sol | 275 ++++++++ .../2/DLR/BalanceAllocation.sol | 275 ++++++++ .../2/ECS/BalanceAllocation.sol | 275 ++++++++ .../2/FVR/BalanceAllocation.sol | 275 ++++++++ .../2/GVR/BalanceAllocation.sol | 275 ++++++++ .../2/ILR/BalanceAllocation.sol | 275 ++++++++ .../2/LSC/BalanceAllocation.sol | 275 ++++++++ .../2/RSD/BalanceAllocation.sol | 275 ++++++++ .../2/UORD/BalanceAllocation.sol | 275 ++++++++ .../3/BOR/BalanceAllocation.sol | 275 ++++++++ .../3/DLR/BalanceAllocation.sol | 275 ++++++++ .../3/ECS/BalanceAllocation.sol | 275 ++++++++ .../3/FVR/BalanceAllocation.sol | 275 ++++++++ .../3/GVR/BalanceAllocation.sol | 275 ++++++++ .../3/ILR/BalanceAllocation.sol | 275 ++++++++ .../3/RSD/BalanceAllocation.sol | 275 ++++++++ .../3/UORD/BalanceAllocation.sol | 275 ++++++++ .../4/BOR/BalanceAllocation.sol | 275 ++++++++ .../4/DLR/BalanceAllocation.sol | 275 ++++++++ .../4/ECS/BalanceAllocation.sol | 275 ++++++++ .../4/FVR/BalanceAllocation.sol | 275 ++++++++ .../4/ILR/BalanceAllocation.sol | 275 ++++++++ .../4/RSD/BalanceAllocation.sol | 275 ++++++++ .../5/BOR/BalanceAllocation.sol | 275 ++++++++ .../5/ECS/BalanceAllocation.sol | 275 ++++++++ .../5/FVR/BalanceAllocation.sol | 275 ++++++++ .../5/ILR/BalanceAllocation.sol | 275 ++++++++ .../5/RSD/BalanceAllocation.sol | 275 ++++++++ .../6/BOR/BalanceAllocation.sol | 275 ++++++++ .../6/ECS/BalanceAllocation.sol | 275 ++++++++ .../6/FVR/BalanceAllocation.sol | 275 ++++++++ .../6/ILR/BalanceAllocation.sol | 275 ++++++++ .../6/RSD/BalanceAllocation.sol | 275 ++++++++ .../7/BOR/BalanceAllocation.sol | 275 ++++++++ .../7/ECS/BalanceAllocation.sol | 275 ++++++++ .../7/FVR/BalanceAllocation.sol | 275 ++++++++ .../7/ILR/BalanceAllocation.sol | 275 ++++++++ .../7/RSD/BalanceAllocation.sol | 275 ++++++++ .../8/BOR/BalanceAllocation.sol | 275 ++++++++ .../8/FVR/BalanceAllocation.sol | 275 ++++++++ .../8/ILR/BalanceAllocation.sol | 275 ++++++++ .../8/RSD/BalanceAllocation.sol | 275 ++++++++ .../9/BOR/BalanceAllocation.sol | 275 ++++++++ .../9/FVR/BalanceAllocation.sol | 275 ++++++++ .../9/ILR/BalanceAllocation.sol | 275 ++++++++ .../9/RSD/BalanceAllocation.sol | 275 ++++++++ .../original/BalanceAllocation.sol | 275 ++++++++ .../1/DLR/BalanceAllocationMock.sol | 89 +++ .../1/DLR/diff_result_difft.json | 32 + .../1/FVR/BalanceAllocationMock.sol | 89 +++ .../1/FVR/diff_result_difft.json | 32 + .../1/RSD/BalanceAllocationMock.sol | 89 +++ .../1/RSD/diff_result_difft.json | 62 ++ .../10/FVR/BalanceAllocationMock.sol | 89 +++ .../10/FVR/diff_result_difft.json | 248 ++++++++ .../10/RSD/BalanceAllocationMock.sol | 89 +++ .../10/RSD/diff_result_difft.json | 596 ++++++++++++++++++ .../2/DLR/BalanceAllocationMock.sol | 89 +++ .../2/DLR/diff_result_difft.json | 44 ++ .../2/FVR/BalanceAllocationMock.sol | 89 +++ .../2/FVR/diff_result_difft.json | 56 ++ .../2/RSD/BalanceAllocationMock.sol | 89 +++ .../2/RSD/diff_result_difft.json | 122 ++++ .../3/FVR/BalanceAllocationMock.sol | 89 +++ .../3/FVR/diff_result_difft.json | 80 +++ .../3/RSD/BalanceAllocationMock.sol | 89 +++ .../3/RSD/diff_result_difft.json | 176 ++++++ .../4/FVR/BalanceAllocationMock.sol | 89 +++ .../4/FVR/diff_result_difft.json | 104 +++ .../4/RSD/BalanceAllocationMock.sol | 89 +++ .../4/RSD/diff_result_difft.json | 230 +++++++ .../5/FVR/BalanceAllocationMock.sol | 89 +++ .../5/FVR/diff_result_difft.json | 128 ++++ .../5/RSD/BalanceAllocationMock.sol | 89 +++ .../5/RSD/diff_result_difft.json | 284 +++++++++ .../6/FVR/BalanceAllocationMock.sol | 89 +++ .../6/FVR/diff_result_difft.json | 152 +++++ .../6/RSD/BalanceAllocationMock.sol | 89 +++ .../6/RSD/diff_result_difft.json | 338 ++++++++++ .../7/FVR/BalanceAllocationMock.sol | 89 +++ .../7/FVR/diff_result_difft.json | 176 ++++++ .../7/RSD/BalanceAllocationMock.sol | 89 +++ .../7/RSD/diff_result_difft.json | 392 ++++++++++++ .../8/FVR/BalanceAllocationMock.sol | 89 +++ .../8/FVR/diff_result_difft.json | 200 ++++++ .../8/RSD/BalanceAllocationMock.sol | 89 +++ .../8/RSD/diff_result_difft.json | 476 ++++++++++++++ .../9/FVR/BalanceAllocationMock.sol | 89 +++ .../9/FVR/diff_result_difft.json | 224 +++++++ .../9/RSD/BalanceAllocationMock.sol | 89 +++ .../9/RSD/diff_result_difft.json | 536 ++++++++++++++++ .../original/BalanceAllocationMock.sol | 89 +++ .../mutants/BalanceDrip/1/BOR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/1/CSC/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/1/DLR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/1/ECS/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/1/FVR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/1/ILR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/1/RSD/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/1/SFR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/2/BOR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/2/CSC/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/2/DLR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/2/ECS/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/2/FVR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/2/ILR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/2/RSD/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/2/SFR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/3/BOR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/3/CSC/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/3/DLR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/3/ECS/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/3/FVR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/3/ILR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/3/RSD/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/3/SFR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/4/BOR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/4/CSC/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/4/DLR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/4/ECS/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/4/FVR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/4/ILR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/4/RSD/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/4/SFR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/5/BOR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/5/DLR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/5/ILR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/5/SFR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/6/BOR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/6/ILR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/7/BOR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/7/ILR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/8/BOR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/8/ILR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/9/BOR/BalanceDrip.sol | 115 ++++ .../mutants/BalanceDrip/9/ILR/BalanceDrip.sol | 115 ++++ .../BalanceDrip/original/BalanceDrip.sol | 115 ++++ 283 files changed, 34371 insertions(+) create mode 100644 contracts/mutants/BackedToken/1/BLR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/BOR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/CCD/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/EHC/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/FVR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/ILR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/MOC/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/MOD/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/MOI/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/MOR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/SKD/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/SLR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/TOR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/1/VVR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/2/BOR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/2/FVR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/2/ILR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/2/SLR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/2/TOR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/2/VVR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/3/BOR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/3/FVR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/3/ILR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/4/BOR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/4/ILR/BackedToken.sol create mode 100644 contracts/mutants/BackedToken/original/BackedToken.sol create mode 100644 contracts/mutants/BadBeacon/1/EHC/BadBeacon.sol create mode 100644 contracts/mutants/BadBeacon/1/EHC/diff_result_difft.json create mode 100644 contracts/mutants/BadBeacon/original/BadBeacon.sol create mode 100644 contracts/mutants/BadBeaconTwo/1/BOR/BadBeaconTwo.sol create mode 100644 contracts/mutants/BadBeaconTwo/1/CSC/BadBeaconTwo.sol create mode 100644 contracts/mutants/BadBeaconTwo/1/EHC/BadBeaconTwo.sol create mode 100644 contracts/mutants/BadBeaconTwo/1/ILR/BadBeaconTwo.sol create mode 100644 contracts/mutants/BadBeaconTwo/2/ILR/BadBeaconTwo.sol create mode 100644 contracts/mutants/BadBeaconTwo/original/BadBeaconTwo.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/1/FVR/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/1/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/1/ILR/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/1/ILR/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/1/MOD/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/1/MOD/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/1/RSD/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/1/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/1/VVR/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/1/VVR/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/2/FVR/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/2/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/2/ILR/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/2/ILR/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/2/MOD/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/2/MOD/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/2/VVR/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/2/VVR/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/3/FVR/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/3/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/3/MOD/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/3/MOD/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/4/FVR/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/4/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/4/MOD/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/4/MOD/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/5/FVR/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadBeaconUpgradeable/5/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BadBeaconUpgradeable/original/BadBeaconUpgradeable.sol create mode 100644 contracts/mutants/BadToken/1/CCD/BadToken.sol create mode 100644 contracts/mutants/BadToken/1/CCD/diff_result_difft.json create mode 100644 contracts/mutants/BadToken/1/FVR/BadToken.sol create mode 100644 contracts/mutants/BadToken/1/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BadToken/1/ILR/BadToken.sol create mode 100644 contracts/mutants/BadToken/1/ILR/diff_result_difft.json create mode 100644 contracts/mutants/BadToken/1/RSD/BadToken.sol create mode 100644 contracts/mutants/BadToken/1/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BadToken/2/FVR/BadToken.sol create mode 100644 contracts/mutants/BadToken/2/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BadToken/original/BadToken.sol create mode 100644 contracts/mutants/BadTokenMock/1/BLR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/1/BLR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/1/BOR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/1/BOR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/1/CCD/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/1/CCD/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/1/DLR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/1/DLR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/1/EED/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/1/EED/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/1/EHC/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/1/EHC/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/1/FVR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/1/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/1/ILR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/1/ILR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/1/RSD/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/1/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/1/TOR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/1/TOR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/1/VVR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/1/VVR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/2/BOR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/2/BOR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/2/DLR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/2/DLR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/2/EHC/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/2/EHC/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/2/FVR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/2/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/2/ILR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/2/ILR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/2/TOR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/2/TOR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/2/VVR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/2/VVR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/3/VVR/BadTokenMock.sol create mode 100644 contracts/mutants/BadTokenMock/3/VVR/diff_result_difft.json create mode 100644 contracts/mutants/BadTokenMock/original/BadTokenMock.sol create mode 100644 contracts/mutants/BalanceAccounting/1/AOR/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/1/AVR/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/1/FVR/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/1/ICM/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/1/LSC/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/1/RSD/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/1/VVR/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/2/AOR/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/2/AVR/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/2/FVR/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/2/ICM/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/2/LSC/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/2/RSD/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/3/AOR/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/3/AVR/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/4/AOR/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/4/AVR/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAccounting/original/BalanceAccounting.sol create mode 100644 contracts/mutants/BalanceAllocation/1/BOR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/1/DLR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/1/ECS/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/1/EHC/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/1/FVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/1/GVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/1/ILR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/1/LSC/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/1/RSD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/1/UORD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/10/BOR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/10/FVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/10/ILR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/10/RSD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/2/BOR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/2/DLR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/2/ECS/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/2/FVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/2/GVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/2/ILR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/2/LSC/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/2/RSD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/2/UORD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/3/BOR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/3/DLR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/3/ECS/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/3/FVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/3/GVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/3/ILR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/3/RSD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/3/UORD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/4/BOR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/4/DLR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/4/ECS/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/4/FVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/4/ILR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/4/RSD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/5/BOR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/5/ECS/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/5/FVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/5/ILR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/5/RSD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/6/BOR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/6/ECS/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/6/FVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/6/ILR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/6/RSD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/7/BOR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/7/ECS/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/7/FVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/7/ILR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/7/RSD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/8/BOR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/8/FVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/8/ILR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/8/RSD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/9/BOR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/9/FVR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/9/ILR/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/9/RSD/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocation/original/BalanceAllocation.sol create mode 100644 contracts/mutants/BalanceAllocationMock/1/DLR/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/1/DLR/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/1/FVR/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/1/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/1/RSD/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/1/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/10/FVR/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/10/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/10/RSD/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/10/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/2/DLR/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/2/DLR/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/2/FVR/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/2/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/2/RSD/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/2/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/3/FVR/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/3/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/3/RSD/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/3/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/4/FVR/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/4/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/4/RSD/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/4/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/5/FVR/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/5/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/5/RSD/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/5/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/6/FVR/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/6/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/6/RSD/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/6/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/7/FVR/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/7/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/7/RSD/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/7/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/8/FVR/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/8/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/8/RSD/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/8/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/9/FVR/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/9/FVR/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/9/RSD/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceAllocationMock/9/RSD/diff_result_difft.json create mode 100644 contracts/mutants/BalanceAllocationMock/original/BalanceAllocationMock.sol create mode 100644 contracts/mutants/BalanceDrip/1/BOR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/1/CSC/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/1/DLR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/1/ECS/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/1/FVR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/1/ILR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/1/RSD/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/1/SFR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/2/BOR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/2/CSC/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/2/DLR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/2/ECS/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/2/FVR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/2/ILR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/2/RSD/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/2/SFR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/3/BOR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/3/CSC/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/3/DLR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/3/ECS/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/3/FVR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/3/ILR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/3/RSD/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/3/SFR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/4/BOR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/4/CSC/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/4/DLR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/4/ECS/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/4/FVR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/4/ILR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/4/RSD/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/4/SFR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/5/BOR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/5/DLR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/5/ILR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/5/SFR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/6/BOR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/6/ILR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/7/BOR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/7/ILR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/8/BOR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/8/ILR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/9/BOR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/9/ILR/BalanceDrip.sol create mode 100644 contracts/mutants/BalanceDrip/original/BalanceDrip.sol diff --git a/contracts/mutants/BackedToken/1/BLR/BackedToken.sol b/contracts/mutants/BackedToken/1/BLR/BackedToken.sol new file mode 100644 index 00000000000..f80b7a0047a --- /dev/null +++ b/contracts/mutants/BackedToken/1/BLR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = false; + } +} diff --git a/contracts/mutants/BackedToken/1/BOR/BackedToken.sol b/contracts/mutants/BackedToken/1/BOR/BackedToken.sol new file mode 100644 index 00000000000..01c310e61bc --- /dev/null +++ b/contracts/mutants/BackedToken/1/BOR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 + 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/1/CCD/BackedToken.sol b/contracts/mutants/BackedToken/1/CCD/BackedToken.sol new file mode 100644 index 00000000000..c4b4b03543f --- /dev/null +++ b/contracts/mutants/BackedToken/1/CCD/BackedToken.sol @@ -0,0 +1,29 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/1/EHC/BackedToken.sol b/contracts/mutants/BackedToken/1/EHC/BackedToken.sol new file mode 100644 index 00000000000..a6622747475 --- /dev/null +++ b/contracts/mutants/BackedToken/1/EHC/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + /* require(_unlocked || from == _owner, "token transfer while locked"); */ + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/1/FVR/BackedToken.sol b/contracts/mutants/BackedToken/1/FVR/BackedToken.sol new file mode 100644 index 00000000000..f22053a2649 --- /dev/null +++ b/contracts/mutants/BackedToken/1/FVR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() internal ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/1/ILR/BackedToken.sol b/contracts/mutants/BackedToken/1/ILR/BackedToken.sol new file mode 100644 index 00000000000..3adb8b63919 --- /dev/null +++ b/contracts/mutants/BackedToken/1/ILR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 17) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/1/MOC/BackedToken.sol b/contracts/mutants/BackedToken/1/MOC/BackedToken.sol new file mode 100644 index 00000000000..6dbcae27c98 --- /dev/null +++ b/contracts/mutants/BackedToken/1/MOC/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20Detailed("BACKED", "BAKT", 18) ERC20() { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/1/MOD/BackedToken.sol b/contracts/mutants/BackedToken/1/MOD/BackedToken.sol new file mode 100644 index 00000000000..6dbcae27c98 --- /dev/null +++ b/contracts/mutants/BackedToken/1/MOD/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20Detailed("BACKED", "BAKT", 18) ERC20() { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/1/MOI/BackedToken.sol b/contracts/mutants/BackedToken/1/MOI/BackedToken.sol new file mode 100644 index 00000000000..fd9328aed64 --- /dev/null +++ b/contracts/mutants/BackedToken/1/MOI/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal onlyOwner { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/1/MOR/BackedToken.sol b/contracts/mutants/BackedToken/1/MOR/BackedToken.sol new file mode 100644 index 00000000000..f76dded32b5 --- /dev/null +++ b/contracts/mutants/BackedToken/1/MOR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public ERC20() { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/1/SKD/BackedToken.sol b/contracts/mutants/BackedToken/1/SKD/BackedToken.sol new file mode 100644 index 00000000000..39e04344ada --- /dev/null +++ b/contracts/mutants/BackedToken/1/SKD/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + _transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/1/SLR/BackedToken.sol b/contracts/mutants/BackedToken/1/SLR/BackedToken.sol new file mode 100644 index 00000000000..e41f2fdd57b --- /dev/null +++ b/contracts/mutants/BackedToken/1/SLR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("", "BAKT", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/1/TOR/BackedToken.sol b/contracts/mutants/BackedToken/1/TOR/BackedToken.sol new file mode 100644 index 00000000000..4de87cfb921 --- /dev/null +++ b/contracts/mutants/BackedToken/1/TOR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(tx.origin, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/1/VVR/BackedToken.sol b/contracts/mutants/BackedToken/1/VVR/BackedToken.sol new file mode 100644 index 00000000000..f96b151bfa6 --- /dev/null +++ b/contracts/mutants/BackedToken/1/VVR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool public _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/2/BOR/BackedToken.sol b/contracts/mutants/BackedToken/2/BOR/BackedToken.sol new file mode 100644 index 00000000000..824caf97f6d --- /dev/null +++ b/contracts/mutants/BackedToken/2/BOR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 + 10+18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/2/FVR/BackedToken.sol b/contracts/mutants/BackedToken/2/FVR/BackedToken.sol new file mode 100644 index 00000000000..7182f9be0a0 --- /dev/null +++ b/contracts/mutants/BackedToken/2/FVR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() internal ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) public { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/2/ILR/BackedToken.sol b/contracts/mutants/BackedToken/2/ILR/BackedToken.sol new file mode 100644 index 00000000000..2591e2d5103 --- /dev/null +++ b/contracts/mutants/BackedToken/2/ILR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 17) { + _mint(msg.sender, 99999999 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/2/SLR/BackedToken.sol b/contracts/mutants/BackedToken/2/SLR/BackedToken.sol new file mode 100644 index 00000000000..d7fe337304f --- /dev/null +++ b/contracts/mutants/BackedToken/2/SLR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("", "", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/2/TOR/BackedToken.sol b/contracts/mutants/BackedToken/2/TOR/BackedToken.sol new file mode 100644 index 00000000000..5687ad6e9bf --- /dev/null +++ b/contracts/mutants/BackedToken/2/TOR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(tx.origin, 100000000 * 10**18); + _owner = tx.origin; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/2/VVR/BackedToken.sol b/contracts/mutants/BackedToken/2/VVR/BackedToken.sol new file mode 100644 index 00000000000..543b5444e48 --- /dev/null +++ b/contracts/mutants/BackedToken/2/VVR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool public _unlocked; + // SWC-119-Shadowing State Variables: L12 + address public _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/3/BOR/BackedToken.sol b/contracts/mutants/BackedToken/3/BOR/BackedToken.sol new file mode 100644 index 00000000000..18bb14823ea --- /dev/null +++ b/contracts/mutants/BackedToken/3/BOR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 + 10+18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked && from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/3/FVR/BackedToken.sol b/contracts/mutants/BackedToken/3/FVR/BackedToken.sol new file mode 100644 index 00000000000..99399aa2a95 --- /dev/null +++ b/contracts/mutants/BackedToken/3/FVR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() internal ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) public { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() external onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/3/ILR/BackedToken.sol b/contracts/mutants/BackedToken/3/ILR/BackedToken.sol new file mode 100644 index 00000000000..2f1ad125665 --- /dev/null +++ b/contracts/mutants/BackedToken/3/ILR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 17) { + _mint(msg.sender, 99999999 * 9**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/4/BOR/BackedToken.sol b/contracts/mutants/BackedToken/4/BOR/BackedToken.sol new file mode 100644 index 00000000000..0c16243c6ea --- /dev/null +++ b/contracts/mutants/BackedToken/4/BOR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 + 10+18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked && from <= _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/4/ILR/BackedToken.sol b/contracts/mutants/BackedToken/4/ILR/BackedToken.sol new file mode 100644 index 00000000000..4259c98e002 --- /dev/null +++ b/contracts/mutants/BackedToken/4/ILR/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 17) { + _mint(msg.sender, 99999999 * 9**17); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BackedToken/original/BackedToken.sol b/contracts/mutants/BackedToken/original/BackedToken.sol new file mode 100644 index 00000000000..b89c7c59f89 --- /dev/null +++ b/contracts/mutants/BackedToken/original/BackedToken.sol @@ -0,0 +1,32 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.5.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; +import "@openzeppelin/contracts/ownership/Ownable.sol"; + +contract BackedToken is ERC20, ERC20Detailed, Ownable { + + bool _unlocked; + // SWC-119-Shadowing State Variables: L12 + address private _owner; + + constructor() public ERC20() ERC20Detailed("BACKED", "BAKT", 18) { + _mint(msg.sender, 100000000 * 10**18); + _owner = msg.sender; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal { + require(_unlocked || from == _owner, "token transfer while locked"); + super._transfer(from, to, amount); + } + + // SWC-100-Function Default Visibility: L28 + function unlock() public onlyOwner { + _unlocked = true; + } +} diff --git a/contracts/mutants/BadBeacon/1/EHC/BadBeacon.sol b/contracts/mutants/BadBeacon/1/EHC/BadBeacon.sol new file mode 100644 index 00000000000..a1408252a14 --- /dev/null +++ b/contracts/mutants/BadBeacon/1/EHC/BadBeacon.sol @@ -0,0 +1,11 @@ +pragma solidity 0.5.11; + + +/** + * @title BadBeacon + */ +contract BadBeacon { + function () external { + /* revert("This is not a working upgrade beacon."); */ + } +} \ No newline at end of file diff --git a/contracts/mutants/BadBeacon/1/EHC/diff_result_difft.json b/contracts/mutants/BadBeacon/1/EHC/diff_result_difft.json new file mode 100644 index 00000000000..b236574097b --- /dev/null +++ b/contracts/mutants/BadBeacon/1/EHC/diff_result_difft.json @@ -0,0 +1,50 @@ +{ + "number_of_changes": 4, + "timing": 0.23898029327392578, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 4, + "end": 10, + "content": "revert", + "highlight": "normal" + }, + { + "start": 10, + "end": 11, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 11, + "end": 50, + "content": "\"This is not a working upgrade beacon.\"", + "highlight": "string" + }, + { + "start": 50, + "end": 51, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 8, + "changes": [ + { + "start": 4, + "end": 58, + "content": "/* revert(\"This is not a working upgrade beacon.\"); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeacon/original/BadBeacon.sol b/contracts/mutants/BadBeacon/original/BadBeacon.sol new file mode 100644 index 00000000000..da51c746871 --- /dev/null +++ b/contracts/mutants/BadBeacon/original/BadBeacon.sol @@ -0,0 +1,11 @@ +pragma solidity 0.5.11; + + +/** + * @title BadBeacon + */ +contract BadBeacon { + function () external { + revert("This is not a working upgrade beacon."); + } +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconTwo/1/BOR/BadBeaconTwo.sol b/contracts/mutants/BadBeaconTwo/1/BOR/BadBeaconTwo.sol new file mode 100644 index 00000000000..cca853d2887 --- /dev/null +++ b/contracts/mutants/BadBeaconTwo/1/BOR/BadBeaconTwo.sol @@ -0,0 +1,19 @@ +pragma solidity 0.5.11; + + +/** + * @title BadBeaconTwo + */ +contract BadBeaconTwo { + function () external { + if (msg.data.length >= 0) { + revert("This is not an upgradeable upgrade beacon."); + } + + address implementation = address(0); + assembly { + mstore(0, implementation) + return(0, 32) + } + } +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconTwo/1/CSC/BadBeaconTwo.sol b/contracts/mutants/BadBeaconTwo/1/CSC/BadBeaconTwo.sol new file mode 100644 index 00000000000..681a0993d7a --- /dev/null +++ b/contracts/mutants/BadBeaconTwo/1/CSC/BadBeaconTwo.sol @@ -0,0 +1,19 @@ +pragma solidity 0.5.11; + + +/** + * @title BadBeaconTwo + */ +contract BadBeaconTwo { + function () external { + if (true) { + revert("This is not an upgradeable upgrade beacon."); + } + + address implementation = address(0); + assembly { + mstore(0, implementation) + return(0, 32) + } + } +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconTwo/1/EHC/BadBeaconTwo.sol b/contracts/mutants/BadBeaconTwo/1/EHC/BadBeaconTwo.sol new file mode 100644 index 00000000000..206cf7d05e7 --- /dev/null +++ b/contracts/mutants/BadBeaconTwo/1/EHC/BadBeaconTwo.sol @@ -0,0 +1,19 @@ +pragma solidity 0.5.11; + + +/** + * @title BadBeaconTwo + */ +contract BadBeaconTwo { + function () external { + if (msg.data.length > 0) { + /* revert("This is not an upgradeable upgrade beacon."); */ + } + + address implementation = address(0); + assembly { + mstore(0, implementation) + return(0, 32) + } + } +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconTwo/1/ILR/BadBeaconTwo.sol b/contracts/mutants/BadBeaconTwo/1/ILR/BadBeaconTwo.sol new file mode 100644 index 00000000000..68110b98056 --- /dev/null +++ b/contracts/mutants/BadBeaconTwo/1/ILR/BadBeaconTwo.sol @@ -0,0 +1,19 @@ +pragma solidity 0.5.11; + + +/** + * @title BadBeaconTwo + */ +contract BadBeaconTwo { + function () external { + if (msg.data.length > 1) { + revert("This is not an upgradeable upgrade beacon."); + } + + address implementation = address(0); + assembly { + mstore(0, implementation) + return(0, 32) + } + } +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconTwo/2/ILR/BadBeaconTwo.sol b/contracts/mutants/BadBeaconTwo/2/ILR/BadBeaconTwo.sol new file mode 100644 index 00000000000..8201e351658 --- /dev/null +++ b/contracts/mutants/BadBeaconTwo/2/ILR/BadBeaconTwo.sol @@ -0,0 +1,19 @@ +pragma solidity 0.5.11; + + +/** + * @title BadBeaconTwo + */ +contract BadBeaconTwo { + function () external { + if (msg.data.length > 1) { + revert("This is not an upgradeable upgrade beacon."); + } + + address implementation = address(1); + assembly { + mstore(0, implementation) + return(0, 32) + } + } +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconTwo/original/BadBeaconTwo.sol b/contracts/mutants/BadBeaconTwo/original/BadBeaconTwo.sol new file mode 100644 index 00000000000..12ec6d483b2 --- /dev/null +++ b/contracts/mutants/BadBeaconTwo/original/BadBeaconTwo.sol @@ -0,0 +1,19 @@ +pragma solidity 0.5.11; + + +/** + * @title BadBeaconTwo + */ +contract BadBeaconTwo { + function () external { + if (msg.data.length > 0) { + revert("This is not an upgradeable upgrade beacon."); + } + + address implementation = address(0); + assembly { + mstore(0, implementation) + return(0, 32) + } + } +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/1/FVR/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/1/FVR/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..40685b0e7b3 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/1/FVR/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() public onlyInitializing { + } + + function __BadBeaconNoImpl_init_unchained() internal onlyInitializing { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() internal onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() internal onlyInitializing { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/1/FVR/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/1/FVR/diff_result_difft.json new file mode 100644 index 00000000000..29234702072 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/1/FVR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.20847225189208984, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 5, + "changes": [ + { + "start": 92, + "end": 100, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 5, + "changes": [ + { + "start": 92, + "end": 98, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/1/ILR/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/1/ILR/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..081a1209196 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/1/ILR/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() internal onlyInitializing { + } + + function __BadBeaconNoImpl_init_unchained() internal onlyInitializing { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[49] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() internal onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() internal onlyInitializing { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/1/ILR/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/1/ILR/diff_result_difft.json new file mode 100644 index 00000000000..7a208fe7cc7 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/1/ILR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.12909150123596191, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 16, + "changes": [ + { + "start": 12, + "end": 14, + "content": "50", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 16, + "changes": [ + { + "start": 12, + "end": 14, + "content": "49", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/1/MOD/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/1/MOD/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..375ac50c971 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/1/MOD/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() internal { + } + + function __BadBeaconNoImpl_init_unchained() internal onlyInitializing { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() internal onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() internal onlyInitializing { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/1/MOD/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/1/MOD/diff_result_difft.json new file mode 100644 index 00000000000..903c1e73c66 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/1/MOD/diff_result_difft.json @@ -0,0 +1,25 @@ +{ + "number_of_changes": 1, + "timing": 0.2746775150299072, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 5, + "changes": [ + { + "start": 101, + "end": 117, + "content": "onlyInitializing", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 5, + "changes": [] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/1/RSD/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/1/RSD/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..2497a68a381 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/1/RSD/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() internal onlyInitializing { + } + + function __BadBeaconNoImpl_init_unchained() internal onlyInitializing { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() internal onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() internal onlyInitializing { + } + function implementation() external pure returns (address) { + /* return address(0x1); */ + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/1/RSD/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/1/RSD/diff_result_difft.json new file mode 100644 index 00000000000..5df0b45cf66 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/1/RSD/diff_result_difft.json @@ -0,0 +1,56 @@ +{ + "number_of_changes": 5, + "timing": 0.250957727432251, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "address", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 23, + "end": 26, + "content": "0x1", + "highlight": "normal" + }, + { + "start": 26, + "end": 27, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 34, + "content": "/* return address(0x1); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/1/VVR/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/1/VVR/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..24ffeb01021 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/1/VVR/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() internal onlyInitializing { + } + + function __BadBeaconNoImpl_init_unchained() internal onlyInitializing { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] public __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() internal onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() internal onlyInitializing { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/1/VVR/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/1/VVR/diff_result_difft.json new file mode 100644 index 00000000000..c64d01376a2 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/1/VVR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.1747901439666748, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 16, + "changes": [ + { + "start": 16, + "end": 23, + "content": "private", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 16, + "changes": [ + { + "start": 16, + "end": 22, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/2/FVR/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/2/FVR/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..9509597c8e8 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/2/FVR/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() public onlyInitializing { + } + + function __BadBeaconNoImpl_init_unchained() public onlyInitializing { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() internal onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() internal onlyInitializing { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/2/FVR/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/2/FVR/diff_result_difft.json new file mode 100644 index 00000000000..6fd926649d2 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/2/FVR/diff_result_difft.json @@ -0,0 +1,56 @@ +{ + "number_of_changes": 2, + "timing": 0.11611008644104004, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 48, + "end": 56, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 8, + "changes": [ + { + "start": 48, + "end": 54, + "content": "public", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 5, + "changes": [ + { + "start": 92, + "end": 100, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 5, + "changes": [ + { + "start": 92, + "end": 98, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/2/ILR/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/2/ILR/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..4d65ec80393 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/2/ILR/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() internal onlyInitializing { + } + + function __BadBeaconNoImpl_init_unchained() internal onlyInitializing { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[49] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() internal onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() internal onlyInitializing { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[49] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/2/ILR/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/2/ILR/diff_result_difft.json new file mode 100644 index 00000000000..f47a71354ce --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/2/ILR/diff_result_difft.json @@ -0,0 +1,58 @@ +{ + "number_of_changes": 2, + "timing": 0.17252469062805176, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 16, + "changes": [ + { + "start": 12, + "end": 14, + "content": "50", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 16, + "changes": [ + { + "start": 12, + "end": 14, + "content": "49", + "highlight": "normal" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 12, + "end": 14, + "content": "50", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 12, + "end": 14, + "content": "49", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/2/MOD/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/2/MOD/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..a3c7fc7a570 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/2/MOD/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() internal { + } + + function __BadBeaconNoImpl_init_unchained() internal { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() internal onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() internal onlyInitializing { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/2/MOD/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/2/MOD/diff_result_difft.json new file mode 100644 index 00000000000..e612ad65bf8 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/2/MOD/diff_result_difft.json @@ -0,0 +1,42 @@ +{ + "number_of_changes": 2, + "timing": 0.29298853874206543, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 5, + "changes": [ + { + "start": 101, + "end": 117, + "content": "onlyInitializing", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 5, + "changes": [] + } + }, + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 57, + "end": 73, + "content": "onlyInitializing", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 8, + "changes": [] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/2/VVR/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/2/VVR/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..2a22f6591ef --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/2/VVR/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() internal onlyInitializing { + } + + function __BadBeaconNoImpl_init_unchained() internal onlyInitializing { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] public __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() internal onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() internal onlyInitializing { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] public __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/2/VVR/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/2/VVR/diff_result_difft.json new file mode 100644 index 00000000000..491e6f12fd3 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/2/VVR/diff_result_difft.json @@ -0,0 +1,58 @@ +{ + "number_of_changes": 2, + "timing": 0.0985422134399414, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 16, + "changes": [ + { + "start": 16, + "end": 23, + "content": "private", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 16, + "changes": [ + { + "start": 16, + "end": 22, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 16, + "end": 23, + "content": "private", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 16, + "end": 22, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/3/FVR/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/3/FVR/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..4b0ad8013c3 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/3/FVR/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() public onlyInitializing { + } + + function __BadBeaconNoImpl_init_unchained() public onlyInitializing { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() public onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() internal onlyInitializing { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/3/FVR/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/3/FVR/diff_result_difft.json new file mode 100644 index 00000000000..17b50bf58e4 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/3/FVR/diff_result_difft.json @@ -0,0 +1,82 @@ +{ + "number_of_changes": 3, + "timing": 0.20494723320007324, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 5, + "changes": [ + { + "start": 92, + "end": 100, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 5, + "changes": [ + { + "start": 92, + "end": 98, + "content": "public", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 48, + "end": 56, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 8, + "changes": [ + { + "start": 48, + "end": 54, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 43, + "end": 51, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 20, + "changes": [ + { + "start": 43, + "end": 49, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/3/MOD/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/3/MOD/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..329912b5d75 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/3/MOD/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() internal { + } + + function __BadBeaconNoImpl_init_unchained() internal { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() internal { + } + + function __BadBeaconNotContract_init_unchained() internal onlyInitializing { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/3/MOD/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/3/MOD/diff_result_difft.json new file mode 100644 index 00000000000..7f3ec99e7f6 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/3/MOD/diff_result_difft.json @@ -0,0 +1,61 @@ +{ + "number_of_changes": 3, + "timing": 0.13519835472106934, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 57, + "end": 73, + "content": "onlyInitializing", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 8, + "changes": [] + } + }, + { + "lhs": { + "line_number": 5, + "changes": [ + { + "start": 101, + "end": 117, + "content": "onlyInitializing", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 5, + "changes": [] + } + } + ], + [ + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 52, + "end": 68, + "content": "onlyInitializing", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 20, + "changes": [] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/4/FVR/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/4/FVR/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..8fb4af9a775 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/4/FVR/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() public onlyInitializing { + } + + function __BadBeaconNoImpl_init_unchained() public onlyInitializing { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() public onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() public onlyInitializing { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/4/FVR/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/4/FVR/diff_result_difft.json new file mode 100644 index 00000000000..62285bfa56b --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/4/FVR/diff_result_difft.json @@ -0,0 +1,106 @@ +{ + "number_of_changes": 4, + "timing": 0.24634623527526855, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 5, + "changes": [ + { + "start": 92, + "end": 100, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 5, + "changes": [ + { + "start": 92, + "end": 98, + "content": "public", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 48, + "end": 56, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 8, + "changes": [ + { + "start": 48, + "end": 54, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 23, + "changes": [ + { + "start": 53, + "end": 61, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 23, + "changes": [ + { + "start": 53, + "end": 59, + "content": "public", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 43, + "end": 51, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 20, + "changes": [ + { + "start": 43, + "end": 49, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/4/MOD/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/4/MOD/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..22b82ed1aeb --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/4/MOD/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() internal { + } + + function __BadBeaconNoImpl_init_unchained() internal { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() internal { + } + + function __BadBeaconNotContract_init_unchained() internal { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/4/MOD/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/4/MOD/diff_result_difft.json new file mode 100644 index 00000000000..80a01557500 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/4/MOD/diff_result_difft.json @@ -0,0 +1,78 @@ +{ + "number_of_changes": 4, + "timing": 0.13117599487304688, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 57, + "end": 73, + "content": "onlyInitializing", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 8, + "changes": [] + } + }, + { + "lhs": { + "line_number": 5, + "changes": [ + { + "start": 101, + "end": 117, + "content": "onlyInitializing", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 5, + "changes": [] + } + } + ], + [ + { + "lhs": { + "line_number": 23, + "changes": [ + { + "start": 62, + "end": 78, + "content": "onlyInitializing", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 23, + "changes": [] + } + }, + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 52, + "end": 68, + "content": "onlyInitializing", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 20, + "changes": [] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/5/FVR/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/5/FVR/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..6bb3e3a1e1a --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/5/FVR/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() public onlyInitializing { + } + + function __BadBeaconNoImpl_init_unchained() public onlyInitializing { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() public onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() public onlyInitializing { + } + function implementation() public pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadBeaconUpgradeable/5/FVR/diff_result_difft.json b/contracts/mutants/BadBeaconUpgradeable/5/FVR/diff_result_difft.json new file mode 100644 index 00000000000..076f71af1dc --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/5/FVR/diff_result_difft.json @@ -0,0 +1,130 @@ +{ + "number_of_changes": 5, + "timing": 0.24119949340820312, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 5, + "changes": [ + { + "start": 92, + "end": 100, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 5, + "changes": [ + { + "start": 92, + "end": 98, + "content": "public", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 48, + "end": 56, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 8, + "changes": [ + { + "start": 48, + "end": 54, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 43, + "end": 51, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 20, + "changes": [ + { + "start": 43, + "end": 49, + "content": "public", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 23, + "changes": [ + { + "start": 53, + "end": 61, + "content": "internal", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 23, + "changes": [ + { + "start": 53, + "end": 59, + "content": "public", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 25, + "changes": [ + { + "start": 30, + "end": 38, + "content": "external", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 25, + "changes": [ + { + "start": 30, + "end": 36, + "content": "public", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadBeaconUpgradeable/original/BadBeaconUpgradeable.sol b/contracts/mutants/BadBeaconUpgradeable/original/BadBeaconUpgradeable.sol new file mode 100644 index 00000000000..f795145cc51 --- /dev/null +++ b/contracts/mutants/BadBeaconUpgradeable/original/BadBeaconUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +contract BadBeaconNoImplUpgradeable is Initializable { function __BadBeaconNoImpl_init() internal onlyInitializing { + } + + function __BadBeaconNoImpl_init_unchained() internal onlyInitializing { + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +contract BadBeaconNotContractUpgradeable is Initializable { + function __BadBeaconNotContract_init() internal onlyInitializing { + } + + function __BadBeaconNotContract_init_unchained() internal onlyInitializing { + } + function implementation() external pure returns (address) { + return address(0x1); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} diff --git a/contracts/mutants/BadToken/1/CCD/BadToken.sol b/contracts/mutants/BadToken/1/CCD/BadToken.sol new file mode 100644 index 00000000000..d8da1e47ab7 --- /dev/null +++ b/contracts/mutants/BadToken/1/CCD/BadToken.sol @@ -0,0 +1,13 @@ +pragma solidity 0.4.24; + +import "@aragon/apps-shared-minime/contracts/MiniMeToken.sol"; + + +contract BadToken is MiniMeToken { + + + // should be changed to view when MiniMe is updated + function totalSupplyAt(uint) public view returns(uint) { + return 1; + } +} diff --git a/contracts/mutants/BadToken/1/CCD/diff_result_difft.json b/contracts/mutants/BadToken/1/CCD/diff_result_difft.json new file mode 100644 index 00000000000..030730566a5 --- /dev/null +++ b/contracts/mutants/BadToken/1/CCD/diff_result_difft.json @@ -0,0 +1,355 @@ +{ + "number_of_changes": 42, + "timing": 0.19576382637023926, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 9, + "changes": [ + { + "start": 8, + "end": 12, + "content": "uint", + "highlight": "normal" + }, + { + "start": 13, + "end": 33, + "content": "_parentSnapShotBlock", + "highlight": "normal" + }, + { + "start": 33, + "end": 34, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 14, + "changes": [ + { + "start": 4, + "end": 5, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 6, + "end": 12, + "content": "public", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 19, + "changes": [ + { + "start": 4, + "end": 5, + "content": "}", + "highlight": "delimiter" + } + ] + } + }, + { + "lhs": { + "line_number": 6, + "changes": [ + { + "start": 4, + "end": 15, + "content": "constructor", + "highlight": "type" + }, + { + "start": 15, + "end": 16, + "content": "(", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 6, + "changes": [] + } + }, + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 8, + "end": 19, + "content": "MiniMeToken", + "highlight": "type" + }, + { + "start": 20, + "end": 32, + "content": "_parentToken", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 11, + "changes": [ + { + "start": 8, + "end": 13, + "content": "uint8", + "highlight": "normal" + }, + { + "start": 14, + "end": 27, + "content": "_decimalUnits", + "highlight": "normal" + }, + { + "start": 27, + "end": 28, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 13, + "changes": [ + { + "start": 8, + "end": 12, + "content": "bool", + "highlight": "normal" + }, + { + "start": 13, + "end": 30, + "content": "_transfersEnabled", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 7, + "changes": [ + { + "start": 8, + "end": 26, + "content": "MiniMeTokenFactory", + "highlight": "type" + }, + { + "start": 27, + "end": 40, + "content": "_tokenFactory", + "highlight": "normal" + }, + { + "start": 40, + "end": 41, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 15, + "changes": [ + { + "start": 8, + "end": 19, + "content": "MiniMeToken", + "highlight": "normal" + }, + { + "start": 19, + "end": 20, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 20, + "end": 33, + "content": "_tokenFactory", + "highlight": "normal" + }, + { + "start": 33, + "end": 34, + "content": ",", + "highlight": "normal" + }, + { + "start": 35, + "end": 47, + "content": "_parentToken", + "highlight": "normal" + }, + { + "start": 47, + "end": 48, + "content": ",", + "highlight": "normal" + }, + { + "start": 49, + "end": 69, + "content": "_parentSnapShotBlock", + "highlight": "normal" + }, + { + "start": 69, + "end": 70, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 10, + "changes": [ + { + "start": 8, + "end": 14, + "content": "string", + "highlight": "normal" + }, + { + "start": 15, + "end": 25, + "content": "_tokenName", + "highlight": "normal" + }, + { + "start": 25, + "end": 26, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 16, + "changes": [ + { + "start": 20, + "end": 30, + "content": "_tokenName", + "highlight": "normal" + }, + { + "start": 30, + "end": 31, + "content": ",", + "highlight": "normal" + }, + { + "start": 32, + "end": 45, + "content": "_decimalUnits", + "highlight": "normal" + }, + { + "start": 45, + "end": 46, + "content": ",", + "highlight": "normal" + }, + { + "start": 47, + "end": 59, + "content": "_tokenSymbol", + "highlight": "normal" + }, + { + "start": 59, + "end": 60, + "content": ",", + "highlight": "normal" + }, + { + "start": 61, + "end": 78, + "content": "_transfersEnabled", + "highlight": "normal" + }, + { + "start": 78, + "end": 79, + "content": ")", + "highlight": "delimiter" + } + ] + } + }, + { + "lhs": { + "line_number": 12, + "changes": [ + { + "start": 8, + "end": 14, + "content": "string", + "highlight": "normal" + }, + { + "start": 15, + "end": 27, + "content": "_tokenSymbol", + "highlight": "normal" + }, + { + "start": 27, + "end": 28, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 17, + "changes": [ + { + "start": 4, + "end": 5, + "content": "{", + "highlight": "delimiter" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadToken/1/FVR/BadToken.sol b/contracts/mutants/BadToken/1/FVR/BadToken.sol new file mode 100644 index 00000000000..82dacaa9ba9 --- /dev/null +++ b/contracts/mutants/BadToken/1/FVR/BadToken.sol @@ -0,0 +1,26 @@ +pragma solidity 0.4.24; + +import "@aragon/apps-shared-minime/contracts/MiniMeToken.sol"; + + +contract BadToken is MiniMeToken { + constructor( + MiniMeTokenFactory _tokenFactory, + MiniMeToken _parentToken, + uint _parentSnapShotBlock, + string _tokenName, + uint8 _decimalUnits, + string _tokenSymbol, + bool _transfersEnabled + ) internal + MiniMeToken(_tokenFactory, _parentToken, _parentSnapShotBlock, + _tokenName, _decimalUnits, _tokenSymbol, _transfersEnabled) + { + + } + + // should be changed to view when MiniMe is updated + function totalSupplyAt(uint) public view returns(uint) { + return 1; + } +} diff --git a/contracts/mutants/BadToken/1/FVR/diff_result_difft.json b/contracts/mutants/BadToken/1/FVR/diff_result_difft.json new file mode 100644 index 00000000000..c71e75086d3 --- /dev/null +++ b/contracts/mutants/BadToken/1/FVR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.4087662696838379, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 14, + "changes": [ + { + "start": 6, + "end": 12, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 14, + "changes": [ + { + "start": 6, + "end": 14, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadToken/1/ILR/BadToken.sol b/contracts/mutants/BadToken/1/ILR/BadToken.sol new file mode 100644 index 00000000000..f58453b8763 --- /dev/null +++ b/contracts/mutants/BadToken/1/ILR/BadToken.sol @@ -0,0 +1,26 @@ +pragma solidity 0.4.24; + +import "@aragon/apps-shared-minime/contracts/MiniMeToken.sol"; + + +contract BadToken is MiniMeToken { + constructor( + MiniMeTokenFactory _tokenFactory, + MiniMeToken _parentToken, + uint _parentSnapShotBlock, + string _tokenName, + uint8 _decimalUnits, + string _tokenSymbol, + bool _transfersEnabled + ) public + MiniMeToken(_tokenFactory, _parentToken, _parentSnapShotBlock, + _tokenName, _decimalUnits, _tokenSymbol, _transfersEnabled) + { + + } + + // should be changed to view when MiniMe is updated + function totalSupplyAt(uint) public view returns(uint) { + return 0; + } +} diff --git a/contracts/mutants/BadToken/1/ILR/diff_result_difft.json b/contracts/mutants/BadToken/1/ILR/diff_result_difft.json new file mode 100644 index 00000000000..a5bcbba107f --- /dev/null +++ b/contracts/mutants/BadToken/1/ILR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.1790757179260254, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 23, + "changes": [ + { + "start": 15, + "end": 16, + "content": "1", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 23, + "changes": [ + { + "start": 15, + "end": 16, + "content": "0", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadToken/1/RSD/BadToken.sol b/contracts/mutants/BadToken/1/RSD/BadToken.sol new file mode 100644 index 00000000000..9d4735acebd --- /dev/null +++ b/contracts/mutants/BadToken/1/RSD/BadToken.sol @@ -0,0 +1,26 @@ +pragma solidity 0.4.24; + +import "@aragon/apps-shared-minime/contracts/MiniMeToken.sol"; + + +contract BadToken is MiniMeToken { + constructor( + MiniMeTokenFactory _tokenFactory, + MiniMeToken _parentToken, + uint _parentSnapShotBlock, + string _tokenName, + uint8 _decimalUnits, + string _tokenSymbol, + bool _transfersEnabled + ) public + MiniMeToken(_tokenFactory, _parentToken, _parentSnapShotBlock, + _tokenName, _decimalUnits, _tokenSymbol, _transfersEnabled) + { + + } + + // should be changed to view when MiniMe is updated + function totalSupplyAt(uint) public view returns(uint) { + /* return 1; */ + } +} diff --git a/contracts/mutants/BadToken/1/RSD/diff_result_difft.json b/contracts/mutants/BadToken/1/RSD/diff_result_difft.json new file mode 100644 index 00000000000..89bf63edcaf --- /dev/null +++ b/contracts/mutants/BadToken/1/RSD/diff_result_difft.json @@ -0,0 +1,38 @@ +{ + "number_of_changes": 2, + "timing": 0.08076691627502441, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 23, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 16, + "content": "1", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 23, + "changes": [ + { + "start": 8, + "end": 23, + "content": "/* return 1; */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadToken/2/FVR/BadToken.sol b/contracts/mutants/BadToken/2/FVR/BadToken.sol new file mode 100644 index 00000000000..eaa0c0b9968 --- /dev/null +++ b/contracts/mutants/BadToken/2/FVR/BadToken.sol @@ -0,0 +1,26 @@ +pragma solidity 0.4.24; + +import "@aragon/apps-shared-minime/contracts/MiniMeToken.sol"; + + +contract BadToken is MiniMeToken { + constructor( + MiniMeTokenFactory _tokenFactory, + MiniMeToken _parentToken, + uint _parentSnapShotBlock, + string _tokenName, + uint8 _decimalUnits, + string _tokenSymbol, + bool _transfersEnabled + ) internal + MiniMeToken(_tokenFactory, _parentToken, _parentSnapShotBlock, + _tokenName, _decimalUnits, _tokenSymbol, _transfersEnabled) + { + + } + + // should be changed to view when MiniMe is updated + function totalSupplyAt(uint) external view returns(uint) { + return 1; + } +} diff --git a/contracts/mutants/BadToken/2/FVR/diff_result_difft.json b/contracts/mutants/BadToken/2/FVR/diff_result_difft.json new file mode 100644 index 00000000000..d77068c1522 --- /dev/null +++ b/contracts/mutants/BadToken/2/FVR/diff_result_difft.json @@ -0,0 +1,58 @@ +{ + "number_of_changes": 2, + "timing": 0.12478327751159668, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 14, + "changes": [ + { + "start": 6, + "end": 12, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 14, + "changes": [ + { + "start": 6, + "end": 14, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 33, + "end": 39, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 22, + "changes": [ + { + "start": 33, + "end": 41, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadToken/original/BadToken.sol b/contracts/mutants/BadToken/original/BadToken.sol new file mode 100644 index 00000000000..3542b0b24d6 --- /dev/null +++ b/contracts/mutants/BadToken/original/BadToken.sol @@ -0,0 +1,26 @@ +pragma solidity 0.4.24; + +import "@aragon/apps-shared-minime/contracts/MiniMeToken.sol"; + + +contract BadToken is MiniMeToken { + constructor( + MiniMeTokenFactory _tokenFactory, + MiniMeToken _parentToken, + uint _parentSnapShotBlock, + string _tokenName, + uint8 _decimalUnits, + string _tokenSymbol, + bool _transfersEnabled + ) public + MiniMeToken(_tokenFactory, _parentToken, _parentSnapShotBlock, + _tokenName, _decimalUnits, _tokenSymbol, _transfersEnabled) + { + + } + + // should be changed to view when MiniMe is updated + function totalSupplyAt(uint) public view returns(uint) { + return 1; + } +} diff --git a/contracts/mutants/BadTokenMock/1/BLR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/1/BLR/BadTokenMock.sol new file mode 100644 index 00000000000..d68222bffc5 --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/BLR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return false; + } +} diff --git a/contracts/mutants/BadTokenMock/1/BLR/diff_result_difft.json b/contracts/mutants/BadTokenMock/1/BLR/diff_result_difft.json new file mode 100644 index 00000000000..8d669652e4b --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/BLR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.029870033264160156, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 36, + "changes": [ + { + "start": 11, + "end": 15, + "content": "true", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 36, + "changes": [ + { + "start": 11, + "end": 16, + "content": "false", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/1/BOR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/1/BOR/BadTokenMock.sol new file mode 100644 index 00000000000..2e8e2d60ee8 --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/BOR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to > address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/1/BOR/diff_result_difft.json b/contracts/mutants/BadTokenMock/1/BOR/diff_result_difft.json new file mode 100644 index 00000000000..a26746534f7 --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/BOR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.22131752967834473, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 16, + "end": 18, + "content": "!=", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 16, + "end": 17, + "content": ">", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/1/CCD/BadTokenMock.sol b/contracts/mutants/BadTokenMock/1/CCD/BadTokenMock.sol new file mode 100644 index 00000000000..5b08297a2cc --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/CCD/BadTokenMock.sol @@ -0,0 +1,29 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/1/CCD/diff_result_difft.json b/contracts/mutants/BadTokenMock/1/CCD/diff_result_difft.json new file mode 100644 index 00000000000..019f934d3fb --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/CCD/diff_result_difft.json @@ -0,0 +1,275 @@ +{ + "number_of_changes": 31, + "timing": 0.10694074630737305, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 19, + "changes": [ + { + "start": 4, + "end": 9, + "content": "_mint", + "highlight": "normal" + }, + { + "start": 9, + "end": 10, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 10, + "end": 24, + "content": "initialAccount", + "highlight": "normal" + }, + { + "start": 24, + "end": 25, + "content": ",", + "highlight": "normal" + }, + { + "start": 26, + "end": 40, + "content": "initialBalance", + "highlight": "normal" + }, + { + "start": 40, + "end": 41, + "content": ")", + "highlight": "delimiter" + } + ] + } + }, + { + "lhs": { + "line_number": 13, + "changes": [ + { + "start": 4, + "end": 11, + "content": "address", + "highlight": "normal" + }, + { + "start": 12, + "end": 26, + "content": "initialAccount", + "highlight": "normal" + }, + { + "start": 26, + "end": 27, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 17, + "changes": [ + { + "start": 4, + "end": 10, + "content": "public", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 20, + "changes": [ + { + "start": 4, + "end": 8, + "content": "name", + "highlight": "normal" + }, + { + "start": 9, + "end": 10, + "content": "=", + "highlight": "normal" + }, + { + "start": 11, + "end": 16, + "content": "_name", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 2, + "end": 3, + "content": "}", + "highlight": "delimiter" + } + ] + } + }, + { + "lhs": { + "line_number": 15, + "changes": [ + { + "start": 4, + "end": 10, + "content": "string", + "highlight": "normal" + }, + { + "start": 11, + "end": 17, + "content": "memory", + "highlight": "keyword" + }, + { + "start": 18, + "end": 23, + "content": "_name", + "highlight": "normal" + }, + { + "start": 23, + "end": 24, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 14, + "changes": [ + { + "start": 4, + "end": 11, + "content": "uint256", + "highlight": "normal" + }, + { + "start": 12, + "end": 26, + "content": "initialBalance", + "highlight": "normal" + }, + { + "start": 26, + "end": 27, + "content": ",", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 16, + "changes": [ + { + "start": 4, + "end": 10, + "content": "string", + "highlight": "normal" + }, + { + "start": 11, + "end": 17, + "content": "memory", + "highlight": "keyword" + }, + { + "start": 18, + "end": 25, + "content": "_symbol", + "highlight": "normal" + }, + { + "start": 25, + "end": 26, + "content": ")", + "highlight": "delimiter" + } + ] + } + }, + { + "lhs": { + "line_number": 12, + "changes": [ + { + "start": 2, + "end": 13, + "content": "constructor", + "highlight": "type" + }, + { + "start": 13, + "end": 14, + "content": "(", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 12, + "changes": [] + } + }, + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 4, + "end": 10, + "content": "symbol", + "highlight": "normal" + }, + { + "start": 11, + "end": 12, + "content": "=", + "highlight": "normal" + }, + { + "start": 13, + "end": 20, + "content": "_symbol", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 18, + "changes": [ + { + "start": 2, + "end": 3, + "content": "{", + "highlight": "delimiter" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/1/DLR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/1/DLR/BadTokenMock.sol new file mode 100644 index 00000000000..57be398b147 --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/DLR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string storage _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/1/DLR/diff_result_difft.json b/contracts/mutants/BadTokenMock/1/DLR/diff_result_difft.json new file mode 100644 index 00000000000..6dc08dd763f --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/DLR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.20310425758361816, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 15, + "changes": [ + { + "start": 11, + "end": 17, + "content": "memory", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 15, + "changes": [ + { + "start": 11, + "end": 18, + "content": "storage", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/1/EED/BadTokenMock.sol b/contracts/mutants/BadTokenMock/1/EED/BadTokenMock.sol new file mode 100644 index 00000000000..d7480d91779 --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/EED/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + /* emit Transfer(msg.sender, _to, _value); */ + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/1/EED/diff_result_difft.json b/contracts/mutants/BadTokenMock/1/EED/diff_result_difft.json new file mode 100644 index 00000000000..d9f6cdabd4e --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/EED/diff_result_difft.json @@ -0,0 +1,92 @@ +{ + "number_of_changes": 11, + "timing": 0.40080738067626953, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 35, + "changes": [ + { + "start": 4, + "end": 8, + "content": "emit", + "highlight": "keyword" + }, + { + "start": 9, + "end": 17, + "content": "Transfer", + "highlight": "type" + }, + { + "start": 17, + "end": 18, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 18, + "end": 21, + "content": "msg", + "highlight": "normal" + }, + { + "start": 21, + "end": 22, + "content": ".", + "highlight": "normal" + }, + { + "start": 22, + "end": 28, + "content": "sender", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": ",", + "highlight": "normal" + }, + { + "start": 30, + "end": 33, + "content": "_to", + "highlight": "normal" + }, + { + "start": 33, + "end": 34, + "content": ",", + "highlight": "normal" + }, + { + "start": 35, + "end": 41, + "content": "_value", + "highlight": "normal" + }, + { + "start": 41, + "end": 42, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 35, + "changes": [ + { + "start": 4, + "end": 49, + "content": "/* emit Transfer(msg.sender, _to, _value); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/1/EHC/BadTokenMock.sol b/contracts/mutants/BadTokenMock/1/EHC/BadTokenMock.sol new file mode 100644 index 00000000000..ac2cc9df449 --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/EHC/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + /* require(_to != address(0)); */ + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/1/EHC/diff_result_difft.json b/contracts/mutants/BadTokenMock/1/EHC/diff_result_difft.json new file mode 100644 index 00000000000..338c9ede854 --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/EHC/diff_result_difft.json @@ -0,0 +1,80 @@ +{ + "number_of_changes": 9, + "timing": 0.034441471099853516, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 4, + "end": 11, + "content": "require", + "highlight": "normal" + }, + { + "start": 11, + "end": 12, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 12, + "end": 15, + "content": "_to", + "highlight": "normal" + }, + { + "start": 16, + "end": 18, + "content": "!=", + "highlight": "keyword" + }, + { + "start": 19, + "end": 26, + "content": "address", + "highlight": "normal" + }, + { + "start": 26, + "end": 27, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 27, + "end": 28, + "content": "0", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 4, + "end": 37, + "content": "/* require(_to != address(0)); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/1/FVR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/1/FVR/BadTokenMock.sol new file mode 100644 index 00000000000..8428fad7467 --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/FVR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + internal + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/1/FVR/diff_result_difft.json b/contracts/mutants/BadTokenMock/1/FVR/diff_result_difft.json new file mode 100644 index 00000000000..beee418ff78 --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/FVR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.02761363983154297, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 17, + "changes": [ + { + "start": 4, + "end": 10, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 17, + "changes": [ + { + "start": 4, + "end": 12, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/1/ILR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/1/ILR/BadTokenMock.sol new file mode 100644 index 00000000000..c4d8b8348ea --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/ILR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 17; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/1/ILR/diff_result_difft.json b/contracts/mutants/BadTokenMock/1/ILR/diff_result_difft.json new file mode 100644 index 00000000000..d2171ef4c5f --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/ILR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.14425325393676758, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 37, + "end": 39, + "content": "18", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 8, + "changes": [ + { + "start": 37, + "end": 39, + "content": "17", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/1/RSD/BadTokenMock.sol b/contracts/mutants/BadTokenMock/1/RSD/BadTokenMock.sol new file mode 100644 index 00000000000..de5f84a401d --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/RSD/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + /* return true; */ + } +} diff --git a/contracts/mutants/BadTokenMock/1/RSD/diff_result_difft.json b/contracts/mutants/BadTokenMock/1/RSD/diff_result_difft.json new file mode 100644 index 00000000000..0565e6c3b95 --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/RSD/diff_result_difft.json @@ -0,0 +1,38 @@ +{ + "number_of_changes": 2, + "timing": 0.13402247428894043, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 36, + "changes": [ + { + "start": 4, + "end": 10, + "content": "return", + "highlight": "keyword" + }, + { + "start": 11, + "end": 15, + "content": "true", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 36, + "changes": [ + { + "start": 4, + "end": 22, + "content": "/* return true; */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/1/TOR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/1/TOR/BadTokenMock.sol new file mode 100644 index 00000000000..4c1acbbd92f --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/TOR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(tx.origin)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/1/TOR/diff_result_difft.json b/contracts/mutants/BadTokenMock/1/TOR/diff_result_difft.json new file mode 100644 index 00000000000..45a40bf465e --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/TOR/diff_result_difft.json @@ -0,0 +1,44 @@ +{ + "number_of_changes": 2, + "timing": 0.16350698471069336, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 31, + "changes": [ + { + "start": 32, + "end": 35, + "content": "msg", + "highlight": "normal" + }, + { + "start": 36, + "end": 42, + "content": "sender", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 31, + "changes": [ + { + "start": 32, + "end": 34, + "content": "tx", + "highlight": "normal" + }, + { + "start": 35, + "end": 41, + "content": "origin", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/1/VVR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/1/VVR/BadTokenMock.sol new file mode 100644 index 00000000000..00d34c46154 --- /dev/null +++ b/contracts/mutants/BadTokenMock/1/VVR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant internal decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/1/VVR/diff_result_difft.json b/contracts/mutants/BadTokenMock/1/VVR/diff_result_difft.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contracts/mutants/BadTokenMock/2/BOR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/2/BOR/BadTokenMock.sol new file mode 100644 index 00000000000..86645506183 --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/BOR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to > address(0)); + require(_value < balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/2/BOR/diff_result_difft.json b/contracts/mutants/BadTokenMock/2/BOR/diff_result_difft.json new file mode 100644 index 00000000000..2f2b8dd066a --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/BOR/diff_result_difft.json @@ -0,0 +1,56 @@ +{ + "number_of_changes": 2, + "timing": 0.2579073905944824, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 16, + "end": 18, + "content": "!=", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 16, + "end": 17, + "content": ">", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 31, + "changes": [ + { + "start": 19, + "end": 21, + "content": "<=", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 31, + "changes": [ + { + "start": 20, + "end": 21, + "content": "<", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/2/DLR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/2/DLR/BadTokenMock.sol new file mode 100644 index 00000000000..5c372fce05e --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/DLR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string storage _name, + string storage _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/2/DLR/diff_result_difft.json b/contracts/mutants/BadTokenMock/2/DLR/diff_result_difft.json new file mode 100644 index 00000000000..61dec55f09f --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/DLR/diff_result_difft.json @@ -0,0 +1,56 @@ +{ + "number_of_changes": 2, + "timing": 0.15331029891967773, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 15, + "changes": [ + { + "start": 11, + "end": 17, + "content": "memory", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 15, + "changes": [ + { + "start": 11, + "end": 18, + "content": "storage", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 16, + "changes": [ + { + "start": 11, + "end": 17, + "content": "memory", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 16, + "changes": [ + { + "start": 11, + "end": 18, + "content": "storage", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/2/EHC/BadTokenMock.sol b/contracts/mutants/BadTokenMock/2/EHC/BadTokenMock.sol new file mode 100644 index 00000000000..89b93668f1f --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/EHC/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + /* require(_to != address(0)); */ + /* require(_value <= balanceOf(msg.sender)); */ + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/2/EHC/diff_result_difft.json b/contracts/mutants/BadTokenMock/2/EHC/diff_result_difft.json new file mode 100644 index 00000000000..e6d155fa169 --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/EHC/diff_result_difft.json @@ -0,0 +1,164 @@ +{ + "number_of_changes": 20, + "timing": 0.15966463088989258, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 31, + "changes": [ + { + "start": 4, + "end": 11, + "content": "require", + "highlight": "normal" + }, + { + "start": 11, + "end": 12, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 12, + "end": 18, + "content": "_value", + "highlight": "normal" + }, + { + "start": 19, + "end": 21, + "content": "<=", + "highlight": "keyword" + }, + { + "start": 22, + "end": 31, + "content": "balanceOf", + "highlight": "normal" + }, + { + "start": 31, + "end": 32, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 32, + "end": 35, + "content": "msg", + "highlight": "normal" + }, + { + "start": 35, + "end": 36, + "content": ".", + "highlight": "normal" + }, + { + "start": 36, + "end": 42, + "content": "sender", + "highlight": "normal" + }, + { + "start": 42, + "end": 43, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 43, + "end": 44, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 31, + "changes": [ + { + "start": 4, + "end": 51, + "content": "/* require(_value <= balanceOf(msg.sender)); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 4, + "end": 11, + "content": "require", + "highlight": "normal" + }, + { + "start": 11, + "end": 12, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 12, + "end": 15, + "content": "_to", + "highlight": "normal" + }, + { + "start": 16, + "end": 18, + "content": "!=", + "highlight": "keyword" + }, + { + "start": 19, + "end": 26, + "content": "address", + "highlight": "normal" + }, + { + "start": 26, + "end": 27, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 27, + "end": 28, + "content": "0", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": ")", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 4, + "end": 37, + "content": "/* require(_to != address(0)); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/2/FVR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/2/FVR/BadTokenMock.sol new file mode 100644 index 00000000000..c3745e37a68 --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/FVR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + internal + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) external returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/2/FVR/diff_result_difft.json b/contracts/mutants/BadTokenMock/2/FVR/diff_result_difft.json new file mode 100644 index 00000000000..9647b96e776 --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/FVR/diff_result_difft.json @@ -0,0 +1,58 @@ +{ + "number_of_changes": 2, + "timing": 0.1297299861907959, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 17, + "changes": [ + { + "start": 4, + "end": 10, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 17, + "changes": [ + { + "start": 4, + "end": 12, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 29, + "changes": [ + { + "start": 49, + "end": 55, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 29, + "changes": [ + { + "start": 49, + "end": 57, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/2/ILR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/2/ILR/BadTokenMock.sol new file mode 100644 index 00000000000..568e3dbf81d --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/ILR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 17; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(1)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/2/ILR/diff_result_difft.json b/contracts/mutants/BadTokenMock/2/ILR/diff_result_difft.json new file mode 100644 index 00000000000..690be8c022e --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/ILR/diff_result_difft.json @@ -0,0 +1,58 @@ +{ + "number_of_changes": 2, + "timing": 0.10995316505432129, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 37, + "end": 39, + "content": "18", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 8, + "changes": [ + { + "start": 37, + "end": 39, + "content": "17", + "highlight": "normal" + } + ] + } + } + ], + [ + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 27, + "end": 28, + "content": "0", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 27, + "end": 28, + "content": "1", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/2/TOR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/2/TOR/BadTokenMock.sol new file mode 100644 index 00000000000..01e74e796c4 --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/TOR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(tx.origin)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(tx.origin, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/2/TOR/diff_result_difft.json b/contracts/mutants/BadTokenMock/2/TOR/diff_result_difft.json new file mode 100644 index 00000000000..4106d9fe547 --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/TOR/diff_result_difft.json @@ -0,0 +1,80 @@ +{ + "number_of_changes": 4, + "timing": 0.36158180236816406, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 31, + "changes": [ + { + "start": 32, + "end": 35, + "content": "msg", + "highlight": "normal" + }, + { + "start": 36, + "end": 42, + "content": "sender", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 31, + "changes": [ + { + "start": 32, + "end": 34, + "content": "tx", + "highlight": "normal" + }, + { + "start": 35, + "end": 41, + "content": "origin", + "highlight": "normal" + } + ] + } + }, + { + "lhs": { + "line_number": 35, + "changes": [ + { + "start": 18, + "end": 21, + "content": "msg", + "highlight": "normal" + }, + { + "start": 22, + "end": 28, + "content": "sender", + "highlight": "normal" + } + ] + }, + "rhs": { + "line_number": 35, + "changes": [ + { + "start": 18, + "end": 20, + "content": "tx", + "highlight": "normal" + }, + { + "start": 21, + "end": 27, + "content": "origin", + "highlight": "normal" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/2/VVR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/2/VVR/BadTokenMock.sol new file mode 100644 index 00000000000..9a6359fa798 --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/VVR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant internal decimals = 18; + string internal name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/2/VVR/diff_result_difft.json b/contracts/mutants/BadTokenMock/2/VVR/diff_result_difft.json new file mode 100644 index 00000000000..e6b1316bcb5 --- /dev/null +++ b/contracts/mutants/BadTokenMock/2/VVR/diff_result_difft.json @@ -0,0 +1,56 @@ +{ + "number_of_changes": 2, + "timing": 0.14941954612731934, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 9, + "changes": [ + { + "start": 9, + "end": 15, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 9, + "changes": [ + { + "start": 9, + "end": 17, + "content": "internal", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 19, + "end": 25, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 8, + "changes": [ + { + "start": 19, + "end": 27, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/3/VVR/BadTokenMock.sol b/contracts/mutants/BadTokenMock/3/VVR/BadTokenMock.sol new file mode 100644 index 00000000000..83e6424906b --- /dev/null +++ b/contracts/mutants/BadTokenMock/3/VVR/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant internal decimals = 18; + string internal name; + string internal symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BadTokenMock/3/VVR/diff_result_difft.json b/contracts/mutants/BadTokenMock/3/VVR/diff_result_difft.json new file mode 100644 index 00000000000..17f4c7136a3 --- /dev/null +++ b/contracts/mutants/BadTokenMock/3/VVR/diff_result_difft.json @@ -0,0 +1,80 @@ +{ + "number_of_changes": 3, + "timing": 0.2333393096923828, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 10, + "changes": [ + { + "start": 9, + "end": 15, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 10, + "changes": [ + { + "start": 9, + "end": 17, + "content": "internal", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 8, + "changes": [ + { + "start": 19, + "end": 25, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 8, + "changes": [ + { + "start": 19, + "end": 27, + "content": "internal", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 9, + "changes": [ + { + "start": 9, + "end": 15, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 9, + "changes": [ + { + "start": 9, + "end": 17, + "content": "internal", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BadTokenMock/original/BadTokenMock.sol b/contracts/mutants/BadTokenMock/original/BadTokenMock.sol new file mode 100644 index 00000000000..ba4d2bdf38f --- /dev/null +++ b/contracts/mutants/BadTokenMock/original/BadTokenMock.sol @@ -0,0 +1,39 @@ +pragma solidity 0.5.4; + + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; + + +// mock class using BasicToken +contract BadTokenMock is ERC20 { + uint256 constant public decimals = 18; + string public name; + string public symbol; + + constructor( + address initialAccount, + uint256 initialBalance, + string memory _name, + string memory _symbol) + public + { + _mint(initialAccount, initialBalance); + name = _name; + symbol = _symbol; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balanceOf(msg.sender)); + + // BAD TOKEN which does not update balances properly + + emit Transfer(msg.sender, _to, _value); + return true; + } +} diff --git a/contracts/mutants/BalanceAccounting/1/AOR/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/1/AOR/BalanceAccounting.sol new file mode 100644 index 00000000000..0160b89ec78 --- /dev/null +++ b/contracts/mutants/BalanceAccounting/1/AOR/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply -= amount; + unchecked { + _balances[account] += amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] -= amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/1/AVR/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/1/AVR/BalanceAccounting.sol new file mode 100644 index 00000000000..0160b89ec78 --- /dev/null +++ b/contracts/mutants/BalanceAccounting/1/AVR/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply -= amount; + unchecked { + _balances[account] += amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] -= amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/1/FVR/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/1/FVR/BalanceAccounting.sol new file mode 100644 index 00000000000..bfb29ea13b3 --- /dev/null +++ b/contracts/mutants/BalanceAccounting/1/FVR/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() external view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply += amount; + unchecked { + _balances[account] += amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] -= amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/1/ICM/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/1/ICM/BalanceAccounting.sol new file mode 100644 index 00000000000..f67978b143d --- /dev/null +++ b/contracts/mutants/BalanceAccounting/1/ICM/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply += amount; + unchecked { + _balances[account] += amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] =- amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/1/LSC/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/1/LSC/BalanceAccounting.sol new file mode 100644 index 00000000000..f67978b143d --- /dev/null +++ b/contracts/mutants/BalanceAccounting/1/LSC/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply += amount; + unchecked { + _balances[account] += amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] =- amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/1/RSD/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/1/RSD/BalanceAccounting.sol new file mode 100644 index 00000000000..9a772e1fcab --- /dev/null +++ b/contracts/mutants/BalanceAccounting/1/RSD/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + /* return _totalSupply; */ + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply += amount; + unchecked { + _balances[account] += amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] -= amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/1/VVR/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/1/VVR/BalanceAccounting.sol new file mode 100644 index 00000000000..06b8458e2f3 --- /dev/null +++ b/contracts/mutants/BalanceAccounting/1/VVR/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 public _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply += amount; + unchecked { + _balances[account] += amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] -= amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/2/AOR/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/2/AOR/BalanceAccounting.sol new file mode 100644 index 00000000000..998b0e6bc6b --- /dev/null +++ b/contracts/mutants/BalanceAccounting/2/AOR/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply -= amount; + unchecked { + _balances[account] -= amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] -= amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/2/AVR/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/2/AVR/BalanceAccounting.sol new file mode 100644 index 00000000000..998b0e6bc6b --- /dev/null +++ b/contracts/mutants/BalanceAccounting/2/AVR/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply -= amount; + unchecked { + _balances[account] -= amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] -= amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/2/FVR/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/2/FVR/BalanceAccounting.sol new file mode 100644 index 00000000000..c97e9f19562 --- /dev/null +++ b/contracts/mutants/BalanceAccounting/2/FVR/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() external view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) external view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply += amount; + unchecked { + _balances[account] += amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] -= amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/2/ICM/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/2/ICM/BalanceAccounting.sol new file mode 100644 index 00000000000..5c6305f5311 --- /dev/null +++ b/contracts/mutants/BalanceAccounting/2/ICM/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply += amount; + unchecked { + _balances[account] += amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] =- amount; + unchecked { + _totalSupply =- amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/2/LSC/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/2/LSC/BalanceAccounting.sol new file mode 100644 index 00000000000..5c6305f5311 --- /dev/null +++ b/contracts/mutants/BalanceAccounting/2/LSC/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply += amount; + unchecked { + _balances[account] += amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] =- amount; + unchecked { + _totalSupply =- amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/2/RSD/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/2/RSD/BalanceAccounting.sol new file mode 100644 index 00000000000..cc5362b455c --- /dev/null +++ b/contracts/mutants/BalanceAccounting/2/RSD/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + /* return _totalSupply; */ + } + + function balanceOf(address account) public view returns (uint256) { + /* return _balances[account]; */ + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply += amount; + unchecked { + _balances[account] += amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] -= amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/3/AOR/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/3/AOR/BalanceAccounting.sol new file mode 100644 index 00000000000..5985e752012 --- /dev/null +++ b/contracts/mutants/BalanceAccounting/3/AOR/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply -= amount; + unchecked { + _balances[account] -= amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] += amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/3/AVR/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/3/AVR/BalanceAccounting.sol new file mode 100644 index 00000000000..5985e752012 --- /dev/null +++ b/contracts/mutants/BalanceAccounting/3/AVR/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply -= amount; + unchecked { + _balances[account] -= amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] += amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/4/AOR/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/4/AOR/BalanceAccounting.sol new file mode 100644 index 00000000000..dd5ccfa3196 --- /dev/null +++ b/contracts/mutants/BalanceAccounting/4/AOR/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply -= amount; + unchecked { + _balances[account] -= amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] += amount; + unchecked { + _totalSupply += amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/4/AVR/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/4/AVR/BalanceAccounting.sol new file mode 100644 index 00000000000..dd5ccfa3196 --- /dev/null +++ b/contracts/mutants/BalanceAccounting/4/AVR/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply -= amount; + unchecked { + _balances[account] -= amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] += amount; + unchecked { + _totalSupply += amount; + } + } +} diff --git a/contracts/mutants/BalanceAccounting/original/BalanceAccounting.sol b/contracts/mutants/BalanceAccounting/original/BalanceAccounting.sol new file mode 100644 index 00000000000..7af25f23519 --- /dev/null +++ b/contracts/mutants/BalanceAccounting/original/BalanceAccounting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + + +contract BalanceAccounting { + uint256 private _totalSupply; + mapping(address => uint256) private _balances; + + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 amount) internal virtual { + _totalSupply += amount; + unchecked { + _balances[account] += amount; + } + } + + function _burn(address account, uint256 amount) internal virtual { + _balances[account] -= amount; + unchecked { + _totalSupply -= amount; + } + } +} diff --git a/contracts/mutants/BalanceAllocation/1/BOR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/1/BOR/BalanceAllocation.sol new file mode 100644 index 00000000000..0791725447c --- /dev/null +++ b/contracts/mutants/BalanceAllocation/1/BOR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/1/DLR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/1/DLR/BalanceAllocation.sol new file mode 100644 index 00000000000..892dd45a579 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/1/DLR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] storage balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/1/ECS/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/1/ECS/BalanceAllocation.sol new file mode 100644 index 00000000000..92af1f8cc78 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/1/ECS/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/1/EHC/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/1/EHC/BalanceAllocation.sol new file mode 100644 index 00000000000..70033ad77ac --- /dev/null +++ b/contracts/mutants/BalanceAllocation/1/EHC/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + /* require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); */ + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/1/FVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/1/FVR/BalanceAllocation.sol new file mode 100644 index 00000000000..29b60c93813 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/1/FVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) public pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/1/GVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/1/GVR/BalanceAllocation.sol new file mode 100644 index 00000000000..3791941be5e --- /dev/null +++ b/contracts/mutants/BalanceAllocation/1/GVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.difficulty; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/1/ILR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/1/ILR/BalanceAllocation.sol new file mode 100644 index 00000000000..4acb720df9b --- /dev/null +++ b/contracts/mutants/BalanceAllocation/1/ILR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/1/LSC/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/1/LSC/BalanceAllocation.sol new file mode 100644 index 00000000000..dcd955bb085 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/1/LSC/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; true; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/1/RSD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/1/RSD/BalanceAllocation.sol new file mode 100644 index 00000000000..20e108e8bc5 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/1/RSD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + /* return cash(balance).add(managed(balance)); */ + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/1/UORD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/1/UORD/BalanceAllocation.sol new file mode 100644 index 00000000000..e7af60516b8 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/1/UORD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i--) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/10/BOR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/10/BOR/BalanceAllocation.sol new file mode 100644 index 00000000000..6b40566b301 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/10/BOR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance) | mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance << 112) | mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(32) + 1; + return uint256(balance << 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/10/FVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/10/FVR/BalanceAllocation.sol new file mode 100644 index 00000000000..7cb937bc66c --- /dev/null +++ b/contracts/mutants/BalanceAllocation/10/FVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) public pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) public pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + public + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) public pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) public pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) public pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/10/ILR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/10/ILR/BalanceAllocation.sol new file mode 100644 index 00000000000..2e15ba31e4a --- /dev/null +++ b/contracts/mutants/BalanceAllocation/10/ILR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance >> 111) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(31) - 0; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/10/RSD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/10/RSD/BalanceAllocation.sol new file mode 100644 index 00000000000..465709c11a2 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/10/RSD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + /* return cash(balance).add(managed(balance)); */ + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance) & mask; */ + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance >> 112) & mask; */ + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + /* return uint256(balance >> 224) & mask; */ + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + /* return (uint256(balance) & mask) == 0; */ + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + /* return !isZero(balance); */ + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + /* return _pack(_cash, _managed, _blockNumber); */ + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + /* return toBalance(newCash, currentManaged, newBlockNumber); */ + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + /* return toBalance(newCash, currentManaged, newBlockNumber); */ + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + /* return toBalance(newCash, newManaged, currentBlockNumber); */ + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/2/BOR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/2/BOR/BalanceAllocation.sol new file mode 100644 index 00000000000..cb20d967c63 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/2/BOR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/2/DLR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/2/DLR/BalanceAllocation.sol new file mode 100644 index 00000000000..b8566c6f7ff --- /dev/null +++ b/contracts/mutants/BalanceAllocation/2/DLR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] storage balances) internal pure returns (uint256[] storage results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/2/ECS/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/2/ECS/BalanceAllocation.sol new file mode 100644 index 00000000000..1799f940c15 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/2/ECS/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/2/FVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/2/FVR/BalanceAllocation.sol new file mode 100644 index 00000000000..749a66a7ec7 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/2/FVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) public pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/2/GVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/2/GVR/BalanceAllocation.sol new file mode 100644 index 00000000000..e901473d489 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/2/GVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.difficulty; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.difficulty; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/2/ILR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/2/ILR/BalanceAllocation.sol new file mode 100644 index 00000000000..30151ed5b25 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/2/ILR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/2/LSC/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/2/LSC/BalanceAllocation.sol new file mode 100644 index 00000000000..1a5b25eaccd --- /dev/null +++ b/contracts/mutants/BalanceAllocation/2/LSC/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; true; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; true; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/2/RSD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/2/RSD/BalanceAllocation.sol new file mode 100644 index 00000000000..73057ec425f --- /dev/null +++ b/contracts/mutants/BalanceAllocation/2/RSD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + /* return cash(balance).add(managed(balance)); */ + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance) & mask; */ + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/2/UORD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/2/UORD/BalanceAllocation.sol new file mode 100644 index 00000000000..7348ce417a9 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/2/UORD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i--) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i--) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/3/BOR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/3/BOR/BalanceAllocation.sol new file mode 100644 index 00000000000..67aff6c6fed --- /dev/null +++ b/contracts/mutants/BalanceAllocation/3/BOR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance) | mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/3/DLR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/3/DLR/BalanceAllocation.sol new file mode 100644 index 00000000000..6dbc750575f --- /dev/null +++ b/contracts/mutants/BalanceAllocation/3/DLR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] storage balances) internal pure returns (uint256[] storage results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] storage balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/3/ECS/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/3/ECS/BalanceAllocation.sol new file mode 100644 index 00000000000..fc6376c1a3f --- /dev/null +++ b/contracts/mutants/BalanceAllocation/3/ECS/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint8(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/3/FVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/3/FVR/BalanceAllocation.sol new file mode 100644 index 00000000000..4f90b6fe4f9 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/3/FVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) public pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/3/GVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/3/GVR/BalanceAllocation.sol new file mode 100644 index 00000000000..0b5fb35f010 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/3/GVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.difficulty; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.difficulty; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.difficulty; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/3/ILR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/3/ILR/BalanceAllocation.sol new file mode 100644 index 00000000000..b332f92ad8f --- /dev/null +++ b/contracts/mutants/BalanceAllocation/3/ILR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/3/RSD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/3/RSD/BalanceAllocation.sol new file mode 100644 index 00000000000..4190a5ed99f --- /dev/null +++ b/contracts/mutants/BalanceAllocation/3/RSD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + /* return cash(balance).add(managed(balance)); */ + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance) & mask; */ + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance >> 112) & mask; */ + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/3/UORD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/3/UORD/BalanceAllocation.sol new file mode 100644 index 00000000000..dcdb8349ce6 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/3/UORD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i--) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i--) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/4/BOR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/4/BOR/BalanceAllocation.sol new file mode 100644 index 00000000000..4e228b2f315 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/4/BOR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance) | mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/4/DLR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/4/DLR/BalanceAllocation.sol new file mode 100644 index 00000000000..b05ef7f02e6 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/4/DLR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] storage balances) internal pure returns (uint256[] storage results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] storage balances) + internal + pure + returns (uint256[] storage results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/4/ECS/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/4/ECS/BalanceAllocation.sol new file mode 100644 index 00000000000..c5541ee8193 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/4/ECS/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint8(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint8(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/4/FVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/4/FVR/BalanceAllocation.sol new file mode 100644 index 00000000000..7441bba48fc --- /dev/null +++ b/contracts/mutants/BalanceAllocation/4/FVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) public pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/4/ILR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/4/ILR/BalanceAllocation.sol new file mode 100644 index 00000000000..3b5684b8580 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/4/ILR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/4/RSD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/4/RSD/BalanceAllocation.sol new file mode 100644 index 00000000000..49d5677c54b --- /dev/null +++ b/contracts/mutants/BalanceAllocation/4/RSD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + /* return cash(balance).add(managed(balance)); */ + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance) & mask; */ + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance >> 112) & mask; */ + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + /* return uint256(balance >> 224) & mask; */ + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/5/BOR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/5/BOR/BalanceAllocation.sol new file mode 100644 index 00000000000..c186c86a2c9 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/5/BOR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance) | mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/5/ECS/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/5/ECS/BalanceAllocation.sol new file mode 100644 index 00000000000..b1c3e9238dc --- /dev/null +++ b/contracts/mutants/BalanceAllocation/5/ECS/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint8(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint8(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/5/FVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/5/FVR/BalanceAllocation.sol new file mode 100644 index 00000000000..e2344eee897 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/5/FVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) public pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) public pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/5/ILR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/5/ILR/BalanceAllocation.sol new file mode 100644 index 00000000000..6c21a1f0223 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/5/ILR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/5/RSD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/5/RSD/BalanceAllocation.sol new file mode 100644 index 00000000000..e78b164ff39 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/5/RSD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + /* return cash(balance).add(managed(balance)); */ + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance) & mask; */ + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance >> 112) & mask; */ + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + /* return uint256(balance >> 224) & mask; */ + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + /* return (uint256(balance) & mask) == 0; */ + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/6/BOR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/6/BOR/BalanceAllocation.sol new file mode 100644 index 00000000000..e30ec1fd4f3 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/6/BOR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance) | mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance << 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/6/ECS/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/6/ECS/BalanceAllocation.sol new file mode 100644 index 00000000000..6c725dd114a --- /dev/null +++ b/contracts/mutants/BalanceAllocation/6/ECS/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint8(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint8(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/6/FVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/6/FVR/BalanceAllocation.sol new file mode 100644 index 00000000000..6d7188013d7 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/6/FVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) public pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) public pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + public + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/6/ILR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/6/ILR/BalanceAllocation.sol new file mode 100644 index 00000000000..b4f0f031542 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/6/ILR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/6/RSD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/6/RSD/BalanceAllocation.sol new file mode 100644 index 00000000000..0799310068e --- /dev/null +++ b/contracts/mutants/BalanceAllocation/6/RSD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + /* return cash(balance).add(managed(balance)); */ + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance) & mask; */ + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance >> 112) & mask; */ + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + /* return uint256(balance >> 224) & mask; */ + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + /* return (uint256(balance) & mask) == 0; */ + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + /* return !isZero(balance); */ + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/7/BOR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/7/BOR/BalanceAllocation.sol new file mode 100644 index 00000000000..93aecf54986 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/7/BOR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance) | mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance << 112) | mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/7/ECS/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/7/ECS/BalanceAllocation.sol new file mode 100644 index 00000000000..561a485a92e --- /dev/null +++ b/contracts/mutants/BalanceAllocation/7/ECS/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint8(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint8(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint8(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes1((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/7/FVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/7/FVR/BalanceAllocation.sol new file mode 100644 index 00000000000..481ec44a84d --- /dev/null +++ b/contracts/mutants/BalanceAllocation/7/FVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) public pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) public pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + public + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) public pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/7/ILR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/7/ILR/BalanceAllocation.sol new file mode 100644 index 00000000000..d7c03eaea24 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/7/ILR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance >> 111) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/7/RSD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/7/RSD/BalanceAllocation.sol new file mode 100644 index 00000000000..b7ef9fa106e --- /dev/null +++ b/contracts/mutants/BalanceAllocation/7/RSD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + /* return cash(balance).add(managed(balance)); */ + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance) & mask; */ + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance >> 112) & mask; */ + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + /* return uint256(balance >> 224) & mask; */ + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + /* return (uint256(balance) & mask) == 0; */ + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + /* return !isZero(balance); */ + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + /* return _pack(_cash, _managed, _blockNumber); */ + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/8/BOR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/8/BOR/BalanceAllocation.sol new file mode 100644 index 00000000000..2d787c5e633 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/8/BOR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance) | mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance << 112) | mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/8/FVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/8/FVR/BalanceAllocation.sol new file mode 100644 index 00000000000..a3d1d5951cb --- /dev/null +++ b/contracts/mutants/BalanceAllocation/8/FVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) public pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) public pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + public + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) public pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) public pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/8/ILR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/8/ILR/BalanceAllocation.sol new file mode 100644 index 00000000000..9188a1abc27 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/8/ILR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance >> 111) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/8/RSD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/8/RSD/BalanceAllocation.sol new file mode 100644 index 00000000000..854f2d1c74a --- /dev/null +++ b/contracts/mutants/BalanceAllocation/8/RSD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + /* return cash(balance).add(managed(balance)); */ + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance) & mask; */ + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance >> 112) & mask; */ + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + /* return uint256(balance >> 224) & mask; */ + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + /* return (uint256(balance) & mask) == 0; */ + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + /* return !isZero(balance); */ + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + /* return _pack(_cash, _managed, _blockNumber); */ + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + /* return toBalance(newCash, currentManaged, newBlockNumber); */ + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/9/BOR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/9/BOR/BalanceAllocation.sol new file mode 100644 index 00000000000..d50087c4abe --- /dev/null +++ b/contracts/mutants/BalanceAllocation/9/BOR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance) | mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(112) + 1; + return uint256(balance << 112) | mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2+(32) + 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/9/FVR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/9/FVR/BalanceAllocation.sol new file mode 100644 index 00000000000..96fd590bbcf --- /dev/null +++ b/contracts/mutants/BalanceAllocation/9/FVR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) public pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) public pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) public pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + public + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) public pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) public pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) public pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/9/ILR/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/9/ILR/BalanceAllocation.sol new file mode 100644 index 00000000000..e95207efce4 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/9/ILR/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(111) - 0; + return uint256(balance >> 111) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 1**(31) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/9/RSD/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/9/RSD/BalanceAllocation.sol new file mode 100644 index 00000000000..b966d9d47a6 --- /dev/null +++ b/contracts/mutants/BalanceAllocation/9/RSD/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + /* return cash(balance).add(managed(balance)); */ + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance) & mask; */ + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + /* return uint256(balance >> 112) & mask; */ + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + /* return uint256(balance >> 224) & mask; */ + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + /* return (uint256(balance) & mask) == 0; */ + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + /* return !isZero(balance); */ + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + /* return _pack(_cash, _managed, _blockNumber); */ + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + /* return toBalance(newCash, currentManaged, newBlockNumber); */ + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + /* return toBalance(newCash, currentManaged, newBlockNumber); */ + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocation/original/BalanceAllocation.sol b/contracts/mutants/BalanceAllocation/original/BalanceAllocation.sol new file mode 100644 index 00000000000..f96afd1db1a --- /dev/null +++ b/contracts/mutants/BalanceAllocation/original/BalanceAllocation.sol @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../../lib/math/Math.sol"; + +// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many +// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the +// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including +// tokens that are *not* inside of the Vault. +// +// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are +// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash' +// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for +// events transferring funds to and from the asset manager. +// +// The Vault disallows the Pool's 'cash' ever becoming negative, in other words, it can never use any tokens that +// are not inside of the Vault. +// +// One of the goals of this library is to store the entire token balance in a single storage slot, which is we we use +// 112 bit unsigned integers for 'cash' and 'managed'. Since 'total' is also a 112 bit unsigned value, any combination +// of 'cash' and 'managed' that yields a 'total' that doesn't fit in that range is disallowed. +// +// The remaining 32 bits of each storage slot are used to store the most recent block number where a balance was +// updated. This can be used to implement price oracles that are resilient to 'sandwich' attacks. +// +// We could use a Solidity struct to pack these two values together in a single storage slot, but unfortunately Solidity +// only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes up a +// slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot (two +// 112 bit values), using memory is strictly less gas performant. Therefore, we do manual packing and unpacking. The +// type we use to represent these values is bytes32, as it doesn't have any arithmetic operations and therefore reduces +// the chance of misuse. +library BalanceAllocation { + using Math for uint256; + + // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the + // 'managed' part uses the most significant 112 bits. + + /** + * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed'). + */ + function total(bytes32 balance) internal pure returns (uint256) { + return cash(balance).add(managed(balance)); + } + + /** + * @dev Returns the amount of Pool tokens currently in the Vault. + */ + function cash(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance) & mask; + } + + /** + * @dev Returns the amount of Pool tokens that have been withdrawn (or reported) by its Asset Manager. + */ + function managed(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(balance >> 112) & mask; + } + + /** + * @dev Returns the last block number when a balance was updated. + */ + function blockNumber(bytes32 balance) internal pure returns (uint256) { + uint256 mask = 2**(32) - 1; + return uint256(balance >> 224) & mask; + } + + /** + * @dev Returns the total balance for each entry in `balances`. + */ + function totals(bytes32[] memory balances) internal pure returns (uint256[] memory results) { + results = new uint256[](balances.length); + for (uint256 i = 0; i < results.length; i++) { + results[i] = total(balances[i]); + } + } + + /** + * @dev Returns the total balance for each entry in `balances`, as well as the latest block number when any of them + * was last updated. + */ + function totalsAndMaxBlockNumber(bytes32[] memory balances) + internal + pure + returns (uint256[] memory results, uint256 maxBlockNumber) + { + maxBlockNumber = 0; + results = new uint256[](balances.length); + + for (uint256 i = 0; i < results.length; i++) { + bytes32 balance = balances[i]; + results[i] = total(balance); + maxBlockNumber = Math.max(maxBlockNumber, blockNumber(balance)); + } + } + + /** + * @dev Returns true if `balance`'s total balance is zero. Costs less gas than computing the total. + */ + function isZero(bytes32 balance) internal pure returns (bool) { + // We simply need to check the least significant 224 bytes of the word, the block number does not affect this. + uint256 mask = 2**(224) - 1; + return (uint256(balance) & mask) == 0; + } + + /** + * @dev Returns true if `balance`'s total balance is not zero. Costs less gas than computing the total. + */ + function isNotZero(bytes32 balance) internal pure returns (bool) { + return !isZero(balance); + } + + /** + * @dev Packs together cash and managed amounts with a block number to create a balance value. + * + * Critically, this also checks the sum of cash and external doesn't overflow, that is, that `total()` can be + * computed. + */ + function toBalance( + uint256 _cash, + uint256 _managed, + uint256 _blockNumber + ) internal pure returns (bytes32) { + uint256 balance = _cash + _managed; + require(balance >= _cash && balance < 2**112, "BALANCE_TOTAL_OVERFLOW"); + // We assume the block number will fits in an uint32 - this is expected to hold for at least a few decades. + return _pack(_cash, _managed, _blockNumber); + } + + /** + * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except + * when an Asset Manager action decreases the managed balance). + */ + function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault + * (except as an Asset Manager action that increases the managed balance). + */ + function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 currentManaged = managed(balance); + uint256 newBlockNumber = block.number; + + return toBalance(newCash, currentManaged, newBlockNumber); + } + + /** + * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when Pool tokens are sent from the Vault + * when an Asset Manager action increases the managed balance. + */ + function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).sub(amount); + uint256 newManaged = managed(balance).add(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when Pool tokens are sent to the Vault when + * an Asset Manager action decreases the managed balance. + */ + function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) { + uint256 newCash = cash(balance).add(amount); + uint256 newManaged = managed(balance).sub(amount); + uint256 currentBlockNumber = blockNumber(balance); + + return toBalance(newCash, newManaged, currentBlockNumber); + } + + /** + * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports + * profits or losses. It's the Manager's responsibility to provide a meaningful value. + */ + function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) { + uint256 currentCash = cash(balance); + uint256 newBlockNumber = block.number; + return toBalance(currentCash, newManaged, newBlockNumber); + } + + // Alternative mode for Pools with the token token specialization setting + + // Instead of storing cash and external for each token in a single storage slot, two token pools store the cash for + // both tokens in the same slot, and the external for both in another one. This reduces the gas cost for swaps, + // because the only slot that needs to be updated is the one with the cash. However, it also means that managing + // balances is more cumbersome, as both tokens need to be read/written at the same time. + // The field with both cash balances packed is called sharedCash, and the one with external amounts is called + // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion + // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part + // uses the most significant 112 bits. + // Becase only cash is written to during a swap, we store the block number there. Typically Pools have a distinct + // block number per token: in the case of two token Pools this is not necessary, as both values will be the same. + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A. + */ + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B. + */ + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) { + return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), blockNumber(sharedCash)); + } + + /** + * @dev Returns the sharedCash shared field, given the current balances for tokenA and tokenB. + */ + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + // Both balances have the block number, since both balances are always updated at the same time it does not + // mater where we pick it from. + return _pack(cash(tokenABalance), cash(tokenBBalance), blockNumber(tokenABalance)); + } + + /** + * @dev Returns the sharedManaged shared field, given the current balances for tokenA and tokenB. + */ + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) { + return _pack(managed(tokenABalance), managed(tokenBBalance), 0); + } + + /** + * @dev Unpacks the balance corresponding to token A for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance) & mask; + } + + /** + * @dev Unpacks the balance corresponding to token B for a shared balance + * Note that this function can be used to decode both cash and managed balances. + */ + function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) { + uint256 mask = 2**(112) - 1; + return uint256(sharedBalance >> 112) & mask; + } + + // Shared functions + + /** + * @dev Packs together two uint112 and one uint32 into a bytes32 + */ + function _pack( + uint256 _leastSignificant, + uint256 _midSignificant, + uint256 _mostSignificant + ) private pure returns (bytes32) { + return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/1/DLR/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/1/DLR/BalanceAllocationMock.sol new file mode 100644 index 00000000000..80d7b7419f0 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/1/DLR/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] storage balances) public pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) public pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) public pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/1/DLR/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/1/DLR/diff_result_difft.json new file mode 100644 index 00000000000..b818ae7de84 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/1/DLR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.3397829532623291, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 25, + "changes": [ + { + "start": 30, + "end": 36, + "content": "memory", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 25, + "changes": [ + { + "start": 30, + "end": 37, + "content": "storage", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/1/FVR/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/1/FVR/BalanceAllocationMock.sol new file mode 100644 index 00000000000..5d44e491584 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/1/FVR/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) external pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] memory balances) public pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) public pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) public pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/1/FVR/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/1/FVR/diff_result_difft.json new file mode 100644 index 00000000000..9b01dbcc893 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/1/FVR/diff_result_difft.json @@ -0,0 +1,32 @@ +{ + "number_of_changes": 1, + "timing": 0.19877076148986816, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 42, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 44, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/1/RSD/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/1/RSD/BalanceAllocationMock.sol new file mode 100644 index 00000000000..6779a889986 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/1/RSD/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + /* return balance.total(); */ + } + + function totals(bytes32[] memory balances) public pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) public pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) public pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/1/RSD/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/1/RSD/diff_result_difft.json new file mode 100644 index 00000000000..a9647481f93 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/1/RSD/diff_result_difft.json @@ -0,0 +1,62 @@ +{ + "number_of_changes": 6, + "timing": 0.15529417991638184, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 28, + "content": "total", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 37, + "content": "/* return balance.total(); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/10/FVR/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/10/FVR/BalanceAllocationMock.sol new file mode 100644 index 00000000000..a7712c0384d --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/10/FVR/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) external pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] memory balances) external pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) external pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) external pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) external pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) external pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) external pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) external pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) external view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) external view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/10/FVR/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/10/FVR/diff_result_difft.json new file mode 100644 index 00000000000..6aecd4390f9 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/10/FVR/diff_result_difft.json @@ -0,0 +1,248 @@ +{ + "number_of_changes": 10, + "timing": 0.1778099536895752, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 53, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 55, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 53, + "changes": [ + { + "start": 59, + "end": 65, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 53, + "changes": [ + { + "start": 59, + "end": 67, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 57, + "changes": [ + { + "start": 59, + "end": 65, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 57, + "changes": [ + { + "start": 59, + "end": 67, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 44, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 46, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 45, + "changes": [ + { + "start": 37, + "end": 43, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 45, + "changes": [ + { + "start": 37, + "end": 45, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 49, + "changes": [ + { + "start": 78, + "end": 84, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 49, + "changes": [ + { + "start": 78, + "end": 86, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 42, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 44, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 41, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 43, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 37, + "changes": [ + { + "start": 42, + "end": 48, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 37, + "changes": [ + { + "start": 42, + "end": 50, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 41, + "changes": [ + { + "start": 40, + "end": 46, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 41, + "changes": [ + { + "start": 40, + "end": 48, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/10/RSD/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/10/RSD/BalanceAllocationMock.sol new file mode 100644 index 00000000000..71b2becb25f --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/10/RSD/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + /* return balance.total(); */ + } + + function totals(bytes32[] memory balances) public pure returns (uint256[] memory) { + /* return BalanceAllocation.totals(balances); */ + } + + function cash(bytes32 balance) public pure returns (uint256) { + /* return balance.cash(); */ + } + + function managed(bytes32 balance) public pure returns (uint256) { + /* return balance.managed(); */ + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + /* return balance.blockNumber(); */ + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + /* return balance.isNotZero(); */ + } + + function isZero(bytes32 balance) public pure returns (bool) { + /* return balance.isZero(); */ + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + /* return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); */ + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + /* return balance.increaseCash(amount); */ + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + /* return balance.decreaseCash(amount); */ + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/10/RSD/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/10/RSD/diff_result_difft.json new file mode 100644 index 00000000000..3d1698ed346 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/10/RSD/diff_result_difft.json @@ -0,0 +1,596 @@ +{ + "number_of_changes": 68, + "timing": 0.2283928394317627, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 54, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 35, + "content": "increaseCash", + "highlight": "normal" + }, + { + "start": 35, + "end": 36, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 36, + "end": 42, + "content": "amount", + "highlight": "normal" + }, + { + "start": 42, + "end": 43, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 54, + "changes": [ + { + "start": 8, + "end": 50, + "content": "/* return balance.increaseCash(amount); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 30, + "content": "managed", + "highlight": "normal" + }, + { + "start": 30, + "end": 31, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 31, + "end": 32, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 39, + "content": "/* return balance.managed(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 46, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 29, + "content": "isZero", + "highlight": "normal" + }, + { + "start": 29, + "end": 30, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 30, + "end": 31, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 46, + "changes": [ + { + "start": 8, + "end": 38, + "content": "/* return balance.isZero(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 27, + "content": "cash", + "highlight": "normal" + }, + { + "start": 27, + "end": 28, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 28, + "end": 29, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 36, + "content": "/* return balance.cash(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 38, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 34, + "content": "blockNumber", + "highlight": "normal" + }, + { + "start": 34, + "end": 35, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 35, + "end": 36, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 38, + "changes": [ + { + "start": 8, + "end": 43, + "content": "/* return balance.blockNumber(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 58, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 35, + "content": "decreaseCash", + "highlight": "normal" + }, + { + "start": 35, + "end": 36, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 36, + "end": 42, + "content": "amount", + "highlight": "normal" + }, + { + "start": 42, + "end": 43, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 58, + "changes": [ + { + "start": 8, + "end": 50, + "content": "/* return balance.decreaseCash(amount); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 32, + "content": "BalanceAllocation", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "totals", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 40, + "end": 48, + "content": "balances", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* return BalanceAllocation.totals(balances); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 50, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 32, + "content": "BalanceAllocation", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 42, + "content": "toBalance", + "highlight": "normal" + }, + { + "start": 42, + "end": 43, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 43, + "end": 48, + "content": "_cash", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ",", + "highlight": "normal" + }, + { + "start": 50, + "end": 58, + "content": "_managed", + "highlight": "normal" + }, + { + "start": 58, + "end": 59, + "content": ",", + "highlight": "normal" + }, + { + "start": 60, + "end": 72, + "content": "_blockNumber", + "highlight": "normal" + }, + { + "start": 72, + "end": 73, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 50, + "changes": [ + { + "start": 8, + "end": 80, + "content": "/* return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 42, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 32, + "content": "isNotZero", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 33, + "end": 34, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 42, + "changes": [ + { + "start": 8, + "end": 41, + "content": "/* return balance.isNotZero(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 28, + "content": "total", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 37, + "content": "/* return balance.total(); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/2/DLR/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/2/DLR/BalanceAllocationMock.sol new file mode 100644 index 00000000000..c97d1c01560 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/2/DLR/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] storage balances) public pure returns (uint256[] storage) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) public pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) public pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/2/DLR/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/2/DLR/diff_result_difft.json new file mode 100644 index 00000000000..facc83e18df --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/2/DLR/diff_result_difft.json @@ -0,0 +1,44 @@ +{ + "number_of_changes": 2, + "timing": 0.15073800086975098, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 25, + "changes": [ + { + "start": 30, + "end": 36, + "content": "memory", + "highlight": "keyword" + }, + { + "start": 78, + "end": 84, + "content": "memory", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 25, + "changes": [ + { + "start": 30, + "end": 37, + "content": "storage", + "highlight": "keyword" + }, + { + "start": 79, + "end": 86, + "content": "storage", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/2/FVR/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/2/FVR/BalanceAllocationMock.sol new file mode 100644 index 00000000000..f6813cda2e4 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/2/FVR/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) external pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] memory balances) external pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) public pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) public pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/2/FVR/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/2/FVR/diff_result_difft.json new file mode 100644 index 00000000000..1773480a395 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/2/FVR/diff_result_difft.json @@ -0,0 +1,56 @@ +{ + "number_of_changes": 2, + "timing": 0.11944246292114258, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 42, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 44, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 53, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 55, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/2/RSD/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/2/RSD/BalanceAllocationMock.sol new file mode 100644 index 00000000000..1e9dd035be5 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/2/RSD/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + /* return balance.total(); */ + } + + function totals(bytes32[] memory balances) public pure returns (uint256[] memory) { + /* return BalanceAllocation.totals(balances); */ + } + + function cash(bytes32 balance) public pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) public pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/2/RSD/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/2/RSD/diff_result_difft.json new file mode 100644 index 00000000000..273241ff5c5 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/2/RSD/diff_result_difft.json @@ -0,0 +1,122 @@ +{ + "number_of_changes": 13, + "timing": 0.1296672821044922, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 32, + "content": "BalanceAllocation", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "totals", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 40, + "end": 48, + "content": "balances", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* return BalanceAllocation.totals(balances); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 28, + "content": "total", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 37, + "content": "/* return balance.total(); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/3/FVR/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/3/FVR/BalanceAllocationMock.sol new file mode 100644 index 00000000000..411c5a55074 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/3/FVR/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) external pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] memory balances) external pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) external pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) public pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/3/FVR/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/3/FVR/diff_result_difft.json new file mode 100644 index 00000000000..30bf8047c4c --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/3/FVR/diff_result_difft.json @@ -0,0 +1,80 @@ +{ + "number_of_changes": 3, + "timing": 0.09284257888793945, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 53, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 55, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 41, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 43, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 42, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 44, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/3/RSD/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/3/RSD/BalanceAllocationMock.sol new file mode 100644 index 00000000000..b93e4416298 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/3/RSD/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + /* return balance.total(); */ + } + + function totals(bytes32[] memory balances) public pure returns (uint256[] memory) { + /* return BalanceAllocation.totals(balances); */ + } + + function cash(bytes32 balance) public pure returns (uint256) { + /* return balance.cash(); */ + } + + function managed(bytes32 balance) public pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/3/RSD/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/3/RSD/diff_result_difft.json new file mode 100644 index 00000000000..1645eaa74d2 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/3/RSD/diff_result_difft.json @@ -0,0 +1,176 @@ +{ + "number_of_changes": 19, + "timing": 0.14673686027526855, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 27, + "content": "cash", + "highlight": "normal" + }, + { + "start": 27, + "end": 28, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 28, + "end": 29, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 36, + "content": "/* return balance.cash(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 28, + "content": "total", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 37, + "content": "/* return balance.total(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 32, + "content": "BalanceAllocation", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "totals", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 40, + "end": 48, + "content": "balances", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* return BalanceAllocation.totals(balances); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/4/FVR/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/4/FVR/BalanceAllocationMock.sol new file mode 100644 index 00000000000..f320b5e1c02 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/4/FVR/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) external pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] memory balances) external pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) external pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) external pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/4/FVR/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/4/FVR/diff_result_difft.json new file mode 100644 index 00000000000..fc1935ee9e8 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/4/FVR/diff_result_difft.json @@ -0,0 +1,104 @@ +{ + "number_of_changes": 4, + "timing": 0.30687594413757324, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 44, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 46, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 53, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 55, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 42, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 44, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 41, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 43, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/4/RSD/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/4/RSD/BalanceAllocationMock.sol new file mode 100644 index 00000000000..e7e3106a874 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/4/RSD/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + /* return balance.total(); */ + } + + function totals(bytes32[] memory balances) public pure returns (uint256[] memory) { + /* return BalanceAllocation.totals(balances); */ + } + + function cash(bytes32 balance) public pure returns (uint256) { + /* return balance.cash(); */ + } + + function managed(bytes32 balance) public pure returns (uint256) { + /* return balance.managed(); */ + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/4/RSD/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/4/RSD/diff_result_difft.json new file mode 100644 index 00000000000..e580aee70df --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/4/RSD/diff_result_difft.json @@ -0,0 +1,230 @@ +{ + "number_of_changes": 25, + "timing": 0.09148788452148438, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 30, + "content": "managed", + "highlight": "normal" + }, + { + "start": 30, + "end": 31, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 31, + "end": 32, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 39, + "content": "/* return balance.managed(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 28, + "content": "total", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 37, + "content": "/* return balance.total(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 32, + "content": "BalanceAllocation", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "totals", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 40, + "end": 48, + "content": "balances", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* return BalanceAllocation.totals(balances); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 27, + "content": "cash", + "highlight": "normal" + }, + { + "start": 27, + "end": 28, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 28, + "end": 29, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 36, + "content": "/* return balance.cash(); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/5/FVR/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/5/FVR/BalanceAllocationMock.sol new file mode 100644 index 00000000000..0be6df38725 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/5/FVR/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) external pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] memory balances) external pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) external pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) external pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) external pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/5/FVR/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/5/FVR/diff_result_difft.json new file mode 100644 index 00000000000..40a939ce5bf --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/5/FVR/diff_result_difft.json @@ -0,0 +1,128 @@ +{ + "number_of_changes": 5, + "timing": 0.08070826530456543, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 37, + "changes": [ + { + "start": 42, + "end": 48, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 37, + "changes": [ + { + "start": 42, + "end": 50, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 42, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 44, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 41, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 43, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 53, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 55, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 44, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 46, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/5/RSD/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/5/RSD/BalanceAllocationMock.sol new file mode 100644 index 00000000000..a764dee8104 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/5/RSD/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + /* return balance.total(); */ + } + + function totals(bytes32[] memory balances) public pure returns (uint256[] memory) { + /* return BalanceAllocation.totals(balances); */ + } + + function cash(bytes32 balance) public pure returns (uint256) { + /* return balance.cash(); */ + } + + function managed(bytes32 balance) public pure returns (uint256) { + /* return balance.managed(); */ + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + /* return balance.blockNumber(); */ + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/5/RSD/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/5/RSD/diff_result_difft.json new file mode 100644 index 00000000000..7e7c05a06ff --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/5/RSD/diff_result_difft.json @@ -0,0 +1,284 @@ +{ + "number_of_changes": 31, + "timing": 0.2856729030609131, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 38, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 34, + "content": "blockNumber", + "highlight": "normal" + }, + { + "start": 34, + "end": 35, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 35, + "end": 36, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 38, + "changes": [ + { + "start": 8, + "end": 43, + "content": "/* return balance.blockNumber(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 32, + "content": "BalanceAllocation", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "totals", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 40, + "end": 48, + "content": "balances", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* return BalanceAllocation.totals(balances); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 28, + "content": "total", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 37, + "content": "/* return balance.total(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 27, + "content": "cash", + "highlight": "normal" + }, + { + "start": 27, + "end": 28, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 28, + "end": 29, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 36, + "content": "/* return balance.cash(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 30, + "content": "managed", + "highlight": "normal" + }, + { + "start": 30, + "end": 31, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 31, + "end": 32, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 39, + "content": "/* return balance.managed(); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/6/FVR/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/6/FVR/BalanceAllocationMock.sol new file mode 100644 index 00000000000..a390e4a8b09 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/6/FVR/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) external pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] memory balances) external pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) external pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) external pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) external pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) external pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/6/FVR/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/6/FVR/diff_result_difft.json new file mode 100644 index 00000000000..2e2e381a426 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/6/FVR/diff_result_difft.json @@ -0,0 +1,152 @@ +{ + "number_of_changes": 6, + "timing": 0.1405506134033203, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 42, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 44, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 41, + "changes": [ + { + "start": 40, + "end": 46, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 41, + "changes": [ + { + "start": 40, + "end": 48, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 53, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 55, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 41, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 43, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 44, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 46, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 37, + "changes": [ + { + "start": 42, + "end": 48, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 37, + "changes": [ + { + "start": 42, + "end": 50, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/6/RSD/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/6/RSD/BalanceAllocationMock.sol new file mode 100644 index 00000000000..9a5ebb7ee1f --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/6/RSD/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + /* return balance.total(); */ + } + + function totals(bytes32[] memory balances) public pure returns (uint256[] memory) { + /* return BalanceAllocation.totals(balances); */ + } + + function cash(bytes32 balance) public pure returns (uint256) { + /* return balance.cash(); */ + } + + function managed(bytes32 balance) public pure returns (uint256) { + /* return balance.managed(); */ + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + /* return balance.blockNumber(); */ + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + /* return balance.isNotZero(); */ + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/6/RSD/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/6/RSD/diff_result_difft.json new file mode 100644 index 00000000000..d0c798a8adc --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/6/RSD/diff_result_difft.json @@ -0,0 +1,338 @@ +{ + "number_of_changes": 37, + "timing": 0.1805250644683838, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 30, + "content": "managed", + "highlight": "normal" + }, + { + "start": 30, + "end": 31, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 31, + "end": 32, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 39, + "content": "/* return balance.managed(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 32, + "content": "BalanceAllocation", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "totals", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 40, + "end": 48, + "content": "balances", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* return BalanceAllocation.totals(balances); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 38, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 34, + "content": "blockNumber", + "highlight": "normal" + }, + { + "start": 34, + "end": 35, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 35, + "end": 36, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 38, + "changes": [ + { + "start": 8, + "end": 43, + "content": "/* return balance.blockNumber(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 28, + "content": "total", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 37, + "content": "/* return balance.total(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 27, + "content": "cash", + "highlight": "normal" + }, + { + "start": 27, + "end": 28, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 28, + "end": 29, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 36, + "content": "/* return balance.cash(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 42, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 32, + "content": "isNotZero", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 33, + "end": 34, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 42, + "changes": [ + { + "start": 8, + "end": 41, + "content": "/* return balance.isNotZero(); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/7/FVR/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/7/FVR/BalanceAllocationMock.sol new file mode 100644 index 00000000000..3de197c7c4f --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/7/FVR/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) external pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] memory balances) external pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) external pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) external pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) external pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) external pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) external pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/7/FVR/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/7/FVR/diff_result_difft.json new file mode 100644 index 00000000000..d4ebc637d44 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/7/FVR/diff_result_difft.json @@ -0,0 +1,176 @@ +{ + "number_of_changes": 7, + "timing": 0.15514564514160156, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 37, + "changes": [ + { + "start": 42, + "end": 48, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 37, + "changes": [ + { + "start": 42, + "end": 50, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 41, + "changes": [ + { + "start": 40, + "end": 46, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 41, + "changes": [ + { + "start": 40, + "end": 48, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 45, + "changes": [ + { + "start": 37, + "end": 43, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 45, + "changes": [ + { + "start": 37, + "end": 45, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 41, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 43, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 44, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 46, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 53, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 55, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 42, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 44, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/7/RSD/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/7/RSD/BalanceAllocationMock.sol new file mode 100644 index 00000000000..75bc06b86bb --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/7/RSD/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + /* return balance.total(); */ + } + + function totals(bytes32[] memory balances) public pure returns (uint256[] memory) { + /* return BalanceAllocation.totals(balances); */ + } + + function cash(bytes32 balance) public pure returns (uint256) { + /* return balance.cash(); */ + } + + function managed(bytes32 balance) public pure returns (uint256) { + /* return balance.managed(); */ + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + /* return balance.blockNumber(); */ + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + /* return balance.isNotZero(); */ + } + + function isZero(bytes32 balance) public pure returns (bool) { + /* return balance.isZero(); */ + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/7/RSD/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/7/RSD/diff_result_difft.json new file mode 100644 index 00000000000..076f00b795f --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/7/RSD/diff_result_difft.json @@ -0,0 +1,392 @@ +{ + "number_of_changes": 43, + "timing": 0.3377070426940918, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 42, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 32, + "content": "isNotZero", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 33, + "end": 34, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 42, + "changes": [ + { + "start": 8, + "end": 41, + "content": "/* return balance.isNotZero(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 30, + "content": "managed", + "highlight": "normal" + }, + { + "start": 30, + "end": 31, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 31, + "end": 32, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 39, + "content": "/* return balance.managed(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 28, + "content": "total", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 37, + "content": "/* return balance.total(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 38, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 34, + "content": "blockNumber", + "highlight": "normal" + }, + { + "start": 34, + "end": 35, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 35, + "end": 36, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 38, + "changes": [ + { + "start": 8, + "end": 43, + "content": "/* return balance.blockNumber(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 27, + "content": "cash", + "highlight": "normal" + }, + { + "start": 27, + "end": 28, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 28, + "end": 29, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 36, + "content": "/* return balance.cash(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 46, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 29, + "content": "isZero", + "highlight": "normal" + }, + { + "start": 29, + "end": 30, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 30, + "end": 31, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 46, + "changes": [ + { + "start": 8, + "end": 38, + "content": "/* return balance.isZero(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 32, + "content": "BalanceAllocation", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "totals", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 40, + "end": 48, + "content": "balances", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* return BalanceAllocation.totals(balances); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/8/FVR/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/8/FVR/BalanceAllocationMock.sol new file mode 100644 index 00000000000..2d8dc213d58 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/8/FVR/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) external pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] memory balances) external pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) external pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) external pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) external pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) external pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) external pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) external pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/8/FVR/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/8/FVR/diff_result_difft.json new file mode 100644 index 00000000000..116c697a59b --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/8/FVR/diff_result_difft.json @@ -0,0 +1,200 @@ +{ + "number_of_changes": 8, + "timing": 0.2854752540588379, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 45, + "changes": [ + { + "start": 37, + "end": 43, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 45, + "changes": [ + { + "start": 37, + "end": 45, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 41, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 43, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 42, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 44, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 53, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 55, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 37, + "changes": [ + { + "start": 42, + "end": 48, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 37, + "changes": [ + { + "start": 42, + "end": 50, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 49, + "changes": [ + { + "start": 78, + "end": 84, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 49, + "changes": [ + { + "start": 78, + "end": 86, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 44, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 46, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 41, + "changes": [ + { + "start": 40, + "end": 46, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 41, + "changes": [ + { + "start": 40, + "end": 48, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/8/RSD/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/8/RSD/BalanceAllocationMock.sol new file mode 100644 index 00000000000..e2854720715 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/8/RSD/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + /* return balance.total(); */ + } + + function totals(bytes32[] memory balances) public pure returns (uint256[] memory) { + /* return BalanceAllocation.totals(balances); */ + } + + function cash(bytes32 balance) public pure returns (uint256) { + /* return balance.cash(); */ + } + + function managed(bytes32 balance) public pure returns (uint256) { + /* return balance.managed(); */ + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + /* return balance.blockNumber(); */ + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + /* return balance.isNotZero(); */ + } + + function isZero(bytes32 balance) public pure returns (bool) { + /* return balance.isZero(); */ + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + /* return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); */ + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/8/RSD/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/8/RSD/diff_result_difft.json new file mode 100644 index 00000000000..d5e310158f1 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/8/RSD/diff_result_difft.json @@ -0,0 +1,476 @@ +{ + "number_of_changes": 54, + "timing": 0.2659950256347656, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 46, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 29, + "content": "isZero", + "highlight": "normal" + }, + { + "start": 29, + "end": 30, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 30, + "end": 31, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 46, + "changes": [ + { + "start": 8, + "end": 38, + "content": "/* return balance.isZero(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 38, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 34, + "content": "blockNumber", + "highlight": "normal" + }, + { + "start": 34, + "end": 35, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 35, + "end": 36, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 38, + "changes": [ + { + "start": 8, + "end": 43, + "content": "/* return balance.blockNumber(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 28, + "content": "total", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 37, + "content": "/* return balance.total(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 30, + "content": "managed", + "highlight": "normal" + }, + { + "start": 30, + "end": 31, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 31, + "end": 32, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 39, + "content": "/* return balance.managed(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 42, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 32, + "content": "isNotZero", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 33, + "end": 34, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 42, + "changes": [ + { + "start": 8, + "end": 41, + "content": "/* return balance.isNotZero(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 50, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 32, + "content": "BalanceAllocation", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 42, + "content": "toBalance", + "highlight": "normal" + }, + { + "start": 42, + "end": 43, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 43, + "end": 48, + "content": "_cash", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ",", + "highlight": "normal" + }, + { + "start": 50, + "end": 58, + "content": "_managed", + "highlight": "normal" + }, + { + "start": 58, + "end": 59, + "content": ",", + "highlight": "normal" + }, + { + "start": 60, + "end": 72, + "content": "_blockNumber", + "highlight": "normal" + }, + { + "start": 72, + "end": 73, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 50, + "changes": [ + { + "start": 8, + "end": 80, + "content": "/* return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 32, + "content": "BalanceAllocation", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "totals", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 40, + "end": 48, + "content": "balances", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* return BalanceAllocation.totals(balances); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 27, + "content": "cash", + "highlight": "normal" + }, + { + "start": 27, + "end": 28, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 28, + "end": 29, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 36, + "content": "/* return balance.cash(); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/9/FVR/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/9/FVR/BalanceAllocationMock.sol new file mode 100644 index 00000000000..45d85e179e6 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/9/FVR/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) external pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] memory balances) external pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) external pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) external pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) external pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) external pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) external pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) external pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) external view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/9/FVR/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/9/FVR/diff_result_difft.json new file mode 100644 index 00000000000..be12f736289 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/9/FVR/diff_result_difft.json @@ -0,0 +1,224 @@ +{ + "number_of_changes": 9, + "timing": 0.13638520240783691, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 44, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 33, + "changes": [ + { + "start": 38, + "end": 46, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 45, + "changes": [ + { + "start": 37, + "end": 43, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 45, + "changes": [ + { + "start": 37, + "end": 45, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 42, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 21, + "changes": [ + { + "start": 36, + "end": 44, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 41, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 29, + "changes": [ + { + "start": 35, + "end": 43, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 49, + "changes": [ + { + "start": 78, + "end": 84, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 49, + "changes": [ + { + "start": 78, + "end": 86, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 53, + "changes": [ + { + "start": 59, + "end": 65, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 53, + "changes": [ + { + "start": 59, + "end": 67, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 37, + "changes": [ + { + "start": 42, + "end": 48, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 37, + "changes": [ + { + "start": 42, + "end": 50, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 53, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 25, + "changes": [ + { + "start": 47, + "end": 55, + "content": "external", + "highlight": "keyword" + } + ] + } + }, + { + "lhs": { + "line_number": 41, + "changes": [ + { + "start": 40, + "end": 46, + "content": "public", + "highlight": "keyword" + } + ] + }, + "rhs": { + "line_number": 41, + "changes": [ + { + "start": 40, + "end": 48, + "content": "external", + "highlight": "keyword" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/9/RSD/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/9/RSD/BalanceAllocationMock.sol new file mode 100644 index 00000000000..2aa49330ff1 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/9/RSD/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + /* return balance.total(); */ + } + + function totals(bytes32[] memory balances) public pure returns (uint256[] memory) { + /* return BalanceAllocation.totals(balances); */ + } + + function cash(bytes32 balance) public pure returns (uint256) { + /* return balance.cash(); */ + } + + function managed(bytes32 balance) public pure returns (uint256) { + /* return balance.managed(); */ + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + /* return balance.blockNumber(); */ + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + /* return balance.isNotZero(); */ + } + + function isZero(bytes32 balance) public pure returns (bool) { + /* return balance.isZero(); */ + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + /* return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); */ + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + /* return balance.increaseCash(amount); */ + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceAllocationMock/9/RSD/diff_result_difft.json b/contracts/mutants/BalanceAllocationMock/9/RSD/diff_result_difft.json new file mode 100644 index 00000000000..248a43db1d0 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/9/RSD/diff_result_difft.json @@ -0,0 +1,536 @@ +{ + "number_of_changes": 61, + "timing": 0.29120588302612305, + "diff_chunks": [ + [ + { + "lhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 28, + "content": "total", + "highlight": "normal" + }, + { + "start": 28, + "end": 29, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 29, + "end": 30, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 22, + "changes": [ + { + "start": 8, + "end": 37, + "content": "/* return balance.total(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 32, + "content": "BalanceAllocation", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 39, + "content": "totals", + "highlight": "normal" + }, + { + "start": 39, + "end": 40, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 40, + "end": 48, + "content": "balances", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 26, + "changes": [ + { + "start": 8, + "end": 56, + "content": "/* return BalanceAllocation.totals(balances); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 50, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 32, + "content": "BalanceAllocation", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": ".", + "highlight": "normal" + }, + { + "start": 33, + "end": 42, + "content": "toBalance", + "highlight": "normal" + }, + { + "start": 42, + "end": 43, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 43, + "end": 48, + "content": "_cash", + "highlight": "normal" + }, + { + "start": 48, + "end": 49, + "content": ",", + "highlight": "normal" + }, + { + "start": 50, + "end": 58, + "content": "_managed", + "highlight": "normal" + }, + { + "start": 58, + "end": 59, + "content": ",", + "highlight": "normal" + }, + { + "start": 60, + "end": 72, + "content": "_blockNumber", + "highlight": "normal" + }, + { + "start": 72, + "end": 73, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 50, + "changes": [ + { + "start": 8, + "end": 80, + "content": "/* return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 54, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 35, + "content": "increaseCash", + "highlight": "normal" + }, + { + "start": 35, + "end": 36, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 36, + "end": 42, + "content": "amount", + "highlight": "normal" + }, + { + "start": 42, + "end": 43, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 54, + "changes": [ + { + "start": 8, + "end": 50, + "content": "/* return balance.increaseCash(amount); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 46, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 29, + "content": "isZero", + "highlight": "normal" + }, + { + "start": 29, + "end": 30, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 30, + "end": 31, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 46, + "changes": [ + { + "start": 8, + "end": 38, + "content": "/* return balance.isZero(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 27, + "content": "cash", + "highlight": "normal" + }, + { + "start": 27, + "end": 28, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 28, + "end": 29, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 30, + "changes": [ + { + "start": 8, + "end": 36, + "content": "/* return balance.cash(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 30, + "content": "managed", + "highlight": "normal" + }, + { + "start": 30, + "end": 31, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 31, + "end": 32, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 34, + "changes": [ + { + "start": 8, + "end": 39, + "content": "/* return balance.managed(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 42, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 32, + "content": "isNotZero", + "highlight": "normal" + }, + { + "start": 32, + "end": 33, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 33, + "end": 34, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 42, + "changes": [ + { + "start": 8, + "end": 41, + "content": "/* return balance.isNotZero(); */", + "highlight": "comment" + } + ] + } + }, + { + "lhs": { + "line_number": 38, + "changes": [ + { + "start": 8, + "end": 14, + "content": "return", + "highlight": "keyword" + }, + { + "start": 15, + "end": 22, + "content": "balance", + "highlight": "normal" + }, + { + "start": 22, + "end": 23, + "content": ".", + "highlight": "normal" + }, + { + "start": 23, + "end": 34, + "content": "blockNumber", + "highlight": "normal" + }, + { + "start": 34, + "end": 35, + "content": "(", + "highlight": "delimiter" + }, + { + "start": 35, + "end": 36, + "content": ")", + "highlight": "delimiter" + } + ] + }, + "rhs": { + "line_number": 38, + "changes": [ + { + "start": 8, + "end": 43, + "content": "/* return balance.blockNumber(); */", + "highlight": "comment" + } + ] + } + } + ] + ] +} \ No newline at end of file diff --git a/contracts/mutants/BalanceAllocationMock/original/BalanceAllocationMock.sol b/contracts/mutants/BalanceAllocationMock/original/BalanceAllocationMock.sol new file mode 100644 index 00000000000..a7a260af2a3 --- /dev/null +++ b/contracts/mutants/BalanceAllocationMock/original/BalanceAllocationMock.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.7.0; + +import "../vault/balances/BalanceAllocation.sol"; + +contract BalanceAllocationMock { + using BalanceAllocation for bytes32; + + function total(bytes32 balance) public pure returns (uint256) { + return balance.total(); + } + + function totals(bytes32[] memory balances) public pure returns (uint256[] memory) { + return BalanceAllocation.totals(balances); + } + + function cash(bytes32 balance) public pure returns (uint256) { + return balance.cash(); + } + + function managed(bytes32 balance) public pure returns (uint256) { + return balance.managed(); + } + + function blockNumber(bytes32 balance) public pure returns (uint256) { + return balance.blockNumber(); + } + + function isNotZero(bytes32 balance) public pure returns (bool) { + return balance.isNotZero(); + } + + function isZero(bytes32 balance) public pure returns (bool) { + return balance.isZero(); + } + + function toBalance(uint256 _cash, uint256 _managed, uint256 _blockNumber) public pure returns (bytes32) { + return BalanceAllocation.toBalance(_cash, _managed, _blockNumber); + } + + function increaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.increaseCash(amount); + } + + function decreaseCash(bytes32 balance, uint256 amount) public view returns (bytes32) { + return balance.decreaseCash(amount); + } + + function cashToManaged(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.cashToManaged(amount); + } + + function managedToCash(bytes32 balance, uint256 amount) public pure returns (bytes32) { + return balance.managedToCash(amount); + } + + function setManaged(bytes32 balance, uint256 newManaged) public view returns (bytes32) { + return balance.setManaged(newManaged); + } + + function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged); + } + + function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) public pure returns (bytes32) { + return BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged); + } + + function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedCash(tokenABalance, tokenBBalance); + } + + function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) public pure returns (bytes32) { + return BalanceAllocation.toSharedManaged(tokenABalance, tokenBBalance); + } +} diff --git a/contracts/mutants/BalanceDrip/1/BOR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/1/BOR/BalanceDrip.sol new file mode 100644 index 00000000000..eb62c738465 --- /dev/null +++ b/contracts/mutants/BalanceDrip/1/BOR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp <= uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/1/CSC/BalanceDrip.sol b/contracts/mutants/BalanceDrip/1/CSC/BalanceDrip.sol new file mode 100644 index 00000000000..117cf3a82b9 --- /dev/null +++ b/contracts/mutants/BalanceDrip/1/CSC/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (true) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/1/DLR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/1/DLR/BalanceDrip.sol new file mode 100644 index 00000000000..3b29ba8cca9 --- /dev/null +++ b/contracts/mutants/BalanceDrip/1/DLR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State memory self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/1/ECS/BalanceDrip.sol b/contracts/mutants/BalanceDrip/1/ECS/BalanceDrip.sol new file mode 100644 index 00000000000..8757efe35fe --- /dev/null +++ b/contracts/mutants/BalanceDrip/1/ECS/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint8(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/1/FVR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/1/FVR/BalanceDrip.sol new file mode 100644 index 00000000000..103c398d606 --- /dev/null +++ b/contracts/mutants/BalanceDrip/1/FVR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) public returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/1/ILR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/1/ILR/BalanceDrip.sol new file mode 100644 index 00000000000..9394f51abe5 --- /dev/null +++ b/contracts/mutants/BalanceDrip/1/ILR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 1; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/1/RSD/BalanceDrip.sol b/contracts/mutants/BalanceDrip/1/RSD/BalanceDrip.sol new file mode 100644 index 00000000000..8be16b4946d --- /dev/null +++ b/contracts/mutants/BalanceDrip/1/RSD/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + /* return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); */ + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/1/SFR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/1/SFR/BalanceDrip.sol new file mode 100644 index 00000000000..863e14d05e0 --- /dev/null +++ b/contracts/mutants/BalanceDrip/1/SFR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.add(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/2/BOR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/2/BOR/BalanceDrip.sol new file mode 100644 index 00000000000..b21c07b8f41 --- /dev/null +++ b/contracts/mutants/BalanceDrip/2/BOR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp <= uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp <= 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/2/CSC/BalanceDrip.sol b/contracts/mutants/BalanceDrip/2/CSC/BalanceDrip.sol new file mode 100644 index 00000000000..54639d85954 --- /dev/null +++ b/contracts/mutants/BalanceDrip/2/CSC/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (true) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (true) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/2/DLR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/2/DLR/BalanceDrip.sol new file mode 100644 index 00000000000..4ba3e922d9a --- /dev/null +++ b/contracts/mutants/BalanceDrip/2/DLR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State memory self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State memory self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/2/ECS/BalanceDrip.sol b/contracts/mutants/BalanceDrip/2/ECS/BalanceDrip.sol new file mode 100644 index 00000000000..978c4e7968e --- /dev/null +++ b/contracts/mutants/BalanceDrip/2/ECS/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint8(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint8(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/2/FVR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/2/FVR/BalanceDrip.sol new file mode 100644 index 00000000000..512f3d0bcd9 --- /dev/null +++ b/contracts/mutants/BalanceDrip/2/FVR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) public returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) public { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/2/ILR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/2/ILR/BalanceDrip.sol new file mode 100644 index 00000000000..f7403c3a27b --- /dev/null +++ b/contracts/mutants/BalanceDrip/2/ILR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 1; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 1; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/2/RSD/BalanceDrip.sol b/contracts/mutants/BalanceDrip/2/RSD/BalanceDrip.sol new file mode 100644 index 00000000000..e16131fa462 --- /dev/null +++ b/contracts/mutants/BalanceDrip/2/RSD/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + /* return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); */ + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + /* return 0; */ + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/2/SFR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/2/SFR/BalanceDrip.sol new file mode 100644 index 00000000000..c944a0a41f5 --- /dev/null +++ b/contracts/mutants/BalanceDrip/2/SFR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.add(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.add(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/3/BOR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/3/BOR/BalanceDrip.sol new file mode 100644 index 00000000000..432852f6ba8 --- /dev/null +++ b/contracts/mutants/BalanceDrip/3/BOR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp <= uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp <= 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa <= 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/3/CSC/BalanceDrip.sol b/contracts/mutants/BalanceDrip/3/CSC/BalanceDrip.sol new file mode 100644 index 00000000000..c56aac643c6 --- /dev/null +++ b/contracts/mutants/BalanceDrip/3/CSC/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (true) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (true) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (true) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/3/DLR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/3/DLR/BalanceDrip.sol new file mode 100644 index 00000000000..09f6af4fbde --- /dev/null +++ b/contracts/mutants/BalanceDrip/3/DLR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State memory self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State memory self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State memory self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/3/ECS/BalanceDrip.sol b/contracts/mutants/BalanceDrip/3/ECS/BalanceDrip.sol new file mode 100644 index 00000000000..20626b3952d --- /dev/null +++ b/contracts/mutants/BalanceDrip/3/ECS/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint8(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint8(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint8(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/3/FVR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/3/FVR/BalanceDrip.sol new file mode 100644 index 00000000000..5e01b3994ca --- /dev/null +++ b/contracts/mutants/BalanceDrip/3/FVR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) public returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) public { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) public returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/3/ILR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/3/ILR/BalanceDrip.sol new file mode 100644 index 00000000000..65f8f3a0c86 --- /dev/null +++ b/contracts/mutants/BalanceDrip/3/ILR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 1; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 1; + } + + uint256 lastTime = self.timestamp == 1 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/3/RSD/BalanceDrip.sol b/contracts/mutants/BalanceDrip/3/RSD/BalanceDrip.sol new file mode 100644 index 00000000000..e6232cf8081 --- /dev/null +++ b/contracts/mutants/BalanceDrip/3/RSD/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + /* return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); */ + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + /* return 0; */ + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + /* return newTokens; */ + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/3/SFR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/3/SFR/BalanceDrip.sol new file mode 100644 index 00000000000..86d332e6983 --- /dev/null +++ b/contracts/mutants/BalanceDrip/3/SFR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.add(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.add(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).sub(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/4/BOR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/4/BOR/BalanceDrip.sol new file mode 100644 index 00000000000..beb3a4d18cd --- /dev/null +++ b/contracts/mutants/BalanceDrip/4/BOR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp <= uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp <= 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa <= 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds >= 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/4/CSC/BalanceDrip.sol b/contracts/mutants/BalanceDrip/4/CSC/BalanceDrip.sol new file mode 100644 index 00000000000..8828753a969 --- /dev/null +++ b/contracts/mutants/BalanceDrip/4/CSC/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (true) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (true) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (true) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (true) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/4/DLR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/4/DLR/BalanceDrip.sol new file mode 100644 index 00000000000..a208bb09ccb --- /dev/null +++ b/contracts/mutants/BalanceDrip/4/DLR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State memory self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State memory self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State memory self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State memory self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/4/ECS/BalanceDrip.sol b/contracts/mutants/BalanceDrip/4/ECS/BalanceDrip.sol new file mode 100644 index 00000000000..835bbb3cfca --- /dev/null +++ b/contracts/mutants/BalanceDrip/4/ECS/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint8(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint8(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint8(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint8(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/4/FVR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/4/FVR/BalanceDrip.sol new file mode 100644 index 00000000000..6708317ce73 --- /dev/null +++ b/contracts/mutants/BalanceDrip/4/FVR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) public returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) public { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) public returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) public returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/4/ILR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/4/ILR/BalanceDrip.sol new file mode 100644 index 00000000000..f06eca057d6 --- /dev/null +++ b/contracts/mutants/BalanceDrip/4/ILR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 1; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 1; + } + + uint256 lastTime = self.timestamp == 1 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 1 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/4/RSD/BalanceDrip.sol b/contracts/mutants/BalanceDrip/4/RSD/BalanceDrip.sol new file mode 100644 index 00000000000..443315fa11f --- /dev/null +++ b/contracts/mutants/BalanceDrip/4/RSD/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + /* return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); */ + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + /* return 0; */ + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + /* return newTokens; */ + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + /* return newTokens; */ + } +} diff --git a/contracts/mutants/BalanceDrip/4/SFR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/4/SFR/BalanceDrip.sol new file mode 100644 index 00000000000..651e9645401 --- /dev/null +++ b/contracts/mutants/BalanceDrip/4/SFR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.add(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.add(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).sub(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).sub(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/5/BOR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/5/BOR/BalanceDrip.sol new file mode 100644 index 00000000000..239f9be060d --- /dev/null +++ b/contracts/mutants/BalanceDrip/5/BOR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp <= uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp <= 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa <= 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds >= 0 || self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/5/DLR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/5/DLR/BalanceDrip.sol new file mode 100644 index 00000000000..f8fdaa1b292 --- /dev/null +++ b/contracts/mutants/BalanceDrip/5/DLR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State memory self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State memory self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State memory self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State memory self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState memory userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/5/ILR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/5/ILR/BalanceDrip.sol new file mode 100644 index 00000000000..017cb06e28b --- /dev/null +++ b/contracts/mutants/BalanceDrip/5/ILR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 1; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 1; + } + + uint256 lastTime = self.timestamp == 1 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 1 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 1 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/5/SFR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/5/SFR/BalanceDrip.sol new file mode 100644 index 00000000000..3ef80dc5100 --- /dev/null +++ b/contracts/mutants/BalanceDrip/5/SFR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.add(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.add(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).sub(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).sub(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).add(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/6/BOR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/6/BOR/BalanceDrip.sol new file mode 100644 index 00000000000..83651f2e952 --- /dev/null +++ b/contracts/mutants/BalanceDrip/6/BOR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp <= uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp <= 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa <= 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds >= 0 || self.dripRatePerSecond >= 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/6/ILR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/6/ILR/BalanceDrip.sol new file mode 100644 index 00000000000..3ce7c475252 --- /dev/null +++ b/contracts/mutants/BalanceDrip/6/ILR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 1; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 1; + } + + uint256 lastTime = self.timestamp == 1 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 1 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 1 && self.dripRatePerSecond > 1) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/7/BOR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/7/BOR/BalanceDrip.sol new file mode 100644 index 00000000000..70a5e54f15e --- /dev/null +++ b/contracts/mutants/BalanceDrip/7/BOR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp <= uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp <= 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa <= 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds >= 0 || self.dripRatePerSecond >= 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens >= maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/7/ILR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/7/ILR/BalanceDrip.sol new file mode 100644 index 00000000000..66baa188c40 --- /dev/null +++ b/contracts/mutants/BalanceDrip/7/ILR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 1; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 1; + } + + uint256 lastTime = self.timestamp == 1 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 1 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 1 && self.dripRatePerSecond > 1) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 1 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/8/BOR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/8/BOR/BalanceDrip.sol new file mode 100644 index 00000000000..2a6157dbd0b --- /dev/null +++ b/contracts/mutants/BalanceDrip/8/BOR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp <= uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp <= 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa <= 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds >= 0 || self.dripRatePerSecond >= 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens >= maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply >= 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/8/ILR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/8/ILR/BalanceDrip.sol new file mode 100644 index 00000000000..23c87b3aeb2 --- /dev/null +++ b/contracts/mutants/BalanceDrip/8/ILR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 1; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 1; + } + + uint256 lastTime = self.timestamp == 1 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 1 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 1 && self.dripRatePerSecond > 1) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 1 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 1; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/9/BOR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/9/BOR/BalanceDrip.sol new file mode 100644 index 00000000000..5ab651e4aba --- /dev/null +++ b/contracts/mutants/BalanceDrip/9/BOR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp <= uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp <= 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa <= 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds >= 0 || self.dripRatePerSecond >= 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens >= maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply >= 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa <= 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/9/ILR/BalanceDrip.sol b/contracts/mutants/BalanceDrip/9/ILR/BalanceDrip.sol new file mode 100644 index 00000000000..0e153612fa4 --- /dev/null +++ b/contracts/mutants/BalanceDrip/9/ILR/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 1; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 1; + } + + uint256 lastTime = self.timestamp == 1 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 1 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 1 && self.dripRatePerSecond > 1) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 1 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 1; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 1) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +} diff --git a/contracts/mutants/BalanceDrip/original/BalanceDrip.sol b/contracts/mutants/BalanceDrip/original/BalanceDrip.sol new file mode 100644 index 00000000000..874362f30cc --- /dev/null +++ b/contracts/mutants/BalanceDrip/original/BalanceDrip.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.6.0 <0.7.0; + +import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol"; + +import "../utils/ExtendedSafeCast.sol"; +import "@pooltogether/fixed-point/contracts/FixedPoint.sol"; + +/// @title Calculates a users share of a token faucet. +/// @notice The tokens are dripped at a "drip rate per second". This is the number of tokens that +/// are dripped each second to the entire supply of a "measure" token. A user's share of ownership +/// of the measure token corresponds to the share of the drip tokens per second. +library BalanceDrip { + using SafeMathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using ExtendedSafeCast for uint256; + + struct UserState { + uint128 lastExchangeRateMantissa; + } + + struct State { + uint256 dripRatePerSecond; + uint112 exchangeRateMantissa; + uint112 totalDripped; + uint32 timestamp; + mapping(address => UserState) userStates; + } + + /// @notice Captures new tokens for a user + /// @dev This must be called before changes to the user's balance (i.e. before mint, transfer or burns) + /// @param self The balance drip state + /// @param user The user to capture tokens for + /// @param userMeasureBalance The current balance of the user's measure tokens + /// @return The number of new tokens + function captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) internal returns (uint128) { + return _captureNewTokensForUser( + self, + user, + userMeasureBalance + ); + } + + function resetTotalDripped(State storage self) internal { + self.totalDripped = 0; + } + + /// @notice Drips new tokens. + /// @dev Should be called immediately before a change to the measure token's total supply + /// @param self The balance drip state + /// @param measureTotalSupply The measure token's last total supply (prior to any change) + /// @param timestamp The current time + /// @param maxNewTokens Maximum new tokens that can be dripped + /// @return The number of new tokens dripped. + function drip( + State storage self, + uint256 measureTotalSupply, + uint256 timestamp, + uint256 maxNewTokens + ) internal returns (uint256) { + // this should only run once per block. + if (self.timestamp == uint32(timestamp)) { + return 0; + } + + uint256 lastTime = self.timestamp == 0 ? timestamp : self.timestamp; + uint256 newSeconds = timestamp.sub(lastTime); + + uint112 exchangeRateMantissa = self.exchangeRateMantissa == 0 ? FixedPoint.SCALE.toUint112() : self.exchangeRateMantissa; + + uint256 newTokens; + if (newSeconds > 0 && self.dripRatePerSecond > 0) { + newTokens = newSeconds.mul(self.dripRatePerSecond); + if (newTokens > maxNewTokens) { + newTokens = maxNewTokens; + } + uint256 indexDeltaMantissa = measureTotalSupply > 0 ? FixedPoint.calculateMantissa(newTokens, measureTotalSupply) : 0; + exchangeRateMantissa = uint256(exchangeRateMantissa).add(indexDeltaMantissa).toUint112(); + } + + self.exchangeRateMantissa = exchangeRateMantissa; + self.totalDripped = uint256(self.totalDripped).add(newTokens).toUint112(); + self.timestamp = timestamp.toUint32(); + + return newTokens; + } + + function _captureNewTokensForUser( + State storage self, + address user, + uint256 userMeasureBalance + ) private returns (uint128) { + UserState storage userState = self.userStates[user]; + uint256 lastExchangeRateMantissa = userState.lastExchangeRateMantissa; + if (lastExchangeRateMantissa == 0) { + // if the index is not intialized + lastExchangeRateMantissa = FixedPoint.SCALE.toUint112(); + } + + uint256 deltaExchangeRateMantissa = uint256(self.exchangeRateMantissa).sub(lastExchangeRateMantissa); + uint128 newTokens = FixedPoint.multiplyUintByMantissa(userMeasureBalance, deltaExchangeRateMantissa).toUint128(); + + self.userStates[user] = UserState({ + lastExchangeRateMantissa: self.exchangeRateMantissa + }); + + return newTokens; + } +}