From dc7194e45556e34afa5f520c2fb60155f62cd5be Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 6 Feb 2024 00:36:56 -0500 Subject: [PATCH 01/50] add cctx status aborted_refundable and aborted_non_refundable --- .../smoketest/smoketests/test_erc20_refund.go | 2 +- .../smoketests/test_message_passing.go | 2 +- .../orchestrator/smoketest/utils/zetacore.go | 2 +- proto/crosschain/cross_chain_tx.proto | 3 +- proto/crosschain/tx.proto | 8 + x/crosschain/keeper/cctx.go | 2 +- x/crosschain/keeper/cctx_test.go | 2 +- .../keeper/msg_server_abort_stuck_cctx.go | 2 +- .../msg_server_abort_stuck_cctx_test.go | 6 +- .../msg_server_add_to_outtx_tracker_test.go | 4 +- .../keeper/msg_server_refund_aborted_tx.go | 11 + .../keeper/msg_server_vote_inbound_tx.go | 10 +- .../keeper/msg_server_vote_inbound_tx_test.go | 4 +- .../keeper/msg_server_vote_outbound_tx.go | 6 +- x/crosschain/migrations/v4/migrate.go | 2 +- x/crosschain/migrations/v4/migrate_test.go | 2 +- x/crosschain/types/cross_chain_tx.pb.go | 170 +++--- x/crosschain/types/status.go | 8 +- x/crosschain/types/tx.pb.go | 562 +++++++++++++++--- 19 files changed, 605 insertions(+), 203 deletions(-) create mode 100644 x/crosschain/keeper/msg_server_refund_aborted_tx.go diff --git a/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go b/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go index 7834baacfa..5a72270dfa 100644 --- a/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go +++ b/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go @@ -32,7 +32,7 @@ func TestERC20DepositAndCallRefund(sm *runner.SmokeTestRunner) { // There is no liquidity pool, therefore the cctx should abort cctx := utils.WaitCctxMinedByInTxHash(sm.Ctx, inTxHash, sm.CctxClient, sm.Logger, sm.CctxTimeout) - if cctx.CctxStatus.Status != types.CctxStatus_Aborted { + if cctx.CctxStatus.Status != types.CctxStatus_Aborted_Refundable { panic(fmt.Sprintf("expected cctx status to be Aborted; got %s", cctx.CctxStatus.Status)) } diff --git a/contrib/localnet/orchestrator/smoketest/smoketests/test_message_passing.go b/contrib/localnet/orchestrator/smoketest/smoketests/test_message_passing.go index 0ca5ae987b..ac3fd49268 100644 --- a/contrib/localnet/orchestrator/smoketest/smoketests/test_message_passing.go +++ b/contrib/localnet/orchestrator/smoketest/smoketests/test_message_passing.go @@ -146,7 +146,7 @@ func TestMessagePassingRevertFail(sm *runner.SmokeTestRunner) { if receipt.Status != 0 { panic("expected revert tx to fail") } - if cctx.CctxStatus.Status != cctxtypes.CctxStatus_Aborted { + if cctx.CctxStatus.Status != cctxtypes.CctxStatus_Aborted_Refundable { panic("expected cctx to be aborted") } } diff --git a/contrib/localnet/orchestrator/smoketest/utils/zetacore.go b/contrib/localnet/orchestrator/smoketest/utils/zetacore.go index 2ec8074354..9f6e022dc7 100644 --- a/contrib/localnet/orchestrator/smoketest/utils/zetacore.go +++ b/contrib/localnet/orchestrator/smoketest/utils/zetacore.go @@ -99,7 +99,7 @@ func WaitCctxsMinedByInTxHash( func IsTerminalStatus(status crosschaintypes.CctxStatus) bool { return status == crosschaintypes.CctxStatus_OutboundMined || - status == crosschaintypes.CctxStatus_Aborted || + status == crosschaintypes.CctxStatus_Aborted_Refundable || status == crosschaintypes.CctxStatus_Reverted } diff --git a/proto/crosschain/cross_chain_tx.proto b/proto/crosschain/cross_chain_tx.proto index 28f9d92452..e2d3582d54 100644 --- a/proto/crosschain/cross_chain_tx.proto +++ b/proto/crosschain/cross_chain_tx.proto @@ -13,7 +13,8 @@ enum CctxStatus { OutboundMined = 3; // the corresponding outbound tx is mined PendingRevert = 4; // outbound cannot succeed; should revert inbound Reverted = 5; // inbound reverted. - Aborted = 6; // inbound tx error or invalid paramters and cannot revert; just abort + Aborted_Refundable = 6; // inbound tx error or invalid paramters and cannot revert; just abort. But the amount can be refunded to zetachain + Aborted_NonRefundable = 7; // inbound tx error or invalid paramters and cannot revert; just abort. The amount cannot be refunded at all } enum TxFinalizationStatus { diff --git a/proto/crosschain/tx.proto b/proto/crosschain/tx.proto index 3ccfba1911..69374a7a31 100644 --- a/proto/crosschain/tx.proto +++ b/proto/crosschain/tx.proto @@ -21,6 +21,7 @@ service Msg { rpc CreateTSSVoter(MsgCreateTSSVoter) returns (MsgCreateTSSVoterResponse); rpc AbortStuckCCTX(MsgAbortStuckCCTX) returns (MsgAbortStuckCCTXResponse); + rpc RefundAbortedCCTX(MsgRefundAbortedCCTX) returns (MsgRefundAbortedCCTXResponse); } message MsgCreateTSSVoter { @@ -162,3 +163,10 @@ message MsgAbortStuckCCTX { } message MsgAbortStuckCCTXResponse {} + +message MsgRefundAbortedCCTX { + string creator = 1; + string cctx_index = 2; +} + +message MsgRefundAbortedCCTXResponse {} diff --git a/x/crosschain/keeper/cctx.go b/x/crosschain/keeper/cctx.go index e3a2a06f71..fee66b2c5e 100644 --- a/x/crosschain/keeper/cctx.go +++ b/x/crosschain/keeper/cctx.go @@ -48,7 +48,7 @@ func (k Keeper) SetCctxAndNonceToCctxAndInTxHashToCctx(ctx sdk.Context, cctx typ Tss: tss.TssPubkey, }) } - if cctx.CctxStatus.Status == types.CctxStatus_Aborted && cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { + if cctx.CctxStatus.Status == types.CctxStatus_Aborted_Refundable && cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { k.AddZetaAbortedAmount(ctx, cctx.GetCurrentOutTxParam().Amount) } } diff --git a/x/crosschain/keeper/cctx_test.go b/x/crosschain/keeper/cctx_test.go index 13218eca13..7ebb5dc4d6 100644 --- a/x/crosschain/keeper/cctx_test.go +++ b/x/crosschain/keeper/cctx_test.go @@ -122,7 +122,7 @@ func TestSends(t *testing.T) { sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.PendingInbound, types.CctxStatus_PendingInbound)...) sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.PendingOutbound, types.CctxStatus_PendingOutbound)...) sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.PendingRevert, types.CctxStatus_PendingRevert)...) - sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.Aborted, types.CctxStatus_Aborted)...) + sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.Aborted, types.CctxStatus_Aborted_Refundable)...) sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.OutboundMined, types.CctxStatus_OutboundMined)...) sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.Reverted, types.CctxStatus_Reverted)...) //assert.Equal(t, tt.PendingOutbound, len(keeper.GetAllCctxByStatuses(ctx, []types.CctxStatus{types.CctxStatus_PendingOutbound}))) diff --git a/x/crosschain/keeper/msg_server_abort_stuck_cctx.go b/x/crosschain/keeper/msg_server_abort_stuck_cctx.go index 32c4bdf55f..df7a59d38e 100644 --- a/x/crosschain/keeper/msg_server_abort_stuck_cctx.go +++ b/x/crosschain/keeper/msg_server_abort_stuck_cctx.go @@ -41,7 +41,7 @@ func (k msgServer) AbortStuckCCTX( } cctx.CctxStatus = &types.Status{ - Status: types.CctxStatus_Aborted, + Status: types.CctxStatus_Aborted_Refundable, StatusMessage: AbortMessage, } diff --git a/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go b/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go index f9b7c380e0..5e9d070b2a 100644 --- a/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go +++ b/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go @@ -35,7 +35,7 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { require.NoError(t, err) cctxFound, found := k.GetCrossChainTx(ctx, "cctx_index") require.True(t, found) - require.Equal(t, crosschaintypes.CctxStatus_Aborted, cctxFound.CctxStatus.Status) + require.Equal(t, crosschaintypes.CctxStatus_Aborted_Refundable, cctxFound.CctxStatus.Status) require.Equal(t, crosschainkeeper.AbortMessage, cctxFound.CctxStatus.StatusMessage) }) @@ -62,7 +62,7 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { require.NoError(t, err) cctxFound, found := k.GetCrossChainTx(ctx, "cctx_index") require.True(t, found) - require.Equal(t, crosschaintypes.CctxStatus_Aborted, cctxFound.CctxStatus.Status) + require.Equal(t, crosschaintypes.CctxStatus_Aborted_Refundable, cctxFound.CctxStatus.Status) require.Equal(t, crosschainkeeper.AbortMessage, cctxFound.CctxStatus.StatusMessage) }) @@ -89,7 +89,7 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { require.NoError(t, err) cctxFound, found := k.GetCrossChainTx(ctx, "cctx_index") require.True(t, found) - require.Equal(t, crosschaintypes.CctxStatus_Aborted, cctxFound.CctxStatus.Status) + require.Equal(t, crosschaintypes.CctxStatus_Aborted_Refundable, cctxFound.CctxStatus.Status) require.Equal(t, crosschainkeeper.AbortMessage, cctxFound.CctxStatus.StatusMessage) }) diff --git a/x/crosschain/keeper/msg_server_add_to_outtx_tracker_test.go b/x/crosschain/keeper/msg_server_add_to_outtx_tracker_test.go index 72820fcffc..dffa896348 100644 --- a/x/crosschain/keeper/msg_server_add_to_outtx_tracker_test.go +++ b/x/crosschain/keeper/msg_server_add_to_outtx_tracker_test.go @@ -283,7 +283,7 @@ func setupTssAndNonceToCctx(k *keeper.Keeper, ctx sdk.Context, chainId, nonce in k.GetObserverKeeper().SetTSS(ctx, observerTypes.TSS{ TssPubkey: tssPubKey, }) - k.SetPendingNonces(ctx, types.PendingNonces{ + k.GetObserverKeeper().SetPendingNonces(ctx, observerTypes.PendingNonces{ Tss: tssPubKey, NonceLow: 0, NonceHigh: 1, @@ -297,7 +297,7 @@ func setupTssAndNonceToCctx(k *keeper.Keeper, ctx sdk.Context, chainId, nonce in }, } k.SetCrossChainTx(ctx, cctx) - k.SetNonceToCctx(ctx, types.NonceToCctx{ + k.GetObserverKeeper().SetNonceToCctx(ctx, observerTypes.NonceToCctx{ ChainId: chainId, Nonce: nonce, CctxIndex: "0x123", diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go new file mode 100644 index 0000000000..b9789d3a8f --- /dev/null +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -0,0 +1,11 @@ +package keeper + +import ( + "github.com/zeta-chain/zetacore/x/crosschain/types" + "golang.org/x/net/context" +) + +func (k msgServer) RefundAbortedTx(goCtx context.Context, msg *types.MsgRefundAbortedCCTX) (*types.MsgRefundAbortedCCTXResponse, error) { + + return &types.MsgRefundAbortedCCTXResponse{}, nil +} diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 57c3e54041..ec55d4cddd 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -142,19 +142,19 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg isContractReverted, err := k.HandleEVMDeposit(tmpCtx, &cctx, *msg, observationChain) if err != nil && !isContractReverted { // exceptional case; internal error; should abort CCTX - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, err.Error()) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } else if err != nil && isContractReverted { // contract call reverted; should refund revertMessage := err.Error() chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundTxParams.SenderChainId) if chain == nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "invalid sender chain") + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, "invalid sender chain") return &types.MsgVoteOnObservedInboundTxResponse{}, nil } gasLimit, err := k.GetRevertGasLimit(ctx, cctx) if err != nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "can't get revert tx gas limit"+err.Error()) + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, "can't get revert tx gas limit"+err.Error()) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } if gasLimit == 0 { @@ -204,7 +204,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg } } - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()+" deposit revert message: "+revertMessage) + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, err.Error()+" deposit revert message: "+revertMessage) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } commit() @@ -234,7 +234,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg }() if err != nil { // do not commit anything here as the CCTX should be aborted - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, err.Error()) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } commit() diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go index 32a0578ed8..b802488751 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -167,7 +167,7 @@ func TestStatus_StatusTransition(t *testing.T) { }, Msg: "Got super majority and finalized Inbound", NonErrStatus: types.CctxStatus_PendingOutbound, - ErrStatus: types.CctxStatus_Aborted, + ErrStatus: types.CctxStatus_Aborted_Refundable, IsErr: false, }, { @@ -179,7 +179,7 @@ func TestStatus_StatusTransition(t *testing.T) { }, Msg: "Got super majority and finalized Inbound", NonErrStatus: types.CctxStatus_OutboundMined, - ErrStatus: types.CctxStatus_Aborted, + ErrStatus: types.CctxStatus_Aborted_Refundable, IsErr: false, }, } diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index 17319d1f8a..f3e43a9e07 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -160,7 +160,7 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms case observerTypes.BallotStatus_BallotFinalized_FailureObservation: if msg.CoinType == common.CoinType_Cmd || common.IsZetaChain(cctx.InboundTxParams.SenderChainId) { // if the cctx is of coin type cmd or the sender chain is zeta chain, then we do not revert, the cctx is aborted - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "") + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, "") } else { switch oldStatus { case types.CctxStatus_PendingOutbound: @@ -200,7 +200,7 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms } cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, "Outbound failed, start revert") case types.CctxStatus_PendingRevert: - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "Outbound failed: revert failed; abort TX") + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, "Outbound failed: revert failed; abort TX") } } newStatus := cctx.CctxStatus.Status.String() @@ -210,7 +210,7 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms }() if err != nil { // do not commit tmpCtx - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, err.Error()) cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed ctx.Logger().Error(err.Error()) // #nosec G701 always in range diff --git a/x/crosschain/migrations/v4/migrate.go b/x/crosschain/migrations/v4/migrate.go index e4b368e44c..4ee36baca0 100644 --- a/x/crosschain/migrations/v4/migrate.go +++ b/x/crosschain/migrations/v4/migrate.go @@ -54,7 +54,7 @@ func SetZetaAccounting( for ; iterator.Valid(); iterator.Next() { var val types.CrossChainTx cdc.MustUnmarshal(iterator.Value(), &val) - if val.CctxStatus.Status == types.CctxStatus_Aborted && val.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { + if val.CctxStatus.Status == types.CctxStatus_Aborted_Refundable && val.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { abortedAmountZeta = abortedAmountZeta.Add(val.GetCurrentOutTxParam().Amount) } } diff --git a/x/crosschain/migrations/v4/migrate_test.go b/x/crosschain/migrations/v4/migrate_test.go index 5ff2f9ee54..a3c484e94a 100644 --- a/x/crosschain/migrations/v4/migrate_test.go +++ b/x/crosschain/migrations/v4/migrate_test.go @@ -168,7 +168,7 @@ func SetRandomCctx(ctx sdk.Context, k keeper.Keeper) sdkmath.Uint { amount := sdkmath.NewUint(uint64(r.Uint32())) k.SetCrossChainTx(ctx, types.CrossChainTx{ Index: fmt.Sprintf("%d", i), - CctxStatus: &types.Status{Status: types.CctxStatus_Aborted}, + CctxStatus: &types.Status{Status: types.CctxStatus_Aborted_Refundable}, OutboundTxParams: []*types.OutboundTxParams{{ Amount: amount, CoinType: common.CoinType_Zeta, diff --git a/x/crosschain/types/cross_chain_tx.pb.go b/x/crosschain/types/cross_chain_tx.pb.go index f74b500a81..0bb09e6a6a 100644 --- a/x/crosschain/types/cross_chain_tx.pb.go +++ b/x/crosschain/types/cross_chain_tx.pb.go @@ -29,12 +29,13 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type CctxStatus int32 const ( - CctxStatus_PendingInbound CctxStatus = 0 - CctxStatus_PendingOutbound CctxStatus = 1 - CctxStatus_OutboundMined CctxStatus = 3 - CctxStatus_PendingRevert CctxStatus = 4 - CctxStatus_Reverted CctxStatus = 5 - CctxStatus_Aborted CctxStatus = 6 + CctxStatus_PendingInbound CctxStatus = 0 + CctxStatus_PendingOutbound CctxStatus = 1 + CctxStatus_OutboundMined CctxStatus = 3 + CctxStatus_PendingRevert CctxStatus = 4 + CctxStatus_Reverted CctxStatus = 5 + CctxStatus_Aborted_Refundable CctxStatus = 6 + CctxStatus_Aborted_NonRefundable CctxStatus = 7 ) var CctxStatus_name = map[int32]string{ @@ -43,16 +44,18 @@ var CctxStatus_name = map[int32]string{ 3: "OutboundMined", 4: "PendingRevert", 5: "Reverted", - 6: "Aborted", + 6: "Aborted_Refundable", + 7: "Aborted_NonRefundable", } var CctxStatus_value = map[string]int32{ - "PendingInbound": 0, - "PendingOutbound": 1, - "OutboundMined": 3, - "PendingRevert": 4, - "Reverted": 5, - "Aborted": 6, + "PendingInbound": 0, + "PendingOutbound": 1, + "OutboundMined": 3, + "PendingRevert": 4, + "Reverted": 5, + "Aborted_Refundable": 6, + "Aborted_NonRefundable": 7, } func (x CctxStatus) String() string { @@ -548,76 +551,77 @@ func init() { func init() { proto.RegisterFile("crosschain/cross_chain_tx.proto", fileDescriptor_af3a0ad055343c21) } var fileDescriptor_af3a0ad055343c21 = []byte{ - // 1100 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcd, 0x6e, 0x1b, 0x37, - 0x10, 0xd6, 0x46, 0x8a, 0x2c, 0x8d, 0x6c, 0x6b, 0x4d, 0xcb, 0xe9, 0xc2, 0x69, 0x24, 0x41, 0x6d, - 0x12, 0x25, 0x80, 0x25, 0xd8, 0x41, 0x11, 0xa0, 0x37, 0xdb, 0xb5, 0x13, 0x23, 0x89, 0x6d, 0x6c, - 0xed, 0x8b, 0x81, 0x62, 0x4b, 0xed, 0xd2, 0x12, 0x11, 0x69, 0xa9, 0x2e, 0x29, 0x43, 0x0e, 0xfa, - 0x10, 0x3d, 0xf4, 0x11, 0x5a, 0xa0, 0x8f, 0x92, 0x43, 0x0f, 0x39, 0x16, 0x3d, 0x18, 0x85, 0x7d, - 0xee, 0xa5, 0x4f, 0x50, 0xf0, 0x67, 0x57, 0x6b, 0xd5, 0x3f, 0xfd, 0x3b, 0xed, 0x70, 0xc8, 0xef, - 0x1b, 0x72, 0xe6, 0x1b, 0x2e, 0xa1, 0xe6, 0x47, 0x8c, 0x73, 0xbf, 0x87, 0x69, 0xd8, 0x56, 0xa6, - 0xa7, 0x6c, 0x4f, 0x8c, 0x5b, 0xc3, 0x88, 0x09, 0x86, 0x1e, 0xbc, 0x23, 0x02, 0x2b, 0x5f, 0x4b, - 0x59, 0x2c, 0x22, 0xad, 0x09, 0x66, 0x79, 0xd1, 0x67, 0x83, 0x01, 0x0b, 0xdb, 0xfa, 0xa3, 0x31, - 0xcb, 0x95, 0x2e, 0xeb, 0x32, 0x65, 0xb6, 0xa5, 0xa5, 0xbd, 0x8d, 0xdf, 0x73, 0x50, 0xde, 0x09, - 0x3b, 0x6c, 0x14, 0x06, 0x07, 0xe3, 0x7d, 0x1c, 0xe1, 0x01, 0x47, 0xf7, 0x20, 0xcf, 0x49, 0x18, - 0x90, 0xc8, 0xb1, 0xea, 0x56, 0xb3, 0xe8, 0x9a, 0x11, 0x7a, 0x04, 0x65, 0x6d, 0x99, 0xed, 0xd0, - 0xc0, 0xb9, 0x53, 0xb7, 0x9a, 0x59, 0x77, 0x4e, 0xbb, 0x37, 0xa5, 0x77, 0x27, 0x40, 0xf7, 0xa1, - 0x28, 0xc6, 0x1e, 0x8b, 0x68, 0x97, 0x86, 0x4e, 0x56, 0x51, 0x14, 0xc4, 0x78, 0x4f, 0x8d, 0xd1, - 0x0a, 0x14, 0x7d, 0x26, 0xcf, 0x72, 0x3a, 0x24, 0x4e, 0xae, 0x6e, 0x35, 0xe7, 0xd7, 0xec, 0x96, - 0xd9, 0xe8, 0x26, 0xa3, 0xe1, 0xc1, 0xe9, 0x90, 0xb8, 0x05, 0xdf, 0x58, 0xa8, 0x02, 0x77, 0x31, - 0xe7, 0x44, 0x38, 0x77, 0x15, 0x8f, 0x1e, 0xa0, 0x17, 0x90, 0xc7, 0x03, 0x36, 0x0a, 0x85, 0x93, - 0x97, 0xee, 0x8d, 0xf6, 0xfb, 0xb3, 0x5a, 0xe6, 0xd7, 0xb3, 0xda, 0xe3, 0x2e, 0x15, 0xbd, 0x51, - 0x47, 0xf2, 0xb5, 0x7d, 0xc6, 0x07, 0x8c, 0x9b, 0xcf, 0x0a, 0x0f, 0xde, 0xb6, 0x65, 0x48, 0xde, - 0x3a, 0xa4, 0xa1, 0x70, 0x0d, 0x1c, 0x3d, 0x07, 0x87, 0xea, 0xd3, 0x7b, 0x72, 0xcb, 0x1d, 0x4e, - 0xa2, 0x13, 0x12, 0x78, 0x3d, 0xcc, 0x7b, 0xce, 0x8c, 0x8a, 0xb8, 0x44, 0xe3, 0xec, 0xec, 0x99, - 0xd9, 0x97, 0x98, 0xf7, 0xd0, 0x6b, 0xf8, 0xe4, 0x2a, 0x20, 0x19, 0x0b, 0x12, 0x85, 0xb8, 0xef, - 0xf5, 0x08, 0xed, 0xf6, 0x84, 0x53, 0xa8, 0x5b, 0xcd, 0x9c, 0x5b, 0xfb, 0x0b, 0xc7, 0x96, 0x59, - 0xf7, 0x52, 0x2d, 0x43, 0x9f, 0xc1, 0x47, 0x29, 0xb6, 0x0e, 0xee, 0xf7, 0x99, 0xf0, 0x68, 0x18, - 0x90, 0xb1, 0x53, 0x54, 0xbb, 0xa8, 0x24, 0x0c, 0x1b, 0x6a, 0x72, 0x47, 0xce, 0xa1, 0x6d, 0xa8, - 0xa7, 0x60, 0xc7, 0x34, 0xc4, 0x7d, 0xfa, 0x8e, 0x04, 0x9e, 0xd4, 0x44, 0xbc, 0x03, 0x50, 0x3b, - 0xf8, 0x38, 0xc1, 0x6f, 0xc7, 0xab, 0x8e, 0x88, 0xc0, 0x26, 0x3c, 0x85, 0x7b, 0x13, 0x3c, 0x16, - 0x94, 0x85, 0x1e, 0x17, 0x58, 0x8c, 0xb8, 0x53, 0x52, 0x05, 0x7a, 0xd6, 0xba, 0x51, 0x6f, 0xad, - 0x84, 0x55, 0x61, 0xbf, 0x54, 0x50, 0xb7, 0x22, 0xae, 0xf0, 0x36, 0xbe, 0x81, 0x79, 0x19, 0x78, - 0xdd, 0xf7, 0x65, 0xfe, 0x69, 0xd8, 0x45, 0x1e, 0x2c, 0xe2, 0x0e, 0x8b, 0x44, 0xbc, 0x6f, 0x53, - 0x58, 0xeb, 0xdf, 0x15, 0x76, 0xc1, 0x70, 0xa9, 0x20, 0x8a, 0xa9, 0xf1, 0xfd, 0x0c, 0xd8, 0x7b, - 0x23, 0x71, 0x59, 0xe3, 0xcb, 0x50, 0x88, 0x88, 0x4f, 0xe8, 0x49, 0xa2, 0xf2, 0x64, 0x8c, 0x9e, - 0x80, 0x1d, 0xdb, 0x5a, 0xe9, 0x3b, 0xb1, 0xd0, 0xcb, 0xb1, 0x3f, 0x96, 0xfa, 0x25, 0x35, 0x67, - 0x6f, 0x55, 0xf3, 0x44, 0xb7, 0xb9, 0xff, 0xa6, 0xdb, 0x55, 0x58, 0x62, 0xe6, 0x48, 0xb2, 0xf4, - 0x82, 0x73, 0x2f, 0x64, 0xa1, 0x4f, 0x54, 0x9b, 0xe4, 0x5c, 0xc4, 0x92, 0xf3, 0x1e, 0x70, 0xbe, - 0x2b, 0x67, 0xa6, 0x21, 0x5d, 0xcc, 0xbd, 0x3e, 0x1d, 0x50, 0xdd, 0x42, 0x97, 0x20, 0x2f, 0x30, - 0x7f, 0x2d, 0x67, 0xae, 0x82, 0x0c, 0x23, 0xea, 0x13, 0xd3, 0x1a, 0x97, 0x21, 0xfb, 0x72, 0x06, - 0x35, 0xc1, 0x4e, 0x43, 0x54, 0x23, 0x15, 0xd4, 0xea, 0xf9, 0xc9, 0x6a, 0xd5, 0x41, 0xcf, 0xc1, - 0x49, 0xaf, 0xbc, 0x42, 0xf4, 0x4b, 0x13, 0x44, 0x5a, 0xf5, 0xbb, 0xf0, 0x69, 0x1a, 0x78, 0x6d, - 0xef, 0x69, 0xe5, 0xd7, 0x27, 0x24, 0xd7, 0x34, 0x5f, 0x1b, 0x2a, 0xd3, 0xa7, 0x1c, 0x71, 0x12, - 0x38, 0x15, 0x85, 0x5f, 0xb8, 0x74, 0xc8, 0x43, 0x4e, 0x02, 0x24, 0xa0, 0x96, 0x06, 0x90, 0xe3, - 0x63, 0xe2, 0x0b, 0x7a, 0x42, 0x52, 0x09, 0x5a, 0x52, 0xe5, 0x6d, 0x99, 0xf2, 0x3e, 0xfa, 0x1b, - 0xe5, 0xdd, 0x09, 0x85, 0x7b, 0x7f, 0x12, 0x6b, 0x2b, 0x26, 0x4d, 0x32, 0xfb, 0xc5, 0x4d, 0x51, - 0x75, 0x25, 0xef, 0xa9, 0x1d, 0x5f, 0xc3, 0xa2, 0x4b, 0xfa, 0x00, 0x40, 0x8a, 0x65, 0x38, 0xea, - 0xbc, 0x25, 0xa7, 0xaa, 0xbd, 0x8b, 0x6e, 0x51, 0x70, 0xbe, 0xaf, 0x1c, 0x37, 0xdc, 0x04, 0xb3, - 0xff, 0xf7, 0x4d, 0xf0, 0xa3, 0x05, 0x79, 0x6d, 0xa2, 0x75, 0xc8, 0x9b, 0x28, 0x96, 0x8a, 0xf2, - 0xe4, 0x96, 0x28, 0x9b, 0xbe, 0x18, 0x1b, 0x6e, 0x03, 0x44, 0x0f, 0x61, 0x5e, 0x5b, 0xde, 0x80, - 0x70, 0x8e, 0xbb, 0x44, 0x75, 0x6c, 0xd1, 0x9d, 0xd3, 0xde, 0x37, 0xda, 0x89, 0x56, 0xa1, 0xd2, - 0xc7, 0x5c, 0x1c, 0x0e, 0x03, 0x2c, 0x88, 0x27, 0xe8, 0x80, 0x70, 0x81, 0x07, 0x43, 0xd5, 0xba, - 0x59, 0x77, 0x71, 0x32, 0x77, 0x10, 0x4f, 0x35, 0x7e, 0xce, 0xc2, 0xec, 0xa6, 0x8c, 0xad, 0x7a, - 0xfe, 0x60, 0x8c, 0x1c, 0x98, 0xf1, 0x23, 0x82, 0x05, 0x8b, 0x6f, 0x8e, 0x78, 0x28, 0x7f, 0x56, - 0x5a, 0xbf, 0x3a, 0xb6, 0x1e, 0xa0, 0xaf, 0xa1, 0xa8, 0x2e, 0xb6, 0x63, 0x42, 0xb8, 0xfe, 0x8d, - 0x6d, 0x6c, 0xfe, 0xc3, 0xbe, 0xff, 0xe3, 0xac, 0x66, 0x9f, 0xe2, 0x41, 0xff, 0xf3, 0x46, 0xc2, - 0xd4, 0x70, 0x0b, 0xd2, 0xde, 0x26, 0x84, 0xa3, 0xc7, 0x50, 0x8e, 0x48, 0x1f, 0x9f, 0x92, 0x20, - 0x39, 0x7d, 0x5e, 0xf7, 0x9c, 0x71, 0xc7, 0xc7, 0xdf, 0x86, 0x92, 0xef, 0x8b, 0x71, 0x5c, 0x53, - 0xd9, 0x98, 0xa5, 0xb5, 0x87, 0xb7, 0x64, 0xdb, 0x64, 0x1a, 0xfc, 0x24, 0xeb, 0xe8, 0x08, 0x16, - 0x52, 0x3f, 0x9e, 0xa1, 0xba, 0x52, 0x55, 0xd3, 0x96, 0xd6, 0x5a, 0xb7, 0xb0, 0x4d, 0x3d, 0x36, - 0xdc, 0x32, 0x9d, 0x7a, 0x7d, 0x7c, 0x05, 0x28, 0xad, 0x73, 0x43, 0x0e, 0xf5, 0x6c, 0xb3, 0xb4, - 0xd6, 0xbe, 0x85, 0x7c, 0xfa, 0x9a, 0x77, 0x6d, 0x36, 0xe5, 0x79, 0xfa, 0x2d, 0xc0, 0x44, 0x3e, - 0x08, 0xc1, 0xfc, 0x3e, 0x09, 0x03, 0x1a, 0x76, 0xcd, 0xbe, 0xec, 0x0c, 0x5a, 0x84, 0xb2, 0xf1, - 0xc5, 0x74, 0xb6, 0x85, 0x16, 0x60, 0x2e, 0x1e, 0xbd, 0xa1, 0x21, 0x09, 0xec, 0xac, 0x74, 0x99, - 0x75, 0x2e, 0x39, 0x21, 0x91, 0xb0, 0x73, 0x68, 0x16, 0x0a, 0xda, 0x26, 0x81, 0x7d, 0x17, 0x95, - 0x60, 0x66, 0x5d, 0xff, 0x8d, 0xec, 0xfc, 0x72, 0xee, 0xa7, 0x1f, 0xaa, 0xd6, 0xd3, 0x57, 0x50, - 0xb9, 0xaa, 0x45, 0x90, 0x0d, 0xb3, 0xbb, 0x4c, 0x24, 0xff, 0x66, 0x3b, 0x83, 0xe6, 0xa0, 0x38, - 0x19, 0x5a, 0x92, 0x79, 0x6b, 0x4c, 0xfc, 0x91, 0x24, 0xbb, 0xa3, 0xc9, 0x36, 0x5e, 0xbd, 0x3f, - 0xaf, 0x5a, 0x1f, 0xce, 0xab, 0xd6, 0x6f, 0xe7, 0x55, 0xeb, 0xbb, 0x8b, 0x6a, 0xe6, 0xc3, 0x45, - 0x35, 0xf3, 0xcb, 0x45, 0x35, 0x73, 0xb4, 0x9a, 0xd2, 0x95, 0xcc, 0xd3, 0x8a, 0x7e, 0x4b, 0xc6, - 0x29, 0x6b, 0x8f, 0xdb, 0xa9, 0x17, 0xa6, 0x92, 0x59, 0x27, 0xaf, 0xde, 0x83, 0xcf, 0xfe, 0x0c, - 0x00, 0x00, 0xff, 0xff, 0xd3, 0x52, 0xba, 0xe1, 0x7c, 0x0a, 0x00, 0x00, + // 1120 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcb, 0x6e, 0x1b, 0x37, + 0x17, 0xd6, 0x44, 0xb2, 0x2c, 0x1d, 0x5f, 0x34, 0xa6, 0x65, 0xff, 0xf3, 0x3b, 0x8d, 0x24, 0xa8, + 0x4d, 0xa2, 0x04, 0xb0, 0x04, 0x3b, 0x28, 0x02, 0x74, 0x67, 0xbb, 0x76, 0x62, 0x24, 0xb1, 0x8d, + 0xa9, 0xbd, 0x31, 0x50, 0x4c, 0xa9, 0x19, 0x5a, 0x22, 0x22, 0x0d, 0xd5, 0x21, 0x65, 0xc8, 0x79, + 0x8a, 0x2e, 0xfa, 0x04, 0x45, 0x0b, 0xf4, 0x51, 0xb2, 0xe8, 0x22, 0xcb, 0xa2, 0x0b, 0xa3, 0xb0, + 0xd7, 0xdd, 0xf4, 0x09, 0x0a, 0x5e, 0x66, 0x34, 0x56, 0x7d, 0xe9, 0x6d, 0x35, 0x87, 0x87, 0xfc, + 0xbe, 0x43, 0x9e, 0xf3, 0x1d, 0x0e, 0xa1, 0xea, 0x47, 0x8c, 0x73, 0xbf, 0x8b, 0x69, 0xd8, 0x52, + 0xa6, 0xa7, 0x6c, 0x4f, 0x8c, 0x9a, 0x83, 0x88, 0x09, 0x86, 0x1e, 0xbc, 0x23, 0x02, 0x2b, 0x5f, + 0x53, 0x59, 0x2c, 0x22, 0xcd, 0x31, 0x66, 0x65, 0xd1, 0x67, 0xfd, 0x3e, 0x0b, 0x5b, 0xfa, 0xa3, + 0x31, 0x2b, 0xe5, 0x0e, 0xeb, 0x30, 0x65, 0xb6, 0xa4, 0xa5, 0xbd, 0xf5, 0xdf, 0x72, 0x50, 0xda, + 0x0d, 0xdb, 0x6c, 0x18, 0x06, 0x87, 0xa3, 0x03, 0x1c, 0xe1, 0x3e, 0x47, 0xcb, 0x90, 0xe7, 0x24, + 0x0c, 0x48, 0xe4, 0x58, 0x35, 0xab, 0x51, 0x74, 0xcd, 0x08, 0x3d, 0x82, 0x92, 0xb6, 0xcc, 0x76, + 0x68, 0xe0, 0xdc, 0xab, 0x59, 0x8d, 0xac, 0x3b, 0xa7, 0xdd, 0x5b, 0xd2, 0xbb, 0x1b, 0xa0, 0xfb, + 0x50, 0x14, 0x23, 0x8f, 0x45, 0xb4, 0x43, 0x43, 0x27, 0xab, 0x28, 0x0a, 0x62, 0xb4, 0xaf, 0xc6, + 0x68, 0x15, 0x8a, 0x3e, 0x93, 0x67, 0x39, 0x1b, 0x10, 0x27, 0x57, 0xb3, 0x1a, 0xf3, 0xeb, 0x76, + 0xd3, 0x6c, 0x74, 0x8b, 0xd1, 0xf0, 0xf0, 0x6c, 0x40, 0xdc, 0x82, 0x6f, 0x2c, 0x54, 0x86, 0x29, + 0xcc, 0x39, 0x11, 0xce, 0x94, 0xe2, 0xd1, 0x03, 0xf4, 0x02, 0xf2, 0xb8, 0xcf, 0x86, 0xa1, 0x70, + 0xf2, 0xd2, 0xbd, 0xd9, 0x7a, 0x7f, 0x5e, 0xcd, 0xfc, 0x72, 0x5e, 0x7d, 0xdc, 0xa1, 0xa2, 0x3b, + 0x6c, 0x4b, 0xbe, 0x96, 0xcf, 0x78, 0x9f, 0x71, 0xf3, 0x59, 0xe5, 0xc1, 0xdb, 0x96, 0x0c, 0xc9, + 0x9b, 0x47, 0x34, 0x14, 0xae, 0x81, 0xa3, 0xe7, 0xe0, 0x50, 0x7d, 0x7a, 0x4f, 0x6e, 0xb9, 0xcd, + 0x49, 0x74, 0x4a, 0x02, 0xaf, 0x8b, 0x79, 0xd7, 0x99, 0x56, 0x11, 0x97, 0x68, 0x9c, 0x9d, 0x7d, + 0x33, 0xfb, 0x12, 0xf3, 0x2e, 0x7a, 0x0d, 0x1f, 0x5f, 0x07, 0x24, 0x23, 0x41, 0xa2, 0x10, 0xf7, + 0xbc, 0x2e, 0xa1, 0x9d, 0xae, 0x70, 0x0a, 0x35, 0xab, 0x91, 0x73, 0xab, 0x7f, 0xe2, 0xd8, 0x36, + 0xeb, 0x5e, 0xaa, 0x65, 0xe8, 0x53, 0xf8, 0x5f, 0x8a, 0xad, 0x8d, 0x7b, 0x3d, 0x26, 0x3c, 0x1a, + 0x06, 0x64, 0xe4, 0x14, 0xd5, 0x2e, 0xca, 0x09, 0xc3, 0xa6, 0x9a, 0xdc, 0x95, 0x73, 0x68, 0x07, + 0x6a, 0x29, 0xd8, 0x09, 0x0d, 0x71, 0x8f, 0xbe, 0x23, 0x81, 0x27, 0x35, 0x11, 0xef, 0x00, 0xd4, + 0x0e, 0x3e, 0x4a, 0xf0, 0x3b, 0xf1, 0xaa, 0x63, 0x22, 0xb0, 0x09, 0x4f, 0x61, 0x79, 0x8c, 0xc7, + 0x82, 0xb2, 0xd0, 0xe3, 0x02, 0x8b, 0x21, 0x77, 0x66, 0x54, 0x81, 0x9e, 0x35, 0x6f, 0xd5, 0x5b, + 0x33, 0x61, 0x55, 0xd8, 0x2f, 0x14, 0xd4, 0x2d, 0x8b, 0x6b, 0xbc, 0xf5, 0xaf, 0x61, 0x5e, 0x06, + 0xde, 0xf0, 0x7d, 0x99, 0x7f, 0x1a, 0x76, 0x90, 0x07, 0x8b, 0xb8, 0xcd, 0x22, 0x11, 0xef, 0xdb, + 0x14, 0xd6, 0xfa, 0x67, 0x85, 0x5d, 0x30, 0x5c, 0x2a, 0x88, 0x62, 0xaa, 0x7f, 0x3b, 0x0d, 0xf6, + 0xfe, 0x50, 0x5c, 0xd5, 0xf8, 0x0a, 0x14, 0x22, 0xe2, 0x13, 0x7a, 0x9a, 0xa8, 0x3c, 0x19, 0xa3, + 0x27, 0x60, 0xc7, 0xb6, 0x56, 0xfa, 0x6e, 0x2c, 0xf4, 0x52, 0xec, 0x8f, 0xa5, 0x7e, 0x45, 0xcd, + 0xd9, 0x3b, 0xd5, 0x3c, 0xd6, 0x6d, 0xee, 0xdf, 0xe9, 0x76, 0x0d, 0x96, 0x98, 0x39, 0x92, 0x2c, + 0xbd, 0xe0, 0xdc, 0x0b, 0x59, 0xe8, 0x13, 0xd5, 0x26, 0x39, 0x17, 0xb1, 0xe4, 0xbc, 0x87, 0x9c, + 0xef, 0xc9, 0x99, 0x49, 0x48, 0x07, 0x73, 0xaf, 0x47, 0xfb, 0x54, 0xb7, 0xd0, 0x15, 0xc8, 0x0b, + 0xcc, 0x5f, 0xcb, 0x99, 0xeb, 0x20, 0x83, 0x88, 0xfa, 0xc4, 0xb4, 0xc6, 0x55, 0xc8, 0x81, 0x9c, + 0x41, 0x0d, 0xb0, 0xd3, 0x10, 0xd5, 0x48, 0x05, 0xb5, 0x7a, 0x7e, 0xbc, 0x5a, 0x75, 0xd0, 0x73, + 0x70, 0xd2, 0x2b, 0xaf, 0x11, 0xfd, 0xd2, 0x18, 0x91, 0x56, 0xfd, 0x1e, 0x7c, 0x92, 0x06, 0xde, + 0xd8, 0x7b, 0x5a, 0xf9, 0xb5, 0x31, 0xc9, 0x0d, 0xcd, 0xd7, 0x82, 0xf2, 0xe4, 0x29, 0x87, 0x9c, + 0x04, 0x4e, 0x59, 0xe1, 0x17, 0xae, 0x1c, 0xf2, 0x88, 0x93, 0x00, 0x09, 0xa8, 0xa6, 0x01, 0xe4, + 0xe4, 0x84, 0xf8, 0x82, 0x9e, 0x92, 0x54, 0x82, 0x96, 0x54, 0x79, 0x9b, 0xa6, 0xbc, 0x8f, 0xfe, + 0x42, 0x79, 0x77, 0x43, 0xe1, 0xde, 0x1f, 0xc7, 0xda, 0x8e, 0x49, 0x93, 0xcc, 0x7e, 0x7e, 0x5b, + 0x54, 0x5d, 0xc9, 0x65, 0xb5, 0xe3, 0x1b, 0x58, 0x74, 0x49, 0x1f, 0x00, 0x48, 0xb1, 0x0c, 0x86, + 0xed, 0xb7, 0xe4, 0x4c, 0xb5, 0x77, 0xd1, 0x2d, 0x0a, 0xce, 0x0f, 0x94, 0xe3, 0x96, 0x9b, 0x60, + 0xf6, 0xbf, 0xbe, 0x09, 0x7e, 0xb0, 0x20, 0xaf, 0x4d, 0xb4, 0x01, 0x79, 0x13, 0xc5, 0x52, 0x51, + 0x9e, 0xdc, 0x11, 0x65, 0xcb, 0x17, 0x23, 0xc3, 0x6d, 0x80, 0xe8, 0x21, 0xcc, 0x6b, 0xcb, 0xeb, + 0x13, 0xce, 0x71, 0x87, 0xa8, 0x8e, 0x2d, 0xba, 0x73, 0xda, 0xfb, 0x46, 0x3b, 0xd1, 0x1a, 0x94, + 0x7b, 0x98, 0x8b, 0xa3, 0x41, 0x80, 0x05, 0xf1, 0x04, 0xed, 0x13, 0x2e, 0x70, 0x7f, 0xa0, 0x5a, + 0x37, 0xeb, 0x2e, 0x8e, 0xe7, 0x0e, 0xe3, 0xa9, 0xfa, 0x4f, 0x59, 0x98, 0xdd, 0x92, 0xb1, 0x55, + 0xcf, 0x1f, 0x8e, 0x90, 0x03, 0xd3, 0x7e, 0x44, 0xb0, 0x60, 0xf1, 0xcd, 0x11, 0x0f, 0xe5, 0xcf, + 0x4a, 0xeb, 0x57, 0xc7, 0xd6, 0x03, 0xf4, 0x15, 0x14, 0xd5, 0xc5, 0x76, 0x42, 0x08, 0xd7, 0xbf, + 0xb1, 0xcd, 0xad, 0xbf, 0xd9, 0xf7, 0xbf, 0x9f, 0x57, 0xed, 0x33, 0xdc, 0xef, 0x7d, 0x56, 0x4f, + 0x98, 0xea, 0x6e, 0x41, 0xda, 0x3b, 0x84, 0x70, 0xf4, 0x18, 0x4a, 0x11, 0xe9, 0xe1, 0x33, 0x12, + 0x24, 0xa7, 0xcf, 0xeb, 0x9e, 0x33, 0xee, 0xf8, 0xf8, 0x3b, 0x30, 0xe3, 0xfb, 0x62, 0x14, 0xd7, + 0x54, 0x36, 0xe6, 0xcc, 0xfa, 0xc3, 0x3b, 0xb2, 0x6d, 0x32, 0x0d, 0x7e, 0x92, 0x75, 0x74, 0x0c, + 0x0b, 0xa9, 0x1f, 0xcf, 0x40, 0x5d, 0xa9, 0xaa, 0x69, 0x67, 0xd6, 0x9b, 0x77, 0xb0, 0x4d, 0x3c, + 0x36, 0xdc, 0x12, 0x9d, 0x78, 0x7d, 0x7c, 0x09, 0x28, 0xad, 0x73, 0x43, 0x0e, 0xb5, 0x6c, 0x63, + 0x66, 0xbd, 0x75, 0x07, 0xf9, 0xe4, 0x35, 0xef, 0xda, 0x6c, 0xc2, 0xf3, 0xf4, 0x3b, 0x0b, 0x60, + 0xac, 0x1f, 0x84, 0x60, 0xfe, 0x80, 0x84, 0x01, 0x0d, 0x3b, 0x66, 0x63, 0x76, 0x06, 0x2d, 0x42, + 0xc9, 0xf8, 0x62, 0x3e, 0xdb, 0x42, 0x0b, 0x30, 0x17, 0x8f, 0xde, 0xd0, 0x90, 0x04, 0x76, 0x56, + 0xba, 0xcc, 0x3a, 0x97, 0x9c, 0x92, 0x48, 0xd8, 0x39, 0x34, 0x0b, 0x05, 0x6d, 0x93, 0xc0, 0x9e, + 0x42, 0xcb, 0x80, 0x36, 0xcc, 0xaf, 0xcd, 0x25, 0x27, 0xc3, 0x30, 0xc0, 0xed, 0x1e, 0xb1, 0xf3, + 0xe8, 0xff, 0xb0, 0x14, 0xfb, 0xf7, 0x58, 0x98, 0x9a, 0x9a, 0x5e, 0xc9, 0xfd, 0xf8, 0x7d, 0xc5, + 0x7a, 0xfa, 0x0a, 0xca, 0xd7, 0x75, 0x12, 0xb2, 0x61, 0x76, 0x8f, 0x89, 0xe4, 0x17, 0x6e, 0x67, + 0xd0, 0x1c, 0x14, 0xc7, 0x43, 0x4b, 0xc6, 0xdf, 0x1e, 0x11, 0x7f, 0x28, 0xe3, 0xdf, 0xd3, 0x64, + 0x9b, 0xaf, 0xde, 0x5f, 0x54, 0xac, 0x0f, 0x17, 0x15, 0xeb, 0xd7, 0x8b, 0x8a, 0xf5, 0xcd, 0x65, + 0x25, 0xf3, 0xe1, 0xb2, 0x92, 0xf9, 0xf9, 0xb2, 0x92, 0x39, 0x5e, 0x4b, 0xc9, 0x4f, 0xa6, 0x73, + 0x55, 0x3f, 0x39, 0xe3, 0xcc, 0xb6, 0x46, 0xad, 0xd4, 0x43, 0x54, 0xa9, 0xb1, 0x9d, 0x57, 0xcf, + 0xc6, 0x67, 0x7f, 0x04, 0x00, 0x00, 0xff, 0xff, 0xbf, 0x44, 0x13, 0xe8, 0xa3, 0x0a, 0x00, 0x00, } func (m *InboundTxParams) Marshal() (dAtA []byte, err error) { diff --git a/x/crosschain/types/status.go b/x/crosschain/types/status.go index 1364e5946c..b4b1149d0a 100644 --- a/x/crosschain/types/status.go +++ b/x/crosschain/types/status.go @@ -11,7 +11,7 @@ func (m *Status) ChangeStatus(newStatus CctxStatus, msg string) { } if !m.ValidateTransition(newStatus) { m.StatusMessage = fmt.Sprintf("Failed to transition : OldStatus %s , NewStatus %s , MSG : %s :", m.Status.String(), newStatus.String(), msg) - m.Status = CctxStatus_Aborted + m.Status = CctxStatus_Aborted_Refundable return } m.Status = newStatus @@ -37,19 +37,19 @@ func stateTransitionMap() map[CctxStatus][]CctxStatus { stateTransitionMap := make(map[CctxStatus][]CctxStatus) stateTransitionMap[CctxStatus_PendingInbound] = []CctxStatus{ CctxStatus_PendingOutbound, - CctxStatus_Aborted, + CctxStatus_Aborted_Refundable, CctxStatus_OutboundMined, // EVM Deposit CctxStatus_PendingRevert, // EVM Deposit contract call reverted; should refund } stateTransitionMap[CctxStatus_PendingOutbound] = []CctxStatus{ - CctxStatus_Aborted, + CctxStatus_Aborted_Refundable, CctxStatus_PendingRevert, CctxStatus_OutboundMined, CctxStatus_Reverted, } stateTransitionMap[CctxStatus_PendingRevert] = []CctxStatus{ - CctxStatus_Aborted, + CctxStatus_Aborted_Refundable, CctxStatus_OutboundMined, CctxStatus_Reverted, } diff --git a/x/crosschain/types/tx.pb.go b/x/crosschain/types/tx.pb.go index c784912394..be52dc057f 100644 --- a/x/crosschain/types/tx.pb.go +++ b/x/crosschain/types/tx.pb.go @@ -1350,6 +1350,94 @@ func (m *MsgAbortStuckCCTXResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgAbortStuckCCTXResponse proto.InternalMessageInfo +type MsgRefundAbortedCCTX struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + CctxIndex string `protobuf:"bytes,2,opt,name=cctx_index,json=cctxIndex,proto3" json:"cctx_index,omitempty"` +} + +func (m *MsgRefundAbortedCCTX) Reset() { *m = MsgRefundAbortedCCTX{} } +func (m *MsgRefundAbortedCCTX) String() string { return proto.CompactTextString(m) } +func (*MsgRefundAbortedCCTX) ProtoMessage() {} +func (*MsgRefundAbortedCCTX) Descriptor() ([]byte, []int) { + return fileDescriptor_81d6d611190b7635, []int{22} +} +func (m *MsgRefundAbortedCCTX) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRefundAbortedCCTX) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRefundAbortedCCTX.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRefundAbortedCCTX) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRefundAbortedCCTX.Merge(m, src) +} +func (m *MsgRefundAbortedCCTX) XXX_Size() int { + return m.Size() +} +func (m *MsgRefundAbortedCCTX) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRefundAbortedCCTX.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRefundAbortedCCTX proto.InternalMessageInfo + +func (m *MsgRefundAbortedCCTX) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgRefundAbortedCCTX) GetCctxIndex() string { + if m != nil { + return m.CctxIndex + } + return "" +} + +type MsgRefundAbortedCCTXResponse struct { +} + +func (m *MsgRefundAbortedCCTXResponse) Reset() { *m = MsgRefundAbortedCCTXResponse{} } +func (m *MsgRefundAbortedCCTXResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRefundAbortedCCTXResponse) ProtoMessage() {} +func (*MsgRefundAbortedCCTXResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_81d6d611190b7635, []int{23} +} +func (m *MsgRefundAbortedCCTXResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRefundAbortedCCTXResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRefundAbortedCCTXResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRefundAbortedCCTXResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRefundAbortedCCTXResponse.Merge(m, src) +} +func (m *MsgRefundAbortedCCTXResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRefundAbortedCCTXResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRefundAbortedCCTXResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRefundAbortedCCTXResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*MsgCreateTSSVoter)(nil), "zetachain.zetacore.crosschain.MsgCreateTSSVoter") proto.RegisterType((*MsgCreateTSSVoterResponse)(nil), "zetachain.zetacore.crosschain.MsgCreateTSSVoterResponse") @@ -1373,103 +1461,107 @@ func init() { proto.RegisterType((*MsgVoteOnObservedInboundTxResponse)(nil), "zetachain.zetacore.crosschain.MsgVoteOnObservedInboundTxResponse") proto.RegisterType((*MsgAbortStuckCCTX)(nil), "zetachain.zetacore.crosschain.MsgAbortStuckCCTX") proto.RegisterType((*MsgAbortStuckCCTXResponse)(nil), "zetachain.zetacore.crosschain.MsgAbortStuckCCTXResponse") + proto.RegisterType((*MsgRefundAbortedCCTX)(nil), "zetachain.zetacore.crosschain.MsgRefundAbortedCCTX") + proto.RegisterType((*MsgRefundAbortedCCTXResponse)(nil), "zetachain.zetacore.crosschain.MsgRefundAbortedCCTXResponse") } func init() { proto.RegisterFile("crosschain/tx.proto", fileDescriptor_81d6d611190b7635) } var fileDescriptor_81d6d611190b7635 = []byte{ - // 1449 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x6d, 0x4f, 0xdb, 0xd6, - 0x17, 0xc7, 0x7f, 0x20, 0x24, 0x07, 0x02, 0xd4, 0xd0, 0x36, 0x35, 0x25, 0x50, 0xf3, 0x6f, 0x87, - 0x26, 0x91, 0xb4, 0x54, 0xd3, 0xda, 0x6e, 0x93, 0x06, 0x51, 0x4b, 0xd9, 0x4a, 0xa9, 0x4c, 0xba, - 0x4d, 0x7d, 0x63, 0x39, 0xf6, 0xc5, 0xb1, 0x88, 0x7d, 0x23, 0xdf, 0x6b, 0x94, 0xa0, 0x49, 0x93, - 0x2a, 0xed, 0xfd, 0x34, 0x4d, 0xda, 0xb4, 0x2f, 0xb0, 0xaf, 0xd2, 0x97, 0xd5, 0x5e, 0xad, 0x9b, - 0x54, 0x4d, 0xed, 0x27, 0xd8, 0x3e, 0xc1, 0x74, 0x1f, 0x6c, 0xe2, 0x40, 0x1e, 0xa0, 0xea, 0xab, - 0xdc, 0x73, 0xee, 0x3d, 0x4f, 0xbf, 0x73, 0xce, 0x3d, 0x37, 0x86, 0x39, 0x3b, 0xc4, 0x84, 0xd8, - 0x75, 0xcb, 0x0b, 0xca, 0xb4, 0x55, 0x6a, 0x86, 0x98, 0x62, 0x75, 0xf1, 0x08, 0x51, 0x8b, 0xf3, - 0x4a, 0x7c, 0x85, 0x43, 0x54, 0x3a, 0x3e, 0xa7, 0xcd, 0xd9, 0xd8, 0xf7, 0x71, 0x50, 0x16, 0x3f, - 0x42, 0x46, 0x9b, 0x77, 0xb1, 0x8b, 0xf9, 0xb2, 0xcc, 0x56, 0x82, 0xab, 0xff, 0xa6, 0xc0, 0x85, - 0x1d, 0xe2, 0x56, 0x42, 0x64, 0x51, 0x54, 0xdd, 0xdb, 0xfb, 0x0a, 0x53, 0x14, 0xaa, 0x05, 0x98, - 0xb0, 0x19, 0x07, 0x87, 0x05, 0x65, 0x59, 0x59, 0xcd, 0x19, 0x31, 0xa9, 0x2e, 0x02, 0x50, 0x42, - 0xcc, 0x66, 0x54, 0x3b, 0x40, 0xed, 0xc2, 0xff, 0xf8, 0x66, 0x8e, 0x12, 0xf2, 0x84, 0x33, 0xd4, - 0x0f, 0x61, 0xf6, 0x00, 0xb5, 0xb7, 0x50, 0xf0, 0x0c, 0x51, 0xeb, 0x21, 0xf2, 0xdc, 0x3a, 0x2d, - 0x8c, 0x2e, 0x2b, 0xab, 0xa3, 0xc6, 0x09, 0xbe, 0xba, 0x06, 0x19, 0x42, 0x2d, 0x1a, 0x91, 0xc2, - 0xd8, 0xb2, 0xb2, 0x3a, 0xbd, 0x7e, 0xb1, 0x24, 0xfd, 0x35, 0x90, 0x8d, 0xbc, 0x43, 0xb4, 0xc7, - 0x37, 0x0d, 0x79, 0x48, 0x5f, 0x80, 0x2b, 0x27, 0x1c, 0x35, 0x10, 0x69, 0xe2, 0x80, 0x20, 0xfd, - 0x47, 0x05, 0xd4, 0x1d, 0xe2, 0xee, 0x78, 0x6e, 0xc8, 0xb6, 0x09, 0x79, 0x10, 0x05, 0x0e, 0xe9, - 0x13, 0xc7, 0x15, 0xc8, 0x72, 0xac, 0x4c, 0xcf, 0xe1, 0x51, 0x8c, 0x1a, 0x13, 0x9c, 0xde, 0x76, - 0xd4, 0x2d, 0xc8, 0x58, 0x3e, 0x8e, 0x02, 0xe1, 0x79, 0x6e, 0xb3, 0xfc, 0xe2, 0xf5, 0xd2, 0xc8, - 0x9f, 0xaf, 0x97, 0x3e, 0x70, 0x3d, 0x5a, 0x8f, 0x6a, 0xcc, 0xcb, 0xb2, 0x8d, 0x89, 0x8f, 0x89, - 0xfc, 0x59, 0x23, 0xce, 0x41, 0x99, 0xb6, 0x9b, 0x88, 0x94, 0x9e, 0x7a, 0x01, 0x35, 0xa4, 0xb8, - 0x7e, 0x15, 0xb4, 0x93, 0x3e, 0x25, 0x2e, 0x3f, 0x86, 0xb9, 0x1d, 0xe2, 0x3e, 0x6d, 0x3a, 0x62, - 0x73, 0xc3, 0x71, 0x42, 0x44, 0xc8, 0xb9, 0xa1, 0xd7, 0x17, 0x61, 0xe1, 0x14, 0x7d, 0x89, 0xb9, - 0x7f, 0x14, 0x6e, 0x6f, 0xc3, 0x71, 0xaa, 0x78, 0x3b, 0xa8, 0xb6, 0xaa, 0xa1, 0x65, 0x1f, 0xf4, - 0x4d, 0x75, 0x1f, 0x88, 0x2e, 0xc3, 0x04, 0x6d, 0x99, 0x75, 0x8b, 0xd4, 0x05, 0x46, 0x46, 0x86, - 0xb6, 0x1e, 0x5a, 0xa4, 0xae, 0xae, 0x41, 0xce, 0xc6, 0x5e, 0x60, 0x32, 0x34, 0x64, 0x5a, 0x67, - 0xe3, 0xb4, 0x56, 0xb0, 0x17, 0x54, 0xdb, 0x4d, 0x64, 0x64, 0x6d, 0xb9, 0x52, 0x57, 0x60, 0xbc, - 0x19, 0x62, 0xbc, 0x5f, 0x18, 0x5f, 0x56, 0x56, 0x27, 0xd7, 0xf3, 0xf1, 0xd1, 0x27, 0x8c, 0x69, - 0x88, 0x3d, 0x16, 0x77, 0xad, 0x81, 0xed, 0x03, 0x61, 0x2f, 0x23, 0xe2, 0xe6, 0x1c, 0x6e, 0xf2, - 0x0a, 0x64, 0x69, 0xcb, 0xf4, 0x02, 0x07, 0xb5, 0x0a, 0x13, 0xc2, 0x4d, 0xda, 0xda, 0x66, 0xa4, - 0x84, 0xa4, 0x3b, 0xe4, 0x04, 0x92, 0xdf, 0x45, 0xed, 0x7f, 0x5d, 0xf7, 0x28, 0x6a, 0x78, 0x84, - 0xde, 0x37, 0x2a, 0xeb, 0x37, 0xfb, 0x00, 0xb2, 0x02, 0x79, 0x14, 0xda, 0xeb, 0x37, 0x4d, 0x4b, - 0x60, 0x2b, 0x73, 0x30, 0xc5, 0x99, 0x71, 0xfe, 0x3a, 0x51, 0x1b, 0x4d, 0xa3, 0xa6, 0xc2, 0x58, - 0x60, 0xf9, 0x02, 0x97, 0x9c, 0xc1, 0xd7, 0xea, 0x25, 0xc8, 0x90, 0xb6, 0x5f, 0xc3, 0x0d, 0x0e, - 0x41, 0xce, 0x90, 0x94, 0xaa, 0x41, 0xd6, 0x41, 0xb6, 0xe7, 0x5b, 0x0d, 0xc2, 0x43, 0xce, 0x1b, - 0x09, 0xad, 0x2e, 0x40, 0xce, 0xb5, 0x88, 0xd9, 0xf0, 0x7c, 0x8f, 0xca, 0x90, 0xb3, 0xae, 0x45, - 0x1e, 0x31, 0x5a, 0x37, 0x79, 0x9b, 0xa4, 0x63, 0x8a, 0x23, 0x66, 0x11, 0x1c, 0xa5, 0x22, 0x10, - 0x11, 0x4e, 0x1d, 0x75, 0x46, 0xb0, 0x08, 0x60, 0xdb, 0x09, 0xa4, 0xb2, 0xce, 0x18, 0x47, 0x80, - 0xfa, 0x4a, 0x81, 0xf9, 0x18, 0xd5, 0xdd, 0x88, 0xbe, 0x63, 0x25, 0xcd, 0xc3, 0x78, 0x80, 0x03, - 0x1b, 0x71, 0xac, 0xc6, 0x0c, 0x41, 0x74, 0xd6, 0xd7, 0x58, 0xaa, 0xbe, 0xde, 0x73, 0xc1, 0x7c, - 0x06, 0x57, 0x4f, 0x0b, 0x2d, 0xc1, 0x6f, 0x11, 0xc0, 0x23, 0x66, 0x88, 0x7c, 0x7c, 0x88, 0x1c, - 0x1e, 0x65, 0xd6, 0xc8, 0x79, 0xc4, 0x10, 0x0c, 0x7d, 0x9f, 0x63, 0x2f, 0xa8, 0x07, 0x21, 0xf6, - 0xdf, 0x13, 0x3c, 0xfa, 0x0a, 0x5c, 0xeb, 0x69, 0x27, 0xa9, 0xee, 0x5f, 0x14, 0x98, 0xdd, 0x21, - 0xee, 0x96, 0x45, 0x9e, 0x84, 0x9e, 0x8d, 0x06, 0x5d, 0xec, 0xfd, 0x9d, 0x68, 0x32, 0x15, 0xb1, - 0x13, 0x9c, 0x50, 0xaf, 0xc1, 0x94, 0x40, 0x39, 0x88, 0xfc, 0x1a, 0x0a, 0x79, 0xa2, 0xc6, 0x8c, - 0x49, 0xce, 0x7b, 0xcc, 0x59, 0xbc, 0xb8, 0xa3, 0x66, 0xb3, 0xd1, 0x4e, 0x8a, 0x9b, 0x53, 0xba, - 0x06, 0x85, 0x6e, 0xcf, 0x12, 0xb7, 0x5f, 0x8d, 0xf3, 0xa6, 0x65, 0xcc, 0xdd, 0x60, 0xb7, 0x46, - 0x50, 0x78, 0x88, 0x9c, 0xdd, 0x88, 0xd6, 0x70, 0x14, 0x38, 0xd5, 0x56, 0x9f, 0x08, 0x16, 0x80, - 0x57, 0xa9, 0xc8, 0xba, 0x28, 0xdb, 0x2c, 0x63, 0xf0, 0xa4, 0x97, 0x60, 0x0e, 0x4b, 0x65, 0x26, - 0x66, 0x70, 0x75, 0xde, 0x5e, 0x17, 0xf0, 0xb1, 0x9d, 0xaa, 0x38, 0xff, 0x29, 0x68, 0x5d, 0xe7, - 0x45, 0x01, 0x89, 0x91, 0x26, 0x62, 0x2d, 0xa4, 0xc4, 0x36, 0x8f, 0xf7, 0xd5, 0x8f, 0xe0, 0x72, - 0x97, 0x34, 0x6b, 0xd8, 0x88, 0x20, 0xa7, 0x00, 0x5c, 0x74, 0x3e, 0x25, 0xba, 0x65, 0x91, 0xa7, - 0x04, 0x39, 0xea, 0x11, 0xe8, 0x5d, 0x62, 0x68, 0x7f, 0x1f, 0xd9, 0xd4, 0x3b, 0x44, 0x5c, 0x81, - 0xc8, 0xc2, 0x24, 0x9f, 0x4a, 0x25, 0x39, 0x95, 0x6e, 0x0c, 0x31, 0x95, 0xb6, 0x03, 0x6a, 0x14, - 0x53, 0x16, 0xef, 0xc7, 0x7a, 0xe3, 0x24, 0xa8, 0x5f, 0x0c, 0xb0, 0x2d, 0x6e, 0x9b, 0x29, 0xee, - 0x7d, 0x6f, 0x5d, 0xfc, 0x0e, 0x52, 0x31, 0x4c, 0x1f, 0x5a, 0x8d, 0x08, 0x99, 0xa1, 0x98, 0xe4, - 0x8e, 0xc8, 0xff, 0xe6, 0xc3, 0x33, 0x4e, 0xd2, 0x7f, 0x5f, 0x2f, 0x5d, 0x6c, 0x5b, 0x7e, 0xe3, - 0x9e, 0x9e, 0x56, 0xa7, 0x1b, 0x79, 0xce, 0x90, 0x0f, 0x05, 0xa7, 0xe3, 0x29, 0x91, 0x19, 0xe2, - 0x29, 0xa1, 0x2e, 0xc1, 0xa4, 0x08, 0x91, 0x57, 0xb8, 0xbc, 0x04, 0x80, 0xb3, 0x2a, 0x8c, 0xa3, - 0xde, 0x80, 0x19, 0x71, 0x80, 0x0d, 0x5c, 0xd1, 0x80, 0x59, 0x1e, 0x79, 0x9e, 0xb3, 0xab, 0x84, - 0x3c, 0xe6, 0xf7, 0x54, 0x6a, 0xdc, 0xe5, 0x06, 0x8d, 0x3b, 0xfd, 0x3a, 0xac, 0xf4, 0x29, 0xed, - 0xa4, 0x05, 0x9e, 0x8f, 0xf1, 0x87, 0x43, 0xfa, 0xdc, 0x76, 0x30, 0xb8, 0x03, 0x58, 0xbf, 0xa1, - 0xc0, 0x41, 0xa1, 0x2c, 0x7f, 0x49, 0xb1, 0x70, 0xc4, 0xca, 0xec, 0x1a, 0x4d, 0x79, 0xc1, 0xae, - 0xc8, 0x46, 0xd7, 0x20, 0x2b, 0x21, 0x0e, 0xe5, 0xbd, 0x9b, 0xd0, 0xea, 0x75, 0x98, 0x8e, 0xd7, - 0x12, 0xb6, 0x71, 0xa1, 0x22, 0xe6, 0x0a, 0xe4, 0x8e, 0x1f, 0x4f, 0x99, 0x77, 0x7a, 0x3c, 0xb1, - 0x28, 0x7d, 0x44, 0x88, 0xe5, 0x0a, 0xe8, 0x73, 0x46, 0x4c, 0xaa, 0x57, 0x01, 0x18, 0xe4, 0xb2, - 0x83, 0x73, 0xc2, 0x4f, 0x2f, 0x90, 0x8d, 0x7b, 0x03, 0x66, 0xbc, 0xc0, 0x94, 0xf7, 0xbf, 0xe8, - 0x56, 0xd1, 0x72, 0x79, 0x2f, 0xe8, 0x6c, 0xd1, 0xd4, 0x10, 0x9d, 0xe4, 0x27, 0x92, 0x21, 0x9a, - 0xce, 0xeb, 0xd4, 0xc0, 0x67, 0xcc, 0x02, 0xe4, 0x68, 0xcb, 0xc4, 0xa1, 0xe7, 0x7a, 0x41, 0x21, - 0x2f, 0x1c, 0xa2, 0xad, 0x5d, 0x4e, 0xb3, 0xdb, 0xd3, 0x22, 0x04, 0xd1, 0xc2, 0x34, 0xdf, 0x10, - 0x04, 0x2b, 0x41, 0x74, 0x88, 0x02, 0x2a, 0xe7, 0xd0, 0x0c, 0x77, 0x00, 0x38, 0x4b, 0x8c, 0xa2, - 0xff, 0x83, 0xde, 0xbb, 0x06, 0x92, 0x52, 0x79, 0xc4, 0x5f, 0x30, 0x1b, 0x35, 0x1c, 0xd2, 0x3d, - 0x1a, 0xd9, 0x07, 0x95, 0x4a, 0xf5, 0x9b, 0xfe, 0x4f, 0xc8, 0x7e, 0xa3, 0x5d, 0x3c, 0xb1, 0xd3, - 0xda, 0x62, 0x53, 0xeb, 0x7f, 0x4d, 0xc2, 0xe8, 0x0e, 0x71, 0xd5, 0xef, 0x15, 0xb8, 0x70, 0x72, - 0xf8, 0xdf, 0x2e, 0xf5, 0xfd, 0x4b, 0x52, 0x3a, 0x6d, 0xac, 0x6a, 0x9f, 0x9c, 0x43, 0x28, 0x99, - 0xc5, 0xcf, 0x15, 0x98, 0x3d, 0xf1, 0x9a, 0x5d, 0x1f, 0x52, 0x63, 0x87, 0x8c, 0x76, 0xef, 0xec, - 0x32, 0x89, 0x13, 0x3f, 0x29, 0x70, 0xa9, 0xc7, 0xbc, 0xbf, 0x33, 0x58, 0xed, 0xe9, 0x92, 0xda, - 0xe7, 0xe7, 0x95, 0x4c, 0xdc, 0x6a, 0x43, 0x3e, 0x3d, 0xf7, 0xcb, 0x83, 0x55, 0xa6, 0x04, 0xb4, - 0x8f, 0xcf, 0x28, 0x90, 0x98, 0xfe, 0x55, 0x81, 0x42, 0xcf, 0xe1, 0x3d, 0x04, 0xd4, 0xbd, 0x64, - 0xb5, 0xcd, 0xf3, 0xcb, 0x26, 0xce, 0xfd, 0xac, 0xc0, 0xe5, 0x5e, 0xd7, 0xea, 0xdd, 0xb3, 0xea, - 0x4f, 0x44, 0xb5, 0x8d, 0x73, 0x8b, 0x26, 0x9e, 0x7d, 0x0b, 0xd3, 0x5d, 0xff, 0x43, 0x6e, 0x0e, - 0x56, 0x9a, 0x96, 0xd0, 0xee, 0x9c, 0x55, 0x22, 0xd5, 0x4b, 0x27, 0xfe, 0x89, 0x0e, 0xd1, 0x4b, - 0xdd, 0x32, 0xc3, 0xf4, 0x52, 0xaf, 0x7f, 0xa8, 0xea, 0x77, 0x30, 0xd3, 0xfd, 0xff, 0xfd, 0xd6, - 0x60, 0x75, 0x5d, 0x22, 0xda, 0xdd, 0x33, 0x8b, 0x74, 0xe6, 0xa0, 0xeb, 0x3b, 0xc8, 0x10, 0x39, - 0x48, 0x4b, 0x0c, 0x93, 0x83, 0xd3, 0x3f, 0x61, 0x30, 0xeb, 0x5d, 0xf7, 0xf8, 0x10, 0xd6, 0xd3, - 0x12, 0xc3, 0x58, 0x3f, 0xfd, 0x76, 0xdf, 0xfc, 0xf2, 0xc5, 0x9b, 0xa2, 0xf2, 0xf2, 0x4d, 0x51, - 0xf9, 0xfb, 0x4d, 0x51, 0xf9, 0xe1, 0x6d, 0x71, 0xe4, 0xe5, 0xdb, 0xe2, 0xc8, 0x1f, 0x6f, 0x8b, - 0x23, 0xcf, 0x6e, 0x75, 0x4c, 0x6e, 0xa6, 0x73, 0x4d, 0x7c, 0x8b, 0x8a, 0xd5, 0x97, 0x5b, 0xe5, - 0xce, 0x2f, 0x54, 0x6c, 0x90, 0xd7, 0x32, 0xfc, 0xdb, 0xd2, 0xed, 0xff, 0x02, 0x00, 0x00, 0xff, - 0xff, 0x1e, 0x53, 0x7a, 0xa6, 0xbc, 0x12, 0x00, 0x00, + // 1486 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x5f, 0x4f, 0xdb, 0x56, + 0x14, 0xc7, 0x03, 0x42, 0x72, 0x20, 0x40, 0x0d, 0x6d, 0x53, 0x53, 0x02, 0x35, 0x6b, 0x87, 0x26, + 0x91, 0xb4, 0x54, 0xd3, 0xda, 0x6e, 0x93, 0x06, 0x51, 0x4b, 0xd9, 0x4a, 0xa9, 0x4c, 0xba, 0x4d, + 0x7d, 0xb1, 0x1c, 0xfb, 0xe2, 0x58, 0x24, 0xf7, 0x46, 0xbe, 0xd7, 0x28, 0x41, 0x93, 0x26, 0x55, + 0xda, 0xfb, 0x34, 0x4d, 0xda, 0xb4, 0x2f, 0xb0, 0xaf, 0xd2, 0xc7, 0x6a, 0x4f, 0xeb, 0x1e, 0xaa, + 0xa9, 0x7c, 0x82, 0xed, 0x13, 0x4c, 0xf7, 0x5e, 0xdb, 0xc4, 0x09, 0xf9, 0x03, 0xa8, 0x4f, 0xf1, + 0x39, 0xbe, 0xe7, 0xdf, 0xef, 0x9c, 0x73, 0xcf, 0x89, 0x61, 0xce, 0xf6, 0x09, 0xa5, 0x76, 0xd5, + 0xf2, 0x70, 0x91, 0x35, 0x0b, 0x0d, 0x9f, 0x30, 0xa2, 0x2e, 0x1e, 0x21, 0x66, 0x09, 0x5e, 0x41, + 0x3c, 0x11, 0x1f, 0x15, 0x4e, 0xce, 0x69, 0x73, 0x36, 0xa9, 0xd7, 0x09, 0x2e, 0xca, 0x1f, 0x29, + 0xa3, 0xcd, 0xbb, 0xc4, 0x25, 0xe2, 0xb1, 0xc8, 0x9f, 0x24, 0x57, 0xff, 0x43, 0x81, 0x4b, 0x3b, + 0xd4, 0x2d, 0xf9, 0xc8, 0x62, 0xa8, 0xbc, 0xb7, 0xf7, 0x0d, 0x61, 0xc8, 0x57, 0x73, 0x30, 0x61, + 0x73, 0x0e, 0xf1, 0x73, 0xca, 0xb2, 0xb2, 0x9a, 0x31, 0x22, 0x52, 0x5d, 0x04, 0x60, 0x94, 0x9a, + 0x8d, 0xa0, 0x72, 0x80, 0x5a, 0xb9, 0x0f, 0xc4, 0xcb, 0x0c, 0xa3, 0xf4, 0x99, 0x60, 0xa8, 0x1f, + 0xc3, 0xec, 0x01, 0x6a, 0x6d, 0x21, 0xfc, 0x02, 0x31, 0xeb, 0x31, 0xf2, 0xdc, 0x2a, 0xcb, 0x8d, + 0x2e, 0x2b, 0xab, 0xa3, 0x46, 0x17, 0x5f, 0x5d, 0x83, 0x14, 0x65, 0x16, 0x0b, 0x68, 0x6e, 0x6c, + 0x59, 0x59, 0x9d, 0x5e, 0xbf, 0x5c, 0x08, 0xfd, 0x35, 0x90, 0x8d, 0xbc, 0x43, 0xb4, 0x27, 0x5e, + 0x1a, 0xe1, 0x21, 0x7d, 0x01, 0xae, 0x75, 0x39, 0x6a, 0x20, 0xda, 0x20, 0x98, 0x22, 0xfd, 0x67, + 0x05, 0xd4, 0x1d, 0xea, 0xee, 0x78, 0xae, 0xcf, 0x5f, 0x53, 0xfa, 0x28, 0xc0, 0x0e, 0xed, 0x13, + 0xc7, 0x35, 0x48, 0x0b, 0xac, 0x4c, 0xcf, 0x11, 0x51, 0x8c, 0x1a, 0x13, 0x82, 0xde, 0x76, 0xd4, + 0x2d, 0x48, 0x59, 0x75, 0x12, 0x60, 0xe9, 0x79, 0x66, 0xb3, 0xf8, 0xea, 0xed, 0xd2, 0xc8, 0xdf, + 0x6f, 0x97, 0x3e, 0x72, 0x3d, 0x56, 0x0d, 0x2a, 0xdc, 0xcb, 0xa2, 0x4d, 0x68, 0x9d, 0xd0, 0xf0, + 0x67, 0x8d, 0x3a, 0x07, 0x45, 0xd6, 0x6a, 0x20, 0x5a, 0x78, 0xee, 0x61, 0x66, 0x84, 0xe2, 0xfa, + 0x75, 0xd0, 0xba, 0x7d, 0x8a, 0x5d, 0x7e, 0x0a, 0x73, 0x3b, 0xd4, 0x7d, 0xde, 0x70, 0xe4, 0xcb, + 0x0d, 0xc7, 0xf1, 0x11, 0xa5, 0xe7, 0x86, 0x5e, 0x5f, 0x84, 0x85, 0x53, 0xf4, 0xc5, 0xe6, 0xfe, + 0x55, 0x84, 0xbd, 0x0d, 0xc7, 0x29, 0x93, 0x6d, 0x5c, 0x6e, 0x96, 0x7d, 0xcb, 0x3e, 0xe8, 0x9b, + 0xea, 0x3e, 0x10, 0x5d, 0x85, 0x09, 0xd6, 0x34, 0xab, 0x16, 0xad, 0x4a, 0x8c, 0x8c, 0x14, 0x6b, + 0x3e, 0xb6, 0x68, 0x55, 0x5d, 0x83, 0x8c, 0x4d, 0x3c, 0x6c, 0x72, 0x34, 0xc2, 0xb4, 0xce, 0x46, + 0x69, 0x2d, 0x11, 0x0f, 0x97, 0x5b, 0x0d, 0x64, 0xa4, 0xed, 0xf0, 0x49, 0x5d, 0x81, 0xf1, 0x86, + 0x4f, 0xc8, 0x7e, 0x6e, 0x7c, 0x59, 0x59, 0x9d, 0x5c, 0xcf, 0x46, 0x47, 0x9f, 0x71, 0xa6, 0x21, + 0xdf, 0xf1, 0xb8, 0x2b, 0x35, 0x62, 0x1f, 0x48, 0x7b, 0x29, 0x19, 0xb7, 0xe0, 0x08, 0x93, 0xd7, + 0x20, 0xcd, 0x9a, 0xa6, 0x87, 0x1d, 0xd4, 0xcc, 0x4d, 0x48, 0x37, 0x59, 0x73, 0x9b, 0x93, 0x21, + 0x24, 0x9d, 0x21, 0xc7, 0x90, 0xfc, 0x29, 0x6b, 0xff, 0xdb, 0xaa, 0xc7, 0x50, 0xcd, 0xa3, 0xec, + 0xa1, 0x51, 0x5a, 0xbf, 0xdd, 0x07, 0x90, 0x15, 0xc8, 0x22, 0xdf, 0x5e, 0xbf, 0x6d, 0x5a, 0x12, + 0xdb, 0x30, 0x07, 0x53, 0x82, 0x19, 0xe5, 0xaf, 0x1d, 0xb5, 0xd1, 0x24, 0x6a, 0x2a, 0x8c, 0x61, + 0xab, 0x2e, 0x71, 0xc9, 0x18, 0xe2, 0x59, 0xbd, 0x02, 0x29, 0xda, 0xaa, 0x57, 0x48, 0x4d, 0x40, + 0x90, 0x31, 0x42, 0x4a, 0xd5, 0x20, 0xed, 0x20, 0xdb, 0xab, 0x5b, 0x35, 0x2a, 0x42, 0xce, 0x1a, + 0x31, 0xad, 0x2e, 0x40, 0xc6, 0xb5, 0xa8, 0x59, 0xf3, 0xea, 0x1e, 0x0b, 0x43, 0x4e, 0xbb, 0x16, + 0x7d, 0xc2, 0x69, 0xdd, 0x14, 0x6d, 0x92, 0x8c, 0x29, 0x8a, 0x98, 0x47, 0x70, 0x94, 0x88, 0x40, + 0x46, 0x38, 0x75, 0xd4, 0x1e, 0xc1, 0x22, 0x80, 0x6d, 0xc7, 0x90, 0x86, 0x75, 0xc6, 0x39, 0x12, + 0xd4, 0x37, 0x0a, 0xcc, 0x47, 0xa8, 0xee, 0x06, 0xec, 0x82, 0x95, 0x34, 0x0f, 0xe3, 0x98, 0x60, + 0x1b, 0x09, 0xac, 0xc6, 0x0c, 0x49, 0xb4, 0xd7, 0xd7, 0x58, 0xa2, 0xbe, 0xde, 0x73, 0xc1, 0x7c, + 0x01, 0xd7, 0x4f, 0x0b, 0x2d, 0xc6, 0x6f, 0x11, 0xc0, 0xa3, 0xa6, 0x8f, 0xea, 0xe4, 0x10, 0x39, + 0x22, 0xca, 0xb4, 0x91, 0xf1, 0xa8, 0x21, 0x19, 0xfa, 0xbe, 0xc0, 0x5e, 0x52, 0x8f, 0x7c, 0x52, + 0x7f, 0x4f, 0xf0, 0xe8, 0x2b, 0x70, 0xa3, 0xa7, 0x9d, 0xb8, 0xba, 0x7f, 0x53, 0x60, 0x76, 0x87, + 0xba, 0x5b, 0x16, 0x7d, 0xe6, 0x7b, 0x36, 0x1a, 0x74, 0xb1, 0xf7, 0x77, 0xa2, 0xc1, 0x55, 0x44, + 0x4e, 0x08, 0x42, 0xbd, 0x01, 0x53, 0x12, 0x65, 0x1c, 0xd4, 0x2b, 0xc8, 0x17, 0x89, 0x1a, 0x33, + 0x26, 0x05, 0xef, 0xa9, 0x60, 0x89, 0xe2, 0x0e, 0x1a, 0x8d, 0x5a, 0x2b, 0x2e, 0x6e, 0x41, 0xe9, + 0x1a, 0xe4, 0x3a, 0x3d, 0x8b, 0xdd, 0x7e, 0x33, 0x2e, 0x9a, 0x96, 0x33, 0x77, 0xf1, 0x6e, 0x85, + 0x22, 0xff, 0x10, 0x39, 0xbb, 0x01, 0xab, 0x90, 0x00, 0x3b, 0xe5, 0x66, 0x9f, 0x08, 0x16, 0x40, + 0x54, 0xa9, 0xcc, 0xba, 0x2c, 0xdb, 0x34, 0x67, 0x88, 0xa4, 0x17, 0x60, 0x8e, 0x84, 0xca, 0x4c, + 0xc2, 0xe1, 0x6a, 0xbf, 0xbd, 0x2e, 0x91, 0x13, 0x3b, 0x65, 0x79, 0xfe, 0x73, 0xd0, 0x3a, 0xce, + 0xcb, 0x02, 0x92, 0x23, 0x4d, 0xc6, 0x9a, 0x4b, 0x88, 0x6d, 0x9e, 0xbc, 0x57, 0x3f, 0x81, 0xab, + 0x1d, 0xd2, 0xbc, 0x61, 0x03, 0x8a, 0x9c, 0x1c, 0x08, 0xd1, 0xf9, 0x84, 0xe8, 0x96, 0x45, 0x9f, + 0x53, 0xe4, 0xa8, 0x47, 0xa0, 0x77, 0x88, 0xa1, 0xfd, 0x7d, 0x64, 0x33, 0xef, 0x10, 0x09, 0x05, + 0x32, 0x0b, 0x93, 0x62, 0x2a, 0x15, 0xc2, 0xa9, 0x74, 0x6b, 0x88, 0xa9, 0xb4, 0x8d, 0x99, 0x91, + 0x4f, 0x58, 0x7c, 0x18, 0xe9, 0x8d, 0x92, 0xa0, 0x7e, 0x35, 0xc0, 0xb6, 0xbc, 0x6d, 0xa6, 0x84, + 0xf7, 0xbd, 0x75, 0x89, 0x3b, 0x48, 0x25, 0x30, 0x7d, 0x68, 0xd5, 0x02, 0x64, 0xfa, 0x72, 0x92, + 0x3b, 0x32, 0xff, 0x9b, 0x8f, 0xcf, 0x38, 0x49, 0xff, 0x7b, 0xbb, 0x74, 0xb9, 0x65, 0xd5, 0x6b, + 0x0f, 0xf4, 0xa4, 0x3a, 0xdd, 0xc8, 0x0a, 0x46, 0xb8, 0x28, 0x38, 0x6d, 0xab, 0x44, 0x6a, 0x88, + 0x55, 0x42, 0x5d, 0x82, 0x49, 0x19, 0xa2, 0xa8, 0xf0, 0xf0, 0x12, 0x00, 0xc1, 0x2a, 0x71, 0x8e, + 0x7a, 0x0b, 0x66, 0xe4, 0x01, 0x3e, 0x70, 0x65, 0x03, 0xa6, 0x45, 0xe4, 0x59, 0xc1, 0x2e, 0x53, + 0xfa, 0x54, 0xdc, 0x53, 0x89, 0x71, 0x97, 0x19, 0x34, 0xee, 0xf4, 0x9b, 0xb0, 0xd2, 0xa7, 0xb4, + 0xe3, 0x16, 0x78, 0x39, 0x26, 0x16, 0x87, 0xe4, 0xb9, 0x6d, 0x3c, 0xb8, 0x03, 0x78, 0xbf, 0x21, + 0xec, 0x20, 0x3f, 0x2c, 0xff, 0x90, 0xe2, 0xe1, 0xc8, 0x27, 0xb3, 0x63, 0x34, 0x65, 0x25, 0xbb, + 0x14, 0x36, 0xba, 0x06, 0xe9, 0x10, 0x62, 0x3f, 0xbc, 0x77, 0x63, 0x5a, 0xbd, 0x09, 0xd3, 0xd1, + 0x73, 0x08, 0xdb, 0xb8, 0x54, 0x11, 0x71, 0x25, 0x72, 0x27, 0xcb, 0x53, 0xea, 0x42, 0xcb, 0x13, + 0x8f, 0xb2, 0x8e, 0x28, 0xb5, 0x5c, 0x09, 0x7d, 0xc6, 0x88, 0x48, 0xf5, 0x3a, 0x00, 0x87, 0x3c, + 0xec, 0xe0, 0x8c, 0xf4, 0xd3, 0xc3, 0x61, 0xe3, 0xde, 0x82, 0x19, 0x0f, 0x9b, 0xe1, 0xfd, 0x2f, + 0xbb, 0x55, 0xb6, 0x5c, 0xd6, 0xc3, 0xed, 0x2d, 0x9a, 0x18, 0xa2, 0x93, 0xe2, 0x44, 0x3c, 0x44, + 0x93, 0x79, 0x9d, 0x1a, 0xb8, 0xc6, 0x2c, 0x40, 0x86, 0x35, 0x4d, 0xe2, 0x7b, 0xae, 0x87, 0x73, + 0x59, 0xe9, 0x10, 0x6b, 0xee, 0x0a, 0x9a, 0xdf, 0x9e, 0x16, 0xa5, 0x88, 0xe5, 0xa6, 0xc5, 0x0b, + 0x49, 0xf0, 0x12, 0x44, 0x87, 0x08, 0xb3, 0x70, 0x0e, 0xcd, 0x08, 0x07, 0x40, 0xb0, 0xe4, 0x28, + 0xfa, 0x10, 0xf4, 0xde, 0x35, 0x10, 0x97, 0xca, 0x13, 0xb1, 0xc1, 0x6c, 0x54, 0x88, 0xcf, 0xf6, + 0x58, 0x60, 0x1f, 0x94, 0x4a, 0xe5, 0xef, 0xfa, 0xaf, 0x90, 0xfd, 0x46, 0xbb, 0x5c, 0xb1, 0x93, + 0xda, 0x62, 0x53, 0xbb, 0x62, 0xec, 0x1b, 0x68, 0x3f, 0xc0, 0x8e, 0x38, 0x82, 0x9c, 0x8b, 0x59, + 0xcb, 0x8b, 0x61, 0xdb, 0xa5, 0x30, 0x32, 0xb8, 0x7e, 0x3c, 0x05, 0xa3, 0x3b, 0xd4, 0x55, 0x7f, + 0x54, 0xe0, 0x52, 0xf7, 0xb6, 0x71, 0xb7, 0xd0, 0xf7, 0x3f, 0x50, 0xe1, 0xb4, 0x39, 0xae, 0x7d, + 0x76, 0x0e, 0xa1, 0x78, 0xf8, 0xbf, 0x54, 0x60, 0xb6, 0x6b, 0x7d, 0x5e, 0x1f, 0x52, 0x63, 0x9b, + 0x8c, 0xf6, 0xe0, 0xec, 0x32, 0xb1, 0x13, 0xbf, 0x28, 0x70, 0xa5, 0xc7, 0x82, 0x71, 0x6f, 0xb0, + 0xda, 0xd3, 0x25, 0xb5, 0x2f, 0xcf, 0x2b, 0x19, 0xbb, 0xd5, 0x82, 0x6c, 0x72, 0xd1, 0x28, 0x0e, + 0x56, 0x99, 0x10, 0xd0, 0x3e, 0x3d, 0xa3, 0x40, 0x6c, 0xfa, 0x77, 0x05, 0x72, 0x3d, 0xb7, 0x85, + 0x21, 0xa0, 0xee, 0x25, 0xab, 0x6d, 0x9e, 0x5f, 0x36, 0x76, 0xee, 0x57, 0x05, 0xae, 0xf6, 0xba, + 0xc7, 0xef, 0x9f, 0x55, 0x7f, 0x2c, 0xaa, 0x6d, 0x9c, 0x5b, 0x34, 0xf6, 0xec, 0x7b, 0x98, 0xee, + 0xf8, 0xe3, 0x73, 0x7b, 0xb0, 0xd2, 0xa4, 0x84, 0x76, 0xef, 0xac, 0x12, 0x89, 0x5e, 0xea, 0xfa, + 0xeb, 0x3b, 0x44, 0x2f, 0x75, 0xca, 0x0c, 0xd3, 0x4b, 0xbd, 0xfe, 0x12, 0xab, 0x3f, 0xc0, 0x4c, + 0xe7, 0x07, 0x83, 0x3b, 0x83, 0xd5, 0x75, 0x88, 0x68, 0xf7, 0xcf, 0x2c, 0xd2, 0x9e, 0x83, 0x8e, + 0x0f, 0x2f, 0x43, 0xe4, 0x20, 0x29, 0x31, 0x4c, 0x0e, 0x4e, 0xff, 0x66, 0xc2, 0xad, 0x77, 0x0c, + 0x8e, 0x21, 0xac, 0x27, 0x25, 0x86, 0xb1, 0x7e, 0xfa, 0x38, 0x11, 0xb7, 0x7a, 0xf7, 0x30, 0xb9, + 0x3b, 0xcc, 0x4d, 0xd4, 0x21, 0x34, 0xcc, 0xad, 0xde, 0x73, 0xca, 0x6c, 0x7e, 0xfd, 0xea, 0x5d, + 0x5e, 0x79, 0xfd, 0x2e, 0xaf, 0xfc, 0xf3, 0x2e, 0xaf, 0xfc, 0x74, 0x9c, 0x1f, 0x79, 0x7d, 0x9c, + 0x1f, 0xf9, 0xeb, 0x38, 0x3f, 0xf2, 0xe2, 0x4e, 0xdb, 0xca, 0xc2, 0xd5, 0xae, 0xc9, 0x8f, 0x70, + 0x91, 0x85, 0x62, 0xb3, 0xd8, 0xfe, 0x69, 0x8e, 0x6f, 0x30, 0x95, 0x94, 0xf8, 0xa8, 0x76, 0xf7, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xad, 0xa4, 0x9f, 0x17, 0xb5, 0x13, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1495,6 +1587,7 @@ type MsgClient interface { MigrateTssFunds(ctx context.Context, in *MsgMigrateTssFunds, opts ...grpc.CallOption) (*MsgMigrateTssFundsResponse, error) CreateTSSVoter(ctx context.Context, in *MsgCreateTSSVoter, opts ...grpc.CallOption) (*MsgCreateTSSVoterResponse, error) AbortStuckCCTX(ctx context.Context, in *MsgAbortStuckCCTX, opts ...grpc.CallOption) (*MsgAbortStuckCCTXResponse, error) + RefundAbortedCCTX(ctx context.Context, in *MsgRefundAbortedCCTX, opts ...grpc.CallOption) (*MsgRefundAbortedCCTXResponse, error) } type msgClient struct { @@ -1604,6 +1697,15 @@ func (c *msgClient) AbortStuckCCTX(ctx context.Context, in *MsgAbortStuckCCTX, o return out, nil } +func (c *msgClient) RefundAbortedCCTX(ctx context.Context, in *MsgRefundAbortedCCTX, opts ...grpc.CallOption) (*MsgRefundAbortedCCTXResponse, error) { + out := new(MsgRefundAbortedCCTXResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Msg/RefundAbortedCCTX", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { AddToOutTxTracker(context.Context, *MsgAddToOutTxTracker) (*MsgAddToOutTxTrackerResponse, error) @@ -1617,6 +1719,7 @@ type MsgServer interface { MigrateTssFunds(context.Context, *MsgMigrateTssFunds) (*MsgMigrateTssFundsResponse, error) CreateTSSVoter(context.Context, *MsgCreateTSSVoter) (*MsgCreateTSSVoterResponse, error) AbortStuckCCTX(context.Context, *MsgAbortStuckCCTX) (*MsgAbortStuckCCTXResponse, error) + RefundAbortedCCTX(context.Context, *MsgRefundAbortedCCTX) (*MsgRefundAbortedCCTXResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -1656,6 +1759,9 @@ func (*UnimplementedMsgServer) CreateTSSVoter(ctx context.Context, req *MsgCreat func (*UnimplementedMsgServer) AbortStuckCCTX(ctx context.Context, req *MsgAbortStuckCCTX) (*MsgAbortStuckCCTXResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AbortStuckCCTX not implemented") } +func (*UnimplementedMsgServer) RefundAbortedCCTX(ctx context.Context, req *MsgRefundAbortedCCTX) (*MsgRefundAbortedCCTXResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RefundAbortedCCTX not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -1859,6 +1965,24 @@ func _Msg_AbortStuckCCTX_Handler(srv interface{}, ctx context.Context, dec func( return interceptor(ctx, in, info, handler) } +func _Msg_RefundAbortedCCTX_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRefundAbortedCCTX) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RefundAbortedCCTX(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/zetachain.zetacore.crosschain.Msg/RefundAbortedCCTX", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RefundAbortedCCTX(ctx, req.(*MsgRefundAbortedCCTX)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "zetachain.zetacore.crosschain.Msg", HandlerType: (*MsgServer)(nil), @@ -1907,6 +2031,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "AbortStuckCCTX", Handler: _Msg_AbortStuckCCTX_Handler, }, + { + MethodName: "RefundAbortedCCTX", + Handler: _Msg_RefundAbortedCCTX_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "crosschain/tx.proto", @@ -2866,6 +2994,66 @@ func (m *MsgAbortStuckCCTXResponse) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } +func (m *MsgRefundAbortedCCTX) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRefundAbortedCCTX) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRefundAbortedCCTX) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CctxIndex) > 0 { + i -= len(m.CctxIndex) + copy(dAtA[i:], m.CctxIndex) + i = encodeVarintTx(dAtA, i, uint64(len(m.CctxIndex))) + i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRefundAbortedCCTXResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRefundAbortedCCTXResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRefundAbortedCCTXResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func encodeVarintTx(dAtA []byte, offset int, v uint64) int { offset -= sovTx(v) base := offset @@ -3312,6 +3500,32 @@ func (m *MsgAbortStuckCCTXResponse) Size() (n int) { return n } +func (m *MsgRefundAbortedCCTX) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.CctxIndex) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRefundAbortedCCTXResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func sovTx(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -6240,6 +6454,170 @@ func (m *MsgAbortStuckCCTXResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgRefundAbortedCCTX) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRefundAbortedCCTX: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRefundAbortedCCTX: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CctxIndex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CctxIndex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRefundAbortedCCTXResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRefundAbortedCCTXResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRefundAbortedCCTXResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From 1ab1feef1191a57d8fe277137b331d6c9d8a313e Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 6 Feb 2024 14:16:57 -0500 Subject: [PATCH 02/50] add msg and cli commands --- common/authz_tx_types.go | 1 + testutil/sample/crosschain.go | 3 +- x/crosschain/client/cli/cli_refund_aborted.go | 31 ++++++++++++ x/crosschain/client/cli/tx.go | 1 + x/crosschain/keeper/cctx_utils.go | 30 ++++++++++-- x/crosschain/keeper/cctx_utils_test.go | 41 ++++++++-------- .../keeper/msg_server_refund_aborted_tx.go | 27 +++++++++- .../keeper/msg_server_vote_inbound_tx.go | 2 +- x/crosschain/types/errors.go | 5 ++ x/crosschain/types/message_refund_aborted.go | 49 +++++++++++++++++++ .../types/message_refund_aborted_test.go | 26 ++++++++++ 11 files changed, 189 insertions(+), 27 deletions(-) create mode 100644 x/crosschain/client/cli/cli_refund_aborted.go create mode 100644 x/crosschain/types/message_refund_aborted.go create mode 100644 x/crosschain/types/message_refund_aborted_test.go diff --git a/common/authz_tx_types.go b/common/authz_tx_types.go index 2eb205f6f9..5477ad8841 100644 --- a/common/authz_tx_types.go +++ b/common/authz_tx_types.go @@ -7,6 +7,7 @@ const ( OutboundVoter TxType = "OutboundVoter" NonceVoter TxType = "NonceVoter" GasPriceVoter TxType = "GasPriceVoter" + RefundAborted TxType = "RefundAborted" ) func (t TxType) String() string { diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index 35082be7d1..907ea7dc3f 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -5,6 +5,7 @@ import ( "testing" "cosmossdk.io/math" + "github.com/ethereum/go-ethereum/crypto" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -80,7 +81,7 @@ func CrossChainTx(t *testing.T, index string) *types.CrossChainTx { return &types.CrossChainTx{ Creator: AccAddress(), - Index: index, + Index: crypto.Keccak256Hash([]byte(index)).String(), ZetaFees: math.NewUint(uint64(r.Int63())), RelayedMessage: StringRandom(r, 32), CctxStatus: Status(t, index), diff --git a/x/crosschain/client/cli/cli_refund_aborted.go b/x/crosschain/client/cli/cli_refund_aborted.go new file mode 100644 index 0000000000..bc1ecf0028 --- /dev/null +++ b/x/crosschain/client/cli/cli_refund_aborted.go @@ -0,0 +1,31 @@ +package cli + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/spf13/cobra" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func CmdRefundAborted() *cobra.Command { + cmd := &cobra.Command{ + Use: "refund-aborted [cctx-index]", + Short: `Refund a aborted tx`, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + msg := types.NewMsgRefundAbortedCCTX(clientCtx.GetFromAddress().String(), args[0]) + err = msg.ValidateBasic() + if err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/x/crosschain/client/cli/tx.go b/x/crosschain/client/cli/tx.go index d8e6b3bc0e..f5668fae44 100644 --- a/x/crosschain/client/cli/tx.go +++ b/x/crosschain/client/cli/tx.go @@ -31,6 +31,7 @@ func GetTxCmd() *cobra.Command { CmdMigrateTssFunds(), CmdAddToInTxTracker(), CmdAbortStuckCCTX(), + CmdRefundAborted(), ) return cmd diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 7b43123cbe..7edb884068 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -4,7 +4,6 @@ import ( "fmt" cosmoserrors "cosmossdk.io/errors" - "cosmossdk.io/math" "github.com/pkg/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -52,9 +51,34 @@ func (k Keeper) UpdateNonce(ctx sdk.Context, receiveChainID int64, cctx *types.C return nil } -// RefundAmountOnZetaChain refunds the amount of the cctx on ZetaChain in case of aborted cctx +func (k Keeper) RefundAmountOnZetaChain(ctx sdk.Context, cctx types.CrossChainTx) error { + coinType := cctx.InboundTxParams.CoinType + switch coinType { + case common.CoinType_Gas: + return k.RefundAmountOnZetaChainGas(ctx, cctx) + case common.CoinType_Zeta: + return k.RefundAmountOnZetaChainZeta(ctx, cctx) + case common.CoinType_ERC20: + return k.RefundAmountOnZetaChainERC20(ctx, cctx) + default: + return errors.New("unsupported coin type for refund on ZetaChain") + } +} + +// RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype gas +func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChainTx) error { + return nil +} + +// RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype zeta +func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossChainTx) error { + return nil +} + +// RefundAmountOnZetaChainERC20 refunds the amount of the cctx on ZetaChain in case of aborted cctx // NOTE: GetCurrentOutTxParam should contain the last up to date cctx amount -func (k Keeper) RefundAmountOnZetaChain(ctx sdk.Context, cctx types.CrossChainTx, inputAmount math.Uint) error { +func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossChainTx) error { + inputAmount := cctx.InboundTxParams.Amount // preliminary checks if cctx.InboundTxParams.CoinType != common.CoinType_ERC20 { return errors.New("unsupported coin type for refund on ZetaChain") diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index 2d122bce7a..4d12008188 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -35,14 +35,14 @@ func TestKeeper_RefundAmountOnZetaChain(t *testing.T) { "bar", ) - err := k.RefundAmountOnZetaChain(ctx, types.CrossChainTx{ + err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_ERC20, SenderChainId: chainID, Sender: sender.String(), Asset: asset, + Amount: math.NewUint(42), }}, - math.NewUint(42), ) require.NoError(t, err) @@ -52,14 +52,14 @@ func TestKeeper_RefundAmountOnZetaChain(t *testing.T) { require.Equal(t, uint64(42), balance.Uint64()) // can refund again - err = k.RefundAmountOnZetaChain(ctx, types.CrossChainTx{ + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_ERC20, SenderChainId: chainID, Sender: sender.String(), Asset: asset, + Amount: math.NewUint(42), }}, - math.NewUint(42), ) require.NoError(t, err) balance, err = zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, sender) @@ -70,71 +70,70 @@ func TestKeeper_RefundAmountOnZetaChain(t *testing.T) { t.Run("should fail with invalid cctx", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - err := k.RefundAmountOnZetaChain(ctx, types.CrossChainTx{ + err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_Zeta, + Amount: math.NewUint(42), }}, - math.NewUint(42), ) require.ErrorContains(t, err, "unsupported coin type") - err = k.RefundAmountOnZetaChain(ctx, types.CrossChainTx{ + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Gas, + CoinType: common.CoinType_Zeta, + Amount: math.NewUint(42), }}, - math.NewUint(42), ) require.ErrorContains(t, err, "unsupported coin type") - err = k.RefundAmountOnZetaChain(ctx, types.CrossChainTx{ + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_ERC20, SenderChainId: 999999, + Amount: math.NewUint(42), }}, - math.NewUint(42), ) require.ErrorContains(t, err, "only EVM chains are supported") - err = k.RefundAmountOnZetaChain(ctx, types.CrossChainTx{ + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_ERC20, SenderChainId: getValidEthChainID(t), Sender: "invalid", + Amount: math.NewUint(42), }}, - math.NewUint(42), ) require.ErrorContains(t, err, "invalid sender address") - err = k.RefundAmountOnZetaChain(ctx, types.CrossChainTx{ + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_ERC20, SenderChainId: getValidEthChainID(t), Sender: sample.EthAddress().String(), - }, - }, - math.Uint{}, + Amount: math.Uint{}, + }}, ) require.ErrorContains(t, err, "no amount to refund") - err = k.RefundAmountOnZetaChain(ctx, types.CrossChainTx{ + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_ERC20, SenderChainId: getValidEthChainID(t), Sender: sample.EthAddress().String(), + Amount: math.ZeroUint(), }}, - math.ZeroUint(), ) require.ErrorContains(t, err, "no amount to refund") // the foreign coin has not been set - err = k.RefundAmountOnZetaChain(ctx, types.CrossChainTx{ + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_ERC20, SenderChainId: getValidEthChainID(t), Sender: sample.EthAddress().String(), Asset: sample.EthAddress().String(), + Amount: math.NewUint(42), }}, - math.NewUint(42), ) require.ErrorContains(t, err, "zrc not found") }) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index b9789d3a8f..304bfe5d50 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -1,11 +1,36 @@ package keeper import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/zeta-chain/zetacore/x/crosschain/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" "golang.org/x/net/context" ) -func (k msgServer) RefundAbortedTx(goCtx context.Context, msg *types.MsgRefundAbortedCCTX) (*types.MsgRefundAbortedCCTXResponse, error) { +func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefundAbortedCCTX) (*types.MsgRefundAbortedCCTXResponse, error) { + + ctx := sdk.UnwrapSDKContext(goCtx) + + // check if authorized + if msg.Creator != k.zetaObserverKeeper.GetParams(ctx).GetAdminPolicyAccount(observertypes.Policy_Type_group2) { + return nil, observertypes.ErrNotAuthorized + } + // check if the cctx exists + cctx, found := k.GetCrossChainTx(ctx, msg.CctxIndex) + if !found { + return nil, types.ErrCannotFindCctx + } + // check if the cctx is aborted + if cctx.CctxStatus.Status != types.CctxStatus_Aborted_Refundable { + return nil, errorsmod.Wrap(types.ErrInvalidStatus, "CCTX is not aborted and refundable") + } + + // refund the amount + err := k.RefundAmountOnZetaChain(ctx, cctx) + if err != nil { + return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) + } return &types.MsgRefundAbortedCCTXResponse{}, nil } diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index ec55d4cddd..f8c570f33f 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -194,7 +194,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg // in this gas we should refund the sender on ZetaChain if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { - if err := k.RefundAmountOnZetaChain(ctx, cctx, cctx.InboundTxParams.Amount); err != nil { + if err := k.RefundAmountOnZetaChainERC20(ctx, cctx); err != nil { // log the error k.Logger(ctx).Error("failed to refund amount of aborted cctx on ZetaChain", "error", err, diff --git a/x/crosschain/types/errors.go b/x/crosschain/types/errors.go index 12bbd4ad84..b531cc6b3f 100644 --- a/x/crosschain/types/errors.go +++ b/x/crosschain/types/errors.go @@ -45,4 +45,9 @@ var ( ErrObservedTxAlreadyFinalized = errorsmod.Register(ModuleName, 1144, "observed tx already finalized") ErrInsufficientFundsTssMigration = errorsmod.Register(ModuleName, 1145, "insufficient funds for TSS migration") + + ErrInvalidCCTXIndex = errorsmod.Register(ModuleName, 1146, "invalid cctx index") + + ErrInvalidStatus = errorsmod.Register(ModuleName, 1147, "invalid status") + ErrUnableProcessRefund = errorsmod.Register(ModuleName, 1148, "unable to process refund") ) diff --git a/x/crosschain/types/message_refund_aborted.go b/x/crosschain/types/message_refund_aborted.go new file mode 100644 index 0000000000..3bee3d857f --- /dev/null +++ b/x/crosschain/types/message_refund_aborted.go @@ -0,0 +1,49 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/zeta-chain/zetacore/common" +) + +var _ sdk.Msg = &MsgRefundAbortedCCTX{} + +func NewMsgRefundAbortedCCTX(creator string, cctxIndex string) *MsgRefundAbortedCCTX { + return &MsgRefundAbortedCCTX{ + Creator: creator, + CctxIndex: cctxIndex, + } +} + +func (msg *MsgRefundAbortedCCTX) Route() string { + return RouterKey +} + +func (msg *MsgRefundAbortedCCTX) Type() string { + return common.RefundAborted.String() +} + +func (msg *MsgRefundAbortedCCTX) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgRefundAbortedCCTX) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgRefundAbortedCCTX) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) + } + if len(msg.CctxIndex) != 66 { + return ErrInvalidCCTXIndex + } + return nil +} diff --git a/x/crosschain/types/message_refund_aborted_test.go b/x/crosschain/types/message_refund_aborted_test.go new file mode 100644 index 0000000000..f523c2b781 --- /dev/null +++ b/x/crosschain/types/message_refund_aborted_test.go @@ -0,0 +1,26 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func TestNewMsgRefundAbortedCCTX(t *testing.T) { + t.Run("successfully validate message", func(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + msg := types.NewMsgRefundAbortedCCTX(sample.AccAddress(), cctx.Index) + assert.NoError(t, msg.ValidateBasic()) + }) + t.Run("invalid creator address", func(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + msg := types.NewMsgRefundAbortedCCTX("invalid", cctx.Index) + assert.ErrorContains(t, msg.ValidateBasic(), "invalid creator address") + }) + t.Run("invalid cctx index", func(t *testing.T) { + msg := types.NewMsgRefundAbortedCCTX(sample.AccAddress(), "invalid") + assert.ErrorContains(t, msg.ValidateBasic(), "invalid cctx index") + }) +} From 1834297933b2161c5851601a272046993e232ebf Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 6 Feb 2024 16:50:08 -0500 Subject: [PATCH 03/50] add refund functions --- proto/crosschain/cross_chain_tx.proto | 4 +- x/crosschain/keeper/cctx.go | 2 +- x/crosschain/keeper/cctx_test.go | 2 +- x/crosschain/keeper/cctx_utils.go | 12 + .../keeper/msg_server_abort_stuck_cctx.go | 2 +- .../msg_server_abort_stuck_cctx_test.go | 6 +- .../keeper/msg_server_refund_aborted_tx.go | 4 +- .../keeper/msg_server_vote_inbound_tx.go | 12 +- .../keeper/msg_server_vote_inbound_tx_test.go | 4 +- .../keeper/msg_server_vote_outbound_tx.go | 6 +- x/crosschain/migrations/v4/migrate.go | 2 +- x/crosschain/migrations/v4/migrate_test.go | 2 +- x/crosschain/types/cross_chain_tx.pb.go | 212 +++++++++++------- x/crosschain/types/status.go | 8 +- 14 files changed, 164 insertions(+), 114 deletions(-) diff --git a/proto/crosschain/cross_chain_tx.proto b/proto/crosschain/cross_chain_tx.proto index e2d3582d54..307e873774 100644 --- a/proto/crosschain/cross_chain_tx.proto +++ b/proto/crosschain/cross_chain_tx.proto @@ -13,8 +13,7 @@ enum CctxStatus { OutboundMined = 3; // the corresponding outbound tx is mined PendingRevert = 4; // outbound cannot succeed; should revert inbound Reverted = 5; // inbound reverted. - Aborted_Refundable = 6; // inbound tx error or invalid paramters and cannot revert; just abort. But the amount can be refunded to zetachain - Aborted_NonRefundable = 7; // inbound tx error or invalid paramters and cannot revert; just abort. The amount cannot be refunded at all + Aborted = 6; // inbound tx error or invalid paramters and cannot revert; just abort. But the amount can be refunded to zetachain using and admin proposal } enum TxFinalizationStatus { @@ -92,4 +91,5 @@ message CrossChainTx { Status cctx_status = 8; InboundTxParams inbound_tx_params = 9; repeated OutboundTxParams outbound_tx_params = 10; + bool isRefunded = 11; } diff --git a/x/crosschain/keeper/cctx.go b/x/crosschain/keeper/cctx.go index fee66b2c5e..e3a2a06f71 100644 --- a/x/crosschain/keeper/cctx.go +++ b/x/crosschain/keeper/cctx.go @@ -48,7 +48,7 @@ func (k Keeper) SetCctxAndNonceToCctxAndInTxHashToCctx(ctx sdk.Context, cctx typ Tss: tss.TssPubkey, }) } - if cctx.CctxStatus.Status == types.CctxStatus_Aborted_Refundable && cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { + if cctx.CctxStatus.Status == types.CctxStatus_Aborted && cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { k.AddZetaAbortedAmount(ctx, cctx.GetCurrentOutTxParam().Amount) } } diff --git a/x/crosschain/keeper/cctx_test.go b/x/crosschain/keeper/cctx_test.go index 7ebb5dc4d6..13218eca13 100644 --- a/x/crosschain/keeper/cctx_test.go +++ b/x/crosschain/keeper/cctx_test.go @@ -122,7 +122,7 @@ func TestSends(t *testing.T) { sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.PendingInbound, types.CctxStatus_PendingInbound)...) sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.PendingOutbound, types.CctxStatus_PendingOutbound)...) sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.PendingRevert, types.CctxStatus_PendingRevert)...) - sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.Aborted, types.CctxStatus_Aborted_Refundable)...) + sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.Aborted, types.CctxStatus_Aborted)...) sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.OutboundMined, types.CctxStatus_OutboundMined)...) sends = append(sends, createNCctxWithStatus(keeper, ctx, tt.Reverted, types.CctxStatus_Reverted)...) //assert.Equal(t, tt.PendingOutbound, len(keeper.GetAllCctxByStatuses(ctx, []types.CctxStatus{types.CctxStatus_PendingOutbound}))) diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 7edb884068..a640db827d 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -72,6 +72,18 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai // RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype zeta func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossChainTx) error { + // if coin type is Zeta, handle this as a deposit ZETA to zEVM. + // deposit the amount to the tx orgin instead of receiver as this is a refund + to := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) + if to == (ethcommon.Address{}) { + return errors.New("invalid receiver address") + } + if cctx.InboundTxParams.Amount.IsNil() || cctx.InboundTxParams.Amount.IsZero() { + return errors.New("no amount to refund") + } + if err := k.fungibleKeeper.DepositCoinZeta(ctx, to, cctx.InboundTxParams.Amount.BigInt()); err != nil { + return errors.New("failed to deposit zeta on ZetaChain" + err.Error()) + } return nil } diff --git a/x/crosschain/keeper/msg_server_abort_stuck_cctx.go b/x/crosschain/keeper/msg_server_abort_stuck_cctx.go index df7a59d38e..32c4bdf55f 100644 --- a/x/crosschain/keeper/msg_server_abort_stuck_cctx.go +++ b/x/crosschain/keeper/msg_server_abort_stuck_cctx.go @@ -41,7 +41,7 @@ func (k msgServer) AbortStuckCCTX( } cctx.CctxStatus = &types.Status{ - Status: types.CctxStatus_Aborted_Refundable, + Status: types.CctxStatus_Aborted, StatusMessage: AbortMessage, } diff --git a/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go b/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go index 5e9d070b2a..f9b7c380e0 100644 --- a/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go +++ b/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go @@ -35,7 +35,7 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { require.NoError(t, err) cctxFound, found := k.GetCrossChainTx(ctx, "cctx_index") require.True(t, found) - require.Equal(t, crosschaintypes.CctxStatus_Aborted_Refundable, cctxFound.CctxStatus.Status) + require.Equal(t, crosschaintypes.CctxStatus_Aborted, cctxFound.CctxStatus.Status) require.Equal(t, crosschainkeeper.AbortMessage, cctxFound.CctxStatus.StatusMessage) }) @@ -62,7 +62,7 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { require.NoError(t, err) cctxFound, found := k.GetCrossChainTx(ctx, "cctx_index") require.True(t, found) - require.Equal(t, crosschaintypes.CctxStatus_Aborted_Refundable, cctxFound.CctxStatus.Status) + require.Equal(t, crosschaintypes.CctxStatus_Aborted, cctxFound.CctxStatus.Status) require.Equal(t, crosschainkeeper.AbortMessage, cctxFound.CctxStatus.StatusMessage) }) @@ -89,7 +89,7 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { require.NoError(t, err) cctxFound, found := k.GetCrossChainTx(ctx, "cctx_index") require.True(t, found) - require.Equal(t, crosschaintypes.CctxStatus_Aborted_Refundable, cctxFound.CctxStatus.Status) + require.Equal(t, crosschaintypes.CctxStatus_Aborted, cctxFound.CctxStatus.Status) require.Equal(t, crosschainkeeper.AbortMessage, cctxFound.CctxStatus.StatusMessage) }) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 304bfe5d50..007165744e 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -22,8 +22,8 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund return nil, types.ErrCannotFindCctx } // check if the cctx is aborted - if cctx.CctxStatus.Status != types.CctxStatus_Aborted_Refundable { - return nil, errorsmod.Wrap(types.ErrInvalidStatus, "CCTX is not aborted and refundable") + if cctx.CctxStatus.Status != types.CctxStatus_Aborted { + return nil, errorsmod.Wrap(types.ErrInvalidStatus, "CCTX is not aborted") } // refund the amount diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index f8c570f33f..bd42a2e1ce 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -142,19 +142,19 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg isContractReverted, err := k.HandleEVMDeposit(tmpCtx, &cctx, *msg, observationChain) if err != nil && !isContractReverted { // exceptional case; internal error; should abort CCTX - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, err.Error()) + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } else if err != nil && isContractReverted { // contract call reverted; should refund revertMessage := err.Error() chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundTxParams.SenderChainId) if chain == nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, "invalid sender chain") + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "invalid sender chain") return &types.MsgVoteOnObservedInboundTxResponse{}, nil } gasLimit, err := k.GetRevertGasLimit(ctx, cctx) if err != nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, "can't get revert tx gas limit"+err.Error()) + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "can't get revert tx gas limit"+err.Error()) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } if gasLimit == 0 { @@ -203,8 +203,8 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg ) } } - - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, err.Error()+" deposit revert message: "+revertMessage) + cctx.IsRefunded = true + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()+" deposit revert message: "+revertMessage) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } commit() @@ -234,7 +234,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg }() if err != nil { // do not commit anything here as the CCTX should be aborted - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, err.Error()) + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } commit() diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go index b802488751..32a0578ed8 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -167,7 +167,7 @@ func TestStatus_StatusTransition(t *testing.T) { }, Msg: "Got super majority and finalized Inbound", NonErrStatus: types.CctxStatus_PendingOutbound, - ErrStatus: types.CctxStatus_Aborted_Refundable, + ErrStatus: types.CctxStatus_Aborted, IsErr: false, }, { @@ -179,7 +179,7 @@ func TestStatus_StatusTransition(t *testing.T) { }, Msg: "Got super majority and finalized Inbound", NonErrStatus: types.CctxStatus_OutboundMined, - ErrStatus: types.CctxStatus_Aborted_Refundable, + ErrStatus: types.CctxStatus_Aborted, IsErr: false, }, } diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index f3e43a9e07..17319d1f8a 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -160,7 +160,7 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms case observerTypes.BallotStatus_BallotFinalized_FailureObservation: if msg.CoinType == common.CoinType_Cmd || common.IsZetaChain(cctx.InboundTxParams.SenderChainId) { // if the cctx is of coin type cmd or the sender chain is zeta chain, then we do not revert, the cctx is aborted - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, "") + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "") } else { switch oldStatus { case types.CctxStatus_PendingOutbound: @@ -200,7 +200,7 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms } cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, "Outbound failed, start revert") case types.CctxStatus_PendingRevert: - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, "Outbound failed: revert failed; abort TX") + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "Outbound failed: revert failed; abort TX") } } newStatus := cctx.CctxStatus.Status.String() @@ -210,7 +210,7 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms }() if err != nil { // do not commit tmpCtx - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted_Refundable, err.Error()) + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed ctx.Logger().Error(err.Error()) // #nosec G701 always in range diff --git a/x/crosschain/migrations/v4/migrate.go b/x/crosschain/migrations/v4/migrate.go index 4ee36baca0..e4b368e44c 100644 --- a/x/crosschain/migrations/v4/migrate.go +++ b/x/crosschain/migrations/v4/migrate.go @@ -54,7 +54,7 @@ func SetZetaAccounting( for ; iterator.Valid(); iterator.Next() { var val types.CrossChainTx cdc.MustUnmarshal(iterator.Value(), &val) - if val.CctxStatus.Status == types.CctxStatus_Aborted_Refundable && val.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { + if val.CctxStatus.Status == types.CctxStatus_Aborted && val.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { abortedAmountZeta = abortedAmountZeta.Add(val.GetCurrentOutTxParam().Amount) } } diff --git a/x/crosschain/migrations/v4/migrate_test.go b/x/crosschain/migrations/v4/migrate_test.go index a3c484e94a..5ff2f9ee54 100644 --- a/x/crosschain/migrations/v4/migrate_test.go +++ b/x/crosschain/migrations/v4/migrate_test.go @@ -168,7 +168,7 @@ func SetRandomCctx(ctx sdk.Context, k keeper.Keeper) sdkmath.Uint { amount := sdkmath.NewUint(uint64(r.Uint32())) k.SetCrossChainTx(ctx, types.CrossChainTx{ Index: fmt.Sprintf("%d", i), - CctxStatus: &types.Status{Status: types.CctxStatus_Aborted_Refundable}, + CctxStatus: &types.Status{Status: types.CctxStatus_Aborted}, OutboundTxParams: []*types.OutboundTxParams{{ Amount: amount, CoinType: common.CoinType_Zeta, diff --git a/x/crosschain/types/cross_chain_tx.pb.go b/x/crosschain/types/cross_chain_tx.pb.go index 0bb09e6a6a..84e6e1bc6a 100644 --- a/x/crosschain/types/cross_chain_tx.pb.go +++ b/x/crosschain/types/cross_chain_tx.pb.go @@ -29,13 +29,12 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type CctxStatus int32 const ( - CctxStatus_PendingInbound CctxStatus = 0 - CctxStatus_PendingOutbound CctxStatus = 1 - CctxStatus_OutboundMined CctxStatus = 3 - CctxStatus_PendingRevert CctxStatus = 4 - CctxStatus_Reverted CctxStatus = 5 - CctxStatus_Aborted_Refundable CctxStatus = 6 - CctxStatus_Aborted_NonRefundable CctxStatus = 7 + CctxStatus_PendingInbound CctxStatus = 0 + CctxStatus_PendingOutbound CctxStatus = 1 + CctxStatus_OutboundMined CctxStatus = 3 + CctxStatus_PendingRevert CctxStatus = 4 + CctxStatus_Reverted CctxStatus = 5 + CctxStatus_Aborted CctxStatus = 6 ) var CctxStatus_name = map[int32]string{ @@ -44,18 +43,16 @@ var CctxStatus_name = map[int32]string{ 3: "OutboundMined", 4: "PendingRevert", 5: "Reverted", - 6: "Aborted_Refundable", - 7: "Aborted_NonRefundable", + 6: "Aborted", } var CctxStatus_value = map[string]int32{ - "PendingInbound": 0, - "PendingOutbound": 1, - "OutboundMined": 3, - "PendingRevert": 4, - "Reverted": 5, - "Aborted_Refundable": 6, - "Aborted_NonRefundable": 7, + "PendingInbound": 0, + "PendingOutbound": 1, + "OutboundMined": 3, + "PendingRevert": 4, + "Reverted": 5, + "Aborted": 6, } func (x CctxStatus) String() string { @@ -461,6 +458,7 @@ type CrossChainTx struct { CctxStatus *Status `protobuf:"bytes,8,opt,name=cctx_status,json=cctxStatus,proto3" json:"cctx_status,omitempty"` InboundTxParams *InboundTxParams `protobuf:"bytes,9,opt,name=inbound_tx_params,json=inboundTxParams,proto3" json:"inbound_tx_params,omitempty"` OutboundTxParams []*OutboundTxParams `protobuf:"bytes,10,rep,name=outbound_tx_params,json=outboundTxParams,proto3" json:"outbound_tx_params,omitempty"` + IsRefunded bool `protobuf:"varint,11,opt,name=isRefunded,proto3" json:"isRefunded,omitempty"` } func (m *CrossChainTx) Reset() { *m = CrossChainTx{} } @@ -538,6 +536,13 @@ func (m *CrossChainTx) GetOutboundTxParams() []*OutboundTxParams { return nil } +func (m *CrossChainTx) GetIsRefunded() bool { + if m != nil { + return m.IsRefunded + } + return false +} + func init() { proto.RegisterEnum("zetachain.zetacore.crosschain.CctxStatus", CctxStatus_name, CctxStatus_value) proto.RegisterEnum("zetachain.zetacore.crosschain.TxFinalizationStatus", TxFinalizationStatus_name, TxFinalizationStatus_value) @@ -551,77 +556,77 @@ func init() { func init() { proto.RegisterFile("crosschain/cross_chain_tx.proto", fileDescriptor_af3a0ad055343c21) } var fileDescriptor_af3a0ad055343c21 = []byte{ - // 1120 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcb, 0x6e, 0x1b, 0x37, - 0x17, 0xd6, 0x44, 0xb2, 0x2c, 0x1d, 0x5f, 0x34, 0xa6, 0x65, 0xff, 0xf3, 0x3b, 0x8d, 0x24, 0xa8, - 0x4d, 0xa2, 0x04, 0xb0, 0x04, 0x3b, 0x28, 0x02, 0x74, 0x67, 0xbb, 0x76, 0x62, 0x24, 0xb1, 0x8d, - 0xa9, 0xbd, 0x31, 0x50, 0x4c, 0xa9, 0x19, 0x5a, 0x22, 0x22, 0x0d, 0xd5, 0x21, 0x65, 0xc8, 0x79, - 0x8a, 0x2e, 0xfa, 0x04, 0x45, 0x0b, 0xf4, 0x51, 0xb2, 0xe8, 0x22, 0xcb, 0xa2, 0x0b, 0xa3, 0xb0, - 0xd7, 0xdd, 0xf4, 0x09, 0x0a, 0x5e, 0x66, 0x34, 0x56, 0x7d, 0xe9, 0x6d, 0x35, 0x87, 0x87, 0xfc, - 0xbe, 0x43, 0x9e, 0xf3, 0x1d, 0x0e, 0xa1, 0xea, 0x47, 0x8c, 0x73, 0xbf, 0x8b, 0x69, 0xd8, 0x52, - 0xa6, 0xa7, 0x6c, 0x4f, 0x8c, 0x9a, 0x83, 0x88, 0x09, 0x86, 0x1e, 0xbc, 0x23, 0x02, 0x2b, 0x5f, - 0x53, 0x59, 0x2c, 0x22, 0xcd, 0x31, 0x66, 0x65, 0xd1, 0x67, 0xfd, 0x3e, 0x0b, 0x5b, 0xfa, 0xa3, - 0x31, 0x2b, 0xe5, 0x0e, 0xeb, 0x30, 0x65, 0xb6, 0xa4, 0xa5, 0xbd, 0xf5, 0xdf, 0x72, 0x50, 0xda, - 0x0d, 0xdb, 0x6c, 0x18, 0x06, 0x87, 0xa3, 0x03, 0x1c, 0xe1, 0x3e, 0x47, 0xcb, 0x90, 0xe7, 0x24, - 0x0c, 0x48, 0xe4, 0x58, 0x35, 0xab, 0x51, 0x74, 0xcd, 0x08, 0x3d, 0x82, 0x92, 0xb6, 0xcc, 0x76, - 0x68, 0xe0, 0xdc, 0xab, 0x59, 0x8d, 0xac, 0x3b, 0xa7, 0xdd, 0x5b, 0xd2, 0xbb, 0x1b, 0xa0, 0xfb, - 0x50, 0x14, 0x23, 0x8f, 0x45, 0xb4, 0x43, 0x43, 0x27, 0xab, 0x28, 0x0a, 0x62, 0xb4, 0xaf, 0xc6, - 0x68, 0x15, 0x8a, 0x3e, 0x93, 0x67, 0x39, 0x1b, 0x10, 0x27, 0x57, 0xb3, 0x1a, 0xf3, 0xeb, 0x76, - 0xd3, 0x6c, 0x74, 0x8b, 0xd1, 0xf0, 0xf0, 0x6c, 0x40, 0xdc, 0x82, 0x6f, 0x2c, 0x54, 0x86, 0x29, - 0xcc, 0x39, 0x11, 0xce, 0x94, 0xe2, 0xd1, 0x03, 0xf4, 0x02, 0xf2, 0xb8, 0xcf, 0x86, 0xa1, 0x70, - 0xf2, 0xd2, 0xbd, 0xd9, 0x7a, 0x7f, 0x5e, 0xcd, 0xfc, 0x72, 0x5e, 0x7d, 0xdc, 0xa1, 0xa2, 0x3b, - 0x6c, 0x4b, 0xbe, 0x96, 0xcf, 0x78, 0x9f, 0x71, 0xf3, 0x59, 0xe5, 0xc1, 0xdb, 0x96, 0x0c, 0xc9, - 0x9b, 0x47, 0x34, 0x14, 0xae, 0x81, 0xa3, 0xe7, 0xe0, 0x50, 0x7d, 0x7a, 0x4f, 0x6e, 0xb9, 0xcd, - 0x49, 0x74, 0x4a, 0x02, 0xaf, 0x8b, 0x79, 0xd7, 0x99, 0x56, 0x11, 0x97, 0x68, 0x9c, 0x9d, 0x7d, - 0x33, 0xfb, 0x12, 0xf3, 0x2e, 0x7a, 0x0d, 0x1f, 0x5f, 0x07, 0x24, 0x23, 0x41, 0xa2, 0x10, 0xf7, - 0xbc, 0x2e, 0xa1, 0x9d, 0xae, 0x70, 0x0a, 0x35, 0xab, 0x91, 0x73, 0xab, 0x7f, 0xe2, 0xd8, 0x36, - 0xeb, 0x5e, 0xaa, 0x65, 0xe8, 0x53, 0xf8, 0x5f, 0x8a, 0xad, 0x8d, 0x7b, 0x3d, 0x26, 0x3c, 0x1a, - 0x06, 0x64, 0xe4, 0x14, 0xd5, 0x2e, 0xca, 0x09, 0xc3, 0xa6, 0x9a, 0xdc, 0x95, 0x73, 0x68, 0x07, - 0x6a, 0x29, 0xd8, 0x09, 0x0d, 0x71, 0x8f, 0xbe, 0x23, 0x81, 0x27, 0x35, 0x11, 0xef, 0x00, 0xd4, - 0x0e, 0x3e, 0x4a, 0xf0, 0x3b, 0xf1, 0xaa, 0x63, 0x22, 0xb0, 0x09, 0x4f, 0x61, 0x79, 0x8c, 0xc7, - 0x82, 0xb2, 0xd0, 0xe3, 0x02, 0x8b, 0x21, 0x77, 0x66, 0x54, 0x81, 0x9e, 0x35, 0x6f, 0xd5, 0x5b, - 0x33, 0x61, 0x55, 0xd8, 0x2f, 0x14, 0xd4, 0x2d, 0x8b, 0x6b, 0xbc, 0xf5, 0xaf, 0x61, 0x5e, 0x06, - 0xde, 0xf0, 0x7d, 0x99, 0x7f, 0x1a, 0x76, 0x90, 0x07, 0x8b, 0xb8, 0xcd, 0x22, 0x11, 0xef, 0xdb, - 0x14, 0xd6, 0xfa, 0x67, 0x85, 0x5d, 0x30, 0x5c, 0x2a, 0x88, 0x62, 0xaa, 0x7f, 0x3b, 0x0d, 0xf6, - 0xfe, 0x50, 0x5c, 0xd5, 0xf8, 0x0a, 0x14, 0x22, 0xe2, 0x13, 0x7a, 0x9a, 0xa8, 0x3c, 0x19, 0xa3, - 0x27, 0x60, 0xc7, 0xb6, 0x56, 0xfa, 0x6e, 0x2c, 0xf4, 0x52, 0xec, 0x8f, 0xa5, 0x7e, 0x45, 0xcd, - 0xd9, 0x3b, 0xd5, 0x3c, 0xd6, 0x6d, 0xee, 0xdf, 0xe9, 0x76, 0x0d, 0x96, 0x98, 0x39, 0x92, 0x2c, - 0xbd, 0xe0, 0xdc, 0x0b, 0x59, 0xe8, 0x13, 0xd5, 0x26, 0x39, 0x17, 0xb1, 0xe4, 0xbc, 0x87, 0x9c, - 0xef, 0xc9, 0x99, 0x49, 0x48, 0x07, 0x73, 0xaf, 0x47, 0xfb, 0x54, 0xb7, 0xd0, 0x15, 0xc8, 0x0b, - 0xcc, 0x5f, 0xcb, 0x99, 0xeb, 0x20, 0x83, 0x88, 0xfa, 0xc4, 0xb4, 0xc6, 0x55, 0xc8, 0x81, 0x9c, - 0x41, 0x0d, 0xb0, 0xd3, 0x10, 0xd5, 0x48, 0x05, 0xb5, 0x7a, 0x7e, 0xbc, 0x5a, 0x75, 0xd0, 0x73, - 0x70, 0xd2, 0x2b, 0xaf, 0x11, 0xfd, 0xd2, 0x18, 0x91, 0x56, 0xfd, 0x1e, 0x7c, 0x92, 0x06, 0xde, - 0xd8, 0x7b, 0x5a, 0xf9, 0xb5, 0x31, 0xc9, 0x0d, 0xcd, 0xd7, 0x82, 0xf2, 0xe4, 0x29, 0x87, 0x9c, - 0x04, 0x4e, 0x59, 0xe1, 0x17, 0xae, 0x1c, 0xf2, 0x88, 0x93, 0x00, 0x09, 0xa8, 0xa6, 0x01, 0xe4, - 0xe4, 0x84, 0xf8, 0x82, 0x9e, 0x92, 0x54, 0x82, 0x96, 0x54, 0x79, 0x9b, 0xa6, 0xbc, 0x8f, 0xfe, - 0x42, 0x79, 0x77, 0x43, 0xe1, 0xde, 0x1f, 0xc7, 0xda, 0x8e, 0x49, 0x93, 0xcc, 0x7e, 0x7e, 0x5b, - 0x54, 0x5d, 0xc9, 0x65, 0xb5, 0xe3, 0x1b, 0x58, 0x74, 0x49, 0x1f, 0x00, 0x48, 0xb1, 0x0c, 0x86, - 0xed, 0xb7, 0xe4, 0x4c, 0xb5, 0x77, 0xd1, 0x2d, 0x0a, 0xce, 0x0f, 0x94, 0xe3, 0x96, 0x9b, 0x60, - 0xf6, 0xbf, 0xbe, 0x09, 0x7e, 0xb0, 0x20, 0xaf, 0x4d, 0xb4, 0x01, 0x79, 0x13, 0xc5, 0x52, 0x51, - 0x9e, 0xdc, 0x11, 0x65, 0xcb, 0x17, 0x23, 0xc3, 0x6d, 0x80, 0xe8, 0x21, 0xcc, 0x6b, 0xcb, 0xeb, - 0x13, 0xce, 0x71, 0x87, 0xa8, 0x8e, 0x2d, 0xba, 0x73, 0xda, 0xfb, 0x46, 0x3b, 0xd1, 0x1a, 0x94, - 0x7b, 0x98, 0x8b, 0xa3, 0x41, 0x80, 0x05, 0xf1, 0x04, 0xed, 0x13, 0x2e, 0x70, 0x7f, 0xa0, 0x5a, - 0x37, 0xeb, 0x2e, 0x8e, 0xe7, 0x0e, 0xe3, 0xa9, 0xfa, 0x4f, 0x59, 0x98, 0xdd, 0x92, 0xb1, 0x55, - 0xcf, 0x1f, 0x8e, 0x90, 0x03, 0xd3, 0x7e, 0x44, 0xb0, 0x60, 0xf1, 0xcd, 0x11, 0x0f, 0xe5, 0xcf, - 0x4a, 0xeb, 0x57, 0xc7, 0xd6, 0x03, 0xf4, 0x15, 0x14, 0xd5, 0xc5, 0x76, 0x42, 0x08, 0xd7, 0xbf, - 0xb1, 0xcd, 0xad, 0xbf, 0xd9, 0xf7, 0xbf, 0x9f, 0x57, 0xed, 0x33, 0xdc, 0xef, 0x7d, 0x56, 0x4f, - 0x98, 0xea, 0x6e, 0x41, 0xda, 0x3b, 0x84, 0x70, 0xf4, 0x18, 0x4a, 0x11, 0xe9, 0xe1, 0x33, 0x12, - 0x24, 0xa7, 0xcf, 0xeb, 0x9e, 0x33, 0xee, 0xf8, 0xf8, 0x3b, 0x30, 0xe3, 0xfb, 0x62, 0x14, 0xd7, - 0x54, 0x36, 0xe6, 0xcc, 0xfa, 0xc3, 0x3b, 0xb2, 0x6d, 0x32, 0x0d, 0x7e, 0x92, 0x75, 0x74, 0x0c, - 0x0b, 0xa9, 0x1f, 0xcf, 0x40, 0x5d, 0xa9, 0xaa, 0x69, 0x67, 0xd6, 0x9b, 0x77, 0xb0, 0x4d, 0x3c, - 0x36, 0xdc, 0x12, 0x9d, 0x78, 0x7d, 0x7c, 0x09, 0x28, 0xad, 0x73, 0x43, 0x0e, 0xb5, 0x6c, 0x63, - 0x66, 0xbd, 0x75, 0x07, 0xf9, 0xe4, 0x35, 0xef, 0xda, 0x6c, 0xc2, 0xf3, 0xf4, 0x3b, 0x0b, 0x60, - 0xac, 0x1f, 0x84, 0x60, 0xfe, 0x80, 0x84, 0x01, 0x0d, 0x3b, 0x66, 0x63, 0x76, 0x06, 0x2d, 0x42, - 0xc9, 0xf8, 0x62, 0x3e, 0xdb, 0x42, 0x0b, 0x30, 0x17, 0x8f, 0xde, 0xd0, 0x90, 0x04, 0x76, 0x56, - 0xba, 0xcc, 0x3a, 0x97, 0x9c, 0x92, 0x48, 0xd8, 0x39, 0x34, 0x0b, 0x05, 0x6d, 0x93, 0xc0, 0x9e, - 0x42, 0xcb, 0x80, 0x36, 0xcc, 0xaf, 0xcd, 0x25, 0x27, 0xc3, 0x30, 0xc0, 0xed, 0x1e, 0xb1, 0xf3, - 0xe8, 0xff, 0xb0, 0x14, 0xfb, 0xf7, 0x58, 0x98, 0x9a, 0x9a, 0x5e, 0xc9, 0xfd, 0xf8, 0x7d, 0xc5, - 0x7a, 0xfa, 0x0a, 0xca, 0xd7, 0x75, 0x12, 0xb2, 0x61, 0x76, 0x8f, 0x89, 0xe4, 0x17, 0x6e, 0x67, - 0xd0, 0x1c, 0x14, 0xc7, 0x43, 0x4b, 0xc6, 0xdf, 0x1e, 0x11, 0x7f, 0x28, 0xe3, 0xdf, 0xd3, 0x64, - 0x9b, 0xaf, 0xde, 0x5f, 0x54, 0xac, 0x0f, 0x17, 0x15, 0xeb, 0xd7, 0x8b, 0x8a, 0xf5, 0xcd, 0x65, - 0x25, 0xf3, 0xe1, 0xb2, 0x92, 0xf9, 0xf9, 0xb2, 0x92, 0x39, 0x5e, 0x4b, 0xc9, 0x4f, 0xa6, 0x73, - 0x55, 0x3f, 0x39, 0xe3, 0xcc, 0xb6, 0x46, 0xad, 0xd4, 0x43, 0x54, 0xa9, 0xb1, 0x9d, 0x57, 0xcf, - 0xc6, 0x67, 0x7f, 0x04, 0x00, 0x00, 0xff, 0xff, 0xbf, 0x44, 0x13, 0xe8, 0xa3, 0x0a, 0x00, 0x00, + // 1115 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xdd, 0x4e, 0x1b, 0x47, + 0x14, 0xf6, 0xc6, 0x8e, 0xb1, 0x8f, 0x01, 0x2f, 0x83, 0x49, 0x57, 0xa4, 0xb1, 0x2d, 0xb7, 0x49, + 0x9c, 0x48, 0xd8, 0x82, 0xa8, 0x8a, 0xd4, 0x3b, 0xa0, 0x90, 0xa0, 0x24, 0x80, 0xb6, 0x70, 0x83, + 0x54, 0x6d, 0xc7, 0xbb, 0x83, 0x3d, 0x8a, 0xbd, 0xe3, 0xee, 0x8c, 0x91, 0x89, 0xfa, 0x10, 0xbd, + 0xe8, 0x23, 0xb4, 0x52, 0x1f, 0x25, 0x97, 0xb9, 0xac, 0x7a, 0x81, 0x2a, 0xb8, 0x6d, 0x6f, 0xfa, + 0x04, 0xd5, 0xfc, 0xec, 0x7a, 0x71, 0xf9, 0xe9, 0xdf, 0xd5, 0x9e, 0x39, 0x33, 0xdf, 0x77, 0x66, + 0xce, 0xf9, 0xce, 0xec, 0x40, 0xcd, 0x8f, 0x18, 0xe7, 0x7e, 0x0f, 0xd3, 0xb0, 0xad, 0x4c, 0x4f, + 0xd9, 0x9e, 0x18, 0xb7, 0x86, 0x11, 0x13, 0x0c, 0x3d, 0x78, 0x47, 0x04, 0x56, 0xbe, 0x96, 0xb2, + 0x58, 0x44, 0x5a, 0x13, 0xcc, 0xf2, 0xa2, 0xcf, 0x06, 0x03, 0x16, 0xb6, 0xf5, 0x47, 0x63, 0x96, + 0x2b, 0x5d, 0xd6, 0x65, 0xca, 0x6c, 0x4b, 0x4b, 0x7b, 0x1b, 0xbf, 0xe7, 0xa0, 0xbc, 0x13, 0x76, + 0xd8, 0x28, 0x0c, 0x0e, 0xc6, 0xfb, 0x38, 0xc2, 0x03, 0x8e, 0xee, 0x41, 0x9e, 0x93, 0x30, 0x20, + 0x91, 0x63, 0xd5, 0xad, 0x66, 0xd1, 0x35, 0x23, 0xf4, 0x08, 0xca, 0xda, 0x32, 0xdb, 0xa1, 0x81, + 0x73, 0xa7, 0x6e, 0x35, 0xb3, 0xee, 0x9c, 0x76, 0x6f, 0x4a, 0xef, 0x4e, 0x80, 0xee, 0x43, 0x51, + 0x8c, 0x3d, 0x16, 0xd1, 0x2e, 0x0d, 0x9d, 0xac, 0xa2, 0x28, 0x88, 0xf1, 0x9e, 0x1a, 0xa3, 0x15, + 0x28, 0xfa, 0x4c, 0x9e, 0xe5, 0x74, 0x48, 0x9c, 0x5c, 0xdd, 0x6a, 0xce, 0xaf, 0xd9, 0x2d, 0xb3, + 0xd1, 0x4d, 0x46, 0xc3, 0x83, 0xd3, 0x21, 0x71, 0x0b, 0xbe, 0xb1, 0x50, 0x05, 0xee, 0x62, 0xce, + 0x89, 0x70, 0xee, 0x2a, 0x1e, 0x3d, 0x40, 0x2f, 0x20, 0x8f, 0x07, 0x6c, 0x14, 0x0a, 0x27, 0x2f, + 0xdd, 0x1b, 0xed, 0xf7, 0x67, 0xb5, 0xcc, 0x2f, 0x67, 0xb5, 0xc7, 0x5d, 0x2a, 0x7a, 0xa3, 0x8e, + 0xe4, 0x6b, 0xfb, 0x8c, 0x0f, 0x18, 0x37, 0x9f, 0x15, 0x1e, 0xbc, 0x6d, 0xcb, 0x90, 0xbc, 0x75, + 0x48, 0x43, 0xe1, 0x1a, 0x38, 0x7a, 0x0e, 0x0e, 0xd5, 0xa7, 0xf7, 0xe4, 0x96, 0x3b, 0x9c, 0x44, + 0x27, 0x24, 0xf0, 0x7a, 0x98, 0xf7, 0x9c, 0x19, 0x15, 0x71, 0x89, 0xc6, 0xd9, 0xd9, 0x33, 0xb3, + 0x2f, 0x31, 0xef, 0xa1, 0xd7, 0xf0, 0xc9, 0x55, 0x40, 0x32, 0x16, 0x24, 0x0a, 0x71, 0xdf, 0xeb, + 0x11, 0xda, 0xed, 0x09, 0xa7, 0x50, 0xb7, 0x9a, 0x39, 0xb7, 0xf6, 0x17, 0x8e, 0x2d, 0xb3, 0xee, + 0xa5, 0x5a, 0x86, 0x3e, 0x83, 0x8f, 0x52, 0x6c, 0x1d, 0xdc, 0xef, 0x33, 0xe1, 0xd1, 0x30, 0x20, + 0x63, 0xa7, 0xa8, 0x76, 0x51, 0x49, 0x18, 0x36, 0xd4, 0xe4, 0x8e, 0x9c, 0x43, 0xdb, 0x50, 0x4f, + 0xc1, 0x8e, 0x69, 0x88, 0xfb, 0xf4, 0x1d, 0x09, 0x3c, 0xa9, 0x89, 0x78, 0x07, 0xa0, 0x76, 0xf0, + 0x71, 0x82, 0xdf, 0x8e, 0x57, 0x1d, 0x11, 0x81, 0x4d, 0x78, 0x0a, 0xf7, 0x26, 0x78, 0x2c, 0x28, + 0x0b, 0x3d, 0x2e, 0xb0, 0x18, 0x71, 0xa7, 0xa4, 0x0a, 0xf4, 0xac, 0x75, 0xa3, 0xde, 0x5a, 0x09, + 0xab, 0xc2, 0x7e, 0xa9, 0xa0, 0x6e, 0x45, 0x5c, 0xe1, 0x6d, 0x7c, 0x03, 0xf3, 0x32, 0xf0, 0xba, + 0xef, 0xcb, 0xfc, 0xd3, 0xb0, 0x8b, 0x3c, 0x58, 0xc4, 0x1d, 0x16, 0x89, 0x78, 0xdf, 0xa6, 0xb0, + 0xd6, 0xbf, 0x2b, 0xec, 0x82, 0xe1, 0x52, 0x41, 0x14, 0x53, 0xe3, 0xfb, 0x19, 0xb0, 0xf7, 0x46, + 0xe2, 0xb2, 0xc6, 0x97, 0xa1, 0x10, 0x11, 0x9f, 0xd0, 0x93, 0x44, 0xe5, 0xc9, 0x18, 0x3d, 0x01, + 0x3b, 0xb6, 0xb5, 0xd2, 0x77, 0x62, 0xa1, 0x97, 0x63, 0x7f, 0x2c, 0xf5, 0x4b, 0x6a, 0xce, 0xde, + 0xaa, 0xe6, 0x89, 0x6e, 0x73, 0xff, 0x4d, 0xb7, 0xab, 0xb0, 0xc4, 0xcc, 0x91, 0x64, 0xe9, 0x05, + 0xe7, 0x5e, 0xc8, 0x42, 0x9f, 0xa8, 0x36, 0xc9, 0xb9, 0x88, 0x25, 0xe7, 0x3d, 0xe0, 0x7c, 0x57, + 0xce, 0x4c, 0x43, 0xba, 0x98, 0x7b, 0x7d, 0x3a, 0xa0, 0xba, 0x85, 0x2e, 0x41, 0x5e, 0x60, 0xfe, + 0x5a, 0xce, 0x5c, 0x05, 0x19, 0x46, 0xd4, 0x27, 0xa6, 0x35, 0x2e, 0x43, 0xf6, 0xe5, 0x0c, 0x6a, + 0x82, 0x9d, 0x86, 0xa8, 0x46, 0x2a, 0xa8, 0xd5, 0xf3, 0x93, 0xd5, 0xaa, 0x83, 0x9e, 0x83, 0x93, + 0x5e, 0x79, 0x85, 0xe8, 0x97, 0x26, 0x88, 0xb4, 0xea, 0x77, 0xe1, 0xd3, 0x34, 0xf0, 0xda, 0xde, + 0xd3, 0xca, 0xaf, 0x4f, 0x48, 0xae, 0x69, 0xbe, 0x36, 0x54, 0xa6, 0x4f, 0x39, 0xe2, 0x24, 0x70, + 0x2a, 0x0a, 0xbf, 0x70, 0xe9, 0x90, 0x87, 0x9c, 0x04, 0x48, 0x40, 0x2d, 0x0d, 0x20, 0xc7, 0xc7, + 0xc4, 0x17, 0xf4, 0x84, 0xa4, 0x12, 0xb4, 0xa4, 0xca, 0xdb, 0x32, 0xe5, 0x7d, 0xf4, 0x37, 0xca, + 0xbb, 0x13, 0x0a, 0xf7, 0xfe, 0x24, 0xd6, 0x56, 0x4c, 0x9a, 0x64, 0xf6, 0x8b, 0x9b, 0xa2, 0xea, + 0x4a, 0xde, 0x53, 0x3b, 0xbe, 0x86, 0x45, 0x97, 0xf4, 0x01, 0x80, 0x14, 0xcb, 0x70, 0xd4, 0x79, + 0x4b, 0x4e, 0x55, 0x7b, 0x17, 0xdd, 0xa2, 0xe0, 0x7c, 0x5f, 0x39, 0x6e, 0xb8, 0x09, 0x66, 0xff, + 0xef, 0x9b, 0xe0, 0x47, 0x0b, 0xf2, 0xda, 0x44, 0xeb, 0x90, 0x37, 0x51, 0x2c, 0x15, 0xe5, 0xc9, + 0x2d, 0x51, 0x36, 0x7d, 0x31, 0x36, 0xdc, 0x06, 0x88, 0x1e, 0xc2, 0xbc, 0xb6, 0xbc, 0x01, 0xe1, + 0x1c, 0x77, 0x89, 0xea, 0xd8, 0xa2, 0x3b, 0xa7, 0xbd, 0x6f, 0xb4, 0x13, 0xad, 0x42, 0xa5, 0x8f, + 0xb9, 0x38, 0x1c, 0x06, 0x58, 0x10, 0x4f, 0xd0, 0x01, 0xe1, 0x02, 0x0f, 0x86, 0xaa, 0x75, 0xb3, + 0xee, 0xe2, 0x64, 0xee, 0x20, 0x9e, 0x6a, 0xfc, 0x96, 0x85, 0xd9, 0x4d, 0x19, 0x5b, 0xf5, 0xfc, + 0xc1, 0x18, 0x39, 0x30, 0xe3, 0x47, 0x04, 0x0b, 0x16, 0xdf, 0x1c, 0xf1, 0x50, 0xfe, 0xac, 0xb4, + 0x7e, 0x75, 0x6c, 0x3d, 0x40, 0x5f, 0x43, 0x51, 0x5d, 0x6c, 0xc7, 0x84, 0x70, 0xfd, 0x1b, 0xdb, + 0xd8, 0xfc, 0x87, 0x7d, 0xff, 0xc7, 0x59, 0xcd, 0x3e, 0xc5, 0x83, 0xfe, 0xe7, 0x8d, 0x84, 0xa9, + 0xe1, 0x16, 0xa4, 0xbd, 0x4d, 0x08, 0x47, 0x8f, 0xa1, 0x1c, 0x91, 0x3e, 0x3e, 0x25, 0x41, 0x72, + 0xfa, 0xbc, 0xee, 0x39, 0xe3, 0x8e, 0x8f, 0xbf, 0x0d, 0x25, 0xdf, 0x17, 0xe3, 0xb8, 0xa6, 0xb2, + 0x31, 0x4b, 0x6b, 0x0f, 0x6f, 0xc9, 0xb6, 0xc9, 0x34, 0xf8, 0x49, 0xd6, 0xd1, 0x11, 0x2c, 0xa4, + 0x7e, 0x3c, 0x43, 0x75, 0xa5, 0xaa, 0xa6, 0x2d, 0xad, 0xb5, 0x6e, 0x61, 0x9b, 0x7a, 0x6c, 0xb8, + 0x65, 0x3a, 0xf5, 0xfa, 0xf8, 0x0a, 0x50, 0x5a, 0xe7, 0x86, 0x1c, 0xea, 0xd9, 0x66, 0x69, 0xad, + 0x7d, 0x0b, 0xf9, 0xf4, 0x35, 0xef, 0xda, 0x6c, 0xfa, 0xe2, 0xaf, 0x02, 0x50, 0xee, 0x92, 0xe3, + 0x51, 0x18, 0x90, 0x40, 0x35, 0x40, 0xc1, 0x4d, 0x79, 0x9e, 0x7e, 0x0b, 0x30, 0x91, 0x17, 0x42, + 0x30, 0xbf, 0x4f, 0xc2, 0x80, 0x86, 0x5d, 0xb3, 0x6f, 0x3b, 0x83, 0x16, 0xa1, 0x6c, 0x7c, 0x71, + 0x38, 0xdb, 0x42, 0x0b, 0x30, 0x17, 0x8f, 0xde, 0xd0, 0x90, 0x04, 0x76, 0x56, 0xba, 0xcc, 0x3a, + 0x97, 0x9c, 0x90, 0x48, 0xd8, 0x39, 0x34, 0x0b, 0x05, 0x6d, 0x93, 0xc0, 0xbe, 0x8b, 0x4a, 0x30, + 0xb3, 0xae, 0xff, 0x56, 0x76, 0x7e, 0x39, 0xf7, 0xd3, 0x0f, 0x55, 0xeb, 0xe9, 0x2b, 0xa8, 0x5c, + 0xd5, 0x42, 0xc8, 0x86, 0xd9, 0x5d, 0x26, 0x92, 0x7f, 0xb7, 0x9d, 0x41, 0x73, 0x50, 0x9c, 0x0c, + 0x2d, 0xc9, 0xbc, 0x35, 0x26, 0xfe, 0x48, 0x92, 0xdd, 0xd1, 0x64, 0x1b, 0xaf, 0xde, 0x9f, 0x57, + 0xad, 0x0f, 0xe7, 0x55, 0xeb, 0xd7, 0xf3, 0xaa, 0xf5, 0xdd, 0x45, 0x35, 0xf3, 0xe1, 0xa2, 0x9a, + 0xf9, 0xf9, 0xa2, 0x9a, 0x39, 0x5a, 0x4d, 0xe9, 0x4e, 0xe6, 0x71, 0x45, 0xbf, 0x35, 0xe3, 0x94, + 0xb6, 0xc7, 0xed, 0xd4, 0x0b, 0x54, 0xc9, 0xb0, 0x93, 0x57, 0xef, 0xc5, 0x67, 0x7f, 0x06, 0x00, + 0x00, 0xff, 0xff, 0x7f, 0xd3, 0x57, 0x96, 0x9c, 0x0a, 0x00, 0x00, } func (m *InboundTxParams) Marshal() (dAtA []byte, err error) { @@ -934,6 +939,16 @@ func (m *CrossChainTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.IsRefunded { + i-- + if m.IsRefunded { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x58 + } if len(m.OutboundTxParams) > 0 { for iNdEx := len(m.OutboundTxParams) - 1; iNdEx >= 0; iNdEx-- { { @@ -1184,6 +1199,9 @@ func (m *CrossChainTx) Size() (n int) { n += 1 + l + sovCrossChainTx(uint64(l)) } } + if m.IsRefunded { + n += 2 + } return n } @@ -2431,6 +2449,26 @@ func (m *CrossChainTx) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsRefunded", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsRefunded = bool(v != 0) default: iNdEx = preIndex skippy, err := skipCrossChainTx(dAtA[iNdEx:]) diff --git a/x/crosschain/types/status.go b/x/crosschain/types/status.go index b4b1149d0a..1364e5946c 100644 --- a/x/crosschain/types/status.go +++ b/x/crosschain/types/status.go @@ -11,7 +11,7 @@ func (m *Status) ChangeStatus(newStatus CctxStatus, msg string) { } if !m.ValidateTransition(newStatus) { m.StatusMessage = fmt.Sprintf("Failed to transition : OldStatus %s , NewStatus %s , MSG : %s :", m.Status.String(), newStatus.String(), msg) - m.Status = CctxStatus_Aborted_Refundable + m.Status = CctxStatus_Aborted return } m.Status = newStatus @@ -37,19 +37,19 @@ func stateTransitionMap() map[CctxStatus][]CctxStatus { stateTransitionMap := make(map[CctxStatus][]CctxStatus) stateTransitionMap[CctxStatus_PendingInbound] = []CctxStatus{ CctxStatus_PendingOutbound, - CctxStatus_Aborted_Refundable, + CctxStatus_Aborted, CctxStatus_OutboundMined, // EVM Deposit CctxStatus_PendingRevert, // EVM Deposit contract call reverted; should refund } stateTransitionMap[CctxStatus_PendingOutbound] = []CctxStatus{ - CctxStatus_Aborted_Refundable, + CctxStatus_Aborted, CctxStatus_PendingRevert, CctxStatus_OutboundMined, CctxStatus_Reverted, } stateTransitionMap[CctxStatus_PendingRevert] = []CctxStatus{ - CctxStatus_Aborted_Refundable, + CctxStatus_Aborted, CctxStatus_OutboundMined, CctxStatus_Reverted, } From acc3cc47a6a35a3f0ab4c33c1879cdb71838e85a Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 6 Feb 2024 19:21:08 -0500 Subject: [PATCH 04/50] implement refund functions --- x/crosschain/keeper/cctx_utils.go | 73 ----------- .../keeper/msg_server_refund_aborted_tx.go | 2 +- .../keeper/msg_server_vote_inbound_tx.go | 2 +- x/crosschain/keeper/refund.go | 114 ++++++++++++++++++ 4 files changed, 116 insertions(+), 75 deletions(-) create mode 100644 x/crosschain/keeper/refund.go diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index a640db827d..31422b7e63 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -51,79 +51,6 @@ func (k Keeper) UpdateNonce(ctx sdk.Context, receiveChainID int64, cctx *types.C return nil } -func (k Keeper) RefundAmountOnZetaChain(ctx sdk.Context, cctx types.CrossChainTx) error { - coinType := cctx.InboundTxParams.CoinType - switch coinType { - case common.CoinType_Gas: - return k.RefundAmountOnZetaChainGas(ctx, cctx) - case common.CoinType_Zeta: - return k.RefundAmountOnZetaChainZeta(ctx, cctx) - case common.CoinType_ERC20: - return k.RefundAmountOnZetaChainERC20(ctx, cctx) - default: - return errors.New("unsupported coin type for refund on ZetaChain") - } -} - -// RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype gas -func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChainTx) error { - return nil -} - -// RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype zeta -func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossChainTx) error { - // if coin type is Zeta, handle this as a deposit ZETA to zEVM. - // deposit the amount to the tx orgin instead of receiver as this is a refund - to := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) - if to == (ethcommon.Address{}) { - return errors.New("invalid receiver address") - } - if cctx.InboundTxParams.Amount.IsNil() || cctx.InboundTxParams.Amount.IsZero() { - return errors.New("no amount to refund") - } - if err := k.fungibleKeeper.DepositCoinZeta(ctx, to, cctx.InboundTxParams.Amount.BigInt()); err != nil { - return errors.New("failed to deposit zeta on ZetaChain" + err.Error()) - } - return nil -} - -// RefundAmountOnZetaChainERC20 refunds the amount of the cctx on ZetaChain in case of aborted cctx -// NOTE: GetCurrentOutTxParam should contain the last up to date cctx amount -func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossChainTx) error { - inputAmount := cctx.InboundTxParams.Amount - // preliminary checks - if cctx.InboundTxParams.CoinType != common.CoinType_ERC20 { - return errors.New("unsupported coin type for refund on ZetaChain") - } - if !common.IsEVMChain(cctx.InboundTxParams.SenderChainId) { - return errors.New("only EVM chains are supported for refund on ZetaChain") - } - sender := ethcommon.HexToAddress(cctx.InboundTxParams.Sender) - if sender == (ethcommon.Address{}) { - return errors.New("invalid sender address") - } - if inputAmount.IsNil() || inputAmount.IsZero() { - return errors.New("no amount to refund") - } - - // get address of the zrc20 - fc, found := k.fungibleKeeper.GetForeignCoinFromAsset(ctx, cctx.InboundTxParams.Asset, cctx.InboundTxParams.SenderChainId) - if !found { - return fmt.Errorf("asset %s zrc not found", cctx.InboundTxParams.Asset) - } - zrc20 := ethcommon.HexToAddress(fc.Zrc20ContractAddress) - if zrc20 == (ethcommon.Address{}) { - return fmt.Errorf("asset %s invalid zrc address", cctx.InboundTxParams.Asset) - } - - // deposit the amount to the sender - if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, sender, inputAmount.BigInt()); err != nil { - return errors.New("failed to deposit zrc20 on ZetaChain" + err.Error()) - } - - return nil -} - // GetRevertGasLimit returns the gas limit for the revert transaction in a CCTX // It returns 0 if there is no error but the gas limit can't be determined from the CCTX data func (k Keeper) GetRevertGasLimit(ctx sdk.Context, cctx types.CrossChainTx) (uint64, error) { diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 007165744e..795782826c 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -27,7 +27,7 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund } // refund the amount - err := k.RefundAmountOnZetaChain(ctx, cctx) + err := k.RefundAbortedAmountOnZetaChain(ctx, cctx) if err != nil { return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) } diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index bd42a2e1ce..106240c951 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -194,7 +194,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg // in this gas we should refund the sender on ZetaChain if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { - if err := k.RefundAmountOnZetaChainERC20(ctx, cctx); err != nil { + if err := k.RefundAbortedAmountOnZetaChain(ctx, cctx); err != nil { // log the error k.Logger(ctx).Error("failed to refund amount of aborted cctx on ZetaChain", "error", err, diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go new file mode 100644 index 0000000000..c068192557 --- /dev/null +++ b/x/crosschain/keeper/refund.go @@ -0,0 +1,114 @@ +package keeper + +import ( + "errors" + "fmt" + + cosmoserrors "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +func (k Keeper) RefundAbortedAmountOnZetaChain(ctx sdk.Context, cctx types.CrossChainTx) error { + coinType := cctx.InboundTxParams.CoinType + switch coinType { + case common.CoinType_Gas: + return k.RefundAmountOnZetaChainGas(ctx, cctx) + case common.CoinType_Zeta: + return k.RefundAmountOnZetaChainZeta(ctx, cctx) + case common.CoinType_ERC20: + return k.RefundAmountOnZetaChainERC20(ctx, cctx) + default: + return errors.New("unsupported coin type for refund on ZetaChain") + } +} + +// RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype gas +func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChainTx) error { + // refund in gas token of a sender chain to the tx origin + chainID := cctx.InboundTxParams.SenderChainId + amountOfGasTokenLocked := cctx.InboundTxParams.Amount + refundTo := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) + if refundTo == (ethcommon.Address{}) { + return errors.New("invalid address for refund") + } + if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { + return zetaObserverTypes.ErrSupportedChains + } + fcSenderChain, found := k.fungibleKeeper.GetGasCoinForForeignCoin(ctx, chainID) + if !found { + return types.ErrForeignCoinNotFound + } + zrc20 := ethcommon.HexToAddress(fcSenderChain.Zrc20ContractAddress) + if zrc20 == (ethcommon.Address{}) { + return cosmoserrors.Wrapf(types.ErrForeignCoinNotFound, "zrc20 contract address not found for chain %d", chainID) + } + // Calcualte amount ot zeta to refund to the tx origin + zetaAmount, err := k.fungibleKeeper.QueryUniswapV2RouterGetZetaAmountsIn(ctx, amountOfGasTokenLocked.BigInt(), zrc20) + if err != nil { + return cosmoserrors.Wrapf(fungibletypes.ErrContractCall, err.Error()) + } + // deposit the amount to the tx orgin instead of receiver as this is a refund + if err := k.fungibleKeeper.DepositCoinZeta(ctx, refundTo, zetaAmount); err != nil { + return errors.New("failed to refund zeta on ZetaChain" + err.Error()) + } + return nil +} + +// RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype zeta +func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossChainTx) error { + // if coin type is Zeta, handle this as a deposit ZETA to zEVM. + // deposit the amount to the tx orgin instead of receiver as this is a refund + to := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) + if to == (ethcommon.Address{}) { + return errors.New("invalid receiver address") + } + if cctx.InboundTxParams.Amount.IsNil() || cctx.InboundTxParams.Amount.IsZero() { + return errors.New("no amount to refund") + } + if err := k.fungibleKeeper.DepositCoinZeta(ctx, to, cctx.InboundTxParams.Amount.BigInt()); err != nil { + return errors.New("failed to refund zeta on ZetaChain" + err.Error()) + } + return nil +} + +// RefundAmountOnZetaChainERC20 refunds the amount of the cctx on ZetaChain in case of aborted cctx +// NOTE: GetCurrentOutTxParam should contain the last up to date cctx amount +func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossChainTx) error { + inputAmount := cctx.InboundTxParams.Amount + // preliminary checks + if cctx.InboundTxParams.CoinType != common.CoinType_ERC20 { + return errors.New("unsupported coin type for refund on ZetaChain") + } + if !common.IsEVMChain(cctx.InboundTxParams.SenderChainId) { + return errors.New("only EVM chains are supported for refund on ZetaChain") + } + sender := ethcommon.HexToAddress(cctx.InboundTxParams.Sender) + if sender == (ethcommon.Address{}) { + return errors.New("invalid sender address") + } + if inputAmount.IsNil() || inputAmount.IsZero() { + return errors.New("no amount to refund") + } + + // get address of the zrc20 + fc, found := k.fungibleKeeper.GetForeignCoinFromAsset(ctx, cctx.InboundTxParams.Asset, cctx.InboundTxParams.SenderChainId) + if !found { + return fmt.Errorf("asset %s zrc not found", cctx.InboundTxParams.Asset) + } + zrc20 := ethcommon.HexToAddress(fc.Zrc20ContractAddress) + if zrc20 == (ethcommon.Address{}) { + return fmt.Errorf("asset %s invalid zrc address", cctx.InboundTxParams.Asset) + } + + // deposit the amount to the sender + if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, sender, inputAmount.BigInt()); err != nil { + return errors.New("failed to deposit zrc20 on ZetaChain" + err.Error()) + } + + return nil +} From c48e31be6601343252f43951bd0160b600cdbfdc Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 6 Feb 2024 19:23:12 -0500 Subject: [PATCH 05/50] add check for is refunded flag --- x/crosschain/keeper/msg_server_refund_aborted_tx.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 795782826c..33e62dbe64 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -25,12 +25,17 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund if cctx.CctxStatus.Status != types.CctxStatus_Aborted { return nil, errorsmod.Wrap(types.ErrInvalidStatus, "CCTX is not aborted") } + // check if the cctx is not refunded + if cctx.IsRefunded { + return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, "CCTX is already refunded") + } // refund the amount err := k.RefundAbortedAmountOnZetaChain(ctx, cctx) if err != nil { return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) } - + cctx.IsRefunded = true + k.SetCrossChainTx(ctx, cctx) return &types.MsgRefundAbortedCCTXResponse{}, nil } From b64c139b000831b3e22de0c7723f5b9e5b77cb3e Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 7 Feb 2024 00:52:34 -0500 Subject: [PATCH 06/50] fix unit tests --- .../smoketest/smoketests/test_erc20_refund.go | 2 +- .../smoketests/test_message_passing.go | 2 +- .../orchestrator/smoketest/utils/zetacore.go | 2 +- testutil/sample/crosschain.go | 6 ++++-- x/crosschain/keeper/grpc_query_cctx_test.go | 4 ++-- .../keeper/msg_server_abort_stuck_cctx_test.go | 18 +++++++++--------- .../keeper/msg_server_refund_aborted_tx.go | 4 ++++ .../keeper/msg_server_update_tss_test.go | 12 ++++++------ x/crosschain/keeper/zeta_accounting.go | 12 ++++++++++++ 9 files changed, 40 insertions(+), 22 deletions(-) diff --git a/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go b/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go index 5a72270dfa..7834baacfa 100644 --- a/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go +++ b/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go @@ -32,7 +32,7 @@ func TestERC20DepositAndCallRefund(sm *runner.SmokeTestRunner) { // There is no liquidity pool, therefore the cctx should abort cctx := utils.WaitCctxMinedByInTxHash(sm.Ctx, inTxHash, sm.CctxClient, sm.Logger, sm.CctxTimeout) - if cctx.CctxStatus.Status != types.CctxStatus_Aborted_Refundable { + if cctx.CctxStatus.Status != types.CctxStatus_Aborted { panic(fmt.Sprintf("expected cctx status to be Aborted; got %s", cctx.CctxStatus.Status)) } diff --git a/contrib/localnet/orchestrator/smoketest/smoketests/test_message_passing.go b/contrib/localnet/orchestrator/smoketest/smoketests/test_message_passing.go index ac3fd49268..0ca5ae987b 100644 --- a/contrib/localnet/orchestrator/smoketest/smoketests/test_message_passing.go +++ b/contrib/localnet/orchestrator/smoketest/smoketests/test_message_passing.go @@ -146,7 +146,7 @@ func TestMessagePassingRevertFail(sm *runner.SmokeTestRunner) { if receipt.Status != 0 { panic("expected revert tx to fail") } - if cctx.CctxStatus.Status != cctxtypes.CctxStatus_Aborted_Refundable { + if cctx.CctxStatus.Status != cctxtypes.CctxStatus_Aborted { panic("expected cctx to be aborted") } } diff --git a/contrib/localnet/orchestrator/smoketest/utils/zetacore.go b/contrib/localnet/orchestrator/smoketest/utils/zetacore.go index 9f6e022dc7..2ec8074354 100644 --- a/contrib/localnet/orchestrator/smoketest/utils/zetacore.go +++ b/contrib/localnet/orchestrator/smoketest/utils/zetacore.go @@ -99,7 +99,7 @@ func WaitCctxsMinedByInTxHash( func IsTerminalStatus(status crosschaintypes.CctxStatus) bool { return status == crosschaintypes.CctxStatus_OutboundMined || - status == crosschaintypes.CctxStatus_Aborted_Refundable || + status == crosschaintypes.CctxStatus_Aborted || status == crosschaintypes.CctxStatus_Reverted } diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index 907ea7dc3f..f31da030f6 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -75,13 +75,15 @@ func Status(t *testing.T, index string) *types.Status { LastUpdateTimestamp: r.Int63(), } } - +func GetCctxHash(index string) string { + return crypto.Keccak256Hash([]byte(index)).String() +} func CrossChainTx(t *testing.T, index string) *types.CrossChainTx { r := newRandFromStringSeed(t, index) return &types.CrossChainTx{ Creator: AccAddress(), - Index: crypto.Keccak256Hash([]byte(index)).String(), + Index: GetCctxHash(index), ZetaFees: math.NewUint(uint64(r.Int63())), RelayedMessage: StringRandom(r, 32), CctxStatus: Status(t, index), diff --git a/x/crosschain/keeper/grpc_query_cctx_test.go b/x/crosschain/keeper/grpc_query_cctx_test.go index cd5d1e3c14..2c6c29d8c7 100644 --- a/x/crosschain/keeper/grpc_query_cctx_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_test.go @@ -135,12 +135,12 @@ func TestKeeper_CctxListPending(t *testing.T) { cctxs := createCctxWithNonceRange(t, ctx, *k, 1000, 2000, chainID, tss, zk) // set some cctxs as pending below nonce - cctx1, found := k.GetCrossChainTx(ctx, "940") + cctx1, found := k.GetCrossChainTx(ctx, sample.GetCctxHash("940")) require.True(t, found) cctx1.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, cctx1) - cctx2, found := k.GetCrossChainTx(ctx, "955") + cctx2, found := k.GetCrossChainTx(ctx, sample.GetCctxHash("955")) require.True(t, found) cctx2.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, cctx2) diff --git a/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go b/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go index f9b7c380e0..0ee02ff129 100644 --- a/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go +++ b/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go @@ -29,11 +29,11 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { // abort the cctx _, err := msgServer.AbortStuckCCTX(ctx, &crosschaintypes.MsgAbortStuckCCTX{ Creator: admin, - CctxIndex: "cctx_index", + CctxIndex: sample.GetCctxHash("cctx_index"), }) require.NoError(t, err) - cctxFound, found := k.GetCrossChainTx(ctx, "cctx_index") + cctxFound, found := k.GetCrossChainTx(ctx, sample.GetCctxHash("cctx_index")) require.True(t, found) require.Equal(t, crosschaintypes.CctxStatus_Aborted, cctxFound.CctxStatus.Status) require.Equal(t, crosschainkeeper.AbortMessage, cctxFound.CctxStatus.StatusMessage) @@ -56,11 +56,11 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { // abort the cctx _, err := msgServer.AbortStuckCCTX(ctx, &crosschaintypes.MsgAbortStuckCCTX{ Creator: admin, - CctxIndex: "cctx_index", + CctxIndex: sample.GetCctxHash("cctx_index"), }) require.NoError(t, err) - cctxFound, found := k.GetCrossChainTx(ctx, "cctx_index") + cctxFound, found := k.GetCrossChainTx(ctx, sample.GetCctxHash("cctx_index")) require.True(t, found) require.Equal(t, crosschaintypes.CctxStatus_Aborted, cctxFound.CctxStatus.Status) require.Equal(t, crosschainkeeper.AbortMessage, cctxFound.CctxStatus.StatusMessage) @@ -83,11 +83,11 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { // abort the cctx _, err := msgServer.AbortStuckCCTX(ctx, &crosschaintypes.MsgAbortStuckCCTX{ Creator: admin, - CctxIndex: "cctx_index", + CctxIndex: sample.GetCctxHash("cctx_index"), }) require.NoError(t, err) - cctxFound, found := k.GetCrossChainTx(ctx, "cctx_index") + cctxFound, found := k.GetCrossChainTx(ctx, sample.GetCctxHash("cctx_index")) require.True(t, found) require.Equal(t, crosschaintypes.CctxStatus_Aborted, cctxFound.CctxStatus.Status) require.Equal(t, crosschainkeeper.AbortMessage, cctxFound.CctxStatus.StatusMessage) @@ -108,7 +108,7 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { // abort the cctx _, err := msgServer.AbortStuckCCTX(ctx, &crosschaintypes.MsgAbortStuckCCTX{ Creator: sample.AccAddress(), - CctxIndex: "cctx_index", + CctxIndex: sample.GetCctxHash("cctx_index"), }) require.ErrorIs(t, err, observertypes.ErrNotAuthorized) }) @@ -122,7 +122,7 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { // abort the cctx _, err := msgServer.AbortStuckCCTX(ctx, &crosschaintypes.MsgAbortStuckCCTX{ Creator: admin, - CctxIndex: "cctx_index", + CctxIndex: sample.GetCctxHash("cctx_index"), }) require.ErrorIs(t, err, crosschaintypes.ErrCannotFindCctx) }) @@ -144,7 +144,7 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { // abort the cctx _, err := msgServer.AbortStuckCCTX(ctx, &crosschaintypes.MsgAbortStuckCCTX{ Creator: admin, - CctxIndex: "cctx_index", + CctxIndex: sample.GetCctxHash("cctx_index"), }) require.ErrorIs(t, err, crosschaintypes.ErrStatusNotPending) }) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 33e62dbe64..3e37d8b316 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -3,6 +3,7 @@ package keeper import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" observertypes "github.com/zeta-chain/zetacore/x/observer/types" "golang.org/x/net/context" @@ -37,5 +38,8 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund } cctx.IsRefunded = true k.SetCrossChainTx(ctx, cctx) + if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { + k.RemoveZetaAbortedAmount(ctx, cctx.GetCurrentOutTxParam().Amount) + } return &types.MsgRefundAbortedCCTXResponse{}, nil } diff --git a/x/crosschain/keeper/msg_server_update_tss_test.go b/x/crosschain/keeper/msg_server_update_tss_test.go index 9d1207d427..5ed175dd88 100644 --- a/x/crosschain/keeper/msg_server_update_tss_test.go +++ b/x/crosschain/keeper/msg_server_update_tss_test.go @@ -28,7 +28,7 @@ func TestMsgServer_UpdateTssAddress(t *testing.T) { index := chain.ChainName.String() + "_migration_tx_index" k.GetObserverKeeper().SetFundMigrator(ctx, types.TssFundMigratorInfo{ ChainId: chain.ChainId, - MigrationCctxIndex: index, + MigrationCctxIndex: sample.GetCctxHash(index), }) cctx := sample.CrossChainTx(t, index) cctx.CctxStatus.Status = crosschaintypes.CctxStatus_OutboundMined @@ -60,7 +60,7 @@ func TestMsgServer_UpdateTssAddress(t *testing.T) { index := chain.ChainName.String() + "_migration_tx_index" k.GetObserverKeeper().SetFundMigrator(ctx, types.TssFundMigratorInfo{ ChainId: chain.ChainId, - MigrationCctxIndex: index, + MigrationCctxIndex: sample.GetCctxHash(index), }) cctx := sample.CrossChainTx(t, index) cctx.CctxStatus.Status = crosschaintypes.CctxStatus_OutboundMined @@ -91,7 +91,7 @@ func TestMsgServer_UpdateTssAddress(t *testing.T) { index := chain.ChainName.String() + "_migration_tx_index" k.GetObserverKeeper().SetFundMigrator(ctx, types.TssFundMigratorInfo{ ChainId: chain.ChainId, - MigrationCctxIndex: index, + MigrationCctxIndex: sample.GetCctxHash(index), }) cctx := sample.CrossChainTx(t, index) cctx.CctxStatus.Status = crosschaintypes.CctxStatus_OutboundMined @@ -128,7 +128,7 @@ func TestMsgServer_UpdateTssAddress(t *testing.T) { index := chain.ChainName.String() + "_migration_tx_index" k.GetObserverKeeper().SetFundMigrator(ctx, types.TssFundMigratorInfo{ ChainId: chain.ChainId, - MigrationCctxIndex: index, + MigrationCctxIndex: sample.GetCctxHash(index), }) cctx := sample.CrossChainTx(t, index) cctx.CctxStatus.Status = crosschaintypes.CctxStatus_OutboundMined @@ -165,7 +165,7 @@ func TestMsgServer_UpdateTssAddress(t *testing.T) { index := chain.ChainName.String() + "_migration_tx_index" k.GetObserverKeeper().SetFundMigrator(ctx, types.TssFundMigratorInfo{ ChainId: chain.ChainId, - MigrationCctxIndex: index, + MigrationCctxIndex: sample.GetCctxHash(index), }) cctx := sample.CrossChainTx(t, index) cctx.CctxStatus.Status = crosschaintypes.CctxStatus_PendingOutbound @@ -202,7 +202,7 @@ func TestMsgServer_UpdateTssAddress(t *testing.T) { index := chain.ChainName.String() + "_migration_tx_index" k.GetObserverKeeper().SetFundMigrator(ctx, types.TssFundMigratorInfo{ ChainId: chain.ChainId, - MigrationCctxIndex: index, + MigrationCctxIndex: sample.GetCctxHash(index), }) } assert.Equal(t, len(k.GetObserverKeeper().GetAllTssFundMigrators(ctx)), len(k.GetObserverKeeper().GetSupportedChains(ctx))) diff --git a/x/crosschain/keeper/zeta_accounting.go b/x/crosschain/keeper/zeta_accounting.go index ee3184b5e3..ffddc8ba1f 100644 --- a/x/crosschain/keeper/zeta_accounting.go +++ b/x/crosschain/keeper/zeta_accounting.go @@ -33,3 +33,15 @@ func (k Keeper) AddZetaAbortedAmount(ctx sdk.Context, amount sdkmath.Uint) { } k.SetZetaAccounting(ctx, zetaAccounting) } + +func (k Keeper) RemoveZetaAbortedAmount(ctx sdk.Context, amount sdkmath.Uint) { + zetaAccounting, found := k.GetZetaAccounting(ctx) + if !found { + return + } + if zetaAccounting.AbortedZetaAmount.LT(amount) { + return + } + zetaAccounting.AbortedZetaAmount = zetaAccounting.AbortedZetaAmount.Sub(amount) + k.SetZetaAccounting(ctx, zetaAccounting) +} From 9e9f69823e35913a0cb38350ee7a5b96997666d7 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 7 Feb 2024 01:03:04 -0500 Subject: [PATCH 07/50] mint zrc20 gas instead of zeta for gas refunds --- x/crosschain/keeper/refund.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index c068192557..16286ba0c1 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -9,7 +9,6 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" - fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" ) @@ -47,13 +46,8 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai if zrc20 == (ethcommon.Address{}) { return cosmoserrors.Wrapf(types.ErrForeignCoinNotFound, "zrc20 contract address not found for chain %d", chainID) } - // Calcualte amount ot zeta to refund to the tx origin - zetaAmount, err := k.fungibleKeeper.QueryUniswapV2RouterGetZetaAmountsIn(ctx, amountOfGasTokenLocked.BigInt(), zrc20) - if err != nil { - return cosmoserrors.Wrapf(fungibletypes.ErrContractCall, err.Error()) - } // deposit the amount to the tx orgin instead of receiver as this is a refund - if err := k.fungibleKeeper.DepositCoinZeta(ctx, refundTo, zetaAmount); err != nil { + if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundTo, amountOfGasTokenLocked.BigInt()); err != nil { return errors.New("failed to refund zeta on ZetaChain" + err.Error()) } return nil From e5e1bbd7059f532192fb900e870cce6b4165ac9b Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 7 Feb 2024 01:50:15 -0500 Subject: [PATCH 08/50] add positive tests for refund --- x/crosschain/keeper/cctx_utils_test.go | 127 ------------ .../keeper/msg_server_vote_inbound_tx.go | 4 +- x/crosschain/keeper/refund.go | 2 +- x/crosschain/keeper/refund_test.go | 189 ++++++++++++++++++ 4 files changed, 192 insertions(+), 130 deletions(-) create mode 100644 x/crosschain/keeper/refund_test.go diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index 4d12008188..cba32c6a75 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -4,8 +4,6 @@ import ( "math/big" "testing" - "cosmossdk.io/math" - "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" @@ -14,131 +12,6 @@ import ( fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" ) -func TestKeeper_RefundAmountOnZetaChain(t *testing.T) { - t.Run("should refund amount on zeta chain", func(t *testing.T) { - k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) - k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) - asset := sample.EthAddress().String() - sender := sample.EthAddress() - chainID := getValidEthChainID(t) - - // deploy zrc20 - deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) - zrc20Addr := deployZRC20( - t, - ctx, - zk.FungibleKeeper, - sdkk.EvmKeeper, - chainID, - "bar", - asset, - "bar", - ) - - err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: chainID, - Sender: sender.String(), - Asset: asset, - Amount: math.NewUint(42), - }}, - ) - require.NoError(t, err) - - // check amount deposited in balance - balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, sender) - require.NoError(t, err) - require.Equal(t, uint64(42), balance.Uint64()) - - // can refund again - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: chainID, - Sender: sender.String(), - Asset: asset, - Amount: math.NewUint(42), - }}, - ) - require.NoError(t, err) - balance, err = zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, sender) - require.NoError(t, err) - require.Equal(t, uint64(84), balance.Uint64()) - }) - - t.Run("should fail with invalid cctx", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - - err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Zeta, - Amount: math.NewUint(42), - }}, - ) - require.ErrorContains(t, err, "unsupported coin type") - - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Zeta, - Amount: math.NewUint(42), - }}, - ) - require.ErrorContains(t, err, "unsupported coin type") - - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: 999999, - Amount: math.NewUint(42), - }}, - ) - require.ErrorContains(t, err, "only EVM chains are supported") - - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), - Sender: "invalid", - Amount: math.NewUint(42), - }}, - ) - require.ErrorContains(t, err, "invalid sender address") - - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), - Sender: sample.EthAddress().String(), - Amount: math.Uint{}, - }}, - ) - require.ErrorContains(t, err, "no amount to refund") - - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), - Sender: sample.EthAddress().String(), - Amount: math.ZeroUint(), - }}, - ) - require.ErrorContains(t, err, "no amount to refund") - - // the foreign coin has not been set - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), - Sender: sample.EthAddress().String(), - Asset: sample.EthAddress().String(), - Amount: math.NewUint(42), - }}, - ) - require.ErrorContains(t, err, "zrc not found") - }) -} - func TestGetRevertGasLimit(t *testing.T) { t.Run("should return 0 if no inbound tx params", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 106240c951..6bef9f8a92 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -193,7 +193,6 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg // gas payment for erc20 type might fail because no liquidity pool is defined to swap the zrc20 token into the gas token // in this gas we should refund the sender on ZetaChain if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { - if err := k.RefundAbortedAmountOnZetaChain(ctx, cctx); err != nil { // log the error k.Logger(ctx).Error("failed to refund amount of aborted cctx on ZetaChain", @@ -202,8 +201,9 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg "amount", cctx.InboundTxParams.Amount.String(), ) } + cctx.IsRefunded = true } - cctx.IsRefunded = true + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()+" deposit revert message: "+revertMessage) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index 16286ba0c1..d5616c514a 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -46,7 +46,7 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai if zrc20 == (ethcommon.Address{}) { return cosmoserrors.Wrapf(types.ErrForeignCoinNotFound, "zrc20 contract address not found for chain %d", chainID) } - // deposit the amount to the tx orgin instead of receiver as this is a refund + // deposit the amount to the tx origin instead of receiver as this is a refund if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundTo, amountOfGasTokenLocked.BigInt()); err != nil { return errors.New("failed to refund zeta on ZetaChain" + err.Error()) } diff --git a/x/crosschain/keeper/refund_test.go b/x/crosschain/keeper/refund_test.go new file mode 100644 index 0000000000..074c9ca91a --- /dev/null +++ b/x/crosschain/keeper/refund_test.go @@ -0,0 +1,189 @@ +package keeper_test + +import ( + "fmt" + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/cmd/zetacored/config" + "github.com/zeta-chain/zetacore/common" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" +) + +func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { + t.Run("should refund amount zrc20 gas on zeta chain", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") + + err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: chainID, + Sender: sender.String(), + TxOrigin: sender.String(), + Amount: math.NewUint(42), + }}, + ) + require.NoError(t, err) + balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, sender) + require.NoError(t, err) + require.Equal(t, uint64(42), balance.Uint64()) + }) +} + +func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { + t.Run("should refund amount on zeta chain", func(t *testing.T) { + k, ctx, sdkk, _ := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + + err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: chainID, + Sender: sender.String(), + TxOrigin: sender.String(), + Amount: math.NewUint(42), + }}, + ) + require.NoError(t, err) + coin := sdkk.BankKeeper.GetBalance(ctx, sdk.AccAddress(sender.Bytes()), config.BaseDenom) + fmt.Println(coin.Amount.String()) + require.Equal(t, "42", coin.Amount.String()) + }) +} + +func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { + t.Run("should refund amount on zeta chain", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + asset := sample.EthAddress().String() + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + + // deploy zrc20 + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + zrc20Addr := deployZRC20( + t, + ctx, + zk.FungibleKeeper, + sdkk.EvmKeeper, + chainID, + "bar", + asset, + "bar", + ) + + err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: chainID, + Sender: sender.String(), + Asset: asset, + Amount: math.NewUint(42), + }}, + ) + require.NoError(t, err) + + // check amount deposited in balance + balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, sender) + require.NoError(t, err) + require.Equal(t, uint64(42), balance.Uint64()) + + // can refund again + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: chainID, + Sender: sender.String(), + Asset: asset, + Amount: math.NewUint(42), + }}, + ) + require.NoError(t, err) + balance, err = zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, sender) + require.NoError(t, err) + require.Equal(t, uint64(84), balance.Uint64()) + }) + + t.Run("should fail with invalid cctx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + + err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Zeta, + Amount: math.NewUint(42), + }}, + ) + require.ErrorContains(t, err, "unsupported coin type") + + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Zeta, + Amount: math.NewUint(42), + }}, + ) + require.ErrorContains(t, err, "unsupported coin type") + + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: 999999, + Amount: math.NewUint(42), + }}, + ) + require.ErrorContains(t, err, "only EVM chains are supported") + + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: getValidEthChainID(t), + Sender: "invalid", + Amount: math.NewUint(42), + }}, + ) + require.ErrorContains(t, err, "invalid sender address") + + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: getValidEthChainID(t), + Sender: sample.EthAddress().String(), + Amount: math.Uint{}, + }}, + ) + require.ErrorContains(t, err, "no amount to refund") + + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: getValidEthChainID(t), + Sender: sample.EthAddress().String(), + Amount: math.ZeroUint(), + }}, + ) + require.ErrorContains(t, err, "no amount to refund") + + // the foreign coin has not been set + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: getValidEthChainID(t), + Sender: sample.EthAddress().String(), + Asset: sample.EthAddress().String(), + Amount: math.NewUint(42), + }}, + ) + require.ErrorContains(t, err, "zrc not found") + }) +} From a35fe2dbedb6cf58808aaaae05054404b3e5ec8d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 7 Feb 2024 02:16:48 -0500 Subject: [PATCH 09/50] add btc refund --- proto/crosschain/tx.proto | 1 + .../keeper/msg_server_refund_aborted_tx.go | 14 +- .../keeper/msg_server_vote_inbound_tx.go | 2 +- x/crosschain/keeper/refund.go | 12 +- x/crosschain/types/tx.pb.go | 244 +++++++++++------- 5 files changed, 172 insertions(+), 101 deletions(-) diff --git a/proto/crosschain/tx.proto b/proto/crosschain/tx.proto index 69374a7a31..73860e30f7 100644 --- a/proto/crosschain/tx.proto +++ b/proto/crosschain/tx.proto @@ -167,6 +167,7 @@ message MsgAbortStuckCCTXResponse {} message MsgRefundAbortedCCTX { string creator = 1; string cctx_index = 2; + string receiver_btc_refund = 3; } message MsgRefundAbortedCCTXResponse {} diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 3e37d8b316..71f31208c4 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -32,10 +32,18 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund } // refund the amount - err := k.RefundAbortedAmountOnZetaChain(ctx, cctx) - if err != nil { - return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) + if common.IsEVMChain(cctx.InboundTxParams.SenderChainId) { + err := k.RefundAbortedAmountOnZetaChainForEvmChain(ctx, cctx) + if err != nil { + return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) + } + } else if common.IsBitcoinChain(cctx.InboundTxParams.SenderChainId) { + err := k.RefundAbortedAmountOnZetaChainForBitcoinChain(ctx, cctx, msg.ReceiverBtcRefund) + if err != nil { + return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) + } } + cctx.IsRefunded = true k.SetCrossChainTx(ctx, cctx) if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 6bef9f8a92..7352cd8d84 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -193,7 +193,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg // gas payment for erc20 type might fail because no liquidity pool is defined to swap the zrc20 token into the gas token // in this gas we should refund the sender on ZetaChain if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { - if err := k.RefundAbortedAmountOnZetaChain(ctx, cctx); err != nil { + if err := k.RefundAbortedAmountOnZetaChainForEvmChain(ctx, cctx); err != nil { // log the error k.Logger(ctx).Error("failed to refund amount of aborted cctx on ZetaChain", "error", err, diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index d5616c514a..d41bff1383 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -12,7 +12,7 @@ import ( zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" ) -func (k Keeper) RefundAbortedAmountOnZetaChain(ctx sdk.Context, cctx types.CrossChainTx) error { +func (k Keeper) RefundAbortedAmountOnZetaChainForEvmChain(ctx sdk.Context, cctx types.CrossChainTx) error { coinType := cctx.InboundTxParams.CoinType switch coinType { case common.CoinType_Gas: @@ -26,6 +26,16 @@ func (k Keeper) RefundAbortedAmountOnZetaChain(ctx sdk.Context, cctx types.Cross } } +func (k Keeper) RefundAbortedAmountOnZetaChainForBitcoinChain(ctx sdk.Context, cctx types.CrossChainTx, evmAddressForBtcRefund string) error { + refundTo := ethcommon.HexToAddress(evmAddressForBtcRefund) + if refundTo == (ethcommon.Address{}) { + return errors.New("invalid address for refund") + } + // Set TxOrigin to the supplied address so that the refund is made to the evm address + cctx.InboundTxParams.TxOrigin = refundTo.String() + return k.RefundAmountOnZetaChainGas(ctx, cctx) +} + // RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype gas func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChainTx) error { // refund in gas token of a sender chain to the tx origin diff --git a/x/crosschain/types/tx.pb.go b/x/crosschain/types/tx.pb.go index be52dc057f..0c35a89da6 100644 --- a/x/crosschain/types/tx.pb.go +++ b/x/crosschain/types/tx.pb.go @@ -1351,8 +1351,9 @@ func (m *MsgAbortStuckCCTXResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgAbortStuckCCTXResponse proto.InternalMessageInfo type MsgRefundAbortedCCTX struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` - CctxIndex string `protobuf:"bytes,2,opt,name=cctx_index,json=cctxIndex,proto3" json:"cctx_index,omitempty"` + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + CctxIndex string `protobuf:"bytes,2,opt,name=cctx_index,json=cctxIndex,proto3" json:"cctx_index,omitempty"` + ReceiverBtcRefund string `protobuf:"bytes,3,opt,name=receiver_btc_refund,json=receiverBtcRefund,proto3" json:"receiver_btc_refund,omitempty"` } func (m *MsgRefundAbortedCCTX) Reset() { *m = MsgRefundAbortedCCTX{} } @@ -1402,6 +1403,13 @@ func (m *MsgRefundAbortedCCTX) GetCctxIndex() string { return "" } +func (m *MsgRefundAbortedCCTX) GetReceiverBtcRefund() string { + if m != nil { + return m.ReceiverBtcRefund + } + return "" +} + type MsgRefundAbortedCCTXResponse struct { } @@ -1468,100 +1476,101 @@ func init() { func init() { proto.RegisterFile("crosschain/tx.proto", fileDescriptor_81d6d611190b7635) } var fileDescriptor_81d6d611190b7635 = []byte{ - // 1486 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x5f, 0x4f, 0xdb, 0x56, - 0x14, 0xc7, 0x03, 0x42, 0x72, 0x20, 0x40, 0x0d, 0x6d, 0x53, 0x53, 0x02, 0x35, 0x6b, 0x87, 0x26, - 0x91, 0xb4, 0x54, 0xd3, 0xda, 0x6e, 0x93, 0x06, 0x51, 0x4b, 0xd9, 0x4a, 0xa9, 0x4c, 0xba, 0x4d, - 0x7d, 0xb1, 0x1c, 0xfb, 0xe2, 0x58, 0x24, 0xf7, 0x46, 0xbe, 0xd7, 0x28, 0x41, 0x93, 0x26, 0x55, - 0xda, 0xfb, 0x34, 0x4d, 0xda, 0xb4, 0x2f, 0xb0, 0xaf, 0xd2, 0xc7, 0x6a, 0x4f, 0xeb, 0x1e, 0xaa, - 0xa9, 0x7c, 0x82, 0xed, 0x13, 0x4c, 0xf7, 0x5e, 0xdb, 0xc4, 0x09, 0xf9, 0x03, 0xa8, 0x4f, 0xf1, - 0x39, 0xbe, 0xe7, 0xdf, 0xef, 0x9c, 0x73, 0xcf, 0x89, 0x61, 0xce, 0xf6, 0x09, 0xa5, 0x76, 0xd5, - 0xf2, 0x70, 0x91, 0x35, 0x0b, 0x0d, 0x9f, 0x30, 0xa2, 0x2e, 0x1e, 0x21, 0x66, 0x09, 0x5e, 0x41, - 0x3c, 0x11, 0x1f, 0x15, 0x4e, 0xce, 0x69, 0x73, 0x36, 0xa9, 0xd7, 0x09, 0x2e, 0xca, 0x1f, 0x29, - 0xa3, 0xcd, 0xbb, 0xc4, 0x25, 0xe2, 0xb1, 0xc8, 0x9f, 0x24, 0x57, 0xff, 0x43, 0x81, 0x4b, 0x3b, - 0xd4, 0x2d, 0xf9, 0xc8, 0x62, 0xa8, 0xbc, 0xb7, 0xf7, 0x0d, 0x61, 0xc8, 0x57, 0x73, 0x30, 0x61, - 0x73, 0x0e, 0xf1, 0x73, 0xca, 0xb2, 0xb2, 0x9a, 0x31, 0x22, 0x52, 0x5d, 0x04, 0x60, 0x94, 0x9a, - 0x8d, 0xa0, 0x72, 0x80, 0x5a, 0xb9, 0x0f, 0xc4, 0xcb, 0x0c, 0xa3, 0xf4, 0x99, 0x60, 0xa8, 0x1f, - 0xc3, 0xec, 0x01, 0x6a, 0x6d, 0x21, 0xfc, 0x02, 0x31, 0xeb, 0x31, 0xf2, 0xdc, 0x2a, 0xcb, 0x8d, - 0x2e, 0x2b, 0xab, 0xa3, 0x46, 0x17, 0x5f, 0x5d, 0x83, 0x14, 0x65, 0x16, 0x0b, 0x68, 0x6e, 0x6c, - 0x59, 0x59, 0x9d, 0x5e, 0xbf, 0x5c, 0x08, 0xfd, 0x35, 0x90, 0x8d, 0xbc, 0x43, 0xb4, 0x27, 0x5e, - 0x1a, 0xe1, 0x21, 0x7d, 0x01, 0xae, 0x75, 0x39, 0x6a, 0x20, 0xda, 0x20, 0x98, 0x22, 0xfd, 0x67, - 0x05, 0xd4, 0x1d, 0xea, 0xee, 0x78, 0xae, 0xcf, 0x5f, 0x53, 0xfa, 0x28, 0xc0, 0x0e, 0xed, 0x13, - 0xc7, 0x35, 0x48, 0x0b, 0xac, 0x4c, 0xcf, 0x11, 0x51, 0x8c, 0x1a, 0x13, 0x82, 0xde, 0x76, 0xd4, - 0x2d, 0x48, 0x59, 0x75, 0x12, 0x60, 0xe9, 0x79, 0x66, 0xb3, 0xf8, 0xea, 0xed, 0xd2, 0xc8, 0xdf, - 0x6f, 0x97, 0x3e, 0x72, 0x3d, 0x56, 0x0d, 0x2a, 0xdc, 0xcb, 0xa2, 0x4d, 0x68, 0x9d, 0xd0, 0xf0, - 0x67, 0x8d, 0x3a, 0x07, 0x45, 0xd6, 0x6a, 0x20, 0x5a, 0x78, 0xee, 0x61, 0x66, 0x84, 0xe2, 0xfa, - 0x75, 0xd0, 0xba, 0x7d, 0x8a, 0x5d, 0x7e, 0x0a, 0x73, 0x3b, 0xd4, 0x7d, 0xde, 0x70, 0xe4, 0xcb, - 0x0d, 0xc7, 0xf1, 0x11, 0xa5, 0xe7, 0x86, 0x5e, 0x5f, 0x84, 0x85, 0x53, 0xf4, 0xc5, 0xe6, 0xfe, - 0x55, 0x84, 0xbd, 0x0d, 0xc7, 0x29, 0x93, 0x6d, 0x5c, 0x6e, 0x96, 0x7d, 0xcb, 0x3e, 0xe8, 0x9b, - 0xea, 0x3e, 0x10, 0x5d, 0x85, 0x09, 0xd6, 0x34, 0xab, 0x16, 0xad, 0x4a, 0x8c, 0x8c, 0x14, 0x6b, - 0x3e, 0xb6, 0x68, 0x55, 0x5d, 0x83, 0x8c, 0x4d, 0x3c, 0x6c, 0x72, 0x34, 0xc2, 0xb4, 0xce, 0x46, - 0x69, 0x2d, 0x11, 0x0f, 0x97, 0x5b, 0x0d, 0x64, 0xa4, 0xed, 0xf0, 0x49, 0x5d, 0x81, 0xf1, 0x86, - 0x4f, 0xc8, 0x7e, 0x6e, 0x7c, 0x59, 0x59, 0x9d, 0x5c, 0xcf, 0x46, 0x47, 0x9f, 0x71, 0xa6, 0x21, - 0xdf, 0xf1, 0xb8, 0x2b, 0x35, 0x62, 0x1f, 0x48, 0x7b, 0x29, 0x19, 0xb7, 0xe0, 0x08, 0x93, 0xd7, - 0x20, 0xcd, 0x9a, 0xa6, 0x87, 0x1d, 0xd4, 0xcc, 0x4d, 0x48, 0x37, 0x59, 0x73, 0x9b, 0x93, 0x21, - 0x24, 0x9d, 0x21, 0xc7, 0x90, 0xfc, 0x29, 0x6b, 0xff, 0xdb, 0xaa, 0xc7, 0x50, 0xcd, 0xa3, 0xec, - 0xa1, 0x51, 0x5a, 0xbf, 0xdd, 0x07, 0x90, 0x15, 0xc8, 0x22, 0xdf, 0x5e, 0xbf, 0x6d, 0x5a, 0x12, - 0xdb, 0x30, 0x07, 0x53, 0x82, 0x19, 0xe5, 0xaf, 0x1d, 0xb5, 0xd1, 0x24, 0x6a, 0x2a, 0x8c, 0x61, - 0xab, 0x2e, 0x71, 0xc9, 0x18, 0xe2, 0x59, 0xbd, 0x02, 0x29, 0xda, 0xaa, 0x57, 0x48, 0x4d, 0x40, - 0x90, 0x31, 0x42, 0x4a, 0xd5, 0x20, 0xed, 0x20, 0xdb, 0xab, 0x5b, 0x35, 0x2a, 0x42, 0xce, 0x1a, - 0x31, 0xad, 0x2e, 0x40, 0xc6, 0xb5, 0xa8, 0x59, 0xf3, 0xea, 0x1e, 0x0b, 0x43, 0x4e, 0xbb, 0x16, - 0x7d, 0xc2, 0x69, 0xdd, 0x14, 0x6d, 0x92, 0x8c, 0x29, 0x8a, 0x98, 0x47, 0x70, 0x94, 0x88, 0x40, - 0x46, 0x38, 0x75, 0xd4, 0x1e, 0xc1, 0x22, 0x80, 0x6d, 0xc7, 0x90, 0x86, 0x75, 0xc6, 0x39, 0x12, - 0xd4, 0x37, 0x0a, 0xcc, 0x47, 0xa8, 0xee, 0x06, 0xec, 0x82, 0x95, 0x34, 0x0f, 0xe3, 0x98, 0x60, - 0x1b, 0x09, 0xac, 0xc6, 0x0c, 0x49, 0xb4, 0xd7, 0xd7, 0x58, 0xa2, 0xbe, 0xde, 0x73, 0xc1, 0x7c, - 0x01, 0xd7, 0x4f, 0x0b, 0x2d, 0xc6, 0x6f, 0x11, 0xc0, 0xa3, 0xa6, 0x8f, 0xea, 0xe4, 0x10, 0x39, - 0x22, 0xca, 0xb4, 0x91, 0xf1, 0xa8, 0x21, 0x19, 0xfa, 0xbe, 0xc0, 0x5e, 0x52, 0x8f, 0x7c, 0x52, - 0x7f, 0x4f, 0xf0, 0xe8, 0x2b, 0x70, 0xa3, 0xa7, 0x9d, 0xb8, 0xba, 0x7f, 0x53, 0x60, 0x76, 0x87, - 0xba, 0x5b, 0x16, 0x7d, 0xe6, 0x7b, 0x36, 0x1a, 0x74, 0xb1, 0xf7, 0x77, 0xa2, 0xc1, 0x55, 0x44, - 0x4e, 0x08, 0x42, 0xbd, 0x01, 0x53, 0x12, 0x65, 0x1c, 0xd4, 0x2b, 0xc8, 0x17, 0x89, 0x1a, 0x33, - 0x26, 0x05, 0xef, 0xa9, 0x60, 0x89, 0xe2, 0x0e, 0x1a, 0x8d, 0x5a, 0x2b, 0x2e, 0x6e, 0x41, 0xe9, - 0x1a, 0xe4, 0x3a, 0x3d, 0x8b, 0xdd, 0x7e, 0x33, 0x2e, 0x9a, 0x96, 0x33, 0x77, 0xf1, 0x6e, 0x85, - 0x22, 0xff, 0x10, 0x39, 0xbb, 0x01, 0xab, 0x90, 0x00, 0x3b, 0xe5, 0x66, 0x9f, 0x08, 0x16, 0x40, - 0x54, 0xa9, 0xcc, 0xba, 0x2c, 0xdb, 0x34, 0x67, 0x88, 0xa4, 0x17, 0x60, 0x8e, 0x84, 0xca, 0x4c, - 0xc2, 0xe1, 0x6a, 0xbf, 0xbd, 0x2e, 0x91, 0x13, 0x3b, 0x65, 0x79, 0xfe, 0x73, 0xd0, 0x3a, 0xce, - 0xcb, 0x02, 0x92, 0x23, 0x4d, 0xc6, 0x9a, 0x4b, 0x88, 0x6d, 0x9e, 0xbc, 0x57, 0x3f, 0x81, 0xab, - 0x1d, 0xd2, 0xbc, 0x61, 0x03, 0x8a, 0x9c, 0x1c, 0x08, 0xd1, 0xf9, 0x84, 0xe8, 0x96, 0x45, 0x9f, - 0x53, 0xe4, 0xa8, 0x47, 0xa0, 0x77, 0x88, 0xa1, 0xfd, 0x7d, 0x64, 0x33, 0xef, 0x10, 0x09, 0x05, - 0x32, 0x0b, 0x93, 0x62, 0x2a, 0x15, 0xc2, 0xa9, 0x74, 0x6b, 0x88, 0xa9, 0xb4, 0x8d, 0x99, 0x91, - 0x4f, 0x58, 0x7c, 0x18, 0xe9, 0x8d, 0x92, 0xa0, 0x7e, 0x35, 0xc0, 0xb6, 0xbc, 0x6d, 0xa6, 0x84, - 0xf7, 0xbd, 0x75, 0x89, 0x3b, 0x48, 0x25, 0x30, 0x7d, 0x68, 0xd5, 0x02, 0x64, 0xfa, 0x72, 0x92, - 0x3b, 0x32, 0xff, 0x9b, 0x8f, 0xcf, 0x38, 0x49, 0xff, 0x7b, 0xbb, 0x74, 0xb9, 0x65, 0xd5, 0x6b, - 0x0f, 0xf4, 0xa4, 0x3a, 0xdd, 0xc8, 0x0a, 0x46, 0xb8, 0x28, 0x38, 0x6d, 0xab, 0x44, 0x6a, 0x88, - 0x55, 0x42, 0x5d, 0x82, 0x49, 0x19, 0xa2, 0xa8, 0xf0, 0xf0, 0x12, 0x00, 0xc1, 0x2a, 0x71, 0x8e, - 0x7a, 0x0b, 0x66, 0xe4, 0x01, 0x3e, 0x70, 0x65, 0x03, 0xa6, 0x45, 0xe4, 0x59, 0xc1, 0x2e, 0x53, - 0xfa, 0x54, 0xdc, 0x53, 0x89, 0x71, 0x97, 0x19, 0x34, 0xee, 0xf4, 0x9b, 0xb0, 0xd2, 0xa7, 0xb4, - 0xe3, 0x16, 0x78, 0x39, 0x26, 0x16, 0x87, 0xe4, 0xb9, 0x6d, 0x3c, 0xb8, 0x03, 0x78, 0xbf, 0x21, - 0xec, 0x20, 0x3f, 0x2c, 0xff, 0x90, 0xe2, 0xe1, 0xc8, 0x27, 0xb3, 0x63, 0x34, 0x65, 0x25, 0xbb, - 0x14, 0x36, 0xba, 0x06, 0xe9, 0x10, 0x62, 0x3f, 0xbc, 0x77, 0x63, 0x5a, 0xbd, 0x09, 0xd3, 0xd1, - 0x73, 0x08, 0xdb, 0xb8, 0x54, 0x11, 0x71, 0x25, 0x72, 0x27, 0xcb, 0x53, 0xea, 0x42, 0xcb, 0x13, - 0x8f, 0xb2, 0x8e, 0x28, 0xb5, 0x5c, 0x09, 0x7d, 0xc6, 0x88, 0x48, 0xf5, 0x3a, 0x00, 0x87, 0x3c, - 0xec, 0xe0, 0x8c, 0xf4, 0xd3, 0xc3, 0x61, 0xe3, 0xde, 0x82, 0x19, 0x0f, 0x9b, 0xe1, 0xfd, 0x2f, - 0xbb, 0x55, 0xb6, 0x5c, 0xd6, 0xc3, 0xed, 0x2d, 0x9a, 0x18, 0xa2, 0x93, 0xe2, 0x44, 0x3c, 0x44, - 0x93, 0x79, 0x9d, 0x1a, 0xb8, 0xc6, 0x2c, 0x40, 0x86, 0x35, 0x4d, 0xe2, 0x7b, 0xae, 0x87, 0x73, - 0x59, 0xe9, 0x10, 0x6b, 0xee, 0x0a, 0x9a, 0xdf, 0x9e, 0x16, 0xa5, 0x88, 0xe5, 0xa6, 0xc5, 0x0b, - 0x49, 0xf0, 0x12, 0x44, 0x87, 0x08, 0xb3, 0x70, 0x0e, 0xcd, 0x08, 0x07, 0x40, 0xb0, 0xe4, 0x28, - 0xfa, 0x10, 0xf4, 0xde, 0x35, 0x10, 0x97, 0xca, 0x13, 0xb1, 0xc1, 0x6c, 0x54, 0x88, 0xcf, 0xf6, - 0x58, 0x60, 0x1f, 0x94, 0x4a, 0xe5, 0xef, 0xfa, 0xaf, 0x90, 0xfd, 0x46, 0xbb, 0x5c, 0xb1, 0x93, - 0xda, 0x62, 0x53, 0xbb, 0x62, 0xec, 0x1b, 0x68, 0x3f, 0xc0, 0x8e, 0x38, 0x82, 0x9c, 0x8b, 0x59, - 0xcb, 0x8b, 0x61, 0xdb, 0xa5, 0x30, 0x32, 0xb8, 0x7e, 0x3c, 0x05, 0xa3, 0x3b, 0xd4, 0x55, 0x7f, - 0x54, 0xe0, 0x52, 0xf7, 0xb6, 0x71, 0xb7, 0xd0, 0xf7, 0x3f, 0x50, 0xe1, 0xb4, 0x39, 0xae, 0x7d, - 0x76, 0x0e, 0xa1, 0x78, 0xf8, 0xbf, 0x54, 0x60, 0xb6, 0x6b, 0x7d, 0x5e, 0x1f, 0x52, 0x63, 0x9b, - 0x8c, 0xf6, 0xe0, 0xec, 0x32, 0xb1, 0x13, 0xbf, 0x28, 0x70, 0xa5, 0xc7, 0x82, 0x71, 0x6f, 0xb0, - 0xda, 0xd3, 0x25, 0xb5, 0x2f, 0xcf, 0x2b, 0x19, 0xbb, 0xd5, 0x82, 0x6c, 0x72, 0xd1, 0x28, 0x0e, - 0x56, 0x99, 0x10, 0xd0, 0x3e, 0x3d, 0xa3, 0x40, 0x6c, 0xfa, 0x77, 0x05, 0x72, 0x3d, 0xb7, 0x85, - 0x21, 0xa0, 0xee, 0x25, 0xab, 0x6d, 0x9e, 0x5f, 0x36, 0x76, 0xee, 0x57, 0x05, 0xae, 0xf6, 0xba, - 0xc7, 0xef, 0x9f, 0x55, 0x7f, 0x2c, 0xaa, 0x6d, 0x9c, 0x5b, 0x34, 0xf6, 0xec, 0x7b, 0x98, 0xee, - 0xf8, 0xe3, 0x73, 0x7b, 0xb0, 0xd2, 0xa4, 0x84, 0x76, 0xef, 0xac, 0x12, 0x89, 0x5e, 0xea, 0xfa, - 0xeb, 0x3b, 0x44, 0x2f, 0x75, 0xca, 0x0c, 0xd3, 0x4b, 0xbd, 0xfe, 0x12, 0xab, 0x3f, 0xc0, 0x4c, - 0xe7, 0x07, 0x83, 0x3b, 0x83, 0xd5, 0x75, 0x88, 0x68, 0xf7, 0xcf, 0x2c, 0xd2, 0x9e, 0x83, 0x8e, - 0x0f, 0x2f, 0x43, 0xe4, 0x20, 0x29, 0x31, 0x4c, 0x0e, 0x4e, 0xff, 0x66, 0xc2, 0xad, 0x77, 0x0c, - 0x8e, 0x21, 0xac, 0x27, 0x25, 0x86, 0xb1, 0x7e, 0xfa, 0x38, 0x11, 0xb7, 0x7a, 0xf7, 0x30, 0xb9, - 0x3b, 0xcc, 0x4d, 0xd4, 0x21, 0x34, 0xcc, 0xad, 0xde, 0x73, 0xca, 0x6c, 0x7e, 0xfd, 0xea, 0x5d, - 0x5e, 0x79, 0xfd, 0x2e, 0xaf, 0xfc, 0xf3, 0x2e, 0xaf, 0xfc, 0x74, 0x9c, 0x1f, 0x79, 0x7d, 0x9c, - 0x1f, 0xf9, 0xeb, 0x38, 0x3f, 0xf2, 0xe2, 0x4e, 0xdb, 0xca, 0xc2, 0xd5, 0xae, 0xc9, 0x8f, 0x70, - 0x91, 0x85, 0x62, 0xb3, 0xd8, 0xfe, 0x69, 0x8e, 0x6f, 0x30, 0x95, 0x94, 0xf8, 0xa8, 0x76, 0xf7, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xad, 0xa4, 0x9f, 0x17, 0xb5, 0x13, 0x00, 0x00, + // 1502 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x18, 0xdd, 0x4e, 0x1b, 0x47, + 0x97, 0xfd, 0x00, 0x63, 0x1f, 0x30, 0x90, 0x85, 0x24, 0xce, 0x12, 0x0c, 0x59, 0xbe, 0xa4, 0xa8, + 0x12, 0x76, 0x42, 0x54, 0x35, 0x49, 0x5b, 0xa9, 0x60, 0x25, 0x84, 0x36, 0x84, 0x68, 0x71, 0xda, + 0x2a, 0x37, 0xab, 0xf5, 0xee, 0xb0, 0x5e, 0x61, 0xcf, 0x58, 0x3b, 0xb3, 0xc8, 0x46, 0x95, 0x22, + 0x45, 0xea, 0x7d, 0x55, 0x55, 0x6a, 0xd5, 0x17, 0xe8, 0xab, 0xe4, 0x32, 0xea, 0x55, 0xd3, 0x8b, + 0xa8, 0x0a, 0x4f, 0xd0, 0x3e, 0x41, 0x35, 0x33, 0xbb, 0x8b, 0xd7, 0xc6, 0x3f, 0x80, 0x72, 0xe5, + 0x39, 0x67, 0xe6, 0xfc, 0xff, 0x7a, 0x61, 0xce, 0xf6, 0x09, 0xa5, 0x76, 0xd5, 0xf2, 0x70, 0x91, + 0x35, 0x0b, 0x0d, 0x9f, 0x30, 0xa2, 0x2e, 0x1e, 0x21, 0x66, 0x09, 0x5c, 0x41, 0x9c, 0x88, 0x8f, + 0x0a, 0x27, 0xef, 0xb4, 0x39, 0x9b, 0xd4, 0xeb, 0x04, 0x17, 0xe5, 0x8f, 0xa4, 0xd1, 0xe6, 0x5d, + 0xe2, 0x12, 0x71, 0x2c, 0xf2, 0x93, 0xc4, 0xea, 0xbf, 0x2b, 0x70, 0x69, 0x87, 0xba, 0x25, 0x1f, + 0x59, 0x0c, 0x95, 0xf7, 0xf6, 0xbe, 0x21, 0x0c, 0xf9, 0x6a, 0x0e, 0x26, 0x6c, 0x8e, 0x21, 0x7e, + 0x4e, 0x59, 0x56, 0x56, 0x33, 0x46, 0x04, 0xaa, 0x8b, 0x00, 0x8c, 0x52, 0xb3, 0x11, 0x54, 0x0e, + 0x50, 0x2b, 0xf7, 0x3f, 0x71, 0x99, 0x61, 0x94, 0x3e, 0x13, 0x08, 0xf5, 0x63, 0x98, 0x3d, 0x40, + 0xad, 0x2d, 0x84, 0x5f, 0x20, 0x66, 0x3d, 0x46, 0x9e, 0x5b, 0x65, 0xb9, 0xd1, 0x65, 0x65, 0x75, + 0xd4, 0xe8, 0xc2, 0xab, 0x6b, 0x90, 0xa2, 0xcc, 0x62, 0x01, 0xcd, 0x8d, 0x2d, 0x2b, 0xab, 0xd3, + 0xeb, 0x97, 0x0b, 0xa1, 0xbe, 0x06, 0xb2, 0x91, 0x77, 0x88, 0xf6, 0xc4, 0xa5, 0x11, 0x3e, 0xd2, + 0x17, 0xe0, 0x5a, 0x97, 0xa2, 0x06, 0xa2, 0x0d, 0x82, 0x29, 0xd2, 0x7f, 0x52, 0x40, 0xdd, 0xa1, + 0xee, 0x8e, 0xe7, 0xfa, 0xfc, 0x9a, 0xd2, 0x47, 0x01, 0x76, 0x68, 0x1f, 0x3b, 0xae, 0x41, 0x5a, + 0xf8, 0xca, 0xf4, 0x1c, 0x61, 0xc5, 0xa8, 0x31, 0x21, 0xe0, 0x6d, 0x47, 0xdd, 0x82, 0x94, 0x55, + 0x27, 0x01, 0x96, 0x9a, 0x67, 0x36, 0x8b, 0xaf, 0xdf, 0x2d, 0x8d, 0xfc, 0xf5, 0x6e, 0xe9, 0x23, + 0xd7, 0x63, 0xd5, 0xa0, 0xc2, 0xb5, 0x2c, 0xda, 0x84, 0xd6, 0x09, 0x0d, 0x7f, 0xd6, 0xa8, 0x73, + 0x50, 0x64, 0xad, 0x06, 0xa2, 0x85, 0xe7, 0x1e, 0x66, 0x46, 0x48, 0xae, 0x5f, 0x07, 0xad, 0x5b, + 0xa7, 0x58, 0xe5, 0xa7, 0x30, 0xb7, 0x43, 0xdd, 0xe7, 0x0d, 0x47, 0x5e, 0x6e, 0x38, 0x8e, 0x8f, + 0x28, 0x3d, 0xb7, 0xeb, 0xf5, 0x45, 0x58, 0x38, 0x85, 0x5f, 0x2c, 0xee, 0x1f, 0x45, 0xc8, 0xdb, + 0x70, 0x9c, 0x32, 0xd9, 0xc6, 0xe5, 0x66, 0xd9, 0xb7, 0xec, 0x83, 0xbe, 0xa1, 0xee, 0xe3, 0xa2, + 0xab, 0x30, 0xc1, 0x9a, 0x66, 0xd5, 0xa2, 0x55, 0xe9, 0x23, 0x23, 0xc5, 0x9a, 0x8f, 0x2d, 0x5a, + 0x55, 0xd7, 0x20, 0x63, 0x13, 0x0f, 0x9b, 0xdc, 0x1b, 0x61, 0x58, 0x67, 0xa3, 0xb0, 0x96, 0x88, + 0x87, 0xcb, 0xad, 0x06, 0x32, 0xd2, 0x76, 0x78, 0x52, 0x57, 0x60, 0xbc, 0xe1, 0x13, 0xb2, 0x9f, + 0x1b, 0x5f, 0x56, 0x56, 0x27, 0xd7, 0xb3, 0xd1, 0xd3, 0x67, 0x1c, 0x69, 0xc8, 0x3b, 0x6e, 0x77, + 0xa5, 0x46, 0xec, 0x03, 0x29, 0x2f, 0x25, 0xed, 0x16, 0x18, 0x21, 0xf2, 0x1a, 0xa4, 0x59, 0xd3, + 0xf4, 0xb0, 0x83, 0x9a, 0xb9, 0x09, 0xa9, 0x26, 0x6b, 0x6e, 0x73, 0x30, 0x74, 0x49, 0xa7, 0xc9, + 0xb1, 0x4b, 0xfe, 0x90, 0xb9, 0xff, 0x6d, 0xd5, 0x63, 0xa8, 0xe6, 0x51, 0xf6, 0xd0, 0x28, 0xad, + 0xdf, 0xee, 0xe3, 0x90, 0x15, 0xc8, 0x22, 0xdf, 0x5e, 0xbf, 0x6d, 0x5a, 0xd2, 0xb7, 0x61, 0x0c, + 0xa6, 0x04, 0x32, 0x8a, 0x5f, 0xbb, 0xd7, 0x46, 0x93, 0x5e, 0x53, 0x61, 0x0c, 0x5b, 0x75, 0xe9, + 0x97, 0x8c, 0x21, 0xce, 0xea, 0x15, 0x48, 0xd1, 0x56, 0xbd, 0x42, 0x6a, 0xc2, 0x05, 0x19, 0x23, + 0x84, 0x54, 0x0d, 0xd2, 0x0e, 0xb2, 0xbd, 0xba, 0x55, 0xa3, 0xc2, 0xe4, 0xac, 0x11, 0xc3, 0xea, + 0x02, 0x64, 0x5c, 0x8b, 0x9a, 0x35, 0xaf, 0xee, 0xb1, 0xd0, 0xe4, 0xb4, 0x6b, 0xd1, 0x27, 0x1c, + 0xd6, 0x4d, 0x51, 0x26, 0x49, 0x9b, 0x22, 0x8b, 0xb9, 0x05, 0x47, 0x09, 0x0b, 0xa4, 0x85, 0x53, + 0x47, 0xed, 0x16, 0x2c, 0x02, 0xd8, 0x76, 0xec, 0xd2, 0x30, 0xcf, 0x38, 0x46, 0x3a, 0xf5, 0xad, + 0x02, 0xf3, 0x91, 0x57, 0x77, 0x03, 0x76, 0xc1, 0x4c, 0x9a, 0x87, 0x71, 0x4c, 0xb0, 0x8d, 0x84, + 0xaf, 0xc6, 0x0c, 0x09, 0xb4, 0xe7, 0xd7, 0x58, 0x22, 0xbf, 0x3e, 0x70, 0xc2, 0x7c, 0x01, 0xd7, + 0x4f, 0x33, 0x2d, 0xf6, 0xdf, 0x22, 0x80, 0x47, 0x4d, 0x1f, 0xd5, 0xc9, 0x21, 0x72, 0x84, 0x95, + 0x69, 0x23, 0xe3, 0x51, 0x43, 0x22, 0xf4, 0x7d, 0xe1, 0x7b, 0x09, 0x3d, 0xf2, 0x49, 0xfd, 0x03, + 0xb9, 0x47, 0x5f, 0x81, 0x1b, 0x3d, 0xe5, 0xc4, 0xd9, 0xfd, 0xab, 0x02, 0xb3, 0x3b, 0xd4, 0xdd, + 0xb2, 0xe8, 0x33, 0xdf, 0xb3, 0xd1, 0xa0, 0xc6, 0xde, 0x5f, 0x89, 0x06, 0x67, 0x11, 0x29, 0x21, + 0x00, 0xf5, 0x06, 0x4c, 0x49, 0x2f, 0xe3, 0xa0, 0x5e, 0x41, 0xbe, 0x08, 0xd4, 0x98, 0x31, 0x29, + 0x70, 0x4f, 0x05, 0x4a, 0x24, 0x77, 0xd0, 0x68, 0xd4, 0x5a, 0x71, 0x72, 0x0b, 0x48, 0xd7, 0x20, + 0xd7, 0xa9, 0x59, 0xac, 0xf6, 0xdb, 0x71, 0x51, 0xb4, 0x1c, 0xb9, 0x8b, 0x77, 0x2b, 0x14, 0xf9, + 0x87, 0xc8, 0xd9, 0x0d, 0x58, 0x85, 0x04, 0xd8, 0x29, 0x37, 0xfb, 0x58, 0xb0, 0x00, 0x22, 0x4b, + 0x65, 0xd4, 0x65, 0xda, 0xa6, 0x39, 0x42, 0x04, 0xbd, 0x00, 0x73, 0x24, 0x64, 0x66, 0x12, 0xee, + 0xae, 0xf6, 0xee, 0x75, 0x89, 0x9c, 0xc8, 0x29, 0xcb, 0xf7, 0x9f, 0x83, 0xd6, 0xf1, 0x5e, 0x26, + 0x90, 0x1c, 0x69, 0xd2, 0xd6, 0x5c, 0x82, 0x6c, 0xf3, 0xe4, 0x5e, 0xfd, 0x04, 0xae, 0x76, 0x50, + 0xf3, 0x82, 0x0d, 0x28, 0x72, 0x72, 0x20, 0x48, 0xe7, 0x13, 0xa4, 0x5b, 0x16, 0x7d, 0x4e, 0x91, + 0xa3, 0x1e, 0x81, 0xde, 0x41, 0x86, 0xf6, 0xf7, 0x91, 0xcd, 0xbc, 0x43, 0x24, 0x18, 0xc8, 0x28, + 0x4c, 0x8a, 0xa9, 0x54, 0x08, 0xa7, 0xd2, 0xad, 0x21, 0xa6, 0xd2, 0x36, 0x66, 0x46, 0x3e, 0x21, + 0xf1, 0x61, 0xc4, 0x37, 0x0a, 0x82, 0xfa, 0xd5, 0x00, 0xd9, 0xb2, 0xdb, 0x4c, 0x09, 0xed, 0x7b, + 0xf3, 0x12, 0x3d, 0x48, 0x25, 0x30, 0x7d, 0x68, 0xd5, 0x02, 0x64, 0xfa, 0x72, 0x92, 0x3b, 0x32, + 0xfe, 0x9b, 0x8f, 0xcf, 0x38, 0x49, 0xff, 0x7d, 0xb7, 0x74, 0xb9, 0x65, 0xd5, 0x6b, 0x0f, 0xf4, + 0x24, 0x3b, 0xdd, 0xc8, 0x0a, 0x44, 0xb8, 0x28, 0x38, 0x6d, 0xab, 0x44, 0x6a, 0x88, 0x55, 0x42, + 0x5d, 0x82, 0x49, 0x69, 0xa2, 0xc8, 0xf0, 0xb0, 0x09, 0x80, 0x40, 0x95, 0x38, 0x46, 0xbd, 0x05, + 0x33, 0xf2, 0x01, 0x1f, 0xb8, 0xb2, 0x00, 0xd3, 0xc2, 0xf2, 0xac, 0x40, 0x97, 0x29, 0x7d, 0x2a, + 0xfa, 0x54, 0x62, 0xdc, 0x65, 0x06, 0x8d, 0x3b, 0xfd, 0x26, 0xac, 0xf4, 0x49, 0xed, 0xb8, 0x04, + 0x5e, 0x8d, 0x89, 0xc5, 0x21, 0xf9, 0x6e, 0x1b, 0x0f, 0xae, 0x00, 0x5e, 0x6f, 0x08, 0x3b, 0xc8, + 0x0f, 0xd3, 0x3f, 0x84, 0xb8, 0x39, 0xf2, 0x64, 0x76, 0x8c, 0xa6, 0xac, 0x44, 0x97, 0xc2, 0x42, + 0xd7, 0x20, 0x1d, 0xba, 0xd8, 0x0f, 0xfb, 0x6e, 0x0c, 0xab, 0x37, 0x61, 0x3a, 0x3a, 0x87, 0x6e, + 0x1b, 0x97, 0x2c, 0x22, 0xac, 0xf4, 0xdc, 0xc9, 0xf2, 0x94, 0xba, 0xd0, 0xf2, 0xc4, 0xad, 0xac, + 0x23, 0x4a, 0x2d, 0x57, 0xba, 0x3e, 0x63, 0x44, 0xa0, 0x7a, 0x1d, 0x80, 0xbb, 0x3c, 0xac, 0xe0, + 0x8c, 0xd4, 0xd3, 0xc3, 0x61, 0xe1, 0xde, 0x82, 0x19, 0x0f, 0x9b, 0x61, 0xff, 0x97, 0xd5, 0x2a, + 0x4b, 0x2e, 0xeb, 0xe1, 0xf6, 0x12, 0x4d, 0x0c, 0xd1, 0x49, 0xf1, 0x22, 0x1e, 0xa2, 0xc9, 0xb8, + 0x4e, 0x0d, 0x5c, 0x63, 0x16, 0x20, 0xc3, 0x9a, 0x26, 0xf1, 0x3d, 0xd7, 0xc3, 0xb9, 0xac, 0x54, + 0x88, 0x35, 0x77, 0x05, 0xcc, 0xbb, 0xa7, 0x45, 0x29, 0x62, 0xb9, 0x69, 0x71, 0x21, 0x01, 0x9e, + 0x82, 0xe8, 0x10, 0x61, 0x16, 0xce, 0xa1, 0x19, 0xa1, 0x00, 0x08, 0x94, 0x1c, 0x45, 0xff, 0x07, + 0xbd, 0x77, 0x0e, 0xc4, 0xa9, 0xf2, 0x44, 0x6c, 0x30, 0x1b, 0x15, 0xe2, 0xb3, 0x3d, 0x16, 0xd8, + 0x07, 0xa5, 0x52, 0xf9, 0xbb, 0xfe, 0x2b, 0x64, 0xbf, 0xd1, 0x2e, 0x57, 0xec, 0x24, 0xb7, 0x58, + 0xd4, 0x4b, 0x31, 0xf6, 0x0d, 0xb4, 0x1f, 0x60, 0x47, 0x3c, 0x41, 0xce, 0x85, 0xa4, 0xf1, 0x96, + 0x1c, 0x67, 0x54, 0x85, 0xd9, 0xa6, 0x2f, 0x58, 0x47, 0x2d, 0x39, 0xba, 0xda, 0x64, 0xb6, 0x94, + 0xa9, 0xe7, 0xc5, 0x70, 0xee, 0x52, 0x20, 0x52, 0x70, 0xfd, 0x78, 0x0a, 0x46, 0x77, 0xa8, 0xab, + 0xfe, 0xa0, 0xc0, 0xa5, 0xee, 0xed, 0xe4, 0x6e, 0xa1, 0xef, 0x7f, 0xa6, 0xc2, 0x69, 0x73, 0x5f, + 0xfb, 0xec, 0x1c, 0x44, 0xf1, 0xb2, 0xf0, 0x4a, 0x81, 0xd9, 0xae, 0x75, 0x7b, 0x7d, 0x48, 0x8e, + 0x6d, 0x34, 0xda, 0x83, 0xb3, 0xd3, 0xc4, 0x4a, 0xfc, 0xac, 0xc0, 0x95, 0x1e, 0x0b, 0xc9, 0xbd, + 0xc1, 0x6c, 0x4f, 0xa7, 0xd4, 0xbe, 0x3c, 0x2f, 0x65, 0xac, 0x56, 0x0b, 0xb2, 0xc9, 0xc5, 0xa4, + 0x38, 0x98, 0x65, 0x82, 0x40, 0xfb, 0xf4, 0x8c, 0x04, 0xb1, 0xe8, 0xdf, 0x14, 0xc8, 0xf5, 0xdc, + 0x2e, 0x86, 0x70, 0x75, 0x2f, 0x5a, 0x6d, 0xf3, 0xfc, 0xb4, 0xb1, 0x72, 0xbf, 0x28, 0x70, 0xb5, + 0x57, 0xdf, 0xbf, 0x7f, 0x56, 0xfe, 0x31, 0xa9, 0xb6, 0x71, 0x6e, 0xd2, 0x58, 0xb3, 0xef, 0x61, + 0xba, 0xe3, 0x8f, 0xd2, 0xed, 0xc1, 0x4c, 0x93, 0x14, 0xda, 0xbd, 0xb3, 0x52, 0x24, 0x6a, 0xa9, + 0xeb, 0xaf, 0xf2, 0x10, 0xb5, 0xd4, 0x49, 0x33, 0x4c, 0x2d, 0xf5, 0xfa, 0x0b, 0xad, 0xbe, 0x84, + 0x99, 0xce, 0x0f, 0x0c, 0x77, 0x06, 0xb3, 0xeb, 0x20, 0xd1, 0xee, 0x9f, 0x99, 0xa4, 0x3d, 0x06, + 0x1d, 0x1f, 0x6a, 0x86, 0x88, 0x41, 0x92, 0x62, 0x98, 0x18, 0x9c, 0xfe, 0x8d, 0x85, 0x4b, 0xef, + 0x18, 0x34, 0x43, 0x48, 0x4f, 0x52, 0x0c, 0x23, 0xfd, 0xf4, 0xf1, 0x23, 0xba, 0x7a, 0xf7, 0xf0, + 0xb9, 0x3b, 0x4c, 0x27, 0xea, 0x20, 0x1a, 0xa6, 0xab, 0xf7, 0x9c, 0x32, 0x9b, 0x5f, 0xbf, 0x7e, + 0x9f, 0x57, 0xde, 0xbc, 0xcf, 0x2b, 0x7f, 0xbf, 0xcf, 0x2b, 0x3f, 0x1e, 0xe7, 0x47, 0xde, 0x1c, + 0xe7, 0x47, 0xfe, 0x3c, 0xce, 0x8f, 0xbc, 0xb8, 0xd3, 0xb6, 0xe2, 0x70, 0xb6, 0x6b, 0xf2, 0xa3, + 0x5d, 0x24, 0xa1, 0xd8, 0x2c, 0xb6, 0x7f, 0xca, 0xe3, 0x1b, 0x4f, 0x25, 0x25, 0x3e, 0xc2, 0xdd, + 0xfd, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x95, 0x7c, 0x7b, 0x19, 0xe5, 0x13, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3014,6 +3023,13 @@ func (m *MsgRefundAbortedCCTX) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.ReceiverBtcRefund) > 0 { + i -= len(m.ReceiverBtcRefund) + copy(dAtA[i:], m.ReceiverBtcRefund) + i = encodeVarintTx(dAtA, i, uint64(len(m.ReceiverBtcRefund))) + i-- + dAtA[i] = 0x1a + } if len(m.CctxIndex) > 0 { i -= len(m.CctxIndex) copy(dAtA[i:], m.CctxIndex) @@ -3514,6 +3530,10 @@ func (m *MsgRefundAbortedCCTX) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + l = len(m.ReceiverBtcRefund) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } return n } @@ -6547,6 +6567,38 @@ func (m *MsgRefundAbortedCCTX) Unmarshal(dAtA []byte) error { } m.CctxIndex = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReceiverBtcRefund", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ReceiverBtcRefund = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) From 6c6c7b79895c141c8db8d2a54a45c7f2fe2ac4bc Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 7 Feb 2024 15:11:06 -0500 Subject: [PATCH 10/50] unit tests for msg server --- proto/crosschain/tx.proto | 2 +- .../keeper/msg_server_refund_aborted_tx.go | 41 ++- .../msg_server_refund_aborted_tx_test.go | 271 ++++++++++++++++++ .../keeper/msg_server_vote_inbound_tx.go | 6 +- x/crosschain/keeper/refund.go | 46 +-- x/crosschain/keeper/refund_test.go | 93 ++++-- x/crosschain/keeper/utils_test.go | 9 + x/crosschain/types/tx.pb.go | 212 +++++++------- 8 files changed, 501 insertions(+), 179 deletions(-) create mode 100644 x/crosschain/keeper/msg_server_refund_aborted_tx_test.go diff --git a/proto/crosschain/tx.proto b/proto/crosschain/tx.proto index 73860e30f7..5cee0f1f21 100644 --- a/proto/crosschain/tx.proto +++ b/proto/crosschain/tx.proto @@ -167,7 +167,7 @@ message MsgAbortStuckCCTXResponse {} message MsgRefundAbortedCCTX { string creator = 1; string cctx_index = 2; - string receiver_btc_refund = 3; + string refund_address = 3; // if not provided, the refund will be sent to the sender/txOrgin } message MsgRefundAbortedCCTXResponse {} diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 71f31208c4..2c9ac79ea0 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -3,6 +3,7 @@ package keeper import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" observertypes "github.com/zeta-chain/zetacore/x/observer/types" @@ -17,11 +18,17 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund if msg.Creator != k.zetaObserverKeeper.GetParams(ctx).GetAdminPolicyAccount(observertypes.Policy_Type_group2) { return nil, observertypes.ErrNotAuthorized } + // check if the cctx exists cctx, found := k.GetCrossChainTx(ctx, msg.CctxIndex) if !found { return nil, types.ErrCannotFindCctx } + // make sure separate refund address is provided for bitcoin chain as we cannot refund to tx origin or sender in this case + if common.IsBitcoinChain(cctx.InboundTxParams.SenderChainId) && msg.RefundAddress == "" { + return nil, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address") + } + // check if the cctx is aborted if cctx.CctxStatus.Status != types.CctxStatus_Aborted { return nil, errorsmod.Wrap(types.ErrInvalidStatus, "CCTX is not aborted") @@ -31,21 +38,35 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, "CCTX is already refunded") } + // Set the proper refund address. + // For BTC sender chain the refund address is the one provided in the message in the RefundAddress field. + // For EVM chain with coin type ERC20 the refund address is the sender , but can be overridden by the RefundAddress field in the message. + // For EVM chain with coin type Zeta the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. + // For EVM chain with coin type Gas the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. + + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) + if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { + refundAddress = ethcommon.HexToAddress(cctx.InboundTxParams.Sender) + } + if msg.RefundAddress != "" { + refundAddress = ethcommon.HexToAddress(msg.RefundAddress) + } + // Make sure the refund address is valid + if refundAddress == (ethcommon.Address{}) { + return nil, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address") + } + // refund the amount - if common.IsEVMChain(cctx.InboundTxParams.SenderChainId) { - err := k.RefundAbortedAmountOnZetaChainForEvmChain(ctx, cctx) - if err != nil { - return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) - } - } else if common.IsBitcoinChain(cctx.InboundTxParams.SenderChainId) { - err := k.RefundAbortedAmountOnZetaChainForBitcoinChain(ctx, cctx, msg.ReceiverBtcRefund) - if err != nil { - return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) - } + err := k.RefundAbortedAmountOnZetaChain(ctx, cctx, refundAddress) + if err != nil { + return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) } + // set the cctx as refunded cctx.IsRefunded = true k.SetCrossChainTx(ctx, cctx) + + // Include the refunded amount in ZetaAccount, so we can now remove it from the ZetaAbortedAmount counter. if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { k.RemoveZetaAbortedAmount(ctx, cctx.GetCurrentOutTxParam().Amount) } diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go new file mode 100644 index 0000000000..4c11795d3f --- /dev/null +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -0,0 +1,271 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/cmd/zetacored/config" + "github.com/zeta-chain/zetacore/common" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/keeper" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" +) + +func TestMsgServer_RefundAbortedCCTX(t *testing.T) { + t.Run("Successfully refund tx for coin-type Gas", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.IsRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Gas + k.SetCrossChainTx(ctx, *cctx) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "", + }) + require.NoError(t, err) + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) + balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, refundAddress) + require.NoError(t, err) + require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Uint64()) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.True(t, c.IsRefunded) + }) + t.Run("Successfully refund tx for coin-type Zeta", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.IsRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + k.SetCrossChainTx(ctx, *cctx) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "", + }) + require.NoError(t, err) + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) + refundAddressCosmos := sdk.AccAddress(refundAddress.Bytes()) + balance := sdkk.BankKeeper.GetBalance(ctx, refundAddressCosmos, config.BaseDenom) + require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Amount.Uint64()) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.True(t, c.IsRefunded) + }) + t.Run("Successfully refund to refund address if provided", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.IsRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + k.SetCrossChainTx(ctx, *cctx) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + refundAddress := sample.EthAddress() + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: refundAddress.String(), + }) + require.NoError(t, err) + refundAddressCosmos := sdk.AccAddress(refundAddress.Bytes()) + balance := sdkk.BankKeeper.GetBalance(ctx, refundAddressCosmos, config.BaseDenom) + require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Amount.Uint64()) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.True(t, c.IsRefunded) + }) + t.Run("Failed refund if address provided is invalid", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.IsRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + k.SetCrossChainTx(ctx, *cctx) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "invalid-address", + }) + require.ErrorContains(t, err, "invalid refund address") + }) + t.Run("Successfully refund tx for coin-type ERC20", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + asset := sample.EthAddress().String() + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.IsRefunded = false + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_ERC20 + cctx.InboundTxParams.Asset = asset + k.SetCrossChainTx(ctx, *cctx) + // deploy zrc20 + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + zrc20Addr := deployZRC20( + t, + ctx, + zk.FungibleKeeper, + sdkk.EvmKeeper, + chainID, + "bar", + asset, + "bar", + ) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "", + }) + require.NoError(t, err) + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.Sender) + balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, refundAddress) + require.NoError(t, err) + require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Uint64()) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.True(t, c.IsRefunded) + }) + t.Run("Successfully refund tx for coin-type Gas with BTC sender", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidBtcChainID() + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.IsRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Gas + k.SetCrossChainTx(ctx, *cctx) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: cctx.InboundTxParams.TxOrigin, + }) + require.NoError(t, err) + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) + balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, refundAddress) + require.NoError(t, err) + require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Uint64()) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.True(t, c.IsRefunded) + }) + t.Run("Fail refund if status is not aborted", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_PendingOutbound + cctx.IsRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Gas + k.SetCrossChainTx(ctx, *cctx) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "", + }) + require.ErrorContains(t, err, "CCTX is not aborted") + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.False(t, c.IsRefunded) + }) + t.Run("Fail refund if status cctx not found", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_PendingOutbound + cctx.IsRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Gas + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "", + }) + require.ErrorContains(t, err, "cannot find cctx") + }) + t.Run("Fail refund if refund address not provided for BTC chain", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidBtcChainID() + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.IsRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Gas + k.SetCrossChainTx(ctx, *cctx) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _ = setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "", + }) + require.ErrorContains(t, err, "invalid refund address") + }) +} diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 7352cd8d84..e8160af9e9 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -7,6 +7,7 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" observerKeeper "github.com/zeta-chain/zetacore/x/observer/keeper" @@ -192,8 +193,9 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg // gas payment for erc20 type might fail because no liquidity pool is defined to swap the zrc20 token into the gas token // in this gas we should refund the sender on ZetaChain - if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { - if err := k.RefundAbortedAmountOnZetaChainForEvmChain(ctx, cctx); err != nil { + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.Sender) + if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 && refundAddress != (ethcommon.Address{}) { + if err := k.RefundAbortedAmountOnZetaChain(ctx, cctx, refundAddress); err != nil { // log the error k.Logger(ctx).Error("failed to refund amount of aborted cctx on ZetaChain", "error", err, diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index d41bff1383..538c2dfd4f 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -12,39 +12,28 @@ import ( zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" ) -func (k Keeper) RefundAbortedAmountOnZetaChainForEvmChain(ctx sdk.Context, cctx types.CrossChainTx) error { +func (k Keeper) RefundAbortedAmountOnZetaChain(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { coinType := cctx.InboundTxParams.CoinType switch coinType { case common.CoinType_Gas: - return k.RefundAmountOnZetaChainGas(ctx, cctx) + return k.RefundAmountOnZetaChainGas(ctx, cctx, refundAddress) case common.CoinType_Zeta: - return k.RefundAmountOnZetaChainZeta(ctx, cctx) + return k.RefundAmountOnZetaChainZeta(ctx, cctx, refundAddress) case common.CoinType_ERC20: - return k.RefundAmountOnZetaChainERC20(ctx, cctx) + return k.RefundAmountOnZetaChainERC20(ctx, cctx, refundAddress) default: return errors.New("unsupported coin type for refund on ZetaChain") } } -func (k Keeper) RefundAbortedAmountOnZetaChainForBitcoinChain(ctx sdk.Context, cctx types.CrossChainTx, evmAddressForBtcRefund string) error { - refundTo := ethcommon.HexToAddress(evmAddressForBtcRefund) - if refundTo == (ethcommon.Address{}) { - return errors.New("invalid address for refund") - } - // Set TxOrigin to the supplied address so that the refund is made to the evm address - cctx.InboundTxParams.TxOrigin = refundTo.String() - return k.RefundAmountOnZetaChainGas(ctx, cctx) -} - // RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype gas -func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChainTx) error { +func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { // refund in gas token of a sender chain to the tx origin + if cctx.InboundTxParams.Amount.IsNil() || cctx.InboundTxParams.Amount.IsZero() { + return errors.New("no amount to refund") + } chainID := cctx.InboundTxParams.SenderChainId amountOfGasTokenLocked := cctx.InboundTxParams.Amount - refundTo := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) - if refundTo == (ethcommon.Address{}) { - return errors.New("invalid address for refund") - } if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { return zetaObserverTypes.ErrSupportedChains } @@ -57,24 +46,20 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai return cosmoserrors.Wrapf(types.ErrForeignCoinNotFound, "zrc20 contract address not found for chain %d", chainID) } // deposit the amount to the tx origin instead of receiver as this is a refund - if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundTo, amountOfGasTokenLocked.BigInt()); err != nil { + if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundAddress, amountOfGasTokenLocked.BigInt()); err != nil { return errors.New("failed to refund zeta on ZetaChain" + err.Error()) } return nil } // RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype zeta -func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossChainTx) error { +func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { // if coin type is Zeta, handle this as a deposit ZETA to zEVM. // deposit the amount to the tx orgin instead of receiver as this is a refund - to := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) - if to == (ethcommon.Address{}) { - return errors.New("invalid receiver address") - } if cctx.InboundTxParams.Amount.IsNil() || cctx.InboundTxParams.Amount.IsZero() { return errors.New("no amount to refund") } - if err := k.fungibleKeeper.DepositCoinZeta(ctx, to, cctx.InboundTxParams.Amount.BigInt()); err != nil { + if err := k.fungibleKeeper.DepositCoinZeta(ctx, refundAddress, cctx.InboundTxParams.Amount.BigInt()); err != nil { return errors.New("failed to refund zeta on ZetaChain" + err.Error()) } return nil @@ -82,7 +67,7 @@ func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossCha // RefundAmountOnZetaChainERC20 refunds the amount of the cctx on ZetaChain in case of aborted cctx // NOTE: GetCurrentOutTxParam should contain the last up to date cctx amount -func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossChainTx) error { +func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { inputAmount := cctx.InboundTxParams.Amount // preliminary checks if cctx.InboundTxParams.CoinType != common.CoinType_ERC20 { @@ -91,10 +76,7 @@ func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossCh if !common.IsEVMChain(cctx.InboundTxParams.SenderChainId) { return errors.New("only EVM chains are supported for refund on ZetaChain") } - sender := ethcommon.HexToAddress(cctx.InboundTxParams.Sender) - if sender == (ethcommon.Address{}) { - return errors.New("invalid sender address") - } + if inputAmount.IsNil() || inputAmount.IsZero() { return errors.New("no amount to refund") } @@ -110,7 +92,7 @@ func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossCh } // deposit the amount to the sender - if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, sender, inputAmount.BigInt()); err != nil { + if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundAddress, inputAmount.BigInt()); err != nil { return errors.New("failed to deposit zrc20 on ZetaChain" + err.Error()) } diff --git a/x/crosschain/keeper/refund_test.go b/x/crosschain/keeper/refund_test.go index 074c9ca91a..fbf25d0240 100644 --- a/x/crosschain/keeper/refund_test.go +++ b/x/crosschain/keeper/refund_test.go @@ -32,12 +32,52 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { TxOrigin: sender.String(), Amount: math.NewUint(42), }}, + sender, ) require.NoError(t, err) balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, sender) require.NoError(t, err) require.Equal(t, uint64(42), balance.Uint64()) }) + t.Run("failed refund zrc20 gas on zeta chain if gas coin not found", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: chainID, + Sender: sender.String(), + TxOrigin: sender.String(), + Amount: math.NewUint(42), + }}, + sender, + ) + require.ErrorContains(t, err, types.ErrForeignCoinNotFound.Error()) + }) + t.Run("failed refund amount zrc20 gas on zeta chain if amount is 0", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _ = setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") + + err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: chainID, + Sender: sender.String(), + TxOrigin: sender.String(), + Amount: math.ZeroUint(), + }}, + sender, + ) + require.ErrorContains(t, err, "no amount to refund") + }) + } func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { @@ -55,12 +95,31 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { TxOrigin: sender.String(), Amount: math.NewUint(42), }}, + sender, ) require.NoError(t, err) coin := sdkk.BankKeeper.GetBalance(ctx, sdk.AccAddress(sender.Bytes()), config.BaseDenom) fmt.Println(coin.Amount.String()) require.Equal(t, "42", coin.Amount.String()) }) + t.Run("failed refund amount on zeta chain amount is 0", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + + err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: chainID, + Sender: sender.String(), + TxOrigin: sender.String(), + Amount: math.ZeroUint(), + }}, + sender, + ) + require.ErrorContains(t, err, "no amount to refund") + }) } func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { @@ -92,6 +151,7 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { Asset: asset, Amount: math.NewUint(42), }}, + sender, ) require.NoError(t, err) @@ -109,6 +169,7 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { Asset: asset, Amount: math.NewUint(42), }}, + sender, ) require.NoError(t, err) balance, err = zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, sender) @@ -124,14 +185,7 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { CoinType: common.CoinType_Zeta, Amount: math.NewUint(42), }}, - ) - require.ErrorContains(t, err, "unsupported coin type") - - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Zeta, - Amount: math.NewUint(42), - }}, + sample.EthAddress(), ) require.ErrorContains(t, err, "unsupported coin type") @@ -141,19 +195,10 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { SenderChainId: 999999, Amount: math.NewUint(42), }}, + sample.EthAddress(), ) require.ErrorContains(t, err, "only EVM chains are supported") - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), - Sender: "invalid", - Amount: math.NewUint(42), - }}, - ) - require.ErrorContains(t, err, "invalid sender address") - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_ERC20, @@ -161,16 +206,7 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { Sender: sample.EthAddress().String(), Amount: math.Uint{}, }}, - ) - require.ErrorContains(t, err, "no amount to refund") - - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), - Sender: sample.EthAddress().String(), - Amount: math.ZeroUint(), - }}, + sample.EthAddress(), ) require.ErrorContains(t, err, "no amount to refund") @@ -183,6 +219,7 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { Asset: sample.EthAddress().String(), Amount: math.NewUint(42), }}, + sample.EthAddress(), ) require.ErrorContains(t, err, "zrc not found") }) diff --git a/x/crosschain/keeper/utils_test.go b/x/crosschain/keeper/utils_test.go index 83f37b2799..b5735ac0de 100644 --- a/x/crosschain/keeper/utils_test.go +++ b/x/crosschain/keeper/utils_test.go @@ -32,6 +32,15 @@ func getValidEthChain(_ *testing.T) *zetacommon.Chain { return &goerli } +func getValidBTCChain() *zetacommon.Chain { + btcRegNet := zetacommon.BtcRegtestChain() + return &btcRegNet +} + +func getValidBtcChainID() int64 { + return getValidBTCChain().ChainId +} + // getValidEthChainIDWithIndex get a valid eth chain id with index func getValidEthChainIDWithIndex(t *testing.T, index int) int64 { switch index { diff --git a/x/crosschain/types/tx.pb.go b/x/crosschain/types/tx.pb.go index 0c35a89da6..650ef991dd 100644 --- a/x/crosschain/types/tx.pb.go +++ b/x/crosschain/types/tx.pb.go @@ -1351,9 +1351,9 @@ func (m *MsgAbortStuckCCTXResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgAbortStuckCCTXResponse proto.InternalMessageInfo type MsgRefundAbortedCCTX struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` - CctxIndex string `protobuf:"bytes,2,opt,name=cctx_index,json=cctxIndex,proto3" json:"cctx_index,omitempty"` - ReceiverBtcRefund string `protobuf:"bytes,3,opt,name=receiver_btc_refund,json=receiverBtcRefund,proto3" json:"receiver_btc_refund,omitempty"` + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + CctxIndex string `protobuf:"bytes,2,opt,name=cctx_index,json=cctxIndex,proto3" json:"cctx_index,omitempty"` + RefundAddress string `protobuf:"bytes,3,opt,name=refund_address,json=refundAddress,proto3" json:"refund_address,omitempty"` } func (m *MsgRefundAbortedCCTX) Reset() { *m = MsgRefundAbortedCCTX{} } @@ -1403,9 +1403,9 @@ func (m *MsgRefundAbortedCCTX) GetCctxIndex() string { return "" } -func (m *MsgRefundAbortedCCTX) GetReceiverBtcRefund() string { +func (m *MsgRefundAbortedCCTX) GetRefundAddress() string { if m != nil { - return m.ReceiverBtcRefund + return m.RefundAddress } return "" } @@ -1477,100 +1477,100 @@ func init() { proto.RegisterFile("crosschain/tx.proto", fileDescriptor_81d6d6111 var fileDescriptor_81d6d611190b7635 = []byte{ // 1502 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x18, 0xdd, 0x4e, 0x1b, 0x47, - 0x97, 0xfd, 0x00, 0x63, 0x1f, 0x30, 0x90, 0x85, 0x24, 0xce, 0x12, 0x0c, 0x59, 0xbe, 0xa4, 0xa8, - 0x12, 0x76, 0x42, 0x54, 0x35, 0x49, 0x5b, 0xa9, 0x60, 0x25, 0x84, 0x36, 0x84, 0x68, 0x71, 0xda, - 0x2a, 0x37, 0xab, 0xf5, 0xee, 0xb0, 0x5e, 0x61, 0xcf, 0x58, 0x3b, 0xb3, 0xc8, 0x46, 0x95, 0x22, - 0x45, 0xea, 0x7d, 0x55, 0x55, 0x6a, 0xd5, 0x17, 0xe8, 0xab, 0xe4, 0x32, 0xea, 0x55, 0xd3, 0x8b, - 0xa8, 0x0a, 0x4f, 0xd0, 0x3e, 0x41, 0x35, 0x33, 0xbb, 0x8b, 0xd7, 0xc6, 0x3f, 0x80, 0x72, 0xe5, - 0x39, 0x67, 0xe6, 0xfc, 0xff, 0x7a, 0x61, 0xce, 0xf6, 0x09, 0xa5, 0x76, 0xd5, 0xf2, 0x70, 0x91, - 0x35, 0x0b, 0x0d, 0x9f, 0x30, 0xa2, 0x2e, 0x1e, 0x21, 0x66, 0x09, 0x5c, 0x41, 0x9c, 0x88, 0x8f, - 0x0a, 0x27, 0xef, 0xb4, 0x39, 0x9b, 0xd4, 0xeb, 0x04, 0x17, 0xe5, 0x8f, 0xa4, 0xd1, 0xe6, 0x5d, - 0xe2, 0x12, 0x71, 0x2c, 0xf2, 0x93, 0xc4, 0xea, 0xbf, 0x2b, 0x70, 0x69, 0x87, 0xba, 0x25, 0x1f, - 0x59, 0x0c, 0x95, 0xf7, 0xf6, 0xbe, 0x21, 0x0c, 0xf9, 0x6a, 0x0e, 0x26, 0x6c, 0x8e, 0x21, 0x7e, - 0x4e, 0x59, 0x56, 0x56, 0x33, 0x46, 0x04, 0xaa, 0x8b, 0x00, 0x8c, 0x52, 0xb3, 0x11, 0x54, 0x0e, - 0x50, 0x2b, 0xf7, 0x3f, 0x71, 0x99, 0x61, 0x94, 0x3e, 0x13, 0x08, 0xf5, 0x63, 0x98, 0x3d, 0x40, - 0xad, 0x2d, 0x84, 0x5f, 0x20, 0x66, 0x3d, 0x46, 0x9e, 0x5b, 0x65, 0xb9, 0xd1, 0x65, 0x65, 0x75, - 0xd4, 0xe8, 0xc2, 0xab, 0x6b, 0x90, 0xa2, 0xcc, 0x62, 0x01, 0xcd, 0x8d, 0x2d, 0x2b, 0xab, 0xd3, - 0xeb, 0x97, 0x0b, 0xa1, 0xbe, 0x06, 0xb2, 0x91, 0x77, 0x88, 0xf6, 0xc4, 0xa5, 0x11, 0x3e, 0xd2, - 0x17, 0xe0, 0x5a, 0x97, 0xa2, 0x06, 0xa2, 0x0d, 0x82, 0x29, 0xd2, 0x7f, 0x52, 0x40, 0xdd, 0xa1, - 0xee, 0x8e, 0xe7, 0xfa, 0xfc, 0x9a, 0xd2, 0x47, 0x01, 0x76, 0x68, 0x1f, 0x3b, 0xae, 0x41, 0x5a, - 0xf8, 0xca, 0xf4, 0x1c, 0x61, 0xc5, 0xa8, 0x31, 0x21, 0xe0, 0x6d, 0x47, 0xdd, 0x82, 0x94, 0x55, - 0x27, 0x01, 0x96, 0x9a, 0x67, 0x36, 0x8b, 0xaf, 0xdf, 0x2d, 0x8d, 0xfc, 0xf5, 0x6e, 0xe9, 0x23, - 0xd7, 0x63, 0xd5, 0xa0, 0xc2, 0xb5, 0x2c, 0xda, 0x84, 0xd6, 0x09, 0x0d, 0x7f, 0xd6, 0xa8, 0x73, - 0x50, 0x64, 0xad, 0x06, 0xa2, 0x85, 0xe7, 0x1e, 0x66, 0x46, 0x48, 0xae, 0x5f, 0x07, 0xad, 0x5b, - 0xa7, 0x58, 0xe5, 0xa7, 0x30, 0xb7, 0x43, 0xdd, 0xe7, 0x0d, 0x47, 0x5e, 0x6e, 0x38, 0x8e, 0x8f, - 0x28, 0x3d, 0xb7, 0xeb, 0xf5, 0x45, 0x58, 0x38, 0x85, 0x5f, 0x2c, 0xee, 0x1f, 0x45, 0xc8, 0xdb, - 0x70, 0x9c, 0x32, 0xd9, 0xc6, 0xe5, 0x66, 0xd9, 0xb7, 0xec, 0x83, 0xbe, 0xa1, 0xee, 0xe3, 0xa2, - 0xab, 0x30, 0xc1, 0x9a, 0x66, 0xd5, 0xa2, 0x55, 0xe9, 0x23, 0x23, 0xc5, 0x9a, 0x8f, 0x2d, 0x5a, - 0x55, 0xd7, 0x20, 0x63, 0x13, 0x0f, 0x9b, 0xdc, 0x1b, 0x61, 0x58, 0x67, 0xa3, 0xb0, 0x96, 0x88, - 0x87, 0xcb, 0xad, 0x06, 0x32, 0xd2, 0x76, 0x78, 0x52, 0x57, 0x60, 0xbc, 0xe1, 0x13, 0xb2, 0x9f, - 0x1b, 0x5f, 0x56, 0x56, 0x27, 0xd7, 0xb3, 0xd1, 0xd3, 0x67, 0x1c, 0x69, 0xc8, 0x3b, 0x6e, 0x77, - 0xa5, 0x46, 0xec, 0x03, 0x29, 0x2f, 0x25, 0xed, 0x16, 0x18, 0x21, 0xf2, 0x1a, 0xa4, 0x59, 0xd3, - 0xf4, 0xb0, 0x83, 0x9a, 0xb9, 0x09, 0xa9, 0x26, 0x6b, 0x6e, 0x73, 0x30, 0x74, 0x49, 0xa7, 0xc9, - 0xb1, 0x4b, 0xfe, 0x90, 0xb9, 0xff, 0x6d, 0xd5, 0x63, 0xa8, 0xe6, 0x51, 0xf6, 0xd0, 0x28, 0xad, - 0xdf, 0xee, 0xe3, 0x90, 0x15, 0xc8, 0x22, 0xdf, 0x5e, 0xbf, 0x6d, 0x5a, 0xd2, 0xb7, 0x61, 0x0c, - 0xa6, 0x04, 0x32, 0x8a, 0x5f, 0xbb, 0xd7, 0x46, 0x93, 0x5e, 0x53, 0x61, 0x0c, 0x5b, 0x75, 0xe9, - 0x97, 0x8c, 0x21, 0xce, 0xea, 0x15, 0x48, 0xd1, 0x56, 0xbd, 0x42, 0x6a, 0xc2, 0x05, 0x19, 0x23, - 0x84, 0x54, 0x0d, 0xd2, 0x0e, 0xb2, 0xbd, 0xba, 0x55, 0xa3, 0xc2, 0xe4, 0xac, 0x11, 0xc3, 0xea, - 0x02, 0x64, 0x5c, 0x8b, 0x9a, 0x35, 0xaf, 0xee, 0xb1, 0xd0, 0xe4, 0xb4, 0x6b, 0xd1, 0x27, 0x1c, - 0xd6, 0x4d, 0x51, 0x26, 0x49, 0x9b, 0x22, 0x8b, 0xb9, 0x05, 0x47, 0x09, 0x0b, 0xa4, 0x85, 0x53, - 0x47, 0xed, 0x16, 0x2c, 0x02, 0xd8, 0x76, 0xec, 0xd2, 0x30, 0xcf, 0x38, 0x46, 0x3a, 0xf5, 0xad, - 0x02, 0xf3, 0x91, 0x57, 0x77, 0x03, 0x76, 0xc1, 0x4c, 0x9a, 0x87, 0x71, 0x4c, 0xb0, 0x8d, 0x84, - 0xaf, 0xc6, 0x0c, 0x09, 0xb4, 0xe7, 0xd7, 0x58, 0x22, 0xbf, 0x3e, 0x70, 0xc2, 0x7c, 0x01, 0xd7, - 0x4f, 0x33, 0x2d, 0xf6, 0xdf, 0x22, 0x80, 0x47, 0x4d, 0x1f, 0xd5, 0xc9, 0x21, 0x72, 0x84, 0x95, - 0x69, 0x23, 0xe3, 0x51, 0x43, 0x22, 0xf4, 0x7d, 0xe1, 0x7b, 0x09, 0x3d, 0xf2, 0x49, 0xfd, 0x03, - 0xb9, 0x47, 0x5f, 0x81, 0x1b, 0x3d, 0xe5, 0xc4, 0xd9, 0xfd, 0xab, 0x02, 0xb3, 0x3b, 0xd4, 0xdd, - 0xb2, 0xe8, 0x33, 0xdf, 0xb3, 0xd1, 0xa0, 0xc6, 0xde, 0x5f, 0x89, 0x06, 0x67, 0x11, 0x29, 0x21, - 0x00, 0xf5, 0x06, 0x4c, 0x49, 0x2f, 0xe3, 0xa0, 0x5e, 0x41, 0xbe, 0x08, 0xd4, 0x98, 0x31, 0x29, - 0x70, 0x4f, 0x05, 0x4a, 0x24, 0x77, 0xd0, 0x68, 0xd4, 0x5a, 0x71, 0x72, 0x0b, 0x48, 0xd7, 0x20, - 0xd7, 0xa9, 0x59, 0xac, 0xf6, 0xdb, 0x71, 0x51, 0xb4, 0x1c, 0xb9, 0x8b, 0x77, 0x2b, 0x14, 0xf9, - 0x87, 0xc8, 0xd9, 0x0d, 0x58, 0x85, 0x04, 0xd8, 0x29, 0x37, 0xfb, 0x58, 0xb0, 0x00, 0x22, 0x4b, - 0x65, 0xd4, 0x65, 0xda, 0xa6, 0x39, 0x42, 0x04, 0xbd, 0x00, 0x73, 0x24, 0x64, 0x66, 0x12, 0xee, - 0xae, 0xf6, 0xee, 0x75, 0x89, 0x9c, 0xc8, 0x29, 0xcb, 0xf7, 0x9f, 0x83, 0xd6, 0xf1, 0x5e, 0x26, - 0x90, 0x1c, 0x69, 0xd2, 0xd6, 0x5c, 0x82, 0x6c, 0xf3, 0xe4, 0x5e, 0xfd, 0x04, 0xae, 0x76, 0x50, - 0xf3, 0x82, 0x0d, 0x28, 0x72, 0x72, 0x20, 0x48, 0xe7, 0x13, 0xa4, 0x5b, 0x16, 0x7d, 0x4e, 0x91, - 0xa3, 0x1e, 0x81, 0xde, 0x41, 0x86, 0xf6, 0xf7, 0x91, 0xcd, 0xbc, 0x43, 0x24, 0x18, 0xc8, 0x28, - 0x4c, 0x8a, 0xa9, 0x54, 0x08, 0xa7, 0xd2, 0xad, 0x21, 0xa6, 0xd2, 0x36, 0x66, 0x46, 0x3e, 0x21, - 0xf1, 0x61, 0xc4, 0x37, 0x0a, 0x82, 0xfa, 0xd5, 0x00, 0xd9, 0xb2, 0xdb, 0x4c, 0x09, 0xed, 0x7b, - 0xf3, 0x12, 0x3d, 0x48, 0x25, 0x30, 0x7d, 0x68, 0xd5, 0x02, 0x64, 0xfa, 0x72, 0x92, 0x3b, 0x32, - 0xfe, 0x9b, 0x8f, 0xcf, 0x38, 0x49, 0xff, 0x7d, 0xb7, 0x74, 0xb9, 0x65, 0xd5, 0x6b, 0x0f, 0xf4, - 0x24, 0x3b, 0xdd, 0xc8, 0x0a, 0x44, 0xb8, 0x28, 0x38, 0x6d, 0xab, 0x44, 0x6a, 0x88, 0x55, 0x42, - 0x5d, 0x82, 0x49, 0x69, 0xa2, 0xc8, 0xf0, 0xb0, 0x09, 0x80, 0x40, 0x95, 0x38, 0x46, 0xbd, 0x05, - 0x33, 0xf2, 0x01, 0x1f, 0xb8, 0xb2, 0x00, 0xd3, 0xc2, 0xf2, 0xac, 0x40, 0x97, 0x29, 0x7d, 0x2a, - 0xfa, 0x54, 0x62, 0xdc, 0x65, 0x06, 0x8d, 0x3b, 0xfd, 0x26, 0xac, 0xf4, 0x49, 0xed, 0xb8, 0x04, - 0x5e, 0x8d, 0x89, 0xc5, 0x21, 0xf9, 0x6e, 0x1b, 0x0f, 0xae, 0x00, 0x5e, 0x6f, 0x08, 0x3b, 0xc8, - 0x0f, 0xd3, 0x3f, 0x84, 0xb8, 0x39, 0xf2, 0x64, 0x76, 0x8c, 0xa6, 0xac, 0x44, 0x97, 0xc2, 0x42, - 0xd7, 0x20, 0x1d, 0xba, 0xd8, 0x0f, 0xfb, 0x6e, 0x0c, 0xab, 0x37, 0x61, 0x3a, 0x3a, 0x87, 0x6e, - 0x1b, 0x97, 0x2c, 0x22, 0xac, 0xf4, 0xdc, 0xc9, 0xf2, 0x94, 0xba, 0xd0, 0xf2, 0xc4, 0xad, 0xac, - 0x23, 0x4a, 0x2d, 0x57, 0xba, 0x3e, 0x63, 0x44, 0xa0, 0x7a, 0x1d, 0x80, 0xbb, 0x3c, 0xac, 0xe0, - 0x8c, 0xd4, 0xd3, 0xc3, 0x61, 0xe1, 0xde, 0x82, 0x19, 0x0f, 0x9b, 0x61, 0xff, 0x97, 0xd5, 0x2a, - 0x4b, 0x2e, 0xeb, 0xe1, 0xf6, 0x12, 0x4d, 0x0c, 0xd1, 0x49, 0xf1, 0x22, 0x1e, 0xa2, 0xc9, 0xb8, - 0x4e, 0x0d, 0x5c, 0x63, 0x16, 0x20, 0xc3, 0x9a, 0x26, 0xf1, 0x3d, 0xd7, 0xc3, 0xb9, 0xac, 0x54, - 0x88, 0x35, 0x77, 0x05, 0xcc, 0xbb, 0xa7, 0x45, 0x29, 0x62, 0xb9, 0x69, 0x71, 0x21, 0x01, 0x9e, - 0x82, 0xe8, 0x10, 0x61, 0x16, 0xce, 0xa1, 0x19, 0xa1, 0x00, 0x08, 0x94, 0x1c, 0x45, 0xff, 0x07, - 0xbd, 0x77, 0x0e, 0xc4, 0xa9, 0xf2, 0x44, 0x6c, 0x30, 0x1b, 0x15, 0xe2, 0xb3, 0x3d, 0x16, 0xd8, - 0x07, 0xa5, 0x52, 0xf9, 0xbb, 0xfe, 0x2b, 0x64, 0xbf, 0xd1, 0x2e, 0x57, 0xec, 0x24, 0xb7, 0x58, - 0xd4, 0x4b, 0x31, 0xf6, 0x0d, 0xb4, 0x1f, 0x60, 0x47, 0x3c, 0x41, 0xce, 0x85, 0xa4, 0xf1, 0x96, - 0x1c, 0x67, 0x54, 0x85, 0xd9, 0xa6, 0x2f, 0x58, 0x47, 0x2d, 0x39, 0xba, 0xda, 0x64, 0xb6, 0x94, - 0xa9, 0xe7, 0xc5, 0x70, 0xee, 0x52, 0x20, 0x52, 0x70, 0xfd, 0x78, 0x0a, 0x46, 0x77, 0xa8, 0xab, - 0xfe, 0xa0, 0xc0, 0xa5, 0xee, 0xed, 0xe4, 0x6e, 0xa1, 0xef, 0x7f, 0xa6, 0xc2, 0x69, 0x73, 0x5f, - 0xfb, 0xec, 0x1c, 0x44, 0xf1, 0xb2, 0xf0, 0x4a, 0x81, 0xd9, 0xae, 0x75, 0x7b, 0x7d, 0x48, 0x8e, - 0x6d, 0x34, 0xda, 0x83, 0xb3, 0xd3, 0xc4, 0x4a, 0xfc, 0xac, 0xc0, 0x95, 0x1e, 0x0b, 0xc9, 0xbd, - 0xc1, 0x6c, 0x4f, 0xa7, 0xd4, 0xbe, 0x3c, 0x2f, 0x65, 0xac, 0x56, 0x0b, 0xb2, 0xc9, 0xc5, 0xa4, - 0x38, 0x98, 0x65, 0x82, 0x40, 0xfb, 0xf4, 0x8c, 0x04, 0xb1, 0xe8, 0xdf, 0x14, 0xc8, 0xf5, 0xdc, - 0x2e, 0x86, 0x70, 0x75, 0x2f, 0x5a, 0x6d, 0xf3, 0xfc, 0xb4, 0xb1, 0x72, 0xbf, 0x28, 0x70, 0xb5, - 0x57, 0xdf, 0xbf, 0x7f, 0x56, 0xfe, 0x31, 0xa9, 0xb6, 0x71, 0x6e, 0xd2, 0x58, 0xb3, 0xef, 0x61, - 0xba, 0xe3, 0x8f, 0xd2, 0xed, 0xc1, 0x4c, 0x93, 0x14, 0xda, 0xbd, 0xb3, 0x52, 0x24, 0x6a, 0xa9, - 0xeb, 0xaf, 0xf2, 0x10, 0xb5, 0xd4, 0x49, 0x33, 0x4c, 0x2d, 0xf5, 0xfa, 0x0b, 0xad, 0xbe, 0x84, - 0x99, 0xce, 0x0f, 0x0c, 0x77, 0x06, 0xb3, 0xeb, 0x20, 0xd1, 0xee, 0x9f, 0x99, 0xa4, 0x3d, 0x06, - 0x1d, 0x1f, 0x6a, 0x86, 0x88, 0x41, 0x92, 0x62, 0x98, 0x18, 0x9c, 0xfe, 0x8d, 0x85, 0x4b, 0xef, - 0x18, 0x34, 0x43, 0x48, 0x4f, 0x52, 0x0c, 0x23, 0xfd, 0xf4, 0xf1, 0x23, 0xba, 0x7a, 0xf7, 0xf0, - 0xb9, 0x3b, 0x4c, 0x27, 0xea, 0x20, 0x1a, 0xa6, 0xab, 0xf7, 0x9c, 0x32, 0x9b, 0x5f, 0xbf, 0x7e, - 0x9f, 0x57, 0xde, 0xbc, 0xcf, 0x2b, 0x7f, 0xbf, 0xcf, 0x2b, 0x3f, 0x1e, 0xe7, 0x47, 0xde, 0x1c, - 0xe7, 0x47, 0xfe, 0x3c, 0xce, 0x8f, 0xbc, 0xb8, 0xd3, 0xb6, 0xe2, 0x70, 0xb6, 0x6b, 0xf2, 0xa3, - 0x5d, 0x24, 0xa1, 0xd8, 0x2c, 0xb6, 0x7f, 0xca, 0xe3, 0x1b, 0x4f, 0x25, 0x25, 0x3e, 0xc2, 0xdd, - 0xfd, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x95, 0x7c, 0x7b, 0x19, 0xe5, 0x13, 0x00, 0x00, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x6f, 0x4f, 0xdb, 0x56, + 0x17, 0xc7, 0x0f, 0x10, 0x92, 0x03, 0x01, 0x6a, 0x68, 0x9b, 0x9a, 0x12, 0xa8, 0x79, 0xda, 0x07, + 0x3d, 0x12, 0x49, 0x4b, 0x35, 0xad, 0xed, 0x36, 0x69, 0x10, 0xb5, 0x94, 0xad, 0x94, 0xca, 0xa4, + 0xdb, 0xd4, 0x37, 0x96, 0x63, 0x5f, 0x1c, 0x8b, 0xc4, 0x37, 0xf2, 0xbd, 0x8e, 0x12, 0x34, 0x69, + 0x52, 0xa5, 0xbd, 0x9f, 0xa6, 0x49, 0x9b, 0xf6, 0x05, 0xf6, 0x55, 0xfa, 0xb2, 0xda, 0xab, 0x75, + 0x2f, 0xaa, 0xa9, 0x7c, 0x82, 0xed, 0x13, 0x4c, 0xf7, 0x8f, 0x4d, 0x9c, 0x90, 0x3f, 0x50, 0xf5, + 0x55, 0x7c, 0x8e, 0xef, 0xf9, 0xf7, 0x3b, 0xe7, 0xdc, 0x73, 0x62, 0x58, 0xb0, 0x03, 0x4c, 0x88, + 0x5d, 0xb5, 0x3c, 0xbf, 0x48, 0x5b, 0x85, 0x46, 0x80, 0x29, 0x56, 0x97, 0x8f, 0x11, 0xb5, 0x38, + 0xaf, 0xc0, 0x9f, 0x70, 0x80, 0x0a, 0xa7, 0xe7, 0xb4, 0x05, 0x1b, 0xd7, 0xeb, 0xd8, 0x2f, 0x8a, + 0x1f, 0x21, 0xa3, 0x2d, 0xba, 0xd8, 0xc5, 0xfc, 0xb1, 0xc8, 0x9e, 0x04, 0x57, 0xff, 0x4d, 0x81, + 0x4b, 0x7b, 0xc4, 0x2d, 0x05, 0xc8, 0xa2, 0xa8, 0x7c, 0x70, 0xf0, 0x15, 0xa6, 0x28, 0x50, 0x73, + 0x30, 0x65, 0x33, 0x0e, 0x0e, 0x72, 0xca, 0xaa, 0xb2, 0x9e, 0x31, 0x22, 0x52, 0x5d, 0x06, 0xa0, + 0x84, 0x98, 0x8d, 0xb0, 0x72, 0x84, 0xda, 0xb9, 0xff, 0xf0, 0x97, 0x19, 0x4a, 0xc8, 0x33, 0xce, + 0x50, 0xff, 0x0f, 0xf3, 0x47, 0xa8, 0xbd, 0x83, 0xfc, 0x17, 0x88, 0x5a, 0x8f, 0x91, 0xe7, 0x56, + 0x69, 0x6e, 0x7c, 0x55, 0x59, 0x1f, 0x37, 0x7a, 0xf8, 0xea, 0x06, 0xa4, 0x08, 0xb5, 0x68, 0x48, + 0x72, 0x13, 0xab, 0xca, 0xfa, 0xec, 0xe6, 0xe5, 0x82, 0xf4, 0xd7, 0x40, 0x36, 0xf2, 0x9a, 0xe8, + 0x80, 0xbf, 0x34, 0xe4, 0x21, 0x7d, 0x09, 0xae, 0xf5, 0x38, 0x6a, 0x20, 0xd2, 0xc0, 0x3e, 0x41, + 0xfa, 0x8f, 0x0a, 0xa8, 0x7b, 0xc4, 0xdd, 0xf3, 0xdc, 0x80, 0xbd, 0x26, 0xe4, 0x51, 0xe8, 0x3b, + 0x64, 0x40, 0x1c, 0xd7, 0x20, 0xcd, 0xb1, 0x32, 0x3d, 0x87, 0x47, 0x31, 0x6e, 0x4c, 0x71, 0x7a, + 0xd7, 0x51, 0x77, 0x20, 0x65, 0xd5, 0x71, 0xe8, 0x0b, 0xcf, 0x33, 0xdb, 0xc5, 0x57, 0x6f, 0x57, + 0xc6, 0xfe, 0x7c, 0xbb, 0xf2, 0x3f, 0xd7, 0xa3, 0xd5, 0xb0, 0xc2, 0xbc, 0x2c, 0xda, 0x98, 0xd4, + 0x31, 0x91, 0x3f, 0x1b, 0xc4, 0x39, 0x2a, 0xd2, 0x76, 0x03, 0x91, 0xc2, 0x73, 0xcf, 0xa7, 0x86, + 0x14, 0xd7, 0xaf, 0x83, 0xd6, 0xeb, 0x53, 0xec, 0xf2, 0x53, 0x58, 0xd8, 0x23, 0xee, 0xf3, 0x86, + 0x23, 0x5e, 0x6e, 0x39, 0x4e, 0x80, 0x08, 0xb9, 0x30, 0xf4, 0xfa, 0x32, 0x2c, 0x9d, 0xa1, 0x2f, + 0x36, 0xf7, 0xb7, 0xc2, 0xed, 0x6d, 0x39, 0x4e, 0x19, 0xef, 0xfa, 0xe5, 0x56, 0x39, 0xb0, 0xec, + 0xa3, 0x81, 0xa9, 0x1e, 0x00, 0xd1, 0x55, 0x98, 0xa2, 0x2d, 0xb3, 0x6a, 0x91, 0xaa, 0xc0, 0xc8, + 0x48, 0xd1, 0xd6, 0x63, 0x8b, 0x54, 0xd5, 0x0d, 0xc8, 0xd8, 0xd8, 0xf3, 0x4d, 0x86, 0x86, 0x4c, + 0xeb, 0x7c, 0x94, 0xd6, 0x12, 0xf6, 0xfc, 0x72, 0xbb, 0x81, 0x8c, 0xb4, 0x2d, 0x9f, 0xd4, 0x35, + 0x98, 0x6c, 0x04, 0x18, 0x1f, 0xe6, 0x26, 0x57, 0x95, 0xf5, 0xe9, 0xcd, 0x6c, 0x74, 0xf4, 0x19, + 0x63, 0x1a, 0xe2, 0x1d, 0x8b, 0xbb, 0x52, 0xc3, 0xf6, 0x91, 0xb0, 0x97, 0x12, 0x71, 0x73, 0x0e, + 0x37, 0x79, 0x0d, 0xd2, 0xb4, 0x65, 0x7a, 0xbe, 0x83, 0x5a, 0xb9, 0x29, 0xe1, 0x26, 0x6d, 0xed, + 0x32, 0x52, 0x42, 0xd2, 0x1d, 0x72, 0x0c, 0xc9, 0xef, 0xa2, 0xf6, 0xbf, 0xae, 0x7a, 0x14, 0xd5, + 0x3c, 0x42, 0x1f, 0x1a, 0xa5, 0xcd, 0xdb, 0x03, 0x00, 0x59, 0x83, 0x2c, 0x0a, 0xec, 0xcd, 0xdb, + 0xa6, 0x25, 0xb0, 0x95, 0x39, 0x98, 0xe1, 0xcc, 0x28, 0x7f, 0x9d, 0xa8, 0x8d, 0x27, 0x51, 0x53, + 0x61, 0xc2, 0xb7, 0xea, 0x02, 0x97, 0x8c, 0xc1, 0x9f, 0xd5, 0x2b, 0x90, 0x22, 0xed, 0x7a, 0x05, + 0xd7, 0x38, 0x04, 0x19, 0x43, 0x52, 0xaa, 0x06, 0x69, 0x07, 0xd9, 0x5e, 0xdd, 0xaa, 0x11, 0x1e, + 0x72, 0xd6, 0x88, 0x69, 0x75, 0x09, 0x32, 0xae, 0x45, 0xcc, 0x9a, 0x57, 0xf7, 0xa8, 0x0c, 0x39, + 0xed, 0x5a, 0xe4, 0x09, 0xa3, 0x75, 0x93, 0xb7, 0x49, 0x32, 0xa6, 0x28, 0x62, 0x16, 0xc1, 0x71, + 0x22, 0x02, 0x11, 0xe1, 0xcc, 0x71, 0x67, 0x04, 0xcb, 0x00, 0xb6, 0x1d, 0x43, 0x2a, 0xeb, 0x8c, + 0x71, 0x04, 0xa8, 0x6f, 0x14, 0x58, 0x8c, 0x50, 0xdd, 0x0f, 0xe9, 0x7b, 0x56, 0xd2, 0x22, 0x4c, + 0xfa, 0xd8, 0xb7, 0x11, 0xc7, 0x6a, 0xc2, 0x10, 0x44, 0x67, 0x7d, 0x4d, 0x24, 0xea, 0xeb, 0x03, + 0x17, 0xcc, 0x67, 0x70, 0xfd, 0xac, 0xd0, 0x62, 0xfc, 0x96, 0x01, 0x3c, 0x62, 0x06, 0xa8, 0x8e, + 0x9b, 0xc8, 0xe1, 0x51, 0xa6, 0x8d, 0x8c, 0x47, 0x0c, 0xc1, 0xd0, 0x0f, 0x39, 0xf6, 0x82, 0x7a, + 0x14, 0xe0, 0xfa, 0x07, 0x82, 0x47, 0x5f, 0x83, 0x1b, 0x7d, 0xed, 0xc4, 0xd5, 0xfd, 0x8b, 0x02, + 0xf3, 0x7b, 0xc4, 0xdd, 0xb1, 0xc8, 0xb3, 0xc0, 0xb3, 0xd1, 0xb0, 0x8b, 0x7d, 0xb0, 0x13, 0x0d, + 0xa6, 0x22, 0x72, 0x82, 0x13, 0xea, 0x0d, 0x98, 0x11, 0x28, 0xfb, 0x61, 0xbd, 0x82, 0x02, 0x9e, + 0xa8, 0x09, 0x63, 0x9a, 0xf3, 0x9e, 0x72, 0x16, 0x2f, 0xee, 0xb0, 0xd1, 0xa8, 0xb5, 0xe3, 0xe2, + 0xe6, 0x94, 0xae, 0x41, 0xae, 0xdb, 0xb3, 0xd8, 0xed, 0x37, 0x93, 0xbc, 0x69, 0x19, 0x73, 0xdf, + 0xdf, 0xaf, 0x10, 0x14, 0x34, 0x91, 0xb3, 0x1f, 0xd2, 0x0a, 0x0e, 0x7d, 0xa7, 0xdc, 0x1a, 0x10, + 0xc1, 0x12, 0xf0, 0x2a, 0x15, 0x59, 0x17, 0x65, 0x9b, 0x66, 0x0c, 0x9e, 0xf4, 0x02, 0x2c, 0x60, + 0xa9, 0xcc, 0xc4, 0x0c, 0xae, 0xce, 0xdb, 0xeb, 0x12, 0x3e, 0xb5, 0x53, 0x16, 0xe7, 0x3f, 0x05, + 0xad, 0xeb, 0xbc, 0x28, 0x20, 0x31, 0xd2, 0x44, 0xac, 0xb9, 0x84, 0xd8, 0xf6, 0xe9, 0x7b, 0xf5, + 0x23, 0xb8, 0xda, 0x25, 0xcd, 0x1a, 0x36, 0x24, 0xc8, 0xc9, 0x01, 0x17, 0x5d, 0x4c, 0x88, 0xee, + 0x58, 0xe4, 0x39, 0x41, 0x8e, 0x7a, 0x0c, 0x7a, 0x97, 0x18, 0x3a, 0x3c, 0x44, 0x36, 0xf5, 0x9a, + 0x88, 0x2b, 0x10, 0x59, 0x98, 0xe6, 0x53, 0xa9, 0x20, 0xa7, 0xd2, 0xad, 0x11, 0xa6, 0xd2, 0xae, + 0x4f, 0x8d, 0x7c, 0xc2, 0xe2, 0xc3, 0x48, 0x6f, 0x94, 0x04, 0xf5, 0x8b, 0x21, 0xb6, 0xc5, 0x6d, + 0x33, 0xc3, 0xbd, 0xef, 0xaf, 0x8b, 0xdf, 0x41, 0x2a, 0x86, 0xd9, 0xa6, 0x55, 0x0b, 0x91, 0x19, + 0x88, 0x49, 0xee, 0x88, 0xfc, 0x6f, 0x3f, 0x3e, 0xe7, 0x24, 0xfd, 0xe7, 0xed, 0xca, 0xe5, 0xb6, + 0x55, 0xaf, 0x3d, 0xd0, 0x93, 0xea, 0x74, 0x23, 0xcb, 0x19, 0x72, 0x51, 0x70, 0x3a, 0x56, 0x89, + 0xd4, 0x08, 0xab, 0x84, 0xba, 0x02, 0xd3, 0x22, 0x44, 0x5e, 0xe1, 0xf2, 0x12, 0x00, 0xce, 0x2a, + 0x31, 0x8e, 0x7a, 0x0b, 0xe6, 0xc4, 0x01, 0x36, 0x70, 0x45, 0x03, 0xa6, 0x79, 0xe4, 0x59, 0xce, + 0x2e, 0x13, 0xf2, 0x94, 0xdf, 0x53, 0x89, 0x71, 0x97, 0x19, 0x36, 0xee, 0xf4, 0x9b, 0xb0, 0x36, + 0xa0, 0xb4, 0xe3, 0x16, 0x78, 0x39, 0xc1, 0x17, 0x87, 0xe4, 0xb9, 0x5d, 0x7f, 0x78, 0x07, 0xb0, + 0x7e, 0x43, 0xbe, 0x83, 0x02, 0x59, 0xfe, 0x92, 0x62, 0xe1, 0x88, 0x27, 0xb3, 0x6b, 0x34, 0x65, + 0x05, 0xbb, 0x24, 0x1b, 0x5d, 0x83, 0xb4, 0x84, 0x38, 0x90, 0xf7, 0x6e, 0x4c, 0xab, 0x37, 0x61, + 0x36, 0x7a, 0x96, 0xb0, 0x4d, 0x0a, 0x15, 0x11, 0x57, 0x20, 0x77, 0xba, 0x3c, 0xa5, 0xde, 0x6b, + 0x79, 0x62, 0x51, 0xd6, 0x11, 0x21, 0x96, 0x2b, 0xa0, 0xcf, 0x18, 0x11, 0xa9, 0x5e, 0x07, 0x60, + 0x90, 0xcb, 0x0e, 0xce, 0x08, 0x3f, 0x3d, 0x5f, 0x36, 0xee, 0x2d, 0x98, 0xf3, 0x7c, 0x53, 0xde, + 0xff, 0xa2, 0x5b, 0x45, 0xcb, 0x65, 0x3d, 0xbf, 0xb3, 0x45, 0x13, 0x43, 0x74, 0x9a, 0x9f, 0x88, + 0x87, 0x68, 0x32, 0xaf, 0x33, 0x43, 0xd7, 0x98, 0x25, 0xc8, 0xd0, 0x96, 0x89, 0x03, 0xcf, 0xf5, + 0xfc, 0x5c, 0x56, 0x38, 0x44, 0x5b, 0xfb, 0x9c, 0x66, 0xb7, 0xa7, 0x45, 0x08, 0xa2, 0xb9, 0x59, + 0xfe, 0x42, 0x10, 0xac, 0x04, 0x51, 0x13, 0xf9, 0x54, 0xce, 0xa1, 0x39, 0xee, 0x00, 0x70, 0x96, + 0x18, 0x45, 0xff, 0x05, 0xbd, 0x7f, 0x0d, 0xc4, 0xa5, 0xf2, 0x84, 0x6f, 0x30, 0x5b, 0x15, 0x1c, + 0xd0, 0x03, 0x1a, 0xda, 0x47, 0xa5, 0x52, 0xf9, 0x9b, 0xc1, 0x2b, 0xe4, 0xa0, 0xd1, 0x2e, 0x56, + 0xec, 0xa4, 0xb6, 0xd8, 0x54, 0x93, 0x8f, 0x7d, 0x03, 0x1d, 0x86, 0xbe, 0xc3, 0x8f, 0x20, 0xe7, + 0xbd, 0xac, 0x89, 0x8a, 0x62, 0xda, 0xe2, 0x6d, 0x44, 0xdc, 0xc6, 0x59, 0xc1, 0x95, 0xeb, 0x88, + 0x9e, 0xe7, 0x33, 0xb9, 0xc7, 0x6e, 0xe4, 0xd7, 0xe6, 0xc9, 0x0c, 0x8c, 0xef, 0x11, 0x57, 0xfd, + 0x5e, 0x81, 0x4b, 0xbd, 0x4b, 0xc9, 0xdd, 0xc2, 0xc0, 0xbf, 0x4a, 0x85, 0xb3, 0xc6, 0xbd, 0xf6, + 0xc9, 0x05, 0x84, 0xe2, 0x1d, 0xe1, 0xa5, 0x02, 0xf3, 0x3d, 0x5b, 0xf6, 0xe6, 0x88, 0x1a, 0x3b, + 0x64, 0xb4, 0x07, 0xe7, 0x97, 0x89, 0x9d, 0xf8, 0x49, 0x81, 0x2b, 0x7d, 0xf6, 0x90, 0x7b, 0xc3, + 0xd5, 0x9e, 0x2d, 0xa9, 0x7d, 0x7e, 0x51, 0xc9, 0xd8, 0xad, 0x36, 0x64, 0x93, 0xfb, 0x48, 0x71, + 0xb8, 0xca, 0x84, 0x80, 0xf6, 0xf1, 0x39, 0x05, 0x62, 0xd3, 0xbf, 0x2a, 0x90, 0xeb, 0xbb, 0x54, + 0x8c, 0x00, 0x75, 0x3f, 0x59, 0x6d, 0xfb, 0xe2, 0xb2, 0xb1, 0x73, 0x3f, 0x2b, 0x70, 0xb5, 0xdf, + 0x75, 0x7f, 0xff, 0xbc, 0xfa, 0x63, 0x51, 0x6d, 0xeb, 0xc2, 0xa2, 0xb1, 0x67, 0xdf, 0xc2, 0x6c, + 0xd7, 0xff, 0xa3, 0xdb, 0xc3, 0x95, 0x26, 0x25, 0xb4, 0x7b, 0xe7, 0x95, 0x48, 0xf4, 0x52, 0xcf, + 0x3f, 0xe4, 0x11, 0x7a, 0xa9, 0x5b, 0x66, 0x94, 0x5e, 0xea, 0xf7, 0xcf, 0x59, 0xfd, 0x0e, 0xe6, + 0xba, 0xbf, 0x2b, 0xdc, 0x19, 0xae, 0xae, 0x4b, 0x44, 0xbb, 0x7f, 0x6e, 0x91, 0xce, 0x1c, 0x74, + 0x7d, 0x9f, 0x19, 0x21, 0x07, 0x49, 0x89, 0x51, 0x72, 0x70, 0xf6, 0xa7, 0x15, 0x66, 0xbd, 0x6b, + 0xbe, 0x8c, 0x60, 0x3d, 0x29, 0x31, 0x8a, 0xf5, 0xb3, 0xa7, 0x0e, 0xbf, 0xd5, 0x7b, 0x67, 0xce, + 0xdd, 0x51, 0x6e, 0xa2, 0x2e, 0xa1, 0x51, 0x6e, 0xf5, 0xbe, 0x53, 0x66, 0xfb, 0xcb, 0x57, 0xef, + 0xf2, 0xca, 0xeb, 0x77, 0x79, 0xe5, 0xaf, 0x77, 0x79, 0xe5, 0x87, 0x93, 0xfc, 0xd8, 0xeb, 0x93, + 0xfc, 0xd8, 0x1f, 0x27, 0xf9, 0xb1, 0x17, 0x77, 0x3a, 0x36, 0x1b, 0xa6, 0x76, 0x43, 0x7c, 0xab, + 0x8b, 0x2c, 0x14, 0x5b, 0xc5, 0xce, 0x2f, 0x78, 0x6c, 0xd1, 0xa9, 0xa4, 0xf8, 0xb7, 0xb7, 0xbb, + 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x8e, 0x99, 0xcd, 0x4c, 0xdc, 0x13, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3023,10 +3023,10 @@ func (m *MsgRefundAbortedCCTX) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.ReceiverBtcRefund) > 0 { - i -= len(m.ReceiverBtcRefund) - copy(dAtA[i:], m.ReceiverBtcRefund) - i = encodeVarintTx(dAtA, i, uint64(len(m.ReceiverBtcRefund))) + if len(m.RefundAddress) > 0 { + i -= len(m.RefundAddress) + copy(dAtA[i:], m.RefundAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.RefundAddress))) i-- dAtA[i] = 0x1a } @@ -3530,7 +3530,7 @@ func (m *MsgRefundAbortedCCTX) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.ReceiverBtcRefund) + l = len(m.RefundAddress) if l > 0 { n += 1 + l + sovTx(uint64(l)) } @@ -6569,7 +6569,7 @@ func (m *MsgRefundAbortedCCTX) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ReceiverBtcRefund", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RefundAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -6597,7 +6597,7 @@ func (m *MsgRefundAbortedCCTX) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ReceiverBtcRefund = string(dAtA[iNdEx:postIndex]) + m.RefundAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex From 47a35ff21bef74bd002547f75a4eccc5b86ece55 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 01:24:26 -0500 Subject: [PATCH 11/50] change cli to include optional refund address --- x/crosschain/client/cli/cli_refund_aborted.go | 8 ++++---- .../keeper/msg_server_vote_inbound_tx.go | 5 ++--- x/crosschain/keeper/refund.go | 6 +++++- x/crosschain/types/message_refund_aborted.go | 11 ++++++++--- .../types/message_refund_aborted_test.go | 16 +++++++++++++--- 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/x/crosschain/client/cli/cli_refund_aborted.go b/x/crosschain/client/cli/cli_refund_aborted.go index bc1ecf0028..744d95c7b5 100644 --- a/x/crosschain/client/cli/cli_refund_aborted.go +++ b/x/crosschain/client/cli/cli_refund_aborted.go @@ -10,15 +10,15 @@ import ( func CmdRefundAborted() *cobra.Command { cmd := &cobra.Command{ - Use: "refund-aborted [cctx-index]", - Short: `Refund a aborted tx`, - Args: cobra.ExactArgs(1), + Use: "refund-aborted [cctx-index] [refund-address]", + Short: `Refund a aborted tx , the refund address is optional, if not provided, the refund will be sent to the sender/tx origin of the cctx.`, + Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err } - msg := types.NewMsgRefundAbortedCCTX(clientCtx.GetFromAddress().String(), args[0]) + msg := types.NewMsgRefundAbortedCCTX(clientCtx.GetFromAddress().String(), args[0], args[1]) err = msg.ValidateBasic() if err != nil { return err diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index e8160af9e9..aa64de3325 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -193,9 +193,8 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg // gas payment for erc20 type might fail because no liquidity pool is defined to swap the zrc20 token into the gas token // in this gas we should refund the sender on ZetaChain - refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.Sender) - if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 && refundAddress != (ethcommon.Address{}) { - if err := k.RefundAbortedAmountOnZetaChain(ctx, cctx, refundAddress); err != nil { + if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 && ethcommon.IsHexAddress(cctx.InboundTxParams.Sender) { + if err := k.RefundAbortedAmountOnZetaChain(ctx, cctx, ethcommon.HexToAddress(cctx.InboundTxParams.Sender)); err != nil { // log the error k.Logger(ctx).Error("failed to refund amount of aborted cctx on ZetaChain", "error", err, diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index 538c2dfd4f..775f848c60 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -28,15 +28,17 @@ func (k Keeper) RefundAbortedAmountOnZetaChain(ctx sdk.Context, cctx types.Cross // RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype gas func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { - // refund in gas token of a sender chain to the tx origin + // refund in gas token to refund address if cctx.InboundTxParams.Amount.IsNil() || cctx.InboundTxParams.Amount.IsZero() { return errors.New("no amount to refund") } chainID := cctx.InboundTxParams.SenderChainId amountOfGasTokenLocked := cctx.InboundTxParams.Amount + // check if chain is supported if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { return zetaObserverTypes.ErrSupportedChains } + // get the zrc20 contract address fcSenderChain, found := k.fungibleKeeper.GetGasCoinForForeignCoin(ctx, chainID) if !found { return types.ErrForeignCoinNotFound @@ -59,6 +61,7 @@ func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossCha if cctx.InboundTxParams.Amount.IsNil() || cctx.InboundTxParams.Amount.IsZero() { return errors.New("no amount to refund") } + // deposit the amount to refund address if err := k.fungibleKeeper.DepositCoinZeta(ctx, refundAddress, cctx.InboundTxParams.Amount.BigInt()); err != nil { return errors.New("failed to refund zeta on ZetaChain" + err.Error()) } @@ -67,6 +70,7 @@ func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossCha // RefundAmountOnZetaChainERC20 refunds the amount of the cctx on ZetaChain in case of aborted cctx // NOTE: GetCurrentOutTxParam should contain the last up to date cctx amount +// Refund address should already be validated before calling this function func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { inputAmount := cctx.InboundTxParams.Amount // preliminary checks diff --git a/x/crosschain/types/message_refund_aborted.go b/x/crosschain/types/message_refund_aborted.go index 3bee3d857f..1034c7ee18 100644 --- a/x/crosschain/types/message_refund_aborted.go +++ b/x/crosschain/types/message_refund_aborted.go @@ -4,15 +4,17 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/common" ) var _ sdk.Msg = &MsgRefundAbortedCCTX{} -func NewMsgRefundAbortedCCTX(creator string, cctxIndex string) *MsgRefundAbortedCCTX { +func NewMsgRefundAbortedCCTX(creator string, cctxIndex string, refundAddress string) *MsgRefundAbortedCCTX { return &MsgRefundAbortedCCTX{ - Creator: creator, - CctxIndex: cctxIndex, + Creator: creator, + CctxIndex: cctxIndex, + RefundAddress: refundAddress, } } @@ -45,5 +47,8 @@ func (msg *MsgRefundAbortedCCTX) ValidateBasic() error { if len(msg.CctxIndex) != 66 { return ErrInvalidCCTXIndex } + if msg.RefundAddress != "" && !ethcommon.IsHexAddress(msg.RefundAddress) { + return ErrInvalidAddress + } return nil } diff --git a/x/crosschain/types/message_refund_aborted_test.go b/x/crosschain/types/message_refund_aborted_test.go index f523c2b781..7f1a0643f6 100644 --- a/x/crosschain/types/message_refund_aborted_test.go +++ b/x/crosschain/types/message_refund_aborted_test.go @@ -11,16 +11,26 @@ import ( func TestNewMsgRefundAbortedCCTX(t *testing.T) { t.Run("successfully validate message", func(t *testing.T) { cctx := sample.CrossChainTx(t, "test") - msg := types.NewMsgRefundAbortedCCTX(sample.AccAddress(), cctx.Index) + msg := types.NewMsgRefundAbortedCCTX(sample.AccAddress(), cctx.Index, "") assert.NoError(t, msg.ValidateBasic()) }) t.Run("invalid creator address", func(t *testing.T) { cctx := sample.CrossChainTx(t, "test") - msg := types.NewMsgRefundAbortedCCTX("invalid", cctx.Index) + msg := types.NewMsgRefundAbortedCCTX("invalid", cctx.Index, "") assert.ErrorContains(t, msg.ValidateBasic(), "invalid creator address") }) t.Run("invalid cctx index", func(t *testing.T) { - msg := types.NewMsgRefundAbortedCCTX(sample.AccAddress(), "invalid") + msg := types.NewMsgRefundAbortedCCTX(sample.AccAddress(), "invalid", "") assert.ErrorContains(t, msg.ValidateBasic(), "invalid cctx index") }) + t.Run("invalid refund address", func(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + msg := types.NewMsgRefundAbortedCCTX(sample.AccAddress(), cctx.Index, "invalid") + assert.ErrorContains(t, msg.ValidateBasic(), "invalid address") + }) + t.Run("invalid refund address 2", func(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + msg := types.NewMsgRefundAbortedCCTX(sample.AccAddress(), cctx.Index, "0x91da5bf3F8Eb72724E6f50Ec6C3D199C6355c59") + assert.ErrorContains(t, msg.ValidateBasic(), "invalid address") + }) } From e93a5bbd88776ce4021b804a9bdde5b4cadc0735 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 01:31:46 -0500 Subject: [PATCH 12/50] rename to Abort refunded --- proto/crosschain/cross_chain_tx.proto | 2 +- .../keeper/msg_server_refund_aborted_tx.go | 4 +- .../keeper/msg_server_vote_inbound_tx.go | 2 +- x/crosschain/types/cross_chain_tx.pb.go | 224 +++++++++--------- 4 files changed, 116 insertions(+), 116 deletions(-) diff --git a/proto/crosschain/cross_chain_tx.proto b/proto/crosschain/cross_chain_tx.proto index 307e873774..28aeab85db 100644 --- a/proto/crosschain/cross_chain_tx.proto +++ b/proto/crosschain/cross_chain_tx.proto @@ -77,6 +77,7 @@ message Status { CctxStatus status = 1; string status_message = 2; int64 lastUpdate_timestamp = 3; + bool isAbortRefunded = 4; } message CrossChainTx { @@ -91,5 +92,4 @@ message CrossChainTx { Status cctx_status = 8; InboundTxParams inbound_tx_params = 9; repeated OutboundTxParams outbound_tx_params = 10; - bool isRefunded = 11; } diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 2c9ac79ea0..68813c0bed 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -34,7 +34,7 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund return nil, errorsmod.Wrap(types.ErrInvalidStatus, "CCTX is not aborted") } // check if the cctx is not refunded - if cctx.IsRefunded { + if cctx.CctxStatus.IsAbortRefunded { return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, "CCTX is already refunded") } @@ -63,7 +63,7 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund } // set the cctx as refunded - cctx.IsRefunded = true + cctx.CctxStatus.IsAbortRefunded = true k.SetCrossChainTx(ctx, cctx) // Include the refunded amount in ZetaAccount, so we can now remove it from the ZetaAbortedAmount counter. diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index aa64de3325..675051dc45 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -202,7 +202,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg "amount", cctx.InboundTxParams.Amount.String(), ) } - cctx.IsRefunded = true + cctx.CctxStatus.IsAbortRefunded = true } cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()+" deposit revert message: "+revertMessage) diff --git a/x/crosschain/types/cross_chain_tx.pb.go b/x/crosschain/types/cross_chain_tx.pb.go index 84e6e1bc6a..94f34e6e46 100644 --- a/x/crosschain/types/cross_chain_tx.pb.go +++ b/x/crosschain/types/cross_chain_tx.pb.go @@ -394,6 +394,7 @@ type Status struct { Status CctxStatus `protobuf:"varint,1,opt,name=status,proto3,enum=zetachain.zetacore.crosschain.CctxStatus" json:"status,omitempty"` StatusMessage string `protobuf:"bytes,2,opt,name=status_message,json=statusMessage,proto3" json:"status_message,omitempty"` LastUpdateTimestamp int64 `protobuf:"varint,3,opt,name=lastUpdate_timestamp,json=lastUpdateTimestamp,proto3" json:"lastUpdate_timestamp,omitempty"` + IsAbortRefunded bool `protobuf:"varint,4,opt,name=isAbortRefunded,proto3" json:"isAbortRefunded,omitempty"` } func (m *Status) Reset() { *m = Status{} } @@ -450,6 +451,13 @@ func (m *Status) GetLastUpdateTimestamp() int64 { return 0 } +func (m *Status) GetIsAbortRefunded() bool { + if m != nil { + return m.IsAbortRefunded + } + return false +} + type CrossChainTx struct { Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` Index string `protobuf:"bytes,2,opt,name=index,proto3" json:"index,omitempty"` @@ -458,7 +466,6 @@ type CrossChainTx struct { CctxStatus *Status `protobuf:"bytes,8,opt,name=cctx_status,json=cctxStatus,proto3" json:"cctx_status,omitempty"` InboundTxParams *InboundTxParams `protobuf:"bytes,9,opt,name=inbound_tx_params,json=inboundTxParams,proto3" json:"inbound_tx_params,omitempty"` OutboundTxParams []*OutboundTxParams `protobuf:"bytes,10,rep,name=outbound_tx_params,json=outboundTxParams,proto3" json:"outbound_tx_params,omitempty"` - IsRefunded bool `protobuf:"varint,11,opt,name=isRefunded,proto3" json:"isRefunded,omitempty"` } func (m *CrossChainTx) Reset() { *m = CrossChainTx{} } @@ -536,13 +543,6 @@ func (m *CrossChainTx) GetOutboundTxParams() []*OutboundTxParams { return nil } -func (m *CrossChainTx) GetIsRefunded() bool { - if m != nil { - return m.IsRefunded - } - return false -} - func init() { proto.RegisterEnum("zetachain.zetacore.crosschain.CctxStatus", CctxStatus_name, CctxStatus_value) proto.RegisterEnum("zetachain.zetacore.crosschain.TxFinalizationStatus", TxFinalizationStatus_name, TxFinalizationStatus_value) @@ -556,77 +556,77 @@ func init() { func init() { proto.RegisterFile("crosschain/cross_chain_tx.proto", fileDescriptor_af3a0ad055343c21) } var fileDescriptor_af3a0ad055343c21 = []byte{ - // 1115 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xdd, 0x4e, 0x1b, 0x47, - 0x14, 0xf6, 0xc6, 0x8e, 0xb1, 0x8f, 0x01, 0x2f, 0x83, 0x49, 0x57, 0xa4, 0xb1, 0x2d, 0xb7, 0x49, - 0x9c, 0x48, 0xd8, 0x82, 0xa8, 0x8a, 0xd4, 0x3b, 0xa0, 0x90, 0xa0, 0x24, 0x80, 0xb6, 0x70, 0x83, - 0x54, 0x6d, 0xc7, 0xbb, 0x83, 0x3d, 0x8a, 0xbd, 0xe3, 0xee, 0x8c, 0x91, 0x89, 0xfa, 0x10, 0xbd, - 0xe8, 0x23, 0xb4, 0x52, 0x1f, 0x25, 0x97, 0xb9, 0xac, 0x7a, 0x81, 0x2a, 0xb8, 0x6d, 0x6f, 0xfa, - 0x04, 0xd5, 0xfc, 0xec, 0x7a, 0x71, 0xf9, 0xe9, 0xdf, 0xd5, 0x9e, 0x39, 0x33, 0xdf, 0x77, 0x66, - 0xce, 0xf9, 0xce, 0xec, 0x40, 0xcd, 0x8f, 0x18, 0xe7, 0x7e, 0x0f, 0xd3, 0xb0, 0xad, 0x4c, 0x4f, - 0xd9, 0x9e, 0x18, 0xb7, 0x86, 0x11, 0x13, 0x0c, 0x3d, 0x78, 0x47, 0x04, 0x56, 0xbe, 0x96, 0xb2, - 0x58, 0x44, 0x5a, 0x13, 0xcc, 0xf2, 0xa2, 0xcf, 0x06, 0x03, 0x16, 0xb6, 0xf5, 0x47, 0x63, 0x96, - 0x2b, 0x5d, 0xd6, 0x65, 0xca, 0x6c, 0x4b, 0x4b, 0x7b, 0x1b, 0xbf, 0xe7, 0xa0, 0xbc, 0x13, 0x76, - 0xd8, 0x28, 0x0c, 0x0e, 0xc6, 0xfb, 0x38, 0xc2, 0x03, 0x8e, 0xee, 0x41, 0x9e, 0x93, 0x30, 0x20, - 0x91, 0x63, 0xd5, 0xad, 0x66, 0xd1, 0x35, 0x23, 0xf4, 0x08, 0xca, 0xda, 0x32, 0xdb, 0xa1, 0x81, - 0x73, 0xa7, 0x6e, 0x35, 0xb3, 0xee, 0x9c, 0x76, 0x6f, 0x4a, 0xef, 0x4e, 0x80, 0xee, 0x43, 0x51, - 0x8c, 0x3d, 0x16, 0xd1, 0x2e, 0x0d, 0x9d, 0xac, 0xa2, 0x28, 0x88, 0xf1, 0x9e, 0x1a, 0xa3, 0x15, - 0x28, 0xfa, 0x4c, 0x9e, 0xe5, 0x74, 0x48, 0x9c, 0x5c, 0xdd, 0x6a, 0xce, 0xaf, 0xd9, 0x2d, 0xb3, - 0xd1, 0x4d, 0x46, 0xc3, 0x83, 0xd3, 0x21, 0x71, 0x0b, 0xbe, 0xb1, 0x50, 0x05, 0xee, 0x62, 0xce, - 0x89, 0x70, 0xee, 0x2a, 0x1e, 0x3d, 0x40, 0x2f, 0x20, 0x8f, 0x07, 0x6c, 0x14, 0x0a, 0x27, 0x2f, - 0xdd, 0x1b, 0xed, 0xf7, 0x67, 0xb5, 0xcc, 0x2f, 0x67, 0xb5, 0xc7, 0x5d, 0x2a, 0x7a, 0xa3, 0x8e, - 0xe4, 0x6b, 0xfb, 0x8c, 0x0f, 0x18, 0x37, 0x9f, 0x15, 0x1e, 0xbc, 0x6d, 0xcb, 0x90, 0xbc, 0x75, - 0x48, 0x43, 0xe1, 0x1a, 0x38, 0x7a, 0x0e, 0x0e, 0xd5, 0xa7, 0xf7, 0xe4, 0x96, 0x3b, 0x9c, 0x44, - 0x27, 0x24, 0xf0, 0x7a, 0x98, 0xf7, 0x9c, 0x19, 0x15, 0x71, 0x89, 0xc6, 0xd9, 0xd9, 0x33, 0xb3, - 0x2f, 0x31, 0xef, 0xa1, 0xd7, 0xf0, 0xc9, 0x55, 0x40, 0x32, 0x16, 0x24, 0x0a, 0x71, 0xdf, 0xeb, - 0x11, 0xda, 0xed, 0x09, 0xa7, 0x50, 0xb7, 0x9a, 0x39, 0xb7, 0xf6, 0x17, 0x8e, 0x2d, 0xb3, 0xee, - 0xa5, 0x5a, 0x86, 0x3e, 0x83, 0x8f, 0x52, 0x6c, 0x1d, 0xdc, 0xef, 0x33, 0xe1, 0xd1, 0x30, 0x20, - 0x63, 0xa7, 0xa8, 0x76, 0x51, 0x49, 0x18, 0x36, 0xd4, 0xe4, 0x8e, 0x9c, 0x43, 0xdb, 0x50, 0x4f, - 0xc1, 0x8e, 0x69, 0x88, 0xfb, 0xf4, 0x1d, 0x09, 0x3c, 0xa9, 0x89, 0x78, 0x07, 0xa0, 0x76, 0xf0, - 0x71, 0x82, 0xdf, 0x8e, 0x57, 0x1d, 0x11, 0x81, 0x4d, 0x78, 0x0a, 0xf7, 0x26, 0x78, 0x2c, 0x28, - 0x0b, 0x3d, 0x2e, 0xb0, 0x18, 0x71, 0xa7, 0xa4, 0x0a, 0xf4, 0xac, 0x75, 0xa3, 0xde, 0x5a, 0x09, - 0xab, 0xc2, 0x7e, 0xa9, 0xa0, 0x6e, 0x45, 0x5c, 0xe1, 0x6d, 0x7c, 0x03, 0xf3, 0x32, 0xf0, 0xba, - 0xef, 0xcb, 0xfc, 0xd3, 0xb0, 0x8b, 0x3c, 0x58, 0xc4, 0x1d, 0x16, 0x89, 0x78, 0xdf, 0xa6, 0xb0, - 0xd6, 0xbf, 0x2b, 0xec, 0x82, 0xe1, 0x52, 0x41, 0x14, 0x53, 0xe3, 0xfb, 0x19, 0xb0, 0xf7, 0x46, - 0xe2, 0xb2, 0xc6, 0x97, 0xa1, 0x10, 0x11, 0x9f, 0xd0, 0x93, 0x44, 0xe5, 0xc9, 0x18, 0x3d, 0x01, - 0x3b, 0xb6, 0xb5, 0xd2, 0x77, 0x62, 0xa1, 0x97, 0x63, 0x7f, 0x2c, 0xf5, 0x4b, 0x6a, 0xce, 0xde, - 0xaa, 0xe6, 0x89, 0x6e, 0x73, 0xff, 0x4d, 0xb7, 0xab, 0xb0, 0xc4, 0xcc, 0x91, 0x64, 0xe9, 0x05, - 0xe7, 0x5e, 0xc8, 0x42, 0x9f, 0xa8, 0x36, 0xc9, 0xb9, 0x88, 0x25, 0xe7, 0x3d, 0xe0, 0x7c, 0x57, - 0xce, 0x4c, 0x43, 0xba, 0x98, 0x7b, 0x7d, 0x3a, 0xa0, 0xba, 0x85, 0x2e, 0x41, 0x5e, 0x60, 0xfe, - 0x5a, 0xce, 0x5c, 0x05, 0x19, 0x46, 0xd4, 0x27, 0xa6, 0x35, 0x2e, 0x43, 0xf6, 0xe5, 0x0c, 0x6a, - 0x82, 0x9d, 0x86, 0xa8, 0x46, 0x2a, 0xa8, 0xd5, 0xf3, 0x93, 0xd5, 0xaa, 0x83, 0x9e, 0x83, 0x93, - 0x5e, 0x79, 0x85, 0xe8, 0x97, 0x26, 0x88, 0xb4, 0xea, 0x77, 0xe1, 0xd3, 0x34, 0xf0, 0xda, 0xde, - 0xd3, 0xca, 0xaf, 0x4f, 0x48, 0xae, 0x69, 0xbe, 0x36, 0x54, 0xa6, 0x4f, 0x39, 0xe2, 0x24, 0x70, - 0x2a, 0x0a, 0xbf, 0x70, 0xe9, 0x90, 0x87, 0x9c, 0x04, 0x48, 0x40, 0x2d, 0x0d, 0x20, 0xc7, 0xc7, - 0xc4, 0x17, 0xf4, 0x84, 0xa4, 0x12, 0xb4, 0xa4, 0xca, 0xdb, 0x32, 0xe5, 0x7d, 0xf4, 0x37, 0xca, - 0xbb, 0x13, 0x0a, 0xf7, 0xfe, 0x24, 0xd6, 0x56, 0x4c, 0x9a, 0x64, 0xf6, 0x8b, 0x9b, 0xa2, 0xea, - 0x4a, 0xde, 0x53, 0x3b, 0xbe, 0x86, 0x45, 0x97, 0xf4, 0x01, 0x80, 0x14, 0xcb, 0x70, 0xd4, 0x79, - 0x4b, 0x4e, 0x55, 0x7b, 0x17, 0xdd, 0xa2, 0xe0, 0x7c, 0x5f, 0x39, 0x6e, 0xb8, 0x09, 0x66, 0xff, - 0xef, 0x9b, 0xe0, 0x47, 0x0b, 0xf2, 0xda, 0x44, 0xeb, 0x90, 0x37, 0x51, 0x2c, 0x15, 0xe5, 0xc9, - 0x2d, 0x51, 0x36, 0x7d, 0x31, 0x36, 0xdc, 0x06, 0x88, 0x1e, 0xc2, 0xbc, 0xb6, 0xbc, 0x01, 0xe1, - 0x1c, 0x77, 0x89, 0xea, 0xd8, 0xa2, 0x3b, 0xa7, 0xbd, 0x6f, 0xb4, 0x13, 0xad, 0x42, 0xa5, 0x8f, - 0xb9, 0x38, 0x1c, 0x06, 0x58, 0x10, 0x4f, 0xd0, 0x01, 0xe1, 0x02, 0x0f, 0x86, 0xaa, 0x75, 0xb3, - 0xee, 0xe2, 0x64, 0xee, 0x20, 0x9e, 0x6a, 0xfc, 0x96, 0x85, 0xd9, 0x4d, 0x19, 0x5b, 0xf5, 0xfc, - 0xc1, 0x18, 0x39, 0x30, 0xe3, 0x47, 0x04, 0x0b, 0x16, 0xdf, 0x1c, 0xf1, 0x50, 0xfe, 0xac, 0xb4, - 0x7e, 0x75, 0x6c, 0x3d, 0x40, 0x5f, 0x43, 0x51, 0x5d, 0x6c, 0xc7, 0x84, 0x70, 0xfd, 0x1b, 0xdb, - 0xd8, 0xfc, 0x87, 0x7d, 0xff, 0xc7, 0x59, 0xcd, 0x3e, 0xc5, 0x83, 0xfe, 0xe7, 0x8d, 0x84, 0xa9, - 0xe1, 0x16, 0xa4, 0xbd, 0x4d, 0x08, 0x47, 0x8f, 0xa1, 0x1c, 0x91, 0x3e, 0x3e, 0x25, 0x41, 0x72, - 0xfa, 0xbc, 0xee, 0x39, 0xe3, 0x8e, 0x8f, 0xbf, 0x0d, 0x25, 0xdf, 0x17, 0xe3, 0xb8, 0xa6, 0xb2, - 0x31, 0x4b, 0x6b, 0x0f, 0x6f, 0xc9, 0xb6, 0xc9, 0x34, 0xf8, 0x49, 0xd6, 0xd1, 0x11, 0x2c, 0xa4, - 0x7e, 0x3c, 0x43, 0x75, 0xa5, 0xaa, 0xa6, 0x2d, 0xad, 0xb5, 0x6e, 0x61, 0x9b, 0x7a, 0x6c, 0xb8, - 0x65, 0x3a, 0xf5, 0xfa, 0xf8, 0x0a, 0x50, 0x5a, 0xe7, 0x86, 0x1c, 0xea, 0xd9, 0x66, 0x69, 0xad, - 0x7d, 0x0b, 0xf9, 0xf4, 0x35, 0xef, 0xda, 0x6c, 0xfa, 0xe2, 0xaf, 0x02, 0x50, 0xee, 0x92, 0xe3, - 0x51, 0x18, 0x90, 0x40, 0x35, 0x40, 0xc1, 0x4d, 0x79, 0x9e, 0x7e, 0x0b, 0x30, 0x91, 0x17, 0x42, - 0x30, 0xbf, 0x4f, 0xc2, 0x80, 0x86, 0x5d, 0xb3, 0x6f, 0x3b, 0x83, 0x16, 0xa1, 0x6c, 0x7c, 0x71, - 0x38, 0xdb, 0x42, 0x0b, 0x30, 0x17, 0x8f, 0xde, 0xd0, 0x90, 0x04, 0x76, 0x56, 0xba, 0xcc, 0x3a, - 0x97, 0x9c, 0x90, 0x48, 0xd8, 0x39, 0x34, 0x0b, 0x05, 0x6d, 0x93, 0xc0, 0xbe, 0x8b, 0x4a, 0x30, - 0xb3, 0xae, 0xff, 0x56, 0x76, 0x7e, 0x39, 0xf7, 0xd3, 0x0f, 0x55, 0xeb, 0xe9, 0x2b, 0xa8, 0x5c, - 0xd5, 0x42, 0xc8, 0x86, 0xd9, 0x5d, 0x26, 0x92, 0x7f, 0xb7, 0x9d, 0x41, 0x73, 0x50, 0x9c, 0x0c, - 0x2d, 0xc9, 0xbc, 0x35, 0x26, 0xfe, 0x48, 0x92, 0xdd, 0xd1, 0x64, 0x1b, 0xaf, 0xde, 0x9f, 0x57, - 0xad, 0x0f, 0xe7, 0x55, 0xeb, 0xd7, 0xf3, 0xaa, 0xf5, 0xdd, 0x45, 0x35, 0xf3, 0xe1, 0xa2, 0x9a, - 0xf9, 0xf9, 0xa2, 0x9a, 0x39, 0x5a, 0x4d, 0xe9, 0x4e, 0xe6, 0x71, 0x45, 0xbf, 0x35, 0xe3, 0x94, - 0xb6, 0xc7, 0xed, 0xd4, 0x0b, 0x54, 0xc9, 0xb0, 0x93, 0x57, 0xef, 0xc5, 0x67, 0x7f, 0x06, 0x00, - 0x00, 0xff, 0xff, 0x7f, 0xd3, 0x57, 0x96, 0x9c, 0x0a, 0x00, 0x00, + // 1120 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcd, 0x6e, 0x1b, 0x37, + 0x10, 0xd6, 0x46, 0x8a, 0x2c, 0x8d, 0x6c, 0x6b, 0x4d, 0xcb, 0xe9, 0xc2, 0x69, 0x24, 0x41, 0x6d, + 0x12, 0x25, 0x80, 0x25, 0xd8, 0x41, 0x11, 0xa0, 0x37, 0xdb, 0xb5, 0x13, 0x23, 0x89, 0x6d, 0x6c, + 0xed, 0x8b, 0x81, 0x62, 0x4b, 0xed, 0xd2, 0x12, 0x11, 0x69, 0xa9, 0x2e, 0x29, 0x43, 0x0e, 0xfa, + 0x10, 0x3d, 0xf4, 0x11, 0x7a, 0xe8, 0xa3, 0xe4, 0x50, 0xa0, 0x39, 0x16, 0x3d, 0x18, 0x85, 0x7d, + 0xee, 0xa5, 0x4f, 0x50, 0xf0, 0x67, 0x57, 0x6b, 0xd5, 0x3f, 0xfd, 0x3b, 0xed, 0x70, 0xc8, 0xef, + 0x9b, 0x21, 0xe7, 0x1b, 0x72, 0xa1, 0xe6, 0x47, 0x8c, 0x73, 0xbf, 0x87, 0x69, 0xd8, 0x56, 0xa6, + 0xa7, 0x6c, 0x4f, 0x8c, 0x5b, 0xc3, 0x88, 0x09, 0x86, 0x1e, 0xbc, 0x23, 0x02, 0x2b, 0x5f, 0x4b, + 0x59, 0x2c, 0x22, 0xad, 0x09, 0x66, 0x79, 0xd1, 0x67, 0x83, 0x01, 0x0b, 0xdb, 0xfa, 0xa3, 0x31, + 0xcb, 0x95, 0x2e, 0xeb, 0x32, 0x65, 0xb6, 0xa5, 0xa5, 0xbd, 0x8d, 0xdf, 0x73, 0x50, 0xde, 0x09, + 0x3b, 0x6c, 0x14, 0x06, 0x07, 0xe3, 0x7d, 0x1c, 0xe1, 0x01, 0x47, 0xf7, 0x20, 0xcf, 0x49, 0x18, + 0x90, 0xc8, 0xb1, 0xea, 0x56, 0xb3, 0xe8, 0x9a, 0x11, 0x7a, 0x04, 0x65, 0x6d, 0x99, 0x74, 0x68, + 0xe0, 0xdc, 0xa9, 0x5b, 0xcd, 0xac, 0x3b, 0xa7, 0xdd, 0x9b, 0xd2, 0xbb, 0x13, 0xa0, 0xfb, 0x50, + 0x14, 0x63, 0x8f, 0x45, 0xb4, 0x4b, 0x43, 0x27, 0xab, 0x28, 0x0a, 0x62, 0xbc, 0xa7, 0xc6, 0x68, + 0x05, 0x8a, 0x3e, 0x93, 0x7b, 0x39, 0x1d, 0x12, 0x27, 0x57, 0xb7, 0x9a, 0xf3, 0x6b, 0x76, 0xcb, + 0x24, 0xba, 0xc9, 0x68, 0x78, 0x70, 0x3a, 0x24, 0x6e, 0xc1, 0x37, 0x16, 0xaa, 0xc0, 0x5d, 0xcc, + 0x39, 0x11, 0xce, 0x5d, 0xc5, 0xa3, 0x07, 0xe8, 0x05, 0xe4, 0xf1, 0x80, 0x8d, 0x42, 0xe1, 0xe4, + 0xa5, 0x7b, 0xa3, 0xfd, 0xfe, 0xac, 0x96, 0xf9, 0xf5, 0xac, 0xf6, 0xb8, 0x4b, 0x45, 0x6f, 0xd4, + 0x91, 0x7c, 0x6d, 0x9f, 0xf1, 0x01, 0xe3, 0xe6, 0xb3, 0xc2, 0x83, 0xb7, 0x6d, 0x19, 0x92, 0xb7, + 0x0e, 0x69, 0x28, 0x5c, 0x03, 0x47, 0xcf, 0xc1, 0xa1, 0x7a, 0xf7, 0x9e, 0x4c, 0xb9, 0xc3, 0x49, + 0x74, 0x42, 0x02, 0xaf, 0x87, 0x79, 0xcf, 0x99, 0x51, 0x11, 0x97, 0x68, 0x7c, 0x3a, 0x7b, 0x66, + 0xf6, 0x25, 0xe6, 0x3d, 0xf4, 0x1a, 0x3e, 0xb9, 0x0a, 0x48, 0xc6, 0x82, 0x44, 0x21, 0xee, 0x7b, + 0x3d, 0x42, 0xbb, 0x3d, 0xe1, 0x14, 0xea, 0x56, 0x33, 0xe7, 0xd6, 0xfe, 0xc2, 0xb1, 0x65, 0xd6, + 0xbd, 0x54, 0xcb, 0xd0, 0x67, 0xf0, 0x51, 0x8a, 0xad, 0x83, 0xfb, 0x7d, 0x26, 0x3c, 0x1a, 0x06, + 0x64, 0xec, 0x14, 0x55, 0x16, 0x95, 0x84, 0x61, 0x43, 0x4d, 0xee, 0xc8, 0x39, 0xb4, 0x0d, 0xf5, + 0x14, 0xec, 0x98, 0x86, 0xb8, 0x4f, 0xdf, 0x91, 0xc0, 0x93, 0x9a, 0x88, 0x33, 0x00, 0x95, 0xc1, + 0xc7, 0x09, 0x7e, 0x3b, 0x5e, 0x75, 0x44, 0x04, 0x36, 0xe1, 0x29, 0xdc, 0x9b, 0xe0, 0xb1, 0xa0, + 0x2c, 0xf4, 0xb8, 0xc0, 0x62, 0xc4, 0x9d, 0x92, 0x2a, 0xd0, 0xb3, 0xd6, 0x8d, 0x7a, 0x6b, 0x25, + 0xac, 0x0a, 0xfb, 0xa5, 0x82, 0xba, 0x15, 0x71, 0x85, 0xb7, 0xf1, 0x0d, 0xcc, 0xcb, 0xc0, 0xeb, + 0xbe, 0x2f, 0xcf, 0x9f, 0x86, 0x5d, 0xe4, 0xc1, 0x22, 0xee, 0xb0, 0x48, 0xc4, 0x79, 0x9b, 0xc2, + 0x5a, 0xff, 0xae, 0xb0, 0x0b, 0x86, 0x4b, 0x05, 0x51, 0x4c, 0x8d, 0xef, 0x67, 0xc0, 0xde, 0x1b, + 0x89, 0xcb, 0x1a, 0x5f, 0x86, 0x42, 0x44, 0x7c, 0x42, 0x4f, 0x12, 0x95, 0x27, 0x63, 0xf4, 0x04, + 0xec, 0xd8, 0xd6, 0x4a, 0xdf, 0x89, 0x85, 0x5e, 0x8e, 0xfd, 0xb1, 0xd4, 0x2f, 0xa9, 0x39, 0x7b, + 0xab, 0x9a, 0x27, 0xba, 0xcd, 0xfd, 0x37, 0xdd, 0xae, 0xc2, 0x12, 0x33, 0x5b, 0x92, 0xa5, 0x17, + 0x9c, 0x7b, 0x21, 0x0b, 0x7d, 0xa2, 0xda, 0x24, 0xe7, 0x22, 0x96, 0xec, 0xf7, 0x80, 0xf3, 0x5d, + 0x39, 0x33, 0x0d, 0xe9, 0x62, 0xee, 0xf5, 0xe9, 0x80, 0xea, 0x16, 0xba, 0x04, 0x79, 0x81, 0xf9, + 0x6b, 0x39, 0x73, 0x15, 0x64, 0x18, 0x51, 0x9f, 0x98, 0xd6, 0xb8, 0x0c, 0xd9, 0x97, 0x33, 0xa8, + 0x09, 0x76, 0x1a, 0xa2, 0x1a, 0xa9, 0xa0, 0x56, 0xcf, 0x4f, 0x56, 0xab, 0x0e, 0x7a, 0x0e, 0x4e, + 0x7a, 0xe5, 0x15, 0xa2, 0x5f, 0x9a, 0x20, 0xd2, 0xaa, 0xdf, 0x85, 0x4f, 0xd3, 0xc0, 0x6b, 0x7b, + 0x4f, 0x2b, 0xbf, 0x3e, 0x21, 0xb9, 0xa6, 0xf9, 0xda, 0x50, 0x99, 0xde, 0xe5, 0x88, 0x93, 0xc0, + 0xa9, 0x28, 0xfc, 0xc2, 0xa5, 0x4d, 0x1e, 0x72, 0x12, 0x20, 0x01, 0xb5, 0x34, 0x80, 0x1c, 0x1f, + 0x13, 0x5f, 0xd0, 0x13, 0x92, 0x3a, 0xa0, 0x25, 0x55, 0xde, 0x96, 0x29, 0xef, 0xa3, 0xbf, 0x51, + 0xde, 0x9d, 0x50, 0xb8, 0xf7, 0x27, 0xb1, 0xb6, 0x62, 0xd2, 0xe4, 0x64, 0xbf, 0xb8, 0x29, 0xaa, + 0xae, 0xe4, 0x3d, 0x95, 0xf1, 0x35, 0x2c, 0xba, 0xa4, 0x0f, 0x00, 0xa4, 0x58, 0x86, 0xa3, 0xce, + 0x5b, 0x72, 0xaa, 0xda, 0xbb, 0xe8, 0x16, 0x05, 0xe7, 0xfb, 0xca, 0x71, 0xc3, 0x4d, 0x30, 0xfb, + 0x7f, 0xdf, 0x04, 0x3f, 0x5b, 0x90, 0xd7, 0x26, 0x5a, 0x87, 0xbc, 0x89, 0x62, 0xa9, 0x28, 0x4f, + 0x6e, 0x89, 0xb2, 0xe9, 0x8b, 0xb1, 0xe1, 0x36, 0x40, 0xf4, 0x10, 0xe6, 0xb5, 0xe5, 0x0d, 0x08, + 0xe7, 0xb8, 0x4b, 0x54, 0xc7, 0x16, 0xdd, 0x39, 0xed, 0x7d, 0xa3, 0x9d, 0x68, 0x15, 0x2a, 0x7d, + 0xcc, 0xc5, 0xe1, 0x30, 0xc0, 0x82, 0x78, 0x82, 0x0e, 0x08, 0x17, 0x78, 0x30, 0x54, 0xad, 0x9b, + 0x75, 0x17, 0x27, 0x73, 0x07, 0xf1, 0x14, 0x6a, 0x42, 0x99, 0xf2, 0x75, 0x79, 0xab, 0xb8, 0xe4, + 0x78, 0x14, 0x06, 0x24, 0x50, 0xcd, 0x5b, 0x70, 0xa7, 0xdd, 0x8d, 0x9f, 0xb2, 0x30, 0xbb, 0x29, + 0xb3, 0x54, 0xb7, 0xc3, 0xc1, 0x18, 0x39, 0x30, 0xe3, 0x47, 0x04, 0x0b, 0x16, 0xdf, 0x31, 0xf1, + 0x50, 0x3e, 0x6b, 0x5a, 0xe9, 0x3a, 0x4b, 0x3d, 0x40, 0x5f, 0x43, 0x51, 0x5d, 0x81, 0xc7, 0x84, + 0x70, 0xfd, 0xe0, 0x6d, 0x6c, 0xfe, 0xc3, 0x1b, 0xe2, 0x8f, 0xb3, 0x9a, 0x7d, 0x8a, 0x07, 0xfd, + 0xcf, 0x1b, 0x09, 0x53, 0xc3, 0x2d, 0x48, 0x7b, 0x9b, 0x10, 0x8e, 0x1e, 0x43, 0x39, 0x22, 0x7d, + 0x7c, 0x4a, 0x82, 0xe4, 0x9c, 0xf2, 0xba, 0x3b, 0x8d, 0x3b, 0x3e, 0xa8, 0x6d, 0x28, 0xf9, 0xbe, + 0x18, 0xc7, 0xd5, 0x97, 0x2d, 0x5c, 0x5a, 0x7b, 0x78, 0x4b, 0x5d, 0x4c, 0x4d, 0xc0, 0x4f, 0xea, + 0x83, 0x8e, 0x60, 0x21, 0xf5, 0x44, 0x0d, 0xd5, 0xe5, 0xab, 0xda, 0xbb, 0xb4, 0xd6, 0xba, 0x85, + 0x6d, 0xea, 0xb7, 0xc4, 0x2d, 0xd3, 0xa9, 0xff, 0x94, 0xaf, 0x00, 0xa5, 0x3b, 0xc2, 0x90, 0x43, + 0x3d, 0xdb, 0x2c, 0xad, 0xb5, 0x6f, 0x21, 0x9f, 0x7e, 0x10, 0x5c, 0x9b, 0x4d, 0x79, 0x9e, 0x7e, + 0x0b, 0x30, 0x11, 0x1a, 0x42, 0x30, 0xbf, 0x4f, 0xc2, 0x80, 0x86, 0x5d, 0x93, 0x97, 0x9d, 0x41, + 0x8b, 0x50, 0x36, 0xbe, 0x98, 0xce, 0xb6, 0xd0, 0x02, 0xcc, 0xc5, 0xa3, 0x37, 0x34, 0x24, 0x81, + 0x9d, 0x95, 0x2e, 0xb3, 0xce, 0x25, 0x27, 0x24, 0x12, 0x76, 0x0e, 0xcd, 0x42, 0x41, 0xdb, 0x24, + 0xb0, 0xef, 0xa2, 0x12, 0xcc, 0xac, 0xeb, 0x77, 0xcb, 0xce, 0x2f, 0xe7, 0x7e, 0xfc, 0xa1, 0x6a, + 0x3d, 0x7d, 0x05, 0x95, 0xab, 0x9a, 0x09, 0xd9, 0x30, 0xbb, 0xcb, 0x44, 0xf2, 0x8a, 0xdb, 0x19, + 0x34, 0x07, 0xc5, 0xc9, 0xd0, 0x92, 0xcc, 0x5b, 0x63, 0xe2, 0x8f, 0x24, 0xd9, 0x1d, 0x4d, 0xb6, + 0xf1, 0xea, 0xfd, 0x79, 0xd5, 0xfa, 0x70, 0x5e, 0xb5, 0x7e, 0x3b, 0xaf, 0x5a, 0xdf, 0x5d, 0x54, + 0x33, 0x1f, 0x2e, 0xaa, 0x99, 0x5f, 0x2e, 0xaa, 0x99, 0xa3, 0xd5, 0x94, 0xae, 0xe4, 0x39, 0xad, + 0xe8, 0xbf, 0xce, 0xf8, 0xc8, 0xda, 0xe3, 0x76, 0xea, 0x5f, 0x54, 0xc9, 0xac, 0x93, 0x57, 0x7f, + 0x8e, 0xcf, 0xfe, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x13, 0xc7, 0x24, 0x8d, 0xa6, 0x0a, 0x00, 0x00, } func (m *InboundTxParams) Marshal() (dAtA []byte, err error) { @@ -899,6 +899,16 @@ func (m *Status) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.IsAbortRefunded { + i-- + if m.IsAbortRefunded { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } if m.LastUpdateTimestamp != 0 { i = encodeVarintCrossChainTx(dAtA, i, uint64(m.LastUpdateTimestamp)) i-- @@ -939,16 +949,6 @@ func (m *CrossChainTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.IsRefunded { - i-- - if m.IsRefunded { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x58 - } if len(m.OutboundTxParams) > 0 { for iNdEx := len(m.OutboundTxParams) - 1; iNdEx >= 0; iNdEx-- { { @@ -1162,6 +1162,9 @@ func (m *Status) Size() (n int) { if m.LastUpdateTimestamp != 0 { n += 1 + sovCrossChainTx(uint64(m.LastUpdateTimestamp)) } + if m.IsAbortRefunded { + n += 2 + } return n } @@ -1199,9 +1202,6 @@ func (m *CrossChainTx) Size() (n int) { n += 1 + l + sovCrossChainTx(uint64(l)) } } - if m.IsRefunded { - n += 2 - } return n } @@ -2163,6 +2163,26 @@ func (m *Status) Unmarshal(dAtA []byte) error { break } } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsAbortRefunded", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsAbortRefunded = bool(v != 0) default: iNdEx = preIndex skippy, err := skipCrossChainTx(dAtA[iNdEx:]) @@ -2449,26 +2469,6 @@ func (m *CrossChainTx) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 11: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field IsRefunded", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.IsRefunded = bool(v != 0) default: iNdEx = preIndex skippy, err := skipCrossChainTx(dAtA[iNdEx:]) From 367bbd99e207d10bcadb47b171e9e1e22de878da Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 01:41:01 -0500 Subject: [PATCH 13/50] generate files --- docs/cli/zetacored/zetacored_tx_crosschain.md | 1 + .../zetacored_tx_crosschain_refund-aborted.md | 52 ++++++++++++++++++ docs/openapi/openapi.swagger.yaml | 6 +- docs/spec/crosschain/messages.md | 10 ++++ typescript/crosschain/cross_chain_tx_pb.d.ts | 7 ++- typescript/crosschain/tx_pb.d.ts | 55 +++++++++++++++++++ .../msg_server_refund_aborted_tx_test.go | 30 +++++----- x/crosschain/keeper/refund.go | 2 +- 8 files changed, 145 insertions(+), 18 deletions(-) create mode 100644 docs/cli/zetacored/zetacored_tx_crosschain_refund-aborted.md diff --git a/docs/cli/zetacored/zetacored_tx_crosschain.md b/docs/cli/zetacored/zetacored_tx_crosschain.md index bb8a200308..ff4439d3ac 100644 --- a/docs/cli/zetacored/zetacored_tx_crosschain.md +++ b/docs/cli/zetacored/zetacored_tx_crosschain.md @@ -34,6 +34,7 @@ zetacored tx crosschain [flags] * [zetacored tx crosschain inbound-voter](zetacored_tx_crosschain_inbound-voter.md) - Broadcast message sendVoter * [zetacored tx crosschain migrate-tss-funds](zetacored_tx_crosschain_migrate-tss-funds.md) - Migrate TSS funds to the latest TSS address * [zetacored tx crosschain outbound-voter](zetacored_tx_crosschain_outbound-voter.md) - Broadcast message receiveConfirmation +* [zetacored tx crosschain refund-aborted](zetacored_tx_crosschain_refund-aborted.md) - Refund a aborted tx , the refund address is optional, if not provided, the refund will be sent to the sender/tx origin of the cctx. * [zetacored tx crosschain remove-from-out-tx-tracker](zetacored_tx_crosschain_remove-from-out-tx-tracker.md) - Remove a out-tx-tracker * [zetacored tx crosschain update-tss-address](zetacored_tx_crosschain_update-tss-address.md) - Create a new TSSVoter diff --git a/docs/cli/zetacored/zetacored_tx_crosschain_refund-aborted.md b/docs/cli/zetacored/zetacored_tx_crosschain_refund-aborted.md new file mode 100644 index 0000000000..ca53f46410 --- /dev/null +++ b/docs/cli/zetacored/zetacored_tx_crosschain_refund-aborted.md @@ -0,0 +1,52 @@ +# tx crosschain refund-aborted + +Refund a aborted tx , the refund address is optional, if not provided, the refund will be sent to the sender/tx origin of the cctx. + +``` +zetacored tx crosschain refund-aborted [cctx-index] [refund-address] [flags] +``` + +### Options + +``` + -a, --account-number uint The account number of the signing account (offline mode only) + --aux Generate aux signer data instead of sending a tx + -b, --broadcast-mode string Transaction broadcasting mode (sync|async|block) + --dry-run ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it (when enabled, the local Keybase is not accessible) + --fee-granter string Fee granter grants fees for the transaction + --fee-payer string Fee payer pays fees for the transaction instead of deducting from the signer + --fees string Fees to pay along with transaction; eg: 10uatom + --from string Name or address of private key with which to sign + --gas string gas limit to set per-transaction; set to "auto" to calculate sufficient gas automatically. Note: "auto" option doesn't always report accurate results. Set a valid coin value to adjust the result. Can be used instead of "fees". (default 200000) + --gas-adjustment float adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored (default 1) + --gas-prices string Gas prices in decimal format to determine the transaction fee (e.g. 0.1uatom) + --generate-only Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase only accessed when providing a key name) + -h, --help help for refund-aborted + --keyring-backend string Select keyring's backend (os|file|kwallet|pass|test|memory) + --keyring-dir string The client Keyring directory; if omitted, the default 'home' directory will be used + --ledger Use a connected Ledger device + --node string [host]:[port] to tendermint rpc interface for this chain + --note string Note to add a description to the transaction (previously --memo) + --offline Offline mode (does not allow any online functionality) + -o, --output string Output format (text|json) + -s, --sequence uint The sequence number of the signing account (offline mode only) + --sign-mode string Choose sign mode (direct|amino-json|direct-aux), this is an advanced feature + --timeout-height uint Set a block timeout height to prevent the tx from being committed past a certain height + --tip string Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator + -y, --yes Skip tx broadcasting prompt confirmation +``` + +### Options inherited from parent commands + +``` + --chain-id string The network chain ID + --home string directory for config and data + --log_format string The logging format (json|plain) + --log_level string The logging level (trace|debug|info|warn|error|fatal|panic) + --trace print out full stack trace on errors +``` + +### SEE ALSO + +* [zetacored tx crosschain](zetacored_tx_crosschain.md) - crosschain transactions subcommands + diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 1ba9d75fcb..2fb5b28e3e 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -50716,7 +50716,7 @@ definitions: - OutboundMined: the corresponding outbound tx is mined - PendingRevert: outbound cannot succeed; should revert inbound - Reverted: inbound reverted. - - Aborted: inbound tx error or invalid paramters and cannot revert; just abort + - Aborted: inbound tx error or invalid paramters and cannot revert; just abort. But the amount can be refunded to zetachain using and admin proposal crosschainCrossChainTx: type: object properties: @@ -50846,6 +50846,8 @@ definitions: type: object crosschainMsgMigrateTssFundsResponse: type: object + crosschainMsgRefundAbortedCCTXResponse: + type: object crosschainMsgRemoveFromOutTxTrackerResponse: type: object crosschainMsgUpdateTssAddressResponse: @@ -51845,6 +51847,8 @@ definitions: lastUpdate_timestamp: type: string format: int64 + isAbortRefunded: + type: boolean zetacoreemissionsParams: type: object properties: diff --git a/docs/spec/crosschain/messages.md b/docs/spec/crosschain/messages.md index 1659a95bf0..3b8e5a0c7d 100644 --- a/docs/spec/crosschain/messages.md +++ b/docs/spec/crosschain/messages.md @@ -270,3 +270,13 @@ message MsgAbortStuckCCTX { } ``` +## MsgRefundAbortedCCTX + +```proto +message MsgRefundAbortedCCTX { + string creator = 1; + string cctx_index = 2; + string refund_address = 3; +} +``` + diff --git a/typescript/crosschain/cross_chain_tx_pb.d.ts b/typescript/crosschain/cross_chain_tx_pb.d.ts index d8216afcff..0157548d54 100644 --- a/typescript/crosschain/cross_chain_tx_pb.d.ts +++ b/typescript/crosschain/cross_chain_tx_pb.d.ts @@ -47,7 +47,7 @@ export declare enum CctxStatus { Reverted = 5, /** - * inbound tx error or invalid paramters and cannot revert; just abort + * inbound tx error or invalid paramters and cannot revert; just abort. But the amount can be refunded to zetachain using and admin proposal * * @generated from enum value: Aborted = 6; */ @@ -302,6 +302,11 @@ export declare class Status extends Message { */ lastUpdateTimestamp: bigint; + /** + * @generated from field: bool isAbortRefunded = 4; + */ + isAbortRefunded: boolean; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/typescript/crosschain/tx_pb.d.ts b/typescript/crosschain/tx_pb.d.ts index b96408964c..2371a9405c 100644 --- a/typescript/crosschain/tx_pb.d.ts +++ b/typescript/crosschain/tx_pb.d.ts @@ -778,3 +778,58 @@ export declare class MsgAbortStuckCCTXResponse extends Message | undefined, b: MsgAbortStuckCCTXResponse | PlainMessage | undefined): boolean; } +/** + * @generated from message zetachain.zetacore.crosschain.MsgRefundAbortedCCTX + */ +export declare class MsgRefundAbortedCCTX extends Message { + /** + * @generated from field: string creator = 1; + */ + creator: string; + + /** + * @generated from field: string cctx_index = 2; + */ + cctxIndex: string; + + /** + * if not provided, the refund will be sent to the sender/txOrgin + * + * @generated from field: string refund_address = 3; + */ + refundAddress: string; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.MsgRefundAbortedCCTX"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): MsgRefundAbortedCCTX; + + static fromJson(jsonValue: JsonValue, options?: Partial): MsgRefundAbortedCCTX; + + static fromJsonString(jsonString: string, options?: Partial): MsgRefundAbortedCCTX; + + static equals(a: MsgRefundAbortedCCTX | PlainMessage | undefined, b: MsgRefundAbortedCCTX | PlainMessage | undefined): boolean; +} + +/** + * @generated from message zetachain.zetacore.crosschain.MsgRefundAbortedCCTXResponse + */ +export declare class MsgRefundAbortedCCTXResponse extends Message { + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.MsgRefundAbortedCCTXResponse"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): MsgRefundAbortedCCTXResponse; + + static fromJson(jsonValue: JsonValue, options?: Partial): MsgRefundAbortedCCTXResponse; + + static fromJsonString(jsonString: string, options?: Partial): MsgRefundAbortedCCTXResponse; + + static equals(a: MsgRefundAbortedCCTXResponse | PlainMessage | undefined, b: MsgRefundAbortedCCTXResponse | PlainMessage | undefined): boolean; +} + diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index 4c11795d3f..5bbbdee61c 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -25,7 +25,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted - cctx.IsRefunded = false + cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_Gas @@ -44,7 +44,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) - require.True(t, c.IsRefunded) + require.True(t, c.CctxStatus.IsAbortRefunded) }) t.Run("Successfully refund tx for coin-type Zeta", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) @@ -55,7 +55,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted - cctx.IsRefunded = false + cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_Zeta @@ -73,7 +73,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Amount.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) - require.True(t, c.IsRefunded) + require.True(t, c.CctxStatus.IsAbortRefunded) }) t.Run("Successfully refund to refund address if provided", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) @@ -84,7 +84,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted - cctx.IsRefunded = false + cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_Zeta @@ -102,7 +102,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Amount.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) - require.True(t, c.IsRefunded) + require.True(t, c.CctxStatus.IsAbortRefunded) }) t.Run("Failed refund if address provided is invalid", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) @@ -113,7 +113,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted - cctx.IsRefunded = false + cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_Zeta @@ -136,7 +136,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted - cctx.IsRefunded = false + cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_ERC20 cctx.InboundTxParams.Asset = asset @@ -165,7 +165,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) - require.True(t, c.IsRefunded) + require.True(t, c.CctxStatus.IsAbortRefunded) }) t.Run("Successfully refund tx for coin-type Gas with BTC sender", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) @@ -176,7 +176,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted - cctx.IsRefunded = false + cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_Gas @@ -195,7 +195,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) - require.True(t, c.IsRefunded) + require.True(t, c.CctxStatus.IsAbortRefunded) }) t.Run("Fail refund if status is not aborted", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) @@ -206,7 +206,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_PendingOutbound - cctx.IsRefunded = false + cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_Gas @@ -221,7 +221,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.ErrorContains(t, err, "CCTX is not aborted") c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) - require.False(t, c.IsRefunded) + require.False(t, c.CctxStatus.IsAbortRefunded) }) t.Run("Fail refund if status cctx not found", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) @@ -232,7 +232,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_PendingOutbound - cctx.IsRefunded = false + cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_Gas @@ -254,7 +254,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted - cctx.IsRefunded = false + cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_Gas diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index 775f848c60..a45f75a2ab 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -57,7 +57,7 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai // RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype zeta func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { // if coin type is Zeta, handle this as a deposit ZETA to zEVM. - // deposit the amount to the tx orgin instead of receiver as this is a refund + // deposit the amount to the tx origin instead of receiver as this is a refund if cctx.InboundTxParams.Amount.IsNil() || cctx.InboundTxParams.Amount.IsZero() { return errors.New("no amount to refund") } From f7b9e05286588675cf2bd66469003e52def763c5 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 01:44:10 -0500 Subject: [PATCH 14/50] move string for refund aborted type to message file --- common/authz_tx_types.go | 1 - x/crosschain/types/message_refund_aborted.go | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/authz_tx_types.go b/common/authz_tx_types.go index 5477ad8841..2eb205f6f9 100644 --- a/common/authz_tx_types.go +++ b/common/authz_tx_types.go @@ -7,7 +7,6 @@ const ( OutboundVoter TxType = "OutboundVoter" NonceVoter TxType = "NonceVoter" GasPriceVoter TxType = "GasPriceVoter" - RefundAborted TxType = "RefundAborted" ) func (t TxType) String() string { diff --git a/x/crosschain/types/message_refund_aborted.go b/x/crosschain/types/message_refund_aborted.go index 1034c7ee18..698d499b09 100644 --- a/x/crosschain/types/message_refund_aborted.go +++ b/x/crosschain/types/message_refund_aborted.go @@ -5,9 +5,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/zeta-chain/zetacore/common" ) +const RefundAborted = "RefundAbortedCCTX" + var _ sdk.Msg = &MsgRefundAbortedCCTX{} func NewMsgRefundAbortedCCTX(creator string, cctxIndex string, refundAddress string) *MsgRefundAbortedCCTX { @@ -23,7 +24,7 @@ func (msg *MsgRefundAbortedCCTX) Route() string { } func (msg *MsgRefundAbortedCCTX) Type() string { - return common.RefundAborted.String() + return RefundAborted } func (msg *MsgRefundAbortedCCTX) GetSigners() []sdk.AccAddress { From c39f3348199bef4858a1525c728755affaf459a2 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 02:12:27 -0500 Subject: [PATCH 15/50] add check for zetaccounting --- .../keeper/msg_server_refund_aborted_tx.go | 17 ++-- .../msg_server_refund_aborted_tx_test.go | 95 ++++++++++++++----- x/crosschain/keeper/refund_test.go | 19 ++++ x/crosschain/keeper/zeta_accounting.go | 7 +- x/crosschain/types/errors.go | 3 + 5 files changed, 109 insertions(+), 32 deletions(-) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 68813c0bed..bf8fe85091 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -55,20 +55,25 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund if refundAddress == (ethcommon.Address{}) { return nil, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address") } - + // Check if aborted amount is available to maintain zeta accounting + // NOTE: Need to verify if this check works / is required in athens 3 + if cctx.InboundTxParams.CoinType == common.CoinType_Zeta { + err := k.RemoveZetaAbortedAmount(ctx, cctx.GetCurrentOutTxParam().Amount) + if err != nil { + return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) + } + } // refund the amount - err := k.RefundAbortedAmountOnZetaChain(ctx, cctx, refundAddress) + tmpCtx, commit := ctx.CacheContext() + err := k.RefundAbortedAmountOnZetaChain(tmpCtx, cctx, refundAddress) if err != nil { return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) } + commit() // set the cctx as refunded cctx.CctxStatus.IsAbortRefunded = true k.SetCrossChainTx(ctx, cctx) - // Include the refunded amount in ZetaAccount, so we can now remove it from the ZetaAbortedAmount counter. - if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { - k.RemoveZetaAbortedAmount(ctx, cctx.GetCurrentOutTxParam().Amount) - } return &types.MsgRefundAbortedCCTXResponse{}, nil } diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index 5bbbdee61c..8b3a2f256d 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "testing" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" @@ -60,6 +61,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) + k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, @@ -75,7 +77,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Successfully refund to refund address if provided", func(t *testing.T) { + t.Run("Successfully refund to optional refund address if provided", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -89,6 +91,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) + k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) refundAddress := sample.EthAddress() _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ @@ -104,28 +107,6 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Failed refund if address provided is invalid", func(t *testing.T) { - k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) - admin := sample.AccAddress() - chainID := getValidEthChainID(t) - setAdminPolicies(ctx, zk, admin) - msgServer := keeper.NewMsgServerImpl(*k) - k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) - cctx := sample.CrossChainTx(t, "sample-index") - cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted - cctx.CctxStatus.IsAbortRefunded = false - cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender - cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Zeta - k.SetCrossChainTx(ctx, *cctx) - deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) - _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ - Creator: admin, - CctxIndex: cctx.Index, - RefundAddress: "invalid-address", - }) - require.ErrorContains(t, err, "invalid refund address") - }) t.Run("Successfully refund tx for coin-type ERC20", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() @@ -197,6 +178,29 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) + t.Run("Fail refund if address provided is invalid", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.CctxStatus.IsAbortRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + k.SetCrossChainTx(ctx, *cctx) + k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "invalid-address", + }) + require.ErrorContains(t, err, "invalid refund address") + }) t.Run("Fail refund if status is not aborted", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() @@ -268,4 +272,49 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "invalid refund address") }) + t.Run("Fail refund tx for coin-type Zeta if zeta accounting object is not present", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.CctxStatus.IsAbortRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + k.SetCrossChainTx(ctx, *cctx) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "", + }) + require.ErrorContains(t, err, "unable to find zeta accounting") + }) + t.Run("Fail refund tx for coin-type Zeta if zeta accounting does not have enough aborted amount", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.CctxStatus.IsAbortRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + k.SetCrossChainTx(ctx, *cctx) + k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: sdkmath.OneUint()}) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "", + }) + require.ErrorContains(t, err, "insufficient zeta amount") + }) } diff --git a/x/crosschain/keeper/refund_test.go b/x/crosschain/keeper/refund_test.go index fbf25d0240..04fbda1359 100644 --- a/x/crosschain/keeper/refund_test.go +++ b/x/crosschain/keeper/refund_test.go @@ -189,6 +189,14 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { ) require.ErrorContains(t, err, "unsupported coin type") + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + }}, + sample.EthAddress(), + ) + require.ErrorContains(t, err, "unsupported coin type") + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_ERC20, @@ -210,6 +218,17 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { ) require.ErrorContains(t, err, "no amount to refund") + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: getValidEthChainID(t), + Sender: sample.EthAddress().String(), + Amount: math.ZeroUint(), + }}, + sample.EthAddress(), + ) + require.ErrorContains(t, err, "no amount to refund") + // the foreign coin has not been set err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ diff --git a/x/crosschain/keeper/zeta_accounting.go b/x/crosschain/keeper/zeta_accounting.go index ffddc8ba1f..2f9a849666 100644 --- a/x/crosschain/keeper/zeta_accounting.go +++ b/x/crosschain/keeper/zeta_accounting.go @@ -34,14 +34,15 @@ func (k Keeper) AddZetaAbortedAmount(ctx sdk.Context, amount sdkmath.Uint) { k.SetZetaAccounting(ctx, zetaAccounting) } -func (k Keeper) RemoveZetaAbortedAmount(ctx sdk.Context, amount sdkmath.Uint) { +func (k Keeper) RemoveZetaAbortedAmount(ctx sdk.Context, amount sdkmath.Uint) error { zetaAccounting, found := k.GetZetaAccounting(ctx) if !found { - return + return types.ErrUnableToFindZetaAccounting } if zetaAccounting.AbortedZetaAmount.LT(amount) { - return + return types.ErrInsufficientZetaAmount } zetaAccounting.AbortedZetaAmount = zetaAccounting.AbortedZetaAmount.Sub(amount) k.SetZetaAccounting(ctx, zetaAccounting) + return nil } diff --git a/x/crosschain/types/errors.go b/x/crosschain/types/errors.go index b531cc6b3f..be5e034578 100644 --- a/x/crosschain/types/errors.go +++ b/x/crosschain/types/errors.go @@ -50,4 +50,7 @@ var ( ErrInvalidStatus = errorsmod.Register(ModuleName, 1147, "invalid status") ErrUnableProcessRefund = errorsmod.Register(ModuleName, 1148, "unable to process refund") + + ErrUnableToFindZetaAccounting = errorsmod.Register(ModuleName, 1149, "unable to find zeta accounting") + ErrInsufficientZetaAmount = errorsmod.Register(ModuleName, 1150, "insufficient zeta amount") ) From d8d010ef08ac4c6580d26529d639c35255b32df3 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 11:27:44 -0500 Subject: [PATCH 16/50] changelog entry --- changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.md b/changelog.md index 3c82c9f527..110cd49762 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,9 @@ ## Unreleased * `zetaclientd start` : 2 inputs required from stdin +### Features + +*[1728] (https://github.com/zeta-chain/node/pull/1728) - allow aborted transactions to be refunded by minting tokens to zEvm. ### Refactor From 8b41e78eb345bb87b7d6539964206da537e32601 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 11:45:15 -0500 Subject: [PATCH 17/50] add additional check for refund address --- .../keeper/msg_server_refund_aborted_tx.go | 7 ++++-- .../msg_server_refund_aborted_tx_test.go | 25 ++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index bf8fe85091..198e3a02c6 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -26,7 +26,7 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund } // make sure separate refund address is provided for bitcoin chain as we cannot refund to tx origin or sender in this case if common.IsBitcoinChain(cctx.InboundTxParams.SenderChainId) && msg.RefundAddress == "" { - return nil, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address") + return nil, errorsmod.Wrap(types.ErrInvalidAddress, "refund address is required for bitcoin chain") } // check if the cctx is aborted @@ -49,9 +49,12 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund refundAddress = ethcommon.HexToAddress(cctx.InboundTxParams.Sender) } if msg.RefundAddress != "" { + if !ethcommon.IsHexAddress(msg.RefundAddress) { + return nil, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address provided") + } refundAddress = ethcommon.HexToAddress(msg.RefundAddress) } - // Make sure the refund address is valid + // Double check to make sure the refund address is valid if refundAddress == (ethcommon.Address{}) { return nil, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address") } diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index 8b3a2f256d..6a31090286 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -201,6 +201,29 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "invalid refund address") }) + t.Run("Fail refund if address provided is invalid 2 ", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.CctxStatus.IsAbortRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + k.SetCrossChainTx(ctx, *cctx) + k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "0x0000000000000000000000000000000000000000", + }) + require.ErrorContains(t, err, "invalid refund address") + }) t.Run("Fail refund if status is not aborted", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() @@ -270,7 +293,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { CctxIndex: cctx.Index, RefundAddress: "", }) - require.ErrorContains(t, err, "invalid refund address") + require.ErrorContains(t, err, "refund address is required for bitcoin chain") }) t.Run("Fail refund tx for coin-type Zeta if zeta accounting object is not present", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) From 4b41800b66603ec6b025b4e1bf4d5d6a055434c9 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 11:51:49 -0500 Subject: [PATCH 18/50] account for inbound amount --- x/crosschain/keeper/msg_server_refund_aborted_tx.go | 2 +- x/crosschain/keeper/refund.go | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 198e3a02c6..33b5160536 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -61,7 +61,7 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund // Check if aborted amount is available to maintain zeta accounting // NOTE: Need to verify if this check works / is required in athens 3 if cctx.InboundTxParams.CoinType == common.CoinType_Zeta { - err := k.RemoveZetaAbortedAmount(ctx, cctx.GetCurrentOutTxParam().Amount) + err := k.RemoveZetaAbortedAmount(ctx, cctx.InboundTxParams.Amount) if err != nil { return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) } diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index a45f75a2ab..e331d7acba 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -58,6 +58,11 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { // if coin type is Zeta, handle this as a deposit ZETA to zEVM. // deposit the amount to the tx origin instead of receiver as this is a refund + chainID := cctx.InboundTxParams.SenderChainId + // check if chain is supported + if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { + return zetaObserverTypes.ErrSupportedChains + } if cctx.InboundTxParams.Amount.IsNil() || cctx.InboundTxParams.Amount.IsZero() { return errors.New("no amount to refund") } From 191f876830e7bd5153b312c5665191cd93061c04 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 12:17:16 -0500 Subject: [PATCH 19/50] remove checks for unsupported chains, which allows refunds to sender chains which become unsupported --- x/crosschain/keeper/msg_server_vote_inbound_tx.go | 1 + x/crosschain/keeper/refund.go | 12 +++--------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 675051dc45..bc4b9ae8d2 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -194,6 +194,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg // gas payment for erc20 type might fail because no liquidity pool is defined to swap the zrc20 token into the gas token // in this gas we should refund the sender on ZetaChain if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 && ethcommon.IsHexAddress(cctx.InboundTxParams.Sender) { + // Sender is verified to be a valid ethereum address if err := k.RefundAbortedAmountOnZetaChain(ctx, cctx, ethcommon.HexToAddress(cctx.InboundTxParams.Sender)); err != nil { // log the error k.Logger(ctx).Error("failed to refund amount of aborted cctx on ZetaChain", diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index e331d7acba..749fbcd2ff 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -9,7 +9,6 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" - zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" ) func (k Keeper) RefundAbortedAmountOnZetaChain(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { @@ -34,10 +33,6 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai } chainID := cctx.InboundTxParams.SenderChainId amountOfGasTokenLocked := cctx.InboundTxParams.Amount - // check if chain is supported - if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { - return zetaObserverTypes.ErrSupportedChains - } // get the zrc20 contract address fcSenderChain, found := k.fungibleKeeper.GetGasCoinForForeignCoin(ctx, chainID) if !found { @@ -57,11 +52,10 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai // RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype zeta func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { // if coin type is Zeta, handle this as a deposit ZETA to zEVM. - // deposit the amount to the tx origin instead of receiver as this is a refund chainID := cctx.InboundTxParams.SenderChainId - // check if chain is supported - if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { - return zetaObserverTypes.ErrSupportedChains + // check if chain is an EVM chain + if !common.IsEVMChain(chainID) { + return errors.New("only EVM chains are supported for refund when coin type is Zeta") } if cctx.InboundTxParams.Amount.IsNil() || cctx.InboundTxParams.Amount.IsZero() { return errors.New("no amount to refund") From 2e3943d0712ccc6e75b61ecef03dbe164a456062 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 12:25:44 -0500 Subject: [PATCH 20/50] add unit tests for remove zeta amount --- x/crosschain/keeper/zeta_accounting_test.go | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/x/crosschain/keeper/zeta_accounting_test.go b/x/crosschain/keeper/zeta_accounting_test.go index 1d5e1f7921..8a20b4ee4b 100644 --- a/x/crosschain/keeper/zeta_accounting_test.go +++ b/x/crosschain/keeper/zeta_accounting_test.go @@ -47,3 +47,43 @@ func TestKeeper_AddZetaAccounting(t *testing.T) { }) } + +func TestKeeper_RemoveZetaAbortedAmount(t *testing.T) { + t.Run("should remove aborted zeta amount", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + originalAmount := sdkmath.NewUint(100) + k.SetZetaAccounting(ctx, types.ZetaAccounting{ + AbortedZetaAmount: originalAmount, + }) + val, found := k.GetZetaAccounting(ctx) + require.True(t, found) + require.Equal(t, originalAmount, val.AbortedZetaAmount) + removeAmount := originalAmount.Sub(sdkmath.NewUint(50)) + err := k.RemoveZetaAbortedAmount(ctx, removeAmount) + require.NoError(t, err) + val, found = k.GetZetaAccounting(ctx) + require.True(t, found) + require.Equal(t, originalAmount.Sub(removeAmount), val.AbortedZetaAmount) + }) + t.Run("fail remove aborted zeta amount if accounting not set", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + err := k.RemoveZetaAbortedAmount(ctx, sdkmath.OneUint()) + require.ErrorIs(t, err, types.ErrUnableToFindZetaAccounting) + }) + t.Run("fail remove aborted zeta amount if insufficient amount", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + originalAmount := sdkmath.NewUint(100) + k.SetZetaAccounting(ctx, types.ZetaAccounting{ + AbortedZetaAmount: originalAmount, + }) + val, found := k.GetZetaAccounting(ctx) + require.True(t, found) + require.Equal(t, originalAmount, val.AbortedZetaAmount) + removeAmount := originalAmount.Add(sdkmath.NewUint(500)) + err := k.RemoveZetaAbortedAmount(ctx, removeAmount) + require.ErrorIs(t, err, types.ErrInsufficientZetaAmount) + val, found = k.GetZetaAccounting(ctx) + require.True(t, found) + require.Equal(t, originalAmount, val.AbortedZetaAmount) + }) +} From 09c3d8cc44cf7c81728f4eb74cade037c12f227c Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 12:27:09 -0500 Subject: [PATCH 21/50] uni tests zeta accounting --- x/crosschain/keeper/zeta_accounting_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/crosschain/keeper/zeta_accounting_test.go b/x/crosschain/keeper/zeta_accounting_test.go index 8a20b4ee4b..8802fe7666 100644 --- a/x/crosschain/keeper/zeta_accounting_test.go +++ b/x/crosschain/keeper/zeta_accounting_test.go @@ -51,14 +51,14 @@ func TestKeeper_AddZetaAccounting(t *testing.T) { func TestKeeper_RemoveZetaAbortedAmount(t *testing.T) { t.Run("should remove aborted zeta amount", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - originalAmount := sdkmath.NewUint(100) + originalAmount := sdkmath.NewUintFromString("100000000000000000000000000000000000000000000000") k.SetZetaAccounting(ctx, types.ZetaAccounting{ AbortedZetaAmount: originalAmount, }) val, found := k.GetZetaAccounting(ctx) require.True(t, found) require.Equal(t, originalAmount, val.AbortedZetaAmount) - removeAmount := originalAmount.Sub(sdkmath.NewUint(50)) + removeAmount := originalAmount.Sub(sdkmath.NewUintFromString("10000000000000000000000000000000000000000000000")) err := k.RemoveZetaAbortedAmount(ctx, removeAmount) require.NoError(t, err) val, found = k.GetZetaAccounting(ctx) From 54a4936f2aef7e5b54ebab1a28d7086f2f2392de Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 14:07:33 -0500 Subject: [PATCH 22/50] fix abci test for gas price multiplication --- testutil/sample/crosschain.go | 4 ++-- x/crosschain/keeper/abci_test.go | 17 ++++++++--------- x/crosschain/keeper/grpc_query_cctx_test.go | 4 ++-- .../keeper/msg_server_abort_stuck_cctx_test.go | 18 +++++++++--------- .../keeper/msg_server_update_tss_test.go | 12 ++++++------ 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index f31da030f6..87bb3e7245 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -75,7 +75,7 @@ func Status(t *testing.T, index string) *types.Status { LastUpdateTimestamp: r.Int63(), } } -func GetCctxHash(index string) string { +func GetCctxIndexFromString(index string) string { return crypto.Keccak256Hash([]byte(index)).String() } func CrossChainTx(t *testing.T, index string) *types.CrossChainTx { @@ -83,7 +83,7 @@ func CrossChainTx(t *testing.T, index string) *types.CrossChainTx { return &types.CrossChainTx{ Creator: AccAddress(), - Index: GetCctxHash(index), + Index: GetCctxIndexFromString(index), ZetaFees: math.NewUint(uint64(r.Int63())), RelayedMessage: StringRandom(r, 32), CctxStatus: Status(t, index), diff --git a/x/crosschain/keeper/abci_test.go b/x/crosschain/keeper/abci_test.go index ea46e70dc4..4487d7dcec 100644 --- a/x/crosschain/keeper/abci_test.go +++ b/x/crosschain/keeper/abci_test.go @@ -58,7 +58,7 @@ func TestKeeper_IterateAndUpdateCctxGasPrice(t *testing.T) { createCctxWithNonceRange(t, ctx, *k, 40, 45, common.ZetaChainMainnet().ChainId, tss, zk) // set a cctx where the update function should fail to test that the next cctx are not updated but the next chains are - failMap["1-12"] = struct{}{} + failMap[sample.GetCctxIndexFromString("1-12")] = struct{}{} // test that the default crosschain flags are used when not set and the epoch length is not reached ctx = ctx.WithBlockHeight(observertypes.DefaultCrosschainFlags().GasPriceIncreaseFlags.EpochLength + 1) @@ -84,7 +84,6 @@ func TestKeeper_IterateAndUpdateCctxGasPrice(t *testing.T) { require.Equal(t, customFlags, flags) // test that cctx are iterated and updated when the epoch length is reached - ctx = ctx.WithBlockHeight(observertypes.DefaultCrosschainFlags().GasPriceIncreaseFlags.EpochLength * 2) cctxCount, flags = k.IterateAndUpdateCctxGasPrice(ctx, supportedChains, updateFunc) @@ -94,14 +93,14 @@ func TestKeeper_IterateAndUpdateCctxGasPrice(t *testing.T) { // check that the update function was called with the cctx index require.Equal(t, 7, len(updateFuncMap)) - require.Contains(t, updateFuncMap, "1-10") - require.Contains(t, updateFuncMap, "1-11") + require.Contains(t, updateFuncMap, sample.GetCctxIndexFromString("1-10")) + require.Contains(t, updateFuncMap, sample.GetCctxIndexFromString("1-11")) - require.Contains(t, updateFuncMap, "56-30") - require.Contains(t, updateFuncMap, "56-31") - require.Contains(t, updateFuncMap, "56-32") - require.Contains(t, updateFuncMap, "56-33") - require.Contains(t, updateFuncMap, "56-34") + require.Contains(t, updateFuncMap, sample.GetCctxIndexFromString("56-30")) + require.Contains(t, updateFuncMap, sample.GetCctxIndexFromString("56-31")) + require.Contains(t, updateFuncMap, sample.GetCctxIndexFromString("56-32")) + require.Contains(t, updateFuncMap, sample.GetCctxIndexFromString("56-33")) + require.Contains(t, updateFuncMap, sample.GetCctxIndexFromString("56-34")) } func TestCheckAndUpdateCctxGasPrice(t *testing.T) { diff --git a/x/crosschain/keeper/grpc_query_cctx_test.go b/x/crosschain/keeper/grpc_query_cctx_test.go index bf8579990b..6865d6d51e 100644 --- a/x/crosschain/keeper/grpc_query_cctx_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_test.go @@ -135,12 +135,12 @@ func TestKeeper_CctxListPending(t *testing.T) { cctxs := createCctxWithNonceRange(t, ctx, *k, 1000, 2000, chainID, tss, zk) // set some cctxs as pending below nonce - cctx1, found := k.GetCrossChainTx(ctx, sample.GetCctxHash("1337-940")) + cctx1, found := k.GetCrossChainTx(ctx, sample.GetCctxIndexFromString("1337-940")) require.True(t, found) cctx1.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, cctx1) - cctx2, found := k.GetCrossChainTx(ctx, sample.GetCctxHash("1337-955")) + cctx2, found := k.GetCrossChainTx(ctx, sample.GetCctxIndexFromString("1337-955")) require.True(t, found) cctx2.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, cctx2) diff --git a/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go b/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go index 0ee02ff129..fadda6b74f 100644 --- a/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go +++ b/x/crosschain/keeper/msg_server_abort_stuck_cctx_test.go @@ -29,11 +29,11 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { // abort the cctx _, err := msgServer.AbortStuckCCTX(ctx, &crosschaintypes.MsgAbortStuckCCTX{ Creator: admin, - CctxIndex: sample.GetCctxHash("cctx_index"), + CctxIndex: sample.GetCctxIndexFromString("cctx_index"), }) require.NoError(t, err) - cctxFound, found := k.GetCrossChainTx(ctx, sample.GetCctxHash("cctx_index")) + cctxFound, found := k.GetCrossChainTx(ctx, sample.GetCctxIndexFromString("cctx_index")) require.True(t, found) require.Equal(t, crosschaintypes.CctxStatus_Aborted, cctxFound.CctxStatus.Status) require.Equal(t, crosschainkeeper.AbortMessage, cctxFound.CctxStatus.StatusMessage) @@ -56,11 +56,11 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { // abort the cctx _, err := msgServer.AbortStuckCCTX(ctx, &crosschaintypes.MsgAbortStuckCCTX{ Creator: admin, - CctxIndex: sample.GetCctxHash("cctx_index"), + CctxIndex: sample.GetCctxIndexFromString("cctx_index"), }) require.NoError(t, err) - cctxFound, found := k.GetCrossChainTx(ctx, sample.GetCctxHash("cctx_index")) + cctxFound, found := k.GetCrossChainTx(ctx, sample.GetCctxIndexFromString("cctx_index")) require.True(t, found) require.Equal(t, crosschaintypes.CctxStatus_Aborted, cctxFound.CctxStatus.Status) require.Equal(t, crosschainkeeper.AbortMessage, cctxFound.CctxStatus.StatusMessage) @@ -83,11 +83,11 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { // abort the cctx _, err := msgServer.AbortStuckCCTX(ctx, &crosschaintypes.MsgAbortStuckCCTX{ Creator: admin, - CctxIndex: sample.GetCctxHash("cctx_index"), + CctxIndex: sample.GetCctxIndexFromString("cctx_index"), }) require.NoError(t, err) - cctxFound, found := k.GetCrossChainTx(ctx, sample.GetCctxHash("cctx_index")) + cctxFound, found := k.GetCrossChainTx(ctx, sample.GetCctxIndexFromString("cctx_index")) require.True(t, found) require.Equal(t, crosschaintypes.CctxStatus_Aborted, cctxFound.CctxStatus.Status) require.Equal(t, crosschainkeeper.AbortMessage, cctxFound.CctxStatus.StatusMessage) @@ -108,7 +108,7 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { // abort the cctx _, err := msgServer.AbortStuckCCTX(ctx, &crosschaintypes.MsgAbortStuckCCTX{ Creator: sample.AccAddress(), - CctxIndex: sample.GetCctxHash("cctx_index"), + CctxIndex: sample.GetCctxIndexFromString("cctx_index"), }) require.ErrorIs(t, err, observertypes.ErrNotAuthorized) }) @@ -122,7 +122,7 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { // abort the cctx _, err := msgServer.AbortStuckCCTX(ctx, &crosschaintypes.MsgAbortStuckCCTX{ Creator: admin, - CctxIndex: sample.GetCctxHash("cctx_index"), + CctxIndex: sample.GetCctxIndexFromString("cctx_index"), }) require.ErrorIs(t, err, crosschaintypes.ErrCannotFindCctx) }) @@ -144,7 +144,7 @@ func TestMsgServer_AbortStuckCCTX(t *testing.T) { // abort the cctx _, err := msgServer.AbortStuckCCTX(ctx, &crosschaintypes.MsgAbortStuckCCTX{ Creator: admin, - CctxIndex: sample.GetCctxHash("cctx_index"), + CctxIndex: sample.GetCctxIndexFromString("cctx_index"), }) require.ErrorIs(t, err, crosschaintypes.ErrStatusNotPending) }) diff --git a/x/crosschain/keeper/msg_server_update_tss_test.go b/x/crosschain/keeper/msg_server_update_tss_test.go index 5ed175dd88..fbc8567d5f 100644 --- a/x/crosschain/keeper/msg_server_update_tss_test.go +++ b/x/crosschain/keeper/msg_server_update_tss_test.go @@ -28,7 +28,7 @@ func TestMsgServer_UpdateTssAddress(t *testing.T) { index := chain.ChainName.String() + "_migration_tx_index" k.GetObserverKeeper().SetFundMigrator(ctx, types.TssFundMigratorInfo{ ChainId: chain.ChainId, - MigrationCctxIndex: sample.GetCctxHash(index), + MigrationCctxIndex: sample.GetCctxIndexFromString(index), }) cctx := sample.CrossChainTx(t, index) cctx.CctxStatus.Status = crosschaintypes.CctxStatus_OutboundMined @@ -60,7 +60,7 @@ func TestMsgServer_UpdateTssAddress(t *testing.T) { index := chain.ChainName.String() + "_migration_tx_index" k.GetObserverKeeper().SetFundMigrator(ctx, types.TssFundMigratorInfo{ ChainId: chain.ChainId, - MigrationCctxIndex: sample.GetCctxHash(index), + MigrationCctxIndex: sample.GetCctxIndexFromString(index), }) cctx := sample.CrossChainTx(t, index) cctx.CctxStatus.Status = crosschaintypes.CctxStatus_OutboundMined @@ -91,7 +91,7 @@ func TestMsgServer_UpdateTssAddress(t *testing.T) { index := chain.ChainName.String() + "_migration_tx_index" k.GetObserverKeeper().SetFundMigrator(ctx, types.TssFundMigratorInfo{ ChainId: chain.ChainId, - MigrationCctxIndex: sample.GetCctxHash(index), + MigrationCctxIndex: sample.GetCctxIndexFromString(index), }) cctx := sample.CrossChainTx(t, index) cctx.CctxStatus.Status = crosschaintypes.CctxStatus_OutboundMined @@ -128,7 +128,7 @@ func TestMsgServer_UpdateTssAddress(t *testing.T) { index := chain.ChainName.String() + "_migration_tx_index" k.GetObserverKeeper().SetFundMigrator(ctx, types.TssFundMigratorInfo{ ChainId: chain.ChainId, - MigrationCctxIndex: sample.GetCctxHash(index), + MigrationCctxIndex: sample.GetCctxIndexFromString(index), }) cctx := sample.CrossChainTx(t, index) cctx.CctxStatus.Status = crosschaintypes.CctxStatus_OutboundMined @@ -165,7 +165,7 @@ func TestMsgServer_UpdateTssAddress(t *testing.T) { index := chain.ChainName.String() + "_migration_tx_index" k.GetObserverKeeper().SetFundMigrator(ctx, types.TssFundMigratorInfo{ ChainId: chain.ChainId, - MigrationCctxIndex: sample.GetCctxHash(index), + MigrationCctxIndex: sample.GetCctxIndexFromString(index), }) cctx := sample.CrossChainTx(t, index) cctx.CctxStatus.Status = crosschaintypes.CctxStatus_PendingOutbound @@ -202,7 +202,7 @@ func TestMsgServer_UpdateTssAddress(t *testing.T) { index := chain.ChainName.String() + "_migration_tx_index" k.GetObserverKeeper().SetFundMigrator(ctx, types.TssFundMigratorInfo{ ChainId: chain.ChainId, - MigrationCctxIndex: sample.GetCctxHash(index), + MigrationCctxIndex: sample.GetCctxIndexFromString(index), }) } assert.Equal(t, len(k.GetObserverKeeper().GetAllTssFundMigrators(ctx)), len(k.GetObserverKeeper().GetSupportedChains(ctx))) From 74b7140718ee581dc9746d124ee6f6c66d003947 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 14:42:12 -0500 Subject: [PATCH 23/50] Update x/crosschain/client/cli/cli_refund_aborted.go Co-authored-by: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> --- x/crosschain/client/cli/cli_refund_aborted.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/crosschain/client/cli/cli_refund_aborted.go b/x/crosschain/client/cli/cli_refund_aborted.go index 744d95c7b5..12930dcbf0 100644 --- a/x/crosschain/client/cli/cli_refund_aborted.go +++ b/x/crosschain/client/cli/cli_refund_aborted.go @@ -11,7 +11,7 @@ import ( func CmdRefundAborted() *cobra.Command { cmd := &cobra.Command{ Use: "refund-aborted [cctx-index] [refund-address]", - Short: `Refund a aborted tx , the refund address is optional, if not provided, the refund will be sent to the sender/tx origin of the cctx.`, + Short: `Refund an aborted tx , the refund address is optional, if not provided, the refund will be sent to the sender/tx origin of the cctx.`, Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) From dd8d7a81585e56d23844c50e1a5bcb832081ebae Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 14:43:50 -0500 Subject: [PATCH 24/50] Update docs/cli/zetacored/zetacored_tx_crosschain.md Co-authored-by: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> --- docs/cli/zetacored/zetacored_tx_crosschain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cli/zetacored/zetacored_tx_crosschain.md b/docs/cli/zetacored/zetacored_tx_crosschain.md index ff4439d3ac..a31ba0cf6e 100644 --- a/docs/cli/zetacored/zetacored_tx_crosschain.md +++ b/docs/cli/zetacored/zetacored_tx_crosschain.md @@ -34,7 +34,7 @@ zetacored tx crosschain [flags] * [zetacored tx crosschain inbound-voter](zetacored_tx_crosschain_inbound-voter.md) - Broadcast message sendVoter * [zetacored tx crosschain migrate-tss-funds](zetacored_tx_crosschain_migrate-tss-funds.md) - Migrate TSS funds to the latest TSS address * [zetacored tx crosschain outbound-voter](zetacored_tx_crosschain_outbound-voter.md) - Broadcast message receiveConfirmation -* [zetacored tx crosschain refund-aborted](zetacored_tx_crosschain_refund-aborted.md) - Refund a aborted tx , the refund address is optional, if not provided, the refund will be sent to the sender/tx origin of the cctx. +* [zetacored tx crosschain refund-aborted](zetacored_tx_crosschain_refund-aborted.md) - Refund a aborted tx, the refund address is optional, if not provided, the refund will be sent to the sender/tx origin of the cctx. * [zetacored tx crosschain remove-from-out-tx-tracker](zetacored_tx_crosschain_remove-from-out-tx-tracker.md) - Remove a out-tx-tracker * [zetacored tx crosschain update-tss-address](zetacored_tx_crosschain_update-tss-address.md) - Create a new TSSVoter From 792f4c99e4a2cb459892a35b74996f382a737cb7 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 14:53:05 -0500 Subject: [PATCH 25/50] set status timestamp --- x/crosschain/keeper/msg_server_refund_aborted_tx.go | 2 +- x/crosschain/keeper/msg_server_vote_inbound_tx.go | 6 ++++-- x/crosschain/types/status.go | 6 ++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 33b5160536..a2c73f9df0 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -75,7 +75,7 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund commit() // set the cctx as refunded - cctx.CctxStatus.IsAbortRefunded = true + cctx.CctxStatus.AbortRefunded(ctx.BlockTime().Unix()) k.SetCrossChainTx(ctx, cctx) return &types.MsgRefundAbortedCCTXResponse{}, nil diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index bc4b9ae8d2..1d364f36af 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -195,15 +195,17 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg // in this gas we should refund the sender on ZetaChain if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 && ethcommon.IsHexAddress(cctx.InboundTxParams.Sender) { // Sender is verified to be a valid ethereum address - if err := k.RefundAbortedAmountOnZetaChain(ctx, cctx, ethcommon.HexToAddress(cctx.InboundTxParams.Sender)); err != nil { + err := k.RefundAbortedAmountOnZetaChain(ctx, cctx, ethcommon.HexToAddress(cctx.InboundTxParams.Sender)) + if err != nil { // log the error k.Logger(ctx).Error("failed to refund amount of aborted cctx on ZetaChain", "error", err, "sender", cctx.InboundTxParams.Sender, "amount", cctx.InboundTxParams.Amount.String(), ) + } else { + cctx.CctxStatus.AbortRefunded(ctx.BlockTime().Unix()) } - cctx.CctxStatus.IsAbortRefunded = true } cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()+" deposit revert message: "+revertMessage) diff --git a/x/crosschain/types/status.go b/x/crosschain/types/status.go index 1364e5946c..be2b4af62e 100644 --- a/x/crosschain/types/status.go +++ b/x/crosschain/types/status.go @@ -4,6 +4,12 @@ import ( "fmt" ) +func (m *Status) AbortRefunded(timeStamp int64) { + m.IsAbortRefunded = true + m.StatusMessage = "CCTX aborted and Refunded" + m.LastUpdateTimestamp = timeStamp +} + // empty msg does not overwrite old status message func (m *Status) ChangeStatus(newStatus CctxStatus, msg string) { if len(msg) > 0 { From 3c47023670c3d2069be7136dbc8865a2b088d941 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 17:22:01 -0500 Subject: [PATCH 26/50] Update changelog.md Co-authored-by: Lucas Bertrand --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index 13cf33d4b8..2d1deeb647 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,7 @@ ## Unreleased * `zetaclientd start` : 2 inputs required from stdin + ### Features *[1728] (https://github.com/zeta-chain/node/pull/1728) - allow aborted transactions to be refunded by minting tokens to zEvm. From 7f3878e8fb800309464112c536ef662b4bf1447a Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 17:22:12 -0500 Subject: [PATCH 27/50] Update testutil/sample/crosschain.go Co-authored-by: Lucas Bertrand --- testutil/sample/crosschain.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index 87bb3e7245..b516100597 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -75,9 +75,11 @@ func Status(t *testing.T, index string) *types.Status { LastUpdateTimestamp: r.Int63(), } } + func GetCctxIndexFromString(index string) string { return crypto.Keccak256Hash([]byte(index)).String() } + func CrossChainTx(t *testing.T, index string) *types.CrossChainTx { r := newRandFromStringSeed(t, index) From 70b56e15e183e73ecb102c806be7416645857fc6 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 18:27:44 -0500 Subject: [PATCH 28/50] move setting refund address to a separate function --- docs/cli/zetacored/zetacored_tx_crosschain.md | 2 +- .../zetacored_tx_crosschain_refund-aborted.md | 2 +- .../keeper/msg_server_refund_aborted_tx.go | 60 +++++++------ .../msg_server_refund_aborted_tx_test.go | 89 +++++++++++++++++++ .../keeper/msg_server_vote_inbound_tx.go | 4 +- x/crosschain/keeper/refund.go | 4 +- x/crosschain/types/status_test.go | 25 ++++++ 7 files changed, 156 insertions(+), 30 deletions(-) create mode 100644 x/crosschain/types/status_test.go diff --git a/docs/cli/zetacored/zetacored_tx_crosschain.md b/docs/cli/zetacored/zetacored_tx_crosschain.md index a31ba0cf6e..8b66894327 100644 --- a/docs/cli/zetacored/zetacored_tx_crosschain.md +++ b/docs/cli/zetacored/zetacored_tx_crosschain.md @@ -34,7 +34,7 @@ zetacored tx crosschain [flags] * [zetacored tx crosschain inbound-voter](zetacored_tx_crosschain_inbound-voter.md) - Broadcast message sendVoter * [zetacored tx crosschain migrate-tss-funds](zetacored_tx_crosschain_migrate-tss-funds.md) - Migrate TSS funds to the latest TSS address * [zetacored tx crosschain outbound-voter](zetacored_tx_crosschain_outbound-voter.md) - Broadcast message receiveConfirmation -* [zetacored tx crosschain refund-aborted](zetacored_tx_crosschain_refund-aborted.md) - Refund a aborted tx, the refund address is optional, if not provided, the refund will be sent to the sender/tx origin of the cctx. +* [zetacored tx crosschain refund-aborted](zetacored_tx_crosschain_refund-aborted.md) - Refund an aborted tx , the refund address is optional, if not provided, the refund will be sent to the sender/tx origin of the cctx. * [zetacored tx crosschain remove-from-out-tx-tracker](zetacored_tx_crosschain_remove-from-out-tx-tracker.md) - Remove a out-tx-tracker * [zetacored tx crosschain update-tss-address](zetacored_tx_crosschain_update-tss-address.md) - Create a new TSSVoter diff --git a/docs/cli/zetacored/zetacored_tx_crosschain_refund-aborted.md b/docs/cli/zetacored/zetacored_tx_crosschain_refund-aborted.md index ca53f46410..515d85dc32 100644 --- a/docs/cli/zetacored/zetacored_tx_crosschain_refund-aborted.md +++ b/docs/cli/zetacored/zetacored_tx_crosschain_refund-aborted.md @@ -1,6 +1,6 @@ # tx crosschain refund-aborted -Refund a aborted tx , the refund address is optional, if not provided, the refund will be sent to the sender/tx origin of the cctx. +Refund an aborted tx , the refund address is optional, if not provided, the refund will be sent to the sender/tx origin of the cctx. ``` zetacored tx crosschain refund-aborted [cctx-index] [refund-address] [flags] diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index a2c73f9df0..6ba4bdf54d 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -24,10 +24,6 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund if !found { return nil, types.ErrCannotFindCctx } - // make sure separate refund address is provided for bitcoin chain as we cannot refund to tx origin or sender in this case - if common.IsBitcoinChain(cctx.InboundTxParams.SenderChainId) && msg.RefundAddress == "" { - return nil, errorsmod.Wrap(types.ErrInvalidAddress, "refund address is required for bitcoin chain") - } // check if the cctx is aborted if cctx.CctxStatus.Status != types.CctxStatus_Aborted { @@ -38,26 +34,6 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, "CCTX is already refunded") } - // Set the proper refund address. - // For BTC sender chain the refund address is the one provided in the message in the RefundAddress field. - // For EVM chain with coin type ERC20 the refund address is the sender , but can be overridden by the RefundAddress field in the message. - // For EVM chain with coin type Zeta the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. - // For EVM chain with coin type Gas the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. - - refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) - if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { - refundAddress = ethcommon.HexToAddress(cctx.InboundTxParams.Sender) - } - if msg.RefundAddress != "" { - if !ethcommon.IsHexAddress(msg.RefundAddress) { - return nil, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address provided") - } - refundAddress = ethcommon.HexToAddress(msg.RefundAddress) - } - // Double check to make sure the refund address is valid - if refundAddress == (ethcommon.Address{}) { - return nil, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address") - } // Check if aborted amount is available to maintain zeta accounting // NOTE: Need to verify if this check works / is required in athens 3 if cctx.InboundTxParams.CoinType == common.CoinType_Zeta { @@ -66,9 +42,14 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) } } + + refundAddress, err := GetRefundAddress(cctx, msg.RefundAddress) + if err != nil { + return nil, errorsmod.Wrap(types.ErrInvalidAddress, err.Error()) + } // refund the amount tmpCtx, commit := ctx.CacheContext() - err := k.RefundAbortedAmountOnZetaChain(tmpCtx, cctx, refundAddress) + err = k.RefundAbortedAmountOnZetaChain(tmpCtx, cctx, refundAddress) if err != nil { return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) } @@ -76,7 +57,36 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund // set the cctx as refunded cctx.CctxStatus.AbortRefunded(ctx.BlockTime().Unix()) + k.SetCrossChainTx(ctx, cctx) return &types.MsgRefundAbortedCCTXResponse{}, nil } + +func GetRefundAddress(cctx types.CrossChainTx, optionalRefundAddress string) (ethcommon.Address, error) { + // make sure a separate refund address is provided for a bitcoin chain as we cannot refund to tx origin or sender in this case + if common.IsBitcoinChain(cctx.InboundTxParams.SenderChainId) && optionalRefundAddress == "" { + return ethcommon.Address{}, errorsmod.Wrap(types.ErrInvalidAddress, "refund address is required for bitcoin chain") + } + // Set the proper refund address. + // For BTC sender chain the refund address is the one provided in the message in the RefundAddress field. + // For EVM chain with coin type ERC20 the refund address is the sender , but can be overridden by the RefundAddress field in the message. + // For EVM chain with coin type Zeta the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. + // For EVM chain with coin type Gas the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. + + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) + if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { + refundAddress = ethcommon.HexToAddress(cctx.InboundTxParams.Sender) + } + if optionalRefundAddress != "" { + if !ethcommon.IsHexAddress(optionalRefundAddress) { + return ethcommon.Address{}, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address provided") + } + refundAddress = ethcommon.HexToAddress(optionalRefundAddress) + } + // Double check to make sure the refund address is valid + if refundAddress == (ethcommon.Address{}) { + return ethcommon.Address{}, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address") + } + return refundAddress, nil +} diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index 6a31090286..1e987cc8af 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -16,6 +16,95 @@ import ( fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" ) +func Test_GetRefundAddress(t *testing.T) { + t.Run("should return refund address if provided coin-type gas", func(t *testing.T) { + validEthAddress := sample.EthAddress() + address, err := keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ + InboundTxParams: &crosschaintypes.InboundTxParams{ + TxOrigin: validEthAddress.String(), + CoinType: common.CoinType_Gas, + SenderChainId: getValidEthChainID(t), + }}, + "") + require.NoError(t, err) + require.Equal(t, validEthAddress, address) + }) + t.Run("should return refund address if provided coin-type zeta", func(t *testing.T) { + validEthAddress := sample.EthAddress() + address, err := keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ + InboundTxParams: &crosschaintypes.InboundTxParams{ + TxOrigin: validEthAddress.String(), + CoinType: common.CoinType_Zeta, + SenderChainId: getValidEthChainID(t), + }}, + "") + require.NoError(t, err) + require.Equal(t, validEthAddress, address) + }) + t.Run("should return refund address if provided coin-type erc20", func(t *testing.T) { + validEthAddress := sample.EthAddress() + address, err := keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ + InboundTxParams: &crosschaintypes.InboundTxParams{ + Sender: validEthAddress.String(), + CoinType: common.CoinType_ERC20, + SenderChainId: getValidEthChainID(t), + }}, + "") + require.NoError(t, err) + require.Equal(t, validEthAddress, address) + }) + t.Run("should return refund address if provided coin-type gas for btc chain", func(t *testing.T) { + validEthAddress := sample.EthAddress() + address, err := keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ + InboundTxParams: &crosschaintypes.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: getValidBtcChainID(), + }}, + validEthAddress.String()) + require.NoError(t, err) + require.Equal(t, validEthAddress, address) + }) + t.Run("fail if refund address is not provided for btc chain", func(t *testing.T) { + _, err := keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ + InboundTxParams: &crosschaintypes.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: getValidBtcChainID(), + }}, + "") + require.ErrorContains(t, err, "refund address is required for bitcoin chain") + }) + t.Run("address overridden if optional address is provided", func(t *testing.T) { + validEthAddress := sample.EthAddress() + address, err := keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ + InboundTxParams: &crosschaintypes.InboundTxParams{ + Sender: sample.EthAddress().String(), + CoinType: common.CoinType_ERC20, + SenderChainId: getValidEthChainID(t), + }}, + validEthAddress.String()) + require.NoError(t, err) + require.Equal(t, validEthAddress, address) + address, err = keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ + InboundTxParams: &crosschaintypes.InboundTxParams{ + Sender: sample.EthAddress().String(), + CoinType: common.CoinType_Zeta, + SenderChainId: getValidEthChainID(t), + }}, + validEthAddress.String()) + require.NoError(t, err) + require.Equal(t, validEthAddress, address) + address, err = keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ + InboundTxParams: &crosschaintypes.InboundTxParams{ + Sender: sample.EthAddress().String(), + CoinType: common.CoinType_Gas, + SenderChainId: getValidEthChainID(t), + }}, + validEthAddress.String()) + require.NoError(t, err) + require.Equal(t, validEthAddress, address) + }) + +} func TestMsgServer_RefundAbortedCCTX(t *testing.T) { t.Run("Successfully refund tx for coin-type Gas", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 1d364f36af..2c36d7d16b 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -193,7 +193,9 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg // gas payment for erc20 type might fail because no liquidity pool is defined to swap the zrc20 token into the gas token // in this gas we should refund the sender on ZetaChain - if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 && ethcommon.IsHexAddress(cctx.InboundTxParams.Sender) { + if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 && + ethcommon.IsHexAddress(cctx.InboundTxParams.Sender) && + cctx.CctxStatus.IsAbortRefunded == false { // Sender is verified to be a valid ethereum address err := k.RefundAbortedAmountOnZetaChain(ctx, cctx, ethcommon.HexToAddress(cctx.InboundTxParams.Sender)) if err != nil { diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index 749fbcd2ff..ddb3028ef7 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - cosmoserrors "cosmossdk.io/errors" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/common" @@ -40,7 +40,7 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai } zrc20 := ethcommon.HexToAddress(fcSenderChain.Zrc20ContractAddress) if zrc20 == (ethcommon.Address{}) { - return cosmoserrors.Wrapf(types.ErrForeignCoinNotFound, "zrc20 contract address not found for chain %d", chainID) + return errorsmod.Wrapf(types.ErrForeignCoinNotFound, "zrc20 contract address not found for chain %d", chainID) } // deposit the amount to the tx origin instead of receiver as this is a refund if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundAddress, amountOfGasTokenLocked.BigInt()); err != nil { diff --git a/x/crosschain/types/status_test.go b/x/crosschain/types/status_test.go new file mode 100644 index 0000000000..cadf64490e --- /dev/null +++ b/x/crosschain/types/status_test.go @@ -0,0 +1,25 @@ +package types_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func TestStatus_AbortRefunded(t *testing.T) { + t.Run("should set status to aborted and message to CCTX aborted and Refunded", func(t *testing.T) { + status := types.Status{ + Status: 0, + StatusMessage: "", + LastUpdateTimestamp: 0, + IsAbortRefunded: false, + } + timestamp := time.Now().Unix() + status.AbortRefunded(timestamp) + require.Equal(t, status.IsAbortRefunded, true) + require.Equal(t, status.StatusMessage, "CCTX aborted and Refunded") + require.Equal(t, status.LastUpdateTimestamp, timestamp) + }) +} From 86392920961be10b8e9ff16a55ad27e9bd310197 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 18:33:21 -0500 Subject: [PATCH 29/50] move setting refund address to a separate function --- x/crosschain/keeper/msg_server_refund_aborted_tx.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 6ba4bdf54d..8cc85b6a19 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -48,6 +48,7 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund return nil, errorsmod.Wrap(types.ErrInvalidAddress, err.Error()) } // refund the amount + // use temporary context to avoid gas refunding issues and side effects tmpCtx, commit := ctx.CacheContext() err = k.RefundAbortedAmountOnZetaChain(tmpCtx, cctx, refundAddress) if err != nil { From a8dde6e05e40378633845ccbe8bda06bb42d2b7d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 18:35:43 -0500 Subject: [PATCH 30/50] format errors.go --- x/crosschain/types/errors.go | 85 ++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 47 deletions(-) diff --git a/x/crosschain/types/errors.go b/x/crosschain/types/errors.go index be5e034578..0f7fb8341a 100644 --- a/x/crosschain/types/errors.go +++ b/x/crosschain/types/errors.go @@ -5,52 +5,43 @@ import ( ) var ( - ErrUnsupportedChain = errorsmod.Register(ModuleName, 1102, "chain parse error") - ErrInvalidChainID = errorsmod.Register(ModuleName, 1101, "chain id cannot be negative") - ErrInvalidPubKeySet = errorsmod.Register(ModuleName, 1106, "invalid pubkeyset") - ErrUnableToGetGasPrice = errorsmod.Register(ModuleName, 1107, "unable to get gas price") - ErrNotEnoughZetaBurnt = errorsmod.Register(ModuleName, 1109, "not enough zeta burnt") - ErrCannotFindReceiverNonce = errorsmod.Register(ModuleName, 1110, "cannot find receiver chain nonce") - - ErrGasCoinNotFound = errorsmod.Register(ModuleName, 1113, "gas coin not found for sender chain") - ErrUnableToParseAddress = errorsmod.Register(ModuleName, 1115, "cannot parse address and data") - ErrCannotProcessWithdrawal = errorsmod.Register(ModuleName, 1116, "cannot process withdrawal event") - ErrForeignCoinNotFound = errorsmod.Register(ModuleName, 1118, "foreign coin not found for sender chain") - ErrNotEnoughPermissions = errorsmod.Register(ModuleName, 1119, "not enough permissions for current actions") - - ErrCannotFindPendingNonces = errorsmod.Register(ModuleName, 1121, "cannot find pending nonces") - ErrCannotFindTSSKeys = errorsmod.Register(ModuleName, 1122, "cannot find TSS keys") - ErrNonceMismatch = errorsmod.Register(ModuleName, 1123, "nonce mismatch") - ErrNotFoundChainParams = errorsmod.Register(ModuleName, 1126, "not found chain chain params") - ErrUnableToSendCoinType = errorsmod.Register(ModuleName, 1127, "unable to send this coin type to a receiver chain") - - ErrInvalidAddress = errorsmod.Register(ModuleName, 1128, "invalid address") - ErrDeployContract = errorsmod.Register(ModuleName, 1129, "unable to deploy contract") - ErrUnableToUpdateTss = errorsmod.Register(ModuleName, 1130, "unable to update TSS address") - ErrNotEnoughGas = errorsmod.Register(ModuleName, 1131, "not enough gas") - ErrNotEnoughFunds = errorsmod.Register(ModuleName, 1132, "not enough funds") - - ErrProofVerificationFail = errorsmod.Register(ModuleName, 1133, "proof verification fail") - ErrCannotFindCctx = errorsmod.Register(ModuleName, 1134, "cannot find cctx") - ErrStatusNotPending = errorsmod.Register(ModuleName, 1135, "Status not pending") - - ErrCannotFindGasParams = errorsmod.Register(ModuleName, 1136, "cannot find gas params") - ErrInvalidGasAmount = errorsmod.Register(ModuleName, 1137, "invalid gas amount") - ErrNoLiquidityPool = errorsmod.Register(ModuleName, 1138, "no liquidity pool") - ErrInvalidCoinType = errorsmod.Register(ModuleName, 1139, "invalid coin type") - ErrCannotMigrateTssFunds = errorsmod.Register(ModuleName, 1140, "cannot migrate TSS funds") - ErrTxBodyVerificationFail = errorsmod.Register(ModuleName, 1141, "transaction body verification fail") - ErrReceiverIsEmpty = errorsmod.Register(ModuleName, 1142, "receiver is empty") - ErrUnsupportedStatus = errorsmod.Register(ModuleName, 1143, "unsupported status") - ErrObservedTxAlreadyFinalized = errorsmod.Register(ModuleName, 1144, "observed tx already finalized") - + ErrUnsupportedChain = errorsmod.Register(ModuleName, 1102, "chain parse error") + ErrInvalidChainID = errorsmod.Register(ModuleName, 1101, "chain id cannot be negative") + ErrInvalidPubKeySet = errorsmod.Register(ModuleName, 1106, "invalid pubkeyset") + ErrUnableToGetGasPrice = errorsmod.Register(ModuleName, 1107, "unable to get gas price") + ErrNotEnoughZetaBurnt = errorsmod.Register(ModuleName, 1109, "not enough zeta burnt") + ErrCannotFindReceiverNonce = errorsmod.Register(ModuleName, 1110, "cannot find receiver chain nonce") + ErrGasCoinNotFound = errorsmod.Register(ModuleName, 1113, "gas coin not found for sender chain") + ErrUnableToParseAddress = errorsmod.Register(ModuleName, 1115, "cannot parse address and data") + ErrCannotProcessWithdrawal = errorsmod.Register(ModuleName, 1116, "cannot process withdrawal event") + ErrForeignCoinNotFound = errorsmod.Register(ModuleName, 1118, "foreign coin not found for sender chain") + ErrNotEnoughPermissions = errorsmod.Register(ModuleName, 1119, "not enough permissions for current actions") + ErrCannotFindPendingNonces = errorsmod.Register(ModuleName, 1121, "cannot find pending nonces") + ErrCannotFindTSSKeys = errorsmod.Register(ModuleName, 1122, "cannot find TSS keys") + ErrNonceMismatch = errorsmod.Register(ModuleName, 1123, "nonce mismatch") + ErrNotFoundChainParams = errorsmod.Register(ModuleName, 1126, "not found chain chain params") + ErrUnableToSendCoinType = errorsmod.Register(ModuleName, 1127, "unable to send this coin type to a receiver chain") + ErrInvalidAddress = errorsmod.Register(ModuleName, 1128, "invalid address") + ErrDeployContract = errorsmod.Register(ModuleName, 1129, "unable to deploy contract") + ErrUnableToUpdateTss = errorsmod.Register(ModuleName, 1130, "unable to update TSS address") + ErrNotEnoughGas = errorsmod.Register(ModuleName, 1131, "not enough gas") + ErrNotEnoughFunds = errorsmod.Register(ModuleName, 1132, "not enough funds") + ErrProofVerificationFail = errorsmod.Register(ModuleName, 1133, "proof verification fail") + ErrCannotFindCctx = errorsmod.Register(ModuleName, 1134, "cannot find cctx") + ErrStatusNotPending = errorsmod.Register(ModuleName, 1135, "Status not pending") + ErrCannotFindGasParams = errorsmod.Register(ModuleName, 1136, "cannot find gas params") + ErrInvalidGasAmount = errorsmod.Register(ModuleName, 1137, "invalid gas amount") + ErrNoLiquidityPool = errorsmod.Register(ModuleName, 1138, "no liquidity pool") + ErrInvalidCoinType = errorsmod.Register(ModuleName, 1139, "invalid coin type") + ErrCannotMigrateTssFunds = errorsmod.Register(ModuleName, 1140, "cannot migrate TSS funds") + ErrTxBodyVerificationFail = errorsmod.Register(ModuleName, 1141, "transaction body verification fail") + ErrReceiverIsEmpty = errorsmod.Register(ModuleName, 1142, "receiver is empty") + ErrUnsupportedStatus = errorsmod.Register(ModuleName, 1143, "unsupported status") + ErrObservedTxAlreadyFinalized = errorsmod.Register(ModuleName, 1144, "observed tx already finalized") ErrInsufficientFundsTssMigration = errorsmod.Register(ModuleName, 1145, "insufficient funds for TSS migration") - - ErrInvalidCCTXIndex = errorsmod.Register(ModuleName, 1146, "invalid cctx index") - - ErrInvalidStatus = errorsmod.Register(ModuleName, 1147, "invalid status") - ErrUnableProcessRefund = errorsmod.Register(ModuleName, 1148, "unable to process refund") - - ErrUnableToFindZetaAccounting = errorsmod.Register(ModuleName, 1149, "unable to find zeta accounting") - ErrInsufficientZetaAmount = errorsmod.Register(ModuleName, 1150, "insufficient zeta amount") + ErrInvalidCCTXIndex = errorsmod.Register(ModuleName, 1146, "invalid cctx index") + ErrInvalidStatus = errorsmod.Register(ModuleName, 1147, "invalid cctx status") + ErrUnableProcessRefund = errorsmod.Register(ModuleName, 1148, "unable to process refund") + ErrUnableToFindZetaAccounting = errorsmod.Register(ModuleName, 1149, "unable to find zeta accounting") + ErrInsufficientZetaAmount = errorsmod.Register(ModuleName, 1150, "insufficient zeta amount") ) From 843a3bc5b83588a2db81aaf41d99ff05a4e325b0 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 8 Feb 2024 18:39:56 -0500 Subject: [PATCH 31/50] add spacing in test files --- .../smoketest/smoketests/smoketests.go | 2 ++ .../msg_server_refund_aborted_tx_test.go | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/contrib/localnet/orchestrator/smoketest/smoketests/smoketests.go b/contrib/localnet/orchestrator/smoketest/smoketests/smoketests.go index 92d4c97030..300ec2e866 100644 --- a/contrib/localnet/orchestrator/smoketest/smoketests/smoketests.go +++ b/contrib/localnet/orchestrator/smoketest/smoketests/smoketests.go @@ -2,6 +2,8 @@ package smoketests import "github.com/zeta-chain/zetacore/contrib/localnet/orchestrator/smoketest/runner" +// TODO : Add smoke test for abort refund +// https://github.com/zeta-chain/node/issues/1745 const ( TestContextUpgradeName = "context_upgrade" TestDepositAndCallRefundName = "deposit_and_call_refund" diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index 1e987cc8af..4423a5f3b6 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -113,6 +113,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted cctx.CctxStatus.IsAbortRefunded = false @@ -122,12 +123,14 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, RefundAddress: "", }) require.NoError(t, err) + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, refundAddress) require.NoError(t, err) @@ -143,6 +146,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted cctx.CctxStatus.IsAbortRefunded = false @@ -152,12 +156,14 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, RefundAddress: "", }) require.NoError(t, err) + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) refundAddressCosmos := sdk.AccAddress(refundAddress.Bytes()) balance := sdkk.BankKeeper.GetBalance(ctx, refundAddressCosmos, config.BaseDenom) @@ -173,6 +179,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted cctx.CctxStatus.IsAbortRefunded = false @@ -182,6 +189,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + refundAddress := sample.EthAddress() _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, @@ -189,6 +197,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { RefundAddress: refundAddress.String(), }) require.NoError(t, err) + refundAddressCosmos := sdk.AccAddress(refundAddress.Bytes()) balance := sdkk.BankKeeper.GetBalance(ctx, refundAddressCosmos, config.BaseDenom) require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Amount.Uint64()) @@ -204,6 +213,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted cctx.CctxStatus.IsAbortRefunded = false @@ -223,12 +233,14 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { asset, "bar", ) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, RefundAddress: "", }) require.NoError(t, err) + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.Sender) balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, refundAddress) require.NoError(t, err) @@ -244,6 +256,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted cctx.CctxStatus.IsAbortRefunded = false @@ -253,12 +266,14 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, RefundAddress: cctx.InboundTxParams.TxOrigin, }) require.NoError(t, err) + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, refundAddress) require.NoError(t, err) @@ -274,6 +289,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted cctx.CctxStatus.IsAbortRefunded = false @@ -283,6 +299,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, @@ -297,6 +314,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted cctx.CctxStatus.IsAbortRefunded = false @@ -306,6 +324,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, @@ -320,6 +339,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_PendingOutbound cctx.CctxStatus.IsAbortRefunded = false @@ -346,6 +366,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_PendingOutbound cctx.CctxStatus.IsAbortRefunded = false @@ -368,6 +389,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted cctx.CctxStatus.IsAbortRefunded = false @@ -377,6 +399,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) _ = setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, @@ -391,6 +414,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted cctx.CctxStatus.IsAbortRefunded = false @@ -399,6 +423,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.InboundTxParams.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, @@ -413,6 +438,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + cctx := sample.CrossChainTx(t, "sample-index") cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted cctx.CctxStatus.IsAbortRefunded = false @@ -422,6 +448,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: sdkmath.OneUint()}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, From 3d54fe8016d7744cbf0d28afddf1312d1f97bd01 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 9 Feb 2024 15:50:02 -0500 Subject: [PATCH 32/50] use outbound amount for refunds instead of inbound --- x/crosschain/keeper/cctx.go | 2 +- x/crosschain/keeper/cctx_utils.go | 12 +++ .../keeper/msg_server_refund_aborted_tx.go | 24 ++++-- .../msg_server_refund_aborted_tx_test.go | 78 +++++++++++++------ x/crosschain/keeper/refund.go | 17 ++-- x/crosschain/keeper/refund_test.go | 76 +++++++++++++++++- 6 files changed, 168 insertions(+), 41 deletions(-) diff --git a/x/crosschain/keeper/cctx.go b/x/crosschain/keeper/cctx.go index e3a2a06f71..972875785e 100644 --- a/x/crosschain/keeper/cctx.go +++ b/x/crosschain/keeper/cctx.go @@ -49,7 +49,7 @@ func (k Keeper) SetCctxAndNonceToCctxAndInTxHashToCctx(ctx sdk.Context, cctx typ }) } if cctx.CctxStatus.Status == types.CctxStatus_Aborted && cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { - k.AddZetaAbortedAmount(ctx, cctx.GetCurrentOutTxParam().Amount) + k.AddZetaAbortedAmount(ctx, GetAbortedAmount(cctx)) } } diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 31422b7e63..3521c981bd 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -4,6 +4,7 @@ import ( "fmt" cosmoserrors "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" "github.com/pkg/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -89,3 +90,14 @@ func IsPending(cctx types.CrossChainTx) bool { // pending inbound is not considered a "pending" state because it has not reached consensus yet return cctx.CctxStatus.Status == types.CctxStatus_PendingOutbound || cctx.CctxStatus.Status == types.CctxStatus_PendingRevert } + +// GetAbortedAmount returns the amount to refund for a given CCTX . +// If the CCTX has an outbound transaction, it returns the amount of the outbound transaction. +// If OutTxParams is nil or the amount is zero, it returns the amount of the inbound transaction. +// This is because there might be a case where the transaction is set to be aborted before paying gas or creating an outbound transaction.In such a situation we can refund the entire amount that has been locked in connector or TSS +func GetAbortedAmount(cctx types.CrossChainTx) sdkmath.Uint { + if cctx.OutboundTxParams != nil && !cctx.GetCurrentOutTxParam().Amount.IsZero() { + return cctx.GetCurrentOutTxParam().Amount + } + return cctx.InboundTxParams.Amount +} diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 8cc85b6a19..0c6181aa71 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -1,6 +1,8 @@ package keeper import ( + "errors" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" @@ -37,10 +39,16 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund // Check if aborted amount is available to maintain zeta accounting // NOTE: Need to verify if this check works / is required in athens 3 if cctx.InboundTxParams.CoinType == common.CoinType_Zeta { - err := k.RemoveZetaAbortedAmount(ctx, cctx.InboundTxParams.Amount) - if err != nil { + err := k.RemoveZetaAbortedAmount(ctx, GetAbortedAmount(cctx)) + // if the zeta accounting is not found, it means the zeta accounting is not set yet and the refund should not be processed + if errors.Is(err, types.ErrUnableToFindZetaAccounting) { return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) } + // if the zeta accounting is found but the amount is insufficient, it means the refund can be processed but the zeta accounting is not maintained properly + // aborted amounts for zeta accounting would need to be updated in the envionment via a migration script + if errors.Is(err, types.ErrInsufficientZetaAmount) { + ctx.Logger().Error("Zeta Accounting Error: ", err) + } } refundAddress, err := GetRefundAddress(cctx, msg.RefundAddress) @@ -64,17 +72,17 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund return &types.MsgRefundAbortedCCTXResponse{}, nil } +// Set the proper refund address. +// For BTC sender chain the refund address is the one provided in the message in the RefundAddress field. +// For EVM chain with coin type ERC20 the refund address is the sender , but can be overridden by the RefundAddress field in the message. +// For EVM chain with coin type Zeta the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. +// For EVM chain with coin type Gas the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. + func GetRefundAddress(cctx types.CrossChainTx, optionalRefundAddress string) (ethcommon.Address, error) { // make sure a separate refund address is provided for a bitcoin chain as we cannot refund to tx origin or sender in this case if common.IsBitcoinChain(cctx.InboundTxParams.SenderChainId) && optionalRefundAddress == "" { return ethcommon.Address{}, errorsmod.Wrap(types.ErrInvalidAddress, "refund address is required for bitcoin chain") } - // Set the proper refund address. - // For BTC sender chain the refund address is the one provided in the message in the RefundAddress field. - // For EVM chain with coin type ERC20 the refund address is the sender , but can be overridden by the RefundAddress field in the message. - // For EVM chain with coin type Zeta the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. - // For EVM chain with coin type Gas the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. - refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { refundAddress = ethcommon.HexToAddress(cctx.InboundTxParams.Sender) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index 4423a5f3b6..54d6304444 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -3,7 +3,6 @@ package keeper_test import ( "testing" - sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" @@ -14,6 +13,7 @@ import ( "github.com/zeta-chain/zetacore/x/crosschain/keeper" crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) func Test_GetRefundAddress(t *testing.T) { @@ -106,7 +106,7 @@ func Test_GetRefundAddress(t *testing.T) { } func TestMsgServer_RefundAbortedCCTX(t *testing.T) { - t.Run("Successfully refund tx for coin-type Gas", func(t *testing.T) { + t.Run("successfully refund tx for coin-type gas", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -134,12 +134,12 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, refundAddress) require.NoError(t, err) - require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Uint64()) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount.Uint64(), balance.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Successfully refund tx for coin-type Zeta", func(t *testing.T) { + t.Run("successfully refund tx for coin-type zeta", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -154,7 +154,41 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) - k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) + k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.GetCurrentOutTxParam().Amount}) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "", + }) + require.NoError(t, err) + + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) + refundAddressCosmos := sdk.AccAddress(refundAddress.Bytes()) + balance := sdkk.BankKeeper.GetBalance(ctx, refundAddressCosmos, config.BaseDenom) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount.Uint64(), balance.Amount.Uint64()) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.True(t, c.CctxStatus.IsAbortRefunded) + }) + t.Run("successfully refund tx to inbound amount if outbound is not found for coin-type zeta", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.CctxStatus.IsAbortRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.OutboundTxParams = nil + k.SetCrossChainTx(ctx, *cctx) + k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.GetCurrentOutTxParam().Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ @@ -172,7 +206,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Successfully refund to optional refund address if provided", func(t *testing.T) { + t.Run("successfully refund to optional refund address if provided", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -200,12 +234,12 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { refundAddressCosmos := sdk.AccAddress(refundAddress.Bytes()) balance := sdkk.BankKeeper.GetBalance(ctx, refundAddressCosmos, config.BaseDenom) - require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Amount.Uint64()) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount.Uint64(), balance.Amount.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Successfully refund tx for coin-type ERC20", func(t *testing.T) { + t.Run("successfully refund tx for coin-type ERC20", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -244,12 +278,12 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.Sender) balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, refundAddress) require.NoError(t, err) - require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Uint64()) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount.Uint64(), balance.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Successfully refund tx for coin-type Gas with BTC sender", func(t *testing.T) { + t.Run("successfully refund tx for coin-type Gas with BTC sender", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidBtcChainID() @@ -277,12 +311,12 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, refundAddress) require.NoError(t, err) - require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Uint64()) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount.Uint64(), balance.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Fail refund if address provided is invalid", func(t *testing.T) { + t.Run("fail refund if address provided is invalid", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -307,7 +341,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "invalid refund address") }) - t.Run("Fail refund if address provided is invalid 2 ", func(t *testing.T) { + t.Run("fail refund if address provided is null ", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -332,7 +366,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "invalid refund address") }) - t.Run("Fail refund if status is not aborted", func(t *testing.T) { + t.Run("fail refund if status is not aborted", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -359,7 +393,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.True(t, found) require.False(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Fail refund if status cctx not found", func(t *testing.T) { + t.Run("fail refund if status cctx not found", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -382,7 +416,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "cannot find cctx") }) - t.Run("Fail refund if refund address not provided for BTC chain", func(t *testing.T) { + t.Run("fail refund if refund address not provided for BTC chain", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidBtcChainID() @@ -407,7 +441,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "refund address is required for bitcoin chain") }) - t.Run("Fail refund tx for coin-type Zeta if zeta accounting object is not present", func(t *testing.T) { + t.Run("fail refund tx for coin-type Zeta if zeta accounting object is not present", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -431,7 +465,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "unable to find zeta accounting") }) - t.Run("Fail refund tx for coin-type Zeta if zeta accounting does not have enough aborted amount", func(t *testing.T) { + t.Run("fail refund if non admin account is the creator", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -444,16 +478,16 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.InboundTxParams.CoinType = common.CoinType_Gas k.SetCrossChainTx(ctx, *cctx) - k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: sdkmath.OneUint()}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _ = setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ - Creator: admin, + Creator: sample.AccAddress(), CctxIndex: cctx.Index, RefundAddress: "", }) - require.ErrorContains(t, err, "insufficient zeta amount") + require.ErrorIs(t, err, observertypes.ErrNotAuthorized) }) } diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index ddb3028ef7..e3f059e385 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -28,11 +28,12 @@ func (k Keeper) RefundAbortedAmountOnZetaChain(ctx sdk.Context, cctx types.Cross // RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype gas func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { // refund in gas token to refund address - if cctx.InboundTxParams.Amount.IsNil() || cctx.InboundTxParams.Amount.IsZero() { + // Refund the the amount was previously + refundAmount := GetAbortedAmount(cctx) + if refundAmount.IsNil() || refundAmount.IsZero() { return errors.New("no amount to refund") } chainID := cctx.InboundTxParams.SenderChainId - amountOfGasTokenLocked := cctx.InboundTxParams.Amount // get the zrc20 contract address fcSenderChain, found := k.fungibleKeeper.GetGasCoinForForeignCoin(ctx, chainID) if !found { @@ -43,7 +44,7 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai return errorsmod.Wrapf(types.ErrForeignCoinNotFound, "zrc20 contract address not found for chain %d", chainID) } // deposit the amount to the tx origin instead of receiver as this is a refund - if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundAddress, amountOfGasTokenLocked.BigInt()); err != nil { + if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundAddress, refundAmount.BigInt()); err != nil { return errors.New("failed to refund zeta on ZetaChain" + err.Error()) } return nil @@ -52,6 +53,8 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai // RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype zeta func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { // if coin type is Zeta, handle this as a deposit ZETA to zEVM. + refundAmount := GetAbortedAmount(cctx) + fmt.Println("RefundAmountOnZetaChainZeta: refundAmount: ", refundAmount) chainID := cctx.InboundTxParams.SenderChainId // check if chain is an EVM chain if !common.IsEVMChain(chainID) { @@ -61,7 +64,7 @@ func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossCha return errors.New("no amount to refund") } // deposit the amount to refund address - if err := k.fungibleKeeper.DepositCoinZeta(ctx, refundAddress, cctx.InboundTxParams.Amount.BigInt()); err != nil { + if err := k.fungibleKeeper.DepositCoinZeta(ctx, refundAddress, refundAmount.BigInt()); err != nil { return errors.New("failed to refund zeta on ZetaChain" + err.Error()) } return nil @@ -71,7 +74,7 @@ func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossCha // NOTE: GetCurrentOutTxParam should contain the last up to date cctx amount // Refund address should already be validated before calling this function func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { - inputAmount := cctx.InboundTxParams.Amount + refundAmount := GetAbortedAmount(cctx) // preliminary checks if cctx.InboundTxParams.CoinType != common.CoinType_ERC20 { return errors.New("unsupported coin type for refund on ZetaChain") @@ -80,7 +83,7 @@ func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossCh return errors.New("only EVM chains are supported for refund on ZetaChain") } - if inputAmount.IsNil() || inputAmount.IsZero() { + if refundAmount.IsNil() || refundAmount.IsZero() { return errors.New("no amount to refund") } @@ -95,7 +98,7 @@ func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossCh } // deposit the amount to the sender - if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundAddress, inputAmount.BigInt()); err != nil { + if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundAddress, refundAmount.BigInt()); err != nil { return errors.New("failed to deposit zrc20 on ZetaChain" + err.Error()) } diff --git a/x/crosschain/keeper/refund_test.go b/x/crosschain/keeper/refund_test.go index 04fbda1359..e9ecfd346f 100644 --- a/x/crosschain/keeper/refund_test.go +++ b/x/crosschain/keeper/refund_test.go @@ -30,8 +30,12 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), - Amount: math.NewUint(42), + Amount: math.NewUint(20), + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Amount: math.NewUint(42), }}, + }, sender, ) require.NoError(t, err) @@ -39,6 +43,30 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { require.NoError(t, err) require.Equal(t, uint64(42), balance.Uint64()) }) + t.Run("should refund inbound amount zrc20 gas on zeta chain", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") + + err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: chainID, + Sender: sender.String(), + TxOrigin: sender.String(), + Amount: math.NewUint(20), + }, + }, + sender, + ) + require.NoError(t, err) + balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, sender) + require.NoError(t, err) + require.Equal(t, uint64(20), balance.Uint64()) + }) t.Run("failed refund zrc20 gas on zeta chain if gas coin not found", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) @@ -51,8 +79,13 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), - Amount: math.NewUint(42), + Amount: math.NewUint(20), + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Amount: math.NewUint(42), }}, + }, + sender, ) require.ErrorContains(t, err, types.ErrForeignCoinNotFound.Error()) @@ -72,7 +105,11 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { Sender: sender.String(), TxOrigin: sender.String(), Amount: math.ZeroUint(), + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Amount: math.ZeroUint(), }}, + }, sender, ) require.ErrorContains(t, err, "no amount to refund") @@ -93,8 +130,12 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), - Amount: math.NewUint(42), + Amount: math.NewUint(20), + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Amount: math.NewUint(42), }}, + }, sender, ) require.NoError(t, err) @@ -102,6 +143,27 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { fmt.Println(coin.Amount.String()) require.Equal(t, "42", coin.Amount.String()) }) + t.Run("should refund inbound amount on zeta chain if outbound is not present", func(t *testing.T) { + k, ctx, sdkk, _ := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + + err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: chainID, + Sender: sender.String(), + TxOrigin: sender.String(), + Amount: math.NewUint(20), + }, + }, + sender, + ) + require.NoError(t, err) + coin := sdkk.BankKeeper.GetBalance(ctx, sdk.AccAddress(sender.Bytes()), config.BaseDenom) + require.Equal(t, "20", coin.Amount.String()) + }) t.Run("failed refund amount on zeta chain amount is 0", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) @@ -115,7 +177,11 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { Sender: sender.String(), TxOrigin: sender.String(), Amount: math.ZeroUint(), + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Amount: math.ZeroUint(), }}, + }, sender, ) require.ErrorContains(t, err, "no amount to refund") @@ -150,7 +216,11 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { Sender: sender.String(), Asset: asset, Amount: math.NewUint(42), + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Amount: math.NewUint(42), }}, + }, sender, ) require.NoError(t, err) From d1ff261d3c1d1bf7ed47cedfcdac85fd3d24159d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 9 Feb 2024 15:50:02 -0500 Subject: [PATCH 33/50] use outbound amount for refunds instead of inbound --- x/crosschain/keeper/cctx.go | 2 +- x/crosschain/keeper/cctx_utils.go | 16 ++++ x/crosschain/keeper/cctx_utils_test.go | 41 ++++++++++ .../keeper/msg_server_refund_aborted_tx.go | 24 ++++-- .../msg_server_refund_aborted_tx_test.go | 78 +++++++++++++------ x/crosschain/keeper/refund.go | 17 ++-- x/crosschain/keeper/refund_test.go | 76 +++++++++++++++++- 7 files changed, 213 insertions(+), 41 deletions(-) diff --git a/x/crosschain/keeper/cctx.go b/x/crosschain/keeper/cctx.go index e3a2a06f71..972875785e 100644 --- a/x/crosschain/keeper/cctx.go +++ b/x/crosschain/keeper/cctx.go @@ -49,7 +49,7 @@ func (k Keeper) SetCctxAndNonceToCctxAndInTxHashToCctx(ctx sdk.Context, cctx typ }) } if cctx.CctxStatus.Status == types.CctxStatus_Aborted && cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { - k.AddZetaAbortedAmount(ctx, cctx.GetCurrentOutTxParam().Amount) + k.AddZetaAbortedAmount(ctx, GetAbortedAmount(cctx)) } } diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 31422b7e63..8c2edd5013 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -4,6 +4,7 @@ import ( "fmt" cosmoserrors "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" "github.com/pkg/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -89,3 +90,18 @@ func IsPending(cctx types.CrossChainTx) bool { // pending inbound is not considered a "pending" state because it has not reached consensus yet return cctx.CctxStatus.Status == types.CctxStatus_PendingOutbound || cctx.CctxStatus.Status == types.CctxStatus_PendingRevert } + +// GetAbortedAmount returns the amount to refund for a given CCTX . +// If the CCTX has an outbound transaction, it returns the amount of the outbound transaction. +// If OutTxParams is nil or the amount is zero, it returns the amount of the inbound transaction. +// This is because there might be a case where the transaction is set to be aborted before paying gas or creating an outbound transaction.In such a situation we can refund the entire amount that has been locked in connector or TSS +func GetAbortedAmount(cctx types.CrossChainTx) sdkmath.Uint { + if cctx.OutboundTxParams != nil && !cctx.GetCurrentOutTxParam().Amount.IsZero() { + return cctx.GetCurrentOutTxParam().Amount + } + if cctx.InboundTxParams != nil { + return cctx.InboundTxParams.Amount + } + + return sdkmath.ZeroUint() +} diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index cba32c6a75..319ef35a54 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -4,10 +4,12 @@ import ( "math/big" "testing" + sdkmath "cosmossdk.io/math" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" "github.com/zeta-chain/zetacore/testutil/sample" + crosschainkeeper "github.com/zeta-chain/zetacore/x/crosschain/keeper" "github.com/zeta-chain/zetacore/x/crosschain/types" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" ) @@ -150,3 +152,42 @@ func TestGetRevertGasLimit(t *testing.T) { require.ErrorIs(t, err, fungibletypes.ErrContractCall) }) } + +func TestGetAbortedAmount(t *testing.T) { + amount := sdkmath.NewUint(100) + t.Run("should return the inbound amount if outbound not present", func(t *testing.T) { + cctx := types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + Amount: amount, + }, + } + a := crosschainkeeper.GetAbortedAmount(cctx) + require.Equal(t, amount, a) + }) + t.Run("should return the amount outbound amount", func(t *testing.T) { + cctx := types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + Amount: sdkmath.ZeroUint(), + }, + OutboundTxParams: []*types.OutboundTxParams{ + {Amount: amount}, + }, + } + a := crosschainkeeper.GetAbortedAmount(cctx) + require.Equal(t, amount, a) + }) + t.Run("should return the zero if outbound amount is not present and inbound is 0", func(t *testing.T) { + cctx := types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + Amount: sdkmath.ZeroUint(), + }, + } + a := crosschainkeeper.GetAbortedAmount(cctx) + require.Equal(t, sdkmath.ZeroUint(), a) + }) + t.Run("should return the zero if no amounts are present", func(t *testing.T) { + cctx := types.CrossChainTx{} + a := crosschainkeeper.GetAbortedAmount(cctx) + require.Equal(t, sdkmath.ZeroUint(), a) + }) +} diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 8cc85b6a19..0c6181aa71 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -1,6 +1,8 @@ package keeper import ( + "errors" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" @@ -37,10 +39,16 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund // Check if aborted amount is available to maintain zeta accounting // NOTE: Need to verify if this check works / is required in athens 3 if cctx.InboundTxParams.CoinType == common.CoinType_Zeta { - err := k.RemoveZetaAbortedAmount(ctx, cctx.InboundTxParams.Amount) - if err != nil { + err := k.RemoveZetaAbortedAmount(ctx, GetAbortedAmount(cctx)) + // if the zeta accounting is not found, it means the zeta accounting is not set yet and the refund should not be processed + if errors.Is(err, types.ErrUnableToFindZetaAccounting) { return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) } + // if the zeta accounting is found but the amount is insufficient, it means the refund can be processed but the zeta accounting is not maintained properly + // aborted amounts for zeta accounting would need to be updated in the envionment via a migration script + if errors.Is(err, types.ErrInsufficientZetaAmount) { + ctx.Logger().Error("Zeta Accounting Error: ", err) + } } refundAddress, err := GetRefundAddress(cctx, msg.RefundAddress) @@ -64,17 +72,17 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund return &types.MsgRefundAbortedCCTXResponse{}, nil } +// Set the proper refund address. +// For BTC sender chain the refund address is the one provided in the message in the RefundAddress field. +// For EVM chain with coin type ERC20 the refund address is the sender , but can be overridden by the RefundAddress field in the message. +// For EVM chain with coin type Zeta the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. +// For EVM chain with coin type Gas the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. + func GetRefundAddress(cctx types.CrossChainTx, optionalRefundAddress string) (ethcommon.Address, error) { // make sure a separate refund address is provided for a bitcoin chain as we cannot refund to tx origin or sender in this case if common.IsBitcoinChain(cctx.InboundTxParams.SenderChainId) && optionalRefundAddress == "" { return ethcommon.Address{}, errorsmod.Wrap(types.ErrInvalidAddress, "refund address is required for bitcoin chain") } - // Set the proper refund address. - // For BTC sender chain the refund address is the one provided in the message in the RefundAddress field. - // For EVM chain with coin type ERC20 the refund address is the sender , but can be overridden by the RefundAddress field in the message. - // For EVM chain with coin type Zeta the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. - // For EVM chain with coin type Gas the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. - refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { refundAddress = ethcommon.HexToAddress(cctx.InboundTxParams.Sender) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index 4423a5f3b6..54d6304444 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -3,7 +3,6 @@ package keeper_test import ( "testing" - sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" @@ -14,6 +13,7 @@ import ( "github.com/zeta-chain/zetacore/x/crosschain/keeper" crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) func Test_GetRefundAddress(t *testing.T) { @@ -106,7 +106,7 @@ func Test_GetRefundAddress(t *testing.T) { } func TestMsgServer_RefundAbortedCCTX(t *testing.T) { - t.Run("Successfully refund tx for coin-type Gas", func(t *testing.T) { + t.Run("successfully refund tx for coin-type gas", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -134,12 +134,12 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, refundAddress) require.NoError(t, err) - require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Uint64()) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount.Uint64(), balance.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Successfully refund tx for coin-type Zeta", func(t *testing.T) { + t.Run("successfully refund tx for coin-type zeta", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -154,7 +154,41 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.InboundTxParams.SenderChainId = chainID cctx.InboundTxParams.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) - k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) + k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.GetCurrentOutTxParam().Amount}) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + + _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ + Creator: admin, + CctxIndex: cctx.Index, + RefundAddress: "", + }) + require.NoError(t, err) + + refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) + refundAddressCosmos := sdk.AccAddress(refundAddress.Bytes()) + balance := sdkk.BankKeeper.GetBalance(ctx, refundAddressCosmos, config.BaseDenom) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount.Uint64(), balance.Amount.Uint64()) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.True(t, c.CctxStatus.IsAbortRefunded) + }) + t.Run("successfully refund tx to inbound amount if outbound is not found for coin-type zeta", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + chainID := getValidEthChainID(t) + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + + cctx := sample.CrossChainTx(t, "sample-index") + cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted + cctx.CctxStatus.IsAbortRefunded = false + cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.OutboundTxParams = nil + k.SetCrossChainTx(ctx, *cctx) + k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.GetCurrentOutTxParam().Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ @@ -172,7 +206,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Successfully refund to optional refund address if provided", func(t *testing.T) { + t.Run("successfully refund to optional refund address if provided", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -200,12 +234,12 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { refundAddressCosmos := sdk.AccAddress(refundAddress.Bytes()) balance := sdkk.BankKeeper.GetBalance(ctx, refundAddressCosmos, config.BaseDenom) - require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Amount.Uint64()) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount.Uint64(), balance.Amount.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Successfully refund tx for coin-type ERC20", func(t *testing.T) { + t.Run("successfully refund tx for coin-type ERC20", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -244,12 +278,12 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.Sender) balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, refundAddress) require.NoError(t, err) - require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Uint64()) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount.Uint64(), balance.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Successfully refund tx for coin-type Gas with BTC sender", func(t *testing.T) { + t.Run("successfully refund tx for coin-type Gas with BTC sender", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidBtcChainID() @@ -277,12 +311,12 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, refundAddress) require.NoError(t, err) - require.Equal(t, cctx.InboundTxParams.Amount.Uint64(), balance.Uint64()) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount.Uint64(), balance.Uint64()) c, found := k.GetCrossChainTx(ctx, cctx.Index) require.True(t, found) require.True(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Fail refund if address provided is invalid", func(t *testing.T) { + t.Run("fail refund if address provided is invalid", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -307,7 +341,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "invalid refund address") }) - t.Run("Fail refund if address provided is invalid 2 ", func(t *testing.T) { + t.Run("fail refund if address provided is null ", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -332,7 +366,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "invalid refund address") }) - t.Run("Fail refund if status is not aborted", func(t *testing.T) { + t.Run("fail refund if status is not aborted", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -359,7 +393,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { require.True(t, found) require.False(t, c.CctxStatus.IsAbortRefunded) }) - t.Run("Fail refund if status cctx not found", func(t *testing.T) { + t.Run("fail refund if status cctx not found", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -382,7 +416,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "cannot find cctx") }) - t.Run("Fail refund if refund address not provided for BTC chain", func(t *testing.T) { + t.Run("fail refund if refund address not provided for BTC chain", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidBtcChainID() @@ -407,7 +441,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "refund address is required for bitcoin chain") }) - t.Run("Fail refund tx for coin-type Zeta if zeta accounting object is not present", func(t *testing.T) { + t.Run("fail refund tx for coin-type Zeta if zeta accounting object is not present", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -431,7 +465,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "unable to find zeta accounting") }) - t.Run("Fail refund tx for coin-type Zeta if zeta accounting does not have enough aborted amount", func(t *testing.T) { + t.Run("fail refund if non admin account is the creator", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidEthChainID(t) @@ -444,16 +478,16 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.InboundTxParams.CoinType = common.CoinType_Gas k.SetCrossChainTx(ctx, *cctx) - k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: sdkmath.OneUint()}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + _ = setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ - Creator: admin, + Creator: sample.AccAddress(), CctxIndex: cctx.Index, RefundAddress: "", }) - require.ErrorContains(t, err, "insufficient zeta amount") + require.ErrorIs(t, err, observertypes.ErrNotAuthorized) }) } diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index ddb3028ef7..e3f059e385 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -28,11 +28,12 @@ func (k Keeper) RefundAbortedAmountOnZetaChain(ctx sdk.Context, cctx types.Cross // RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype gas func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { // refund in gas token to refund address - if cctx.InboundTxParams.Amount.IsNil() || cctx.InboundTxParams.Amount.IsZero() { + // Refund the the amount was previously + refundAmount := GetAbortedAmount(cctx) + if refundAmount.IsNil() || refundAmount.IsZero() { return errors.New("no amount to refund") } chainID := cctx.InboundTxParams.SenderChainId - amountOfGasTokenLocked := cctx.InboundTxParams.Amount // get the zrc20 contract address fcSenderChain, found := k.fungibleKeeper.GetGasCoinForForeignCoin(ctx, chainID) if !found { @@ -43,7 +44,7 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai return errorsmod.Wrapf(types.ErrForeignCoinNotFound, "zrc20 contract address not found for chain %d", chainID) } // deposit the amount to the tx origin instead of receiver as this is a refund - if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundAddress, amountOfGasTokenLocked.BigInt()); err != nil { + if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundAddress, refundAmount.BigInt()); err != nil { return errors.New("failed to refund zeta on ZetaChain" + err.Error()) } return nil @@ -52,6 +53,8 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai // RefundAmountOnZetaChainGas refunds the amount of the cctx on ZetaChain in case of aborted cctx with cointype zeta func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { // if coin type is Zeta, handle this as a deposit ZETA to zEVM. + refundAmount := GetAbortedAmount(cctx) + fmt.Println("RefundAmountOnZetaChainZeta: refundAmount: ", refundAmount) chainID := cctx.InboundTxParams.SenderChainId // check if chain is an EVM chain if !common.IsEVMChain(chainID) { @@ -61,7 +64,7 @@ func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossCha return errors.New("no amount to refund") } // deposit the amount to refund address - if err := k.fungibleKeeper.DepositCoinZeta(ctx, refundAddress, cctx.InboundTxParams.Amount.BigInt()); err != nil { + if err := k.fungibleKeeper.DepositCoinZeta(ctx, refundAddress, refundAmount.BigInt()); err != nil { return errors.New("failed to refund zeta on ZetaChain" + err.Error()) } return nil @@ -71,7 +74,7 @@ func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossCha // NOTE: GetCurrentOutTxParam should contain the last up to date cctx amount // Refund address should already be validated before calling this function func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { - inputAmount := cctx.InboundTxParams.Amount + refundAmount := GetAbortedAmount(cctx) // preliminary checks if cctx.InboundTxParams.CoinType != common.CoinType_ERC20 { return errors.New("unsupported coin type for refund on ZetaChain") @@ -80,7 +83,7 @@ func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossCh return errors.New("only EVM chains are supported for refund on ZetaChain") } - if inputAmount.IsNil() || inputAmount.IsZero() { + if refundAmount.IsNil() || refundAmount.IsZero() { return errors.New("no amount to refund") } @@ -95,7 +98,7 @@ func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossCh } // deposit the amount to the sender - if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundAddress, inputAmount.BigInt()); err != nil { + if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundAddress, refundAmount.BigInt()); err != nil { return errors.New("failed to deposit zrc20 on ZetaChain" + err.Error()) } diff --git a/x/crosschain/keeper/refund_test.go b/x/crosschain/keeper/refund_test.go index 04fbda1359..e9ecfd346f 100644 --- a/x/crosschain/keeper/refund_test.go +++ b/x/crosschain/keeper/refund_test.go @@ -30,8 +30,12 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), - Amount: math.NewUint(42), + Amount: math.NewUint(20), + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Amount: math.NewUint(42), }}, + }, sender, ) require.NoError(t, err) @@ -39,6 +43,30 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { require.NoError(t, err) require.Equal(t, uint64(42), balance.Uint64()) }) + t.Run("should refund inbound amount zrc20 gas on zeta chain", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") + + err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: chainID, + Sender: sender.String(), + TxOrigin: sender.String(), + Amount: math.NewUint(20), + }, + }, + sender, + ) + require.NoError(t, err) + balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, sender) + require.NoError(t, err) + require.Equal(t, uint64(20), balance.Uint64()) + }) t.Run("failed refund zrc20 gas on zeta chain if gas coin not found", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) @@ -51,8 +79,13 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), - Amount: math.NewUint(42), + Amount: math.NewUint(20), + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Amount: math.NewUint(42), }}, + }, + sender, ) require.ErrorContains(t, err, types.ErrForeignCoinNotFound.Error()) @@ -72,7 +105,11 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { Sender: sender.String(), TxOrigin: sender.String(), Amount: math.ZeroUint(), + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Amount: math.ZeroUint(), }}, + }, sender, ) require.ErrorContains(t, err, "no amount to refund") @@ -93,8 +130,12 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), - Amount: math.NewUint(42), + Amount: math.NewUint(20), + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Amount: math.NewUint(42), }}, + }, sender, ) require.NoError(t, err) @@ -102,6 +143,27 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { fmt.Println(coin.Amount.String()) require.Equal(t, "42", coin.Amount.String()) }) + t.Run("should refund inbound amount on zeta chain if outbound is not present", func(t *testing.T) { + k, ctx, sdkk, _ := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + + err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: chainID, + Sender: sender.String(), + TxOrigin: sender.String(), + Amount: math.NewUint(20), + }, + }, + sender, + ) + require.NoError(t, err) + coin := sdkk.BankKeeper.GetBalance(ctx, sdk.AccAddress(sender.Bytes()), config.BaseDenom) + require.Equal(t, "20", coin.Amount.String()) + }) t.Run("failed refund amount on zeta chain amount is 0", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) @@ -115,7 +177,11 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { Sender: sender.String(), TxOrigin: sender.String(), Amount: math.ZeroUint(), + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Amount: math.ZeroUint(), }}, + }, sender, ) require.ErrorContains(t, err, "no amount to refund") @@ -150,7 +216,11 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { Sender: sender.String(), Asset: asset, Amount: math.NewUint(42), + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Amount: math.NewUint(42), }}, + }, sender, ) require.NoError(t, err) From cd830fb1c6060e0de855bd388cb54b4fd58a7e36 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 9 Feb 2024 16:06:56 -0500 Subject: [PATCH 34/50] update comments --- x/crosschain/keeper/msg_server_refund_aborted_tx.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 0c6181aa71..01c5e18513 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -37,7 +37,6 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund } // Check if aborted amount is available to maintain zeta accounting - // NOTE: Need to verify if this check works / is required in athens 3 if cctx.InboundTxParams.CoinType == common.CoinType_Zeta { err := k.RemoveZetaAbortedAmount(ctx, GetAbortedAmount(cctx)) // if the zeta accounting is not found, it means the zeta accounting is not set yet and the refund should not be processed @@ -45,7 +44,6 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund return nil, errorsmod.Wrap(types.ErrUnableProcessRefund, err.Error()) } // if the zeta accounting is found but the amount is insufficient, it means the refund can be processed but the zeta accounting is not maintained properly - // aborted amounts for zeta accounting would need to be updated in the envionment via a migration script if errors.Is(err, types.ErrInsufficientZetaAmount) { ctx.Logger().Error("Zeta Accounting Error: ", err) } From ca87db9d1d9d2836ccb297bad1ad91497ce448d9 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 9 Feb 2024 16:11:34 -0500 Subject: [PATCH 35/50] update comments --- x/crosschain/keeper/msg_server_refund_aborted_tx.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 01c5e18513..3a467a44fa 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -12,6 +12,11 @@ import ( "golang.org/x/net/context" ) +// RefundAbortedCCTX refunds the aborted CCTX. +// It verifies if the CCTX is aborted and not refunded, and if the refund address is valid. +// It refunds the amount to the refund address and sets the CCTX as refunded. +// Refer to documentation for GetRefundAddress for the refund address logic. +// Refer to documentation for GetAbortedAmount for the aborted amount logic. func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefundAbortedCCTX) (*types.MsgRefundAbortedCCTXResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) From 05f103556193a8359eab9700220f11592ca28a52 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 12 Feb 2024 02:10:02 -0500 Subject: [PATCH 36/50] add migration script to reset zeta aborted amount --- app/setup_handlers.go | 4 +- x/crosschain/keeper/migrator.go | 6 ++ x/crosschain/migrations/v5/migrate.go | 63 +++++++++++++++++ x/crosschain/migrations/v5/migrate_test.go | 81 ++++++++++++++++++++++ x/crosschain/module.go | 3 + 5 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 x/crosschain/migrations/v5/migrate.go create mode 100644 x/crosschain/migrations/v5/migrate_test.go diff --git a/app/setup_handlers.go b/app/setup_handlers.go index 0ed66638d1..ac378e08b4 100644 --- a/app/setup_handlers.go +++ b/app/setup_handlers.go @@ -5,9 +5,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/upgrade/types" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" ) -const releaseVersion = "v12.2.0" +const releaseVersion = "v12.2.3" func SetupHandlers(app *App) { app.UpgradeKeeper.SetUpgradeHandler(releaseVersion, func(ctx sdk.Context, plan types.Plan, vm module.VersionMap) (module.VersionMap, error) { @@ -16,6 +17,7 @@ func SetupHandlers(app *App) { for m, mb := range app.mm.Modules { vm[m] = mb.ConsensusVersion() } + VersionMigrator{v: vm}.TriggerMigration(crosschaintypes.ModuleName) return app.mm.RunMigrations(ctx, app.configurator, vm) }) diff --git a/x/crosschain/keeper/migrator.go b/x/crosschain/keeper/migrator.go index cfdc1bba94..2c30398e3c 100644 --- a/x/crosschain/keeper/migrator.go +++ b/x/crosschain/keeper/migrator.go @@ -5,6 +5,7 @@ import ( v2 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v2" v3 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v3" v4 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v4" + v5 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v5" ) // Migrator is a struct for handling in-place store migrations. @@ -33,3 +34,8 @@ func (m Migrator) Migrate2to3(ctx sdk.Context) error { func (m Migrator) Migrate3to4(ctx sdk.Context) error { return v4.MigrateStore(ctx, m.crossChainKeeper.zetaObserverKeeper, m.crossChainKeeper) } + +// Migrate4to5 migrates the store from consensus version 4 to 5 +func (m Migrator) Migrate4to5(ctx sdk.Context) error { + return v5.MigrateStore(ctx, m.crossChainKeeper) +} diff --git a/x/crosschain/migrations/v5/migrate.go b/x/crosschain/migrations/v5/migrate.go new file mode 100644 index 0000000000..931988dca8 --- /dev/null +++ b/x/crosschain/migrations/v5/migrate.go @@ -0,0 +1,63 @@ +package v5 + +import ( + "fmt" + + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/keeper" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +// crosschainKeeper is an interface to prevent cyclic dependency +type crosschainKeeper interface { + GetStoreKey() storetypes.StoreKey + GetCodec() codec.Codec + GetAllCrossChainTx(ctx sdk.Context) []types.CrossChainTx + AddFinalizedInbound(ctx sdk.Context, inboundTxHash string, senderChainID int64, height uint64) +} + +// MigrateStore migrates the x/crosschain module state from the consensus version 4 to 5 +// It resets the aborted zeta amount to use the inbound tx amount instead in situations where the outbound cctx is never created. +func MigrateStore( + ctx sdk.Context, + crosschainKeeper crosschainKeeper, +) error { + SetZetaAccounting(ctx, crosschainKeeper.GetStoreKey(), crosschainKeeper.GetCodec()) + + return nil +} + +func SetZetaAccounting( + ctx sdk.Context, + crossChainStoreKey storetypes.StoreKey, + cdc codec.BinaryCodec, +) { + p := types.KeyPrefix(fmt.Sprintf("%s", types.SendKey)) + prefixedStore := prefix.NewStore(ctx.KVStore(crossChainStoreKey), p) + abortedAmountZeta := sdkmath.ZeroUint() + iterator := sdk.KVStorePrefixIterator(prefixedStore, []byte{}) + defer func(iterator sdk.Iterator) { + err := iterator.Close() + if err != nil { + panic(err) + } + }(iterator) + for ; iterator.Valid(); iterator.Next() { + var val types.CrossChainTx + cdc.MustUnmarshal(iterator.Value(), &val) + if val.CctxStatus.Status == types.CctxStatus_Aborted && val.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { + abortedValue := keeper.GetAbortedAmount(val) + abortedAmountZeta = abortedAmountZeta.Add(abortedValue) + } + } + b := cdc.MustMarshal(&types.ZetaAccounting{ + AbortedZetaAmount: abortedAmountZeta, + }) + store := ctx.KVStore(crossChainStoreKey) + store.Set([]byte(types.ZetaAccountingKey), b) +} diff --git a/x/crosschain/migrations/v5/migrate_test.go b/x/crosschain/migrations/v5/migrate_test.go new file mode 100644 index 0000000000..1910e28bb8 --- /dev/null +++ b/x/crosschain/migrations/v5/migrate_test.go @@ -0,0 +1,81 @@ +package v5_test + +import ( + "fmt" + "math/rand" + "testing" + + "cosmossdk.io/math" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + crosschainkeeper "github.com/zeta-chain/zetacore/x/crosschain/keeper" + v5 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v5" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func TestMigrateStore(t *testing.T) { + t.Run("TestMigrateStore", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctxList := CrossChainTxList(100) + v5ZetaAccountingAmount := math.ZeroUint() + v4ZetaAccountingAmount := math.ZeroUint() + for _, cctx := range cctxList { + if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_Aborted || cctx.GetCurrentOutTxParam().CoinType != common.CoinType_Zeta { + continue + } + v5ZetaAccountingAmount = v5ZetaAccountingAmount.Add(crosschainkeeper.GetAbortedAmount(cctx)) + v4ZetaAccountingAmount = v4ZetaAccountingAmount.Add(cctx.GetCurrentOutTxParam().Amount) + k.SetCrossChainTx(ctx, cctx) + } + assert.True(t, v5ZetaAccountingAmount.GT(v4ZetaAccountingAmount)) + // Previously set the zeta accounting + k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{ + AbortedZetaAmount: v4ZetaAccountingAmount, + }) + err := v5.MigrateStore(ctx, k) + require.NoError(t, err) + zetaAccounting, found := k.GetZetaAccounting(ctx) + require.True(t, found) + require.True(t, v5ZetaAccountingAmount.Equal(zetaAccounting.AbortedZetaAmount)) + }) + +} + +func CrossChainTxList(count int) []crosschaintypes.CrossChainTx { + cctxList := make([]crosschaintypes.CrossChainTx, count) + i := 0 + r := rand.New(rand.NewSource(9)) + for ; i < count/2; i++ { + amount := math.NewUint(uint64(r.Uint32())) + cctxList[i] = crosschaintypes.CrossChainTx{ + Index: fmt.Sprintf("%d", i), + CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, + InboundTxParams: &crosschaintypes.InboundTxParams{ + Amount: amount.Add(math.NewUint(uint64(r.Uint32()))), + CoinType: common.CoinType_Zeta, + }, + OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ + Amount: amount, + CoinType: common.CoinType_Zeta, + }}, + } + for ; i < count; i++ { + amount := math.NewUint(uint64(r.Uint32())) + cctxList[i] = crosschaintypes.CrossChainTx{ + Index: fmt.Sprintf("%d", i), + CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, + InboundTxParams: &crosschaintypes.InboundTxParams{ + Amount: amount, + CoinType: common.CoinType_Zeta, + }, + OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ + Amount: math.ZeroUint(), + CoinType: common.CoinType_Zeta, + }}, + } + } + } + return cctxList +} diff --git a/x/crosschain/module.go b/x/crosschain/module.go index 421f92c895..8821a7942e 100644 --- a/x/crosschain/module.go +++ b/x/crosschain/module.go @@ -157,6 +157,9 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { if err := cfg.RegisterMigration(types.ModuleName, 3, m.Migrate3to4); err != nil { panic(err) } + if err := cfg.RegisterMigration(types.ModuleName, 4, m.Migrate4to5); err != nil { + panic(err) + } } // RegisterInvariants registers the crosschain module's invariants. From 902d6cffebd9c35955f4fb658c0a5702e447845c Mon Sep 17 00:00:00 2001 From: lumtis Date: Mon, 12 Feb 2024 15:55:32 +0100 Subject: [PATCH 37/50] make change to test upgrade --- Dockerfile-versioned-source | 2 +- Makefile | 2 +- app/setup_handlers.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile-versioned-source b/Dockerfile-versioned-source index 67c4ac4273..528cf3d525 100644 --- a/Dockerfile-versioned-source +++ b/Dockerfile-versioned-source @@ -17,7 +17,7 @@ WORKDIR /go/delivery/zeta-node RUN mkdir -p $GOPATH/bin/old RUN mkdir -p $GOPATH/bin/new -ENV NEW_VERSION=v12.1.0 +ENV NEW_VERSION=v12.3.0 # Build new release from the current source COPY go.mod /go/delivery/zeta-node/ diff --git a/Makefile b/Makefile index 946d7a566b..51ee939cf9 100644 --- a/Makefile +++ b/Makefile @@ -240,7 +240,7 @@ stateful-upgrade: stateful-upgrade-source: @echo "--> Starting stateful smoketest" - $(DOCKER) build --build-arg old_version=v12.0.0 -t zetanode -f ./Dockerfile-versioned-source . + $(DOCKER) build --build-arg old_version=v12.2.1 -t zetanode -f ./Dockerfile-versioned-source . $(DOCKER) build -t orchestrator -f contrib/localnet/orchestrator/Dockerfile-upgrade.fastbuild . cd contrib/localnet/ && $(DOCKER) compose -f docker-compose-stateful.yml up -d diff --git a/app/setup_handlers.go b/app/setup_handlers.go index ac378e08b4..da037ba1a2 100644 --- a/app/setup_handlers.go +++ b/app/setup_handlers.go @@ -8,7 +8,7 @@ import ( crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" ) -const releaseVersion = "v12.2.3" +const releaseVersion = "v12.3.0" func SetupHandlers(app *App) { app.UpgradeKeeper.SetUpgradeHandler(releaseVersion, func(ctx sdk.Context, plan types.Plan, vm module.VersionMap) (module.VersionMap, error) { From 80da939d2193afac07904ba2c3ce5d4f1ff84167 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 12 Feb 2024 12:11:55 -0500 Subject: [PATCH 38/50] use interfac functions in migration script --- x/crosschain/migrations/v5/migrate.go | 52 +++++++++++---------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/x/crosschain/migrations/v5/migrate.go b/x/crosschain/migrations/v5/migrate.go index 931988dca8..2e9bf7e923 100644 --- a/x/crosschain/migrations/v5/migrate.go +++ b/x/crosschain/migrations/v5/migrate.go @@ -1,15 +1,11 @@ package v5 import ( - "fmt" - sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/prefix" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/zeta-chain/zetacore/common" - "github.com/zeta-chain/zetacore/x/crosschain/keeper" "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -19,6 +15,8 @@ type crosschainKeeper interface { GetCodec() codec.Codec GetAllCrossChainTx(ctx sdk.Context) []types.CrossChainTx AddFinalizedInbound(ctx sdk.Context, inboundTxHash string, senderChainID int64, height uint64) + + SetZetaAccounting(ctx sdk.Context, accounting types.ZetaAccounting) } // MigrateStore migrates the x/crosschain module state from the consensus version 4 to 5 @@ -27,37 +25,27 @@ func MigrateStore( ctx sdk.Context, crosschainKeeper crosschainKeeper, ) error { - SetZetaAccounting(ctx, crosschainKeeper.GetStoreKey(), crosschainKeeper.GetCodec()) - return nil -} - -func SetZetaAccounting( - ctx sdk.Context, - crossChainStoreKey storetypes.StoreKey, - cdc codec.BinaryCodec, -) { - p := types.KeyPrefix(fmt.Sprintf("%s", types.SendKey)) - prefixedStore := prefix.NewStore(ctx.KVStore(crossChainStoreKey), p) + ccctxList := crosschainKeeper.GetAllCrossChainTx(ctx) abortedAmountZeta := sdkmath.ZeroUint() - iterator := sdk.KVStorePrefixIterator(prefixedStore, []byte{}) - defer func(iterator sdk.Iterator) { - err := iterator.Close() - if err != nil { - panic(err) - } - }(iterator) - for ; iterator.Valid(); iterator.Next() { - var val types.CrossChainTx - cdc.MustUnmarshal(iterator.Value(), &val) - if val.CctxStatus.Status == types.CctxStatus_Aborted && val.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { - abortedValue := keeper.GetAbortedAmount(val) + for _, cctx := range ccctxList { + if cctx.CctxStatus.Status == types.CctxStatus_Aborted && cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { + abortedValue := GetAbortedAmount(cctx) abortedAmountZeta = abortedAmountZeta.Add(abortedValue) } } - b := cdc.MustMarshal(&types.ZetaAccounting{ - AbortedZetaAmount: abortedAmountZeta, - }) - store := ctx.KVStore(crossChainStoreKey) - store.Set([]byte(types.ZetaAccountingKey), b) + crosschainKeeper.SetZetaAccounting(ctx, types.ZetaAccounting{AbortedZetaAmount: abortedAmountZeta}) + + return nil +} + +func GetAbortedAmount(cctx types.CrossChainTx) sdkmath.Uint { + if cctx.OutboundTxParams != nil && !cctx.GetCurrentOutTxParam().Amount.IsZero() { + return cctx.GetCurrentOutTxParam().Amount + } + if cctx.InboundTxParams != nil { + return cctx.InboundTxParams.Amount + } + + return sdkmath.ZeroUint() } From 8efd39835ee483dc74b7dc3e744a6c695b35da76 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 12 Feb 2024 14:09:11 -0500 Subject: [PATCH 39/50] make refund address mandatory --- .../keeper/msg_server_refund_aborted_tx.go | 25 ++--- .../msg_server_refund_aborted_tx_test.go | 105 +++--------------- 2 files changed, 28 insertions(+), 102 deletions(-) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 3a467a44fa..6d33b4ee53 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -54,7 +54,7 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund } } - refundAddress, err := GetRefundAddress(cctx, msg.RefundAddress) + refundAddress, err := GetRefundAddress(msg.RefundAddress) if err != nil { return nil, errorsmod.Wrap(types.ErrInvalidAddress, err.Error()) } @@ -81,24 +81,19 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund // For EVM chain with coin type Zeta the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. // For EVM chain with coin type Gas the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. -func GetRefundAddress(cctx types.CrossChainTx, optionalRefundAddress string) (ethcommon.Address, error) { +func GetRefundAddress(refundAddress string) (ethcommon.Address, error) { // make sure a separate refund address is provided for a bitcoin chain as we cannot refund to tx origin or sender in this case - if common.IsBitcoinChain(cctx.InboundTxParams.SenderChainId) && optionalRefundAddress == "" { - return ethcommon.Address{}, errorsmod.Wrap(types.ErrInvalidAddress, "refund address is required for bitcoin chain") + if refundAddress == "" { + return ethcommon.Address{}, errorsmod.Wrap(types.ErrInvalidAddress, "refund address is required") } - refundAddress := ethcommon.HexToAddress(cctx.InboundTxParams.TxOrigin) - if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { - refundAddress = ethcommon.HexToAddress(cctx.InboundTxParams.Sender) - } - if optionalRefundAddress != "" { - if !ethcommon.IsHexAddress(optionalRefundAddress) { - return ethcommon.Address{}, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address provided") - } - refundAddress = ethcommon.HexToAddress(optionalRefundAddress) + if !ethcommon.IsHexAddress(refundAddress) { + return ethcommon.Address{}, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address provided") } + ethRefundAddress := ethcommon.HexToAddress(refundAddress) // Double check to make sure the refund address is valid - if refundAddress == (ethcommon.Address{}) { + if ethRefundAddress == (ethcommon.Address{}) { return ethcommon.Address{}, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address") } - return refundAddress, nil + return ethRefundAddress, nil + } diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index 54d6304444..e42360975e 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/cmd/zetacored/config" "github.com/zeta-chain/zetacore/common" @@ -19,89 +20,19 @@ import ( func Test_GetRefundAddress(t *testing.T) { t.Run("should return refund address if provided coin-type gas", func(t *testing.T) { validEthAddress := sample.EthAddress() - address, err := keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ - InboundTxParams: &crosschaintypes.InboundTxParams{ - TxOrigin: validEthAddress.String(), - CoinType: common.CoinType_Gas, - SenderChainId: getValidEthChainID(t), - }}, - "") + address, err := keeper.GetRefundAddress(validEthAddress.String()) require.NoError(t, err) require.Equal(t, validEthAddress, address) }) - t.Run("should return refund address if provided coin-type zeta", func(t *testing.T) { - validEthAddress := sample.EthAddress() - address, err := keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ - InboundTxParams: &crosschaintypes.InboundTxParams{ - TxOrigin: validEthAddress.String(), - CoinType: common.CoinType_Zeta, - SenderChainId: getValidEthChainID(t), - }}, - "") - require.NoError(t, err) - require.Equal(t, validEthAddress, address) + t.Run("should fail if refund address is empty", func(t *testing.T) { + address, err := keeper.GetRefundAddress("") + require.ErrorIs(t, crosschaintypes.ErrInvalidAddress, err) + assert.Equal(t, ethcommon.Address{}, address) }) - t.Run("should return refund address if provided coin-type erc20", func(t *testing.T) { - validEthAddress := sample.EthAddress() - address, err := keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ - InboundTxParams: &crosschaintypes.InboundTxParams{ - Sender: validEthAddress.String(), - CoinType: common.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), - }}, - "") - require.NoError(t, err) - require.Equal(t, validEthAddress, address) - }) - t.Run("should return refund address if provided coin-type gas for btc chain", func(t *testing.T) { - validEthAddress := sample.EthAddress() - address, err := keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ - InboundTxParams: &crosschaintypes.InboundTxParams{ - CoinType: common.CoinType_Gas, - SenderChainId: getValidBtcChainID(), - }}, - validEthAddress.String()) - require.NoError(t, err) - require.Equal(t, validEthAddress, address) - }) - t.Run("fail if refund address is not provided for btc chain", func(t *testing.T) { - _, err := keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ - InboundTxParams: &crosschaintypes.InboundTxParams{ - CoinType: common.CoinType_Gas, - SenderChainId: getValidBtcChainID(), - }}, - "") - require.ErrorContains(t, err, "refund address is required for bitcoin chain") - }) - t.Run("address overridden if optional address is provided", func(t *testing.T) { - validEthAddress := sample.EthAddress() - address, err := keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ - InboundTxParams: &crosschaintypes.InboundTxParams{ - Sender: sample.EthAddress().String(), - CoinType: common.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), - }}, - validEthAddress.String()) - require.NoError(t, err) - require.Equal(t, validEthAddress, address) - address, err = keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ - InboundTxParams: &crosschaintypes.InboundTxParams{ - Sender: sample.EthAddress().String(), - CoinType: common.CoinType_Zeta, - SenderChainId: getValidEthChainID(t), - }}, - validEthAddress.String()) - require.NoError(t, err) - require.Equal(t, validEthAddress, address) - address, err = keeper.GetRefundAddress(crosschaintypes.CrossChainTx{ - InboundTxParams: &crosschaintypes.InboundTxParams{ - Sender: sample.EthAddress().String(), - CoinType: common.CoinType_Gas, - SenderChainId: getValidEthChainID(t), - }}, - validEthAddress.String()) - require.NoError(t, err) - require.Equal(t, validEthAddress, address) + t.Run("should fail if refund address is invalid", func(t *testing.T) { + address, err := keeper.GetRefundAddress("invalid-address") + require.ErrorIs(t, crosschaintypes.ErrInvalidAddress, err) + assert.Equal(t, ethcommon.Address{}, address) }) } @@ -127,7 +58,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, - RefundAddress: "", + RefundAddress: cctx.InboundTxParams.Sender, }) require.NoError(t, err) @@ -160,7 +91,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, - RefundAddress: "", + RefundAddress: cctx.InboundTxParams.Sender, }) require.NoError(t, err) @@ -194,7 +125,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, - RefundAddress: "", + RefundAddress: cctx.InboundTxParams.Sender, }) require.NoError(t, err) @@ -271,7 +202,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, - RefundAddress: "", + RefundAddress: cctx.InboundTxParams.Sender, }) require.NoError(t, err) @@ -416,7 +347,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) require.ErrorContains(t, err, "cannot find cctx") }) - t.Run("fail refund if refund address not provided for BTC chain", func(t *testing.T) { + t.Run("fail refund if refund address not provided", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) admin := sample.AccAddress() chainID := getValidBtcChainID() @@ -439,7 +370,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { CctxIndex: cctx.Index, RefundAddress: "", }) - require.ErrorContains(t, err, "refund address is required for bitcoin chain") + require.ErrorContains(t, err, "refund address is required") }) t.Run("fail refund tx for coin-type Zeta if zeta accounting object is not present", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) @@ -461,7 +392,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: admin, CctxIndex: cctx.Index, - RefundAddress: "", + RefundAddress: cctx.InboundTxParams.Sender, }) require.ErrorContains(t, err, "unable to find zeta accounting") }) @@ -486,7 +417,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ Creator: sample.AccAddress(), CctxIndex: cctx.Index, - RefundAddress: "", + RefundAddress: cctx.InboundTxParams.Sender, }) require.ErrorIs(t, err, observertypes.ErrNotAuthorized) }) From 753a18d400634b8a4af7e16f14a04f63583fb5a5 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 12 Feb 2024 14:17:24 -0500 Subject: [PATCH 40/50] Update x/crosschain/keeper/msg_server_refund_aborted_tx.go Co-authored-by: Lucas Bertrand --- x/crosschain/keeper/msg_server_refund_aborted_tx.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 6d33b4ee53..b011c35163 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -75,12 +75,11 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund return &types.MsgRefundAbortedCCTXResponse{}, nil } -// Set the proper refund address. +// GetRefundAddress gets the proper refund address. // For BTC sender chain the refund address is the one provided in the message in the RefundAddress field. // For EVM chain with coin type ERC20 the refund address is the sender , but can be overridden by the RefundAddress field in the message. // For EVM chain with coin type Zeta the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. // For EVM chain with coin type Gas the refund address is the tx origin, but can be overridden by the RefundAddress field in the message. - func GetRefundAddress(refundAddress string) (ethcommon.Address, error) { // make sure a separate refund address is provided for a bitcoin chain as we cannot refund to tx origin or sender in this case if refundAddress == "" { From 46c1b51a426dce0ef9059dc936f68e69227f284d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 12 Feb 2024 16:01:30 -0500 Subject: [PATCH 41/50] disable refunds for auto refunded transactions --- docs/spec/crosschain/messages.md | 6 ++ x/crosschain/keeper/cctx.go | 1 + x/crosschain/keeper/migrator.go | 2 +- .../keeper/msg_server_vote_inbound_tx.go | 22 ------ x/crosschain/keeper/refund.go | 1 - x/crosschain/migrations/v5/migrate.go | 45 ++++++++++- x/crosschain/migrations/v5/migrate_test.go | 74 ++++++++++++++++++- 7 files changed, 120 insertions(+), 31 deletions(-) diff --git a/docs/spec/crosschain/messages.md b/docs/spec/crosschain/messages.md index 3b8e5a0c7d..f69a931598 100644 --- a/docs/spec/crosschain/messages.md +++ b/docs/spec/crosschain/messages.md @@ -272,6 +272,12 @@ message MsgAbortStuckCCTX { ## MsgRefundAbortedCCTX +RefundAbortedCCTX refunds the aborted CCTX. +It verifies if the CCTX is aborted and not refunded, and if the refund address is valid. +It refunds the amount to the refund address and sets the CCTX as refunded. +Refer to documentation for GetRefundAddress for the refund address logic. +Refer to documentation for GetAbortedAmount for the aborted amount logic. + ```proto message MsgRefundAbortedCCTX { string creator = 1; diff --git a/x/crosschain/keeper/cctx.go b/x/crosschain/keeper/cctx.go index 972875785e..7dad9f4197 100644 --- a/x/crosschain/keeper/cctx.go +++ b/x/crosschain/keeper/cctx.go @@ -133,6 +133,7 @@ func (k Keeper) CreateNewCCTX(ctx sdk.Context, msg *types.MsgVoteOnObservedInbou Status: s, StatusMessage: "", LastUpdateTimestamp: ctx.BlockHeader().Time.Unix(), + IsAbortRefunded: false, } newCctx := types.CrossChainTx{ Creator: msg.Creator, diff --git a/x/crosschain/keeper/migrator.go b/x/crosschain/keeper/migrator.go index 2c30398e3c..4de64140c8 100644 --- a/x/crosschain/keeper/migrator.go +++ b/x/crosschain/keeper/migrator.go @@ -37,5 +37,5 @@ func (m Migrator) Migrate3to4(ctx sdk.Context) error { // Migrate4to5 migrates the store from consensus version 4 to 5 func (m Migrator) Migrate4to5(ctx sdk.Context) error { - return v5.MigrateStore(ctx, m.crossChainKeeper) + return v5.MigrateStore(ctx, m.crossChainKeeper, m.crossChainKeeper.zetaObserverKeeper) } diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 2c36d7d16b..ef98c85bf8 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -7,7 +7,6 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" observerKeeper "github.com/zeta-chain/zetacore/x/observer/keeper" @@ -189,27 +188,6 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg return k.UpdateNonce(tmpCtx, chain.ChainId, &cctx) }() if err != nil { - // do not commit anything here as the CCTX should be aborted - - // gas payment for erc20 type might fail because no liquidity pool is defined to swap the zrc20 token into the gas token - // in this gas we should refund the sender on ZetaChain - if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 && - ethcommon.IsHexAddress(cctx.InboundTxParams.Sender) && - cctx.CctxStatus.IsAbortRefunded == false { - // Sender is verified to be a valid ethereum address - err := k.RefundAbortedAmountOnZetaChain(ctx, cctx, ethcommon.HexToAddress(cctx.InboundTxParams.Sender)) - if err != nil { - // log the error - k.Logger(ctx).Error("failed to refund amount of aborted cctx on ZetaChain", - "error", err, - "sender", cctx.InboundTxParams.Sender, - "amount", cctx.InboundTxParams.Amount.String(), - ) - } else { - cctx.CctxStatus.AbortRefunded(ctx.BlockTime().Unix()) - } - } - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()+" deposit revert message: "+revertMessage) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index e3f059e385..9d10b7ce13 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -54,7 +54,6 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { // if coin type is Zeta, handle this as a deposit ZETA to zEVM. refundAmount := GetAbortedAmount(cctx) - fmt.Println("RefundAmountOnZetaChainZeta: refundAmount: ", refundAmount) chainID := cctx.InboundTxParams.SenderChainId // check if chain is an EVM chain if !common.IsEVMChain(chainID) { diff --git a/x/crosschain/migrations/v5/migrate.go b/x/crosschain/migrations/v5/migrate.go index 2e9bf7e923..8b61823ba7 100644 --- a/x/crosschain/migrations/v5/migrate.go +++ b/x/crosschain/migrations/v5/migrate.go @@ -1,6 +1,8 @@ package v5 import ( + "fmt" + sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" @@ -14,6 +16,8 @@ type crosschainKeeper interface { GetStoreKey() storetypes.StoreKey GetCodec() codec.Codec GetAllCrossChainTx(ctx sdk.Context) []types.CrossChainTx + + SetCrossChainTx(ctx sdk.Context, cctx types.CrossChainTx) AddFinalizedInbound(ctx sdk.Context, inboundTxHash string, senderChainID int64, height uint64) SetZetaAccounting(ctx sdk.Context, accounting types.ZetaAccounting) @@ -24,15 +28,50 @@ type crosschainKeeper interface { func MigrateStore( ctx sdk.Context, crosschainKeeper crosschainKeeper, + observerKeeper types.ObserverKeeper, ) error { ccctxList := crosschainKeeper.GetAllCrossChainTx(ctx) abortedAmountZeta := sdkmath.ZeroUint() for _, cctx := range ccctxList { - if cctx.CctxStatus.Status == types.CctxStatus_Aborted && cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { - abortedValue := GetAbortedAmount(cctx) - abortedAmountZeta = abortedAmountZeta.Add(abortedValue) + if cctx.CctxStatus.Status == types.CctxStatus_Aborted { + + switch cctx.InboundTxParams.CoinType { + case common.CoinType_ERC20: + { + receiverChain := observerKeeper.GetSupportedChainFromChainID(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId) + if receiverChain == nil { + ctx.Logger().Error(fmt.Sprintf("Error getting chain from chain id: %d , cctx index", cctx.GetCurrentOutTxParam().ReceiverChainId), cctx.Index) + continue + } + // There is a chance that this cctx has already been refunded, so we set the isRefunded flag to true. + // Even though, there is a slight possibility that the refund tx failed when doing an auto refund; there is no way for us to know. Which is why we can mark this type of cctx as non-refundable + // Auto refunds are done for ERC20 cctx's when the receiver chain is a zeta chain. + if receiverChain.IsZetaChain() { + cctx.CctxStatus.IsAbortRefunded = true + } else { + cctx.CctxStatus.IsAbortRefunded = false + } + } + case common.CoinType_Zeta: + { + // add the required amount into the zeta accounting. + // GetAbortedAmount replaces using Putbound Amount directly , to make sure we refund the amount deposited by the user if the outbound is never created and the cctx is aborted. + // For these cctx's we allow the refund to be processed later and the Aborted amount would be adjusted when the refund is processed. + abortedValue := GetAbortedAmount(cctx) + abortedAmountZeta = abortedAmountZeta.Add(abortedValue) + cctx.CctxStatus.IsAbortRefunded = false + + } + case common.CoinType_Gas: + { + // CointType gas can be processed as normal and we can issue the refund using the admin refund tx . + cctx.CctxStatus.IsAbortRefunded = false + } + } + crosschainKeeper.SetCrossChainTx(ctx, cctx) } + } crosschainKeeper.SetZetaAccounting(ctx, types.ZetaAccounting{AbortedZetaAmount: abortedAmountZeta}) diff --git a/x/crosschain/migrations/v5/migrate_test.go b/x/crosschain/migrations/v5/migrate_test.go index 1910e28bb8..8033ddc3bf 100644 --- a/x/crosschain/migrations/v5/migrate_test.go +++ b/x/crosschain/migrations/v5/migrate_test.go @@ -17,34 +17,53 @@ import ( func TestMigrateStore(t *testing.T) { t.Run("TestMigrateStore", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) + k, ctx, _, zk := keepertest.CrosschainKeeper(t) cctxList := CrossChainTxList(100) v5ZetaAccountingAmount := math.ZeroUint() v4ZetaAccountingAmount := math.ZeroUint() for _, cctx := range cctxList { + k.SetCrossChainTx(ctx, cctx) if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_Aborted || cctx.GetCurrentOutTxParam().CoinType != common.CoinType_Zeta { continue } v5ZetaAccountingAmount = v5ZetaAccountingAmount.Add(crosschainkeeper.GetAbortedAmount(cctx)) v4ZetaAccountingAmount = v4ZetaAccountingAmount.Add(cctx.GetCurrentOutTxParam().Amount) - k.SetCrossChainTx(ctx, cctx) } + assert.True(t, v5ZetaAccountingAmount.GT(v4ZetaAccountingAmount)) // Previously set the zeta accounting k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{ AbortedZetaAmount: v4ZetaAccountingAmount, }) - err := v5.MigrateStore(ctx, k) + err := v5.MigrateStore(ctx, k, k.GetObserverKeeper()) require.NoError(t, err) zetaAccounting, found := k.GetZetaAccounting(ctx) require.True(t, found) require.True(t, v5ZetaAccountingAmount.Equal(zetaAccounting.AbortedZetaAmount)) + cctxListUpdated := k.GetAllCrossChainTx(ctx) + // Check refund status of the cctx + for _, cctx := range cctxListUpdated { + switch cctx.InboundTxParams.CoinType { + case common.CoinType_ERC20: + receiverChain := zk.ObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId) + require.NotNil(t, receiverChain) + if receiverChain.IsZetaChain() { + require.True(t, cctx.CctxStatus.IsAbortRefunded) + } else { + require.False(t, cctx.CctxStatus.IsAbortRefunded) + } + case common.CoinType_Zeta: + require.False(t, cctx.CctxStatus.IsAbortRefunded) + case common.CoinType_Gas: + require.False(t, cctx.CctxStatus.IsAbortRefunded) + } + } }) } func CrossChainTxList(count int) []crosschaintypes.CrossChainTx { - cctxList := make([]crosschaintypes.CrossChainTx, count) + cctxList := make([]crosschaintypes.CrossChainTx, count+100) i := 0 r := rand.New(rand.NewSource(9)) for ; i < count/2; i++ { @@ -76,6 +95,53 @@ func CrossChainTxList(count int) []crosschaintypes.CrossChainTx { }}, } } + for ; i < count+20; i++ { + amount := math.NewUint(uint64(r.Uint32())) + cctxList[i] = crosschaintypes.CrossChainTx{ + Index: fmt.Sprintf("%d", i), + CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, + InboundTxParams: &crosschaintypes.InboundTxParams{ + Amount: amount, + CoinType: common.CoinType_ERC20, + }, + OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ + Amount: math.ZeroUint(), + CoinType: common.CoinType_ERC20, + ReceiverChainId: common.ZetaPrivnetChain().ChainId, + }}, + } + } + for ; i < count+50; i++ { + amount := math.NewUint(uint64(r.Uint32())) + cctxList[i] = crosschaintypes.CrossChainTx{ + Index: fmt.Sprintf("%d", i), + CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, + InboundTxParams: &crosschaintypes.InboundTxParams{ + Amount: amount, + CoinType: common.CoinType_ERC20, + }, + OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ + Amount: math.ZeroUint(), + CoinType: common.CoinType_ERC20, + ReceiverChainId: common.GoerliLocalnetChain().ChainId, + }}, + } + } + for ; i < count+100; i++ { + amount := math.NewUint(uint64(r.Uint32())) + cctxList[i] = crosschaintypes.CrossChainTx{ + Index: fmt.Sprintf("%d", i), + CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, + InboundTxParams: &crosschaintypes.InboundTxParams{ + Amount: amount, + CoinType: common.CoinType_Gas, + }, + OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ + Amount: amount, + CoinType: common.CoinType_Gas, + }}, + } + } } return cctxList } From 6df27a41561b5005509a1dd6b1b61a46716fa5ec Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 12 Feb 2024 16:18:44 -0500 Subject: [PATCH 42/50] fix lint --- x/emissions/client/tests/suite.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/emissions/client/tests/suite.go b/x/emissions/client/tests/suite.go index 2baea8a338..8d26f1a55a 100644 --- a/x/emissions/client/tests/suite.go +++ b/x/emissions/client/tests/suite.go @@ -88,6 +88,7 @@ func RandomBallotGenerator(numberOfBallots int, voterList []string) []*observerT ObservationType: observerTypes.ObservationType_InBoundTx, BallotThreshold: sdk.MustNewDecFromStr("0.66"), // #nosec G404 randomness used for testing + // #nosec G404 (CWE-338): randomness is not a security issue here BallotStatus: ballotStatus[rand.Intn(max-min)+min], BallotCreationHeight: 0, } From d6d673c1866bc6f438f2a162ca2d0ba7c585f80a Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 12 Feb 2024 17:42:56 -0500 Subject: [PATCH 43/50] fix lint 2 --- x/emissions/client/tests/suite.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x/emissions/client/tests/suite.go b/x/emissions/client/tests/suite.go index 8d26f1a55a..2388e32c23 100644 --- a/x/emissions/client/tests/suite.go +++ b/x/emissions/client/tests/suite.go @@ -80,6 +80,8 @@ func RandomBallotGenerator(numberOfBallots int, voterList []string) []*observerT max := len(ballotStatus) - 1 // #nosec G404 randomness is not a security issue here for i := 0; i < numberOfBallots; i++ { + // #nosec G404 randomness is not a security issue here + randStatus := ballotStatus[rand.Intn(max-min)+min] ballots[i] = &observerTypes.Ballot{ Index: "", BallotIdentifier: "TestBallot" + strconv.Itoa(i), @@ -88,8 +90,7 @@ func RandomBallotGenerator(numberOfBallots int, voterList []string) []*observerT ObservationType: observerTypes.ObservationType_InBoundTx, BallotThreshold: sdk.MustNewDecFromStr("0.66"), // #nosec G404 randomness used for testing - // #nosec G404 (CWE-338): randomness is not a security issue here - BallotStatus: ballotStatus[rand.Intn(max-min)+min], + BallotStatus: randStatus, BallotCreationHeight: 0, } } From b0a8703e0cf651ce1252657b5de29e1d800e958d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 12 Feb 2024 17:48:49 -0500 Subject: [PATCH 44/50] fix lint 2 --- x/emissions/client/tests/suite.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x/emissions/client/tests/suite.go b/x/emissions/client/tests/suite.go index 2388e32c23..68b57f43ee 100644 --- a/x/emissions/client/tests/suite.go +++ b/x/emissions/client/tests/suite.go @@ -81,7 +81,9 @@ func RandomBallotGenerator(numberOfBallots int, voterList []string) []*observerT // #nosec G404 randomness is not a security issue here for i := 0; i < numberOfBallots; i++ { // #nosec G404 randomness is not a security issue here - randStatus := ballotStatus[rand.Intn(max-min)+min] + randIndex := rand.Intn(max-min) + min + // #nosec G404 randomness is not a security issue here + randStatus := ballotStatus[randIndex] ballots[i] = &observerTypes.Ballot{ Index: "", BallotIdentifier: "TestBallot" + strconv.Itoa(i), From 064c3cf66ee2e7cdccbcc9b6d6146f4606af7f75 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 13 Feb 2024 01:33:30 -0500 Subject: [PATCH 45/50] fix smoke test --- .../smoketest/smoketests/test_erc20_refund.go | 26 +++++++++---------- x/emissions/client/tests/suite.go | 8 +----- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go b/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go index dcfc86acc1..e0c5bd264e 100644 --- a/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go +++ b/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go @@ -15,10 +15,10 @@ import ( func TestERC20DepositAndCallRefund(sm *runner.SmokeTestRunner) { // Get the initial balance of the deployer - initialBal, err := sm.USDTZRC20.BalanceOf(&bind.CallOpts{}, sm.DeployerAddress) - if err != nil { - panic(err) - } + //initialBal, err := sm.USDTZRC20.BalanceOf(&bind.CallOpts{}, sm.DeployerAddress) + //if err != nil { + // panic(err) + //} sm.Logger.Info("Sending a deposit that should revert without a liquidity pool makes the cctx aborted") @@ -38,15 +38,15 @@ func TestERC20DepositAndCallRefund(sm *runner.SmokeTestRunner) { } // Check that the erc20 in the aborted cctx was refunded on ZetaChain - newBalance, err := sm.USDTZRC20.BalanceOf(&bind.CallOpts{}, sm.DeployerAddress) - if err != nil { - panic(err) - } - expectedBalance := initialBal.Add(initialBal, amount) - if newBalance.Cmp(expectedBalance) != 0 { - panic(fmt.Sprintf("expected balance to be %s after refund; got %s", expectedBalance.String(), newBalance.String())) - } - sm.Logger.Info("CCTX has been aborted and the erc20 has been refunded on ZetaChain") + //newBalance, err := sm.USDTZRC20.BalanceOf(&bind.CallOpts{}, sm.DeployerAddress) + //if err != nil { + // panic(err) + //} + //expectedBalance := initialBal.Add(initialBal, amount) + //if newBalance.Cmp(expectedBalance) != 0 { + // panic(fmt.Sprintf("expected balance to be %s after refund; got %s", expectedBalance.String(), newBalance.String())) + //} + sm.Logger.Info("CCTX has been aborted on ZetaChain") // test refund when there is a liquidity pool sm.Logger.Info("Sending a deposit that should revert with a liquidity pool") diff --git a/x/emissions/client/tests/suite.go b/x/emissions/client/tests/suite.go index 68b57f43ee..3d23ca2ef6 100644 --- a/x/emissions/client/tests/suite.go +++ b/x/emissions/client/tests/suite.go @@ -76,14 +76,8 @@ func CreateRandomVoteList(numberOfVotes int) []observerTypes.VoteType { func RandomBallotGenerator(numberOfBallots int, voterList []string) []*observerTypes.Ballot { ballots := make([]*observerTypes.Ballot, numberOfBallots) ballotStatus := []observerTypes.BallotStatus{observerTypes.BallotStatus_BallotFinalized_FailureObservation, observerTypes.BallotStatus_BallotFinalized_SuccessObservation} - min := 0 - max := len(ballotStatus) - 1 // #nosec G404 randomness is not a security issue here for i := 0; i < numberOfBallots; i++ { - // #nosec G404 randomness is not a security issue here - randIndex := rand.Intn(max-min) + min - // #nosec G404 randomness is not a security issue here - randStatus := ballotStatus[randIndex] ballots[i] = &observerTypes.Ballot{ Index: "", BallotIdentifier: "TestBallot" + strconv.Itoa(i), @@ -92,7 +86,7 @@ func RandomBallotGenerator(numberOfBallots int, voterList []string) []*observerT ObservationType: observerTypes.ObservationType_InBoundTx, BallotThreshold: sdk.MustNewDecFromStr("0.66"), // #nosec G404 randomness used for testing - BallotStatus: randStatus, + BallotStatus: ballotStatus[rand.Intn(2)], BallotCreationHeight: 0, } } From fe2265301938319122dce218ea55fccb59e2b78d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 13 Feb 2024 01:48:38 -0500 Subject: [PATCH 46/50] remove rand generator for ballot --- x/emissions/client/tests/suite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/emissions/client/tests/suite.go b/x/emissions/client/tests/suite.go index 3d23ca2ef6..5f2b580267 100644 --- a/x/emissions/client/tests/suite.go +++ b/x/emissions/client/tests/suite.go @@ -86,7 +86,7 @@ func RandomBallotGenerator(numberOfBallots int, voterList []string) []*observerT ObservationType: observerTypes.ObservationType_InBoundTx, BallotThreshold: sdk.MustNewDecFromStr("0.66"), // #nosec G404 randomness used for testing - BallotStatus: ballotStatus[rand.Intn(2)], + BallotStatus: ballotStatus[i%2], BallotCreationHeight: 0, } } From 020e2baa75028926b4c921de5a789bfc36944c67 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 13 Feb 2024 02:06:02 -0500 Subject: [PATCH 47/50] add check for cctx status --- .../orchestrator/smoketest/smoketests/test_erc20_refund.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go b/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go index e0c5bd264e..a551905008 100644 --- a/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go +++ b/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go @@ -37,6 +37,10 @@ func TestERC20DepositAndCallRefund(sm *runner.SmokeTestRunner) { panic(fmt.Sprintf("expected cctx status to be Aborted; got %s", cctx.CctxStatus.Status)) } + if cctx.CctxStatus.IsAbortRefunded != false { + panic(fmt.Sprintf("expected cctx status to be not refunded; got %s", cctx.CctxStatus.IsAbortRefunded)) + } + // Check that the erc20 in the aborted cctx was refunded on ZetaChain //newBalance, err := sm.USDTZRC20.BalanceOf(&bind.CallOpts{}, sm.DeployerAddress) //if err != nil { From 4675fd5c4ed99bee14df5d7c5e7f7b7f4fbfe57d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 13 Feb 2024 02:19:18 -0500 Subject: [PATCH 48/50] add check for cctx status --- .../orchestrator/smoketest/smoketests/test_erc20_refund.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go b/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go index a551905008..c07c78ba5e 100644 --- a/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go +++ b/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go @@ -38,7 +38,7 @@ func TestERC20DepositAndCallRefund(sm *runner.SmokeTestRunner) { } if cctx.CctxStatus.IsAbortRefunded != false { - panic(fmt.Sprintf("expected cctx status to be not refunded; got %s", cctx.CctxStatus.IsAbortRefunded)) + panic(fmt.Sprintf("expected cctx status to be not refunded; got %t", cctx.CctxStatus.IsAbortRefunded)) } // Check that the erc20 in the aborted cctx was refunded on ZetaChain From 0cd4a12338e2af10740ce8238e2ccacc41a4f4ca Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 13 Feb 2024 13:05:19 -0500 Subject: [PATCH 49/50] Update x/crosschain/migrations/v5/migrate.go Co-authored-by: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> --- x/crosschain/migrations/v5/migrate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/crosschain/migrations/v5/migrate.go b/x/crosschain/migrations/v5/migrate.go index 8b61823ba7..b5e40ceee3 100644 --- a/x/crosschain/migrations/v5/migrate.go +++ b/x/crosschain/migrations/v5/migrate.go @@ -56,7 +56,7 @@ func MigrateStore( case common.CoinType_Zeta: { // add the required amount into the zeta accounting. - // GetAbortedAmount replaces using Putbound Amount directly , to make sure we refund the amount deposited by the user if the outbound is never created and the cctx is aborted. + // GetAbortedAmount replaces using Outbound Amount directly, to make sure we refund the amount deposited by the user if the outbound is never created and the cctx is aborted. // For these cctx's we allow the refund to be processed later and the Aborted amount would be adjusted when the refund is processed. abortedValue := GetAbortedAmount(cctx) abortedAmountZeta = abortedAmountZeta.Add(abortedValue) From b27c97cc7d32eb41347e2f943a88d89202fb5024 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 13 Feb 2024 14:44:37 -0500 Subject: [PATCH 50/50] add admin refund to smoketest --- .../smoketest/smoketests/test_erc20_refund.go | 44 ++++++++++++------- .../smoketest/txserver/zeta_tx_server.go | 5 +++ 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go b/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go index c07c78ba5e..e7728dda15 100644 --- a/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go +++ b/contrib/localnet/orchestrator/smoketest/smoketests/test_erc20_refund.go @@ -10,15 +10,15 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/contrib/localnet/orchestrator/smoketest/runner" "github.com/zeta-chain/zetacore/contrib/localnet/orchestrator/smoketest/utils" - "github.com/zeta-chain/zetacore/x/crosschain/types" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" ) func TestERC20DepositAndCallRefund(sm *runner.SmokeTestRunner) { - // Get the initial balance of the deployer - //initialBal, err := sm.USDTZRC20.BalanceOf(&bind.CallOpts{}, sm.DeployerAddress) - //if err != nil { - // panic(err) - //} + //Get the initial balance of the deployer + initialBal, err := sm.USDTZRC20.BalanceOf(&bind.CallOpts{}, sm.DeployerAddress) + if err != nil { + panic(err) + } sm.Logger.Info("Sending a deposit that should revert without a liquidity pool makes the cctx aborted") @@ -33,7 +33,7 @@ func TestERC20DepositAndCallRefund(sm *runner.SmokeTestRunner) { // There is no liquidity pool, therefore the cctx should abort cctx := utils.WaitCctxMinedByInTxHash(sm.Ctx, inTxHash, sm.CctxClient, sm.Logger, sm.CctxTimeout) sm.Logger.CCTX(*cctx, "deposit") - if cctx.CctxStatus.Status != types.CctxStatus_Aborted { + if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_Aborted { panic(fmt.Sprintf("expected cctx status to be Aborted; got %s", cctx.CctxStatus.Status)) } @@ -41,15 +41,25 @@ func TestERC20DepositAndCallRefund(sm *runner.SmokeTestRunner) { panic(fmt.Sprintf("expected cctx status to be not refunded; got %t", cctx.CctxStatus.IsAbortRefunded)) } - // Check that the erc20 in the aborted cctx was refunded on ZetaChain - //newBalance, err := sm.USDTZRC20.BalanceOf(&bind.CallOpts{}, sm.DeployerAddress) - //if err != nil { - // panic(err) - //} - //expectedBalance := initialBal.Add(initialBal, amount) - //if newBalance.Cmp(expectedBalance) != 0 { - // panic(fmt.Sprintf("expected balance to be %s after refund; got %s", expectedBalance.String(), newBalance.String())) - //} + sm.Logger.Info("Refunding the cctx via admin") + msg := crosschaintypes.NewMsgRefundAbortedCCTX( + sm.ZetaTxServer.GetAccountAddress(0), + cctx.Index, + sm.DeployerAddress.String()) + _, err = sm.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, msg) + if err != nil { + panic(err) + } + + //Check that the erc20 in the aborted cctx was refunded on ZetaChain + newBalance, err := sm.USDTZRC20.BalanceOf(&bind.CallOpts{}, sm.DeployerAddress) + if err != nil { + panic(err) + } + expectedBalance := initialBal.Add(initialBal, amount) + if newBalance.Cmp(expectedBalance) != 0 { + panic(fmt.Sprintf("expected balance to be %s after refund; got %s", expectedBalance.String(), newBalance.String())) + } sm.Logger.Info("CCTX has been aborted on ZetaChain") // test refund when there is a liquidity pool @@ -79,7 +89,7 @@ func TestERC20DepositAndCallRefund(sm *runner.SmokeTestRunner) { cctx = utils.WaitCctxMinedByInTxHash(sm.Ctx, inTxHash, sm.CctxClient, sm.Logger, sm.CctxTimeout) // the revert tx creation will fail because the sender, used as the recipient, is not defined in the cctx - if cctx.CctxStatus.Status != types.CctxStatus_Reverted { + if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_Reverted { panic(fmt.Sprintf( "expected cctx status to be PendingRevert; got %s, aborted message: %s", cctx.CctxStatus.Status, diff --git a/contrib/localnet/orchestrator/smoketest/txserver/zeta_tx_server.go b/contrib/localnet/orchestrator/smoketest/txserver/zeta_tx_server.go index d43cbd7fe6..ee63851a74 100644 --- a/contrib/localnet/orchestrator/smoketest/txserver/zeta_tx_server.go +++ b/contrib/localnet/orchestrator/smoketest/txserver/zeta_tx_server.go @@ -121,6 +121,11 @@ func (zts ZetaTxServer) GetAccountAddress(index int) string { return zts.address[index] } +func (zts ZetaTxServer) GetAllAccountAddress() []string { + return zts.address + +} + // GetAccountMnemonic returns the account name from the given index // returns empty string if index is out of bound, error should be handled by caller func (zts ZetaTxServer) GetAccountMnemonic(index int) string {