Skip to content

Commit

Permalink
cleanup and add extra validation
Browse files Browse the repository at this point in the history
  • Loading branch information
thomas-nguy committed Sep 1, 2021
1 parent d2d93b5 commit 0880b6a
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 141 deletions.
146 changes: 146 additions & 0 deletions x/cronos/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ package keeper
import (
"fmt"

"github.com/armon/go-metrics"
"github.com/cosmos/cosmos-sdk/telemetry"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ibctransfertypes "github.com/cosmos/ibc-go/modules/apps/transfer/types"
ibcclienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types"

evmTypes "github.com/tharsis/ethermint/x/evm/types"

paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
Expand Down Expand Up @@ -69,3 +75,143 @@ func NewKeeper(
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
}

func (k Keeper) ConvertVouchersToEvmCoins(ctx sdk.Context, from string, coins sdk.Coins) error {
acc, err := sdk.AccAddressFromBech32(from)
if err != nil {
return err
}

params := k.GetParams(ctx)
evmParams := k.GetEvmParams(ctx)
for _, c := range coins {
switch c.Denom {
case params.IbcCroDenom:
if params.IbcCroDenom == "" {
return sdkerrors.Wrap(types.ErrIbcCroDenomEmpty, "ibc is disabled")
}

// Send ibc tokens to escrow address
err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, acc, types.ModuleName, sdk.NewCoins(c))
if err != nil {
return err
}
// Compute new amount, because basecro is a 8 decimals token, we need to multiply by 10^10 to make it
// a 18 decimals token
amount18dec := sdk.NewCoin(evmParams.EvmDenom, c.Amount.Mul(sdk.NewIntFromBigInt(types.TenPowTen)))

// Mint new evm tokens
if err := k.bankKeeper.MintCoins(
ctx, types.ModuleName, sdk.NewCoins(amount18dec),
); err != nil {
return err
}

// Send evm tokens to receiver
if err := k.bankKeeper.SendCoinsFromModuleToAccount(
ctx, types.ModuleName, acc, sdk.NewCoins(amount18dec),
); err != nil {
return err
}

default:
// TODO handle ERC20 tokens
}
}
defer func() {
for _, a := range coins {
if a.Amount.IsInt64() {
telemetry.SetGaugeWithLabels(
[]string{"tx", "msg", "ConvertVouchersToEvmCoins"},
float32(a.Amount.Int64()),
[]metrics.Label{telemetry.NewLabel("denom", a.Denom)},
)
}
}
}()
return nil
}

func (k Keeper) IbcTransferCoins(ctx sdk.Context, from, destination string, coins sdk.Coins) error {
acc, err := sdk.AccAddressFromBech32(from)
if err != nil {
return err
}

params := k.GetParams(ctx)
evmParams := k.GetEvmParams(ctx)

for _, c := range coins {
switch c.Denom {
case evmParams.EvmDenom:
// Compute the remainder, we won't transfer anything lower than 10^10
amount8decRem := c.Amount.Mod(sdk.NewIntFromBigInt(types.TenPowTen))
amountToBurn := c.Amount.Sub(amount8decRem)
if amountToBurn.IsZero() {
// Amount too small
break
}
coins := sdk.NewCoins(sdk.NewCoin(evmParams.EvmDenom, amountToBurn))

// Send evm tokens to escrow address
err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, acc, types.ModuleName, coins)
if err != nil {
return err
}
// Burns the evm tokens
if err := k.bankKeeper.BurnCoins(
ctx, types.ModuleName, coins); err != nil {
return err
}

// Transfer ibc tokens back to the user
// We divide by 10^10 to come back to an 8decimals token
amount8dec := c.Amount.Quo(sdk.NewIntFromBigInt(types.TenPowTen))
ibcCoin := sdk.NewCoin(params.IbcCroDenom, amount8dec)
if err := k.bankKeeper.SendCoinsFromModuleToAccount(
ctx, types.ModuleName, acc, sdk.NewCoins(ibcCoin),
); err != nil {
return err
}

channelID, err := k.GetSourceChannelID(ctx, params.IbcCroDenom)
if err != nil {
return err
}
// Transfer coins to receiver through IBC
// We use current time for timeout timestamp and zero height for timeoutHeight
// it means it can never fail by timeout
// TODO Might need to consider add timeout option in configuration.
timeoutTimestamp := ctx.BlockTime().UnixNano()
timeoutHeight := ibcclienttypes.ZeroHeight()
err = k.transferKeeper.SendTransfer(
ctx,
ibctransfertypes.PortID,
channelID,
ibcCoin,
acc,
destination,
timeoutHeight,
uint64(timeoutTimestamp))
if err != nil {
return err
}

default:
// TODO handle erc20 tokens
}
}

defer func() {
for _, a := range coins {
if a.Amount.IsInt64() {
telemetry.SetGaugeWithLabels(
[]string{"tx", "msg", "IbcTransferCoins"},
float32(a.Amount.Int64()),
[]metrics.Label{telemetry.NewLabel("denom", a.Denom)},
)
}
}
}()
return nil
}
137 changes: 3 additions & 134 deletions x/cronos/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ package keeper
import (
"context"

"github.com/armon/go-metrics"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ibctransfertypes "github.com/cosmos/ibc-go/modules/apps/transfer/types"
ibcclienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types"
"github.com/crypto-org-chain/cronos/x/cronos/types"
)

Expand All @@ -26,63 +21,14 @@ var _ types.MsgServer = msgServer{}

func (k msgServer) ConvertVouchers(goCtx context.Context, msg *types.MsgConvertVouchers) (*types.MsgConvertResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

acc, err := sdk.AccAddressFromBech32(msg.Address)
err := k.ConvertVouchersToEvmCoins(ctx, msg.Address, msg.Coins)
if err != nil {
return nil, err
}

params := k.GetParams(ctx)
evmParams := k.GetEvmParams(ctx)
for _, c := range msg.Coins {
switch c.Denom {
case params.IbcCroDenom:
if params.IbcCroDenom == "" {
return nil, sdkerrors.Wrap(types.ErrIbcCroDenomEmpty, "ibc is disabled")
}

// Send ibc tokens to escrow address
err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, acc, types.ModuleName, sdk.NewCoins(c))
if err != nil {
return nil, err
}
// Compute new amount, because basecro is a 8 decimals token, we need to multiply by 10^10 to make it
// a 18 decimals token
amount18dec := sdk.NewCoin(evmParams.EvmDenom, c.Amount.Mul(sdk.NewIntFromBigInt(types.TenPowTen)))

// Mint new evm tokens
if err := k.bankKeeper.MintCoins(
ctx, types.ModuleName, sdk.NewCoins(amount18dec),
); err != nil {
return nil, err
}

// Send evm tokens to receiver
if err := k.bankKeeper.SendCoinsFromModuleToAccount(
ctx, types.ModuleName, acc, sdk.NewCoins(amount18dec),
); err != nil {
return nil, err
}

default:
// TODO handle ERC20 tokens
}
}
defer func() {
for _, a := range msg.Coins {
if a.Amount.IsInt64() {
telemetry.SetGaugeWithLabels(
[]string{"tx", "msg", "convertVouchers"},
float32(a.Amount.Int64()),
[]metrics.Label{telemetry.NewLabel("denom", a.Denom)},
)
}
}
}()

// emit events
ctx.EventManager().EmitEvents(sdk.Events{
types.NewConvertVouchersEvent(acc, msg.Coins),
types.NewConvertVouchersEvent(msg.Address, msg.Coins),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
Expand All @@ -94,88 +40,11 @@ func (k msgServer) ConvertVouchers(goCtx context.Context, msg *types.MsgConvertV

func (k msgServer) TransferTokens(goCtx context.Context, msg *types.MsgTransferTokens) (*types.MsgConvertResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

acc, err := sdk.AccAddressFromBech32(msg.From)
err := k.IbcTransferCoins(ctx, msg.From, msg.To, msg.Coins)
if err != nil {
return nil, err
}

params := k.GetParams(ctx)
evmParams := k.GetEvmParams(ctx)

for _, c := range msg.Coins {
switch c.Denom {
case evmParams.EvmDenom:
// Compute the remainder, we won't transfer anything lower than 10^10
amount8decRem := c.Amount.Mod(sdk.NewIntFromBigInt(types.TenPowTen))
amountToBurn := c.Amount.Sub(amount8decRem)
if amountToBurn.IsZero() {
// Amount too small
break
}
coins := sdk.NewCoins(sdk.NewCoin(evmParams.EvmDenom, amountToBurn))

// Send evm tokens to escrow address
err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, acc, types.ModuleName, coins)
if err != nil {
return nil, err
}
// Burns the evm tokens
if err := k.bankKeeper.BurnCoins(
ctx, types.ModuleName, coins); err != nil {
return nil, err
}

// Transfer ibc tokens back to the user
// We divide by 10^10 to come back to an 8decimals token
amount8dec := c.Amount.Quo(sdk.NewIntFromBigInt(types.TenPowTen))
ibcCoin := sdk.NewCoin(params.IbcCroDenom, amount8dec)
if err := k.bankKeeper.SendCoinsFromModuleToAccount(
ctx, types.ModuleName, acc, sdk.NewCoins(ibcCoin),
); err != nil {
return nil, err
}

channelID, err := k.GetSourceChannelID(ctx, params.IbcCroDenom)
if err != nil {
return nil, err
}
// Transfer coins to receiver through IBC
// We use current time for timeout timestamp and zero height for timeoutHeight
// it means it can never fail by timeout
// TODO Might need to consider add timeout option in configuration.
timeoutTimestamp := ctx.BlockTime().UnixNano()
timeoutHeight := ibcclienttypes.ZeroHeight()
err = k.transferKeeper.SendTransfer(
ctx,
ibctransfertypes.PortID,
channelID,
ibcCoin,
acc,
msg.To,
timeoutHeight,
uint64(timeoutTimestamp))
if err != nil {
return nil, err
}

default:
// TODO handle erc20 tokens
}
}

defer func() {
for _, a := range msg.Coins {
if a.Amount.IsInt64() {
telemetry.SetGaugeWithLabels(
[]string{"tx", "msg", "transferTokens"},
float32(a.Amount.Int64()),
[]metrics.Label{telemetry.NewLabel("denom", a.Denom)},
)
}
}
}()

// emit events
ctx.EventManager().EmitEvents(sdk.Events{
types.NewTransferTokensEvent(msg.From, msg.To, msg.Coins),
Expand Down
4 changes: 2 additions & 2 deletions x/cronos/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ const (

// NewConvertVouchersEvent constructs a new voucher convert sdk.Event
// nolint: interfacer
func NewConvertVouchersEvent(sender sdk.AccAddress, amount fmt.Stringer) sdk.Event {
func NewConvertVouchersEvent(sender string, amount fmt.Stringer) sdk.Event {
return sdk.NewEvent(
EventTypeConvertVouchers,
sdk.NewAttribute(AttributeKeySender, sender.String()),
sdk.NewAttribute(AttributeKeySender, sender),
sdk.NewAttribute(sdk.AttributeKeyAmount, amount.String()),
)
}
Expand Down
17 changes: 12 additions & 5 deletions x/cronos/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
"fmt"
"strings"

yaml "gopkg.in/yaml.v2"

Expand All @@ -13,6 +14,8 @@ var (
KeyIbcCroDenom = []byte("IbcCroDenom")
)

const IbcCroDenomDefaultValue = "ibc/6B5A664BF0AF4F71B2F0BAA33141E2F1321242FBD5D19762F541EC971ACB0865"

// ParamKeyTable returns the parameter key table.
func ParamKeyTable() paramtypes.KeyTable {
return paramtypes.NewKeyTable().RegisterParamSet(&Params{})
Expand All @@ -28,13 +31,13 @@ func NewParams(ibcCroDenom string) Params {
// DefaultParams is the default parameter configuration for the cronos module
func DefaultParams() Params {
return Params{
IbcCroDenom: "ibc/6B5A664BF0AF4F71B2F0BAA33141E2F1321242FBD5D19762F541EC971ACB0865",
IbcCroDenom: IbcCroDenomDefaultValue,
}
}

// Validate all cronos module parameters
func (p Params) Validate() error {
return validateIsString(p.IbcCroDenom)
return validateIsIbcDenom(p.IbcCroDenom)
}

// String implements the fmt.Stringer interface
Expand All @@ -46,14 +49,18 @@ func (p Params) String() string {
// ParamSetPairs implements params.ParamSet
func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
return paramtypes.ParamSetPairs{
paramtypes.NewParamSetPair(KeyIbcCroDenom, &p.IbcCroDenom, validateIsString),
paramtypes.NewParamSetPair(KeyIbcCroDenom, &p.IbcCroDenom, validateIsIbcDenom),
}
}

func validateIsString(i interface{}) error {
_, ok := i.(string)
func validateIsIbcDenom(i interface{}) error {
s, ok := i.(string)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}

if s != "" && (!strings.HasPrefix(s, "ibc/") || len(s) != 68) {
return fmt.Errorf("invalid ibc denom: %T", i)
}
return nil
}

0 comments on commit 0880b6a

Please sign in to comment.