use r402_protocol::network::ChainId;
use r402_protocol::payment::PriceTag;
#[cfg(not(feature = "experimental-tron"))]
use super::feature_missing;
#[cfg(feature = "experimental-tron")]
use super::{
accept_custom_decimals, custom_asset_address, invalid_asset_address, invalid_network,
invalid_pay_to, named_ticker, no_deployment, require_exact,
};
use crate::config::{AcceptConfig, ConfigError};
#[cfg(not(feature = "experimental-tron"))]
pub(super) fn build(
_accept: &AcceptConfig,
_network: &ChainId,
_amount: u128,
_pay_to: &str,
) -> Result<PriceTag, ConfigError> {
Err(feature_missing("tron", "experimental-tron"))
}
#[cfg(not(feature = "experimental-tron"))]
pub(super) fn decimals(_accept: &AcceptConfig, _network: &ChainId) -> Result<u8, ConfigError> {
Err(feature_missing("tron", "experimental-tron"))
}
#[cfg(feature = "experimental-tron")]
pub(super) fn decimals(accept: &AcceptConfig, network: &ChainId) -> Result<u8, ConfigError> {
Ok(token(accept, network)?.decimals)
}
#[cfg(feature = "experimental-tron")]
pub(super) fn build(
accept: &AcceptConfig,
network: &ChainId,
amount: u128,
pay_to: &str,
) -> Result<PriceTag, ConfigError> {
use std::str::FromStr as _;
use alloy_primitives::U256;
use r402_tron::TronExact;
use r402_tron::chain::Address;
require_exact(accept)?;
let pay_to =
Address::from_str(pay_to).map_err(|error| invalid_pay_to("Tron", pay_to, error))?;
let token = token(accept, network)?;
let method = transfer_method(accept, token.tip712.is_some())?;
let deployed = token.amount(U256::from(amount));
Ok(TronExact::price_tag(pay_to, &deployed, method))
}
#[cfg(feature = "experimental-tron")]
fn token(
accept: &AcceptConfig,
network: &ChainId,
) -> Result<r402_tron::chain::TronTokenDeployment, ConfigError> {
use std::str::FromStr as _;
use r402_tron::USDT;
use r402_tron::chain::{Address, TronChainReference, TronTokenDeployment};
let chain = TronChainReference::try_from(network.clone())
.map_err(|error| invalid_network("tron", &accept.network, error))?;
if named_ticker(accept, &["usdt"])?.is_some() {
if accept.eip712_name.is_some() || accept.eip712_version.is_some() {
return Err(ConfigError::Validation(
"eip712_name is only valid on custom tron accepts".to_owned(),
));
}
return USDT::on(chain)
.cloned()
.ok_or_else(|| no_deployment("USDT", &accept.network));
}
let address = custom_asset_address(accept)?;
let address =
Address::from_str(address).map_err(|error| invalid_asset_address(address, error))?;
let decimals = accept_custom_decimals(accept)?;
let deployment = TronTokenDeployment::new(chain, address, decimals);
match (
accept.eip712_name.as_deref(),
accept.eip712_version.as_deref(),
) {
(None, None) => Ok(deployment),
(Some(name), Some(version)) => Ok(deployment.with_tip712(name, version)),
_ => Err(ConfigError::Validation(
"custom Tron accepts need both eip712_name and eip712_version".to_owned(),
)),
}
}
#[cfg(feature = "experimental-tron")]
fn transfer_method(
accept: &AcceptConfig,
has_tip712: bool,
) -> Result<Option<r402_tron::AssetTransferMethod>, ConfigError> {
match accept.transfer_method.as_deref() {
None | Some("permit2") => Ok(Some(r402_tron::AssetTransferMethod::Permit2)),
Some("eip3009") => {
if !has_tip712 {
return Err(ConfigError::Validation(
"transfer_method = \"eip3009\" requires eip712_name and eip712_version on tron accepts"
.to_owned(),
));
}
Ok(Some(r402_tron::AssetTransferMethod::Eip3009))
}
Some(other) => Err(ConfigError::Validation(format!(
"unsupported transfer_method '{other}'"
))),
}
}