use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::{HashId, ProgramRelease, ProgramSpec, StackManifest};
pub const PROTOCOL_SPEC_SCHEMA_V1: &str = "arete.protocol-spec/v1";
pub const PROTOCOL_HANDLER_ABI_V1: &str = "arete.protocol-handler/v1";
pub const PROTOCOL_CTX_V1: &str = "arete.protocol-ctx/v1";
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ProtocolSpecV1 {
pub schema: String,
pub name: String,
pub version: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub handler_abi: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ctx_version: Option<String>,
pub programs: BTreeMap<String, ProtocolProgramV1>,
pub stacks: BTreeMap<String, ProtocolStackDependencyV1>,
pub params: ObjectSchemaV1,
pub roles: BTreeMap<String, RoleV1>,
pub resources: BTreeMap<String, ResourceDeclV1>,
pub instance_visibility: InstanceVisibility,
pub reads: BTreeMap<String, ReadV1>,
pub machines: MachinesV1,
pub steps: BTreeMap<String, StepV1>,
pub reactions: Vec<ReactionV1>,
pub events: BTreeMap<String, EventV1>,
pub metadata: MetadataV1,
pub stack: StackSurfaceV1,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase", deny_unknown_fields)]
pub enum ProtocolProgramV1 {
#[serde(rename_all = "camelCase")]
ProgramSpec {
program_id: String,
program_spec_hash: HashId<ProgramSpec>,
#[serde(default, skip_serializing_if = "Option::is_none")]
program_release_hash: Option<HashId<ProgramRelease>>,
},
Builtin { builtin: BuiltinProgram },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum BuiltinProgram {
System,
SplToken,
AssociatedToken,
ComputeBudget,
Memo,
}
impl BuiltinProgram {
pub const ALL: [&'static str; 5] = [
"system",
"splToken",
"associatedToken",
"computeBudget",
"memo",
];
pub const fn program_id(self) -> &'static str {
match self {
Self::System => "11111111111111111111111111111111",
Self::SplToken => "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
Self::AssociatedToken => "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
Self::ComputeBudget => "ComputeBudget111111111111111111111111111111",
Self::Memo => "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ProtocolStackDependencyV1 {
pub stack_manifest_hash: HashId<StackManifest>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub package: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ObjectSchemaV1 {
#[serde(rename = "type")]
pub schema_type: ObjectType,
pub properties: BTreeMap<String, FieldSchemaV1>,
pub required: Vec<String>,
pub additional_properties: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ObjectType {
Object,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct FieldSchemaV1 {
#[serde(rename = "type")]
pub field_type: FieldType,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub format: Option<StringFormat>,
#[serde(default, rename = "enum", skip_serializing_if = "Option::is_none")]
pub enum_values: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max_length: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub minimum: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub maximum: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub items: Option<Box<FieldSchemaV1>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max_items: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub properties: Option<BTreeMap<String, FieldSchemaV1>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub required: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub additional_properties: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum FieldType {
String,
Boolean,
Integer,
Array,
Object,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum StringFormat {
Pubkey,
U8,
U16,
U32,
U64,
U128,
I64,
UnixTimestamp,
Uri,
}
impl StringFormat {
pub const ALL: [&'static str; 9] = [
"pubkey",
"u8",
"u16",
"u32",
"u64",
"u128",
"i64",
"unixTimestamp",
"uri",
];
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct RoleV1 {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ResourceDeclV1 {
pub schema: FieldSchemaV1,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum InstanceVisibility {
Shared,
Account,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase", deny_unknown_fields)]
pub enum ReadV1 {
Account {
program: String,
account: String,
address: String,
optional: bool,
},
TokenAccount { address: String, optional: bool },
Lamports { address: String },
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct MachinesV1 {
pub instance: MachineV1,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub participant: Option<MachineV1>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum MachineKind {
Instance,
Participant,
}
impl MachineKind {
pub const fn as_str(self) -> &'static str {
match self {
Self::Instance => "instance",
Self::Participant => "participant",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct MachineV1 {
pub initial: String,
pub states: BTreeMap<String, StateV1>,
pub derive: Vec<DeriveRuleV1>,
pub reads: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct StateV1 {
pub kind: StateKind,
pub terminal: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum StateKind {
Recorded,
Derived,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct DeriveRuleV1 {
pub from: Vec<String>,
pub to: String,
pub when: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub at: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum StepScope {
Create,
Instance,
Participant,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase", deny_unknown_fields)]
pub enum AuthorityV1 {
Creator,
Participant,
Role { role: String },
Keeper,
#[serde(rename_all = "camelCase")]
SquadsProposer { multisig: String },
}
impl AuthorityV1 {
pub fn signer_class(&self) -> SignerClass {
match self {
Self::Creator | Self::Participant | Self::Role { .. } => SignerClass::Wallet,
Self::Keeper => SignerClass::Keeper,
Self::SquadsProposer { .. } => SignerClass::SquadsProposer,
}
}
pub fn is_client_callable(&self) -> bool {
matches!(self.signer_class(), SignerClass::Wallet)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum SignerClass {
Wallet,
Ephemeral,
Attestation,
Keeper,
SquadsProposer,
}
impl SignerClass {
pub const ALL: [&'static str; 5] = [
"wallet",
"ephemeral",
"attestation",
"keeper",
"squadsProposer",
];
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum StepAccess {
Public,
Secret,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct StepV1 {
pub scope: StepScope,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub authority: AuthorityV1,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub access: Option<StepAccess>,
pub args: ObjectSchemaV1,
pub guards: Vec<GuardV1>,
pub reads: Vec<String>,
pub ephemeral: Vec<String>,
pub fee: FeeBasisV1,
pub transitions: Vec<TransitionV1>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub bind: Option<BindV1>,
pub glue: GlueV1,
pub build: BuildV1,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct GuardV1 {
pub code: String,
pub expr: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase", deny_unknown_fields)]
pub enum FeeBasisV1 {
None,
#[serde(rename_all = "camelCase")]
Input {
amount_arg: String,
asset: FeeAssetV1,
},
Fixed,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase", deny_unknown_fields)]
pub enum FeeAssetV1 {
Native,
#[serde(rename_all = "camelCase")]
Spl {
mint: String,
source_arg: String,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct TransitionV1 {
pub machine: MachineKind,
pub from: Vec<String>,
pub to: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct BindV1 {
pub accounts: BTreeMap<String, String>,
pub roles: BTreeMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct GlueV1 {
pub atas: Vec<AtaGlueV1>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub wrap_sol: Option<WrapSolV1>,
pub unwrap_sol: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct AtaGlueV1 {
pub owner: String,
pub mint: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct WrapSolV1 {
pub amount: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase", deny_unknown_fields)]
pub enum BuildV1 {
Template {
instructions: Vec<TemplateInstructionV1>,
},
Handler {
export: String,
programs: Vec<String>,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct TemplateInstructionV1 {
pub program: String,
pub instruction: String,
pub args: BTreeMap<String, String>,
pub accounts: BTreeMap<String, String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub remaining_accounts: Vec<RemainingAccountV1>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct RemainingAccountV1 {
pub pubkey: String,
pub is_writable: bool,
pub is_signer: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ReactionV1 {
pub id: String,
pub trigger: TriggerV1,
pub action: ActionV1,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase", deny_unknown_fields)]
pub enum TriggerV1 {
At {
machine: MachineKind,
#[serde(rename = "in")]
in_states: Vec<String>,
time: String,
},
When {
machine: MachineKind,
#[serde(rename = "in")]
in_states: Vec<String>,
condition: String,
},
OnTransition {
machine: MachineKind,
from: Vec<String>,
to: Vec<String>,
},
OnConfirmed { step: String },
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase", deny_unknown_fields)]
pub enum ActionV1 {
RunKeeperStep { step: String },
ProposeSquads { step: String },
Emit { event: String },
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct EventV1 {
pub machine: MachineKind,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct MetadataV1 {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub instance: Option<MetadataSchemaV1>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub participant: Option<MetadataSchemaV1>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct MetadataSchemaV1 {
pub fields: BTreeMap<String, MetadataFieldV1>,
pub max_bytes: u32,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct MetadataFieldV1 {
pub schema: FieldSchemaV1,
pub writer: MetadataWriter,
pub filterable: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum MetadataWriter {
Creator,
Participant,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct StackSurfaceV1 {
pub instance_accounts: BTreeMap<String, StackInstanceAccountV1>,
pub instance_fields: BTreeMap<String, StackInstanceFieldV1>,
pub activity: Vec<StackActivityV1>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct StackInstanceAccountV1 {
pub program: String,
pub account: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct StackInstanceFieldV1 {
pub account: String,
pub field: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct StackActivityV1 {
pub step: String,
pub program: String,
pub instruction: String,
pub instance_account: String,
pub wallet_account: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub amount_arg: Option<String>,
}
pub type ContractValue = Value;