Skip to content

Commit

Permalink
e2e: finish disitribute tests
Browse files Browse the repository at this point in the history
  • Loading branch information
fbac committed Oct 24, 2024
1 parent 5ea0fac commit 7da0e3a
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 50 deletions.
2 changes: 2 additions & 0 deletions cmd/zetae2e/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ func localE2ETest(cmd *cobra.Command, _ []string) {
e2etests.TestPrecompilesBankName,
e2etests.TestPrecompilesBankFailName,
e2etests.TestPrecompilesBankThroughContractName,
e2etests.TestPrecompilesDistributeName,
e2etests.TestPrecompilesDistributeThroughContractName,
}
}

Expand Down
111 changes: 62 additions & 49 deletions e2e/e2etests/test_precompiles_distribute.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
package e2etests

import (
"fmt"
"math/big"

"github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -43,7 +40,7 @@ func TestPrecompilesDistribute(r *runner.E2ERunner, args []string) {
r.ZEVMAuth.GasLimit = 10_000_000

// Set the test to reset the state after it finishes.
defer resetTest(r, lockerAddress, previousGasLimit)
defer resetTest(r, lockerAddress, previousGasLimit, fiveHundred)

// Get ERC20ZRC20.
txHash := r.DepositERC20WithAmountAndMessage(spenderAddress, oneThousand, []byte{})
Expand All @@ -52,9 +49,10 @@ func TestPrecompilesDistribute(r *runner.E2ERunner, args []string) {
dstrContract, err := staking.NewIStaking(distributeContractAddress, r.ZEVMClient)
require.NoError(r, err, "failed to create distribute contract caller")

validators, err := dstrContract.GetAllValidators(&bind.CallOpts{})
require.NoError(r, err)
fmt.Println(validators)
// DO NOT REMOVE - will be used in a subsequent PR when the ability to withdraw delegator rewards is introduced.
// Get validators through staking contract.
// validators, err := dstrContract.GetAllValidators(&bind.CallOpts{})
// require.NoError(r, err)

// Check initial balances.
balanceShouldBe(r, 1000, checkZRC20Balance(r, spenderAddress))
Expand Down Expand Up @@ -118,48 +116,53 @@ func TestPrecompilesDistribute(r *runner.E2ERunner, args []string) {
// After one block the rewards should have been distributed and fee collector should have 0 ZRC20 balance.
r.WaitForBlocks(1)
balanceShouldBe(r, 0, checkCosmosBalance(r, feeCollectorAddress, zrc20Denom))
res, err := r.DistributionClient.ValidatorDistributionInfo(
r.Ctx,
&distributiontypes.QueryValidatorDistributionInfoRequest{
ValidatorAddress: validators[0].OperatorAddress,
},
)
require.NoError(r, err)
fmt.Printf("Validator 0 distribution info: %+v\n", res)

res2, err := r.DistributionClient.ValidatorOutstandingRewards(r.Ctx, &distributiontypes.QueryValidatorOutstandingRewardsRequest{
ValidatorAddress: validators[0].OperatorAddress,
})
require.NoError(r, err)
fmt.Printf("Validator 0 outstanding rewards: %+v\n", res2)

res3, err := r.DistributionClient.ValidatorCommission(r.Ctx, &distributiontypes.QueryValidatorCommissionRequest{
ValidatorAddress: validators[0].OperatorAddress,
})
require.NoError(r, err)
fmt.Printf("Validator 0 commission: %+v\n", res3)

// Validator 1
res, err = r.DistributionClient.ValidatorDistributionInfo(
r.Ctx,
&distributiontypes.QueryValidatorDistributionInfoRequest{
ValidatorAddress: validators[1].OperatorAddress,
},
)
require.NoError(r, err)
fmt.Printf("Validator 1 distribution info: %+v\n", res)

res2, err = r.DistributionClient.ValidatorOutstandingRewards(r.Ctx, &distributiontypes.QueryValidatorOutstandingRewardsRequest{
ValidatorAddress: validators[1].OperatorAddress,
})
require.NoError(r, err)
fmt.Printf("Validator 1 outstanding rewards: %+v\n", res2)

res3, err = r.DistributionClient.ValidatorCommission(r.Ctx, &distributiontypes.QueryValidatorCommissionRequest{
ValidatorAddress: validators[1].OperatorAddress,
})
require.NoError(r, err)
fmt.Printf("Validator 1 commission: %+v\n", res3)
// DO NOT REMOVE THE FOLLOWING CODE
// This section is commented until a following PR introduces the ability to withdraw delegator rewards.
// This validator checks will be used then to complete the whole e2e.

// res, err := r.DistributionClient.ValidatorDistributionInfo(
// r.Ctx,
// &distributiontypes.QueryValidatorDistributionInfoRequest{
// ValidatorAddress: validators[0].OperatorAddress,
// },
// )
// require.NoError(r, err)
// fmt.Printf("Validator 0 distribution info: %+v\n", res)

// res2, err := r.DistributionClient.ValidatorOutstandingRewards(r.Ctx, &distributiontypes.QueryValidatorOutstandingRewardsRequest{
// ValidatorAddress: validators[0].OperatorAddress,
// })
// require.NoError(r, err)
// fmt.Printf("Validator 0 outstanding rewards: %+v\n", res2)

// res3, err := r.DistributionClient.ValidatorCommission(r.Ctx, &distributiontypes.QueryValidatorCommissionRequest{
// ValidatorAddress: validators[0].OperatorAddress,
// })
// require.NoError(r, err)
// fmt.Printf("Validator 0 commission: %+v\n", res3)

// // Validator 1
// res, err = r.DistributionClient.ValidatorDistributionInfo(
// r.Ctx,
// &distributiontypes.QueryValidatorDistributionInfoRequest{
// ValidatorAddress: validators[1].OperatorAddress,
// },
// )
// require.NoError(r, err)
// fmt.Printf("Validator 1 distribution info: %+v\n", res)

// res2, err = r.DistributionClient.ValidatorOutstandingRewards(r.Ctx, &distributiontypes.QueryValidatorOutstandingRewardsRequest{
// ValidatorAddress: validators[1].OperatorAddress,
// })
// require.NoError(r, err)
// fmt.Printf("Validator 1 outstanding rewards: %+v\n", res2)

// res3, err = r.DistributionClient.ValidatorCommission(r.Ctx, &distributiontypes.QueryValidatorCommissionRequest{
// ValidatorAddress: validators[1].OperatorAddress,
// })
// require.NoError(r, err)
// fmt.Printf("Validator 1 commission: %+v\n", res3)
}

func checkCosmosBalance(r *runner.E2ERunner, address types.AccAddress, denom string) *big.Int {
Expand All @@ -172,12 +175,22 @@ func checkCosmosBalance(r *runner.E2ERunner, address types.AccAddress, denom str
return bal.Balance.Amount.BigInt()
}

func resetTest(r *runner.E2ERunner, lockerAddress common.Address, previousGasLimit uint64) {
func resetTest(r *runner.E2ERunner, lockerAddress common.Address, previousGasLimit uint64, amount *big.Int) {
r.ZEVMAuth.GasLimit = previousGasLimit

// Reset the allowance to 0; this is needed when running upgrade tests where this test runs twice.
tx, err := r.ERC20ZRC20.Approve(r.ZEVMAuth, lockerAddress, big.NewInt(0))
require.NoError(r, err)
receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout)
utils.RequireTxSuccessful(r, receipt, "Resetting allowance failed")

// Reset balance to 0 for spender; this is needed when running upgrade tests where this test runs twice.
tx, err = r.ERC20ZRC20.Transfer(
r.ZEVMAuth,
common.HexToAddress("0x000000000000000000000000000000000000dEaD"),
amount,
)
require.NoError(r, err)
receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout)
utils.RequireTxSuccessful(r, receipt, "Resetting balance failed")
}
111 changes: 111 additions & 0 deletions e2e/e2etests/test_precompiles_distribute_through_contract.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,122 @@
package e2etests

import (
"math/big"

authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"

"github.com/zeta-chain/node/e2e/contracts/testdistribute"
"github.com/zeta-chain/node/e2e/runner"
"github.com/zeta-chain/node/e2e/utils"
"github.com/zeta-chain/node/precompiles/bank"
"github.com/zeta-chain/node/precompiles/staking"
ptypes "github.com/zeta-chain/node/precompiles/types"
)

func TestPrecompilesDistributeThroughContract(r *runner.E2ERunner, args []string) {
require.Len(r, args, 0, "No arguments expected")

var (
spenderAddress = r.EVMAddress()
distributeContractAddress = staking.ContractAddress
feeCollectorAddress = authtypes.NewModuleAddress("fee_collector")
lockerAddress = bank.ContractAddress

zrc20Address = r.ERC20ZRC20Addr
zrc20Denom = ptypes.ZRC20ToCosmosDenom(zrc20Address)

oneThousand = big.NewInt(1e3)
oneThousandOne = big.NewInt(1001)
fiveHundred = big.NewInt(500)
fiveHundredOne = big.NewInt(501)

previousGasLimit = r.ZEVMAuth.GasLimit
)

// Get ERC20ZRC20.
txHash := r.DepositERC20WithAmountAndMessage(spenderAddress, oneThousand, []byte{})
utils.WaitCctxMinedByInboundHash(r.Ctx, txHash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout)

dstrContract, err := staking.NewIStaking(distributeContractAddress, r.ZEVMClient)
require.NoError(r, err, "failed to create distribute contract caller")

_, tx, testDstrContract, err := testdistribute.DeployTestDistribute(r.ZEVMAuth, r.ZEVMClient)
require.NoError(r, err)
receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout)
utils.RequireTxSuccessful(r, receipt, "deployment of disitributor caller contract failed")

// Set new gas limit to avoid out of gas errors.
r.ZEVMAuth.GasLimit = 10_000_000

// Set the test to reset the state after it finishes.
defer resetTest(r, lockerAddress, previousGasLimit, fiveHundred)

// Check initial balances.
balanceShouldBe(r, 1000, checkZRC20Balance(r, spenderAddress))
balanceShouldBe(r, 500, checkZRC20Balance(r, lockerAddress)) // Carries 500 from distribute e2e.
balanceShouldBe(r, 0, checkCosmosBalance(r, feeCollectorAddress, zrc20Denom))

receipt = distributeThroughContract(r, testDstrContract, zrc20Address, oneThousand)
utils.RequiredTxFailed(r, receipt, "distribute should fail when there's no allowance")

// Balances shouldn't change after a failed attempt.
balanceShouldBe(r, 1000, checkZRC20Balance(r, spenderAddress))
balanceShouldBe(r, 500, checkZRC20Balance(r, lockerAddress)) // Carries 500 from distribute e2e.
balanceShouldBe(r, 0, checkCosmosBalance(r, feeCollectorAddress, zrc20Denom))

// Allow 500.
approveAllowance(r, distributeContractAddress, fiveHundred)

receipt = distributeThroughContract(r, testDstrContract, zrc20Address, fiveHundredOne)
utils.RequiredTxFailed(r, receipt, "distribute should fail trying to distribute more than allowed")

// Balances shouldn't change after a failed attempt.
balanceShouldBe(r, 1000, checkZRC20Balance(r, spenderAddress))
balanceShouldBe(r, 500, checkZRC20Balance(r, lockerAddress)) // Carries 500 from distribute e2e.
balanceShouldBe(r, 0, checkCosmosBalance(r, feeCollectorAddress, zrc20Denom))

// Raise the allowance to 1000.
approveAllowance(r, distributeContractAddress, oneThousand)

// Shouldn't be able to distribute more than owned balance.
receipt = distributeThroughContract(r, testDstrContract, zrc20Address, oneThousandOne)
utils.RequiredTxFailed(r, receipt, "distribute should fail trying to distribute more than owned balance")

// Balances shouldn't change after a failed attempt.
balanceShouldBe(r, 1000, checkZRC20Balance(r, spenderAddress))
balanceShouldBe(r, 500, checkZRC20Balance(r, lockerAddress)) // Carries 500 from distribute e2e.
balanceShouldBe(r, 0, checkCosmosBalance(r, feeCollectorAddress, zrc20Denom))

// Should be able to distribute 500, which is within balance and allowance.
receipt = distributeThroughContract(r, testDstrContract, zrc20Address, fiveHundred)
utils.RequireTxSuccessful(r, receipt, "distribute should succeed when distributing within balance and allowance")

balanceShouldBe(r, 500, checkZRC20Balance(r, spenderAddress))
balanceShouldBe(r, 1000, checkZRC20Balance(r, lockerAddress)) // Carries 500 from distribute e2e.
balanceShouldBe(r, 500, checkCosmosBalance(r, feeCollectorAddress, zrc20Denom))

eventDitributed, err := dstrContract.ParseDistributed(*receipt.Logs[0])
require.NoError(r, err)
require.Equal(r, zrc20Address, eventDitributed.Zrc20Token)
require.Equal(r, spenderAddress, eventDitributed.Zrc20Distributor)
require.Equal(r, fiveHundred.Uint64(), eventDitributed.Amount.Uint64())

// After one block the rewards should have been distributed and fee collector should have 0 ZRC20 balance.
r.WaitForBlocks(1)
balanceShouldBe(r, 0, checkCosmosBalance(r, feeCollectorAddress, zrc20Denom))
}

func distributeThroughContract(
r *runner.E2ERunner,
dstr *testdistribute.TestDistribute,
zrc20Address common.Address,
amount *big.Int,
) *types.Receipt {
tx, err := dstr.DistributeThroughContract(r.ZEVMAuth, zrc20Address, amount)
require.NoError(r, err)
receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout)
return receipt
}
2 changes: 1 addition & 1 deletion e2e/utils/require.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func RequireTxSuccessful(t require.TestingT, receipt *ethtypes.Receipt, msgAndAr
// RequiredTxFailed checks if the receipt status is failed.
// Currently, it accepts eth receipt, but we can make this more generic by using type assertion.
func RequiredTxFailed(t require.TestingT, receipt *ethtypes.Receipt, msgAndArgs ...any) {
msg := "receipt status is not successful: %s"
msg := "receipt status is not failed: %s"
require.Equal(
t,
ethtypes.ReceiptStatusFailed,
Expand Down

0 comments on commit 7da0e3a

Please sign in to comment.