@gooddollar/goodprotocol 1.0.28 → 1.0.29-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/artifacts/abis/BulkProof.min.json +1 -1
- package/artifacts/abis/DistributionBridgeMock.min.json +1 -0
- package/artifacts/abis/DistributionHelper.min.json +1 -0
- package/artifacts/abis/DistributionHelperTest.min.json +1 -0
- package/artifacts/abis/DistributionHelperTestHelper.min.json +1 -0
- package/artifacts/abis/ERC20.min.json +1 -1
- package/artifacts/abis/GoodDollarMintBurnWrapper.min.json +1 -0
- package/artifacts/abis/GoodDollarStaking.min.json +1 -0
- package/artifacts/abis/GoodDollarStakingMock.min.json +1 -0
- package/artifacts/abis/GoodReserveCDai.min.json +1 -1
- package/artifacts/abis/IERC2917.min.json +1 -1
- package/artifacts/abis/IGoodDollarStakingTest.min.json +1 -0
- package/artifacts/abis/IMultichainRouter.min.json +1 -0
- package/artifacts/abis/IRouter.min.json +1 -0
- package/artifacts/abis/IWrapper.min.json +1 -0
- package/artifacts/abis/Math64x64.min.json +1 -0
- package/artifacts/abis/MultichainBridgeHelper.min.json +1 -0
- package/artifacts/abis/MultichainRouterMock.min.json +1 -0
- package/artifacts/abis/OverMintTester.min.json +1 -1
- package/artifacts/abis/PausableControl.min.json +1 -0
- package/artifacts/abis/RewardsMinter.min.json +1 -0
- package/artifacts/abis/StakingMockFixedAPY.min.json +1 -0
- package/artifacts/abis/StakingRewardsFixedAPY.min.json +1 -0
- package/artifacts/abis/TokenOperation.min.json +1 -0
- package/artifacts/abis/cERC20.min.json +1 -1
- package/artifacts/contracts/DAOStackInterfaces.sol/Avatar.dbg.json +1 -1
- package/artifacts/contracts/DAOStackInterfaces.sol/Controller.dbg.json +1 -1
- package/artifacts/contracts/DAOStackInterfaces.sol/GlobalConstraintInterface.dbg.json +1 -1
- package/artifacts/contracts/DAOStackInterfaces.sol/IntVoteInterface.dbg.json +1 -1
- package/artifacts/contracts/DAOStackInterfaces.sol/ReputationInterface.dbg.json +1 -1
- package/artifacts/contracts/DAOStackInterfaces.sol/SchemeRegistrar.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/AggregatorV3Interface.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/ERC20.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/ERC20.json +13 -0
- package/artifacts/contracts/Interfaces.sol/IAaveIncentivesController.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IAdminWallet.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IDonationStaking.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IERC2917.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IERC2917.json +13 -0
- package/artifacts/contracts/Interfaces.sol/IFirstClaimPool.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IGoodDollar.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IGoodStaking.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IHasRouter.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IIdentity.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/ILendingPool.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IMultichainRouter.dbg.json +4 -0
- package/artifacts/contracts/Interfaces.sol/IMultichainRouter.json +67 -0
- package/artifacts/contracts/Interfaces.sol/INameService.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/IUBIScheme.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/ProxyAdmin.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/Reserve.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/Staking.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/Uniswap.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/UniswapFactory.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/UniswapPair.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/cERC20.dbg.json +1 -1
- package/artifacts/contracts/Interfaces.sol/cERC20.json +13 -0
- package/artifacts/contracts/fuseFaucet/FuseFaucet.sol/FuseFaucet.dbg.json +1 -1
- package/artifacts/contracts/fuseFaucet/FuseFaucet.sol/FuseFaucet.json +2 -2
- package/artifacts/contracts/governance/ClaimersDistribution.sol/ClaimersDistribution.dbg.json +1 -1
- package/artifacts/contracts/governance/ClaimersDistribution.sol/ClaimersDistribution.json +2 -2
- package/artifacts/contracts/governance/CompoundVotingMachine.sol/CompoundVotingMachine.dbg.json +1 -1
- package/artifacts/contracts/governance/CompoundVotingMachine.sol/CompoundVotingMachine.json +2 -2
- package/artifacts/contracts/governance/GReputation.sol/GReputation.dbg.json +1 -1
- package/artifacts/contracts/governance/GReputation.sol/GReputation.json +2 -2
- package/artifacts/contracts/governance/GoodDollarStaking.sol/GoodDollarStaking.dbg.json +4 -0
- package/artifacts/contracts/governance/GoodDollarStaking.sol/GoodDollarStaking.json +1322 -0
- package/artifacts/contracts/governance/GoodDollarStaking.sol/RewardsMinter.dbg.json +4 -0
- package/artifacts/contracts/governance/GoodDollarStaking.sol/RewardsMinter.json +35 -0
- package/artifacts/contracts/governance/GovernanceStaking.sol/GovernanceStaking.dbg.json +1 -1
- package/artifacts/contracts/governance/GovernanceStaking.sol/GovernanceStaking.json +2 -2
- package/artifacts/contracts/governance/MultiBaseGovernanceShareField.sol/MultiBaseGovernanceShareField.dbg.json +1 -1
- package/artifacts/contracts/governance/Reputation.sol/Reputation.dbg.json +1 -1
- package/artifacts/contracts/governance/Reputation.sol/Reputation.json +2 -2
- package/artifacts/contracts/governance/StakersDistribution.sol/StakersDistribution.dbg.json +1 -1
- package/artifacts/contracts/governance/StakersDistribution.sol/StakersDistribution.json +2 -2
- package/artifacts/contracts/invite/InvitesV1.sol/InvitesV1.dbg.json +1 -1
- package/artifacts/contracts/invite/InvitesV1.sol/InvitesV1.json +2 -2
- package/artifacts/contracts/mocks/AaveMock.sol/AaveMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/DAIMock.sol/DAIMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/DecimalsMock.sol/DecimalsMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/DistributionBridgeMock.sol/DistributionBridgeMock.dbg.json +4 -0
- package/artifacts/contracts/mocks/DistributionBridgeMock.sol/DistributionBridgeMock.json +152 -0
- package/artifacts/contracts/mocks/DistributionHelperTest.sol/DistributionHelperTest.dbg.json +4 -0
- package/artifacts/contracts/mocks/DistributionHelperTest.sol/DistributionHelperTest.json +662 -0
- package/artifacts/contracts/mocks/DistributionHelperTest.sol/DistributionHelperTestHelper.dbg.json +4 -0
- package/artifacts/contracts/mocks/DistributionHelperTest.sol/DistributionHelperTestHelper.json +680 -0
- package/artifacts/contracts/mocks/GoodCompoundStakingTest.sol/GoodCompoundStakingTest.dbg.json +1 -1
- package/artifacts/contracts/mocks/GoodCompoundStakingTest.sol/GoodCompoundStakingTest.json +2 -2
- package/artifacts/contracts/mocks/GoodDollarStakingMock.sol/GoodDollarStakingMock.dbg.json +4 -0
- package/artifacts/contracts/mocks/GoodDollarStakingMock.sol/GoodDollarStakingMock.json +1322 -0
- package/artifacts/contracts/mocks/GoodFundManagerTest.sol/GoodFundManagerTest.dbg.json +1 -1
- package/artifacts/contracts/mocks/GoodFundManagerTest.sol/GoodFundManagerTest.json +2 -2
- package/artifacts/contracts/mocks/IncentiveControllerMock.sol/IncentiveControllerMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/LendingPoolMock.sol/LendingPoolMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/MultichainRouterMock.sol/IWrapper.dbg.json +4 -0
- package/artifacts/contracts/mocks/MultichainRouterMock.sol/IWrapper.json +59 -0
- package/artifacts/contracts/mocks/MultichainRouterMock.sol/MultichainRouterMock.dbg.json +4 -0
- package/artifacts/contracts/mocks/MultichainRouterMock.sol/MultichainRouterMock.json +81 -0
- package/artifacts/contracts/mocks/OverMintTester.sol/IGoodDollarStakingTest.dbg.json +4 -0
- package/artifacts/contracts/mocks/OverMintTester.sol/IGoodDollarStakingTest.json +49 -0
- package/artifacts/contracts/mocks/OverMintTester.sol/OverMintTester.dbg.json +1 -1
- package/artifacts/contracts/mocks/OverMintTester.sol/OverMintTester.json +4 -4
- package/artifacts/contracts/mocks/OverMintTesterRegularStake.sol/OverMintTesterRegularStake.dbg.json +1 -1
- package/artifacts/contracts/mocks/OverMintTesterRegularStake.sol/OverMintTesterRegularStake.json +2 -2
- package/artifacts/contracts/mocks/SixteenDecimalsTokenMock.sol/SixteenDecimalsTokenMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/StakingMockFixedAPY.sol/StakingMockFixedAPY.dbg.json +4 -0
- package/artifacts/contracts/mocks/StakingMockFixedAPY.sol/StakingMockFixedAPY.json +682 -0
- package/artifacts/contracts/mocks/SwapHelperTest.sol/SwapHelperTest.dbg.json +1 -1
- package/artifacts/contracts/mocks/SwapHelperTest.sol/SwapHelperTest.json +2 -2
- package/artifacts/contracts/mocks/TwentyDecimalsTokenMock.sol/TwentyDecimalsTokenMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock.json +2 -2
- package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock2.dbg.json +1 -1
- package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock2.json +2 -2
- package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock3.dbg.json +1 -1
- package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock3.json +2 -2
- package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock4.dbg.json +1 -1
- package/artifacts/contracts/mocks/UpgradableMocks.sol/UpgradableMock4.json +2 -2
- package/artifacts/contracts/mocks/UsdcMock.sol/USDCMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cBATMock.sol/cBATMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cDAILowWorthMock.sol/cDAILowWorthMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cDAIMock.sol/cDAIMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cDAINonMintableMock.sol/cDAINonMintableMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cDecimalsMock.sol/cDecimalsMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cSDTMock.sol/cSDTMock.dbg.json +1 -1
- package/artifacts/contracts/mocks/cUSDCMock.sol/cUSDCMock.dbg.json +1 -1
- package/artifacts/contracts/reserve/DistributionHelper.sol/DistributionHelper.dbg.json +4 -0
- package/artifacts/contracts/reserve/DistributionHelper.sol/DistributionHelper.json +662 -0
- package/artifacts/contracts/reserve/ExchangeHelper.sol/ExchangeHelper.dbg.json +1 -1
- package/artifacts/contracts/reserve/ExchangeHelper.sol/ExchangeHelper.json +2 -2
- package/artifacts/contracts/reserve/GoodMarketMaker.sol/GoodMarketMaker.dbg.json +1 -1
- package/artifacts/contracts/reserve/GoodMarketMaker.sol/GoodMarketMaker.json +2 -2
- package/artifacts/contracts/reserve/GoodReserveCDai.sol/ContributionCalc.dbg.json +1 -1
- package/artifacts/contracts/reserve/GoodReserveCDai.sol/GoodReserveCDai.dbg.json +1 -1
- package/artifacts/contracts/reserve/GoodReserveCDai.sol/GoodReserveCDai.json +75 -35
- package/artifacts/contracts/staking/BaseShareField.sol/BaseShareField.dbg.json +1 -1
- package/artifacts/contracts/staking/BaseShareField.sol/BaseShareField.json +2 -2
- package/artifacts/contracts/staking/BaseShareFieldV2.sol/BaseShareFieldV2.dbg.json +1 -1
- package/artifacts/contracts/staking/BaseShareFieldV2.sol/BaseShareFieldV2.json +2 -2
- package/artifacts/contracts/staking/DonationsStaking.sol/DonationsStaking.dbg.json +1 -1
- package/artifacts/contracts/staking/DonationsStaking.sol/DonationsStaking.json +2 -2
- package/artifacts/contracts/staking/FuseStakingV3.sol/FuseStakingV3.dbg.json +1 -1
- package/artifacts/contracts/staking/FuseStakingV3.sol/FuseStakingV3.json +2 -2
- package/artifacts/contracts/staking/FuseStakingV3.sol/IConsensus.dbg.json +1 -1
- package/artifacts/contracts/staking/FuseStakingV3.sol/PegSwap.dbg.json +1 -1
- package/artifacts/contracts/staking/GoodFundManager.sol/GoodFundManager.dbg.json +1 -1
- package/artifacts/contracts/staking/GoodFundManager.sol/GoodFundManager.json +2 -2
- package/artifacts/contracts/staking/SimpleStaking.sol/SimpleStaking.dbg.json +1 -1
- package/artifacts/contracts/staking/SimpleStakingV2.sol/SimpleStakingV2.dbg.json +1 -1
- package/artifacts/contracts/staking/UniswapV2SwapHelper.sol/UniswapV2SwapHelper.dbg.json +1 -1
- package/artifacts/contracts/staking/UniswapV2SwapHelper.sol/UniswapV2SwapHelper.json +2 -2
- package/artifacts/contracts/staking/aave/AaveStakingFactory.sol/AaveStakingFactory.dbg.json +1 -1
- package/artifacts/contracts/staking/aave/AaveStakingFactory.sol/AaveStakingFactory.json +2 -2
- package/artifacts/contracts/staking/aave/GoodAaveStaking.sol/GoodAaveStaking.dbg.json +1 -1
- package/artifacts/contracts/staking/aave/GoodAaveStaking.sol/GoodAaveStaking.json +2 -2
- package/artifacts/contracts/staking/aave/GoodAaveStakingV2.sol/GoodAaveStakingV2.dbg.json +1 -1
- package/artifacts/contracts/staking/aave/GoodAaveStakingV2.sol/GoodAaveStakingV2.json +2 -2
- package/artifacts/contracts/staking/compound/CompoundStakingFactory.sol/CompoundStakingFactory.dbg.json +1 -1
- package/artifacts/contracts/staking/compound/CompoundStakingFactory.sol/CompoundStakingFactory.json +2 -2
- package/artifacts/contracts/staking/compound/GoodCompoundStaking.sol/GoodCompoundStaking.dbg.json +1 -1
- package/artifacts/contracts/staking/compound/GoodCompoundStaking.sol/GoodCompoundStaking.json +2 -2
- package/artifacts/contracts/staking/compound/GoodCompoundStakingV2.sol/GoodCompoundStakingV2.dbg.json +1 -1
- package/artifacts/contracts/staking/compound/GoodCompoundStakingV2.sol/GoodCompoundStakingV2.json +2 -2
- package/artifacts/contracts/staking/utils/Math64X64.sol/Math64x64.dbg.json +4 -0
- package/artifacts/contracts/staking/utils/Math64X64.sol/Math64x64.json +10 -0
- package/artifacts/contracts/staking/utils/StakingRewardsFixedAPY.sol/StakingRewardsFixedAPY.dbg.json +4 -0
- package/artifacts/contracts/staking/utils/StakingRewardsFixedAPY.sol/StakingRewardsFixedAPY.json +268 -0
- package/artifacts/contracts/ubi/UBIScheme.sol/UBIScheme.dbg.json +1 -1
- package/artifacts/contracts/ubi/UBIScheme.sol/UBIScheme.json +2 -2
- package/artifacts/contracts/utils/AdminWallet.sol/AdminWallet.dbg.json +1 -1
- package/artifacts/contracts/utils/AdminWallet.sol/AdminWallet.json +2 -2
- package/artifacts/contracts/utils/BancorFormula.sol/BancorFormula.dbg.json +1 -1
- package/artifacts/contracts/utils/BulkProof.sol/BulkProof.dbg.json +1 -1
- package/artifacts/contracts/utils/BulkProof.sol/BulkProof.json +3 -34
- package/artifacts/contracts/utils/DAOContract.sol/DAOContract.dbg.json +1 -1
- package/artifacts/contracts/utils/DAOContract.sol/DAOContract.json +2 -2
- package/artifacts/contracts/utils/DAOUpgradeableContract.sol/DAOUpgradeableContract.dbg.json +1 -1
- package/artifacts/contracts/utils/DAOUpgradeableContract.sol/DAOUpgradeableContract.json +2 -2
- package/artifacts/contracts/utils/DSMath.sol/DSMath.dbg.json +1 -1
- package/artifacts/contracts/utils/DataTypes.sol/DataTypes.dbg.json +1 -1
- package/artifacts/contracts/utils/GoodDollarMintBurnWrapper.sol/GoodDollarMintBurnWrapper.dbg.json +4 -0
- package/artifacts/contracts/utils/GoodDollarMintBurnWrapper.sol/GoodDollarMintBurnWrapper.json +1263 -0
- package/artifacts/contracts/utils/GoodDollarMintBurnWrapper.sol/IRouter.dbg.json +4 -0
- package/artifacts/contracts/utils/GoodDollarMintBurnWrapper.sol/IRouter.json +59 -0
- package/artifacts/contracts/utils/GoodDollarMintBurnWrapper.sol/PausableControl.dbg.json +4 -0
- package/artifacts/contracts/utils/GoodDollarMintBurnWrapper.sol/PausableControl.json +69 -0
- package/artifacts/contracts/utils/GoodDollarMintBurnWrapper.sol/TokenOperation.dbg.json +4 -0
- package/artifacts/contracts/utils/GoodDollarMintBurnWrapper.sol/TokenOperation.json +10 -0
- package/artifacts/contracts/utils/MultichainBridgeHelper.sol/MultichainBridgeHelper.dbg.json +4 -0
- package/artifacts/contracts/utils/MultichainBridgeHelper.sol/MultichainBridgeHelper.json +79 -0
- package/artifacts/contracts/utils/NameService.sol/NameService.dbg.json +1 -1
- package/artifacts/contracts/utils/ProtocolUpgrade.sol/OldMarketMaker.dbg.json +1 -1
- package/artifacts/contracts/utils/ProtocolUpgrade.sol/ProtocolUpgrade.dbg.json +1 -1
- package/artifacts/contracts/utils/ProtocolUpgrade.sol/ProtocolUpgrade.json +2 -2
- package/artifacts/contracts/utils/ProtocolUpgradeFuse.sol/ProtocolUpgradeFuse.dbg.json +1 -1
- package/artifacts/contracts/utils/ProtocolUpgradeFuse.sol/ProtocolUpgradeFuse.json +2 -2
- package/artifacts/contracts/utils/ProtocolUpgradeFuseRecover.sol/ProtocolUpgradeFuseRecover.dbg.json +1 -1
- package/artifacts/contracts/utils/ProtocolUpgradeFuseRecover.sol/ProtocolUpgradeFuseRecover.json +2 -2
- package/artifacts/contracts/utils/ProtocolUpgradeRecover.sol/ProtocolUpgradeRecover.dbg.json +1 -1
- package/artifacts/contracts/utils/ProtocolUpgradeRecover.sol/ProtocolUpgradeRecover.json +2 -2
- package/artifacts/contracts/utils/ProxyFactory1967.sol/ERC1967Proxy.dbg.json +1 -1
- package/artifacts/contracts/utils/ProxyFactory1967.sol/ProxyFactory1967.dbg.json +1 -1
- package/artifacts/contracts/utils/ReputationTestHelper.sol/ReputationTestHelper.dbg.json +1 -1
- package/artifacts/contracts/utils/ReputationTestHelper.sol/ReputationTestHelper.json +2 -2
- package/contracts/Interfaces.sol +20 -0
- package/contracts/governance/GoodDollarStaking.sol +510 -0
- package/contracts/governance/MultiBaseGovernanceShareField.sol +1 -0
- package/contracts/mocks/DistributionBridgeMock.sol +50 -0
- package/contracts/mocks/DistributionHelperTest.sol +22 -0
- package/contracts/mocks/GoodDollarStakingMock.sol +24 -0
- package/contracts/mocks/MultichainRouterMock.sol +38 -0
- package/contracts/mocks/OverMintTester.sol +39 -25
- package/contracts/mocks/StakingMockFixedAPY.sol +78 -0
- package/contracts/reserve/DistributionHelper.sol +142 -0
- package/contracts/reserve/GoodReserveCDai.sol +95 -41
- package/contracts/staking/utils/Math64X64.sol +268 -0
- package/contracts/staking/utils/StakingRewardsFixedAPY.sol +336 -0
- package/contracts/utils/BulkProof.sol +10 -10
- package/contracts/utils/GoodDollarMintBurnWrapper.sol +638 -0
- package/contracts/utils/MultichainBridgeHelper.sol +39 -0
- package/hardhat.config.ts +5 -3
- package/package.json +7 -4
- package/patches/@openzeppelin+hardhat-upgrades+1.7.0.patch.depracate +67 -0
- package/releases/deployment.json +10 -3
- package/releases/olddao.json +1 -1
- package/scripts/analytics/activeUsersCount.ts +65 -0
- package/scripts/analytics/activeWalletsStats.ts +150 -0
- package/scripts/analytics/claimIncidentStats.ts +117 -0
- package/scripts/analytics/faucetStats.ts +103 -0
- package/scripts/analytics/goodHolders.ts +50 -0
- package/scripts/{misc → analytics}/goodgiveback.ts +0 -0
- package/scripts/governance/airdropCalculation.ts +1 -0
- package/scripts/multichain-deploy/basicdao-deploy.ts +20 -5
- package/scripts/multichain-deploy/gdSavings-deploy.ts +232 -0
- package/scripts/multichain-deploy/helpers.ts +73 -8
- package/scripts/multichain-deploy/multichainWrapper-deploy.ts +56 -0
- package/scripts/multichain-deploy/nonubiDistribution-deploy.ts +170 -0
- package/scripts/voltageswaps.ts +47 -0
- package/test/governance/ClaimersDistribution.test.ts +1 -1
- package/test/governance/GoodDollarStaking.gd.test.ts +559 -0
- package/test/governance/GoodDollarStaking.good.test.ts +998 -0
- package/test/governance/GovernanceStaking.test.ts +43 -0
- package/test/helpers.ts +9 -12
- package/test/reserve/DistributionHelper.test.ts +394 -0
- package/test/reserve/GoodReserveCDai.distribution.test.ts +296 -0
- package/test/reserve/GoodReserveCDai.gdx.test.ts +21 -16
- package/test/reserve/GoodReserveCDai.pause.test.ts +116 -0
- package/test/staking/StakingRewardsFixedAPY.test.ts +900 -0
- package/test/utils/AdminWallet.test.ts +35 -6
- package/test/utils/GoodDollarMintBurnWrapper.test.ts +796 -0
- package/tsconfig.json +4 -9
- package/types/AccessControl.ts +361 -0
- package/types/CERC20.ts +25 -0
- package/types/DistributionBridgeMock.ts +251 -0
- package/types/DistributionHelper.ts +908 -0
- package/types/DistributionHelperTest.ts +909 -0
- package/types/DistributionHelperTestHelper.ts +945 -0
- package/types/ERC165.ts +104 -0
- package/types/ERC20.ts +101 -49
- package/types/GoodDollarMintBurnWrapper.ts +1806 -0
- package/types/GoodDollarStaking.ts +1855 -0
- package/types/GoodDollarStakingMock.ts +1855 -0
- package/types/GoodReserveCDai.ts +90 -55
- package/types/IAccessControl.ts +306 -0
- package/types/IERC165.ts +104 -0
- package/types/IERC20.ts +300 -0
- package/types/IERC20Metadata.ts +339 -0
- package/types/IERC2917.ts +25 -0
- package/types/IGoodDollarStakingTest.ts +160 -0
- package/types/IMultichainRouter.ts +166 -0
- package/types/IRouter.ts +143 -0
- package/types/IWrapper.ts +143 -0
- package/types/MultichainBridgeHelper.ts +170 -0
- package/types/MultichainRouterMock.ts +141 -0
- package/types/Pausable.ts +103 -0
- package/types/PausableControl.ts +125 -0
- package/types/{BulkProof.ts → RewardsMinter.ts} +24 -28
- package/types/StakingMockFixedAPY.ts +995 -0
- package/types/StakingRewardsFixedAPY.ts +428 -0
- package/types/factories/AaveStakingFactory__factory.ts +1 -1
- package/types/factories/AccessControl__factory.ts +227 -0
- package/types/factories/AdminWallet__factory.ts +1 -1
- package/types/factories/BaseShareFieldV2__factory.ts +1 -1
- package/types/factories/BaseShareField__factory.ts +1 -1
- package/types/factories/CERC20__factory.ts +13 -0
- package/types/factories/ClaimersDistribution__factory.ts +1 -1
- package/types/factories/CompoundStakingFactory__factory.ts +1 -1
- package/types/factories/CompoundVotingMachine__factory.ts +1 -1
- package/types/factories/DAOContract__factory.ts +1 -1
- package/types/factories/DAOUpgradeableContract__factory.ts +1 -1
- package/types/factories/DistributionBridgeMock__factory.ts +207 -0
- package/types/factories/DistributionHelperTestHelper__factory.ts +737 -0
- package/types/factories/DistributionHelperTest__factory.ts +717 -0
- package/types/factories/DistributionHelper__factory.ts +713 -0
- package/types/factories/DonationsStaking__factory.ts +1 -1
- package/types/factories/ERC165__factory.ts +39 -0
- package/types/factories/ERC20__factory.ts +13 -0
- package/types/factories/ExchangeHelper__factory.ts +1 -1
- package/types/factories/FuseFaucet__factory.ts +1 -1
- package/types/factories/FuseStakingV3__factory.ts +1 -1
- package/types/factories/GReputation__factory.ts +1 -1
- package/types/factories/GoodAaveStakingV2__factory.ts +1 -1
- package/types/factories/GoodAaveStaking__factory.ts +1 -1
- package/types/factories/GoodCompoundStakingTest__factory.ts +1 -1
- package/types/factories/GoodCompoundStakingV2__factory.ts +1 -1
- package/types/factories/GoodCompoundStaking__factory.ts +1 -1
- package/types/factories/GoodDollarMintBurnWrapper__factory.ts +1318 -0
- package/types/factories/GoodDollarStakingMock__factory.ts +1404 -0
- package/types/factories/GoodDollarStaking__factory.ts +1400 -0
- package/types/factories/GoodFundManagerTest__factory.ts +1 -1
- package/types/factories/GoodFundManager__factory.ts +1 -1
- package/types/factories/GoodMarketMaker__factory.ts +1 -1
- package/types/factories/GoodReserveCDai__factory.ts +74 -34
- package/types/factories/GovernanceStaking__factory.ts +1 -1
- package/types/factories/IAccessControl__factory.ts +198 -0
- package/types/factories/IERC165__factory.ts +42 -0
- package/types/factories/IERC20Metadata__factory.ts +248 -0
- package/types/factories/IERC20__factory.ts +203 -0
- package/types/factories/IERC2917__factory.ts +13 -0
- package/types/factories/IGoodDollarStakingTest__factory.ts +68 -0
- package/types/factories/IMultichainRouter__factory.ts +82 -0
- package/types/factories/IRouter__factory.ts +71 -0
- package/types/factories/IWrapper__factory.ts +71 -0
- package/types/factories/InvitesV1__factory.ts +1 -1
- package/types/factories/MultichainBridgeHelper__factory.ts +134 -0
- package/types/factories/MultichainRouterMock__factory.ts +141 -0
- package/types/factories/OverMintTesterRegularStake__factory.ts +1 -1
- package/types/factories/OverMintTester__factory.ts +3 -3
- package/types/factories/PausableControl__factory.ts +84 -0
- package/types/factories/Pausable__factory.ts +62 -0
- package/types/factories/ProtocolUpgradeFuseRecover__factory.ts +1 -1
- package/types/factories/ProtocolUpgradeFuse__factory.ts +1 -1
- package/types/factories/ProtocolUpgradeRecover__factory.ts +1 -1
- package/types/factories/ProtocolUpgrade__factory.ts +1 -1
- package/types/factories/ReputationTestHelper__factory.ts +1 -1
- package/types/factories/Reputation__factory.ts +1 -1
- package/types/factories/RewardsMinter__factory.ts +47 -0
- package/types/factories/StakersDistribution__factory.ts +1 -1
- package/types/factories/StakingMockFixedAPY__factory.ts +745 -0
- package/types/factories/StakingRewardsFixedAPY__factory.ts +287 -0
- package/types/factories/SwapHelperTest__factory.ts +1 -1
- package/types/factories/UBIScheme__factory.ts +1 -1
- package/types/factories/UniswapV2SwapHelper__factory.ts +1 -1
- package/types/factories/UpgradableMock2__factory.ts +1 -1
- package/types/factories/UpgradableMock3__factory.ts +1 -1
- package/types/factories/UpgradableMock4__factory.ts +1 -1
- package/types/factories/UpgradableMock__factory.ts +1 -1
- package/types/hardhat.d.ts +225 -9
- package/types/index.ts +50 -4
- package/yarn.lock +180 -104
- package/types/factories/BulkProof__factory.ts +0 -89
|
@@ -0,0 +1,900 @@
|
|
|
1
|
+
import { expect } from "chai";
|
|
2
|
+
import { ethers, waffle } from "hardhat";
|
|
3
|
+
import { createDAO, advanceBlocks } from "../helpers";
|
|
4
|
+
import { StakingMockFixedAPY } from "../../types";
|
|
5
|
+
import { default as StakingABI } from "../../artifacts/contracts/mocks/StakingMockFixedAPY.sol/StakingMockFixedAPY.json";
|
|
6
|
+
const BN = ethers.BigNumber;
|
|
7
|
+
|
|
8
|
+
// APY=5% | Blocks per year = 12*60*24*365 = 6307200
|
|
9
|
+
// per block = nroot(1+0.05,numberOfBlocksPerYear) = 1000000007735630000
|
|
10
|
+
const BLOCKS_ONE_YEAR = 6307200;
|
|
11
|
+
const BLOCKS_FOUR_YEARS = 25228800;
|
|
12
|
+
const BLOCKS_TEN_YEARS = 63072000;
|
|
13
|
+
const INTEREST_RATE_5APY_X64 = BN.from("1000000007735630000"); // x64 representation of same number
|
|
14
|
+
const INTEREST_RATE_5APY_128 = BN.from("18446744216406738474"); // 128 representation of same number
|
|
15
|
+
// APY = 10% | nroot(1+0.10,numberOfBlocksPerYear) = 1000000015111330000
|
|
16
|
+
const INTEREST_RATE_10APY_X64 = BN.from("1000000015111330000"); // x64 representation of same number
|
|
17
|
+
const INTEREST_RATE_10APY_128 = BN.from("18446744352464388739"); // 128 representation of same number
|
|
18
|
+
// APY = 8% | nroot(1+0.08,numberOfBlocksPerYear) = 1000000012202093100
|
|
19
|
+
const INTEREST_RATE_8APY_X64 = BN.from("1000000012202093100"); // x64 representation of same number
|
|
20
|
+
|
|
21
|
+
describe("StakingRewardsFixedAPY - generic staking for fixed APY rewards contract", () => {
|
|
22
|
+
let signers,
|
|
23
|
+
setNSAddress,
|
|
24
|
+
nameService,
|
|
25
|
+
avatar,
|
|
26
|
+
genericCall,
|
|
27
|
+
controller,
|
|
28
|
+
fixedStaking: StakingMockFixedAPY,
|
|
29
|
+
goodDollar,
|
|
30
|
+
founder,
|
|
31
|
+
staker1,
|
|
32
|
+
staker2,
|
|
33
|
+
staker3,
|
|
34
|
+
staker4;
|
|
35
|
+
|
|
36
|
+
async function stake(_staker, _amount, contract = fixedStaking) {
|
|
37
|
+
await contract.connect(_staker).stake(_staker.address, _amount);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// on withdraw: _amount / sharePrice = shares redeemed
|
|
41
|
+
// on stake: _amount / sharePrice = shares added
|
|
42
|
+
async function getExpectedSharesChange(_amount, _contract = fixedStaking) {
|
|
43
|
+
return BN.from(_amount)
|
|
44
|
+
.mul(await _contract.SHARE_PRECISION())
|
|
45
|
+
.div(await _contract.sharePrice());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function expectSavings(_staker, _amount, _contract = fixedStaking) {
|
|
49
|
+
const savings = await _contract.getSavings(_staker.address);
|
|
50
|
+
expect(savings.eq(_amount)).to.be.true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
before(async () => {
|
|
54
|
+
[founder, staker1, staker2, staker3, staker4, ...signers] =
|
|
55
|
+
await ethers.getSigners();
|
|
56
|
+
|
|
57
|
+
let {
|
|
58
|
+
controller: ctrl,
|
|
59
|
+
avatar: av,
|
|
60
|
+
genericCall: gc,
|
|
61
|
+
gd,
|
|
62
|
+
nameService: ns,
|
|
63
|
+
setDAOAddress
|
|
64
|
+
} = await createDAO();
|
|
65
|
+
|
|
66
|
+
setNSAddress = setDAOAddress;
|
|
67
|
+
nameService = ns;
|
|
68
|
+
avatar = av;
|
|
69
|
+
genericCall = gc;
|
|
70
|
+
controller = ctrl;
|
|
71
|
+
goodDollar = await ethers.getContractAt("IGoodDollar", gd);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const fixture_initOnly = async (wallets, provider) => {
|
|
75
|
+
const staking: StakingMockFixedAPY = (await waffle.deployContract(
|
|
76
|
+
provider.getWallets()[0],
|
|
77
|
+
StakingABI,
|
|
78
|
+
[INTEREST_RATE_5APY_X64]
|
|
79
|
+
)) as StakingMockFixedAPY;
|
|
80
|
+
|
|
81
|
+
return { staking };
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const fixture_2 = async (wallets, provider) => {
|
|
85
|
+
const staking: StakingMockFixedAPY = (await waffle.deployContract(
|
|
86
|
+
provider.getWallets()[0],
|
|
87
|
+
StakingABI,
|
|
88
|
+
[INTEREST_RATE_5APY_X64]
|
|
89
|
+
)) as StakingMockFixedAPY;
|
|
90
|
+
|
|
91
|
+
return { staking };
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const fixture_1year = async (wallets, provider) => {
|
|
95
|
+
const staking: StakingMockFixedAPY = (await waffle.deployContract(
|
|
96
|
+
provider.getWallets()[0],
|
|
97
|
+
StakingABI,
|
|
98
|
+
[INTEREST_RATE_5APY_X64]
|
|
99
|
+
)) as StakingMockFixedAPY;
|
|
100
|
+
|
|
101
|
+
await stake(staker1, 10000, staking);
|
|
102
|
+
await stake(staker2, 10000, staking);
|
|
103
|
+
await stake(staker3, 10000, staking);
|
|
104
|
+
|
|
105
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
106
|
+
return { staking };
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const fixture_1year_single = async (wallets, provider) => {
|
|
110
|
+
const staking: StakingMockFixedAPY = (await waffle.deployContract(
|
|
111
|
+
provider.getWallets()[0],
|
|
112
|
+
StakingABI,
|
|
113
|
+
[INTEREST_RATE_5APY_X64]
|
|
114
|
+
)) as StakingMockFixedAPY;
|
|
115
|
+
|
|
116
|
+
await stake(staker3, 10000, staking);
|
|
117
|
+
|
|
118
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
119
|
+
return { staking };
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
it("should set APY successfully", async () => {
|
|
123
|
+
const { staking } = await waffle.loadFixture(fixture_initOnly);
|
|
124
|
+
|
|
125
|
+
const beforeSetInterestRateIn128 = await staking.interestRatePerBlockX64();
|
|
126
|
+
|
|
127
|
+
const interestRatePerBlockX64 = BN.from(INTEREST_RATE_10APY_X64); // x64 representation of same number
|
|
128
|
+
const interestRateInt128Format = BN.from(INTEREST_RATE_10APY_128); // 128 representation of same number
|
|
129
|
+
await staking.setAPY(interestRatePerBlockX64);
|
|
130
|
+
|
|
131
|
+
const afterSetInterestRateIn128 = await staking.interestRatePerBlockX64();
|
|
132
|
+
|
|
133
|
+
expect(afterSetInterestRateIn128).to.not.equal(beforeSetInterestRateIn128);
|
|
134
|
+
expect(afterSetInterestRateIn128).to.equal(interestRateInt128Format);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("should update staker info after stake operation", async () => {
|
|
138
|
+
const { staking } = await waffle.loadFixture(fixture_initOnly);
|
|
139
|
+
|
|
140
|
+
await stake(staker1, 9000, staking);
|
|
141
|
+
|
|
142
|
+
let info = await staking.stakersInfo(staker1.address);
|
|
143
|
+
const initialShares = (await staking.SHARE_DECIMALS()).mul(9000);
|
|
144
|
+
expect(info.lastSharePrice)
|
|
145
|
+
.to.equal(
|
|
146
|
+
(await staking.SHARE_PRECISION()).div(await staking.SHARE_DECIMALS())
|
|
147
|
+
)
|
|
148
|
+
.to.eq(await staking.sharePrice()); // (1g$ with 2 decimals)
|
|
149
|
+
expect(await staking.sharesSupply())
|
|
150
|
+
.to.equal(initialShares)
|
|
151
|
+
.to.equal(await staking.totalSupply());
|
|
152
|
+
expect(await staking.sharesOf(staker1.address))
|
|
153
|
+
.eq(initialShares)
|
|
154
|
+
.eq(await staking.balanceOf(staker1.address));
|
|
155
|
+
expect(info.rewardsPaid).to.equal(0);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should handle stake/withdraw the minimal amount of 1", async () => {
|
|
159
|
+
const { staking } = await waffle.loadFixture(fixture_initOnly);
|
|
160
|
+
|
|
161
|
+
await stake(staker4, 1, staking);
|
|
162
|
+
|
|
163
|
+
await advanceBlocks(BLOCKS_TEN_YEARS);
|
|
164
|
+
await advanceBlocks(BLOCKS_FOUR_YEARS);
|
|
165
|
+
|
|
166
|
+
await expectSavings(staker4, 1, staking); // (1.01^14) = 1.979931
|
|
167
|
+
// await expect((await staking.sharePrice()).eq(BN.from(1979931))).to.be.true;
|
|
168
|
+
|
|
169
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
170
|
+
|
|
171
|
+
await expectSavings(staker4, 2, staking); // (1.01^15) = 2.078928
|
|
172
|
+
await expect((await staking.sharePrice()).eq(207892821613185)).to.be.true;
|
|
173
|
+
|
|
174
|
+
const minimalShares = await staking.amountToShares(1);
|
|
175
|
+
const stakerInfo = await staking.stakersInfo(staker4.address);
|
|
176
|
+
console.log({
|
|
177
|
+
sharePrice: await staking.sharePrice(),
|
|
178
|
+
minimalShares,
|
|
179
|
+
stakerInfo,
|
|
180
|
+
stakerShares: await staking.balanceOf(staker4.address)
|
|
181
|
+
});
|
|
182
|
+
await staking.withdraw(staker4.address, minimalShares); //this also withdraws the donated rewards
|
|
183
|
+
|
|
184
|
+
let info = await staking.stakersInfo(staker4.address);
|
|
185
|
+
await expectSavings(staker4, 1, staking);
|
|
186
|
+
expect(info.rewardsPaid).to.equal(1);
|
|
187
|
+
expect(await staking.balanceOf(staker4.address)).to.equal(
|
|
188
|
+
10000 - minimalShares.toNumber()
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
await expect(
|
|
192
|
+
staking.withdraw(
|
|
193
|
+
staker4.address,
|
|
194
|
+
(await staking.amountToShares(1)).sub(1)
|
|
195
|
+
)
|
|
196
|
+
).revertedWith("min shares");
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("should fail on staking 0", async () => {
|
|
200
|
+
const { staking } = await waffle.loadFixture(fixture_initOnly);
|
|
201
|
+
await expect(stake(staker4, 0, staking)).to.be.revertedWith("stake 0");
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
xit("should fail on staking with donationRatio > 100", async () => {
|
|
205
|
+
const { staking } = await waffle.loadFixture(fixture_initOnly);
|
|
206
|
+
await expect(stake(staker4, 1, 101, staking)).to.be.revertedWith(
|
|
207
|
+
"donation"
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("should fail on staking less than minimal amount of 1", async () => {
|
|
212
|
+
const { staking } = await waffle.loadFixture(fixture_initOnly);
|
|
213
|
+
await expect(stake(staker4, 0.99, staking)).to.be.reverted;
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("Should fail to withdraw exceeding amount", async () => {
|
|
217
|
+
const { staking } = await waffle.loadFixture(fixture_initOnly);
|
|
218
|
+
await stake(staker1, 1000, staking);
|
|
219
|
+
|
|
220
|
+
const shares = await staking.balanceOf(staker1.address);
|
|
221
|
+
await expect(staking.withdraw(staker1.address, shares.add(1))).revertedWith(
|
|
222
|
+
"no balance"
|
|
223
|
+
);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("Should fail to withdraw when empty balance", async () => {
|
|
227
|
+
const { staking } = await waffle.loadFixture(fixture_initOnly);
|
|
228
|
+
|
|
229
|
+
await expect(staking.withdraw(staker1.address, 0)).revertedWith(
|
|
230
|
+
"no balance"
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("should update global stats after stake operation", async () => {
|
|
235
|
+
const { staking } = await waffle.loadFixture(fixture_initOnly);
|
|
236
|
+
const statsBefore = await staking.stats();
|
|
237
|
+
const PRECISION = await staking.PRECISION();
|
|
238
|
+
|
|
239
|
+
await stake(staker1, 9000, staking);
|
|
240
|
+
|
|
241
|
+
const statsAfter = await staking.stats();
|
|
242
|
+
expect(statsAfter.lastUpdateBlock.gt(statsBefore.lastUpdateBlock));
|
|
243
|
+
expect(statsAfter.totalStaked).to.equal(9000);
|
|
244
|
+
expect(await staking.sharesSupply()).eq(
|
|
245
|
+
(await staking.SHARE_DECIMALS()).mul(9000)
|
|
246
|
+
);
|
|
247
|
+
expect(statsAfter.totalRewardsPaid).to.equal(0);
|
|
248
|
+
expect(statsAfter.savings).to.equal(PRECISION.mul(9000));
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("should update staker info after withdraw operation", async () => {
|
|
252
|
+
const { staking } = await waffle.loadFixture(fixture_initOnly);
|
|
253
|
+
await stake(staker1, 9000, staking);
|
|
254
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
255
|
+
|
|
256
|
+
const sharesToWithdraw = await staking.amountToShares(4000);
|
|
257
|
+
const rewardsBalanceBefore = await staking.earned(staker1.address);
|
|
258
|
+
expect(rewardsBalanceBefore).eq(450);
|
|
259
|
+
await staking.withdraw(staker1.address, sharesToWithdraw);
|
|
260
|
+
|
|
261
|
+
let info = await staking.stakersInfo(staker1.address);
|
|
262
|
+
|
|
263
|
+
const initialShares = (await staking.SHARE_DECIMALS()).mul(9000);
|
|
264
|
+
const shares = await staking.sharesOf(staker1.address);
|
|
265
|
+
const savings = await staking.getSavings(staker1.address);
|
|
266
|
+
const rewardsBalance = await staking.earned(staker1.address);
|
|
267
|
+
const depositShareAfterWithdraw = info.lastSharePrice
|
|
268
|
+
.mul(shares)
|
|
269
|
+
.div(await staking.SHARE_PRECISION());
|
|
270
|
+
|
|
271
|
+
expect(savings).to.eq(5450); // 9000 deposit + 450 rewards - 4000 withdrawn
|
|
272
|
+
expect(rewardsBalance).to.eq(0); // 449 - 190
|
|
273
|
+
expect(shares).to.equal(initialShares.sub(sharesToWithdraw));
|
|
274
|
+
expect(info.rewardsPaid).to.equal(450); //relative amount of withdraw from total savings multiplied by rewards earned 4000/9450 * 450 and rounded up
|
|
275
|
+
|
|
276
|
+
await staking.withdraw(staker1.address, shares); //now withdraw everything
|
|
277
|
+
info = await staking.stakersInfo(staker1.address);
|
|
278
|
+
expect(await staking.sharesOf(staker1.address)).eq(0);
|
|
279
|
+
expect(info.rewardsPaid).to.equal(450);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it("should update global stats after withdraw operation", async () => {
|
|
283
|
+
const { staking } = await waffle.loadFixture(fixture_initOnly);
|
|
284
|
+
await stake(staker1, 9000, staking);
|
|
285
|
+
const statsBefore = await staking.stats();
|
|
286
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
287
|
+
|
|
288
|
+
const sharesToWithdraw = await staking.amountToShares(4000);
|
|
289
|
+
await staking.withdraw(staker1.address, sharesToWithdraw);
|
|
290
|
+
|
|
291
|
+
const statsAfter = await staking.stats();
|
|
292
|
+
const initialShares = (await staking.SHARE_DECIMALS()).mul(9000);
|
|
293
|
+
expect(statsAfter.lastUpdateBlock.gt(statsBefore.lastUpdateBlock));
|
|
294
|
+
expect(statsAfter.totalStaked).to.equal(9000 - 4000 + 450); // 9000 - (4000 - 190 rewards component withdrawn)
|
|
295
|
+
expect(await staking.sharesSupply()).to.equal(
|
|
296
|
+
initialShares.sub(sharesToWithdraw)
|
|
297
|
+
);
|
|
298
|
+
expect(statsAfter.totalRewardsPaid).to.equal(450);
|
|
299
|
+
expect(statsAfter.savings).to.equal(await staking.compoundNextBlock());
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("should compound savings over period", async () => {
|
|
303
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
304
|
+
console.log(
|
|
305
|
+
"shares:",
|
|
306
|
+
await staking.balanceOf(staker1.address),
|
|
307
|
+
await staking.balanceOf(staker2.address),
|
|
308
|
+
await staking.balanceOf(staker3.address),
|
|
309
|
+
"info:",
|
|
310
|
+
await staking.stakersInfo(staker1.address),
|
|
311
|
+
await staking.stakersInfo(staker2.address),
|
|
312
|
+
await staking.stakersInfo(staker3.address)
|
|
313
|
+
);
|
|
314
|
+
let savings = await staking.getSavings(staker1.address);
|
|
315
|
+
expect(savings).to.equal(10500);
|
|
316
|
+
savings = await staking.getSavings(staker2.address);
|
|
317
|
+
expect(savings).to.equal(10500);
|
|
318
|
+
savings = await staking.getSavings(staker3.address);
|
|
319
|
+
expect(savings).to.equal(10499); //bought in 2 blocks after
|
|
320
|
+
|
|
321
|
+
let info = await staking.stakersInfo(staker1.address);
|
|
322
|
+
const initialShares = (await staking.SHARE_DECIMALS()).mul(10000);
|
|
323
|
+
expect(await staking.principle(staker1.address)).to.equal(10000);
|
|
324
|
+
expect(await staking.balanceOf(staker1.address)).to.equal(initialShares);
|
|
325
|
+
|
|
326
|
+
info = await staking.stakersInfo(staker2.address);
|
|
327
|
+
expect(await staking.principle(staker2.address)).to.equal(9999);
|
|
328
|
+
expect(await staking.balanceOf(staker2.address)).to.equal(99999999);
|
|
329
|
+
expect(info.rewardsPaid).to.equal(0);
|
|
330
|
+
|
|
331
|
+
info = await staking.stakersInfo(staker3.address);
|
|
332
|
+
expect(await staking.principle(staker3.address)).to.equal(9999);
|
|
333
|
+
expect(await staking.balanceOf(staker3.address)).to.equal(99999998);
|
|
334
|
+
expect(info.rewardsPaid).to.equal(0);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it("should compound savings over 2 years and new staker after 1 year", async () => {
|
|
338
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
339
|
+
|
|
340
|
+
//add staker after first year
|
|
341
|
+
await stake(staker4, 125125, staking);
|
|
342
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
343
|
+
//check all stakes after 2nd year
|
|
344
|
+
let savings = await staking.getSavings(staker1.address);
|
|
345
|
+
expect(savings).to.equal(11025);
|
|
346
|
+
savings = await staking.getSavings(staker2.address);
|
|
347
|
+
expect(savings).to.equal(11025);
|
|
348
|
+
savings = await staking.getSavings(staker3.address);
|
|
349
|
+
expect(savings).to.equal(11025);
|
|
350
|
+
savings = await staking.getSavings(staker4.address);
|
|
351
|
+
expect(savings).to.equal(131381);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it("should withdraw full amount", async () => {
|
|
355
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
356
|
+
const balance = await staking.sharesOf(staker1.address);
|
|
357
|
+
await staking.withdraw(staker1.address, balance);
|
|
358
|
+
const info = await staking.stakersInfo(staker1.address);
|
|
359
|
+
|
|
360
|
+
expect(await staking.getSavings(staker1.address)).to.equal(0);
|
|
361
|
+
expect(await staking.balanceOf(staker1.address)).to.equal(0);
|
|
362
|
+
expect(info.rewardsPaid).to.equal(500);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it("should withdraw partial amount and calculate savings correctly after 1 year", async () => {
|
|
366
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
367
|
+
const sharesBefore = await staking.sharesOf(staker3.address);
|
|
368
|
+
//9500 withdraw / sharePrice = shares to reduce
|
|
369
|
+
const expectedSharesRedeemed = await staking.amountToShares(9500);
|
|
370
|
+
await staking.withdraw(staker3.address, expectedSharesRedeemed);
|
|
371
|
+
|
|
372
|
+
const balanceAfterWithdraw = await staking.getSavings(staker3.address);
|
|
373
|
+
expect(balanceAfterWithdraw).to.equal(999); //shares are not exactly 9500
|
|
374
|
+
expect((await staking.stakersInfo(staker3.address)).rewardsPaid).to.eq(500);
|
|
375
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
376
|
+
|
|
377
|
+
const info = await staking.stakersInfo(staker3.address);
|
|
378
|
+
const earnedRewards = await staking.earned(staker3.address);
|
|
379
|
+
expect(await staking.getSavings(staker3.address)).to.equal(1049); //savings after 999 + 1 year 5%
|
|
380
|
+
expect(earnedRewards).to.equal(50);
|
|
381
|
+
|
|
382
|
+
//check shares
|
|
383
|
+
expect(await staking.sharesOf(staker3.address)).to.equal(
|
|
384
|
+
sharesBefore.sub(expectedSharesRedeemed)
|
|
385
|
+
);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
xit("should withdraw partial amount when partially donating and calculate savings correctly after 1 year", async () => {
|
|
389
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
390
|
+
const infoBefore = await staking.stakersInfo(staker2.address);
|
|
391
|
+
const expectedSharesRedeemed = await getExpectedSharesChange(
|
|
392
|
+
9500 + 125,
|
|
393
|
+
staking
|
|
394
|
+
); //withdrawing 9500 but 125 donated rewards will be withdrawn also
|
|
395
|
+
|
|
396
|
+
await staking.withdraw(staker2.address, BN.from(9500)); // will withdraw 9500 from savings but also 125 donated rewards, 375 will be withdrawn from the rewards part.
|
|
397
|
+
|
|
398
|
+
const balanceAfterWithdraw = await staking.getSavings(staker2.address);
|
|
399
|
+
expect(balanceAfterWithdraw).to.equal(875); //10500 - 9500 + 125 donated
|
|
400
|
+
|
|
401
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
402
|
+
|
|
403
|
+
const info = await staking.stakersInfo(staker2.address);
|
|
404
|
+
const [earnedRewards, earnedRewardsAfterDonations] = await staking.earned(
|
|
405
|
+
staker2.address
|
|
406
|
+
);
|
|
407
|
+
expect(await staking.getSavings(staker2.address)).to.equal(
|
|
408
|
+
907 //918 after 1 year. rewards part 43, donated 43*0.25=10.75 = 918-10.75
|
|
409
|
+
); // 875 + 5%APY * 25%donation
|
|
410
|
+
expect(info.deposit).to.equal(875);
|
|
411
|
+
expect(info.rewardsPaid).to.equal(375);
|
|
412
|
+
expect(info.rewardsDonated).to.equal(125);
|
|
413
|
+
expect(info.avgDonationRatio).to.equal((await staking.PRECISION()).mul(25));
|
|
414
|
+
expect(info.shares.toNumber()).to.equal(
|
|
415
|
+
infoBefore.shares.sub(expectedSharesRedeemed)
|
|
416
|
+
);
|
|
417
|
+
expect(
|
|
418
|
+
info.shares
|
|
419
|
+
.mul(await staking.sharePrice())
|
|
420
|
+
.div(await staking.SHARE_PRECISION())
|
|
421
|
+
).to.equal(info.deposit.add(earnedRewards));
|
|
422
|
+
expect(await staking.getSavings(staker2.address)).to.equal(
|
|
423
|
+
info.deposit.add(earnedRewardsAfterDonations)
|
|
424
|
+
);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
xit("should withdraw partial amount when donating 100% and calculate savings correctly after 1 year", async () => {
|
|
428
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
429
|
+
const infoBefore = await staking.stakersInfo(staker1.address);
|
|
430
|
+
const expectedSharesRedeemed = await getExpectedSharesChange(
|
|
431
|
+
9500 + 500,
|
|
432
|
+
staking
|
|
433
|
+
); //withdrawing 9500 but 500 donated rewards will be withdrawn also
|
|
434
|
+
|
|
435
|
+
await staking.withdraw(staker1.address, BN.from(9500)); // this will withdraw 9500 from deposit but also 500 donated rewards
|
|
436
|
+
|
|
437
|
+
const balanceAfterWithdraw = await staking.getSavings(staker1.address);
|
|
438
|
+
expect(balanceAfterWithdraw).to.equal(500);
|
|
439
|
+
|
|
440
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
441
|
+
|
|
442
|
+
const info = await staking.stakersInfo(staker1.address);
|
|
443
|
+
const [earnedRewards, earnedRewardsAfterDonations] = await staking.earned(
|
|
444
|
+
staker1.address
|
|
445
|
+
);
|
|
446
|
+
expect(await staking.getSavings(staker1.address)).to.equal(500);
|
|
447
|
+
expect(info.deposit).to.equal(500);
|
|
448
|
+
expect(info.rewardsPaid).to.equal(0);
|
|
449
|
+
expect(info.rewardsDonated).to.equal(500);
|
|
450
|
+
expect(info.avgDonationRatio).to.equal(
|
|
451
|
+
(await staking.PRECISION()).mul(100)
|
|
452
|
+
);
|
|
453
|
+
expect(info.shares.toNumber()).to.equal(
|
|
454
|
+
infoBefore.shares.sub(expectedSharesRedeemed)
|
|
455
|
+
);
|
|
456
|
+
expect(
|
|
457
|
+
info.shares
|
|
458
|
+
.mul(await staking.sharePrice())
|
|
459
|
+
.div(await staking.SHARE_PRECISION())
|
|
460
|
+
).to.equal(info.deposit.add(earnedRewards));
|
|
461
|
+
expect(await staking.getSavings(staker1.address)).to.equal(
|
|
462
|
+
info.deposit.add(earnedRewardsAfterDonations)
|
|
463
|
+
);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
xit("should withdraw rewards from rewards only", async () => {
|
|
467
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
468
|
+
const infoBefore = await staking.stakersInfo(staker3.address);
|
|
469
|
+
const balance = await staking.getSavings(staker3.address);
|
|
470
|
+
|
|
471
|
+
const expectedSharesRedeemed = await getExpectedSharesChange(500, staking);
|
|
472
|
+
await staking.withdraw(staker3.address, 500);
|
|
473
|
+
const info = await staking.stakersInfo(staker3.address);
|
|
474
|
+
|
|
475
|
+
expect(balance).to.equal(10500); //initial stake 10000 + 5%
|
|
476
|
+
expect(await staking.getSavings(staker3.address)).to.equal(10000);
|
|
477
|
+
expect(info.deposit).to.equal(10000);
|
|
478
|
+
expect(info.shares.toNumber()).to.equal(
|
|
479
|
+
infoBefore.shares.sub(expectedSharesRedeemed)
|
|
480
|
+
);
|
|
481
|
+
expect(info.rewardsPaid).to.equal(500);
|
|
482
|
+
expect(info.rewardsDonated).to.equal(0);
|
|
483
|
+
expect(info.avgDonationRatio).to.equal(0);
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
xit("should update avgDonationRatio after second stake", async () => {
|
|
487
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
488
|
+
const infoBefore = await staking.stakersInfo(staker1.address);
|
|
489
|
+
const statsBefore = await staking.stats();
|
|
490
|
+
|
|
491
|
+
await staking.stake(
|
|
492
|
+
staker1.address,
|
|
493
|
+
BN.from(infoBefore.shares) // staker1 buys same amount of shares he had
|
|
494
|
+
.mul(await staking.sharePrice())
|
|
495
|
+
.div(await staking.SHARE_PRECISION()),
|
|
496
|
+
0
|
|
497
|
+
);
|
|
498
|
+
|
|
499
|
+
const infoAfter = await staking.stakersInfo(staker1.address);
|
|
500
|
+
const statsAfter = await staking.stats();
|
|
501
|
+
const PRECISION = await staking.PRECISION();
|
|
502
|
+
|
|
503
|
+
expect(infoBefore.avgDonationRatio).to.equal(PRECISION.mul(100)); // 1st stake had 100% donation
|
|
504
|
+
expect(infoAfter.avgDonationRatio).to.equal(PRECISION.mul(50)); // 2nd stake had 0% for same amount of shares => 50% average
|
|
505
|
+
expect(statsBefore.avgDonationRatio).to.equal(PRECISION.mul(125).div(3)); // total avg of 3 stakers => 0, 25, 100 each had staked 10000
|
|
506
|
+
expect(statsAfter.avgDonationRatio).to.equal(
|
|
507
|
+
BN.from("31249999999999999999")
|
|
508
|
+
); // 31.25% = (2 * 0% + 1 * 25% + 1 * 100%) / 4
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
xit("should update avgDonationRatio after partial withdraw", async () => {
|
|
512
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
513
|
+
const infoBeforeWithdraw = await staking.stakersInfo(staker1.address);
|
|
514
|
+
const statsBeforeWithdraw = await staking.stats();
|
|
515
|
+
const expectedSharesRedeemed = await getExpectedSharesChange(
|
|
516
|
+
2000 + 500,
|
|
517
|
+
staking
|
|
518
|
+
); //2000 + 500 that are donated
|
|
519
|
+
await staking.withdraw(staker1.address, 2000); //this also withdraws the donated rewards
|
|
520
|
+
const statsAfterWithdraw = await staking.stats();
|
|
521
|
+
|
|
522
|
+
const expectedGlobalAvgRatio = statsBeforeWithdraw.avgDonationRatio
|
|
523
|
+
.mul(statsBeforeWithdraw.totalShares)
|
|
524
|
+
.sub(expectedSharesRedeemed.mul(infoBeforeWithdraw.avgDonationRatio))
|
|
525
|
+
.div(statsAfterWithdraw.totalShares);
|
|
526
|
+
|
|
527
|
+
const infoAfterWithdraw = await staking.stakersInfo(staker1.address);
|
|
528
|
+
expect(infoBeforeWithdraw.avgDonationRatio).to.equal(
|
|
529
|
+
infoAfterWithdraw.avgDonationRatio
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
expect(expectedGlobalAvgRatio).to.equal(
|
|
533
|
+
statsAfterWithdraw.avgDonationRatio
|
|
534
|
+
);
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
it("should calculate correct share price after savings has grown", async () => {
|
|
538
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
539
|
+
const SHARE_PRECISION = await staking.SHARE_PRECISION();
|
|
540
|
+
|
|
541
|
+
const savingsBefore = await staking.compound();
|
|
542
|
+
const expectedSharePriceBefore = BN.from(savingsBefore)
|
|
543
|
+
.mul(SHARE_PRECISION)
|
|
544
|
+
.div(await staking.PRECISION())
|
|
545
|
+
.div(await staking.sharesSupply());
|
|
546
|
+
const actualSharePriceBefore = await staking.sharePrice();
|
|
547
|
+
expect(actualSharePriceBefore).to.equal(expectedSharePriceBefore);
|
|
548
|
+
|
|
549
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
550
|
+
|
|
551
|
+
const savingsAfter = savingsBefore.mul(105).div(100); //estimate
|
|
552
|
+
const expectedSharePriceAfter = BN.from(savingsAfter)
|
|
553
|
+
.mul(SHARE_PRECISION)
|
|
554
|
+
.div(await staking.PRECISION())
|
|
555
|
+
.div(await staking.sharesSupply());
|
|
556
|
+
const actualSharePriceAfter = await staking.sharePrice();
|
|
557
|
+
expect(actualSharePriceAfter.div(1e8)).to.eq(
|
|
558
|
+
expectedSharePriceAfter.div(1e8)
|
|
559
|
+
); //compare rough estimate so we reduce precision by 1e8
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
it("should check compound function compounds savings correctly", async () => {
|
|
563
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
564
|
+
const PRECISION = await staking.PRECISION();
|
|
565
|
+
|
|
566
|
+
const expectedCompoundBefore = 3 * 10000 * 1.05; // 3 stakers of 10000 with 5 APY, after one year
|
|
567
|
+
const actualCompoundBefore = (await staking.compound()).div(PRECISION);
|
|
568
|
+
expect(actualCompoundBefore).to.equal(expectedCompoundBefore);
|
|
569
|
+
|
|
570
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
571
|
+
|
|
572
|
+
const expectedCompoundAfter = expectedCompoundBefore * 1.05;
|
|
573
|
+
const actualCompoundAfter = (await staking.compound()).div(PRECISION);
|
|
574
|
+
expect(actualCompoundAfter).to.equal(expectedCompoundAfter);
|
|
575
|
+
expect(actualCompoundAfter.gt(actualCompoundBefore)).to.be.true;
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
it("should calculate earned rewards in period", async () => {
|
|
579
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
580
|
+
let earnedRewards1 = await staking.earned(staker1.address);
|
|
581
|
+
let earnedRewards2 = await staking.earned(staker2.address);
|
|
582
|
+
let earnedRewards3 = await staking.earned(staker3.address);
|
|
583
|
+
|
|
584
|
+
expect(earnedRewards1).equal(earnedRewards2).equal(500);
|
|
585
|
+
expect(earnedRewards3).eq(499);
|
|
586
|
+
|
|
587
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
588
|
+
earnedRewards1 = await staking.earned(staker1.address);
|
|
589
|
+
earnedRewards2 = await staking.earned(staker2.address);
|
|
590
|
+
earnedRewards3 = await staking.earned(staker3.address);
|
|
591
|
+
|
|
592
|
+
expect(earnedRewards1)
|
|
593
|
+
.equal(earnedRewards2)
|
|
594
|
+
.equal(earnedRewards3)
|
|
595
|
+
.equal(1025);
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
it("Should undo reward part and update staker info", async () => {
|
|
599
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
600
|
+
|
|
601
|
+
const initialInfo = await staking.stakersInfo(staker3.address);
|
|
602
|
+
const sharesToWithdraw = await staking.amountToShares(500);
|
|
603
|
+
const initialRewards = await staking.earned(staker3.address);
|
|
604
|
+
await staking.withdrawAndUndo(staker3.address, sharesToWithdraw);
|
|
605
|
+
|
|
606
|
+
const infoAfterUndo = await staking.stakersInfo(staker3.address);
|
|
607
|
+
|
|
608
|
+
expect(await staking.getSavings(staker3.address)).to.equal(10499);
|
|
609
|
+
|
|
610
|
+
expect(await staking.earned(staker3.address)).to.eq(500);
|
|
611
|
+
expect(infoAfterUndo.rewardsPaid).to.equal(initialInfo.rewardsPaid);
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
it("Should undo reward and keep global stats the same", async () => {
|
|
615
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
616
|
+
|
|
617
|
+
const initialStats = await staking.stats();
|
|
618
|
+
|
|
619
|
+
const initialSavings = await staking.compoundNextBlock(); //withdrawAndUndo will calculate savings of next block
|
|
620
|
+
const sharesToWithdraw = await staking.amountToShares(500);
|
|
621
|
+
const initialShares = await staking.sharesSupply();
|
|
622
|
+
await staking.withdrawAndUndo(staker3.address, sharesToWithdraw);
|
|
623
|
+
const statsAfterUndo = await staking.stats();
|
|
624
|
+
|
|
625
|
+
expect(statsAfterUndo.savings.div(ethers.constants.WeiPerEther)).to.equal(
|
|
626
|
+
31500
|
|
627
|
+
);
|
|
628
|
+
|
|
629
|
+
expect(initialStats.totalRewardsPaid).to.equal(
|
|
630
|
+
statsAfterUndo.totalRewardsPaid
|
|
631
|
+
);
|
|
632
|
+
|
|
633
|
+
expect(await staking.sharesSupply()).to.lt(initialShares);
|
|
634
|
+
expect(initialStats.totalStaked).to.equal(statsAfterUndo.totalStaked);
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
xit("Should undo reward when part of them is donated and keep info and global stats the same", async () => {
|
|
638
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
639
|
+
|
|
640
|
+
const initialStats = await staking.stats();
|
|
641
|
+
const initialInfo = await staking.stakersInfo(staker2.address);
|
|
642
|
+
const initialSavings = await staking.getSavings(staker2.address);
|
|
643
|
+
const latestSavings = await staking.compoundNextBlock(); //withdrawAndUndo will calculate savings of next block
|
|
644
|
+
|
|
645
|
+
await staking.withdrawAndUndo(staker2.address, 375); //375 rewards 125 donated
|
|
646
|
+
|
|
647
|
+
const infoAfterUndo = await staking.stakersInfo(staker2.address);
|
|
648
|
+
expect(await staking.getSavings(staker2.address)).to.equal(initialSavings);
|
|
649
|
+
expect(infoAfterUndo.rewardsPaid).to.equal(0);
|
|
650
|
+
expect(infoAfterUndo.rewardsDonated).to.equal(0);
|
|
651
|
+
|
|
652
|
+
expect(infoAfterUndo.avgDonationRatio).to.equal(
|
|
653
|
+
initialInfo.avgDonationRatio
|
|
654
|
+
);
|
|
655
|
+
expect(initialInfo.shares).to.eq(infoAfterUndo.shares);
|
|
656
|
+
|
|
657
|
+
//check global stats
|
|
658
|
+
const statsAfterUndo = await staking.stats();
|
|
659
|
+
|
|
660
|
+
expect(statsAfterUndo.savings).to.equal(latestSavings);
|
|
661
|
+
|
|
662
|
+
expect(initialStats.totalRewardsDonated).to.equal(
|
|
663
|
+
statsAfterUndo.totalRewardsDonated
|
|
664
|
+
);
|
|
665
|
+
expect(initialStats.totalRewardsPaid).to.equal(
|
|
666
|
+
statsAfterUndo.totalRewardsPaid
|
|
667
|
+
);
|
|
668
|
+
expect(initialStats.totalShares).to.equal(statsAfterUndo.totalShares);
|
|
669
|
+
expect(initialStats.totalStaked).to.equal(statsAfterUndo.totalStaked);
|
|
670
|
+
expect(initialStats.avgDonationRatio).to.equal(
|
|
671
|
+
statsAfterUndo.avgDonationRatio.add(1) //precision loss during withdraw avgDonationRatio calculation
|
|
672
|
+
);
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
it("Should undo reward when withdrawing partial rewards keep info and global stats the same", async () => {
|
|
676
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
677
|
+
|
|
678
|
+
const initialInfo = await staking.stakersInfo(staker2.address);
|
|
679
|
+
const initialSavings = await staking.getSavings(staker2.address);
|
|
680
|
+
const initialStats = await staking.stats();
|
|
681
|
+
const initialTotalSavings = await staking.compoundNextBlock(); //withdrawAndUndo will calculate savings of next block
|
|
682
|
+
const initialSharesSupply = await staking.sharesSupply();
|
|
683
|
+
//current rewards are 500 so 250 is only partial withdraw of rewards
|
|
684
|
+
const sharesToWithdraw = await staking.amountToShares(250);
|
|
685
|
+
await staking.withdrawAndUndo(staker2.address, sharesToWithdraw);
|
|
686
|
+
|
|
687
|
+
const infoAfterUndo = await staking.stakersInfo(staker2.address);
|
|
688
|
+
expect(await staking.getSavings(staker2.address)).to.equal(initialSavings);
|
|
689
|
+
expect(infoAfterUndo.rewardsPaid).to.equal(initialInfo.rewardsPaid);
|
|
690
|
+
|
|
691
|
+
//check global stats
|
|
692
|
+
const statsAfterUndo = await staking.stats();
|
|
693
|
+
|
|
694
|
+
expect(statsAfterUndo.savings).to.equal(initialTotalSavings);
|
|
695
|
+
|
|
696
|
+
expect(initialStats.totalRewardsDonated).to.equal(
|
|
697
|
+
statsAfterUndo.totalRewardsDonated
|
|
698
|
+
);
|
|
699
|
+
expect(initialStats.totalRewardsPaid).to.equal(
|
|
700
|
+
statsAfterUndo.totalRewardsPaid
|
|
701
|
+
);
|
|
702
|
+
expect(initialSharesSupply).to.equal((await staking.sharesSupply()).add(1)); //precision loss when converting back from rewards amount to shares
|
|
703
|
+
expect(initialStats.totalStaked).to.equal(statsAfterUndo.totalStaked);
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
//helper test
|
|
707
|
+
// it.only("Should not suffer from endless precission loss", async () => {
|
|
708
|
+
// const { staking } = await waffle.loadFixture(fixture_1year_single);
|
|
709
|
+
|
|
710
|
+
// const initialShares = await staking.sharesOf(staker3.address);
|
|
711
|
+
// const maxLoss = await staking.amountToShares(1);
|
|
712
|
+
// for (let i = 0; i < 500; i++) {
|
|
713
|
+
// expect(await staking.getSavings(staker3.address)).eq(10500);
|
|
714
|
+
// expect(await staking.sharesOf(staker3.address)).gte(
|
|
715
|
+
// initialShares.sub(maxLoss)
|
|
716
|
+
// );
|
|
717
|
+
// expect(await staking.earned(staker3.address)).eq(500);
|
|
718
|
+
// const sharesToWithdraw = await staking.amountToShares(500);
|
|
719
|
+
// await staking.withdrawAndUndo(staker3.address, sharesToWithdraw);
|
|
720
|
+
// }
|
|
721
|
+
// });
|
|
722
|
+
|
|
723
|
+
xit("Should undo reward when withdrawing rewards + deposit and update deposit info and stats correctly", async () => {});
|
|
724
|
+
|
|
725
|
+
it("Should be able to withdraw right after staking", async () => {
|
|
726
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
727
|
+
await stake(staker4, 10000, staking);
|
|
728
|
+
await expect(
|
|
729
|
+
staking.withdraw(
|
|
730
|
+
staker4.address,
|
|
731
|
+
await staking.balanceOf(staker4.address)
|
|
732
|
+
)
|
|
733
|
+
).not.reverted;
|
|
734
|
+
|
|
735
|
+
const info = await staking.stakersInfo(staker4.address);
|
|
736
|
+
expect(await staking.getSavings(staker4.address)).to.equal(0);
|
|
737
|
+
expect(info.rewardsPaid).to.equal(0);
|
|
738
|
+
expect(info.lastSharePrice.div(1e8)).to.equal(
|
|
739
|
+
(await staking.sharePrice()).div(1e8)
|
|
740
|
+
);
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
it("should calculate savings correctly after set APY ", async () => {
|
|
744
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
745
|
+
await stake(staker4, 125125, staking);
|
|
746
|
+
|
|
747
|
+
// before set, APY is 5%
|
|
748
|
+
const beforeSetInterestRateIn128 = await staking.interestRatePerBlockX64();
|
|
749
|
+
expect(beforeSetInterestRateIn128).to.equal(INTEREST_RATE_5APY_128);
|
|
750
|
+
|
|
751
|
+
// set APY to 10%
|
|
752
|
+
await staking.setAPY(INTEREST_RATE_10APY_X64);
|
|
753
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
754
|
+
|
|
755
|
+
await expectSavings(staker1, 11550, staking);
|
|
756
|
+
await expectSavings(staker2, 11550, staking);
|
|
757
|
+
await expectSavings(staker3, 11550, staking); // 10000 + 10000((1.05APY1 * 1.10APY2) - 1)
|
|
758
|
+
await expectSavings(staker4, 137637, staking); // 125125((1.10APY2) - 1)
|
|
759
|
+
|
|
760
|
+
// set APY to 8%
|
|
761
|
+
await staking.setAPY(INTEREST_RATE_8APY_X64);
|
|
762
|
+
await advanceBlocks(BLOCKS_ONE_YEAR);
|
|
763
|
+
|
|
764
|
+
await expectSavings(staker1, 12474, staking);
|
|
765
|
+
await expectSavings(staker2, 12474, staking);
|
|
766
|
+
await expectSavings(staker3, 12474, staking);
|
|
767
|
+
await expectSavings(staker4, 148648, staking); // 125125((1.10APY2 * 1.08APY3) - 1)
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
it("should handle first stake big, followed by smaller actions", async () => {
|
|
771
|
+
const { staking } = await waffle.loadFixture(fixture_2);
|
|
772
|
+
|
|
773
|
+
await stake(staker4, 10000000, staking);
|
|
774
|
+
|
|
775
|
+
const savingsAfterBigStake = await staking.getSavings(staker4.address);
|
|
776
|
+
const infoAfterBigStake = await staking.stakersInfo(staker4.address);
|
|
777
|
+
await stake(signers[0], 5, staking);
|
|
778
|
+
|
|
779
|
+
const savingsAfterSmallStake = await staking.getSavings(staker4.address);
|
|
780
|
+
const smallStakeSavings = await staking.getSavings(signers[0].address);
|
|
781
|
+
expect(smallStakeSavings).gt(0);
|
|
782
|
+
const sharesAfterBigStake = await staking.balanceOf(staker4.address);
|
|
783
|
+
|
|
784
|
+
const sharesAfterSmallStake = await staking.balanceOf(signers[0].address);
|
|
785
|
+
expect(savingsAfterSmallStake.eq(savingsAfterBigStake)).to.be.true;
|
|
786
|
+
expect(sharesAfterSmallStake).gt(0);
|
|
787
|
+
|
|
788
|
+
const onegdShares = await staking.amountToShares(1);
|
|
789
|
+
await expect(staking.withdraw(staker4.address, 1000)).revertedWith("min");
|
|
790
|
+
|
|
791
|
+
await expect(staking.withdraw(staker4.address, onegdShares)).not.reverted;
|
|
792
|
+
await expect(
|
|
793
|
+
staking.withdraw(
|
|
794
|
+
signers[0].address,
|
|
795
|
+
await staking.balanceOf(signers[0].address)
|
|
796
|
+
)
|
|
797
|
+
).not.reverted;
|
|
798
|
+
|
|
799
|
+
const sharesAfterWithdraw = await staking.balanceOf(staker4.address);
|
|
800
|
+
const sharesAfterWithdraw2 = await staking.balanceOf(signers[0].address);
|
|
801
|
+
|
|
802
|
+
expect(sharesAfterWithdraw).to.equal(sharesAfterBigStake.sub(onegdShares));
|
|
803
|
+
expect(sharesAfterWithdraw2).to.equal(0);
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
it("should handle first stake small, followed by 100 Billion stake", async () => {
|
|
807
|
+
const { staking } = await waffle.loadFixture(fixture_2);
|
|
808
|
+
|
|
809
|
+
await stake(signers[0], 5, staking);
|
|
810
|
+
await stake(staker4, 1e13, staking);
|
|
811
|
+
|
|
812
|
+
const onegdShares = await staking.amountToShares(1);
|
|
813
|
+
await staking.withdraw(staker4.address, onegdShares);
|
|
814
|
+
|
|
815
|
+
await expect(
|
|
816
|
+
staking.withdraw(
|
|
817
|
+
signers[0].address,
|
|
818
|
+
await staking.balanceOf(signers[0].address)
|
|
819
|
+
)
|
|
820
|
+
).not.reverted;
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
it("should handle first 100 Billion stake, followed by a small", async () => {
|
|
824
|
+
const { staking } = await waffle.loadFixture(fixture_2);
|
|
825
|
+
|
|
826
|
+
await stake(staker4, 1e13, staking);
|
|
827
|
+
await stake(signers[0], 5, staking);
|
|
828
|
+
|
|
829
|
+
const onegdShares = await staking.amountToShares(1);
|
|
830
|
+
await expect(
|
|
831
|
+
staking.withdraw(
|
|
832
|
+
signers[0].address,
|
|
833
|
+
await staking.balanceOf(signers[0].address)
|
|
834
|
+
)
|
|
835
|
+
).not.reverted;
|
|
836
|
+
await expect(staking.withdraw(staker4.address, onegdShares)).not.reverted;
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
xit("should withdraw all when amount=max uint", async () => {
|
|
840
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
841
|
+
await expect(staking.withdraw(staker3.address, 0)).revertedWith("balance");
|
|
842
|
+
await staking.withdraw(staker3.address, ethers.constants.MaxUint256);
|
|
843
|
+
const info = await staking.stakersInfo(staker3.address);
|
|
844
|
+
|
|
845
|
+
expect(info.rewardsPaid).to.equal(499);
|
|
846
|
+
expect(await staking.sharesOf(staker3.address)).to.equal(0);
|
|
847
|
+
expect(await staking.getSavings(staker3.address)).to.equal(0);
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
it("should be able to get rewards debt (ie savings - deposits - donated rewards)", async () => {
|
|
851
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
852
|
+
const debt = (await staking.getRewardsDebt()).div(
|
|
853
|
+
ethers.utils.parseEther("1")
|
|
854
|
+
); //debt is in 1e18 precision
|
|
855
|
+
expect(debt).to.equal(1500); //30000*1.05 - 300000
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
it("should not be able to stake less than share price", async () => {
|
|
859
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
860
|
+
await advanceBlocks(BLOCKS_TEN_YEARS * 20);
|
|
861
|
+
|
|
862
|
+
await expect(stake(staker1, 1, staking)).to.revertedWith("share");
|
|
863
|
+
await expect(stake(staker1, 2, staking)).to.not.reverted;
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
it("should not be able to withdraw less than share price", async () => {
|
|
867
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
868
|
+
await advanceBlocks(BLOCKS_TEN_YEARS * 10);
|
|
869
|
+
|
|
870
|
+
const sharePrice = await staking.sharePrice();
|
|
871
|
+
await expect(staking.withdraw(staker3.address, 1)).to.revertedWith("share");
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
it("should handle stake/withdraw for 1 Trillion staked for 50 years", async () => {
|
|
875
|
+
const { staking } = await waffle.loadFixture(fixture_1year);
|
|
876
|
+
await stake(staker3, 100000000000000, staking);
|
|
877
|
+
await advanceBlocks(BLOCKS_TEN_YEARS * 5);
|
|
878
|
+
|
|
879
|
+
await expect(
|
|
880
|
+
staking.withdraw(
|
|
881
|
+
staker3.address,
|
|
882
|
+
await staking.balanceOf(staker3.address)
|
|
883
|
+
)
|
|
884
|
+
).to.not.reverted;
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
it("should have undo reward handle invalid input", async () => {
|
|
888
|
+
const staking: StakingMockFixedAPY = (await (
|
|
889
|
+
await ethers.getContractFactory("StakingMockFixedAPY")
|
|
890
|
+
).deploy(INTEREST_RATE_5APY_X64)) as StakingMockFixedAPY;
|
|
891
|
+
|
|
892
|
+
//undo 0 rewards
|
|
893
|
+
await stake(staker4, 10000, staking);
|
|
894
|
+
await staking.withdraw(
|
|
895
|
+
staker4.address,
|
|
896
|
+
await staking.balanceOf(staker4.address)
|
|
897
|
+
);
|
|
898
|
+
await expect(staking.undoReward(staker4.address, 0)).to.not.reverted;
|
|
899
|
+
});
|
|
900
|
+
});
|