use canton_proto::com::daml::ledger::api::v2::Identifier;
use crate::value::{FromValue, ToValue, ValueError};
pub trait Contract {
const PACKAGE_ID: &'static str;
const PACKAGE_NAME: &'static str;
const MODULE_NAME: &'static str;
const ENTITY_NAME: &'static str;
#[must_use]
fn template_id() -> Identifier {
let package = if Self::PACKAGE_NAME.is_empty() {
Self::PACKAGE_ID.to_string()
} else {
format!("#{}", Self::PACKAGE_NAME)
};
Identifier {
package_id: package,
module_name: Self::MODULE_NAME.to_string(),
entity_name: Self::ENTITY_NAME.to_string(),
}
}
}
pub trait Template: Contract + ToValue + FromValue {
fn to_record(&self) -> canton_proto::com::daml::ledger::api::v2::Record;
fn from_created_event(
event: &canton_proto::com::daml::ledger::api::v2::CreatedEvent,
) -> Result<Self, ValueError> {
if let Some(id) = &event.template_id
&& (id.entity_name != Self::ENTITY_NAME || id.module_name != Self::MODULE_NAME)
{
return Err(ValueError::new(format!(
"event is {}:{}, expected {}:{}",
id.module_name,
id.entity_name,
Self::MODULE_NAME,
Self::ENTITY_NAME,
)));
}
let record = event
.create_arguments
.as_ref()
.ok_or_else(|| ValueError::new("created event carries no create_arguments payload"))?;
crate::value::from_record(record)
}
fn from_json_created_event(event: &serde_json::Value) -> Result<Self, ValueError>
where
Self: serde::de::DeserializeOwned,
{
let created = ["CreatedEvent", "createdEvent"]
.iter()
.find_map(|key| event.get(key))
.unwrap_or(event);
if let Some(id) = created
.get("templateId")
.and_then(serde_json::Value::as_str)
{
let mut parts = id.rsplit(':');
let entity = parts.next().unwrap_or_default();
let module = parts.next().unwrap_or_default();
if entity != Self::ENTITY_NAME || module != Self::MODULE_NAME {
return Err(ValueError::new(format!(
"event is {module}:{entity}, expected {}:{}",
Self::MODULE_NAME,
Self::ENTITY_NAME,
)));
}
}
let payload = created.get("createArgument").ok_or_else(|| {
ValueError::new("created event carries no createArgument payload")
})?;
serde_json::from_value(payload.clone())
.map_err(|error| ValueError::new(format!("payload did not decode: {error}")))
}
}
pub trait Interface: Contract {
type View: FromValue;
}
pub trait WithKey: Template {
type Key: ToValue;
}