diff --git a/x/staking/precompile/allowance_shares.go b/x/staking/precompile/allowance_shares.go index 5674bce2..d60f8eed 100644 --- a/x/staking/precompile/allowance_shares.go +++ b/x/staking/precompile/allowance_shares.go @@ -12,13 +12,13 @@ import ( type AllowanceSharesMethod struct { *Keeper - abi.Method + AllowanceSharesABI } func NewAllowanceSharesMethod(keeper *Keeper) *AllowanceSharesMethod { return &AllowanceSharesMethod{ - Keeper: keeper, - Method: stakingABI.Methods["allowanceShares"], + Keeper: keeper, + AllowanceSharesABI: NewAllowanceSharesABI(), } } @@ -46,25 +46,35 @@ func (m *AllowanceSharesMethod) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, return m.PackOutput(allowance) } -func (m *AllowanceSharesMethod) PackInput(args fxstakingtypes.AllowanceSharesArgs) ([]byte, error) { +type AllowanceSharesABI struct { + abi.Method +} + +func NewAllowanceSharesABI() AllowanceSharesABI { + return AllowanceSharesABI{ + Method: stakingABI.Methods["allowanceShares"], + } +} + +func (m AllowanceSharesABI) PackInput(args fxstakingtypes.AllowanceSharesArgs) ([]byte, error) { arguments, err := m.Method.Inputs.Pack(args.Validator, args.Owner, args.Spender) if err != nil { return nil, err } - return append(m.GetMethodId(), arguments...), nil + return append(m.Method.ID, arguments...), nil } -func (m *AllowanceSharesMethod) UnpackInput(data []byte) (*fxstakingtypes.AllowanceSharesArgs, error) { +func (m AllowanceSharesABI) UnpackInput(data []byte) (*fxstakingtypes.AllowanceSharesArgs, error) { args := new(fxstakingtypes.AllowanceSharesArgs) err := types.ParseMethodArgs(m.Method, args, data[4:]) return args, err } -func (m *AllowanceSharesMethod) PackOutput(amount *big.Int) ([]byte, error) { +func (m AllowanceSharesABI) PackOutput(amount *big.Int) ([]byte, error) { return m.Method.Outputs.Pack(amount) } -func (m *AllowanceSharesMethod) UnpackOutput(data []byte) (*big.Int, error) { +func (m AllowanceSharesABI) UnpackOutput(data []byte) (*big.Int, error) { amount, err := m.Method.Outputs.Unpack(data) if err != nil { return nil, err diff --git a/x/staking/precompile/approve_shares.go b/x/staking/precompile/approve_shares.go index 75dfe680..ca55c65b 100644 --- a/x/staking/precompile/approve_shares.go +++ b/x/staking/precompile/approve_shares.go @@ -17,15 +17,13 @@ import ( type ApproveSharesMethod struct { *Keeper - abi.Method - abi.Event + ApproveSharesABI } func NewApproveSharesMethod(keeper *Keeper) *ApproveSharesMethod { return &ApproveSharesMethod{ - Keeper: keeper, - Method: stakingABI.Methods["approveShares"], - Event: stakingABI.Events["ApproveShares"], + Keeper: keeper, + ApproveSharesABI: NewApproveSharesABI(), } } @@ -66,7 +64,19 @@ func (m *ApproveSharesMethod) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, e return m.PackOutput(true) } -func (m *ApproveSharesMethod) NewApproveSharesEvent(owner, spender common.Address, validator string, shares *big.Int) (data []byte, topic []common.Hash, err error) { +type ApproveSharesABI struct { + abi.Method + abi.Event +} + +func NewApproveSharesABI() ApproveSharesABI { + return ApproveSharesABI{ + Method: stakingABI.Methods["approveShares"], + Event: stakingABI.Events["ApproveShares"], + } +} + +func (m ApproveSharesABI) NewApproveSharesEvent(owner, spender common.Address, validator string, shares *big.Int) (data []byte, topic []common.Hash, err error) { data, topic, err = types.PackTopicData(m.Event, []common.Hash{owner.Hash(), spender.Hash()}, validator, shares) if err != nil { return nil, nil, err @@ -74,25 +84,25 @@ func (m *ApproveSharesMethod) NewApproveSharesEvent(owner, spender common.Addres return data, topic, nil } -func (m *ApproveSharesMethod) PackInput(args fxstakingtypes.ApproveSharesArgs) ([]byte, error) { +func (m ApproveSharesABI) PackInput(args fxstakingtypes.ApproveSharesArgs) ([]byte, error) { arguments, err := m.Method.Inputs.Pack(args.Validator, args.Spender, args.Shares) if err != nil { return nil, err } - return append(m.GetMethodId(), arguments...), nil + return append(m.Method.ID, arguments...), nil } -func (m *ApproveSharesMethod) UnpackInput(data []byte) (*fxstakingtypes.ApproveSharesArgs, error) { +func (m ApproveSharesABI) UnpackInput(data []byte) (*fxstakingtypes.ApproveSharesArgs, error) { args := new(fxstakingtypes.ApproveSharesArgs) err := types.ParseMethodArgs(m.Method, args, data[4:]) return args, err } -func (m *ApproveSharesMethod) PackOutput(result bool) ([]byte, error) { +func (m ApproveSharesABI) PackOutput(result bool) ([]byte, error) { return m.Method.Outputs.Pack(result) } -func (m *ApproveSharesMethod) UnpackOutput(data []byte) (bool, error) { +func (m ApproveSharesABI) UnpackOutput(data []byte) (bool, error) { amount, err := m.Method.Outputs.Unpack(data) if err != nil { return false, err @@ -100,7 +110,7 @@ func (m *ApproveSharesMethod) UnpackOutput(data []byte) (bool, error) { return amount[0].(bool), nil } -func (m *ApproveSharesMethod) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingApproveShares, error) { +func (m ApproveSharesABI) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingApproveShares, error) { if log == nil { return nil, errors.New("empty log") } diff --git a/x/staking/precompile/contract_test.go b/x/staking/precompile/contract_test.go index 36269b5f..231a765b 100644 --- a/x/staking/precompile/contract_test.go +++ b/x/staking/precompile/contract_test.go @@ -42,10 +42,10 @@ type PrecompileTestSuite struct { delegateV2Method *precompile.DelegateV2Method delegationMethod *precompile.DelegationMethod delegationRewardsMethod *precompile.DelegationRewardsMethod - redelegateMethodV2 *precompile.RedelegateMethodV2 + redelegateV2Method *precompile.RedelegateV2Method // slashingInfoMethod *precompile.SlashingInfoMethod - transferSharesMethod *precompile.TransferShares - transferFromSharesMethod *precompile.TransferFromShares + transferSharesMethod *precompile.TransferSharesMethod + transferFromSharesMethod *precompile.TransferFromSharesMethod undelegateV2Method *precompile.UndelegateV2Method validatorListMethod *precompile.ValidatorListMethod withdrawMethod *precompile.WithdrawMethod @@ -85,7 +85,7 @@ func (suite *PrecompileTestSuite) SetupTest() { suite.delegateV2Method = precompile.NewDelegateV2Method(nil) suite.delegationMethod = precompile.NewDelegationMethod(nil) suite.delegationRewardsMethod = precompile.NewDelegationRewardsMethod(nil) - suite.redelegateMethodV2 = precompile.NewRedelegateV2Method(nil) + suite.redelegateV2Method = precompile.NewRedelegateV2Method(nil) // suite.slashingInfoMethod = precompile.NewSlashingInfoMethod(nil) suite.transferSharesMethod = precompile.NewTransferSharesMethod(nil) suite.transferFromSharesMethod = precompile.NewTransferFromSharesMethod(nil) diff --git a/x/staking/precompile/delegate.go b/x/staking/precompile/delegate.go index 66edf70f..825a9391 100644 --- a/x/staking/precompile/delegate.go +++ b/x/staking/precompile/delegate.go @@ -18,15 +18,13 @@ import ( type DelegateV2Method struct { *Keeper - abi.Method - abi.Event + DelegateV2ABI } func NewDelegateV2Method(keeper *Keeper) *DelegateV2Method { return &DelegateV2Method{ - Keeper: keeper, - Method: stakingABI.Methods["delegateV2"], - Event: stakingABI.Events["DelegateV2"], + Keeper: keeper, + DelegateV2ABI: NewDelegateV2ABI(), } } @@ -71,7 +69,19 @@ func (m *DelegateV2Method) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, erro return m.PackOutput(true) } -func (m *DelegateV2Method) NewDelegateEvent(sender common.Address, validator string, amount *big.Int) (data []byte, topic []common.Hash, err error) { +type DelegateV2ABI struct { + abi.Method + abi.Event +} + +func NewDelegateV2ABI() DelegateV2ABI { + return DelegateV2ABI{ + Method: stakingABI.Methods["delegateV2"], + Event: stakingABI.Events["DelegateV2"], + } +} + +func (m DelegateV2ABI) NewDelegateEvent(sender common.Address, validator string, amount *big.Int) (data []byte, topic []common.Hash, err error) { data, topic, err = types.PackTopicData(m.Event, []common.Hash{sender.Hash()}, validator, amount) if err != nil { return nil, nil, err @@ -79,25 +89,25 @@ func (m *DelegateV2Method) NewDelegateEvent(sender common.Address, validator str return data, topic, nil } -func (m *DelegateV2Method) PackInput(args fxstakingtypes.DelegateV2Args) ([]byte, error) { +func (m DelegateV2ABI) PackInput(args fxstakingtypes.DelegateV2Args) ([]byte, error) { arguments, err := m.Method.Inputs.Pack(args.Validator, args.Amount) if err != nil { return nil, err } - return append(m.GetMethodId(), arguments...), nil + return append(m.Method.ID, arguments...), nil } -func (m *DelegateV2Method) UnpackInput(data []byte) (*fxstakingtypes.DelegateV2Args, error) { +func (m DelegateV2ABI) UnpackInput(data []byte) (*fxstakingtypes.DelegateV2Args, error) { args := new(fxstakingtypes.DelegateV2Args) err := types.ParseMethodArgs(m.Method, args, data[4:]) return args, err } -func (m *DelegateV2Method) PackOutput(result bool) ([]byte, error) { +func (m DelegateV2ABI) PackOutput(result bool) ([]byte, error) { return m.Method.Outputs.Pack(result) } -func (m *DelegateV2Method) UnpackOutput(data []byte) (bool, error) { +func (m DelegateV2ABI) UnpackOutput(data []byte) (bool, error) { amount, err := m.Method.Outputs.Unpack(data) if err != nil { return false, err @@ -105,7 +115,7 @@ func (m *DelegateV2Method) UnpackOutput(data []byte) (bool, error) { return amount[0].(bool), nil } -func (m *DelegateV2Method) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingDelegateV2, error) { +func (m DelegateV2ABI) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingDelegateV2, error) { if log == nil { return nil, errors.New("empty log") } diff --git a/x/staking/precompile/delegation.go b/x/staking/precompile/delegation.go index 82f00293..f7d680e2 100644 --- a/x/staking/precompile/delegation.go +++ b/x/staking/precompile/delegation.go @@ -14,13 +14,13 @@ import ( type DelegationMethod struct { *Keeper - abi.Method + DelegationABI } func NewDelegationMethod(keeper *Keeper) *DelegationMethod { return &DelegationMethod{ - Keeper: keeper, - Method: stakingABI.Methods["delegation"], + Keeper: keeper, + DelegationABI: NewDelegationABI(), } } @@ -63,25 +63,35 @@ func (m *DelegationMethod) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, erro return m.PackOutput(delegation.GetShares().TruncateInt().BigInt(), delegationAmt.TruncateInt().BigInt()) } -func (m *DelegationMethod) PackInput(args fxstakingtypes.DelegationArgs) ([]byte, error) { +type DelegationABI struct { + abi.Method +} + +func NewDelegationABI() DelegationABI { + return DelegationABI{ + Method: stakingABI.Methods["delegation"], + } +} + +func (m DelegationABI) PackInput(args fxstakingtypes.DelegationArgs) ([]byte, error) { arguments, err := m.Method.Inputs.Pack(args.Validator, args.Delegator) if err != nil { return nil, err } - return append(m.GetMethodId(), arguments...), nil + return append(m.Method.ID, arguments...), nil } -func (m *DelegationMethod) UnpackInput(data []byte) (*fxstakingtypes.DelegationArgs, error) { +func (m DelegationABI) UnpackInput(data []byte) (*fxstakingtypes.DelegationArgs, error) { args := new(fxstakingtypes.DelegationArgs) err := types.ParseMethodArgs(m.Method, args, data[4:]) return args, err } -func (m *DelegationMethod) PackOutput(shares, amount *big.Int) ([]byte, error) { +func (m DelegationABI) PackOutput(shares, amount *big.Int) ([]byte, error) { return m.Method.Outputs.Pack(shares, amount) } -func (m *DelegationMethod) UnpackOutput(data []byte) (*big.Int, *big.Int, error) { +func (m DelegationABI) UnpackOutput(data []byte) (*big.Int, *big.Int, error) { unpack, err := m.Method.Outputs.Unpack(data) if err != nil { return nil, nil, err diff --git a/x/staking/precompile/delegation_rewards.go b/x/staking/precompile/delegation_rewards.go index 6e09295b..9e4bbf94 100644 --- a/x/staking/precompile/delegation_rewards.go +++ b/x/staking/precompile/delegation_rewards.go @@ -14,13 +14,13 @@ import ( type DelegationRewardsMethod struct { *Keeper - abi.Method + DelegationRewardsABI } func NewDelegationRewardsMethod(keeper *Keeper) *DelegationRewardsMethod { return &DelegationRewardsMethod{ - Keeper: keeper, - Method: stakingABI.Methods["delegationRewards"], + Keeper: keeper, + DelegationRewardsABI: NewDelegationRewardsABI(), } } @@ -69,25 +69,35 @@ func (m *DelegationRewardsMethod) Run(evm *vm.EVM, contract *vm.Contract) ([]byt return m.PackOutput(rewards.AmountOf(m.stakingDenom).TruncateInt().BigInt()) } -func (m *DelegationRewardsMethod) PackInput(args fxstakingtypes.DelegationRewardsArgs) ([]byte, error) { +type DelegationRewardsABI struct { + abi.Method +} + +func NewDelegationRewardsABI() DelegationRewardsABI { + return DelegationRewardsABI{ + Method: stakingABI.Methods["delegationRewards"], + } +} + +func (m DelegationRewardsABI) PackInput(args fxstakingtypes.DelegationRewardsArgs) ([]byte, error) { arguments, err := m.Method.Inputs.Pack(args.Validator, args.Delegator) if err != nil { return nil, err } - return append(m.GetMethodId(), arguments...), nil + return append(m.Method.ID, arguments...), nil } -func (m *DelegationRewardsMethod) UnpackInput(data []byte) (*fxstakingtypes.DelegationRewardsArgs, error) { +func (m DelegationRewardsABI) UnpackInput(data []byte) (*fxstakingtypes.DelegationRewardsArgs, error) { args := new(fxstakingtypes.DelegationRewardsArgs) err := types.ParseMethodArgs(m.Method, args, data[4:]) return args, err } -func (m *DelegationRewardsMethod) PackOutput(amount *big.Int) ([]byte, error) { +func (m DelegationRewardsABI) PackOutput(amount *big.Int) ([]byte, error) { return m.Method.Outputs.Pack(amount) } -func (m *DelegationRewardsMethod) UnpackOutput(data []byte) (*big.Int, error) { +func (m DelegationRewardsABI) UnpackOutput(data []byte) (*big.Int, error) { amount, err := m.Method.Outputs.Unpack(data) if err != nil { return nil, err diff --git a/x/staking/precompile/keeper.go b/x/staking/precompile/keeper.go index 60000f01..17395d82 100644 --- a/x/staking/precompile/keeper.go +++ b/x/staking/precompile/keeper.go @@ -1,14 +1,26 @@ package precompile import ( + "errors" + "fmt" "math/big" + "sort" sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + + fxcontract "github.com/functionx/fx-core/v8/contract" ) +type Validator struct { + ValAddr string + MissedBlocks int64 +} + type Keeper struct { bankKeeper BankKeeper distrKeeper DistrKeeper @@ -19,6 +31,232 @@ type Keeper struct { stakingDenom string } +//nolint:gocyclo // need to refactor +func (k Keeper) handlerTransferShares( + ctx sdk.Context, + evm *vm.EVM, + valAddr sdk.ValAddress, + from, to common.Address, + sharesInt *big.Int, +) (*big.Int, *big.Int, error) { + validator, err := k.stakingKeeper.GetValidator(ctx, valAddr) + if err != nil { + return nil, nil, err + } + fromDel, err := k.stakingKeeper.GetDelegation(ctx, from.Bytes(), valAddr) + if err != nil { + return nil, nil, err + } + // if from has receiving redelegation, can't transfer shares + has, err := k.stakingKeeper.HasReceivingRedelegation(ctx, from.Bytes(), valAddr) + if err != nil { + return nil, nil, err + } + if has { + return nil, nil, errors.New("from has receiving redelegation") + } + + shares := sdkmath.LegacyNewDecFromBigInt(sharesInt) + if fromDel.GetShares().LT(shares) { + return nil, nil, fmt.Errorf("insufficient shares(%s < %s)", fromDel.GetShares().TruncateInt().String(), shares.TruncateInt().String()) + } + + // withdraw reward + withdrawAddr, err := k.distrKeeper.GetDelegatorWithdrawAddr(ctx, to.Bytes()) + if err != nil { + return nil, nil, err + } + beforeDelBalance := k.bankKeeper.GetBalance(ctx, withdrawAddr, k.stakingDenom) + + // withdraw reward + withdrawRewardRes, err := k.distrMsgServer.WithdrawDelegatorReward(ctx, &distrtypes.MsgWithdrawDelegatorReward{ + DelegatorAddress: sdk.AccAddress(from.Bytes()).String(), + ValidatorAddress: valAddr.String(), + }) + if err != nil { + return nil, nil, err + } + + withdrawMethod := NewWithdrawMethod(nil) + data, topic, err := withdrawMethod.NewWithdrawEvent(from, valAddr.String(), withdrawRewardRes.Amount.AmountOf(k.stakingDenom).BigInt()) + if err != nil { + return nil, nil, err + } + fxcontract.EmitEvent(evm, stakingAddress, data, topic) + + // get to delegation + toDel, err := k.stakingKeeper.GetDelegation(ctx, to.Bytes(), valAddr) + toDelFound := false + if err != nil { + if !errors.Is(err, stakingtypes.ErrNoDelegation) { + return nil, nil, err + } + toDel = stakingtypes.NewDelegation(sdk.AccAddress(to.Bytes()).String(), valAddr.String(), sdkmath.LegacyZeroDec()) + // if address to not delegate before, increase validator period + if _, err = k.distrKeeper.IncrementValidatorPeriod(ctx, validator); err != nil { + return nil, nil, err + } + } else { + toDelFound = true + toWithdrawRewardsRes, err := k.distrMsgServer.WithdrawDelegatorReward(ctx, &distrtypes.MsgWithdrawDelegatorReward{ + DelegatorAddress: sdk.AccAddress(to.Bytes()).String(), + ValidatorAddress: valAddr.String(), + }) + if err != nil { + return nil, nil, err + } + data, topic, err = withdrawMethod.NewWithdrawEvent(to, valAddr.String(), toWithdrawRewardsRes.Amount.AmountOf(k.stakingDenom).BigInt()) + if err != nil { + return nil, nil, err + } + fxcontract.EmitEvent(evm, stakingAddress, data, topic) + } + + // update from delegate, delete it if shares zero + fromDelStartingInfo, err := k.distrKeeper.GetDelegatorStartingInfo(ctx, valAddr, from.Bytes()) + if err != nil { + return nil, nil, err + } + fromDel.Shares = fromDel.Shares.Sub(shares) + if fromDel.GetShares().IsZero() { + // if shares zero, remove delegation and delete starting info and reference count + if err = k.stakingKeeper.RemoveDelegation(ctx, fromDel); err != nil { + return nil, nil, err + } + // decrement previous period reference count + if err = k.decrementReferenceCount(ctx, valAddr, fromDelStartingInfo.PreviousPeriod); err != nil { + return nil, nil, err + } + if err = k.distrKeeper.DeleteDelegatorStartingInfo(ctx, valAddr, from.Bytes()); err != nil { + return nil, nil, err + } + } else { + if err = k.stakingKeeper.SetDelegation(ctx, fromDel); err != nil { + return nil, nil, err + } + // update from starting info + fromDelStartingInfo.Stake = validator.TokensFromSharesTruncated(fromDel.GetShares()) + if err = k.distrKeeper.SetDelegatorStartingInfo(ctx, valAddr, from.Bytes(), fromDelStartingInfo); err != nil { + return nil, nil, err + } + } + + // update to delegate, set starting info if to not delegate before + toDel.Shares = toDel.Shares.Add(shares) + if err = k.stakingKeeper.SetDelegation(ctx, toDel); err != nil { + return nil, nil, err + } + if !toDelFound { + // if to not delegate before, last period reference count - 1 and set starting info + validatorCurrentRewards, err := k.distrKeeper.GetValidatorCurrentRewards(ctx, valAddr) + if err != nil { + return nil, nil, err + } + previousPeriod := validatorCurrentRewards.Period - 1 + if err = k.incrementReferenceCount(ctx, valAddr, previousPeriod); err != nil { + return nil, nil, err + } + + stakeToken := validator.TokensFromSharesTruncated(shares) + toDelStartingInfo := distrtypes.NewDelegatorStartingInfo(previousPeriod, stakeToken, uint64(ctx.BlockHeight())) + if err = k.distrKeeper.SetDelegatorStartingInfo(ctx, valAddr, to.Bytes(), toDelStartingInfo); err != nil { + return nil, nil, err + } + } else { + // update to starting info + toDelStartingInfo, err := k.distrKeeper.GetDelegatorStartingInfo(ctx, valAddr, to.Bytes()) + if err != nil { + return nil, nil, err + } + toDelStartingInfo.Stake = validator.TokensFromSharesTruncated(toDel.GetShares()) + if err = k.distrKeeper.SetDelegatorStartingInfo(ctx, valAddr, to.Bytes(), toDelStartingInfo); err != nil { + return nil, nil, err + } + } + + // calculate token from shares + token := validator.TokensFromShares(shares).TruncateInt() + + afterDelBalance := k.bankKeeper.GetBalance(ctx, withdrawAddr, k.stakingDenom) + toRewardCoin := afterDelBalance.Sub(beforeDelBalance) + + return token.BigInt(), toRewardCoin.Amount.BigInt(), nil +} + +func (k Keeper) decrementAllowance(ctx sdk.Context, valAddr sdk.ValAddress, owner, spender sdk.AccAddress, decrease *big.Int) error { + allowance := k.stakingKeeper.GetAllowance(ctx, valAddr, owner, spender) + if allowance.Cmp(decrease) < 0 { + return fmt.Errorf("transfer shares exceeds allowance(%s < %s)", allowance.String(), decrease.String()) + } + newAllowance := big.NewInt(0).Sub(allowance, decrease) + k.stakingKeeper.SetAllowance(ctx, valAddr, owner, spender, newAllowance) + return nil +} + +// increment the reference count for a historical rewards value +func (k Keeper) incrementReferenceCount(ctx sdk.Context, valAddr sdk.ValAddress, period uint64) error { + historical, err := k.distrKeeper.GetValidatorHistoricalRewards(ctx, valAddr, period) + if err != nil { + return err + } + if historical.ReferenceCount > 2 { + return errors.New("reference count should never exceed 2") + } + historical.ReferenceCount++ + return k.distrKeeper.SetValidatorHistoricalRewards(ctx, valAddr, period, historical) +} + +// decrement the reference count for a historical rewards value, and delete if zero references remain +func (k Keeper) decrementReferenceCount(ctx sdk.Context, valAddr sdk.ValAddress, period uint64) error { + historical, err := k.distrKeeper.GetValidatorHistoricalRewards(ctx, valAddr, period) + if err != nil { + return err + } + if historical.ReferenceCount == 0 { + panic("cannot set negative reference count") + } + historical.ReferenceCount-- + if historical.ReferenceCount == 0 { + return k.distrKeeper.DeleteValidatorHistoricalReward(ctx, valAddr, period) + } else { + return k.distrKeeper.SetValidatorHistoricalRewards(ctx, valAddr, period, historical) + } +} + func (k Keeper) NewStakingCoin(amount *big.Int) sdk.Coin { return sdk.NewCoin(k.stakingDenom, sdkmath.NewIntFromBigInt(amount)) } + +func (k Keeper) ValidatorListMissedBlock(ctx sdk.Context, bondedVals []stakingtypes.Validator) ([]string, error) { + valList := make([]Validator, 0, len(bondedVals)) + for _, val := range bondedVals { + consAddr, err := val.GetConsAddr() + if err != nil { + return nil, err + } + info, err := k.slashingKeeper.GetValidatorSigningInfo(ctx, consAddr) + if err != nil { + return nil, err + } + valList = append(valList, Validator{ + ValAddr: val.OperatorAddress, + MissedBlocks: info.MissedBlocksCounter, + }) + } + sort.Slice(valList, func(i, j int) bool { + return valList[i].MissedBlocks > valList[j].MissedBlocks + }) + valAddrs := make([]string, 0, len(valList)) + for _, l := range valList { + valAddrs = append(valAddrs, l.ValAddr) + } + return valAddrs, nil +} + +func validatorListPower(bondedVals []stakingtypes.Validator) []string { + valAddrs := make([]string, 0, len(bondedVals)) + for _, val := range bondedVals { + valAddrs = append(valAddrs, val.OperatorAddress) + } + return valAddrs +} diff --git a/x/staking/precompile/redelegate.go b/x/staking/precompile/redelegate.go index 2f5ce89f..7adfceeb 100644 --- a/x/staking/precompile/redelegate.go +++ b/x/staking/precompile/redelegate.go @@ -16,33 +16,31 @@ import ( fxstakingtypes "github.com/functionx/fx-core/v8/x/staking/types" ) -type RedelegateMethodV2 struct { +type RedelegateV2Method struct { *Keeper - abi.Method - abi.Event + RedelegateABI } -func NewRedelegateV2Method(keeper *Keeper) *RedelegateMethodV2 { - return &RedelegateMethodV2{ - Keeper: keeper, - Method: stakingABI.Methods["redelegateV2"], - Event: stakingABI.Events["RedelegateV2"], +func NewRedelegateV2Method(keeper *Keeper) *RedelegateV2Method { + return &RedelegateV2Method{ + Keeper: keeper, + RedelegateABI: NewRedelegateABI(), } } -func (m *RedelegateMethodV2) IsReadonly() bool { +func (m *RedelegateV2Method) IsReadonly() bool { return false } -func (m *RedelegateMethodV2) GetMethodId() []byte { +func (m *RedelegateV2Method) GetMethodId() []byte { return m.Method.ID } -func (m *RedelegateMethodV2) RequiredGas() uint64 { +func (m *RedelegateV2Method) RequiredGas() uint64 { return 60_000 } -func (m *RedelegateMethodV2) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, error) { +func (m *RedelegateV2Method) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, error) { args, err := m.UnpackInput(contract.Input) if err != nil { return nil, err @@ -76,7 +74,19 @@ func (m *RedelegateMethodV2) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, er return m.PackOutput(true) } -func (m *RedelegateMethodV2) NewRedelegationEvent(sender common.Address, validatorSrc, validatorDst string, amount *big.Int, completionTime int64) (data []byte, topic []common.Hash, err error) { +type RedelegateABI struct { + abi.Method + abi.Event +} + +func NewRedelegateABI() RedelegateABI { + return RedelegateABI{ + Method: stakingABI.Methods["redelegateV2"], + Event: stakingABI.Events["RedelegateV2"], + } +} + +func (m RedelegateABI) NewRedelegationEvent(sender common.Address, validatorSrc, validatorDst string, amount *big.Int, completionTime int64) (data []byte, topic []common.Hash, err error) { data, topic, err = types.PackTopicData(m.Event, []common.Hash{sender.Hash()}, validatorSrc, validatorDst, amount, big.NewInt(completionTime)) if err != nil { return nil, nil, err @@ -84,25 +94,25 @@ func (m *RedelegateMethodV2) NewRedelegationEvent(sender common.Address, validat return data, topic, nil } -func (m *RedelegateMethodV2) PackInput(args fxstakingtypes.RedelegateV2Args) ([]byte, error) { +func (m RedelegateABI) PackInput(args fxstakingtypes.RedelegateV2Args) ([]byte, error) { arguments, err := m.Method.Inputs.Pack(args.ValidatorSrc, args.ValidatorDst, args.Amount) if err != nil { return nil, err } - return append(m.GetMethodId(), arguments...), nil + return append(m.Method.ID, arguments...), nil } -func (m *RedelegateMethodV2) UnpackInput(data []byte) (*fxstakingtypes.RedelegateV2Args, error) { +func (m RedelegateABI) UnpackInput(data []byte) (*fxstakingtypes.RedelegateV2Args, error) { args := new(fxstakingtypes.RedelegateV2Args) err := types.ParseMethodArgs(m.Method, args, data[4:]) return args, err } -func (m *RedelegateMethodV2) PackOutput(result bool) ([]byte, error) { +func (m RedelegateABI) PackOutput(result bool) ([]byte, error) { return m.Method.Outputs.Pack(result) } -func (m *RedelegateMethodV2) UnpackOutput(data []byte) (bool, error) { +func (m RedelegateABI) UnpackOutput(data []byte) (bool, error) { amount, err := m.Method.Outputs.Unpack(data) if err != nil { return false, err @@ -110,7 +120,7 @@ func (m *RedelegateMethodV2) UnpackOutput(data []byte) (bool, error) { return amount[0].(bool), nil } -func (m *RedelegateMethodV2) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingRedelegateV2, error) { +func (m RedelegateABI) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingRedelegateV2, error) { if log == nil { return nil, errors.New("empty log") } diff --git a/x/staking/precompile/redelegate_test.go b/x/staking/precompile/redelegate_test.go index ddce00cd..ade2da1d 100644 --- a/x/staking/precompile/redelegate_test.go +++ b/x/staking/precompile/redelegate_test.go @@ -113,7 +113,7 @@ func (suite *PrecompileTestSuite) TestRedelegate() { var packData []byte args, errResult := tc.malleate(operator0, operator1, delegation0.Shares, delAmt) - packData, err = suite.redelegateMethodV2.PackInput(args.(types.RedelegateV2Args)) + packData, err = suite.redelegateV2Method.PackInput(args.(types.RedelegateV2Args)) suite.Require().NoError(err) res = suite.EthereumTx(suite.signer, stakingContract, big.NewInt(0), packData) diff --git a/x/staking/precompile/slashing_info.go b/x/staking/precompile/slashing_info.go index 7de7a69e..9bcdc01d 100644 --- a/x/staking/precompile/slashing_info.go +++ b/x/staking/precompile/slashing_info.go @@ -12,13 +12,13 @@ import ( type SlashingInfoMethod struct { *Keeper - abi.Method + SlashingABI } func NewSlashingInfoMethod(keeper *Keeper) *SlashingInfoMethod { return &SlashingInfoMethod{ - Keeper: keeper, - Method: stakingABI.Methods["slashingInfo"], + Keeper: keeper, + SlashingABI: NewSlashingABI(), } } @@ -60,25 +60,35 @@ func (m *SlashingInfoMethod) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, er return m.PackOutput(validator.Jailed, signingInfo.MissedBlocksCounter) } -func (m *SlashingInfoMethod) PackInput(args fxstakingtypes.SlashingInfoArgs) ([]byte, error) { +type SlashingABI struct { + abi.Method +} + +func NewSlashingABI() SlashingABI { + return SlashingABI{ + Method: stakingABI.Methods["slashingInfo"], + } +} + +func (m SlashingABI) PackInput(args fxstakingtypes.SlashingInfoArgs) ([]byte, error) { arguments, err := m.Method.Inputs.Pack(args.Validator) if err != nil { return nil, err } - return append(m.GetMethodId(), arguments...), nil + return append(m.Method.ID, arguments...), nil } -func (m *SlashingInfoMethod) UnpackInput(data []byte) (*fxstakingtypes.SlashingInfoArgs, error) { +func (m SlashingABI) UnpackInput(data []byte) (*fxstakingtypes.SlashingInfoArgs, error) { args := new(fxstakingtypes.SlashingInfoArgs) err := types.ParseMethodArgs(m.Method, args, data[4:]) return args, err } -func (m *SlashingInfoMethod) PackOutput(jailed bool, missed int64) ([]byte, error) { +func (m SlashingABI) PackOutput(jailed bool, missed int64) ([]byte, error) { return m.Method.Outputs.Pack(jailed, big.NewInt(missed)) } -func (m *SlashingInfoMethod) UnpackOutput(data []byte) (bool, *big.Int, error) { +func (m SlashingABI) UnpackOutput(data []byte) (bool, *big.Int, error) { unpack, err := m.Method.Outputs.Unpack(data) if err != nil { return false, nil, err diff --git a/x/staking/precompile/transfer_shares.go b/x/staking/precompile/transfer_shares.go index 965970cb..8c8efda8 100644 --- a/x/staking/precompile/transfer_shares.go +++ b/x/staking/precompile/transfer_shares.go @@ -2,13 +2,9 @@ package precompile import ( "errors" - "fmt" "math/big" - sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -20,39 +16,31 @@ import ( fxstakingtypes "github.com/functionx/fx-core/v8/x/staking/types" ) -type TransferShare struct { +type TransferSharesMethod struct { *Keeper - abi.Method - abi.Event -} - -type TransferShares struct { - *TransferShare + TransferSharesABI } -func NewTransferSharesMethod(keeper *Keeper) *TransferShares { - return &TransferShares{ - TransferShare: &TransferShare{ - Keeper: keeper, - Method: stakingABI.Methods["transferShares"], - Event: stakingABI.Events["TransferShares"], - }, +func NewTransferSharesMethod(keeper *Keeper) *TransferSharesMethod { + return &TransferSharesMethod{ + Keeper: keeper, + TransferSharesABI: NewTransferSharesABI(), } } -func (m *TransferShares) IsReadonly() bool { +func (m *TransferSharesMethod) IsReadonly() bool { return false } -func (m *TransferShares) GetMethodId() []byte { +func (m *TransferSharesMethod) GetMethodId() []byte { return m.Method.ID } -func (m *TransferShares) RequiredGas() uint64 { +func (m *TransferSharesMethod) RequiredGas() uint64 { return 50_000 } -func (m *TransferShares) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, error) { +func (m *TransferSharesMethod) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, error) { args, err := m.UnpackInput(contract.Input) if err != nil { return nil, err @@ -67,6 +55,12 @@ func (m *TransferShares) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, error) return err } + data, topic, err := m.NewTransferShareEvent(contract.Caller(), args.To, valAddr.String(), args.Shares, token) + if err != nil { + return err + } + fxcontract.EmitEvent(evm, stakingAddress, data, topic) + ctx.EventManager().EmitEvent( sdk.NewEvent( sdk.EventTypeMessage, @@ -82,47 +76,58 @@ func (m *TransferShares) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, error) return result, nil } -func (m *TransferShares) PackInput(args fxstakingtypes.TransferSharesArgs) ([]byte, error) { +type TransferSharesABI struct { + transferShareABI +} + +func NewTransferSharesABI() TransferSharesABI { + return TransferSharesABI{ + transferShareABI: transferShareABI{ + Method: stakingABI.Methods["transferShares"], + Event: stakingABI.Events["TransferShares"], + }, + } +} + +func (m TransferSharesABI) PackInput(args fxstakingtypes.TransferSharesArgs) ([]byte, error) { arguments, err := m.Method.Inputs.Pack(args.Validator, args.To, args.Shares) if err != nil { return nil, err } - return append(m.GetMethodId(), arguments...), nil + return append(m.Method.ID, arguments...), nil } -func (m *TransferShares) UnpackInput(data []byte) (*fxstakingtypes.TransferSharesArgs, error) { +func (m TransferSharesABI) UnpackInput(data []byte) (*fxstakingtypes.TransferSharesArgs, error) { args := new(fxstakingtypes.TransferSharesArgs) err := types.ParseMethodArgs(m.Method, args, data[4:]) return args, err } -type TransferFromShares struct { - *TransferShare +type TransferFromSharesMethod struct { + *Keeper + TransferFromSharesABI } -func NewTransferFromSharesMethod(keeper *Keeper) *TransferFromShares { - return &TransferFromShares{ - TransferShare: &TransferShare{ - Keeper: keeper, - Method: stakingABI.Methods["transferFromShares"], - Event: stakingABI.Events["TransferShares"], - }, +func NewTransferFromSharesMethod(keeper *Keeper) *TransferFromSharesMethod { + return &TransferFromSharesMethod{ + Keeper: keeper, + TransferFromSharesABI: NewTransferFromSharesABI(), } } -func (m *TransferFromShares) IsReadonly() bool { +func (m *TransferFromSharesMethod) IsReadonly() bool { return false } -func (m *TransferFromShares) GetMethodId() []byte { +func (m *TransferFromSharesMethod) GetMethodId() []byte { return m.Method.ID } -func (m *TransferFromShares) RequiredGas() uint64 { +func (m *TransferFromSharesMethod) RequiredGas() uint64 { return 60_000 } -func (m *TransferFromShares) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, error) { +func (m *TransferFromSharesMethod) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, error) { args, err := m.UnpackInput(contract.Input) if err != nil { return nil, err @@ -141,6 +146,12 @@ func (m *TransferFromShares) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, er return err } + data, topic, err := m.NewTransferShareEvent(args.From, args.To, valAddr.String(), args.Shares, token) + if err != nil { + return err + } + fxcontract.EmitEvent(evm, stakingAddress, data, topic) + result, err = m.PackOutput(token, reward) if err != nil { return err @@ -158,194 +169,43 @@ func (m *TransferFromShares) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, er return result, err } -func (m *TransferFromShares) PackInput(args fxstakingtypes.TransferFromSharesArgs) ([]byte, error) { +type TransferFromSharesABI struct { + transferShareABI +} + +func NewTransferFromSharesABI() TransferFromSharesABI { + return TransferFromSharesABI{ + transferShareABI: transferShareABI{ + Method: stakingABI.Methods["transferFromShares"], + Event: stakingABI.Events["TransferShares"], + }, + } +} + +func (m TransferFromSharesABI) PackInput(args fxstakingtypes.TransferFromSharesArgs) ([]byte, error) { arguments, err := m.Method.Inputs.Pack(args.Validator, args.From, args.To, args.Shares) if err != nil { return nil, err } - return append(m.GetMethodId(), arguments...), nil + return append(m.Method.ID, arguments...), nil } -func (m *TransferFromShares) UnpackInput(data []byte) (*fxstakingtypes.TransferFromSharesArgs, error) { +func (m TransferFromSharesABI) UnpackInput(data []byte) (*fxstakingtypes.TransferFromSharesArgs, error) { args := new(fxstakingtypes.TransferFromSharesArgs) err := types.ParseMethodArgs(m.Method, args, data[4:]) return args, err } -func (m *TransferShare) decrementAllowance(ctx sdk.Context, valAddr sdk.ValAddress, owner, spender sdk.AccAddress, decrease *big.Int) error { - allowance := m.stakingKeeper.GetAllowance(ctx, valAddr, owner, spender) - if allowance.Cmp(decrease) < 0 { - return fmt.Errorf("transfer shares exceeds allowance(%s < %s)", allowance.String(), decrease.String()) - } - newAllowance := big.NewInt(0).Sub(allowance, decrease) - m.stakingKeeper.SetAllowance(ctx, valAddr, owner, spender, newAllowance) - return nil -} - -//nolint:gocyclo // need to refactor -func (m *TransferShare) handlerTransferShares( - ctx sdk.Context, - evm *vm.EVM, - valAddr sdk.ValAddress, - from, to common.Address, - sharesInt *big.Int, -) (*big.Int, *big.Int, error) { - validator, err := m.stakingKeeper.GetValidator(ctx, valAddr) - if err != nil { - return nil, nil, err - } - fromDel, err := m.stakingKeeper.GetDelegation(ctx, from.Bytes(), valAddr) - if err != nil { - return nil, nil, err - } - // if from has receiving redelegation, can't transfer shares - has, err := m.stakingKeeper.HasReceivingRedelegation(ctx, from.Bytes(), valAddr) - if err != nil { - return nil, nil, err - } - if has { - return nil, nil, errors.New("from has receiving redelegation") - } - - shares := sdkmath.LegacyNewDecFromBigInt(sharesInt) - if fromDel.GetShares().LT(shares) { - return nil, nil, fmt.Errorf("insufficient shares(%s < %s)", fromDel.GetShares().TruncateInt().String(), shares.TruncateInt().String()) - } - - // withdraw reward - withdrawAddr, err := m.distrKeeper.GetDelegatorWithdrawAddr(ctx, to.Bytes()) - if err != nil { - return nil, nil, err - } - beforeDelBalance := m.bankKeeper.GetBalance(ctx, withdrawAddr, m.stakingDenom) - - // withdraw reward - withdrawRewardRes, err := m.distrMsgServer.WithdrawDelegatorReward(ctx, &distrtypes.MsgWithdrawDelegatorReward{ - DelegatorAddress: sdk.AccAddress(from.Bytes()).String(), - ValidatorAddress: valAddr.String(), - }) - if err != nil { - return nil, nil, err - } - - withdrawMethod := NewWithdrawMethod(nil) - data, topic, err := withdrawMethod.NewWithdrawEvent(from, valAddr.String(), withdrawRewardRes.Amount.AmountOf(m.stakingDenom).BigInt()) - if err != nil { - return nil, nil, err - } - fxcontract.EmitEvent(evm, stakingAddress, data, topic) - - // get to delegation - toDel, err := m.stakingKeeper.GetDelegation(ctx, to.Bytes(), valAddr) - toDelFound := false - if err != nil { - if !errors.Is(err, stakingtypes.ErrNoDelegation) { - return nil, nil, err - } - toDel = stakingtypes.NewDelegation(sdk.AccAddress(to.Bytes()).String(), valAddr.String(), sdkmath.LegacyZeroDec()) - // if address to not delegate before, increase validator period - if _, err = m.distrKeeper.IncrementValidatorPeriod(ctx, validator); err != nil { - return nil, nil, err - } - } else { - toDelFound = true - toWithdrawRewardsRes, err := m.distrMsgServer.WithdrawDelegatorReward(ctx, &distrtypes.MsgWithdrawDelegatorReward{ - DelegatorAddress: sdk.AccAddress(to.Bytes()).String(), - ValidatorAddress: valAddr.String(), - }) - if err != nil { - return nil, nil, err - } - data, topic, err = withdrawMethod.NewWithdrawEvent(to, valAddr.String(), toWithdrawRewardsRes.Amount.AmountOf(m.stakingDenom).BigInt()) - if err != nil { - return nil, nil, err - } - fxcontract.EmitEvent(evm, stakingAddress, data, topic) - } - - // update from delegate, delete it if shares zero - fromDelStartingInfo, err := m.distrKeeper.GetDelegatorStartingInfo(ctx, valAddr, from.Bytes()) - if err != nil { - return nil, nil, err - } - fromDel.Shares = fromDel.Shares.Sub(shares) - if fromDel.GetShares().IsZero() { - // if shares zero, remove delegation and delete starting info and reference count - if err = m.stakingKeeper.RemoveDelegation(ctx, fromDel); err != nil { - return nil, nil, err - } - // decrement previous period reference count - if err = decrementReferenceCount(m.distrKeeper, ctx, valAddr, fromDelStartingInfo.PreviousPeriod); err != nil { - return nil, nil, err - } - if err = m.distrKeeper.DeleteDelegatorStartingInfo(ctx, valAddr, from.Bytes()); err != nil { - return nil, nil, err - } - } else { - if err = m.stakingKeeper.SetDelegation(ctx, fromDel); err != nil { - return nil, nil, err - } - // update from starting info - fromDelStartingInfo.Stake = validator.TokensFromSharesTruncated(fromDel.GetShares()) - if err = m.distrKeeper.SetDelegatorStartingInfo(ctx, valAddr, from.Bytes(), fromDelStartingInfo); err != nil { - return nil, nil, err - } - } - - // update to delegate, set starting info if to not delegate before - toDel.Shares = toDel.Shares.Add(shares) - if err = m.stakingKeeper.SetDelegation(ctx, toDel); err != nil { - return nil, nil, err - } - if !toDelFound { - // if to not delegate before, last period reference count - 1 and set starting info - validatorCurrentRewards, err := m.distrKeeper.GetValidatorCurrentRewards(ctx, valAddr) - if err != nil { - return nil, nil, err - } - previousPeriod := validatorCurrentRewards.Period - 1 - if err = incrementReferenceCount(m.distrKeeper, ctx, valAddr, previousPeriod); err != nil { - return nil, nil, err - } - - stakeToken := validator.TokensFromSharesTruncated(shares) - toDelStartingInfo := distrtypes.NewDelegatorStartingInfo(previousPeriod, stakeToken, uint64(ctx.BlockHeight())) - if err = m.distrKeeper.SetDelegatorStartingInfo(ctx, valAddr, to.Bytes(), toDelStartingInfo); err != nil { - return nil, nil, err - } - } else { - // update to starting info - toDelStartingInfo, err := m.distrKeeper.GetDelegatorStartingInfo(ctx, valAddr, to.Bytes()) - if err != nil { - return nil, nil, err - } - toDelStartingInfo.Stake = validator.TokensFromSharesTruncated(toDel.GetShares()) - if err = m.distrKeeper.SetDelegatorStartingInfo(ctx, valAddr, to.Bytes(), toDelStartingInfo); err != nil { - return nil, nil, err - } - } - - // calculate token from shares - token := validator.TokensFromShares(shares).TruncateInt() - - afterDelBalance := m.bankKeeper.GetBalance(ctx, withdrawAddr, m.stakingDenom) - toRewardCoin := afterDelBalance.Sub(beforeDelBalance) - - // add log - data, topic, err = m.NewTransferShareEvent(from, to, valAddr.String(), shares.TruncateInt().BigInt(), token.BigInt()) - if err != nil { - return nil, nil, err - } - fxcontract.EmitEvent(evm, stakingAddress, data, topic) - - return token.BigInt(), toRewardCoin.Amount.BigInt(), nil +type transferShareABI struct { + abi.Method + abi.Event } -func (m *TransferShare) PackOutput(amount, reward *big.Int) ([]byte, error) { +func (m transferShareABI) PackOutput(amount, reward *big.Int) ([]byte, error) { return m.Method.Outputs.Pack(amount, reward) } -func (m *TransferShare) UnpackOutput(data []byte) (*big.Int, *big.Int, error) { +func (m transferShareABI) UnpackOutput(data []byte) (*big.Int, *big.Int, error) { unpacks, err := m.Method.Outputs.Unpack(data) if err != nil { return nil, nil, err @@ -353,7 +213,7 @@ func (m *TransferShare) UnpackOutput(data []byte) (*big.Int, *big.Int, error) { return unpacks[0].(*big.Int), unpacks[1].(*big.Int), nil } -func (m *TransferShare) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingTransferShares, error) { +func (m transferShareABI) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingTransferShares, error) { if log == nil { return nil, errors.New("empty log") } @@ -364,40 +224,10 @@ func (m *TransferShare) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingTran return filterer.ParseTransferShares(*log) } -func (m *TransferShare) NewTransferShareEvent(sender, to common.Address, validator string, shares, amount *big.Int) (data []byte, topic []common.Hash, err error) { +func (m transferShareABI) NewTransferShareEvent(sender, to common.Address, validator string, shares, amount *big.Int) (data []byte, topic []common.Hash, err error) { data, topic, err = types.PackTopicData(m.Event, []common.Hash{sender.Hash(), to.Hash()}, validator, shares, amount) if err != nil { return nil, nil, err } return data, topic, nil } - -// increment the reference count for a historical rewards value -func incrementReferenceCount(k DistrKeeper, ctx sdk.Context, valAddr sdk.ValAddress, period uint64) error { - historical, err := k.GetValidatorHistoricalRewards(ctx, valAddr, period) - if err != nil { - return err - } - if historical.ReferenceCount > 2 { - return errors.New("reference count should never exceed 2") - } - historical.ReferenceCount++ - return k.SetValidatorHistoricalRewards(ctx, valAddr, period, historical) -} - -// decrement the reference count for a historical rewards value, and delete if zero references remain -func decrementReferenceCount(k DistrKeeper, ctx sdk.Context, valAddr sdk.ValAddress, period uint64) error { - historical, err := k.GetValidatorHistoricalRewards(ctx, valAddr, period) - if err != nil { - return err - } - if historical.ReferenceCount == 0 { - panic("cannot set negative reference count") - } - historical.ReferenceCount-- - if historical.ReferenceCount == 0 { - return k.DeleteValidatorHistoricalReward(ctx, valAddr, period) - } else { - return k.SetValidatorHistoricalRewards(ctx, valAddr, period, historical) - } -} diff --git a/x/staking/precompile/undelegate.go b/x/staking/precompile/undelegate.go index c4ac3251..f219321f 100644 --- a/x/staking/precompile/undelegate.go +++ b/x/staking/precompile/undelegate.go @@ -18,15 +18,13 @@ import ( type UndelegateV2Method struct { *Keeper - abi.Method - abi.Event + UndelegateABI } func NewUndelegateV2Method(keeper *Keeper) *UndelegateV2Method { return &UndelegateV2Method{ - Keeper: keeper, - Method: stakingABI.Methods["undelegateV2"], - Event: stakingABI.Events["UndelegateV2"], + Keeper: keeper, + UndelegateABI: NewUndelegateV2ABI(), } } @@ -81,25 +79,37 @@ func (m *UndelegateV2Method) NewUndelegateEvent(sender common.Address, validator return data, topic, nil } -func (m *UndelegateV2Method) PackInput(args fxstakingtypes.UndelegateV2Args) ([]byte, error) { +type UndelegateABI struct { + abi.Method + abi.Event +} + +func NewUndelegateV2ABI() UndelegateABI { + return UndelegateABI{ + Method: stakingABI.Methods["undelegateV2"], + Event: stakingABI.Events["UndelegateV2"], + } +} + +func (m UndelegateABI) PackInput(args fxstakingtypes.UndelegateV2Args) ([]byte, error) { arguments, err := m.Method.Inputs.Pack(args.Validator, args.Amount) if err != nil { return nil, err } - return append(m.GetMethodId(), arguments...), nil + return append(m.Method.ID, arguments...), nil } -func (m *UndelegateV2Method) UnpackInput(data []byte) (*fxstakingtypes.UndelegateV2Args, error) { +func (m UndelegateABI) UnpackInput(data []byte) (*fxstakingtypes.UndelegateV2Args, error) { args := new(fxstakingtypes.UndelegateV2Args) err := types.ParseMethodArgs(m.Method, args, data[4:]) return args, err } -func (m *UndelegateV2Method) PackOutput(result bool) ([]byte, error) { +func (m UndelegateABI) PackOutput(result bool) ([]byte, error) { return m.Method.Outputs.Pack(result) } -func (m *UndelegateV2Method) UnpackOutput(data []byte) (bool, error) { +func (m UndelegateABI) UnpackOutput(data []byte) (bool, error) { amount, err := m.Method.Outputs.Unpack(data) if err != nil { return false, err @@ -107,7 +117,7 @@ func (m *UndelegateV2Method) UnpackOutput(data []byte) (bool, error) { return amount[0].(bool), nil } -func (m *UndelegateV2Method) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingUndelegateV2, error) { +func (m UndelegateABI) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingUndelegateV2, error) { if log == nil { return nil, errors.New("empty log") } diff --git a/x/staking/precompile/validator_list.go b/x/staking/precompile/validator_list.go index 0b0a91a4..1d28be82 100644 --- a/x/staking/precompile/validator_list.go +++ b/x/staking/precompile/validator_list.go @@ -1,10 +1,6 @@ package precompile import ( - "sort" - - sdk "github.com/cosmos/cosmos-sdk/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/core/vm" @@ -14,18 +10,13 @@ import ( type ValidatorListMethod struct { *Keeper - abi.Method -} - -type ValidatorList struct { - ValAddr string - MissedBlocks int64 + ValidatorListABI } func NewValidatorListMethod(keeper *Keeper) *ValidatorListMethod { return &ValidatorListMethod{ - Keeper: keeper, - Method: stakingABI.Methods["validatorList"], + Keeper: keeper, + ValidatorListABI: NewValidatorListABI(), } } @@ -58,7 +49,7 @@ func (m *ValidatorListMethod) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, e valAddrs := make([]string, 0, len(bondedVals)) switch args.GetSortBy() { case fxstakingtypes.ValidatorSortByPower: - valAddrs = m.ValidatorListPower(bondedVals) + valAddrs = validatorListPower(bondedVals) case fxstakingtypes.ValidatorSortByMissed: valAddrs, err = m.ValidatorListMissedBlock(cacheCtx, bondedVals) if err != nil { @@ -69,59 +60,35 @@ func (m *ValidatorListMethod) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, e return m.PackOutput(valAddrs) } -func (m *ValidatorListMethod) ValidatorListPower(bondedVals []stakingtypes.Validator) []string { - valAddrs := make([]string, 0, len(bondedVals)) - for _, val := range bondedVals { - valAddrs = append(valAddrs, val.OperatorAddress) - } - return valAddrs +type ValidatorListABI struct { + abi.Method } -func (m *ValidatorListMethod) ValidatorListMissedBlock(ctx sdk.Context, bondedVals []stakingtypes.Validator) ([]string, error) { - valList := make([]ValidatorList, 0, len(bondedVals)) - for _, val := range bondedVals { - consAddr, err := val.GetConsAddr() - if err != nil { - return nil, err - } - info, err := m.slashingKeeper.GetValidatorSigningInfo(ctx, consAddr) - if err != nil { - return nil, err - } - valList = append(valList, ValidatorList{ - ValAddr: val.OperatorAddress, - MissedBlocks: info.MissedBlocksCounter, - }) - } - sort.Slice(valList, func(i, j int) bool { - return valList[i].MissedBlocks > valList[j].MissedBlocks - }) - valAddrs := make([]string, 0, len(valList)) - for _, l := range valList { - valAddrs = append(valAddrs, l.ValAddr) +func NewValidatorListABI() ValidatorListABI { + return ValidatorListABI{ + Method: stakingABI.Methods["validatorList"], } - return valAddrs, nil } -func (m *ValidatorListMethod) PackInput(args fxstakingtypes.ValidatorListArgs) ([]byte, error) { +func (m ValidatorListABI) PackInput(args fxstakingtypes.ValidatorListArgs) ([]byte, error) { arguments, err := m.Method.Inputs.Pack(args.SortBy) if err != nil { return nil, err } - return append(m.GetMethodId(), arguments...), nil + return append(m.Method.ID, arguments...), nil } -func (m *ValidatorListMethod) UnpackInput(data []byte) (*fxstakingtypes.ValidatorListArgs, error) { +func (m ValidatorListABI) UnpackInput(data []byte) (*fxstakingtypes.ValidatorListArgs, error) { args := new(fxstakingtypes.ValidatorListArgs) err := types.ParseMethodArgs(m.Method, args, data[4:]) return args, err } -func (m *ValidatorListMethod) PackOutput(valList []string) ([]byte, error) { +func (m ValidatorListABI) PackOutput(valList []string) ([]byte, error) { return m.Method.Outputs.Pack(valList) } -func (m *ValidatorListMethod) UnpackOutput(data []byte) ([]string, error) { +func (m ValidatorListABI) UnpackOutput(data []byte) ([]string, error) { unpack, err := m.Method.Outputs.Unpack(data) if err != nil { return nil, err diff --git a/x/staking/precompile/validator_list_test.go b/x/staking/precompile/validator_list_test.go index fa455d05..d8bac289 100644 --- a/x/staking/precompile/validator_list_test.go +++ b/x/staking/precompile/validator_list_test.go @@ -113,13 +113,13 @@ func (suite *PrecompileTestSuite) TestValidatorList() { } } if args.GetSortBy() == types.ValidatorSortByMissed { - valList := make([]precompile.ValidatorList, 0, len(valsByPower)) + valList := make([]precompile.Validator, 0, len(valsByPower)) for _, validator := range valsByPower { consAddr, err := validator.GetConsAddr() suite.Require().NoError(err) info, err := suite.App.SlashingKeeper.GetValidatorSigningInfo(suite.Ctx, consAddr) suite.Require().NoError(err) - valList = append(valList, precompile.ValidatorList{ + valList = append(valList, precompile.Validator{ ValAddr: validator.OperatorAddress, MissedBlocks: info.MissedBlocksCounter, }) diff --git a/x/staking/precompile/withdraw.go b/x/staking/precompile/withdraw.go index 6a21908f..a6e0e2aa 100644 --- a/x/staking/precompile/withdraw.go +++ b/x/staking/precompile/withdraw.go @@ -18,15 +18,13 @@ import ( type WithdrawMethod struct { *Keeper - abi.Method - abi.Event + WithdrawABI } func NewWithdrawMethod(keeper *Keeper) *WithdrawMethod { return &WithdrawMethod{ - Keeper: keeper, - Method: stakingABI.Methods["withdraw"], - Event: stakingABI.Events["Withdraw"], + Keeper: keeper, + WithdrawABI: NewWithdrawABI(), } } @@ -76,7 +74,19 @@ func (m *WithdrawMethod) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, error) return result, err } -func (m *WithdrawMethod) NewWithdrawEvent(sender common.Address, validator string, reward *big.Int) (data []byte, topic []common.Hash, err error) { +type WithdrawABI struct { + abi.Method + abi.Event +} + +func NewWithdrawABI() WithdrawABI { + return WithdrawABI{ + Method: stakingABI.Methods["withdraw"], + Event: stakingABI.Events["Withdraw"], + } +} + +func (m WithdrawABI) NewWithdrawEvent(sender common.Address, validator string, reward *big.Int) (data []byte, topic []common.Hash, err error) { data, topic, err = types.PackTopicData(m.Event, []common.Hash{sender.Hash()}, validator, reward) if err != nil { return nil, nil, err @@ -84,25 +94,25 @@ func (m *WithdrawMethod) NewWithdrawEvent(sender common.Address, validator strin return data, topic, nil } -func (m *WithdrawMethod) PackInput(args fxstakingtypes.WithdrawArgs) ([]byte, error) { +func (m WithdrawABI) PackInput(args fxstakingtypes.WithdrawArgs) ([]byte, error) { arguments, err := m.Method.Inputs.Pack(args.Validator) if err != nil { return nil, err } - return append(m.GetMethodId(), arguments...), nil + return append(m.Method.ID, arguments...), nil } -func (m *WithdrawMethod) UnpackInput(data []byte) (*fxstakingtypes.WithdrawArgs, error) { +func (m WithdrawABI) UnpackInput(data []byte) (*fxstakingtypes.WithdrawArgs, error) { args := new(fxstakingtypes.WithdrawArgs) err := types.ParseMethodArgs(m.Method, args, data[4:]) return args, err } -func (m *WithdrawMethod) PackOutput(reward *big.Int) ([]byte, error) { +func (m WithdrawABI) PackOutput(reward *big.Int) ([]byte, error) { return m.Method.Outputs.Pack(reward) } -func (m *WithdrawMethod) UnpackOutput(data []byte) (*big.Int, error) { +func (m WithdrawABI) UnpackOutput(data []byte) (*big.Int, error) { amount, err := m.Method.Outputs.Unpack(data) if err != nil { return nil, err @@ -110,7 +120,7 @@ func (m *WithdrawMethod) UnpackOutput(data []byte) (*big.Int, error) { return amount[0].(*big.Int), nil } -func (m *WithdrawMethod) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingWithdraw, error) { +func (m WithdrawABI) UnpackEvent(log *ethtypes.Log) (*fxcontract.IStakingWithdraw, error) { if log == nil { return nil, errors.New("empty log") }