Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(audit): resolve more audit findings #217

Merged
merged 12 commits into from
Oct 18, 2024
67 changes: 47 additions & 20 deletions app/ante/cosmos/sigverify.go
Original file line number Diff line number Diff line change
Expand Up @@ -495,26 +495,9 @@ func ConsumeMultisignatureVerificationGas(
meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey,
params types.Params, accSeq uint64,
) error {
size := sig.BitArray.Count()
sigIndex := 0

for i := 0; i < size; i++ {
if !sig.BitArray.GetIndex(i) {
continue
}
sigV2 := signing.SignatureV2{
PubKey: pubkey.GetPubKeys()[i],
Data: sig.Signatures[sigIndex],
Sequence: accSeq,
}
err := DefaultSigVerificationGasConsumer(meter, sigV2, params)
if err != nil {
return err
}
sigIndex++
}

return nil
return ConsumeMultisignatureVerificationGasWithVerifier(
meter, sig, pubkey, params, accSeq, DefaultSigVerificationGasConsumer,
)
}

// GetSignerAcc returns an account for a given address that is expected to sign
Expand Down Expand Up @@ -580,3 +563,47 @@ func signatureDataToBz(data signing.SignatureData) ([][]byte, error) {
return nil, sdkerrors.ErrInvalidType.Wrapf("unexpected signature data type %T", data)
}
}

// ConsumeMultisignatureVerificationGasWithVerifier consumes gas from a GasMeter for verifying
// a multisig pubkey signature. It uses the provided verifier function to verify each signature
// and consume gas accordingly.
func ConsumeMultisignatureVerificationGasWithVerifier(
meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey,
params types.Params, accSeq uint64, verifier authante.SignatureVerificationGasConsumer,
) error {
pubkeys := pubkey.GetPubKeys()
size := sig.BitArray.Count()
if size != len(pubkeys) {
return sdkerrors.ErrInvalidPubKey.Wrap(
"bitarray length doesn't match the number of public keys",
)
}
if len(sig.Signatures) != sig.BitArray.NumTrueBitsBefore(size) {
return sdkerrors.ErrTooManySignatures.Wrap(
"number of signatures doesn't equal the number of true bits in bitarray",
)
}
// we have verified that size == len(pubkeys)
// and that the number of signatures == number of true bits in the bitarray
// so we can safely iterate over the pubkeys and signatures
sigIndex := 0

for i := 0; i < size; i++ {
if !sig.BitArray.GetIndex(i) {
// not signed
continue
}
sigV2 := signing.SignatureV2{
PubKey: pubkeys[i],
Data: sig.Signatures[sigIndex],
Sequence: accSeq,
}
err := verifier(meter, sigV2, params)
if err != nil {
return err
}
sigIndex++
}

return nil
}
35 changes: 4 additions & 31 deletions app/ante/sigverify.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

errorsmod "cosmossdk.io/errors"
cosmosante "github.com/ExocoreNetwork/exocore/app/ante/cosmos"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -64,35 +65,7 @@ func ConsumeMultisignatureVerificationGas(
meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey,
params authtypes.Params, accSeq uint64,
) error {
pubkeys := pubkey.GetPubKeys()
size := sig.BitArray.Count()
if size != len(pubkeys) {
return errorsmod.Wrapf(errortypes.ErrInvalidPubKey, "bitarray length doesn't match the number of public keys")
}
if len(sig.Signatures) != sig.BitArray.NumTrueBitsBefore(size) {
return errorsmod.Wrapf(errortypes.ErrTooManySignatures, "number of signatures exceeds number of bits in bitarray")
}
// we have verified that size == len(pubkeys)
// and that the number of signatures == number of true bits in the bitarray
// so we can safely iterate over the pubkeys and signatures
sigIndex := 0

for i := 0; i < size; i++ {
if !sig.BitArray.GetIndex(i) {
// not signed
continue
}
sigV2 := signing.SignatureV2{
PubKey: pubkeys[i],
Data: sig.Signatures[sigIndex],
Sequence: accSeq,
}
err := SigVerificationGasConsumer(meter, sigV2, params)
if err != nil {
return err
}
sigIndex++
}

return nil
return cosmosante.ConsumeMultisignatureVerificationGasWithVerifier(
meter, sig, pubkey, params, accSeq, SigVerificationGasConsumer,
)
}
2 changes: 1 addition & 1 deletion x/avs/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func (k Keeper) UpdateAVSInfo(ctx sdk.Context, params *types.AVSRegisterOrDeregi

// If avs DeRegisterAction check UnbondingPeriod
// #nosec G115
if epoch.CurrentEpoch-int64(avsInfo.GetInfo().StartingEpoch) > int64(avsInfo.Info.AvsUnbondingPeriod) {
if epoch.CurrentEpoch-int64(avsInfo.GetInfo().StartingEpoch) <= int64(avsInfo.Info.AvsUnbondingPeriod) {
return errorsmod.Wrap(types.ErrUnbondingPeriod, fmt.Sprintf("not qualified to deregister %s", avsInfo))
}

Expand Down
67 changes: 31 additions & 36 deletions x/reward/keeper/claim_reward.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,15 @@ package keeper
import (
"bytes"
"encoding/binary"
"fmt"
"log"
"math/big"
"strings"

errorsmod "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
"github.com/ExocoreNetwork/exocore/x/assets/types"
rtypes "github.com/ExocoreNetwork/exocore/x/reward/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/evmos/evmos/v16/rpc/namespaces/ethereum/eth/filters"
Expand Down Expand Up @@ -83,13 +80,6 @@ func getRewardParamsFromEventLog(log *ethtypes.Log) (*RewardParams, error) {
}, nil
}

func getStakeIDAndAssetID(params *RewardParams) (stakeID string, assetID string) {
clientChainLzIDStr := hexutil.EncodeUint64(params.ClientChainLzID)
stakeID = strings.Join([]string{hexutil.Encode(params.WithdrawRewardAddress), clientChainLzIDStr}, "_")
assetID = strings.Join([]string{hexutil.Encode(params.AssetsAddress), clientChainLzIDStr}, "_")
return
}

func (k Keeper) PostTxProcessing(ctx sdk.Context, _ core.Message, receipt *ethtypes.Receipt) error {
// TODO check if contract address is valid layerZero relayer address
// check if log address and topicId is valid
Expand Down Expand Up @@ -124,33 +114,38 @@ func (k Keeper) PostTxProcessing(ctx sdk.Context, _ core.Message, receipt *ethty
return nil
}

func (k Keeper) RewardForWithdraw(ctx sdk.Context, event *RewardParams) error {
// check event parameter then execute RewardForWithdraw operation
if event.OpAmount.IsNegative() {
return errorsmod.Wrap(rtypes.ErrRewardAmountIsNegative, fmt.Sprintf("the amount is:%s", event.OpAmount))
}
stakeID, assetID := getStakeIDAndAssetID(event)
// check is asset exist
if !k.assetsKeeper.IsStakingAsset(ctx, assetID) {
return errorsmod.Wrap(rtypes.ErrRewardAssetNotExist, fmt.Sprintf("the assetID is:%s", assetID))
}
func (k Keeper) RewardForWithdraw(sdk.Context, *RewardParams) error {
// TODO: rewards aren't yet supported
// it is safe to return an error, since the precompile call will prevent an error
// if err != nil return false
// the false will ensure no unnecessary LZ messages are sent by the gateway
return rtypes.ErrNotSupportYet
// // check event parameter then execute RewardForWithdraw operation
// if event.OpAmount.IsNegative() {
// return errorsmod.Wrap(rtypes.ErrRewardAmountIsNegative, fmt.Sprintf("the amount is:%s", event.OpAmount))
// }
// stakeID, assetID := getStakeIDAndAssetID(event)
// // check is asset exist
// if !k.assetsKeeper.IsStakingAsset(ctx, assetID) {
// return errorsmod.Wrap(rtypes.ErrRewardAssetNotExist, fmt.Sprintf("the assetID is:%s", assetID))
// }

// TODO
changeAmount := types.DeltaStakerSingleAsset{
TotalDepositAmount: event.OpAmount,
WithdrawableAmount: event.OpAmount,
}
// TODO: there should be a reward pool to be transferred from for native tokens' reward, don't update staker-asset-info, just transfer exo-native-token:pool->staker or handled by validators since the reward would be transferred to validators directly.
if assetID != types.ExocoreAssetID {
err := k.assetsKeeper.UpdateStakerAssetState(ctx, stakeID, assetID, changeAmount)
if err != nil {
return err
}
if err = k.assetsKeeper.UpdateStakingAssetTotalAmount(ctx, assetID, event.OpAmount); err != nil {
return err
}
}
return nil
// // TODO verify the reward amount is valid
// changeAmount := types.DeltaStakerSingleAsset{
// TotalDepositAmount: event.OpAmount,
// WithdrawableAmount: event.OpAmount,
// }
// // TODO: there should be a reward pool to be transferred from for native tokens' reward, don't update staker-asset-info, just transfer exo-native-token:pool->staker or handled by validators since the reward would be transferred to validators directly.
// if assetID != types.ExocoreAssetID {
// err := k.assetsKeeper.UpdateStakerAssetState(ctx, stakeID, assetID, changeAmount)
// if err != nil {
// return err
// }
// if err = k.assetsKeeper.UpdateStakingAssetTotalAmount(ctx, assetID, event.OpAmount); err != nil {
// return err
// }
// }
// return nil
}

// WithdrawDelegationRewards is an implementation of a function in the distribution interface.
Expand Down
Loading