Abstract Name Service

The Abstract Name Service (or ANS in short) is an on-chain data store of the most important address space related data of the blockchain it is deployed on. It allows for chain-agnostic action execution and dynamic address resolution. These features enable both users and developers to engage with the blockchain in a more intuitive manner.

ANS Architecture

The ANS is a smart contract that stores the following data:

  • Assets: The most relevant assets on the local blockchain.
  • Contracts: Contracts related to certain protocols or applications that could be dynamically resolved. This could be used to store the address for an asset-pair for a dex. For example, “osmosis/juno,osmo” could be resolved to the address of the osmosis pool that allows you to swap osmo for juno.
  • Channels: IBC channel data to map a protocol + destination chain to a channel id. This allows for dynamic IBC transfers without having to know the channel id beforehand.

The ANS contract state layout is defined here. It consists of key-value mappings for the different entries.

#![allow(unused)]
fn main() {
    /// Stores name and address of tokens and pairs
    /// LP token pairs are stored alphabetically
    pub const ASSET_ADDRESSES: Map<&AssetEntry, AssetInfo> =
        Map::new(storage_namespaces::ans_host::ASSET_ADDRESSES);
    pub const REV_ASSET_ADDRESSES: Map<&AssetInfo, AssetEntry> =
        Map::new(storage_namespaces::ans_host::REV_ASSET_ADDRESSES);

    /// Stores contract addresses
    pub const CONTRACT_ADDRESSES: Map<&ContractEntry, Addr> =
        Map::new(storage_namespaces::ans_host::CONTRACT_ADDRESSES);

    /// stores channel-ids
    pub const CHANNELS: Map<&ChannelEntry, String> =
        Map::new(storage_namespaces::ans_host::CHANNELS);

    /// Stores the registered dex names
    pub const REGISTERED_DEXES: Item<Vec<DexName>> =
        Item::new(storage_namespaces::ans_host::REGISTERED_DEXES);

    /// Stores the asset pairing entries to their pool ids
    /// (asset1, asset2, dex_name) -> {id: uniqueId, pool_id: poolId}
    pub const ASSET_PAIRINGS: Map<&DexAssetPairing, Vec<PoolReference>> =
        Map::new(storage_namespaces::ans_host::ASSET_PAIRINGS);

    /// Stores the metadata for the pools using the unique pool id as the key
    pub const POOL_METADATA: Map<UniquePoolId, PoolMetadata> =
        Map::new(storage_namespaces::ans_host::POOL_METADATA);
}

Info

You can find the full source code for the ANS contract here.

Resolving Entries

The information provided by the ANS is great to have. However, directly calling CosmWasm smart queries on the ANS contract can make your code messy and significantly raise gas usage. For this reason, we offer three methods to efficiently and dependably execute low-gas queries on the ANS contract.

Resolving your asset/contract name to its matching value is much like resolving a domain name like abstract.money to its IP address (172.67.163.181).

There are three ways to resolve your entry into its matching value.

Both App and Adapter objects implement the AbstractNameService trait which allows you to resolve entries.

let juno_name = AssetEntry::new("juno");
let juno_asset_info = my_app.name_service(deps).query(&juno_name)?;

Resolve Trait

Entries that are resolvable by the Abstract Name Service implement the Resolve trait which gives them the ability to be resolved by ANS explicitly.

let ans_host = my_app.ans_host(deps)?;
let juno_name = AssetEntry::new("juno");
let juno_asset_info = juno_name.resolve(&deps.querier, &ans_host)?;

AnsHost Object

You can also load or create an AnsHost struct. This struct is a simple wrapper around an Addr and implements methods that perform raw queries on the wrapped address.

let ans_host = AnsHost {address: "juno1...."};
let juno_name = AssetEntry::new("juno");
let juno_asset_info = ans_host.query_asset(deps, &juno_name)?;