Skip to main content

aptos_sdk/api/
ans.rs

1//! Aptos Names Service (ANS) client -- **scaffold / not yet implemented**.
2//!
3//! This module exists so `AGENTS.md` can stop referencing a missing file,
4//! and so future work can land in one obvious place. **Nothing here issues
5//! a network call yet.**
6//!
7//! # Scope when implemented
8//!
9//! At minimum we want:
10//!
11//! - `lookup(name)` -- resolve a `.apt` / sub-domain string into an
12//!   [`AccountAddress`].
13//! - `reverse_lookup(address)` -- find the primary name registered to an
14//!   address, if any.
15//!
16//! At extension time:
17//!
18//! - Register / renew flows (entry-function builders against the on-chain
19//!   ANS contract -- requires pinned contract addresses per network and a
20//!   plan for how the SDK should pick them).
21//! - Sub-domain queries.
22//!
23//! # Why not implemented yet
24//!
25//! The TS SDK's ANS module hard-codes contract addresses per network and
26//! relies on the indexer for some lookups. Mirroring that 1:1 without
27//! making network-specific decisions visible to callers needs design
28//! work that's tracked separately from the May-2026 audit follow-ups. See
29//! `AUDIT_SUMMARY_2026-05.md` and the audit follow-up commits for context.
30
31use crate::api::FullnodeClient;
32use crate::error::{AptosError, AptosResult};
33use crate::types::AccountAddress;
34
35/// Skeleton client for Aptos Names Service.
36///
37/// All methods currently return
38/// [`AptosError::Internal`]
39/// so callers fail fast rather than silently accepting placeholder values.
40#[derive(Debug, Clone)]
41pub struct AnsClient {
42    #[allow(dead_code)] // wired up when lookups land
43    fullnode: FullnodeClient,
44}
45
46impl AnsClient {
47    /// Constructs a new ANS client bound to a given fullnode.
48    #[must_use]
49    pub fn new(fullnode: FullnodeClient) -> Self {
50        Self { fullnode }
51    }
52
53    /// Resolves an ANS name (e.g. `"alice.apt"`) to its registered
54    /// [`AccountAddress`].
55    ///
56    /// # Errors
57    ///
58    /// Currently always returns [`AptosError::Internal`]; the lookup is
59    /// scheduled but not yet wired up. Track progress against the audit
60    /// follow-up issue cited in this module's docs.
61    pub async fn lookup(&self, _name: &str) -> AptosResult<AccountAddress> {
62        Err(AptosError::Internal(
63            "ANS lookup is not yet implemented in the Rust SDK (tracked as an audit \
64             follow-up); use the on-chain `0x...::router::get_address` view \
65             function directly for now"
66                .to_string(),
67        ))
68    }
69
70    /// Finds the primary ANS name registered to a given address, if any.
71    ///
72    /// # Errors
73    ///
74    /// Currently always returns [`AptosError::Internal`]; the reverse
75    /// lookup is scheduled but not yet wired up.
76    pub async fn reverse_lookup(&self, _address: AccountAddress) -> AptosResult<Option<String>> {
77        Err(AptosError::Internal(
78            "ANS reverse lookup is not yet implemented in the Rust SDK \
79             (tracked as an audit follow-up)"
80                .to_string(),
81        ))
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88    use crate::config::AptosConfig;
89
90    #[tokio::test]
91    async fn lookup_is_unsupported() {
92        let fullnode = FullnodeClient::new(AptosConfig::testnet()).unwrap();
93        let ans = AnsClient::new(fullnode);
94        let err = ans.lookup("alice.apt").await.unwrap_err();
95        assert!(matches!(err, AptosError::Internal(_)));
96    }
97
98    #[tokio::test]
99    async fn reverse_lookup_is_unsupported() {
100        let fullnode = FullnodeClient::new(AptosConfig::testnet()).unwrap();
101        let ans = AnsClient::new(fullnode);
102        let err = ans.reverse_lookup(AccountAddress::ONE).await.unwrap_err();
103        assert!(matches!(err, AptosError::Internal(_)));
104    }
105}