syntax = "proto3";
package band.oracle.v1;

option go_package = "github.com/bandprotocol/chain/v3/x/oracle/types";

import "gogoproto/gogo.proto";
import "google/protobuf/timestamp.proto";
import "cosmos/base/v1beta1/coin.proto";

// DataSource is the data structure for storing data sources in the storage.
message DataSource {
  option (gogoproto.equal) = true;
  // Owner is an address of the account who own the data source
  string owner = 1;
  // Name is data source name used for display
  string name = 2;
  // Description is data source description used for display
  string description = 3;
  // Filename is string of file name used as reference for locating
  // data source file stored in bandchain nodes
  string filename = 4;
  // Treasury is the account address who receive data source fee from requester.
  string treasury = 5;
  // Fee is the data source fee per ask_count that data provider will receive
  // from requester.
  repeated cosmos.base.v1beta1.Coin fee = 6
      [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
}

// OracleScript is the data structure for storing oracle scripts in the storage.
message OracleScript {
  option (gogoproto.equal) = true;
  // Owner is an address of the account who own the oracle script
  string owner = 1;
  // Name is oracle script name used for display
  string name = 2;
  // Description is oracle script description used for display
  string description = 3;
  // Filename is string of file name used as reference for locating
  // compiled oracle script WASM file stored in bandchain nodes
  string filename = 4;
  // Schema is the schema of the oracle script input/output
  // which is formatted in OBI format e.g.
  // "{symbol:string,multiplier:u64}/{px:u64}"
  string schema = 5;
  // SourceCodeURL is the URL of oracle script's source code.
  // It is recommendded to store source code on IPFS and get its URL to preserve
  // decentralization.
  string source_code_url = 6 [(gogoproto.customname) = "SourceCodeURL"];
}

// RawRequest is the data structure for storing raw requests in the storage.
message RawRequest {
  option (gogoproto.equal) = true;
  // ExternalID is an ID of the raw request
  uint64 external_id = 1 [(gogoproto.customname) = "ExternalID", (gogoproto.casttype) = "ExternalID"];
  // DataSourceID is an ID of data source script that relates to the raw request
  uint64 data_source_id = 2 [(gogoproto.customname) = "DataSourceID", (gogoproto.casttype) = "DataSourceID"];
  // Calldata is the data used as argument params for executing data source
  // script
  bytes calldata = 3;
}

// RawReport is the data structure for storing raw reporter in the storage.
message RawReport {
  option (gogoproto.equal) = true;
  // ExternalID is an ID of the raw request
  uint64 external_id = 1 [(gogoproto.customname) = "ExternalID", (gogoproto.casttype) = "ExternalID"];
  // ExitCode is status code provided by validators to specify error, if any.
  // Exit code is usually filled by the exit code returned from execution of
  // specified data source script. With code 0 means there is no error.
  uint32 exit_code = 2;
  // Data is raw result provided by validators.
  // It is usually filled by the result from execution of specified data source
  // script.
  bytes data = 3;
}

// Request is the data structure for storing requests in the storage.
message Request {
  option (gogoproto.equal) = true;
  // OracleScriptID is ID of an oracle script
  uint64 oracle_script_id = 1 [(gogoproto.customname) = "OracleScriptID", (gogoproto.casttype) = "OracleScriptID"];
  // Calldata is the data used as argument params for the oracle script
  bytes calldata = 2;
  // RequestedValidators is a list of validator addresses that are assigned for
  // fulfilling the request
  repeated string requested_validators = 3;
  // MinCount is minimum number of validators required for fulfilling the
  // request
  uint64 min_count = 4;
  // RequestHeight is block height that the request has been created
  int64 request_height = 5;
  // RequestTime is timestamp of the chain's block which contains the request
  int64 request_time = 6;
  // ClientID is arbitrary id provided by requester.
  // It is used by client-side for referencing the request
  string client_id = 7 [(gogoproto.customname) = "ClientID"];
  // RawRequests is a list of raw requests specified by execution of oracle
  // script
  repeated RawRequest raw_requests = 8 [(gogoproto.nullable) = false];
  // IBCChannel is an IBC channel info of the other chain, which contains a
  // channel and a port to allow bandchain connect to that chain. This field
  // allows other chain be able to request data from bandchain via IBC.
  IBCChannel ibc_channel = 9 [(gogoproto.customname) = "IBCChannel"];
  // ExecuteGas is amount of gas to reserve for executing
  uint64 execute_gas = 10;
  // TSSEncoder is the mode of encoding oracle result signature order.
  Encoder tss_encoder = 11 [(gogoproto.customname) = "TSSEncoder"];
  // Requester is the address of person who requests the data.
  string requester = 12;
  // FeeLimit is the maximum tokens that will be paid for this request.
  repeated cosmos.base.v1beta1.Coin fee_limit = 13
      [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
}

// Report is the data structure for storing reports in the storage.
message Report {
  option (gogoproto.equal) = true;
  // Validator is a validator address who submit the report
  string validator = 1;
  // InBeforeResolve indicates whether the report is submitted before the
  // request resolved
  bool in_before_resolve = 2;
  // RawReports is list of raw reports provided by the validator.
  // Each raw report has different external ID
  repeated RawReport raw_reports = 3 [(gogoproto.nullable) = false];
}

// ResolveStatus encodes the status of an oracle request.
enum ResolveStatus {
  option (gogoproto.goproto_enum_prefix) = false;

  // Open - the request is not yet resolved.
  RESOLVE_STATUS_OPEN_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "RESOLVE_STATUS_OPEN"];
  // Success - the request has been resolved successfully with no errors.
  RESOLVE_STATUS_SUCCESS = 1 [(gogoproto.enumvalue_customname) = "RESOLVE_STATUS_SUCCESS"];
  // Failure - an error occurred during the request's resolve call.
  RESOLVE_STATUS_FAILURE = 2 [(gogoproto.enumvalue_customname) = "RESOLVE_STATUS_FAILURE"];
  // Expired - the request does not get enough reports from validator within the
  // timeframe.
  RESOLVE_STATUS_EXPIRED = 3 [(gogoproto.enumvalue_customname) = "RESOLVE_STATUS_EXPIRED"];
}

// OracleRequestPacketData encodes an oracle request sent from other blockchains
// to BandChain.
message OracleRequestPacketData {
  option (gogoproto.equal) = true;
  // ClientID is the unique identifier of this oracle request, as specified by
  // the client. This same unique ID will be sent back to the requester with the
  // oracle response.
  string client_id = 1 [(gogoproto.customname) = "ClientID"];
  // OracleScriptID is the unique identifier of the oracle script to be
  // executed.
  uint64 oracle_script_id = 2 [(gogoproto.customname) = "OracleScriptID", (gogoproto.casttype) = "OracleScriptID"];
  // Calldata is the OBI-encoded calldata bytes available for oracle executor to
  // read.
  bytes calldata = 3;
  // AskCount is the number of validators that are requested to respond to this
  // oracle request. Higher value means more security, at a higher gas cost.
  uint64 ask_count = 4;
  // MinCount is the minimum number of validators necessary for the request to
  // proceed to the execution phase. Higher value means more security, at the
  // cost of liveness.
  uint64 min_count = 5;
  // FeeLimit is the maximum tokens that will be paid to all data source
  // providers.
  repeated cosmos.base.v1beta1.Coin fee_limit = 6
      [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
  // PrepareGas is amount of gas to pay to prepare raw requests
  uint64 prepare_gas = 7;
  // ExecuteGas is amount of gas to reserve for executing
  uint64 execute_gas = 8;
  // TSSEncoder is the mode of encoding oracle result signature order.
  Encoder tss_encoder = 9 [(gogoproto.customname) = "TSSEncoder"];
}

// OracleRequestPacketAcknowledgement encodes an oracle request acknowledgement
// send back to requester chain.
message OracleRequestPacketAcknowledgement {
  option (gogoproto.equal) = true;
  // RequestID is BandChain's unique identifier for this oracle request.
  uint64 request_id = 1 [(gogoproto.customname) = "RequestID", (gogoproto.casttype) = "RequestID"];
}

// OracleResponsePacketData encodes an oracle response from BandChain to the
// requester.
message OracleResponsePacketData {
  option (gogoproto.equal) = true;
  // ClientID is the unique identifier matched with that of the oracle request
  // packet.
  string client_id = 1 [(gogoproto.customname) = "ClientID"];
  // RequestID is BandChain's unique identifier for this oracle request.
  uint64 request_id = 2 [(gogoproto.customname) = "RequestID", (gogoproto.casttype) = "RequestID"];
  // AnsCount is the number of validators among to the asked validators that
  // actually responded to this oracle request prior to this oracle request
  // being resolved.
  uint64 ans_count = 3;
  // RequestTime is the UNIX epoch time at which the request was sent to
  // BandChain.
  int64 request_time = 4;
  // ResolveTime is the UNIX epoch time at which the request was resolved to the
  // final result.
  int64 resolve_time = 5;
  // ResolveStatus is the status of this oracle request, which can be OK,
  // FAILURE, or EXPIRED.
  ResolveStatus resolve_status = 6;
  // Result is the final aggregated value encoded in OBI format. Only available
  // if status if OK.
  bytes result = 7;
}

// Result encodes a result of request and store in chain
message Result {
  option (gogoproto.equal) = true;
  // ClientID is the unique identifier of this oracle request, as specified by
  // the client. This same unique ID will be sent back to the requester with the
  // oracle response.
  string client_id = 1 [(gogoproto.customname) = "ClientID"];
  // OracleScriptID is the unique identifier of the oracle script to be
  // executed.
  uint64 oracle_script_id = 2 [(gogoproto.customname) = "OracleScriptID", (gogoproto.casttype) = "OracleScriptID"];
  // Calldata is the calldata bytes available for oracle executor to read.
  bytes calldata = 3;
  // AskCount is the number of validators that are requested to respond to this
  // oracle request. Higher value means more security, at a higher gas cost.
  uint64 ask_count = 4;
  // MinCount is the minimum number of validators necessary for the request to
  // proceed to the execution phase. Higher value means more security, at the
  // cost of liveness.
  uint64 min_count = 5;
  // RequestID is BandChain's unique identifier for this oracle request.
  uint64 request_id = 6 [(gogoproto.customname) = "RequestID", (gogoproto.casttype) = "RequestID"];
  // AnsCount is the number of validators among to the asked validators that
  // actually responded to this oracle request prior to this oracle request
  // being resolved.
  uint64 ans_count = 7;
  // RequestTime is the UNIX epoch time at which the request was sent to
  // BandChain.
  int64 request_time = 8;
  // ResolveTime is the UNIX epoch time at which the request was resolved to the
  // final result.
  int64 resolve_time = 9;
  // ResolveStatus is the status of this oracle request, which can be OK,
  // FAILURE, or EXPIRED.
  ResolveStatus resolve_status = 10;
  // Result is the final aggregated value only available if status if OK.
  bytes result = 11;
}

// SigningResult encodes a result of signing of request
message SigningResult {
  option (gogoproto.equal) = true;
  // signing_id is the id of the bandtss signing
  uint64 signing_id = 1 [
    (gogoproto.customname) = "SigningID",
    (gogoproto.casttype)   = "github.com/bandprotocol/chain/v3/x/bandtss/types.SigningID"
  ];
  // error_codespace is the codespace of the error
  string error_codespace = 2;
  // error_code is the code in the codespace of the error
  uint64 error_code = 3;
}

// ValidatorStatus maintains whether a validator is an active oracle provider.
message ValidatorStatus {
  option (gogoproto.equal) = true;
  // IsActive is a boolean indicating active status of validator.
  // The validator will be deactivated when they are unable to send reports
  // to fulfill oracle request before the request expired.
  bool is_active = 1;
  // Since is a block timestamp when validator has been activated/deactivated
  google.protobuf.Timestamp since = 2 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
}

// ActiveValidator is information of currently active validator
message ActiveValidator {
  // Address is a validator address
  string address = 1;
  // Power is an amount of token that the validator is holding
  uint64 power = 2;
}

// Params is the data structure that keeps the parameters of the oracle module.
message Params {
  option (gogoproto.equal) = true;
  // MaxRawRequestCount is the maximum number of data source raw requests a
  // request can make.
  uint64 max_raw_request_count = 1;
  // MaxAskCount is the maximum number of validators a request can target.
  uint64 max_ask_count = 2;
  // MaxCalldataSize is the maximum size limit of calldata (bytes) in a request.
  uint64 max_calldata_size = 3;
  // MaxReportDataSize is the maximum size limit of report data (bytes) in a
  // report.
  uint64 max_report_data_size = 4;
  // ExpirationBlockCount is the number of blocks a request stays valid before
  // it gets expired due to insufficient reports.
  uint64 expiration_block_count = 5;
  // BaseOwasmGas is the base amount of Cosmos-SDK gas charged for owasm
  // execution.
  uint64 base_owasm_gas = 6;
  // PerValidatorRequestGas is the amount of Cosmos-SDK gas charged per
  // requested validator.
  uint64 per_validator_request_gas = 7;
  // SamplingTryCount the number of validator sampling tries to pick the highest
  // voting power subset of validators to perform an oracle task.
  uint64 sampling_try_count = 8;
  // OracleRewardPercentage is the percentage of block rewards allocated to
  // active oracle validators.
  uint64 oracle_reward_percentage = 9;
  // InactivePenaltyDuration is the duration period where a validator cannot
  // activate back after missing an oracle report.
  uint64 inactive_penalty_duration = 10;
  // IBCRequestEnabled is a flag indicating whether sending oracle request via
  // IBC is allowed
  bool ibc_request_enabled = 11 [(gogoproto.customname) = "IBCRequestEnabled"];
}

// PendingResolveList is a list of requests that are waiting to be resolved
message PendingResolveList {
  option (gogoproto.equal) = true;
  // RequestIDs is a list of request IDs that are waiting to be resolved
  repeated uint64 request_ids = 1;
}

// IBCChannel is information of IBC protocol to allow communicating with other
// chain
message IBCChannel {
  option (gogoproto.equal) = true;

  // PortID is port ID used for sending response packet when request is
  // resolved.
  string port_id = 1;
  // ChannelID is channel ID used for sending response packet when request is
  // resolved.
  string channel_id = 2;
}

// RequestVerification is a message that is constructed and signed by a reporter
// to be used as a part of verification of oracle request.
message RequestVerification {
  option (gogoproto.equal) = true;
  // ChainID is the ID of targeted chain
  string chain_id = 1 [(gogoproto.customname) = "ChainID"];
  // Validator is an validator address
  string validator = 2;
  // RequestID is the targeted request ID
  uint64 request_id = 3 [(gogoproto.customname) = "RequestID", (gogoproto.casttype) = "RequestID"];
  // ExternalID is the oracle's external ID of data source
  uint64 external_id = 4 [(gogoproto.customname) = "ExternalID", (gogoproto.casttype) = "ExternalID"];
  // DataSourceID is the ID of data source
  uint64 data_source_id = 5 [(gogoproto.customname) = "DataSourceID", (gogoproto.casttype) = "DataSourceID"];
}

// PriceResult is a result from standard price reference
message PriceResult {
  // Symbol is unit of data indicating what the data is. It is price currencies
  // for this case.
  string symbol = 1;
  // Multiplier is a number used for left-shifting value to eliminate decimal
  // digits
  uint64 multiplier = 2;
  // Px is the actual data, which is rate number multiplied by the multiplier.
  uint64 px = 3;
  // RequestID is oracle request ID that contains this price
  uint64 request_id = 4 [(gogoproto.customname) = "RequestID", (gogoproto.casttype) = "RequestID"];
  // ResolveTime is epoch timestamp indicating the time when the request had
  // been resolved
  int64 resolve_time = 5;
}

// OracleResultSignatureOrder defines a request id to request bandtss signature from the oracle result.
message OracleResultSignatureOrder {
  option (gogoproto.goproto_getters) = false;

  // RequestID is oracle's unique identifier for this oracle request.
  uint64 request_id = 1 [(gogoproto.customname) = "RequestID", (gogoproto.casttype) = "RequestID"];

  // encoder is the mode of encoding oracle result signature order.
  Encoder encoder = 2;
}

// Encoder is an enumerator that defines the mode of encoding message in tss module.
enum Encoder {
  option (gogoproto.goproto_enum_prefix) = false;

  // ENCODER_UNSPECIFIED is for unspecified value
  ENCODER_UNSPECIFIED = 0;
  // ENCODER_PROTO is for proto encoding
  ENCODER_PROTO = 1;
  // ENCODER_FULL_ABI is for ABI encoding for full data
  ENCODER_FULL_ABI = 2;
  // ENCODER_PARTIAL_ABI is for ABI encoding for only important data
  ENCODER_PARTIAL_ABI = 3;
}
