diff --git a/app/app.go b/app/app.go index 881a89a79..429db50f8 100644 --- a/app/app.go +++ b/app/app.go @@ -91,6 +91,9 @@ import ( authkeeper "github.com/shentufoundation/shentu/v2/x/auth/keeper" "github.com/shentufoundation/shentu/v2/x/bank" bankkeeper "github.com/shentufoundation/shentu/v2/x/bank/keeper" + "github.com/shentufoundation/shentu/v2/x/bounty" + bountykeeper "github.com/shentufoundation/shentu/v2/x/bounty/keeper" + bountytypes "github.com/shentufoundation/shentu/v2/x/bounty/types" "github.com/shentufoundation/shentu/v2/x/cert" certclient "github.com/shentufoundation/shentu/v2/x/cert/client" certkeeper "github.com/shentufoundation/shentu/v2/x/cert/keeper" @@ -165,6 +168,7 @@ var ( ibc.AppModuleBasic{}, transfer.AppModuleBasic{}, ica.AppModuleBasic{}, + bounty.AppModuleBasic{}, ) // module account permissions @@ -180,6 +184,7 @@ var ( shieldtypes.ModuleName: {authtypes.Burner}, cvmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + bountytypes.ModuleName: {authtypes.Burner}, } ) @@ -219,6 +224,7 @@ type ShentuApp struct { CVMKeeper cvmkeeper.Keeper OracleKeeper oraclekeeper.Keeper ShieldKeeper shieldkeeper.Keeper + BountyKeeper bountykeeper.Keeper // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper @@ -268,6 +274,7 @@ func NewShentuApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest ibctransfertypes.StoreKey, icahosttypes.StoreKey, capabilitytypes.StoreKey, + bountytypes.StoreKey, } keys := sdk.NewKVStoreKeys(ks...) @@ -397,6 +404,13 @@ func NewShentuApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest &app.GovKeeper, app.GetSubspace(shieldtypes.ModuleName), ) + app.BountyKeeper = bountykeeper.NewKeeper( + appCodec, + keys[bountytypes.StoreKey], + app.CertKeeper, + app.GetSubspace(bountytypes.ModuleName), + ) + app.MintKeeper = mintkeeper.NewKeeper( appCodec, keys[sdkminttypes.StoreKey], app.GetSubspace(sdkminttypes.ModuleName), &stakingKeeper, app.AccountKeeper, app.BankKeeper, app.DistrKeeper, app.ShieldKeeper, authtypes.FeeCollectorName, @@ -504,6 +518,7 @@ func NewShentuApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest params.NewAppModule(app.ParamsKeeper), transferModule, icaModule, + bounty.NewAppModule(app.BountyKeeper), ) // NOTE: During BeginBlocker, slashing comes after distr so that @@ -513,7 +528,7 @@ func NewShentuApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest slashingtypes.ModuleName, evidencetypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName, ibctransfertypes.ModuleName, icatypes.ModuleName, authtypes.ModuleName, sdkbanktypes.ModuleName, sdkgovtypes.ModuleName, genutiltypes.ModuleName, sdkauthz.ModuleName, sdkfeegrant.ModuleName, crisistypes.ModuleName, shieldtypes.ModuleName, certtypes.ModuleName, - oracletypes.ModuleName, cvmtypes.ModuleName, paramstypes.ModuleName, + oracletypes.ModuleName, cvmtypes.ModuleName, paramstypes.ModuleName, bountytypes.ModuleName, ) // NOTE: Shield endblocker comes before staking because it queries @@ -522,7 +537,7 @@ func NewShentuApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest capabilitytypes.ModuleName, authtypes.ModuleName, sdkbanktypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName, sdkminttypes.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, sdkauthz.ModuleName, sdkfeegrant.ModuleName, paramstypes.ModuleName, upgradetypes.ModuleName, ibchost.ModuleName, ibctransfertypes.ModuleName, icatypes.ModuleName, - certtypes.ModuleName, oracletypes.ModuleName, cvmtypes.ModuleName, + certtypes.ModuleName, oracletypes.ModuleName, cvmtypes.ModuleName, bountytypes.ModuleName, ) // NOTE: genutil moodule must occur after staking so that pools @@ -550,6 +565,7 @@ func NewShentuApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest sdkfeegrant.ModuleName, paramstypes.ModuleName, upgradetypes.ModuleName, + bountytypes.ModuleName, ) app.mm.SetOrderExportGenesis( @@ -575,6 +591,7 @@ func NewShentuApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest evidencetypes.ModuleName, paramstypes.ModuleName, upgradetypes.ModuleName, + bountytypes.ModuleName, ) app.mm.RegisterInvariants(&app.CrisisKeeper) @@ -602,6 +619,7 @@ func NewShentuApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest shield.NewAppModule(app.ShieldKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), ibc.NewAppModule(app.IBCKeeper), transferModule, + bounty.NewAppModule(app.BountyKeeper), ) app.sm.RegisterStoreDecoders() diff --git a/go.mod b/go.mod index 987aaa963..2bb8aa0a9 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.3 github.com/golangci/golangci-lint v1.50.1 + github.com/google/uuid v1.3.0 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/hyperledger/burrow v0.31.0 diff --git a/go.sum b/go.sum index d3456e5c6..1db4322fc 100644 --- a/go.sum +++ b/go.sum @@ -544,6 +544,8 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= diff --git a/proto/shentu/bounty/v1/bounty.proto b/proto/shentu/bounty/v1/bounty.proto new file mode 100644 index 000000000..ad619a464 --- /dev/null +++ b/proto/shentu/bounty/v1/bounty.proto @@ -0,0 +1,136 @@ +syntax = "proto3"; +package shentu.bounty.v1; + +import "gogoproto/gogo.proto"; +import "google/protobuf/timestamp.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos_proto/cosmos.proto"; +import "google/protobuf/any.proto"; + +option go_package = "github.com/shentufoundation/shentu/x/bounty/types"; + +message Program { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string program_id = 1 [(gogoproto.moretags) = "yaml:\"program_id\""]; + string name = 2 [(gogoproto.moretags) = "yaml:\"name\""]; + // JSON by ProgramDetail + string detail = 3 [(gogoproto.moretags) = "yaml:\"detail\""]; + string admin_address = 4 [(gogoproto.moretags) = "yaml:\"admin_address\""]; + ProgramStatus status = 5 [(gogoproto.moretags) = "yaml:\"status\""]; + google.protobuf.Timestamp create_time = 6 + [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"create_time\""]; +} + +message Finding { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string program_id = 1 [(gogoproto.moretags) = "yaml:\"program_id\""]; + string finding_id = 2 [(gogoproto.moretags) = "yaml:\"finding_id\""]; + string title = 3; + string description = 4 [(gogoproto.moretags) = "yaml:\"description\""]; + string proof_of_concept = 5 [(gogoproto.moretags) = "yaml:\"proof_of_concept\""]; + // hash(description + proof_of_concept + submitter) + string finding_hash = 6 [(gogoproto.moretags) = "yaml:\"finding_hash\""]; + string submitter_address = 7 [(gogoproto.moretags) = "yaml:\"submitter_address\""]; + SeverityLevel severity_level = 8 [(gogoproto.moretags) = "yaml:\"severity_level\""]; + FindingStatus status = 9 [(gogoproto.moretags) = "yaml:\"status\""]; + // JSON by FindingDetail + string detail = 10 [(gogoproto.moretags) = "yaml:\"detail\""]; + string payment_hash = 11 [(gogoproto.moretags) = "yaml:\"payment_hash\""]; + google.protobuf.Timestamp create_time = 12 + [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"create_time\""]; +} + +message ProgramFingerprint { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string program_id = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "yaml:\"id\""]; + string name = 2 [(gogoproto.moretags) = "yaml:\"name\""]; + // JSON by ProgramDetail + string detail = 3 [(gogoproto.moretags) = "yaml:\"detail\""]; + string admin_address = 4 [(gogoproto.moretags) = "yaml:\"admin_address\""]; + ProgramStatus status = 5 [(gogoproto.moretags) = "yaml:\"status\""]; +} + +message FindingFingerprint { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string program_id = 1 [(gogoproto.moretags) = "yaml:\"program_id\""]; + string finding_id = 2 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "yaml:\"id\""]; + string title = 3; + // hash(description + proof_of_concept + submitter) + string finding_hash = 4 [(gogoproto.moretags) = "yaml:\"finding_hash\""]; + SeverityLevel severity_level = 5 [(gogoproto.moretags) = "yaml:\"severity_level\""]; + FindingStatus status = 6 [(gogoproto.moretags) = "yaml:\"status\""]; + // JSON by FindingDetail + string detail = 7 [(gogoproto.moretags) = "yaml:\"detail\""]; + string payment_hash = 8 [(gogoproto.moretags) = "yaml:\"payment_hash\""]; +} + +enum ProgramStatus { + option (gogoproto.goproto_enum_prefix) = false; + + PROGRAM_STATUS_INACTIVE = 0 [(gogoproto.enumvalue_customname) = "ProgramStatusInactive"]; + PROGRAM_STATUS_ACTIVE = 1 [(gogoproto.enumvalue_customname) = "ProgramStatusActive"]; + PROGRAM_STATUS_CLOSED = 2 [(gogoproto.enumvalue_customname) = "ProgramStatusClosed"]; +} + +enum SeverityLevel { + option (gogoproto.goproto_enum_prefix) = false; + + SEVERITY_LEVEL_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "Unspecified"]; + SEVERITY_LEVEL_CRITICAL = 1 [(gogoproto.enumvalue_customname) = "Critical"]; + SEVERITY_LEVEL_HIGH = 2 [(gogoproto.enumvalue_customname) = "High"]; + SEVERITY_LEVEL_MEDIUM = 3 [(gogoproto.enumvalue_customname) = "Medium"]; + SEVERITY_LEVEL_LOW = 4 [(gogoproto.enumvalue_customname) = "Low"]; + SEVERITY_LEVEL_INFORMATIONAL = 5 [(gogoproto.enumvalue_customname) = "Informational"]; +} + +enum FindingStatus { + option (gogoproto.goproto_enum_prefix) = false; + + FINDING_STATUS_SUBMITTED = 0 [(gogoproto.enumvalue_customname) = "FindingStatusSubmitted"]; + FINDING_STATUS_ACTIVE = 1 [(gogoproto.enumvalue_customname) = "FindingStatusActive"]; + FINDING_STATUS_CONFIRMED = 2 [(gogoproto.enumvalue_customname) = "FindingStatusConfirmed"]; + FINDING_STATUS_PAID = 3 [(gogoproto.enumvalue_customname) = "FindingStatusPaid"]; + FINDING_STATUS_CLOSED = 4 [(gogoproto.enumvalue_customname) = "FindingStatusClosed"]; +} + +//message BountyLevel { +// option (gogoproto.equal) = false; +// option (gogoproto.goproto_getters) = false; +// +// SeverityLevel severity_level = 1 [(gogoproto.moretags) = "yaml:\"severity_level\""]; +// bool poc = 2; +// cosmos.base.v1beta1.Coin min_bounty = 3 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"min_bounty\""]; +// cosmos.base.v1beta1.Coin max_bounty = 4 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"max_bounty\""]; +//} + +//// ProgramDetail defines a program detail. +//type ProgramDetail struct { +// Type string `json:"type"` +// Logo string `json:"logo"` +// Desc string `json:"desc"` +// Targets []string `json:"targets"` +// ScopeRules string `json:"scope_rules"` +// KnownIssues string `json:"known_issues"` +// TotalBounty int `json:"total_bounty"` +// BountyLevels []BountyLevel `json:"bounty_levels"` +// PaymentInfo string `json:"payment_info"` +// PaymentChain string `json:"payment_chain"` +// ProgramSLA []SLAItem `json:"sla"` +//} + +//// FindingDetail defines a finding detail. +//type FindingDetail struct{ +// ProgramTarget []string `json:"program_target"` +// Impacts []string `json:"impacts"` +// Attachments []string `json:"attachments"` +// ReceiverInfo ReceiverInfo `json:"receiver_info"` +// PaidInfo PaidInfo `json:"paid_info"` +//} \ No newline at end of file diff --git a/proto/shentu/bounty/v1/genesis.proto b/proto/shentu/bounty/v1/genesis.proto new file mode 100644 index 000000000..fcfdf1f78 --- /dev/null +++ b/proto/shentu/bounty/v1/genesis.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; +package shentu.bounty.v1; + +import "gogoproto/gogo.proto"; + +import "shentu/bounty/v1/bounty.proto"; + +option go_package = "github.com/shentufoundation/shentu/x/bounty/types"; + +message GenesisState { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + repeated Program programs = 1 [(gogoproto.moretags) = "yaml:\"programs\"", (gogoproto.nullable) = false]; + repeated Finding findings = 2 [(gogoproto.moretags) = "yaml:\"findings\"", (gogoproto.nullable) = false]; +} diff --git a/proto/shentu/bounty/v1/query.proto b/proto/shentu/bounty/v1/query.proto new file mode 100644 index 000000000..d06db5665 --- /dev/null +++ b/proto/shentu/bounty/v1/query.proto @@ -0,0 +1,137 @@ +syntax = "proto3"; +package shentu.bounty.v1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; + +import "cosmos/base/query/v1beta1/pagination.proto"; + +import "shentu/bounty/v1/bounty.proto"; + +option go_package = "github.com/shentufoundation/shentu/x/bounty/types"; + +// Query defines the gRPC querier service for bounty module +service Query { + // Programs queries all programs based on given status. + rpc Programs(QueryProgramsRequest) returns (QueryProgramsResponse) { + option (google.api.http).get = "/shentu/bounty/v1/programs"; + } + + // Program queries program details based on ProgramId. + rpc Program(QueryProgramRequest) returns (QueryProgramResponse) { + option (google.api.http).get = "/shentu/bounty/v1/programs/{program_id}"; + } + + // Findings queries findings of a given program. + rpc Findings(QueryFindingsRequest) returns (QueryFindingsResponse) { + option (google.api.http).get = "/shentu/bounty/v1/findings"; + } + + // Finding queries Finding information based on programID, FindingId. + rpc Finding(QueryFindingRequest) returns (QueryFindingResponse) { + option (google.api.http).get = "/shentu/bounty/v1/findings/{finding_id}"; + } + + // FindingFingerprint queries finding fingerprint based on findingId. + rpc FindingFingerprint(QueryFindingFingerprintRequest) returns (QueryFindingFingerprintResponse) { + option (google.api.http).get = "/shentu/bounty/v1/findings/{finding_id}/fingerprint"; + } + + // ProgramFingerprint queries program fingerprint based on programId. + rpc ProgramFingerprint(QueryProgramFingerprintRequest) returns (QueryProgramFingerprintResponse) { + option (google.api.http).get = "/shentu/bounty/v1/programs/{program_id}/fingerprint"; + } +} + +// QueryHostsRequest is the request type for the Query/Hosts RPC method. +message QueryHostsRequest {} + +// QueryHostsResponse is the response type for the Query/Hosts RPC method. +message QueryHostsResponse {} + +// QueryHostRequest is the request type for the Query/Host RPC method. +message QueryHostRequest { + // host_addr defines the host address to query for. + string host_addr = 1; +} + +// QueryHostResponse is the response type for the Query/Host RPC method. +message QueryHostResponse {} + +// QueryProgramsRequest is the request type for the Query/Programs RPC method. +message QueryProgramsRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +// QueryProgramsResponse is the response type for the Query/Programs RPC method. +message QueryProgramsResponse { + repeated Program programs = 1 [(gogoproto.nullable) = false]; + + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryProgramRequest is the request type for the Query/Program RPC method. +message QueryProgramRequest { + // program_id defines the unique id of the bounty program. + string program_id = 1; +} + +// QueryProgramResponse is the response type for the Query/Program RPC method. +message QueryProgramResponse { + Program program = 1 [(gogoproto.nullable) = false]; +} + +// QueryFindingRequests is the request type for the Query/Findings RPC method. +message QueryFindingsRequest { + // program_id defines the unique id of the program. + string program_id = 1; + + // submitter_address defines the find address for the finding. + string submitter_address = 2; + + // pagination defines the pagination in the request. + cosmos.base.query.v1beta1.PageRequest pagination = 3; +} + +// QueryFindingsResponse is the response type for the Query/Findings RPC method. +message QueryFindingsResponse { + repeated Finding findings = 1 [(gogoproto.nullable) = false]; + + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryFindingRequest is the request type for the Query/Finding RPC method. +message QueryFindingRequest { + // finding_id defines the unique id of the finding. + string finding_id = 1; +} + +// QueryFindingResponse is the response type for the Query/Finding RPC method. +message QueryFindingResponse { + Finding finding = 1 [(gogoproto.nullable) = false]; +} + +// QueryFindingFingerPrint is the request type for the Query/Finding RPC method. +message QueryFindingFingerprintRequest { + // finding_id defines the unique id of the finding. + string finding_id = 1; +} + +// QueryFindingFingerPrintResponse is the response type for the Query/Finding RPC method. +message QueryFindingFingerprintResponse { + string fingerprint = 1; +} + +// QueryProgramFingerprintRequest is the request type for the Query/Finding RPC method. +message QueryProgramFingerprintRequest { + // program_id defines the unique id of the finding. + string program_id = 1; +} + +// QueryProgramFingerprintResponse is the response type for the Query/Finding RPC method. +message QueryProgramFingerprintResponse { + string fingerprint = 1; +} \ No newline at end of file diff --git a/proto/shentu/bounty/v1/tx.proto b/proto/shentu/bounty/v1/tx.proto new file mode 100644 index 000000000..828a1bc32 --- /dev/null +++ b/proto/shentu/bounty/v1/tx.proto @@ -0,0 +1,193 @@ +syntax = "proto3"; +package shentu.bounty.v1; + +import "gogoproto/gogo.proto"; +import "google/protobuf/timestamp.proto"; +import "cosmos_proto/cosmos.proto"; +import "google/protobuf/any.proto"; + +import "cosmos/base/v1beta1/coin.proto"; +import "shentu/bounty/v1/bounty.proto"; + +option go_package = "github.com/shentufoundation/shentu/x/bounty/types"; + +// Msg defines the staking Msg service. +service Msg { + // CreateProgram defines a method for creating a new program. + rpc CreateProgram(MsgCreateProgram) returns (MsgCreateProgramResponse); + + // EditProgram defines a method for modifying a program. + rpc EditProgram(MsgEditProgram) returns (MsgEditProgramResponse); + + // Activate a program status by program_id + rpc ActivateProgram(MsgActivateProgram) returns (MsgActivateProgramResponse); + + // Closed a program status by program_id + rpc CloseProgram(MsgCloseProgram) returns (MsgCloseProgramResponse); + + // SubmitFinding defines a method for submitting a new finding. + rpc SubmitFinding(MsgSubmitFinding) returns (MsgSubmitFindingResponse); + + // EditFinding defines a method for editing a new finding. + rpc EditFinding(MsgEditFinding) returns (MsgEditFindingResponse); + + // ActivateFinding defines a method for activate a new finding. + rpc ActivateFinding(MsgActivateFinding) returns (MsgActivateFindingResponse); + + // ConfirmFinding defines a method for host confirm a finding. + rpc ConfirmFinding(MsgConfirmFinding) returns (MsgConfirmFindingResponse); + + // ConfirmFindingPaid defines a method for submitter confirm a finding paid + rpc ConfirmFindingPaid(MsgConfirmFindingPaid) returns (MsgConfirmFindingPaidResponse); + + // CloseFinding defines a method for submitter or certifier close a finding + rpc CloseFinding(MsgCloseFinding) returns (MsgCloseFindingResponse); + + // PublishFinding defines a method for publish a finding. + rpc PublishFinding(MsgPublishFinding) returns (MsgPublishFindingResponse); +} + +// MsgCreateProgram defines a SDK message for creating a new program. +message MsgCreateProgram { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string program_id = 1 [(gogoproto.moretags) = "yaml:\"program_id\""]; + string name = 2; + string detail = 3; + string operator_address = 4 [(gogoproto.moretags) = "yaml:\"operator_address\""]; +} + +// MsgEditProgram defines a SDK message for editing a program. +message MsgEditProgram { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string program_id = 1 [(gogoproto.moretags) = "yaml:\"program_id\""]; + string name = 2; + string detail = 3; + string operator_address = 4 [(gogoproto.moretags) = "yaml:\"operator_address\""]; +} + +// MsgCreateProgramResponse defines the Msg/CreateProgram response type. +message MsgCreateProgramResponse { +} + +// MsgModifyProgramResponse defines the Msg/ModifyProgram response type. +message MsgEditProgramResponse {} + +message MsgActivateProgram { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string program_id = 1 [(gogoproto.moretags) = "yaml:\"program_id\""]; + string operator_address = 2 [(gogoproto.moretags) = "yaml:\"operator_address\""]; +} + +message MsgActivateProgramResponse {} + +message MsgCloseProgram { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string program_id = 1 [(gogoproto.moretags) = "yaml:\"program_id\""]; + string operator_address = 2 [(gogoproto.moretags) = "yaml:\"operator_address\""]; +} + +message MsgCloseProgramResponse {} + +// MsgSubmitFinding defines a message to submit a finding. +message MsgSubmitFinding { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string program_id = 1 [(gogoproto.moretags) = "yaml:\"program_id\""]; + string finding_id = 2 [(gogoproto.moretags) = "yaml:\"finding_id\""]; + string title = 3; + string finding_hash = 4 [(gogoproto.moretags) = "yaml:\"finding_hash\""]; + string operator_address = 5 [(gogoproto.moretags) = "yaml:\"operator_address\""]; + SeverityLevel severity_level = 6 [(gogoproto.moretags) = "yaml:\"severity_level\""]; + string detail = 7; +} + +// MsgSubmitFindingResponse defines the MsgSubmitFinding response type. +message MsgSubmitFindingResponse {} + +// MsgEditFinding defines a message to edit a finding. +message MsgEditFinding { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string finding_id = 1 [(gogoproto.moretags) = "yaml:\"finding_id\""]; + string title = 2; + string finding_hash = 3 [(gogoproto.moretags) = "yaml:\"finding_hash\""]; + string operator_address = 4 [(gogoproto.moretags) = "yaml:\"operator_address\""]; + SeverityLevel severity_level = 5 [(gogoproto.moretags) = "yaml:\"severity_level\""]; + string detail = 6; + string payment_hash = 7 [(gogoproto.moretags) = "yaml:\"payment_hash\""]; +} + +// MsgEditFindingResponse defines the MsgEditFinding response type. +message MsgEditFindingResponse {} + +// MsgConfirmFinding defines a message to confirm a finding to an existing finding. +message MsgConfirmFinding { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string finding_id = 1 [(gogoproto.moretags) = "yaml:\"finding_id\""]; + string operator_address = 2 [(gogoproto.moretags) = "yaml:\"operator_address\""]; + string fingerprint = 3; +} + +// MsgConfirmFindingResponse defines the Msg/AcceptFinding response type. +message MsgConfirmFindingResponse {} + +// MsgActivateFinding defines a message to activate a finding to an existing finding. +message MsgActivateFinding { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string finding_id = 1 [(gogoproto.moretags) = "yaml:\"finding_id\""]; + string operator_address = 2 [(gogoproto.moretags) = "yaml:\"operator_address\""]; +} + +// MsgActivateFindingResponse defines the Msg/AcceptFinding response type. +message MsgActivateFindingResponse {} + +// MsgConfirmFindingPaid defines a message to close a finding to an existing finding. +message MsgConfirmFindingPaid { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string finding_id = 1 [(gogoproto.moretags) = "yaml:\"finding_id\""]; + string operator_address = 2 [(gogoproto.moretags) = "yaml:\"operator_address\""]; +} + +// MsgCloseFindingResponse defines the Msg/CloseFinding response type. +message MsgConfirmFindingPaidResponse {} + +// MsgCloseFinding defines a message to close a finding to an existing finding. +message MsgCloseFinding { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string finding_id = 1 [(gogoproto.moretags) = "yaml:\"finding_id\""]; + string operator_address = 2 [(gogoproto.moretags) = "yaml:\"operator_address\""]; +} + +// MsgCloseFindingResponse defines the Msg/CloseFinding response type. +message MsgCloseFindingResponse {} + +// MsgPublishFinding defines a message to publish a finding. +message MsgPublishFinding { + option (gogoproto.equal) = false; + + string finding_id = 1 [(gogoproto.moretags) = "yaml:\"finding_id\""]; + string description = 2 [(gogoproto.moretags) = "yaml:\"description\""]; + string proof_of_concept = 3 [(gogoproto.moretags) = "yaml:\"proof_of_concept\""]; + string operator_address = 4 [(gogoproto.moretags) = "yaml:\"operator_address\""]; +} + +// MsgPublishFindingResponse defines the MsgPublishFinding response type. +message MsgPublishFindingResponse {} \ No newline at end of file diff --git a/proto/shentu/cert/v1alpha1/cert.proto b/proto/shentu/cert/v1alpha1/cert.proto index 1221d9984..69c9b2aa2 100644 --- a/proto/shentu/cert/v1alpha1/cert.proto +++ b/proto/shentu/cert/v1alpha1/cert.proto @@ -29,6 +29,7 @@ enum CertificateType { CERT_TYPE_SHIELD_POOL_CREATOR = 5 [(gogoproto.enumvalue_customname) = "CertificateTypeShieldPoolCreator"]; CERT_TYPE_IDENTITY = 6 [(gogoproto.enumvalue_customname) = "CertificateTypeIdentity"]; CERT_TYPE_GENERAL = 7 [(gogoproto.enumvalue_customname) = "CertificateTypeGeneral"]; + CERT_TYPE_BOUNTY_ADMIN = 8 [(gogoproto.enumvalue_customname) = "CertificateTypeBountyAdmin"]; } message CompilationContent { @@ -101,6 +102,12 @@ message General { string content = 1; } +message BountyAdmin { + option (cosmos_proto.implements_interface) = "Content"; + + string content = 1; +} + // Platform is a genesis type for certified platform of a validator message Platform { option (gogoproto.equal) = false; diff --git a/tests/e2e/e2e_bounty_test.go b/tests/e2e/e2e_bounty_test.go new file mode 100644 index 000000000..033eef72a --- /dev/null +++ b/tests/e2e/e2e_bounty_test.go @@ -0,0 +1,242 @@ +package e2e + +import ( + "context" + "fmt" + "strings" + "time" + + sdkflags "github.com/cosmos/cosmos-sdk/client/flags" + + bountycli "github.com/shentufoundation/shentu/v2/x/bounty/client/cli" + bountytypes "github.com/shentufoundation/shentu/v2/x/bounty/types" +) + +func (s *IntegrationTestSuite) executeCreateProgram(c *chain, valIdx int, pid, name, detail, creatorAddr, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu bounty create program %s on %s", pid, c.id) + + command := []string{ + shentuBinary, + txCommand, + bountytypes.ModuleName, + "create-program", + fmt.Sprintf("--%s=%s", bountycli.FlagProgramID, pid), + fmt.Sprintf("--%s=%s", bountycli.FlagName, name), + fmt.Sprintf("--%s=%s", bountycli.FlagDetail, detail), + fmt.Sprintf("--%s=%s", sdkflags.FlagFrom, creatorAddr), + fmt.Sprintf("--%s=%s", sdkflags.FlagChainID, c.id), + fmt.Sprintf("--%s=%s", sdkflags.FlagGas, "auto"), + fmt.Sprintf("--%s=%s", sdkflags.FlagFees, fees), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully create program", creatorAddr) +} + +func (s *IntegrationTestSuite) executeActivateProgram(c *chain, valIdx int, pid, operatorAddr, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu bounty create program %s on %s", pid, c.id) + + command := []string{ + shentuBinary, + txCommand, + bountytypes.ModuleName, + "activate-program", + fmt.Sprintf("%s", pid), + fmt.Sprintf("--%s=%s", sdkflags.FlagFrom, operatorAddr), + fmt.Sprintf("--%s=%s", sdkflags.FlagChainID, c.id), + fmt.Sprintf("--%s=%s", sdkflags.FlagGas, "auto"), + fmt.Sprintf("--%s=%s", sdkflags.FlagFees, fees), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully create program", operatorAddr) +} + +func (s *IntegrationTestSuite) executeSubmitFinding(c *chain, valIdx int, pid, fid, submitAddr, title, desc, poc, detail, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu bounty submit finding on %s", c.id) + + command := []string{ + shentuBinary, + txCommand, + bountytypes.ModuleName, + "submit-finding", + fmt.Sprintf("--%s=%s", bountycli.FlagProgramID, pid), + fmt.Sprintf("--%s=%s", bountycli.FlagFindingID, fid), + fmt.Sprintf("--%s=%s", bountycli.FlagFindingTitle, title), + fmt.Sprintf("--%s=%s", bountycli.FlagFindingDescription, desc), + fmt.Sprintf("--%s=%s", bountycli.FlagFindingProofOfContent, poc), + fmt.Sprintf("--%s=%s", bountycli.FlagDetail, detail), + fmt.Sprintf("--%s=%s", bountycli.FlagFindingSeverityLevel, bountytypes.Low.String()), + fmt.Sprintf("--%s=%s", sdkflags.FlagFrom, submitAddr), + fmt.Sprintf("--%s=%s", sdkflags.FlagChainID, c.id), + fmt.Sprintf("--%s=%s", sdkflags.FlagGas, "auto"), + fmt.Sprintf("--%s=%s", sdkflags.FlagFees, fees), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully submit finding", submitAddr) +} + +func (s *IntegrationTestSuite) executeConfirmFinding(c *chain, valIdx int, findingId, hostAddr, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu bounty acctpe finding on %s", c.id) + + command := []string{ + shentuBinary, + txCommand, + bountytypes.ModuleName, + "confirm-finding", + fmt.Sprintf("%s", findingId), + fmt.Sprintf("--%s=%s", sdkflags.FlagFrom, hostAddr), + fmt.Sprintf("--%s=%s", sdkflags.FlagChainID, c.id), + fmt.Sprintf("--%s=%s", sdkflags.FlagGas, "auto"), + fmt.Sprintf("--%s=%s", sdkflags.FlagFees, fees), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully accept finding", hostAddr) +} + +func (s *IntegrationTestSuite) executeCloseFinding(c *chain, valIdx int, findingId, hostAddr, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu bounty reject finding on %s", c.id) + + command := []string{ + shentuBinary, + txCommand, + bountytypes.ModuleName, + "close-finding", + fmt.Sprintf("%s", findingId), + fmt.Sprintf("--%s=%s", sdkflags.FlagFrom, hostAddr), + fmt.Sprintf("--%s=%s", sdkflags.FlagChainID, c.id), + fmt.Sprintf("--%s=%s", sdkflags.FlagGas, "auto"), + fmt.Sprintf("--%s=%s", sdkflags.FlagFees, fees), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully reject finding", hostAddr) +} + +//func (s *IntegrationTestSuite) executeReleaseFinding(c *chain, valIdx, findingId int, hostAddr, keyFile, fees string) { +// ctx, cancel := context.WithTimeout(context.Background(), time.Minute) +// defer cancel() +// +// s.T().Logf("Executing shentu bounty release finding on %s", c.id) +// +// command := []string{ +// shentuBinary, +// txCommand, +// bountytypes.ModuleName, +// "release-finding", +// fmt.Sprintf("%d", findingId), +// fmt.Sprintf("--%s=%s", bountycli.FlagEncKeyFile, keyFile), +// fmt.Sprintf("--%s=%s", sdkflags.FlagFrom, hostAddr), +// fmt.Sprintf("--%s=%s", sdkflags.FlagChainID, c.id), +// fmt.Sprintf("--%s=%s", sdkflags.FlagGas, "auto"), +// fmt.Sprintf("--%s=%s", sdkflags.FlagFees, fees), +// "--keyring-backend=test", +// "--output=json", +// "-y", +// } +// +// s.T().Logf("cmd: %s", strings.Join(command, " ")) +// +// s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) +// s.T().Logf("%s successfully release finding", hostAddr) +//} + +func (s *IntegrationTestSuite) executeEndProgram(c *chain, valIdx int, programId, hostAddr, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu bounty close program on %s", c.id) + + command := []string{ + shentuBinary, + txCommand, + bountytypes.ModuleName, + "close-program", + fmt.Sprintf("%s", programId), + fmt.Sprintf("--%s=%s", sdkflags.FlagFrom, hostAddr), + fmt.Sprintf("--%s=%s", sdkflags.FlagChainID, c.id), + fmt.Sprintf("--%s=%s", sdkflags.FlagGas, "auto"), + fmt.Sprintf("--%s=%s", sdkflags.FlagFees, fees), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully end program", hostAddr) +} + +func queryBountyProgram(endpoint, programID string) (*bountytypes.QueryProgramResponse, error) { + grpcReq := &bountytypes.QueryProgramRequest{ + ProgramId: programID, + } + conn, err := connectGrpc(endpoint) + defer conn.Close() + client := bountytypes.NewQueryClient(conn) + + grpcRsp, err := client.Program(context.Background(), grpcReq) + if err != nil { + return nil, fmt.Errorf("failed to execute request: %w", err) + } + + return grpcRsp, nil +} + +func queryBountyFinding(endpoint, findingID string) (*bountytypes.QueryFindingResponse, error) { + grpcReq := &bountytypes.QueryFindingRequest{ + FindingId: findingID, + } + conn, err := connectGrpc(endpoint) + defer conn.Close() + client := bountytypes.NewQueryClient(conn) + + grpcRsp, err := client.Finding(context.Background(), grpcReq) + if err != nil { + return nil, fmt.Errorf("failed to execute request: %w", err) + } + + return grpcRsp, nil +} diff --git a/tests/e2e/e2e_cert_test.go b/tests/e2e/e2e_cert_test.go new file mode 100644 index 000000000..9b049c832 --- /dev/null +++ b/tests/e2e/e2e_cert_test.go @@ -0,0 +1,54 @@ +package e2e + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/cosmos/cosmos-sdk/client/flags" + certtypes "github.com/shentufoundation/shentu/v2/x/cert/types" +) + +func (s *IntegrationTestSuite) executeIssueCertificate(c *chain, valIdx int, certificateType, content, certifierAddr, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu tx issue certificate %s", c.id) + + command := []string{ + shentuBinary, + txCommand, + certtypes.ModuleName, + "issue-certificate", + certificateType, + content, + fmt.Sprintf("--%s=%s", flags.FlagFrom, certifierAddr), + fmt.Sprintf("--%s=%s", flags.FlagGasPrices, fees), + fmt.Sprintf("--%s=%s", flags.FlagChainID, c.id), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully issue %s certificate to %s", certifierAddr, certificateType, content) +} + +func queryCertificate(endpoint string, certificateId int) (*certtypes.QueryCertificateResponse, error) { + grpcReq := &certtypes.QueryCertificateRequest{ + CertificateId: uint64(certificateId), + } + conn, err := connectGrpc(endpoint) + defer conn.Close() + client := certtypes.NewQueryClient(conn) + + grpcRsp, err := client.Certificate(context.Background(), grpcReq) + if err != nil { + return nil, fmt.Errorf("failed to execute request: %w", err) + } + + return grpcRsp, nil +} diff --git a/tests/e2e/e2e_gov_test.go b/tests/e2e/e2e_gov_test.go new file mode 100644 index 000000000..178c1b1d3 --- /dev/null +++ b/tests/e2e/e2e_gov_test.go @@ -0,0 +1,112 @@ +package e2e + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/cosmos/cosmos-sdk/client/flags" + sdkgovtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govtypes "github.com/shentufoundation/shentu/v2/x/gov/types" +) + +func (s *IntegrationTestSuite) executeSubmitUpgradeProposal(c *chain, valIdx, upgradeHeight int, submitterAddr, proposalName, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu tx submit proposal %s", c.id) + + command := []string{ + shentuBinary, + txCommand, + sdkgovtypes.ModuleName, + "submit-proposal", + "software-upgrade", + proposalName, + fmt.Sprintf("--upgrade-height=%d", upgradeHeight), + fmt.Sprintf("--title=\"title of %s\"", proposalName), + fmt.Sprintf("--description=\"description of %s\"", proposalName), + fmt.Sprintf("--%s=%s", flags.FlagFrom, submitterAddr), + fmt.Sprintf("--%s=%s", flags.FlagGasPrices, fees), + fmt.Sprintf("--%s=%s", flags.FlagChainID, c.id), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully submit %s proposal", submitterAddr, proposalName) +} + +func (s *IntegrationTestSuite) executeDepositProposal(c *chain, valIdx int, submitterAddr string, proposalId int, amount, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu tx deposit proposal %s", c.id) + + command := []string{ + shentuBinary, + txCommand, + sdkgovtypes.ModuleName, + "deposit", + fmt.Sprintf("%d", proposalId), + amount, + fmt.Sprintf("--%s=%s", flags.FlagFrom, submitterAddr), + fmt.Sprintf("--%s=%s", flags.FlagGasPrices, fees), + fmt.Sprintf("--%s=%s", flags.FlagChainID, c.id), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully deposit proposal %d %s", submitterAddr, proposalId, amount) +} + +func (s *IntegrationTestSuite) executeVoteProposal(c *chain, valIdx int, submitterAddr string, proposalId int, vote, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu tx vote proposal %s", c.id) + + command := []string{ + shentuBinary, + txCommand, + sdkgovtypes.ModuleName, + "vote", + fmt.Sprintf("%d", proposalId), + vote, + fmt.Sprintf("--%s=%s", flags.FlagFrom, submitterAddr), + fmt.Sprintf("--%s=%s", flags.FlagGasPrices, fees), + fmt.Sprintf("--%s=%s", flags.FlagChainID, c.id), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully vote proposal %d %s", submitterAddr, proposalId, vote) +} + +func queryProposal(endpoint string, proposalID int) (*sdkgovtypes.QueryProposalResponse, error) { + grpcReq := &sdkgovtypes.QueryProposalRequest{ + ProposalId: uint64(proposalID), + } + conn, err := connectGrpc(endpoint) + defer conn.Close() + client := govtypes.NewQueryClient(conn) + + grpcRsp, err := client.Proposal(context.Background(), grpcReq) + if err != nil { + return nil, fmt.Errorf("failed to execute request: %w", err) + } + + return grpcRsp, nil +} diff --git a/tests/e2e/e2e_setup_test.go b/tests/e2e/e2e_setup_test.go index 0f45c4eb2..6815277dd 100644 --- a/tests/e2e/e2e_setup_test.go +++ b/tests/e2e/e2e_setup_test.go @@ -66,6 +66,8 @@ var ( certificateCounter = 0 shieldPoolCounter = 0 shieldPurchaseCounter = 0 + bountyProgramCounter = 0 + bountyFindingCounter = 0 ) type IntegrationTestSuite struct { diff --git a/tests/e2e/e2e_shield_test.go b/tests/e2e/e2e_shield_test.go new file mode 100644 index 000000000..9b53f65aa --- /dev/null +++ b/tests/e2e/e2e_shield_test.go @@ -0,0 +1,232 @@ +package e2e + +import ( + "context" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "time" + + "github.com/cosmos/cosmos-sdk/client/flags" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + shieldtypes "github.com/shentufoundation/shentu/v2/x/shield/types" +) + +func (s *IntegrationTestSuite) executeDepositCollateral(c *chain, valIdx int, submitterAddr, amount, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu tx shield deposit collateral %s", c.id) + + command := []string{ + shentuBinary, + txCommand, + shieldtypes.ModuleName, + "deposit-collateral", + amount, + fmt.Sprintf("--%s=%s", flags.FlagFrom, submitterAddr), + fmt.Sprintf("--%s=%s", flags.FlagChainID, c.id), + fmt.Sprintf("--%s=%s", flags.FlagGas, "auto"), + fmt.Sprintf("--%s=%s", flags.FlagFees, fees), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully deposit %s", submitterAddr, amount) +} + +func (s *IntegrationTestSuite) executeCreatePool(c *chain, valIdx int, poolAmount, poolName, sponsorAddr, shieldLimit, submitterAddr, nativeAmount, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu tx shield create pool %s", c.id) + + command := []string{ + shentuBinary, + txCommand, + shieldtypes.ModuleName, + "create-pool", + poolAmount, + poolName, + sponsorAddr, + fmt.Sprintf("--%s=%s", "shield-limit", shieldLimit), + fmt.Sprintf("--%s=%s", "native-deposit", nativeAmount), + fmt.Sprintf("--%s=%s", flags.FlagFrom, submitterAddr), + fmt.Sprintf("--%s=%s", flags.FlagChainID, c.id), + fmt.Sprintf("--%s=%s", flags.FlagGas, "auto"), + fmt.Sprintf("--%s=%s", flags.FlagFees, fees), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully create pool %s", submitterAddr, poolName) +} + +func (s *IntegrationTestSuite) executePurchaseShield(c *chain, valIdx, poolId int, shieldAmount, description, submitterAddr, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu tx shield purchase %s", c.id) + + command := []string{ + shentuBinary, + txCommand, + shieldtypes.ModuleName, + "purchase", + fmt.Sprintf("%d", poolId), + shieldAmount, + description, + fmt.Sprintf("--%s=%s", flags.FlagFrom, submitterAddr), + fmt.Sprintf("--%s=%s", flags.FlagChainID, c.id), + fmt.Sprintf("--%s=%s", flags.FlagGas, "auto"), + fmt.Sprintf("--%s=%s", flags.FlagFees, fees), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully purchase shield at pool %d", submitterAddr, poolId) +} + +func (s *IntegrationTestSuite) executeSubmitClaimProposal(c *chain, valIdx int, proposalFile, submitterAddr, fees string) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("Executing shentu tx submit proposal %s", c.id) + + command := []string{ + shentuBinary, + txCommand, + govtypes.ModuleName, + "submit-proposal", + "shield-claim", + proposalFile, + fmt.Sprintf("--%s=%s", flags.FlagFrom, submitterAddr), + fmt.Sprintf("--%s=%s", flags.FlagGas, "auto"), + fmt.Sprintf("--%s=%s", flags.FlagFees, fees), + fmt.Sprintf("--%s=%s", flags.FlagChainID, c.id), + "--keyring-backend=test", + "--output=json", + "-y", + } + + s.T().Logf("cmd: %s", strings.Join(command, " ")) + + s.execShentuTxCmd(ctx, c, command, valIdx, s.defaultExecValidation(c, valIdx)) + s.T().Logf("%s successfully submit claim proposal %s", submitterAddr, proposalFile) +} + +func (s *IntegrationTestSuite) writeClaimProposal(c *chain, valIdx, poolId, purchaseId int, fileName string) string { + type ClaimLoss struct { + Denom string `json:"denom"` + Amount string `json:"amount"` + } + type ClaimProposal struct { + PoolId int `json:"pool_id"` + PurchaseId int `json:"purchase_id"` + Evidence string `json:"evidence"` + Description string `json:"description"` + Loss sdk.Coins `json:"loss"` + Deposit sdk.Coins `json:"deposit"` + } + + loss := sdk.NewCoin(uctkDenom, sdk.NewInt(1000000)) + deposit := sdk.NewCoin(uctkDenom, sdk.NewInt(110000000)) + + var proposal = &ClaimProposal{ + PoolId: poolId, + PurchaseId: purchaseId, + Evidence: "Attack happened on