use crate::encoding::parse_address;
pub(crate) async fn run_release_subdomain(name: &str) -> Result<String, String> {
let token_id = match crate::app::registry::check_name(name).await? {
crate::app::registry::Status::Taken { agent_id } => agent_id,
_ => return Err(format!("'{name}' is not registered")),
};
let owner = crate::app::registry::owner_of_name(name)
.await
.map_err(|e| format!("owner: {e}"))?
.ok_or_else(|| "no on-chain owner".to_string())?;
let diamond = parse_address(crate::app::registry::REGISTRY_ADDRESS)?;
let call = crate::tempo_tx::TempoCall {
to: diamond,
value_wei: 0,
input: crate::app::registry::release_name_calldata(token_id),
};
super::run_sponsored_tempo_call(&owner, vec![call], 1_000_000, "release subdomain").await
}
pub(crate) async fn run_bulk_release(
names: &[String],
) -> Result<(Vec<String>, String), String> {
if names.is_empty() {
return Err("no subdomains to release".into());
}
let (_, owner) = crate::app::tenant::current_tenant_owner().await?;
let main_id = crate::app::registry::main_of(&owner)
.await
.map_err(|e| format!("mainOf: {e}"))?;
let diamond = parse_address(crate::app::registry::REGISTRY_ADDRESS)?;
let mut released: Vec<String> = Vec::with_capacity(names.len());
let mut calls: Vec<crate::tempo_tx::TempoCall> = Vec::with_capacity(names.len());
for raw in names {
let name = raw.trim();
if name.is_empty() {
continue;
}
let token_id = match crate::app::registry::check_name(name).await? {
crate::app::registry::Status::Taken { agent_id } => agent_id,
_ => return Err(format!("'{name}' is not registered")),
};
if main_id != 0 && token_id == main_id {
return Err(format!(
"'{name}' is your MAIN identity and cannot be released"
));
}
let holder = crate::app::registry::owner_of_name(name)
.await
.map_err(|e| format!("owner of {name}: {e}"))?
.ok_or_else(|| format!("no on-chain owner for '{name}'"))?;
if holder.to_lowercase() != owner.to_lowercase() {
return Err(format!("'{name}' is not owned by this identity"));
}
calls.push(crate::tempo_tx::TempoCall {
to: diamond,
value_wei: 0,
input: crate::app::registry::release_name_calldata(token_id),
});
released.push(name.to_string());
}
if calls.is_empty() {
return Err("no subdomains to release after filtering".into());
}
let gas = 1_000_000 + (calls.len() as u128).saturating_sub(1) * 250_000;
let tx = super::run_sponsored_tempo_call(&owner, calls, gas, "bulk release subdomains").await?;
Ok((released, tx))
}
pub(crate) async fn run_batch_create_subdomains(
names: &[String],
) -> Result<(Vec<String>, String), String> {
if names.is_empty() {
return Err("no names to register".into());
}
let (_, owner) = crate::app::tenant::current_tenant_owner().await?;
let diamond = parse_address(crate::app::registry::REGISTRY_ADDRESS)?;
let mut registered: Vec<String> = Vec::with_capacity(names.len());
let mut calls: Vec<crate::tempo_tx::TempoCall> = Vec::with_capacity(names.len());
for raw in names {
let cleaned = crate::app::tenant::sanitize(raw);
if cleaned.len() < 3
|| cleaned.len() > 32
|| cleaned != raw.trim().to_ascii_lowercase()
{
continue;
}
if registered.iter().any(|n| n == &cleaned) {
continue; }
match crate::app::registry::check_name(&cleaned).await? {
crate::app::registry::Status::Available => {}
_ => continue,
}
calls.push(crate::tempo_tx::TempoCall {
to: diamond,
value_wei: 0,
input: crate::app::registry::register_calldata(&cleaned),
});
registered.push(cleaned);
}
if calls.is_empty() {
return Err("no valid, available names to register".into());
}
let cost = crate::app::registry::registration_cost().await.unwrap_or(0);
if cost > 0 {
let total = cost.saturating_mul(registered.len() as u128);
calls.insert(
0,
crate::app::registry::approve_credits_call(total).map_err(|e| format!("approve: {e}"))?,
);
}
let gas = 400_000 + (calls.len() as u128) * 1_500_000 + if cost > 0 { 60_000 } else { 0 };
let tx = super::run_sponsored_tempo_call(&owner, calls, gas, "batch create subdomains").await?;
for name in ®istered {
let n = name.clone();
wasm_bindgen_futures::spawn_local(async move {
super::key_sync::sync_local_key_to_main(&n).await;
});
}
Ok((registered, tx))
}