@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,998 @@
|
|
|
1
|
+
import { default as hre, ethers, waffle } from "hardhat";
|
|
2
|
+
import { BigNumber, Contract, Signer } from "ethers";
|
|
3
|
+
import { expect } from "chai";
|
|
4
|
+
import { GoodReserveCDai, GReputation, GoodDollarStaking } from "../../types";
|
|
5
|
+
import { createDAO, advanceBlocks } from "../helpers";
|
|
6
|
+
import { FormatTypes } from "ethers/lib/utils";
|
|
7
|
+
import { getFounders } from "../../scripts/getFounders";
|
|
8
|
+
|
|
9
|
+
const BN = ethers.BigNumber;
|
|
10
|
+
export const NULL_ADDRESS = ethers.constants.AddressZero;
|
|
11
|
+
export const BLOCK_INTERVAL = 30;
|
|
12
|
+
|
|
13
|
+
describe("GoodDollarStaking - check GOOD rewards based on GovernanceStaking.test.js", () => {
|
|
14
|
+
let dai: Contract;
|
|
15
|
+
let cDAI: Contract;
|
|
16
|
+
let goodReserve: GoodReserveCDai;
|
|
17
|
+
let grep: GReputation;
|
|
18
|
+
let avatar,
|
|
19
|
+
goodDollar,
|
|
20
|
+
controller,
|
|
21
|
+
founder,
|
|
22
|
+
staker,
|
|
23
|
+
staker2,
|
|
24
|
+
staker3,
|
|
25
|
+
schemeMock,
|
|
26
|
+
signers,
|
|
27
|
+
nameService,
|
|
28
|
+
setDAOAddress;
|
|
29
|
+
|
|
30
|
+
before(async () => {
|
|
31
|
+
[founder, staker, staker2, staker3, ...signers] = await ethers.getSigners();
|
|
32
|
+
schemeMock = signers.pop();
|
|
33
|
+
const cdaiFactory = await ethers.getContractFactory("cDAIMock");
|
|
34
|
+
|
|
35
|
+
let {
|
|
36
|
+
controller: ctrl,
|
|
37
|
+
avatar: av,
|
|
38
|
+
gd,
|
|
39
|
+
identity,
|
|
40
|
+
nameService: ns,
|
|
41
|
+
setDAOAddress: sda,
|
|
42
|
+
daiAddress,
|
|
43
|
+
cdaiAddress,
|
|
44
|
+
reserve,
|
|
45
|
+
reputation
|
|
46
|
+
} = await createDAO();
|
|
47
|
+
dai = await ethers.getContractAt("DAIMock", daiAddress);
|
|
48
|
+
cDAI = await ethers.getContractAt("cDAIMock", cdaiAddress);
|
|
49
|
+
avatar = av;
|
|
50
|
+
controller = ctrl;
|
|
51
|
+
setDAOAddress = sda;
|
|
52
|
+
nameService = ns;
|
|
53
|
+
goodReserve = reserve as GoodReserveCDai;
|
|
54
|
+
console.log("deployed dao", {
|
|
55
|
+
founder: founder.address,
|
|
56
|
+
gd,
|
|
57
|
+
identity,
|
|
58
|
+
controller,
|
|
59
|
+
avatar
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
grep = (await ethers.getContractAt(
|
|
63
|
+
"GReputation",
|
|
64
|
+
reputation
|
|
65
|
+
)) as GReputation;
|
|
66
|
+
goodDollar = await ethers.getContractAt("IGoodDollar", gd);
|
|
67
|
+
|
|
68
|
+
//This set addresses should be another function because when we put this initialization of addresses in initializer then nameservice is not ready yet so no proper addresses
|
|
69
|
+
// await goodReserve.setAddresses();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const fixture = async (wallets, provider) => {
|
|
73
|
+
const f = await ethers.getContractFactory("GoodDollarStakingMock");
|
|
74
|
+
|
|
75
|
+
wallets = provider.getWallets();
|
|
76
|
+
const staking = (await waffle.deployContract(
|
|
77
|
+
wallets[0],
|
|
78
|
+
{
|
|
79
|
+
abi: JSON.parse(
|
|
80
|
+
f.interface.format(FormatTypes.json) as string
|
|
81
|
+
) as any[],
|
|
82
|
+
bytecode: f.bytecode
|
|
83
|
+
},
|
|
84
|
+
[nameService.address, BN.from("1000000007735630000"), 518400 * 12, 30]
|
|
85
|
+
)) as GoodDollarStaking;
|
|
86
|
+
|
|
87
|
+
await staking.upgrade();
|
|
88
|
+
|
|
89
|
+
return { staking };
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const fixture_ready = async (wallets, provider) => {
|
|
93
|
+
const f = await ethers.getContractFactory("GoodDollarStakingMock");
|
|
94
|
+
|
|
95
|
+
wallets = provider.getWallets();
|
|
96
|
+
const staking = (await waffle.deployContract(
|
|
97
|
+
wallets[0],
|
|
98
|
+
{
|
|
99
|
+
abi: JSON.parse(
|
|
100
|
+
f.interface.format(FormatTypes.json) as string
|
|
101
|
+
) as any[],
|
|
102
|
+
bytecode: f.bytecode
|
|
103
|
+
},
|
|
104
|
+
[nameService.address, BN.from("1000000007735630000"), 518400 * 12, 30]
|
|
105
|
+
)) as GoodDollarStaking;
|
|
106
|
+
|
|
107
|
+
await staking.upgrade();
|
|
108
|
+
|
|
109
|
+
await setDAOAddress("GDAO_STAKING", staking.address);
|
|
110
|
+
|
|
111
|
+
return { staking };
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const fixture_upgradeTest = async (wallets, provider) => {
|
|
115
|
+
const f = await ethers.getContractFactory("GoodDollarStaking");
|
|
116
|
+
|
|
117
|
+
wallets = provider.getWallets();
|
|
118
|
+
const staking = (await waffle.deployContract(
|
|
119
|
+
wallets[0],
|
|
120
|
+
{
|
|
121
|
+
abi: JSON.parse(
|
|
122
|
+
f.interface.format(FormatTypes.json) as string
|
|
123
|
+
) as any[],
|
|
124
|
+
bytecode: f.bytecode
|
|
125
|
+
},
|
|
126
|
+
[nameService.address, BN.from("1000000007735630000"), 518400 * 12, 30]
|
|
127
|
+
)) as GoodDollarStaking;
|
|
128
|
+
|
|
129
|
+
//TODO: register as scheme here
|
|
130
|
+
|
|
131
|
+
return { staking };
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
it("Should not revert withdraw but also not mint GOOD reward when staking contract is not minter", async () => {
|
|
135
|
+
const { staking } = await waffle.loadFixture(fixture);
|
|
136
|
+
await goodDollar.mint(founder.address, "100");
|
|
137
|
+
await goodDollar.approve(staking.address, "100");
|
|
138
|
+
await staking.stake("100");
|
|
139
|
+
await advanceBlocks(5);
|
|
140
|
+
await expect(
|
|
141
|
+
staking.withdrawStake(await staking.balanceOf(founder.address))
|
|
142
|
+
).to.not.reverted;
|
|
143
|
+
expect(await grep.balanceOfLocal(founder.address)).to.eq(0);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("Should be able to mint rewards after set GDAO staking contract", async () => {
|
|
147
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
148
|
+
|
|
149
|
+
await goodDollar.mint(founder.address, "100");
|
|
150
|
+
await goodDollar.approve(staking.address, "100");
|
|
151
|
+
await staking.stake("100");
|
|
152
|
+
await advanceBlocks(5);
|
|
153
|
+
|
|
154
|
+
const GDAOBalanceBeforeWithdraw = await grep.balanceOfLocal(
|
|
155
|
+
founder.address
|
|
156
|
+
);
|
|
157
|
+
await staking.withdrawStake(await staking.amountToShares("100"));
|
|
158
|
+
const GDAOBalanceAfterWithdraw = await grep.balanceOfLocal(founder.address);
|
|
159
|
+
|
|
160
|
+
expect(GDAOBalanceAfterWithdraw).to.gt(GDAOBalanceBeforeWithdraw);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("Avatar should be able to change rewards per block", async () => {
|
|
164
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
165
|
+
|
|
166
|
+
const ictrl = await ethers.getContractAt(
|
|
167
|
+
"Controller",
|
|
168
|
+
controller,
|
|
169
|
+
schemeMock
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
let encodedCall = staking.interface.encodeFunctionData(
|
|
173
|
+
"setMonthlyGOODRewards",
|
|
174
|
+
[ethers.utils.parseEther("1728000")]
|
|
175
|
+
);
|
|
176
|
+
await ictrl.genericCall(staking.address, encodedCall, avatar, 0);
|
|
177
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
178
|
+
expect(rewardsPerBlock).to.equal(
|
|
179
|
+
ethers.utils.parseEther("1728000").div(BN.from("518400")) // 1728000 is montlhy reward amount and 518400 is monthly blocks for FUSE chain
|
|
180
|
+
);
|
|
181
|
+
await goodDollar.mint(founder.address, "100");
|
|
182
|
+
await goodDollar.approve(staking.address, "100");
|
|
183
|
+
const stakeBlockNumber = (await ethers.provider.getBlockNumber()) + 1;
|
|
184
|
+
await staking.stake("100");
|
|
185
|
+
await advanceBlocks(4);
|
|
186
|
+
const GDAOBalanceBeforeWithdraw = await grep.balanceOfLocal(
|
|
187
|
+
founder.address
|
|
188
|
+
);
|
|
189
|
+
await staking.withdrawStake(await staking.balanceOf(founder.address));
|
|
190
|
+
const withdrawBlockNumber = await ethers.provider.getBlockNumber();
|
|
191
|
+
const GDAOBalanceAfterWithdraw = await grep.balanceOfLocal(founder.address);
|
|
192
|
+
const multiplier = withdrawBlockNumber - stakeBlockNumber;
|
|
193
|
+
const calculatedReward = rewardsPerBlock.mul(multiplier); // We calculate user rewards since it's the only staker so gets whole rewards so rewardsPerBlock * multipler(block that passed between stake and withdraw)
|
|
194
|
+
expect(GDAOBalanceAfterWithdraw).to.be.equal(
|
|
195
|
+
GDAOBalanceBeforeWithdraw.add(calculatedReward)
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("Should be able to withdraw rewards without withdraw stake", async () => {
|
|
200
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
201
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
202
|
+
await goodDollar.mint(founder.address, "100");
|
|
203
|
+
await goodDollar.approve(staking.address, "100");
|
|
204
|
+
const stakeBlockNumber = (await ethers.provider.getBlockNumber()) + 1;
|
|
205
|
+
await staking.stake("100");
|
|
206
|
+
await advanceBlocks(4);
|
|
207
|
+
const GDAOBalanceBeforeWithdraw = await grep.balanceOfLocal(
|
|
208
|
+
founder.address
|
|
209
|
+
);
|
|
210
|
+
const transaction = await (await staking.withdrawRewards()).wait();
|
|
211
|
+
const withdrawBlockNumber = await ethers.provider.getBlockNumber();
|
|
212
|
+
const GDAOBalanceAfterWithdraw = await grep.balanceOfLocal(founder.address);
|
|
213
|
+
const multiplier = withdrawBlockNumber - stakeBlockNumber;
|
|
214
|
+
const calculatedReward = rewardsPerBlock.mul(multiplier); // We calculate user rewards since it's the only staker so gets whole rewards so rewardsPerBlock * multipler(block that passed between stake and withdraw)
|
|
215
|
+
expect(GDAOBalanceAfterWithdraw).to.be.equal(
|
|
216
|
+
GDAOBalanceBeforeWithdraw.add(calculatedReward)
|
|
217
|
+
);
|
|
218
|
+
expect(transaction.events.find(_ => _.event === "ReputationEarned")).to.be
|
|
219
|
+
.not.empty;
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("Should be able to withdraw transferred stakes", async () => {
|
|
223
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
224
|
+
|
|
225
|
+
await goodDollar.mint(staker.address, "100");
|
|
226
|
+
await goodDollar.connect(staker).approve(staking.address, "100");
|
|
227
|
+
await staking.connect(staker).stake("100");
|
|
228
|
+
await advanceBlocks(4);
|
|
229
|
+
await staking
|
|
230
|
+
.connect(staker)
|
|
231
|
+
.transfer(founder.address, await staking.balanceOf(staker.address));
|
|
232
|
+
await staking.connect(staker).withdrawRewards();
|
|
233
|
+
const gdaoBalanceBeforeWithdraw = await grep.balanceOfLocal(
|
|
234
|
+
founder.address
|
|
235
|
+
);
|
|
236
|
+
await staking.withdrawStake(await staking.balanceOf(founder.address));
|
|
237
|
+
const gdaoBalanceAfterWithdraw = await grep.balanceOfLocal(founder.address);
|
|
238
|
+
expect(gdaoBalanceAfterWithdraw).to.gt(gdaoBalanceBeforeWithdraw);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("should not be able to withdraw after they send their stake to somebody else", async () => {
|
|
242
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
243
|
+
|
|
244
|
+
await goodDollar.mint(staker.address, "100");
|
|
245
|
+
await goodDollar.connect(staker).approve(staking.address, "100");
|
|
246
|
+
await staking.connect(staker).stake("100");
|
|
247
|
+
await advanceBlocks(4);
|
|
248
|
+
await staking
|
|
249
|
+
.connect(staker)
|
|
250
|
+
.transfer(founder.address, await staking.balanceOf(staker.address));
|
|
251
|
+
|
|
252
|
+
await expect(staking.connect(staker).withdrawStake(1)).revertedWith(
|
|
253
|
+
"no balance"
|
|
254
|
+
);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it("it should distribute reward with correct precision", async () => {
|
|
258
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
259
|
+
|
|
260
|
+
const ictrl = await ethers.getContractAt(
|
|
261
|
+
"Controller",
|
|
262
|
+
controller,
|
|
263
|
+
schemeMock
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
let encodedCall = staking.interface.encodeFunctionData(
|
|
267
|
+
"setMonthlyGOODRewards",
|
|
268
|
+
["17280000000000000000"] // Give 0.0001 GDAO per block so 17.28 GDAO per month
|
|
269
|
+
);
|
|
270
|
+
await ictrl.genericCall(staking.address, encodedCall, avatar, 0);
|
|
271
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
272
|
+
await goodDollar.mint(founder.address, "100");
|
|
273
|
+
await goodDollar.approve(staking.address, "100");
|
|
274
|
+
const stakeBlockNumber = (await ethers.provider.getBlockNumber()) + 1;
|
|
275
|
+
await staking.stake("100");
|
|
276
|
+
await advanceBlocks(4);
|
|
277
|
+
const GDAOBalanceBeforeWithdraw = await grep.balanceOfLocal(
|
|
278
|
+
founder.address
|
|
279
|
+
);
|
|
280
|
+
await staking.withdrawStake(await staking.balanceOf(founder.address));
|
|
281
|
+
const withdrawBlockNumber = await ethers.provider.getBlockNumber();
|
|
282
|
+
const GDAOBalanceAfterWithdraw = await grep.balanceOfLocal(founder.address);
|
|
283
|
+
const multiplier = withdrawBlockNumber - stakeBlockNumber;
|
|
284
|
+
const calculatedReward = rewardsPerBlock.mul(multiplier); // We calculate user rewards since it's the only staker so gets whole rewards so rewardsPerBlock * multipler(block that passed between stake and withdraw)
|
|
285
|
+
expect(calculatedReward).gt(0);
|
|
286
|
+
expect(GDAOBalanceAfterWithdraw).to.be.equal(
|
|
287
|
+
GDAOBalanceBeforeWithdraw.add(calculatedReward)
|
|
288
|
+
);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it("it should not generate rewards when rewards per block set to 0", async () => {
|
|
292
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
293
|
+
|
|
294
|
+
const ictrl = await ethers.getContractAt(
|
|
295
|
+
"Controller",
|
|
296
|
+
controller,
|
|
297
|
+
schemeMock
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
let encodedCall = staking.interface.encodeFunctionData(
|
|
301
|
+
"setMonthlyGOODRewards",
|
|
302
|
+
["0"] // Give 0 GDAO per block
|
|
303
|
+
);
|
|
304
|
+
await ictrl.genericCall(staking.address, encodedCall, avatar, 0);
|
|
305
|
+
|
|
306
|
+
await goodDollar.mint(founder.address, "100");
|
|
307
|
+
await goodDollar.approve(staking.address, "100");
|
|
308
|
+
await staking.stake("100");
|
|
309
|
+
const userProductivity = await staking["getStaked(address)"](
|
|
310
|
+
founder.address
|
|
311
|
+
);
|
|
312
|
+
expect(userProductivity[0]).to.be.equal("1000000");
|
|
313
|
+
await advanceBlocks(4);
|
|
314
|
+
const GDAOBalanceBeforeWithdraw = await grep.balanceOfLocal(
|
|
315
|
+
founder.address
|
|
316
|
+
);
|
|
317
|
+
await staking.withdrawStake(await staking.balanceOf(founder.address));
|
|
318
|
+
const GDAOBalanceAfterWithdraw = await grep.balanceOfLocal(founder.address);
|
|
319
|
+
expect(GDAOBalanceAfterWithdraw.sub(GDAOBalanceBeforeWithdraw)).to.equal(0);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it("it should return productivity values correctly", async () => {
|
|
323
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
324
|
+
await goodDollar.mint(founder.address, "100");
|
|
325
|
+
await goodDollar.approve(staking.address, "100");
|
|
326
|
+
await staking.stake("100");
|
|
327
|
+
const productivityValue = await staking["getStaked(address)"](
|
|
328
|
+
founder.address
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
expect(productivityValue[0].toString())
|
|
332
|
+
.eq(productivityValue[1].toString())
|
|
333
|
+
.to.equal(await staking.sharesOf(founder.address));
|
|
334
|
+
await staking.withdrawStake(await staking.balanceOf(founder.address));
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it("it should return earned rewards with pending ones properly for a short period", async () => {
|
|
338
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
339
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
340
|
+
await goodDollar.mint(founder.address, "100");
|
|
341
|
+
await goodDollar.approve(staking.address, "100");
|
|
342
|
+
const stakeBlockNumber = (await ethers.provider.getBlockNumber()) + 1;
|
|
343
|
+
await staking.stake("100");
|
|
344
|
+
await advanceBlocks(5);
|
|
345
|
+
const [totalEarnedGOOD] = await staking["getUserPendingReward(address)"](
|
|
346
|
+
founder.address
|
|
347
|
+
);
|
|
348
|
+
const pendingRewardBlockNumber = await ethers.provider.getBlockNumber();
|
|
349
|
+
const multiplier = pendingRewardBlockNumber - stakeBlockNumber;
|
|
350
|
+
const calculatedPendingReward = rewardsPerBlock.mul(multiplier); // We calculate user rewards since it's the only staker so gets whole rewards so rewardsPerBlock * multipler(block that passed between stake and withdraw)
|
|
351
|
+
expect(totalEarnedGOOD).to.be.equal(calculatedPendingReward);
|
|
352
|
+
await staking.withdrawStake(await staking.balanceOf(founder.address));
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it("Accumulated per share has enough precision when reward << totalproductivity", async () => {
|
|
356
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
357
|
+
|
|
358
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
359
|
+
await goodDollar.mint(founder.address, "100000000000000"); // 1 trillion gd stake
|
|
360
|
+
await goodDollar.approve(staking.address, "1000000000000");
|
|
361
|
+
const stakeBlockNumber = (await ethers.provider.getBlockNumber()) + 1;
|
|
362
|
+
await staking.stake("1000000000000");
|
|
363
|
+
await advanceBlocks(4);
|
|
364
|
+
const GDAOBalanceBeforeWithdraw = await grep.balanceOfLocal(
|
|
365
|
+
founder.address
|
|
366
|
+
);
|
|
367
|
+
await staking.withdrawStake(await staking.sharesOf(founder.address));
|
|
368
|
+
const withdrawBlockNumber = await ethers.provider.getBlockNumber();
|
|
369
|
+
const GDAOBalanceAfterWithdraw = await grep.balanceOfLocal(founder.address);
|
|
370
|
+
const multiplier = withdrawBlockNumber - stakeBlockNumber;
|
|
371
|
+
const calculatedReward = rewardsPerBlock.mul(multiplier); // We calculate user rewards since it's the only staker so gets whole rewards so rewardsPerBlock * multipler(block that passed between stake and withdraw)
|
|
372
|
+
expect(GDAOBalanceAfterWithdraw).to.be.equal(
|
|
373
|
+
GDAOBalanceBeforeWithdraw.add(calculatedReward)
|
|
374
|
+
);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it("user receive fractional gdao properly when his stake << totalProductivity", async () => {
|
|
378
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
379
|
+
|
|
380
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
381
|
+
await goodDollar.mint(founder.address, "800"); // 8gd
|
|
382
|
+
await goodDollar.mint(staker.address, "200"); // 2gd
|
|
383
|
+
await goodDollar.approve(staking.address, "800");
|
|
384
|
+
await goodDollar.connect(staker).approve(staking.address, "200");
|
|
385
|
+
await staking.stake("800");
|
|
386
|
+
const secondStakerStakeBlockNumber =
|
|
387
|
+
(await ethers.provider.getBlockNumber()) + 1;
|
|
388
|
+
await staking.connect(staker).stake("200");
|
|
389
|
+
await advanceBlocks(4);
|
|
390
|
+
const GDAOBalanceBeforeWithdraw = await grep.balanceOfLocal(staker.address);
|
|
391
|
+
const FounderGDAOBalanceBeforeWithdraw = await grep.balanceOfLocal(
|
|
392
|
+
founder.address
|
|
393
|
+
);
|
|
394
|
+
const founderShares = await staking.sharesOf(founder.address);
|
|
395
|
+
const stakerShares = await staking.sharesOf(staker.address);
|
|
396
|
+
|
|
397
|
+
const totalShares = await staking.sharesSupply();
|
|
398
|
+
await staking.withdrawStake(founderShares);
|
|
399
|
+
|
|
400
|
+
const founderWithdrawBlockNumber = await ethers.provider.getBlockNumber();
|
|
401
|
+
await staking.connect(staker).withdrawStake(stakerShares);
|
|
402
|
+
const GDAOBalanceAfterWithdraw = await grep.balanceOfLocal(staker.address);
|
|
403
|
+
const FounderGDAOBalanceAfterWithdraw = await grep.balanceOfLocal(
|
|
404
|
+
founder.address
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
const founderCalculatedRewards = rewardsPerBlock.add(
|
|
408
|
+
rewardsPerBlock
|
|
409
|
+
.mul(founderShares)
|
|
410
|
+
.mul(founderWithdrawBlockNumber - secondStakerStakeBlockNumber)
|
|
411
|
+
.div(totalShares)
|
|
412
|
+
); // Founder should get full rewards for one block plus his relative share of the rewards
|
|
413
|
+
const stakerCalculatedRewards = rewardsPerBlock
|
|
414
|
+
.mul(stakerShares)
|
|
415
|
+
.mul(founderWithdrawBlockNumber - secondStakerStakeBlockNumber)
|
|
416
|
+
.div(totalShares)
|
|
417
|
+
.add(rewardsPerBlock)
|
|
418
|
+
.add(1); // Staker should get his relative share of rewards initially then when Founder withdraw their stake Staker would own %100 of rewards and would get full amount
|
|
419
|
+
expect(FounderGDAOBalanceAfterWithdraw).to.be.equal(
|
|
420
|
+
FounderGDAOBalanceBeforeWithdraw.add(founderCalculatedRewards)
|
|
421
|
+
);
|
|
422
|
+
expect(GDAOBalanceAfterWithdraw).to.be.equal(
|
|
423
|
+
GDAOBalanceBeforeWithdraw.add(stakerCalculatedRewards)
|
|
424
|
+
);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it("it should be able to tranfer tokens when user approve", async () => {
|
|
428
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
429
|
+
|
|
430
|
+
await goodDollar.mint(founder.address, "100");
|
|
431
|
+
await goodDollar.approve(staking.address, "100");
|
|
432
|
+
await staking.stake("100");
|
|
433
|
+
const sharesBalance = await staking.balanceOf(founder.address);
|
|
434
|
+
await staking.approve(staker.address, sharesBalance);
|
|
435
|
+
const stakerProductivityBeforeTransfer = await staking.getStaked(
|
|
436
|
+
staker.address
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
await staking
|
|
440
|
+
.connect(staker)
|
|
441
|
+
.transferFrom(founder.address, staker.address, sharesBalance);
|
|
442
|
+
const stakerProductivity = await staking.getStaked(staker.address);
|
|
443
|
+
|
|
444
|
+
expect(await staking.balanceOf(founder.address)).to.equal(0);
|
|
445
|
+
expect(await staking.balanceOf(staker.address)).to.equal(sharesBalance);
|
|
446
|
+
|
|
447
|
+
expect((await staking.goodStakerInfo(staker.address)).amount).to.equal(
|
|
448
|
+
sharesBalance
|
|
449
|
+
);
|
|
450
|
+
expect(stakerProductivityBeforeTransfer[0]).to.be.equal(0);
|
|
451
|
+
expect(stakerProductivity[0]).to.be.equal(sharesBalance);
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
it("it should return staker data", async () => {
|
|
455
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
456
|
+
|
|
457
|
+
await goodDollar.mint(staker2.address, "200");
|
|
458
|
+
await goodDollar.connect(staker2).approve(staking.address, "200");
|
|
459
|
+
await staking.connect(staker2).stake("100");
|
|
460
|
+
|
|
461
|
+
await advanceBlocks(10);
|
|
462
|
+
await staking.connect(staker2).stake("100"); //perform some action so GOOD rewardDebt is updated
|
|
463
|
+
|
|
464
|
+
expect((await staking.goodStakerInfo(staker2.address)).rewardDebt).to.gt(0); //debt should start according to accumulated rewards in contract. debt is the user stake starting point.
|
|
465
|
+
|
|
466
|
+
const sharesToWithdraw = await staking.amountToShares(1);
|
|
467
|
+
const sharesBalance = await staking.balanceOf(staker2.address);
|
|
468
|
+
await staking.connect(staker2).withdrawStake(sharesToWithdraw);
|
|
469
|
+
|
|
470
|
+
expect(await staking.balanceOf(staker2.address)).to.equal(
|
|
471
|
+
sharesBalance.sub(sharesToWithdraw)
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
expect((await staking.goodStakerInfo(staker2.address)).amount).to.equal(
|
|
475
|
+
sharesBalance.sub(sharesToWithdraw)
|
|
476
|
+
);
|
|
477
|
+
expect((await staking.goodStakerInfo(staker2.address)).rewardDebt).to.gt(0); //should have withdrawn rewards after withdraw stake
|
|
478
|
+
expect((await staking.goodStakerInfo(staker2.address)).rewardEarn).to.equal(
|
|
479
|
+
0
|
|
480
|
+
); //should have 0 pending rewards after withdraw stake
|
|
481
|
+
|
|
482
|
+
await advanceBlocks(10);
|
|
483
|
+
await goodDollar.connect(staker2).approve(staking.address, "200");
|
|
484
|
+
|
|
485
|
+
await staking.connect(staker2).stake("1"); //should calculate user pending rewards
|
|
486
|
+
|
|
487
|
+
expect(
|
|
488
|
+
(await staking.goodStakerInfo(staker2.address)).rewardEarn
|
|
489
|
+
).to.be.equal(
|
|
490
|
+
0 //should have 0 rewardEarned because every action, like the above stake withdraws gdao rewards
|
|
491
|
+
);
|
|
492
|
+
await advanceBlocks(2); // pass some blocks
|
|
493
|
+
const [userPendingGoodReward] = await staking[
|
|
494
|
+
"getUserPendingReward(address)"
|
|
495
|
+
](staker2.address);
|
|
496
|
+
expect(userPendingGoodReward).to.be.gt(0);
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it("it should return pendingRewards equal zero after withdraw", async () => {
|
|
500
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
501
|
+
|
|
502
|
+
await goodDollar.mint(staker.address, "200");
|
|
503
|
+
await goodDollar.connect(staker).approve(staking.address, "200");
|
|
504
|
+
await staking.connect(staker).stake("100");
|
|
505
|
+
await advanceBlocks(10);
|
|
506
|
+
|
|
507
|
+
let [userPendingGoodRewards] = await staking[
|
|
508
|
+
"getUserPendingReward(address)"
|
|
509
|
+
](staker.address);
|
|
510
|
+
expect(userPendingGoodRewards).to.be.gt(0);
|
|
511
|
+
await staking.connect(staker).withdrawRewards();
|
|
512
|
+
[userPendingGoodRewards] = await staking["getUserPendingReward(address)"](
|
|
513
|
+
staker.address
|
|
514
|
+
);
|
|
515
|
+
expect(userPendingGoodRewards).to.equal(0);
|
|
516
|
+
await advanceBlocks(1);
|
|
517
|
+
[userPendingGoodRewards] = await staking["getUserPendingReward(address)"](
|
|
518
|
+
staker.address
|
|
519
|
+
);
|
|
520
|
+
expect(userPendingGoodRewards).to.gt(0); //one block passed
|
|
521
|
+
|
|
522
|
+
await staking
|
|
523
|
+
.connect(staker)
|
|
524
|
+
.withdrawStake(await staking.sharesOf(staker.address));
|
|
525
|
+
[userPendingGoodRewards] = await staking["getUserPendingReward(address)"](
|
|
526
|
+
staker.address
|
|
527
|
+
);
|
|
528
|
+
expect(userPendingGoodRewards).to.be.equal(0);
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
it("it should calculate accumulated rewards per share correctly", async () => {
|
|
532
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
533
|
+
|
|
534
|
+
await goodDollar.mint(founder.address, "200");
|
|
535
|
+
await goodDollar.mint(staker.address, "200");
|
|
536
|
+
|
|
537
|
+
await goodDollar.approve(staking.address, "200");
|
|
538
|
+
await goodDollar.connect(staker).approve(staking.address, "200");
|
|
539
|
+
|
|
540
|
+
await staking.stake("100");
|
|
541
|
+
let accumulatedRewardsPerShare = (
|
|
542
|
+
await staking["totalRewardsPerShare()"]()
|
|
543
|
+
)[0];
|
|
544
|
+
expect(accumulatedRewardsPerShare).to.equal(0); //first has no accumulated rewards yet, since no blocks have passed since staking
|
|
545
|
+
|
|
546
|
+
let totalProductiviy = await staking.sharesSupply();
|
|
547
|
+
|
|
548
|
+
await staking.stake("100");
|
|
549
|
+
accumulatedRewardsPerShare = (await staking["totalRewardsPerShare()"]())[0];
|
|
550
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
551
|
+
expect(rewardsPerBlock).to.equal(
|
|
552
|
+
ethers.utils
|
|
553
|
+
.parseEther("2000000") //2M reputation
|
|
554
|
+
.div(await staking.getChainBlocksPerMonth())
|
|
555
|
+
);
|
|
556
|
+
console.log({ rewardsPerBlock, totalProductiviy });
|
|
557
|
+
|
|
558
|
+
//totalRewardsPerShare is in 1e27 , divid by 1e9 to get 1e18 decimals
|
|
559
|
+
expect(accumulatedRewardsPerShare.div(BN.from(1e9))).to.not.equal(
|
|
560
|
+
ethers.utils
|
|
561
|
+
.parseEther("2000000")
|
|
562
|
+
.mul(BN.from(1e2)) //G$ is 2 decimals, dividing reduces decimals by 2, so we first increase to 1e20 decimals
|
|
563
|
+
.div(await staking.getChainBlocksPerMonth())
|
|
564
|
+
.div(totalProductiviy)
|
|
565
|
+
.mul(BN.from("1"))
|
|
566
|
+
.mul(BN.from("10000000000000000")), //increase precision to 1e18 from totalProductivity G$ 2 decimals;
|
|
567
|
+
|
|
568
|
+
"1 blocks"
|
|
569
|
+
); //2 blocks passed but now we have 200 total productivity before 3rd stake
|
|
570
|
+
|
|
571
|
+
totalProductiviy = await staking.sharesSupply();
|
|
572
|
+
await staking.connect(staker).stake("100");
|
|
573
|
+
let accumulatedRewardsPerShare2 = (
|
|
574
|
+
await staking["totalRewardsPerShare()"]()
|
|
575
|
+
)[0];
|
|
576
|
+
|
|
577
|
+
//shouldnt be naive accumlattion of 2 blocks, since total productivity has changed between blocks
|
|
578
|
+
expect(accumulatedRewardsPerShare2.div(BN.from(1e9))).to.not.equal(
|
|
579
|
+
ethers.utils
|
|
580
|
+
.parseEther("2000000")
|
|
581
|
+
.mul(BN.from(1e2)) //G$ is 2 decimals, dividing reduces decimals by 2, so we first increase to 1e20 decimals
|
|
582
|
+
.div(await staking.getChainBlocksPerMonth())
|
|
583
|
+
.div(totalProductiviy)
|
|
584
|
+
.mul(BN.from("2"))
|
|
585
|
+
.mul(BN.from("10000000000000000")), //increase precision to 1e18 from totalProductivity G$ 2 decimals;
|
|
586
|
+
|
|
587
|
+
"2 blocks"
|
|
588
|
+
); //2 blocks passed but now we have 200 total productivity before 3rd stake
|
|
589
|
+
|
|
590
|
+
const calculatedAccRewards = rdiv(
|
|
591
|
+
ethers.utils
|
|
592
|
+
.parseEther("2000000")
|
|
593
|
+
.div(await staking.getChainBlocksPerMonth()),
|
|
594
|
+
totalProductiviy
|
|
595
|
+
);
|
|
596
|
+
//accumulated so far plus block accumulation
|
|
597
|
+
expect(accumulatedRewardsPerShare2).to.equal(
|
|
598
|
+
calculatedAccRewards.add(accumulatedRewardsPerShare).sub(1), //add rewards from previous block
|
|
599
|
+
"2 blocks correct"
|
|
600
|
+
);
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
it("Staking tokens should be 18 decimals", async () => {
|
|
604
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
605
|
+
|
|
606
|
+
const decimals = await staking.decimals();
|
|
607
|
+
expect(decimals.toString()).to.be.equal("18");
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
it("Stake amount should be positive", async () => {
|
|
611
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
612
|
+
|
|
613
|
+
await expect(staking.stake("0")).revertedWith("Cannot stake 0");
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
it("It should approve stake amount in order to stake", async () => {
|
|
617
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
618
|
+
|
|
619
|
+
await expect(staking.stake(ethers.utils.parseEther("10000000"))).to
|
|
620
|
+
.reverted;
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
it("Withdraw 0 should succeed", async () => {
|
|
624
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
625
|
+
|
|
626
|
+
await expect(staking.withdrawStake("0")).to.not.reverted;
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
it("Withdraw uint max should withdraw everything", async () => {
|
|
630
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
631
|
+
|
|
632
|
+
await goodDollar.mint(staker2.address, "200");
|
|
633
|
+
await goodDollar.connect(staker2).approve(staking.address, "200");
|
|
634
|
+
await staking.connect(staker2).stake("200");
|
|
635
|
+
await advanceBlocks(1000);
|
|
636
|
+
await staking
|
|
637
|
+
.connect(staker2)
|
|
638
|
+
.withdrawStake(await staking.sharesOf(staker2.address));
|
|
639
|
+
expect(await staking.getSavings(staker2.address)).to.equal(0);
|
|
640
|
+
const staked = await staking.getStaked(staker2.address);
|
|
641
|
+
staked.map(stake => {
|
|
642
|
+
expect(stake).to.equal(0);
|
|
643
|
+
});
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
it("Should use overriden _transfer that handles productivity when using transferFrom which is defined in super erc20 contract", async () => {
|
|
647
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
648
|
+
await expect(
|
|
649
|
+
staking.transferFrom(
|
|
650
|
+
founder.address,
|
|
651
|
+
staker.address,
|
|
652
|
+
ethers.utils.parseEther("10000000")
|
|
653
|
+
)
|
|
654
|
+
).to.reverted;
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
it("it should get rewards for previous stakes when stake new amount of tokens", async () => {
|
|
658
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
659
|
+
|
|
660
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
661
|
+
await goodDollar.mint(founder.address, "200");
|
|
662
|
+
await goodDollar.approve(staking.address, "200");
|
|
663
|
+
const stakeBlockNumber = (await ethers.provider.getBlockNumber()) + 1;
|
|
664
|
+
await staking.stake("100");
|
|
665
|
+
await advanceBlocks(5);
|
|
666
|
+
const gdaoBalanceBeforeGetRewards = await grep.balanceOfLocal(
|
|
667
|
+
founder.address
|
|
668
|
+
);
|
|
669
|
+
await staking.stake("100");
|
|
670
|
+
const getRewardsBlockNumber = await ethers.provider.getBlockNumber();
|
|
671
|
+
const gdaoBalanceAfterGetRewards = await grep.balanceOfLocal(
|
|
672
|
+
founder.address
|
|
673
|
+
);
|
|
674
|
+
const multiplier = getRewardsBlockNumber - stakeBlockNumber;
|
|
675
|
+
const calculatedReward = rewardsPerBlock.mul(multiplier); // We calculate user rewards since it's the only staker so gets whole rewards so rewardsPerBlock * multipler(block that passed between stake and withdraw)
|
|
676
|
+
await staking.withdrawStake(await staking.sharesOf(founder.address));
|
|
677
|
+
expect(gdaoBalanceAfterGetRewards).to.be.equal(
|
|
678
|
+
gdaoBalanceBeforeGetRewards.add(calculatedReward)
|
|
679
|
+
);
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
it("it should distribute rewards properly when there are multiple stakers", async () => {
|
|
683
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
684
|
+
|
|
685
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
686
|
+
const stakingAmount = BN.from("100");
|
|
687
|
+
await goodDollar.mint(founder.address, stakingAmount);
|
|
688
|
+
await goodDollar.mint(staker.address, stakingAmount);
|
|
689
|
+
await goodDollar.mint(signers[0].address, stakingAmount);
|
|
690
|
+
await goodDollar.mint(signers[1].address, stakingAmount);
|
|
691
|
+
|
|
692
|
+
await goodDollar.approve(staking.address, stakingAmount);
|
|
693
|
+
await goodDollar.connect(staker).approve(staking.address, stakingAmount);
|
|
694
|
+
await goodDollar
|
|
695
|
+
.connect(signers[0])
|
|
696
|
+
.approve(staking.address, stakingAmount);
|
|
697
|
+
await goodDollar
|
|
698
|
+
.connect(signers[1])
|
|
699
|
+
.approve(staking.address, stakingAmount);
|
|
700
|
+
await staking.stake(stakingAmount);
|
|
701
|
+
const stakerOneGDAOBalanceAfterStake = await grep.balanceOfLocal(
|
|
702
|
+
founder.address
|
|
703
|
+
);
|
|
704
|
+
await staking.connect(staker).stake(stakingAmount.div(10));
|
|
705
|
+
const stakerTwoGDAOBalanceAfterStake = await grep.balanceOfLocal(
|
|
706
|
+
staker.address
|
|
707
|
+
);
|
|
708
|
+
await staking.connect(signers[0]).stake(stakingAmount.div(4));
|
|
709
|
+
|
|
710
|
+
const stakerThreeGDAOBalanceAfterStake = await grep.balanceOfLocal(
|
|
711
|
+
signers[0].address
|
|
712
|
+
);
|
|
713
|
+
const stakerFourStakeBlockNumber =
|
|
714
|
+
(await ethers.provider.getBlockNumber()) + 1;
|
|
715
|
+
await staking.connect(signers[1]).stake(stakingAmount.div(5));
|
|
716
|
+
|
|
717
|
+
const stakerFourGDAOBalanceAfterStake = await grep.balanceOfLocal(
|
|
718
|
+
signers[1].address
|
|
719
|
+
);
|
|
720
|
+
await advanceBlocks(10);
|
|
721
|
+
|
|
722
|
+
const totalShares = await staking.sharesSupply();
|
|
723
|
+
const founderShares = await staking.sharesOf(founder.address);
|
|
724
|
+
await staking.withdrawStake(founderShares);
|
|
725
|
+
const stakerOneWithdrawBlockNumber = await ethers.provider.getBlockNumber();
|
|
726
|
+
const stakerOneGDAOBalanceAfterWithdraw = await grep.balanceOfLocal(
|
|
727
|
+
founder.address
|
|
728
|
+
);
|
|
729
|
+
|
|
730
|
+
const stakerShares = await staking.sharesOf(staker.address);
|
|
731
|
+
await staking.connect(staker).withdrawStake(stakerShares);
|
|
732
|
+
const stakerTwoGDAOBalanceAfterWithdraw = await grep.balanceOfLocal(
|
|
733
|
+
staker.address
|
|
734
|
+
);
|
|
735
|
+
|
|
736
|
+
const signer0Shares = await staking.sharesOf(signers[0].address);
|
|
737
|
+
await staking.connect(signers[0]).withdrawStake(signer0Shares);
|
|
738
|
+
const stakerThreeGDAOBalanceAfterWithdraw = await grep.balanceOfLocal(
|
|
739
|
+
signers[0].address
|
|
740
|
+
);
|
|
741
|
+
|
|
742
|
+
const signer1Shares = await staking.sharesOf(signers[1].address);
|
|
743
|
+
|
|
744
|
+
await staking.connect(signers[1]).withdrawStake(signer1Shares);
|
|
745
|
+
const stakerFourGDAOBalanceAfterWithdraw = await grep.balanceOfLocal(
|
|
746
|
+
signers[1].address
|
|
747
|
+
);
|
|
748
|
+
const stakerOneRewardsCalculated = rewardsPerBlock
|
|
749
|
+
.add(
|
|
750
|
+
rewardsPerBlock.mul(founderShares).div(founderShares.add(stakerShares))
|
|
751
|
+
)
|
|
752
|
+
.add(
|
|
753
|
+
rewardsPerBlock
|
|
754
|
+
.mul(founderShares)
|
|
755
|
+
.div(founderShares.add(stakerShares).add(signer0Shares))
|
|
756
|
+
)
|
|
757
|
+
.add(
|
|
758
|
+
rewardsPerBlock
|
|
759
|
+
.mul(founderShares)
|
|
760
|
+
.mul(stakerOneWithdrawBlockNumber - stakerFourStakeBlockNumber)
|
|
761
|
+
.div(totalShares)
|
|
762
|
+
)
|
|
763
|
+
.add(BN.from("2"));
|
|
764
|
+
|
|
765
|
+
const stakerTwoRewardsCalculated = rewardsPerBlock
|
|
766
|
+
.mul(stakerShares)
|
|
767
|
+
.div(founderShares.add(stakerShares))
|
|
768
|
+
.add(
|
|
769
|
+
rewardsPerBlock
|
|
770
|
+
.mul(stakerShares)
|
|
771
|
+
.div(founderShares.add(stakerShares).add(signer0Shares))
|
|
772
|
+
)
|
|
773
|
+
.add(
|
|
774
|
+
rewardsPerBlock
|
|
775
|
+
.mul(stakerShares)
|
|
776
|
+
.mul(stakerOneWithdrawBlockNumber - stakerFourStakeBlockNumber)
|
|
777
|
+
.div(totalShares)
|
|
778
|
+
)
|
|
779
|
+
.add(
|
|
780
|
+
rewardsPerBlock
|
|
781
|
+
.mul(stakerShares)
|
|
782
|
+
.div(stakerShares.add(signer0Shares).add(signer1Shares))
|
|
783
|
+
)
|
|
784
|
+
.add(BN.from("1"));
|
|
785
|
+
|
|
786
|
+
const stakerThreeRewardsCalculated = rewardsPerBlock
|
|
787
|
+
.mul(signer0Shares)
|
|
788
|
+
.div(founderShares.add(stakerShares).add(signer0Shares))
|
|
789
|
+
.add(
|
|
790
|
+
rewardsPerBlock
|
|
791
|
+
.mul(signer0Shares)
|
|
792
|
+
.mul(stakerOneWithdrawBlockNumber - stakerFourStakeBlockNumber)
|
|
793
|
+
.div(totalShares)
|
|
794
|
+
)
|
|
795
|
+
.add(
|
|
796
|
+
rewardsPerBlock
|
|
797
|
+
.mul(signer0Shares)
|
|
798
|
+
.div(stakerShares.add(signer0Shares).add(signer1Shares))
|
|
799
|
+
)
|
|
800
|
+
.add(
|
|
801
|
+
rewardsPerBlock.mul(signer0Shares).div(signer0Shares.add(signer1Shares))
|
|
802
|
+
)
|
|
803
|
+
.add(BN.from("2"));
|
|
804
|
+
|
|
805
|
+
const stakerFourRewardsCalculated = rewardsPerBlock
|
|
806
|
+
.mul(signer1Shares)
|
|
807
|
+
.mul(stakerOneWithdrawBlockNumber - stakerFourStakeBlockNumber)
|
|
808
|
+
.div(totalShares)
|
|
809
|
+
.add(
|
|
810
|
+
rewardsPerBlock
|
|
811
|
+
.mul(signer1Shares)
|
|
812
|
+
.div(stakerShares.add(signer0Shares).add(signer1Shares))
|
|
813
|
+
)
|
|
814
|
+
.add(
|
|
815
|
+
rewardsPerBlock.mul(signer1Shares).div(signer0Shares.add(signer1Shares))
|
|
816
|
+
)
|
|
817
|
+
.add(rewardsPerBlock)
|
|
818
|
+
.add(BN.from("1"));
|
|
819
|
+
expect(stakerOneGDAOBalanceAfterWithdraw).to.be.equal(
|
|
820
|
+
stakerOneGDAOBalanceAfterStake.add(stakerOneRewardsCalculated)
|
|
821
|
+
);
|
|
822
|
+
expect(stakerTwoGDAOBalanceAfterWithdraw).to.be.equal(
|
|
823
|
+
stakerTwoGDAOBalanceAfterStake.add(stakerTwoRewardsCalculated)
|
|
824
|
+
);
|
|
825
|
+
expect(stakerThreeGDAOBalanceAfterWithdraw).to.be.equal(
|
|
826
|
+
stakerThreeGDAOBalanceAfterStake.add(stakerThreeRewardsCalculated)
|
|
827
|
+
);
|
|
828
|
+
expect(stakerFourGDAOBalanceAfterWithdraw).to.be.equal(
|
|
829
|
+
stakerFourGDAOBalanceAfterStake.add(stakerFourRewardsCalculated)
|
|
830
|
+
);
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
it("it should get staking reward even when stake amount is low", async () => {
|
|
834
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
835
|
+
|
|
836
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
837
|
+
const stakingAmount = BN.from("10000");
|
|
838
|
+
await goodDollar.mint(founder.address, stakingAmount);
|
|
839
|
+
await goodDollar.mint(staker.address, stakingAmount);
|
|
840
|
+
await goodDollar.approve(staking.address, stakingAmount);
|
|
841
|
+
await goodDollar.connect(staker).approve(staking.address, stakingAmount);
|
|
842
|
+
await staking.stake(stakingAmount);
|
|
843
|
+
const stakerOneGDAOBalanceAfterStake = await grep.balanceOfLocal(
|
|
844
|
+
founder.address
|
|
845
|
+
);
|
|
846
|
+
const stakerTwoStakeBlockNumber =
|
|
847
|
+
(await ethers.provider.getBlockNumber()) + 1;
|
|
848
|
+
await staking.connect(staker).stake(2);
|
|
849
|
+
const stakerTwoGDAOBalanceAfterStake = await grep.balanceOfLocal(
|
|
850
|
+
staker.address
|
|
851
|
+
);
|
|
852
|
+
await advanceBlocks(10);
|
|
853
|
+
|
|
854
|
+
const staker1Shares = await staking.sharesOf(founder.address);
|
|
855
|
+
const staker2Shares = await staking.sharesOf(staker.address);
|
|
856
|
+
await staking
|
|
857
|
+
.connect(staker)
|
|
858
|
+
.withdrawStake(await staking.sharesOf(staker.address));
|
|
859
|
+
const stakerTwoWithdrawBlockNumber = await ethers.provider.getBlockNumber();
|
|
860
|
+
|
|
861
|
+
await staking.withdrawStake(await staking.sharesOf(founder.address));
|
|
862
|
+
|
|
863
|
+
const stakerOneGDAOBalanceAfterWithdraw = await grep.balanceOfLocal(
|
|
864
|
+
founder.address
|
|
865
|
+
);
|
|
866
|
+
const stakerTwoGDAOBalanceAfterWithdraw = await grep.balanceOfLocal(
|
|
867
|
+
staker.address
|
|
868
|
+
);
|
|
869
|
+
const calculatedRewardsStakerOne = rewardsPerBlock
|
|
870
|
+
.add(
|
|
871
|
+
rewardsPerBlock
|
|
872
|
+
.mul(staker1Shares)
|
|
873
|
+
.mul(stakerTwoWithdrawBlockNumber - stakerTwoStakeBlockNumber)
|
|
874
|
+
.div(staker1Shares.add(staker2Shares))
|
|
875
|
+
)
|
|
876
|
+
.add(rewardsPerBlock);
|
|
877
|
+
|
|
878
|
+
const calculatedRewardsStakerTwo = rewardsPerBlock
|
|
879
|
+
.mul(staker2Shares)
|
|
880
|
+
.mul(stakerTwoWithdrawBlockNumber - stakerTwoStakeBlockNumber)
|
|
881
|
+
.div(staker1Shares.add(staker2Shares))
|
|
882
|
+
.add(BN.from("1"));
|
|
883
|
+
|
|
884
|
+
expect(stakerOneGDAOBalanceAfterWithdraw).to.be.equal(
|
|
885
|
+
stakerOneGDAOBalanceAfterStake.add(calculatedRewardsStakerOne)
|
|
886
|
+
);
|
|
887
|
+
expect(stakerTwoGDAOBalanceAfterWithdraw).to.be.equal(
|
|
888
|
+
stakerTwoGDAOBalanceAfterStake.add(calculatedRewardsStakerTwo).sub(1)
|
|
889
|
+
);
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
it("it should mint rewards properly when withdrawRewards", async () => {
|
|
893
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
894
|
+
await goodDollar.mint(founder.address, "200");
|
|
895
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
896
|
+
await goodDollar.approve(staking.address, "200");
|
|
897
|
+
|
|
898
|
+
const stakeBlockNumber = (await ethers.provider.getBlockNumber()) + 1;
|
|
899
|
+
await staking.stake("200");
|
|
900
|
+
const GDAOBalanceAfterStake = await grep.balanceOfLocal(founder.address);
|
|
901
|
+
await advanceBlocks(100);
|
|
902
|
+
await staking.withdrawRewards();
|
|
903
|
+
const withdrawRewardsBlockNumber = await ethers.provider.getBlockNumber();
|
|
904
|
+
const GDAOBalanceAfterWithdraw = await grep.balanceOfLocal(founder.address);
|
|
905
|
+
|
|
906
|
+
expect(GDAOBalanceAfterWithdraw).to.be.equal(
|
|
907
|
+
GDAOBalanceAfterStake.add(
|
|
908
|
+
rewardsPerBlock.mul(withdrawRewardsBlockNumber - stakeBlockNumber)
|
|
909
|
+
)
|
|
910
|
+
);
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
it("it should not overmint rewards when staker withdraw their rewards", async () => {
|
|
914
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
915
|
+
|
|
916
|
+
const overmintTesterFactory = await ethers.getContractFactory(
|
|
917
|
+
"OverMintTester"
|
|
918
|
+
);
|
|
919
|
+
const overMintTester = await overmintTesterFactory.deploy(
|
|
920
|
+
goodDollar.address,
|
|
921
|
+
staking.address,
|
|
922
|
+
grep.address
|
|
923
|
+
);
|
|
924
|
+
await goodDollar.mint(overMintTester.address, "100");
|
|
925
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
926
|
+
const stakeBlockNumber = (await ethers.provider.getBlockNumber()) + 1;
|
|
927
|
+
await overMintTester.stake();
|
|
928
|
+
const GDAOBalanceAfterStake = await grep.balanceOfLocal(
|
|
929
|
+
overMintTester.address
|
|
930
|
+
);
|
|
931
|
+
await advanceBlocks(100);
|
|
932
|
+
await overMintTester.overMintTest();
|
|
933
|
+
const withdrawRewardsBlockNumber = await ethers.provider.getBlockNumber();
|
|
934
|
+
const GDAOBalanceAfterWithdrawReward = await grep.balanceOfLocal(
|
|
935
|
+
overMintTester.address
|
|
936
|
+
);
|
|
937
|
+
await advanceBlocks(20);
|
|
938
|
+
await overMintTester.overMintTest();
|
|
939
|
+
const secondWithdrawRewardsBlockNumber =
|
|
940
|
+
await ethers.provider.getBlockNumber();
|
|
941
|
+
const GDAOBalanceAfterSecondWithdrawReward = await grep.balanceOfLocal(
|
|
942
|
+
overMintTester.address
|
|
943
|
+
);
|
|
944
|
+
|
|
945
|
+
expect(GDAOBalanceAfterWithdrawReward).to.be.gt(GDAOBalanceAfterStake);
|
|
946
|
+
expect(
|
|
947
|
+
GDAOBalanceAfterWithdrawReward.sub(GDAOBalanceAfterStake)
|
|
948
|
+
).to.be.equal(
|
|
949
|
+
rewardsPerBlock.mul(withdrawRewardsBlockNumber - stakeBlockNumber)
|
|
950
|
+
);
|
|
951
|
+
expect(GDAOBalanceAfterSecondWithdrawReward).to.be.gt(
|
|
952
|
+
GDAOBalanceAfterWithdrawReward
|
|
953
|
+
);
|
|
954
|
+
expect(
|
|
955
|
+
GDAOBalanceAfterSecondWithdrawReward.sub(GDAOBalanceAfterWithdrawReward)
|
|
956
|
+
).to.be.equal(
|
|
957
|
+
rewardsPerBlock.mul(
|
|
958
|
+
secondWithdrawRewardsBlockNumber - withdrawRewardsBlockNumber
|
|
959
|
+
)
|
|
960
|
+
);
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
it("it should accrue previous rewards based on previous monthly rate on monthly rewards rate change to 0", async () => {
|
|
964
|
+
const { staking } = await waffle.loadFixture(fixture_ready);
|
|
965
|
+
|
|
966
|
+
const ictrl = await ethers.getContractAt(
|
|
967
|
+
"Controller",
|
|
968
|
+
controller,
|
|
969
|
+
schemeMock
|
|
970
|
+
);
|
|
971
|
+
|
|
972
|
+
const rewardsPerBlock = (await staking.getRewardsPerBlock())[0];
|
|
973
|
+
await goodDollar.mint(founder.address, "100");
|
|
974
|
+
await goodDollar.approve(staking.address, "100");
|
|
975
|
+
const stakeBlockNumber = (await ethers.provider.getBlockNumber()) + 1;
|
|
976
|
+
await staking.stake("100");
|
|
977
|
+
await advanceBlocks(4);
|
|
978
|
+
|
|
979
|
+
let encodedCall = staking.interface.encodeFunctionData(
|
|
980
|
+
"setMonthlyGOODRewards",
|
|
981
|
+
["0"] // Give 0.0001 GDAO per block so 17.28 GDAO per month
|
|
982
|
+
);
|
|
983
|
+
await ictrl.genericCall(staking.address, encodedCall, avatar, 0);
|
|
984
|
+
|
|
985
|
+
const withdrawBlockNumber = await ethers.provider.getBlockNumber();
|
|
986
|
+
const multiplier = withdrawBlockNumber - stakeBlockNumber;
|
|
987
|
+
const calculatedReward = rewardsPerBlock.mul(multiplier);
|
|
988
|
+
const [pendingReward] = await staking["getUserPendingReward(address)"](
|
|
989
|
+
founder.address
|
|
990
|
+
);
|
|
991
|
+
expect(pendingReward).to.equal(calculatedReward);
|
|
992
|
+
await advanceBlocks(4);
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
function rdiv(x: BigNumber, y: BigNumber) {
|
|
996
|
+
return x.mul(BN.from("10").pow(27)).add(y.div(2)).div(y);
|
|
997
|
+
}
|
|
998
|
+
});
|