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

feat: add MsgBridgeCallClaim to crosschain #192

Merged
merged 1 commit into from
Feb 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ func TestMakeEncodingConfig_RegisterInterfaces(t *testing.T) {
count3++
t.Log(typeURLMap.Key())
}
assert.Equal(t, 262, count3)
assert.Equal(t, 264, count3)

govContent := encodingConfig.InterfaceRegistry.ListImplementations("cosmos.gov.v1beta1.Content")
assert.Equal(t, 14, len(govContent))

msgImplementations := encodingConfig.InterfaceRegistry.ListImplementations(sdk.MsgInterfaceProtoName)
assert.Equal(t, 101, len(msgImplementations))
assert.Equal(t, 102, len(msgImplementations))

type govProposalMsg interface {
GetAuthority() string
Expand Down
21 changes: 21 additions & 0 deletions proto/fx/crosschain/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ service Msg {
rpc BridgeTokenClaim(MsgBridgeTokenClaim) returns (MsgBridgeTokenClaimResponse);

rpc SendToFxClaim(MsgSendToFxClaim) returns (MsgSendToFxClaimResponse);
rpc BridgeCallClaim(MsgBridgeCallClaim) returns (MsgBridgeCallClaimResponse);

rpc SendToExternal(MsgSendToExternal) returns (MsgSendToExternalResponse);
rpc CancelSendToExternal(MsgCancelSendToExternal) returns (MsgCancelSendToExternalResponse);
Expand Down Expand Up @@ -150,6 +151,26 @@ message MsgSendToFxClaim {

message MsgSendToFxClaimResponse {}

message MsgBridgeCallClaim {
string dst_chain_id = 1;
uint64 event_nonce = 2;
string sender = 3;
string receiver = 4;
string asset = 5;
string to = 6;
string message = 7;
string value = 8 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
uint64 gasLimit = 9;
uint64 block_height = 10;
string bridger_address = 11;
string chain_name = 12;
}

message MsgBridgeCallClaimResponse {}

// MsgSendToExternal
// This is the message that a user calls when they want to bridge an asset
// it will later be removed when it is included in a batch and successfully
Expand Down
4 changes: 2 additions & 2 deletions proto/fx/staking/v1beta1/tx.proto
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
syntax = "proto3";
package fx.staking.v1;

import "google/protobuf/any.proto";
import "cosmos_proto/cosmos.proto";
import "google/protobuf/any.proto";

option go_package = "github.com/functionx/fx-core/x/staking/types";

Expand Down Expand Up @@ -30,4 +30,4 @@ message MsgEditConsensusPubKey {
google.protobuf.Any pubkey = 3 [(cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey"];
}

message MsgEditConsensusPubKeyResponse{}
message MsgEditConsensusPubKeyResponse {}
21 changes: 21 additions & 0 deletions types/address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package types

import (
"errors"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/bech32"
"github.com/ethereum/go-ethereum/common"
)

func ParseAddress(addr string) (accAddr sdk.AccAddress, isEvmAddr bool, err error) {
_, bytes, decodeErr := bech32.DecodeAndConvert(addr)
if decodeErr == nil {
return bytes, false, nil
}
ethAddrError := ValidateEthereumAddress(addr)
if ethAddrError == nil {
return common.HexToAddress(addr).Bytes(), true, nil
}
return nil, false, errors.Join(decodeErr, ethAddrError)
}
8 changes: 8 additions & 0 deletions x/crosschain/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,14 @@ func (s MsgServer) SendToFxClaim(c context.Context, msg *types.MsgSendToFxClaim)
return &types.MsgSendToFxClaimResponse{}, nil
}

func (s MsgServer) BridgeCallClaim(c context.Context, msg *types.MsgBridgeCallClaim) (*types.MsgBridgeCallClaimResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
if err := s.claimHandlerCommon(ctx, msg); err != nil {
return nil, err
}
return &types.MsgBridgeCallClaimResponse{}, nil
}

func (s MsgServer) BridgeTokenClaim(c context.Context, msg *types.MsgBridgeTokenClaim) (*types.MsgBridgeTokenClaimResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
if err := s.claimHandlerCommon(ctx, msg); err != nil {
Expand Down
8 changes: 8 additions & 0 deletions x/crosschain/keeper/msg_server_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ func (k msgServer) SendToFxClaim(ctx context.Context, msg *types.MsgSendToFxClai
}
}

func (k msgServer) BridgeCallClaim(ctx context.Context, msg *types.MsgBridgeCallClaim) (*types.MsgBridgeCallClaimResponse, error) {
if queryServer, err := k.getMsgServerByChainName(msg.GetChainName()); err != nil {
return nil, err
} else {
return queryServer.BridgeCallClaim(ctx, msg)
}
}

func (k msgServer) SendToExternal(ctx context.Context, msg *types.MsgSendToExternal) (*types.MsgSendToExternalResponse, error) {
if queryServer, err := k.getMsgServerByChainName(msg.GetChainName()); err != nil {
return nil, err
Expand Down
58 changes: 58 additions & 0 deletions x/crosschain/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1095,3 +1095,61 @@ func (suite *KeeperTestSuite) TestMsgUpdateChainOracles() {
_, err = suite.MsgServer().UpdateChainOracles(suite.ctx, updateOracle)
require.Error(suite.T(), err)
}

func (suite *KeeperTestSuite) TestBridgeCallClaim() {
normalMsg := &types.MsgBondedOracle{
OracleAddress: suite.oracleAddrs[0].String(),
BridgerAddress: suite.bridgerAddrs[0].String(),
ExternalAddress: suite.PubKeyToExternalAddr(suite.externalPris[0].PublicKey),
ValidatorAddress: suite.valAddrs[0].String(),
DelegateAmount: types.NewDelegateAmount(sdkmath.NewInt((tmrand.Int63n(5) + 1) * 10_000).MulRaw(1e18)),
ChainName: suite.chainName,
}
_, err := suite.MsgServer().BondedOracle(sdk.WrapSDKContext(suite.ctx), normalMsg)
require.NoError(suite.T(), err)

oracleLastEventNonce := suite.Keeper().GetLastEventNonceByOracle(suite.ctx, suite.oracleAddrs[0])
require.EqualValues(suite.T(), 0, oracleLastEventNonce)

sender := helpers.GenerateAddress().String()
if suite.chainName == trontypes.ModuleName {
sender = trontypes.AddressFromHex(sender)
}

testMsgs := []struct {
name string
msg *types.MsgBridgeCallClaim
err error
errReason string
}{
{
name: "success",
msg: &types.MsgBridgeCallClaim{
DstChainId: "123",
EventNonce: oracleLastEventNonce + 1,
Sender: sender,
Asset: "123",
Receiver: helpers.GenerateAddress().String(),
To: helpers.GenerateAddress().String(),
Message: "123",
Value: sdkmath.NewInt(0),
BlockHeight: 1,
BridgerAddress: suite.bridgerAddrs[0].String(),
ChainName: suite.chainName,
},
err: nil,
errReason: "",
},
}

for _, testData := range testMsgs {
err = testData.msg.ValidateBasic()
require.NoError(suite.T(), err)
_, err = suite.MsgServer().BridgeCallClaim(sdk.WrapSDKContext(suite.ctx), testData.msg)
require.ErrorIs(suite.T(), err, testData.err, testData.name)
if err == nil {
continue
}
require.EqualValues(suite.T(), testData.errReason, err.Error(), testData.name)
}
}
3 changes: 3 additions & 0 deletions x/crosschain/types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
&MsgBridgeTokenClaim{},

&MsgSendToFxClaim{},
&MsgBridgeCallClaim{},

&MsgSendToExternal{},
&MsgCancelSendToExternal{},
Expand All @@ -58,6 +59,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
(*ExternalClaim)(nil),
&MsgSendToExternalClaim{},
&MsgSendToFxClaim{},
&MsgBridgeCallClaim{},
&MsgBridgeTokenClaim{},
&MsgOracleSetUpdatedClaim{},
)
Expand Down Expand Up @@ -87,6 +89,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
cdc.RegisterConcrete(&MsgBridgeTokenClaim{}, fmt.Sprintf("%s/%s", ModuleName, "MsgBridgeTokenClaim"), nil)

cdc.RegisterConcrete(&MsgSendToFxClaim{}, fmt.Sprintf("%s/%s", ModuleName, "MsgSendToFxClaim"), nil)
cdc.RegisterConcrete(&MsgBridgeCallClaim{}, fmt.Sprintf("%s/%s", ModuleName, "MsgBridgeCallClaim"), nil)

cdc.RegisterConcrete(&MsgSendToExternal{}, fmt.Sprintf("%s/%s", ModuleName, "MsgSendToExternal"), nil)
cdc.RegisterConcrete(&MsgCancelSendToExternal{}, fmt.Sprintf("%s/%s", ModuleName, "MsgCancelSendToExternal"), nil)
Expand Down
28 changes: 28 additions & 0 deletions x/crosschain/types/msg_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,34 @@ func (b MsgValidate) MsgSendToFxClaimValidate(m *MsgSendToFxClaim) (err error) {
return nil
}

func (b MsgValidate) MsgBridgeCallClaimValidate(m *MsgBridgeCallClaim) (err error) {
if _, err = sdk.AccAddressFromBech32(m.BridgerAddress); err != nil {
return errortypes.ErrInvalidAddress.Wrapf("invalid bridger address: %s", err)
}
if m.DstChainId == "" {
return errortypes.ErrInvalidRequest.Wrap("empty dst chain id")
}
if err = fxtypes.ValidateEthereumAddress(m.Sender); err != nil {
return errortypes.ErrInvalidAddress.Wrapf("invalid sender address: %s", err)
}
if err = fxtypes.ValidateEthereumAddress(m.To); err != nil {
return errortypes.ErrInvalidAddress.Wrapf("invalid to contract: %s", err)
}
if _, _, err := fxtypes.ParseAddress(m.Receiver); err != nil {
return errortypes.ErrInvalidAddress.Wrapf("invalid receiver address: %s", err)
}
if m.Value.IsNil() || m.Value.IsNegative() {
return errortypes.ErrInvalidRequest.Wrap("invalid value")
}
if m.EventNonce == 0 {
return errortypes.ErrInvalidRequest.Wrap("zero event nonce")
}
if m.BlockHeight == 0 {
return errortypes.ErrInvalidRequest.Wrap("zero block height")
}
return nil
}

func (b MsgValidate) MsgSendToExternalValidate(m *MsgSendToExternal) (err error) {
if _, err = sdk.AccAddressFromBech32(m.Sender); err != nil {
return errortypes.ErrInvalidAddress.Wrapf("invalid sender address: %s", err)
Expand Down
52 changes: 51 additions & 1 deletion x/crosschain/types/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ const (

TypeMsgBridgeTokenClaim = "bridge_token_claim"

TypeMsgSendToFxClaim = "send_to_fx_claim"
TypeMsgSendToFxClaim = "send_to_fx_claim"
TypeMsgBridgeCallClaim = "bridge_call_claim"

TypeMsgSendToExternal = "send_to_external"
TypeMsgCancelSendToExternal = "cancel_send_to_external"
Expand Down Expand Up @@ -74,6 +75,8 @@ var (

_ sdk.Msg = &MsgSendToFxClaim{}
_ CrossChainMsg = &MsgSendToFxClaim{}
_ sdk.Msg = &MsgBridgeCallClaim{}
_ CrossChainMsg = &MsgBridgeCallClaim{}

_ sdk.Msg = &MsgSendToExternal{}
_ CrossChainMsg = &MsgSendToExternal{}
Expand Down Expand Up @@ -110,6 +113,7 @@ type MsgValidateBasic interface {
MsgSendToExternalClaimValidate(m *MsgSendToExternalClaim) (err error)

MsgSendToFxClaimValidate(m *MsgSendToFxClaim) (err error)
MsgBridgeCallClaimValidate(m *MsgBridgeCallClaim) (err error)
MsgSendToExternalValidate(m *MsgSendToExternal) (err error)

MsgCancelSendToExternalValidate(m *MsgCancelSendToExternal) (err error)
Expand Down Expand Up @@ -526,6 +530,7 @@ type ExternalClaim interface {

var (
_ ExternalClaim = &MsgSendToFxClaim{}
_ ExternalClaim = &MsgBridgeCallClaim{}
_ ExternalClaim = &MsgBridgeTokenClaim{}
_ ExternalClaim = &MsgSendToExternalClaim{}
_ ExternalClaim = &MsgOracleSetUpdatedClaim{}
Expand Down Expand Up @@ -582,6 +587,51 @@ func (m *MsgSendToFxClaim) ClaimHash() []byte {
return tmhash.Sum([]byte(path))
}

// MsgBridgeCallClaim

// GetType returns the type of the claim
func (m *MsgBridgeCallClaim) GetType() ClaimType {
return CLAIM_TYPE_SEND_TO_FX
}

// ValidateBasic performs stateless checks
func (m *MsgBridgeCallClaim) ValidateBasic() (err error) {
if err = ValidateModuleName(m.ChainName); err != nil {
return errortypes.ErrInvalidRequest.Wrap("invalid chain name")
}
if router, ok := msgValidateBasicRouter[m.ChainName]; !ok {
return errortypes.ErrInvalidRequest.Wrap("unrecognized cross chain name")
} else {
return router.MsgBridgeCallClaimValidate(m)
}
}

// GetSignBytes encodes the message for signing
func (m *MsgBridgeCallClaim) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(m))
}

func (m *MsgBridgeCallClaim) GetClaimer() sdk.AccAddress {
return sdk.MustAccAddressFromBech32(m.BridgerAddress)
}

// GetSigners defines whose signature is required
func (m *MsgBridgeCallClaim) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{sdk.MustAccAddressFromBech32(m.BridgerAddress)}
}

// Type should return the action
func (m *MsgBridgeCallClaim) Type() string { return TypeMsgBridgeCallClaim }

// Route should return the name of the module
func (m *MsgBridgeCallClaim) Route() string { return RouterKey }

// ClaimHash Hash implements BridgeSendToExternal.Hash
func (m *MsgBridgeCallClaim) ClaimHash() []byte {
path := fmt.Sprintf("%d/%d/%s/%s/%s/%s/%s/%s/%s/%d", m.BlockHeight, m.EventNonce, m.DstChainId, m.Sender, m.Receiver, m.To, m.Asset, m.Message, m.Value.String(), m.GasLimit)
return tmhash.Sum([]byte(path))
}

// MsgSendToExternalClaim

// GetType returns the claim type
Expand Down
Loading
Loading