use std::collections::BTreeMap;
use alloy_primitives::LogData;
use serde::{Deserialize, Serialize};
use crate::digest::Digest;
use super::{ChainName, ComponentID, ServiceID, WorkflowID};
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub struct Service {
pub id: ServiceID,
pub name: String,
pub components: BTreeMap<ComponentID, Component>,
pub workflows: BTreeMap<WorkflowID, Workflow>,
pub status: ServiceStatus,
pub config: ServiceConfig,
pub testable: bool,
}
impl Service {
pub fn new_simple(
id: ServiceID,
name: Option<String>,
trigger: Trigger,
component_digest: Digest,
submit: Submit,
config: Option<ServiceConfig>,
) -> Self {
let component_id = ComponentID::default();
let workflow_id = WorkflowID::default();
let workflow = Workflow {
trigger,
component: component_id,
submit,
};
let component = Component {
wasm: component_digest,
permissions: Permissions::default(),
};
let components = BTreeMap::from([(workflow.component.clone(), component)]);
let workflows = BTreeMap::from([(workflow_id, workflow)]);
Self {
name: name.unwrap_or_else(|| id.to_string()),
id,
components,
workflows,
status: ServiceStatus::Active,
config: config.unwrap_or_default(),
testable: false,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub struct Component {
pub wasm: Digest,
pub permissions: Permissions,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub struct Workflow {
pub trigger: Trigger,
pub component: ComponentID,
pub submit: Submit,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum Trigger {
CosmosContractEvent {
address: layer_climb_address::Address,
chain_name: ChainName,
event_type: String,
},
EthContractEvent {
address: alloy_primitives::Address,
chain_name: ChainName,
event_hash: [u8; 32],
},
Manual,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum TriggerData {
CosmosContractEvent {
contract_address: layer_climb_address::Address,
chain_name: ChainName,
event: cosmwasm_std::Event,
block_height: u64,
},
EthContractEvent {
contract_address: alloy_primitives::Address,
chain_name: ChainName,
log: LogData,
block_height: u64,
},
Raw(Vec<u8>),
}
impl TriggerData {
pub fn new_raw(data: impl AsRef<[u8]>) -> Self {
TriggerData::Raw(data.as_ref().to_vec())
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum Submit {
None,
EthereumContract {
chain_name: ChainName,
address: alloy_primitives::Address,
max_gas: Option<u64>,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub struct ServiceConfig {
pub fuel_limit: u64,
pub host_envs: Vec<String>,
pub kv: Vec<(String, String)>,
pub max_gas: Option<u64>,
}
impl Default for ServiceConfig {
fn default() -> Self {
Self {
fuel_limit: 100_000_000,
max_gas: None,
host_envs: vec![],
kv: vec![],
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Copy)]
#[serde(rename_all = "snake_case")]
pub enum ServiceStatus {
Active,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(default, rename_all = "snake_case")]
#[derive(Default)]
pub struct Permissions {
pub allowed_http_hosts: AllowedHostPermission,
pub file_system: bool,
}
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum AllowedHostPermission {
All,
Only(Vec<String>),
#[default]
None,
}
mod test_ext {
use crate::{digest::Digest, id::ChainName};
use super::{Component, Submit, Trigger};
impl Submit {
pub fn eth_contract(
chain_name: ChainName,
address: alloy_primitives::Address,
max_gas: Option<u64>,
) -> Submit {
Submit::EthereumContract {
chain_name,
address,
max_gas,
}
}
}
impl Component {
pub fn new(digest: Digest) -> Component {
Self {
wasm: digest,
permissions: Default::default(),
}
}
}
impl Trigger {
pub fn cosmos_contract_event(
address: layer_climb_address::Address,
chain_name: impl Into<ChainName>,
event_type: impl ToString,
) -> Self {
Trigger::CosmosContractEvent {
address,
chain_name: chain_name.into(),
event_type: event_type.to_string(),
}
}
pub fn eth_contract_event(
address: alloy_primitives::Address,
chain_name: impl Into<ChainName>,
event_hash: [u8; 32],
) -> Self {
Trigger::EthContractEvent {
address,
chain_name: chain_name.into(),
event_hash,
}
}
}
}