Skip to content

Commit

Permalink
feat: add manual clearing for forwarding accounts (#312)
Browse files Browse the repository at this point in the history
(cherry picked from commit d809e7e)

# Conflicts:
#	x/forwarding/types/tx.pb.go
  • Loading branch information
johnletey authored and mergify[bot] committed Mar 7, 2024
1 parent 8b4848a commit 48769a3
Show file tree
Hide file tree
Showing 7 changed files with 572 additions and 8 deletions.
83 changes: 75 additions & 8 deletions interchaintest/forwarding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"testing"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"
Expand All @@ -24,7 +25,7 @@ import (
func TestForwarding_RegisterOnNoble(t *testing.T) {
t.Parallel()

ctx, wrapper, gaia, sender, receiver := ForwardingSuite(t)
ctx, wrapper, gaia, _, _, sender, receiver := ForwardingSuite(t)
validator := wrapper.chain.Validators[0]

address, exists := ForwardingAccount(t, ctx, validator, receiver)
Expand Down Expand Up @@ -67,7 +68,7 @@ func TestForwarding_RegisterOnNoble(t *testing.T) {
func TestForwarding_RegisterViaTransfer(t *testing.T) {
t.Parallel()

ctx, wrapper, gaia, _, receiver := ForwardingSuite(t)
ctx, wrapper, gaia, _, _, _, receiver := ForwardingSuite(t)
validator := wrapper.chain.Validators[0]

address, exists := ForwardingAccount(t, ctx, validator, receiver)
Expand Down Expand Up @@ -104,10 +105,14 @@ func TestForwarding_RegisterViaTransfer(t *testing.T) {
}.IBCDenom(), sdk.NewInt(100_000))), stats.TotalForwarded)
}

func TestForwarding_RegisterViaPacket(t *testing.T) {
t.Skip()
}

func TestForwarding_FrontRunAccount(t *testing.T) {
t.Parallel()

ctx, wrapper, gaia, sender, receiver := ForwardingSuite(t)
ctx, wrapper, gaia, _, _, sender, receiver := ForwardingSuite(t)
validator := wrapper.chain.Validators[0]

address, exists := ForwardingAccount(t, ctx, validator, receiver)
Expand Down Expand Up @@ -151,8 +156,70 @@ func TestForwarding_FrontRunAccount(t *testing.T) {
require.Equal(t, sdk.NewCoins(sdk.NewCoin("uusdc", sdk.NewInt(1_000_000))), stats.TotalForwarded)
}

func TestForwarding_RegisterViaPacket(t *testing.T) {
t.Skip()
func TestForwarding_ClearAccount(t *testing.T) {
if testing.Short() {
t.Skip()
}
t.Parallel()

ctx, wrapper, gaia, rly, execReporter, sender, receiver := ForwardingSuite(t)
validator := wrapper.chain.Validators[0]

require.NoError(t, rly.StopRelayer(ctx, execReporter))

address, exists := ForwardingAccount(t, ctx, validator, receiver)
require.False(t, exists)

_, err := validator.ExecTx(ctx, sender.KeyName(), "forwarding", "register-account", "channel-0", receiver.FormattedAddress())
require.NoError(t, err)

_, exists = ForwardingAccount(t, ctx, validator, receiver)
require.True(t, exists)

require.NoError(t, validator.SendFunds(ctx, sender.KeyName(), ibc.WalletAmount{
Address: address,
Denom: "uusdc",
Amount: 1_000_000,
}))

time.Sleep(10 * time.Minute)

require.NoError(t, rly.StartRelayer(ctx, execReporter))
require.NoError(t, testutil.WaitForBlocks(ctx, 10, wrapper.chain, gaia))

senderBalance, err := wrapper.chain.AllBalances(ctx, sender.FormattedAddress())
require.NoError(t, err)
require.True(t, senderBalance.IsZero())

balance, err := wrapper.chain.GetBalance(ctx, address, "uusdc")
require.NoError(t, err)
require.Equal(t, int64(1_000_000), balance)

receiverBalance, err := gaia.GetBalance(ctx, receiver.FormattedAddress(), transfertypes.DenomTrace{
Path: "transfer/channel-0",
BaseDenom: "uusdc",
}.IBCDenom())
require.NoError(t, err)
require.Equal(t, int64(0), receiverBalance)

_, err = validator.ExecTx(ctx, sender.KeyName(), "forwarding", "clear-account", address)
require.NoError(t, err)
require.NoError(t, testutil.WaitForBlocks(ctx, 10, wrapper.chain, gaia))

senderBalance, err = wrapper.chain.AllBalances(ctx, sender.FormattedAddress())
require.NoError(t, err)
require.True(t, senderBalance.IsZero())

balance, err = wrapper.chain.GetBalance(ctx, address, "uusdc")
require.NoError(t, err)
require.Equal(t, int64(0), balance)

receiverBalance, err = gaia.GetBalance(ctx, receiver.FormattedAddress(), transfertypes.DenomTrace{
Path: "transfer/channel-0",
BaseDenom: "uusdc",
}.IBCDenom())
require.NoError(t, err)
require.Equal(t, int64(1_000_000), receiverBalance)
}

//
Expand All @@ -177,11 +244,11 @@ func ForwardingStats(t *testing.T, ctx context.Context, validator *cosmos.ChainN
return res
}

func ForwardingSuite(t *testing.T) (ctx context.Context, wrapper genesisWrapper, gaia *cosmos.CosmosChain, sender ibc.Wallet, receiver ibc.Wallet) {
func ForwardingSuite(t *testing.T) (ctx context.Context, wrapper genesisWrapper, gaia *cosmos.CosmosChain, rly *hermes.Relayer, execReporter *testreporter.RelayerExecReporter, sender ibc.Wallet, receiver ibc.Wallet) {
ctx = context.Background()
logger := zaptest.NewLogger(t)
reporter := testreporter.NewNopReporter()
execReporter := reporter.RelayerExecReporter(t)
execReporter = reporter.RelayerExecReporter(t)
client, network := interchaintest.DockerSetup(t)

numValidators, numFullNodes := 1, 0
Expand Down Expand Up @@ -228,7 +295,7 @@ func ForwardingSuite(t *testing.T) (ctx context.Context, wrapper genesisWrapper,
gaia = chains[1].(*cosmos.CosmosChain)
wrapper.chain = noble

rly := interchaintest.NewBuiltinRelayerFactory(
rly = interchaintest.NewBuiltinRelayerFactory(
ibc.Hermes,
logger,
).Build(t, client, network).(*hermes.Relayer)
Expand Down
8 changes: 8 additions & 0 deletions proto/noble/forwarding/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ option go_package = "github.com/noble-assets/noble/v4/x/forwarding/types";

service Msg {
rpc RegisterAccount(noble.forwarding.v1.MsgRegisterAccount) returns (noble.forwarding.v1.MsgRegisterAccountResponse);
rpc ClearAccount(noble.forwarding.v1.MsgClearAccount) returns (noble.forwarding.v1.MsgClearAccountResponse);
}

//
Expand All @@ -19,3 +20,10 @@ message MsgRegisterAccount {
message MsgRegisterAccountResponse {
string address = 1;
}

message MsgClearAccount {
string signer = 1;
string address = 2;
}

message MsgClearAccountResponse {}
25 changes: 25 additions & 0 deletions x/forwarding/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func GetTxCmd() *cobra.Command {
}

cmd.AddCommand(TxRegisterAccount())
cmd.AddCommand(TxClearAccount())

return cmd
}
Expand Down Expand Up @@ -43,3 +44,27 @@ func TxRegisterAccount() *cobra.Command {

return cmd
}

func TxClearAccount() *cobra.Command {
cmd := &cobra.Command{
Use: "clear-account [address]",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

msg := &types.MsgClearAccount{
Signer: clientCtx.GetFromAddress().String(),
Address: args[0],
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}
22 changes: 22 additions & 0 deletions x/forwarding/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,25 @@ func (k *Keeper) RegisterAccount(goCtx context.Context, msg *types.MsgRegisterAc

return &types.MsgRegisterAccountResponse{Address: address.String()}, nil
}

func (k *Keeper) ClearAccount(goCtx context.Context, msg *types.MsgClearAccount) (*types.MsgClearAccountResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
address := sdk.MustAccAddressFromBech32(msg.Address)

rawAccount := k.authKeeper.GetAccount(ctx, address)
if rawAccount == nil {
return nil, errors.New("account does not exist")
}
account, ok := rawAccount.(*types.ForwardingAccount)
if !ok {
return nil, errors.New("account is not a forwarding account")
}

if k.bankKeeper.GetAllBalances(ctx, address).IsZero() {
return nil, errors.New("account does not require clearing")
}

k.SetPendingForward(ctx, account)

return &types.MsgClearAccountResponse{}, nil
}
2 changes: 2 additions & 0 deletions x/forwarding/types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ func init() {

func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
cdc.RegisterConcrete(&MsgRegisterAccount{}, "noble/forwarding/RegisterAccount", nil)
cdc.RegisterConcrete(&MsgClearAccount{}, "noble/forwarding/ClearAccount", nil)
}

func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
registry.RegisterImplementations((*authtypes.AccountI)(nil), &ForwardingAccount{})

registry.RegisterImplementations((*sdk.Msg)(nil), &MsgRegisterAccount{})
registry.RegisterImplementations((*sdk.Msg)(nil), &MsgClearAccount{})
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}
40 changes: 40 additions & 0 deletions x/forwarding/types/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,43 @@ func (msg *MsgRegisterAccount) Route() string {
func (msg *MsgRegisterAccount) Type() string {
return "noble/forwarding/RegisterAccount"
}

//

var _ legacytx.LegacyMsg = &MsgClearAccount{}

func (msg *MsgClearAccount) ValidateBasic() error {
_, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return errors.New("invalid signer")
}

_, err = sdk.AccAddressFromBech32(msg.Address)
if err != nil {
return errors.New("invalid address")
}

return nil
}

func (msg *MsgClearAccount) GetSigners() []sdk.AccAddress {
signer, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
panic(err)
}

return []sdk.AccAddress{signer}
}

func (msg *MsgClearAccount) GetSignBytes() []byte {
bz := ModuleCdc.MustMarshalJSON(msg)
return sdk.MustSortJSON(bz)
}

func (msg *MsgClearAccount) Route() string {
return ModuleName
}

func (msg *MsgClearAccount) Type() string {
return "noble/forwarding/ClearAccount"
}
Loading

0 comments on commit 48769a3

Please sign in to comment.