syntax = "proto3";
package provenance.metadata.v1;

import "gogoproto/gogo.proto";

option go_package          = "github.com/provenance-io/provenance/x/metadata/types";
option java_package        = "io.provenance.metadata.v1";
option java_multiple_files = true;

// Specifications are a heirarchy of references to existing on chain data as well as a list of requirements that
// incoming requests to record data against a scope must meet.  Typical requirements included hashes that must be
// supplied corosponding to process/executable that must be ran, required signatures and sources of accounts that
// must sign requests, and allowed attributes/records that may be added to a scope.
//
// Scope Specification
// The top level specification for a scope indicates a set of allowed ContractSpecifications (see add contract spec)
// that are allowed to be used against a given scope to perform updates.  Requests to record data that do not derive
// from these contractspecifications are not allowed.
//
// Record Specification
// The specifics of which records are allowed within a group (and by extension the scope overall) are outlined using
// Consideration_Specs.  These considerations include required inputs, output format, and parties that must be
// associated with any request to record.
//
// Contract Specification
// The primary function of contract specifications is to denote the Contracts/Processes that will be used to manage
// the data within a scope.  These specifications control what information may be recorded on chain.  The use of
// definitions for inputs can build a chain of data references that must be in place in order for records to be
// added to the chain.
//
// Example:
//   A ContractSpecification may list a RecordSpecification that requires an input of type "Record" (indicating a
//   reference to a scope/record must exist on chain) in order for a specific Consideration (process/method) to be
//   executed and have an output_spec ultimately result in a record added to the scope.

// ScopeSpecification defines the required parties, resources, conditions, and consideration outputs for a contract
message ScopeSpecification {
  option (gogoproto.goproto_stringer) = false;
  option (gogoproto.stringer)         = true;

  // unique identifier for this specification on chain
  bytes specification_id = 1 [(gogoproto.nullable) = false, (gogoproto.customtype) = "MetadataAddress"];
  // General information about this scope specification.
  Description description = 2;
  // Addresses of the owners of this scope specification.
  repeated string owner_addresses = 3;
  // A list of parties that must be present on a scope (and their associated roles)
  repeated PartyType parties_involved = 4;
  // A list of contract specification ids allowed for a scope based on this specification.
  repeated bytes contract_spec_ids = 5 [(gogoproto.nullable) = false, (gogoproto.customtype) = "MetadataAddress"];
}

// ContractSpecification defines the required parties, resources, conditions, and consideration outputs for a contract
message ContractSpecification {
  option (gogoproto.goproto_stringer) = false;
  option (gogoproto.stringer)         = true;

  // unique identifier for this specification on chain
  bytes specification_id = 1 [(gogoproto.nullable) = false, (gogoproto.customtype) = "MetadataAddress"];
  // Description information for this contract specification
  Description description = 2;
  // Address of the account that owns this specificaiton
  repeated string owner_addresses = 3;
  // a list of party roles that must be fullfilled when signing a transaction for this contract specification
  repeated PartyType parties_involved = 4;
  // Reference to a metadata record with a hash and type information for the instance of code that will process this
  // contract
  oneof source {
    // the address of a record on chain that represents this contract
    bytes resource_id = 5 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
    // the hash of contract binary (off-chain instance)
    string hash = 6;
  }
  // name of the class/type of this contract executable
  string class_name = 7;
}

// RecordSpecification defines the specification for a Record including allowed/required inputs/outputs
message RecordSpecification {
  option (gogoproto.goproto_stringer) = false;
  option (gogoproto.stringer)         = true;

  // unique identifier for this specification on chain
  bytes specification_id = 1 [(gogoproto.nullable) = false, (gogoproto.customtype) = "MetadataAddress"];
  // Name of Record that will be created when this specification is used
  string name = 2;
  // A set of inputs that must be satisified to apply this RecordSpecification and create a Record
  repeated InputSpecification inputs = 3;
  // A type name for data associated with this record (typically a class or proto name)
  string type_name = 4;
  // Type of result for this record specification (must be RECORD or RECORD_LIST)
  DefinitionType result_type = 5;
  // Type of party responsible for this record
  repeated PartyType responsible_parties = 6;
}

// InputSpecification defines a name, type_name, and source reference (either on or off chain) to define an input
// parameter
message InputSpecification {
  option (gogoproto.goproto_stringer) = false;
  option (gogoproto.stringer)         = true;

  // name for this input
  string name = 1;
  // a type_name (typically a proto name or class_name)
  string type_name = 2;
  // source is either on chain (record_id) or off-chain (hash)
  oneof source {
    // the address of a record on chain (For Established Records)
    bytes record_id = 3 [(gogoproto.customtype) = "MetadataAddress"];
    // the hash of an off-chain piece of information (For Proposed Records)
    string hash = 4;
  }
}

// Description holds general information that is handy to associate with a structure.
message Description {
  // A Name for this thing.
  string name = 1;
  // A description of this thing.
  string description = 3;
  // URL to find even more info.
  string website_url = 4;
  // URL of an icon.
  string icon_url = 5;
}

// DefinitionType indicates the required definition type for this value
enum DefinitionType {
  // DEFINITION_TYPE_UNSPECIFIED indicates an unknown/invalid value
  DEFINITION_TYPE_UNSPECIFIED = 0;
  // DEFINITION_TYPE_PROPOSED indicates a proposed value is used here (a record that is not on-chain)
  DEFINITION_TYPE_PROPOSED = 1;
  // DEFINITION_TYPE_RECORD indicates the value must be a reference to a record on chain
  DEFINITION_TYPE_RECORD = 2;
  // DEFINITION_TYPE_RECORD_LIST indicates the value maybe a reference to a collection of values on chain having
  // the same name
  DEFINITION_TYPE_RECORD_LIST = 3;
}

// PartyType are the different roles parties on a contract may use
enum PartyType {
  // PARTY_TYPE_UNSPECIFIED is an error condition
  PARTY_TYPE_UNSPECIFIED = 0;
  // PARTY_TYPE_ORIGINATOR is an asset originator
  PARTY_TYPE_ORIGINATOR = 1;
  // PARTY_TYPE_SERVICER provides debt servicing functions
  PARTY_TYPE_SERVICER = 2;
  // PARTY_TYPE_INVESTOR is a generic investor
  PARTY_TYPE_INVESTOR = 3;
  // PARTY_TYPE_CUSTODIAN is an entity that provides custodian services for assets
  PARTY_TYPE_CUSTODIAN = 4;
  // PARTY_TYPE_OWNER indicates this party is an owner of the item
  PARTY_TYPE_OWNER = 5;
  // PARTY_TYPE_AFFILIATE is a party with an affiliate agreement
  PARTY_TYPE_AFFILIATE = 6;
  // PARTY_TYPE_OMNIBUS is a special type of party that controls an omnibus bank account
  PARTY_TYPE_OMNIBUS = 7;
  // PARTY_TYPE_PROVENANCE is used to indicate this party represents the blockchain or a smart contract action
  PARTY_TYPE_PROVENANCE = 8;
  // PARTY_TYPE_CONTROLLER is an entity which controls a specific asset on chain (ie enote)
  PARTY_TYPE_CONTROLLER = 10;
  // PARTY_TYPE_VALIDATOR is an entity which validates given assets on chain
  PARTY_TYPE_VALIDATOR = 11;
  // PARTY_TYPE_GENERIC_1 are placeholder types for the user-defined role.
  PARTY_TYPE_GENERIC_1 = 12;
  // PARTY_TYPE_GENERIC_2 are placeholder types for the user-defined role.
  PARTY_TYPE_GENERIC_2 = 13;
  // PARTY_TYPE_GENERIC_3 are placeholder types for the user-defined role.
  PARTY_TYPE_GENERIC_3 = 14;
  // PARTY_TYPE_GENERIC_4 are placeholder types for the user-defined role.
  PARTY_TYPE_GENERIC_4 = 15;
  // PARTY_TYPE_GENERIC_5 are placeholder types for the user-defined role.
  PARTY_TYPE_GENERIC_5 = 16;
  // PARTY_TYPE_GENERIC_6 are placeholder types for the user-defined role.
  PARTY_TYPE_GENERIC_6 = 17;
}