use iota_protocol_config::ProtocolConfig;
use iota_stardust_sdk::types::block::output::AliasOutput as StardustAlias;
use move_core_types::{ident_str, identifier::IdentStr, language_storage::StructTag};
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use crate::{
STARDUST_PACKAGE_ID, TypeTag,
balance::Balance,
base_types::{IotaAddress, ObjectID, SequenceNumber, TxContext},
collection_types::Bag,
id::UID,
object::{Data, MoveObject, Object, Owner},
stardust::{coin_type::CoinType, stardust_to_iota_address},
};
pub const ALIAS_MODULE_NAME: &IdentStr = ident_str!("alias");
pub const ALIAS_OUTPUT_MODULE_NAME: &IdentStr = ident_str!("alias_output");
pub const ALIAS_OUTPUT_STRUCT_NAME: &IdentStr = ident_str!("AliasOutput");
pub const ALIAS_STRUCT_NAME: &IdentStr = ident_str!("Alias");
pub const ALIAS_DYNAMIC_OBJECT_FIELD_KEY: &[u8] = b"alias";
pub const ALIAS_DYNAMIC_OBJECT_FIELD_KEY_TYPE: &str = "vector<u8>";
#[serde_as]
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
pub struct Alias {
pub id: UID,
pub legacy_state_controller: IotaAddress,
pub state_index: u32,
pub state_metadata: Option<Vec<u8>>,
pub sender: Option<IotaAddress>,
pub metadata: Option<Vec<u8>>,
pub immutable_issuer: Option<IotaAddress>,
pub immutable_metadata: Option<Vec<u8>>,
}
impl Alias {
pub fn tag() -> StructTag {
StructTag {
address: STARDUST_PACKAGE_ID.into(),
module: ALIAS_MODULE_NAME.to_owned(),
name: ALIAS_STRUCT_NAME.to_owned(),
type_params: Vec::new(),
}
}
pub fn try_from_stardust(
alias_id: ObjectID,
alias: &StardustAlias,
) -> Result<Self, anyhow::Error> {
if alias_id.as_ref() == [0; 32] {
anyhow::bail!("alias_id must be non-zeroed");
}
let state_metadata: Option<Vec<u8>> = if alias.state_metadata().is_empty() {
None
} else {
Some(alias.state_metadata().to_vec())
};
let sender: Option<IotaAddress> = alias
.features()
.sender()
.map(|sender_feat| stardust_to_iota_address(sender_feat.address()))
.transpose()?;
let metadata: Option<Vec<u8>> = alias
.features()
.metadata()
.map(|metadata_feat| metadata_feat.data().to_vec());
let immutable_issuer: Option<IotaAddress> = alias
.immutable_features()
.issuer()
.map(|issuer_feat| stardust_to_iota_address(issuer_feat.address()))
.transpose()?;
let immutable_metadata: Option<Vec<u8>> = alias
.immutable_features()
.metadata()
.map(|metadata_feat| metadata_feat.data().to_vec());
Ok(Alias {
id: UID::new(alias_id),
legacy_state_controller: stardust_to_iota_address(alias.state_controller_address())?,
state_index: alias.state_index(),
state_metadata,
sender,
metadata,
immutable_issuer,
immutable_metadata,
})
}
pub fn to_genesis_object(
&self,
owner: Owner,
protocol_config: &ProtocolConfig,
tx_context: &TxContext,
version: SequenceNumber,
) -> anyhow::Result<Object> {
let move_alias_object = {
MoveObject::new_from_execution(
Self::tag().into(),
version,
bcs::to_bytes(&self)?,
protocol_config,
)?
};
let move_alias_object = Object::new_from_genesis(
Data::Move(move_alias_object),
owner,
tx_context.digest(),
);
Ok(move_alias_object)
}
}
#[serde_as]
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
pub struct AliasOutput {
pub id: UID,
pub balance: Balance,
pub native_tokens: Bag,
}
impl AliasOutput {
pub fn tag(type_param: TypeTag) -> StructTag {
StructTag {
address: STARDUST_PACKAGE_ID.into(),
module: ALIAS_OUTPUT_MODULE_NAME.to_owned(),
name: ALIAS_OUTPUT_STRUCT_NAME.to_owned(),
type_params: vec![type_param],
}
}
pub fn try_from_stardust(
object_id: ObjectID,
alias: &StardustAlias,
native_tokens: Bag,
) -> Result<Self, anyhow::Error> {
Ok(AliasOutput {
id: UID::new(object_id),
balance: Balance::new(alias.amount()),
native_tokens,
})
}
pub fn to_genesis_object(
&self,
owner: Owner,
protocol_config: &ProtocolConfig,
tx_context: &TxContext,
version: SequenceNumber,
coin_type: CoinType,
) -> anyhow::Result<Object> {
let move_alias_output_object = {
MoveObject::new_from_execution(
AliasOutput::tag(coin_type.to_type_tag()).into(),
version,
bcs::to_bytes(&self)?,
protocol_config,
)?
};
let move_alias_output_object = Object::new_from_genesis(
Data::Move(move_alias_output_object),
owner,
tx_context.digest(),
);
Ok(move_alias_output_object)
}
}