Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 43 additions & 8 deletions precompiles/distribution/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ var _ = Describe("Calling distribution precompile from EOA", func() {
initialBalance := queryRes.Balance

txArgs.GasPrice = gasPrice.BigInt()
txArgs.GasLimit = 300_000
callArgs.Args = []interface{}{
s.keyring.GetAddr(0),
s.network.GetValidators()[0].OperatorAddress,
Expand Down Expand Up @@ -611,6 +612,8 @@ var _ = Describe("Calling distribution precompile from EOA", func() {
Expect(err).To(BeNil(), "error while calling BaseFee")
gasPrice := bfQuery.BaseFee
txArgs.GasPrice = gasPrice.BigInt()
// Set gas limit to avoid out of gas error when claiming from all validators
txArgs.GasLimit = 500_000

claimRewardsCheck := passCheck.WithExpEvents(distribution.EventTypeClaimRewards)

Expand Down Expand Up @@ -714,8 +717,7 @@ var _ = Describe("Calling distribution precompile from EOA", func() {
Quo(math.LegacyNewDec(3)).
// add 5% commission
Quo(math.LegacyNewDecWithPrec(95, 2)).
// Ceil(). // round up to get the same value
TruncateInt()
Ceil().TruncateInt() // round up to get the same value

Expect(rewards[0].Amount.String()).To(Equal(expRewardAmt.BigInt().String()))
})
Expand Down Expand Up @@ -1158,6 +1160,7 @@ var _ = Describe("Calling distribution precompile from another contract", Ordere
Expect(err).To(BeNil())
initBalanceAmt := balRes.Balance.Amount

txArgs.GasLimit = 300_000
callArgs.Args = []interface{}{
s.keyring.GetAddr(0), s.network.GetValidators()[0].OperatorAddress,
}
Expand Down Expand Up @@ -1504,6 +1507,7 @@ var _ = Describe("Calling distribution precompile from another contract", Ordere
})

It("should withdraw rewards successfully without origin check", func() {
txArgs.GasLimit = 300_000
callArgs.Args = []interface{}{s.network.GetValidators()[0].OperatorAddress}

logCheckArgs := passCheck.WithExpEvents(distribution.EventTypeWithdrawDelegatorRewards)
Expand Down Expand Up @@ -2113,6 +2117,7 @@ var _ = Describe("Calling distribution precompile from another contract", Ordere
})

It("should claim rewards successfully", func() {
txArgs.GasLimit = 500_000
callArgs.Args = []interface{}{s.keyring.GetAddr(0), uint32(2)}

logCheckArgs := passCheck.
Expand Down Expand Up @@ -2273,6 +2278,7 @@ var _ = Describe("Calling distribution precompile from another contract", Ordere

callArgs.Args = []interface{}{contractAddr, uint32(2)}
txArgs.GasPrice = gasPrice.BigInt()
txArgs.GasLimit = 500_000

logCheckArgs := passCheck.WithExpEvents(distribution.EventTypeClaimRewards)

Expand Down Expand Up @@ -2527,16 +2533,21 @@ var _ = Describe("Calling distribution precompile from another contract", Ordere
})

It("should not get commission - validator without commission", func() {
// fund validator account to claim commission (if any)
// Fund validator account to pay for transaction fees
err = testutils.FundAccountWithBaseDenom(s.factory, s.network, s.keyring.GetKey(0), s.validatorsKeys[0].AccAddr, math.NewInt(1e18))
Expect(err).To(BeNil())
Expect(s.network.NextBlock()).To(BeNil())

// withdraw validator commission
// Set validator commission to 0%
err = s.setValidatorCommission(s.network.GetValidators()[0].OperatorAddress, math.ZeroInt())
Expect(err).To(BeNil(), "error while setting validator commission to 0%")

// withdraw any existing validator commission before checking
err = s.factory.WithdrawValidatorCommission(s.validatorsKeys[0].Priv)
Expect(err).To(BeNil())
Expect(s.network.NextBlock()).To(BeNil())

// Check initial commission (should be zero after withdrawal)
_, ethRes, err := s.factory.CallContractAndCheckLogs(
s.keyring.GetPrivKey(0),
txArgs,
Expand All @@ -2545,11 +2556,35 @@ var _ = Describe("Calling distribution precompile from another contract", Ordere
)
Expect(err).To(BeNil(), "error while calling the smart contract: %v", err)

var commission []cmn.DecCoin
err = s.precompile.UnpackIntoInterface(&commission, distribution.ValidatorCommissionMethod, ethRes.Ret)
var initialCommission []cmn.DecCoin
err = s.precompile.UnpackIntoInterface(&initialCommission, distribution.ValidatorCommissionMethod, ethRes.Ret)
Expect(err).To(BeNil())
Expect(len(commission)).To(Equal(1))
Expect(commission[0].Amount.Int64()).To(Equal(int64(1486702434866))) // TODO Find out, why commission gained here
Expect(len(initialCommission)).To(Equal(1))
initialCommissionAmt := initialCommission[0].Amount.Int64()

// Wait a few blocks to ensure commission doesn't accumulate with 0% commission rate
Expect(s.network.NextBlock()).To(BeNil())
Expect(s.network.NextBlock()).To(BeNil())
Expect(s.network.NextBlock()).To(BeNil())

// Check that commission hasn't changed (remains zero)
_, ethRes, err = s.factory.CallContractAndCheckLogs(
s.keyring.GetPrivKey(0),
txArgs,
callArgs,
passCheck,
)
Expect(err).To(BeNil(), "error while calling the smart contract: %v", err)

var finalCommission []cmn.DecCoin
err = s.precompile.UnpackIntoInterface(&finalCommission, distribution.ValidatorCommissionMethod, ethRes.Ret)
Expect(err).To(BeNil())
Expect(len(finalCommission)).To(Equal(1))
finalCommissionAmt := finalCommission[0].Amount.Int64()

// Commission should remain unchanged (zero) with 0% commission rate
Expect(initialCommissionAmt).To(Equal(int64(0)), "initial commission should be zero after withdrawal with 0% commission rate")
Expect(finalCommissionAmt).To(Equal(initialCommissionAmt), "commission should not accumulate with 0% commission rate")
})

It("should get commission - validator with commission", func() {
Expand Down
7 changes: 7 additions & 0 deletions precompiles/distribution/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/haqq-network/haqq/testutil/integration/haqq/grpc"
testkeyring "github.com/haqq-network/haqq/testutil/integration/haqq/keyring"
"github.com/haqq-network/haqq/testutil/integration/haqq/network"
coinomicstypes "github.com/haqq-network/haqq/x/coinomics/types"
)

type PrecompileTestSuite struct {
Expand All @@ -39,6 +40,12 @@ func (s *PrecompileTestSuite) SetupTest() {
s.validatorsKeys = generateKeys(3)
customGen := network.CustomGenesisState{}

// Increase reward coefficient for faster reward accrual in tests
// Default is 7.8 (78/10), we increase it to 780 (7800/10) for 100x faster rewards
coinomicsGenesis := coinomicstypes.DefaultGenesisState()
coinomicsGenesis.Params.RewardCoefficient = math.LegacyNewDecWithPrec(78000, 1) // 780 instead of 7.8
customGen[coinomicstypes.ModuleName] = coinomicsGenesis

operatorsAddr := make([]sdk.AccAddress, 3)
for i, k := range s.validatorsKeys {
operatorsAddr[i] = k.AccAddr
Expand Down
53 changes: 53 additions & 0 deletions precompiles/distribution/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/haqq-network/haqq/precompiles/staking"
"github.com/haqq-network/haqq/testutil/integration/haqq/keyring"
coinomicstypes "github.com/haqq-network/haqq/x/coinomics/types"
stakingkeeper "github.com/haqq-network/haqq/x/staking/keeper"
)

type stakingRewards struct {
Expand Down Expand Up @@ -94,3 +95,55 @@ func generateKeys(count int) []keyring.Key {
}
return accs
}

// setValidatorCommission sets the minimum commission rate to the given value (if needed)
// and updates the validator's commission rate using Cosmos SDK message server.
// commissionRate should be a value between 0 and 1e18 (0% to 100% with 18 decimals precision).
func (s *PrecompileTestSuite) setValidatorCommission(validatorOperatorAddr string, commissionRate math.Int) error {
ctx := s.network.GetContext()

// Set minimum commission rate to 0% if setting commission to 0% to allow it
if commissionRate.IsZero() {
stakingParams, err := s.network.App.StakingKeeper.GetParams(ctx)
if err != nil {
return err
}
stakingParams.MinCommissionRate = math.LegacyZeroDec()
if err := s.network.App.StakingKeeper.SetParams(ctx, stakingParams); err != nil {
return err
}
if err := s.network.NextBlock(); err != nil {
return err
}
ctx = s.network.GetContext()
}

// Convert commission rate from math.Int to math.LegacyDec
// commissionRate is in range 0-1e18 (representing 0% to 100% with 18 decimals precision)
// Divide by 1e18 to get decimal value (0.0 to 1.0)
oneE18 := math.NewInt(1e18)
commissionRateDec := math.LegacyNewDecFromInt(commissionRate).QuoInt(oneE18)

// Create MsgEditValidator and execute via Cosmos SDK message server
// Use "[do-not-modify]" for all description fields to indicate we don't want to change them
msg := stakingtypes.NewMsgEditValidator(
validatorOperatorAddr,
stakingtypes.Description{
Moniker: "[do-not-modify]",
Identity: "[do-not-modify]",
Website: "[do-not-modify]",
SecurityContact: "[do-not-modify]",
Details: "[do-not-modify]",
},
&commissionRateDec,
nil, // do not modify min self delegation
)

msgServer := stakingkeeper.NewMsgServerImpl(&s.network.App.StakingKeeper)
_, err := msgServer.EditValidator(ctx, msg)
if err != nil {
return err
}

return s.network.NextBlock()
}
4 changes: 2 additions & 2 deletions testutil/integration/haqq/utils/staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
func WaitToAccrueRewards(n network.Network, gh grpc.Handler, delegatorAddr string, expRewards sdk.DecCoins) (sdk.DecCoins, error) {
var (
err error
lapse = time.Hour * 24 * 7 // one week
lapse = time.Hour * 24 * 7
rewards = sdk.DecCoins{}
)

Expand Down Expand Up @@ -51,7 +51,7 @@ func checkRewardsAfter(n network.Network, gh grpc.Handler, delegatorAddr string,
func WaitToAccrueCommission(n network.Network, gh grpc.Handler, validatorAddr string, expCommission sdk.DecCoins) (sdk.DecCoins, error) {
var (
err error
lapse = time.Hour * 24 * 7 // one week
lapse = time.Hour * 24 * 7
commission = sdk.DecCoins{}
)

Expand Down
Loading