Skip to content

Token Name Service

The secure on chain token symbol namespace for the future of finance

Token Symbol Search:

Tokenlist for use with Uniswap, Sushiswap, and others

Want to point to the USDT token? Use usdt.tkn.eth

Want to use a dapp's interface? Visit uni.tkn.eth.limo

TNS is an API, a source of truth, and a set of tools.

The decentralized namespace for the internet of money.


The Base Protocol of the Defi Stack

  • TNS decentralizes and secures the financial namespace
  • As TNS resides on Ethereum mainnet, the Token API will live as long as the Ethereum Mainnet is maintained, potentially outlasting multiple generations of private companies, and the original TokenDao creators.
  • As we move to a tokenized world, TNS will become the gateway for protocols, DAOs, and all forms of tokenized value.
  • Unlike centralized data sources, the Token API is immune to end of life hazards such as acquisition and bankruptcy.
  • The Token Name Service product is 100% decentralized. No centralized data, no centralized domain name services, and no centralized file hosting.
  • Say goodybe to hex addresses, interact with Token symbols directly

Developers

  • TNS finally brings first class token symbol support to the EVM
  • Can be consumed wherever ENS is supported
  • Wrapped ERC20 contract allows enhanced token interaction without increases in code complexity

Users

  • Works with Etherscan, Metamask, Coinbase, Trust Wallet, Gnosis Safe, and many many others.
  • Tokenlist for use with Uniswap and Sushiswap
  • Publishes uncensorable dapp UIs via IPFS, just type the token into a web3 browser. Example: uni.tkn.eth.limo

The Premiere Dataset

  • The highest quality dataset, with thousands of token symbols coming soon
  • TNS delegates will compete to proactively identify new tokens on chain in real time

Features

  • Looking up token contracts: Tkn subdomains point to the token contract address: usdt.tkn.eth
  • Viewing Dapp webpages: Typing tkn subdomains into the browser will resolve the dapp webpage: uni.tkn.eth.limo
  • Adding tokens to metamask: Lookup the token symbol and then click the fox icon.

Documentation

The Basics

The Token Name Service uses ENS, and can be queried anywhere .eth domains are supported

The Token name set is persisted as subdomains of the *.tkn.eth domain

For instance, the contract for USDC can be found at usdc.tkn.eth and Wrapped Bitcoin at wbtc.tkn.eth

Descriptive metadata can be found on chain in each token's ENS resolver.
Including name, description, avatar, url, decimals, twitter, & github.

The Ticker.sol contract exposes additional queries; such as: fetch all metadata, and token balance for address. Ticker.sol is hosted at tkn.eth

Quickstart

Get token contract address

Retrieves the address where the token contract resides.

Useful for converting a user supplied token symbol into an actionable contract.

await provider.resolveName("uni.tkn.eth");
// '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984'
web3.eth.ens.getAddress('uni.tkn.eth').then(function (address) {
	console.log(address);
	// '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984'
})
pragma solidity ^0.8.4;

contract HelloTicker {
    ITicker ticker;
    constructor() {
        ticker = ITicker(0x8F5007bCDC1870531029C194b31AE1e6005bc30d); 
    }
    
    // Get an account's balance from a ticker symbol
    function balanceForAddress(address user, string calldata tickerSymbol) public view returns (uint) {
		// Fetch the token contract address with ticker:
		address contractAddress = ticker.addressFor(tickerSymbol);
        IERC20 tokenContract = IERC20(contractAddress);
        return tokenContract.balanceOf(user);
    }
}
// Required Interfaces
interface ITicker {
    struct Metadata {
        address contractAddress;
		string name;
        string url;
        string avatar;
        string description;
        string notice;
        string twitter;
        string github;
    }
    function addressFor(string calldata _name) external view returns (address);
    function infoFor(string calldata _name) external view returns (Metadata memory);
    function gasEfficientFetch(bytes32 namehash) external view returns (address);
    function balanceWithTicker(address user, string calldata tickerSymbol) external view returns (uint);
}

interface IERC20 {
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
}

Get single datapoint

Get one of the nine datapoints available for each token.

Pulls a single datapoint, such as a name or description.

const resolver = await provider.getResolver("uni.tkn.eth");
const description = await resolver.getText("description");
// "Protocol used to exchange cryptocurrencies and tokens"
const interface = await web3.eth.ens.getAddress('tkn.eth')
const interface_abi = [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"addressFor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"string","name":"tickerSymbol","type":"string"}],"name":"balanceWithTicker","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"namehash","type":"bytes32"}],"name":"gasEfficientFetch","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"infoFor","outputs":[{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"url","type":"string"},{"internalType":"string","name":"avatar","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"notice","type":"string"},{"internalType":"string","name":"twitter","type":"string"},{"internalType":"string","name":"github","type":"string"}],"internalType":"struct Ticker.Metadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"}];
const contract = await (new web3.eth.Contract(interface_abi, interface));

const info = await contract.methods.infoFor("uni").call()
console.log(info.description)
// "Protocol used to exchange cryptocurrencies and tokens"
pragma solidity ^0.8.4;

contract HelloTicker {
	ITicker ticker;
	constructor() {
		ticker = ITicker(0x8F5007bCDC1870531029C194b31AE1e6005bc30d); 
	}

    // Get a ticker's description
    function descriptionForTicker(string calldata tickerSymbol) public view returns (string memory description) {
        return ticker.infoFor(tickerSymbol).description;
    }
}
// Required Interfaces
interface ITicker {
	struct Metadata {
		address contractAddress;
		string name;
		string url;
		string avatar;
		string description;
		string notice;
		string twitter;
		string github;
	}
	function addressFor(string calldata _name) external view returns (address);
	function infoFor(string calldata _name) external view returns (Metadata memory);
	function gasEfficientFetch(bytes32 namehash) external view returns (address);
	function balanceWithTicker(address user, string calldata tickerSymbol) external view returns (uint);
}

interface IERC20 {
	function balanceOf(address account) external view returns (uint256);
	function transfer(address recipient, uint256 amount) external returns (bool);
}

Kiwis

Praesent nonummy mi in odio.

Tomatos

Praesent nonummy mi in odio. Nullam accumsan lorem in dui. Vestibulum turpis sem, aliquet eget, lobortis pellentesque, rutrum.

Get all token info

Retrieve all nine datapoints for a token.

Useful for fetching all token data in a single query.

let abi = [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"addressFor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"string","name":"tickerSymbol","type":"string"}],"name":"balanceWithTicker","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"namehash","type":"bytes32"}],"name":"gasEfficientFetch","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"infoFor","outputs":[{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"url","type":"string"},{"internalType":"string","name":"avatar","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"notice","type":"string"},{"internalType":"string","name":"twitter","type":"string"},{"internalType":"string","name":"github","type":"string"}],"internalType":"struct Ticker.Metadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"}];
let tkn = new ethers.Contract("tkn.eth", abi, provider)
let data = await tkn.infoFor("uni")
// Returns an object with all token data: 
// data.name: "Uniswap"
// data.avatar: "https://bafybeiclyzf4rogl67kd42ss2z2mnf4o3pf5s2aginvsxk7iomlelxhsdi.ipfs.dweb.link/"
// data.contractAddress: "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
// data.description: "Protocol used to exchange cryptocurrencies and tokens"
// data.url: "https://app.uniswap.org/"
// data.github: "Uniswap"
// data.twitter: "uniswap"
// data.notice: "{\"rev\":0, \"decimals\": 18}"
const interface = await web3.eth.ens.getAddress('tkn.eth')
const interface_abi = [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"addressFor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"string","name":"tickerSymbol","type":"string"}],"name":"balanceWithTicker","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"namehash","type":"bytes32"}],"name":"gasEfficientFetch","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"infoFor","outputs":[{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"url","type":"string"},{"internalType":"string","name":"avatar","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"notice","type":"string"},{"internalType":"string","name":"twitter","type":"string"},{"internalType":"string","name":"github","type":"string"}],"internalType":"struct Ticker.Metadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"}];
const contract = await (new web3.eth.Contract(interface_abi, interface));
const info = await contract.methods.infoFor("uni").call()
// Returns an object with all token data: 
// data.name: "Uniswap"
// data.avatar: "https://bafybeiclyzf4rogl67kd42ss2z2mnf4o3pf5s2aginvsxk7iomlelxhsdi.ipfs.dweb.link/"
// data.contractAddress: "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
// data.description: "Protocol used to exchange cryptocurrencies and tokens"
// data.url: "https://app.uniswap.org/"
// data.github: "Uniswap"
// data.twitter: "uniswap"
// data.notice: "{\"rev\":0, \"decimals\": 18}"
pragma solidity ^0.8.4;

contract HelloTicker {
	ITicker ticker;
	constructor() {
		ticker = ITicker(0x8F5007bCDC1870531029C194b31AE1e6005bc30d); 
	}
	
    // Get the full dataset for a ticker 
    function dataForTicker(string calldata tickerSymbol) public view returns (ITicker.Metadata memory info) {
        ITicker.Metadata memory data = ticker.infoFor(tickerSymbol);
        return data;
    }
}
// Required Interfaces
interface ITicker {
	struct Metadata {
		address contractAddress;
		string name;
		string url;
		string avatar;
		string description;
		string notice;
		string twitter;
		string github;
	}
	function addressFor(string calldata _name) external view returns (address);
	function infoFor(string calldata _name) external view returns (Metadata memory);
	function gasEfficientFetch(bytes32 namehash) external view returns (address);
	function balanceWithTicker(address user, string calldata tickerSymbol) external view returns (uint);
}

interface IERC20 {
	function balanceOf(address account) external view returns (uint256);
	function transfer(address recipient, uint256 amount) external returns (bool);
}

Kiwis

Praesent nonummy mi in odio.

Tomatos

Praesent nonummy mi in odio. Nullam accumsan lorem in dui. Vestibulum turpis sem, aliquet eget, lobortis pellentesque, rutrum.

Get tokens owned by token symbol

Lookup how many tokens an address owns, using a token symbol.

Helpful for looking up an ERC20 account balance without having to fetch the token contract address separately.

let abi = [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"addressFor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"string","name":"tickerSymbol","type":"string"}],"name":"balanceWithTicker","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"namehash","type":"bytes32"}],"name":"gasEfficientFetch","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"infoFor","outputs":[{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"url","type":"string"},{"internalType":"string","name":"avatar","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"notice","type":"string"},{"internalType":"string","name":"twitter","type":"string"},{"internalType":"string","name":"github","type":"string"}],"internalType":"struct Ticker.Metadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"}];
let tkn = new ethers.Contract("tkn.eth", abi, provider)
let account = '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B'
let uniBalance = await tkn.balanceWithTicker(account, "uni")
// uniBalance: 1615576470000000000000
const interface = await web3.eth.ens.getAddress('tkn.eth')
const interface_abi = [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"addressFor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"string","name":"tickerSymbol","type":"string"}],"name":"balanceWithTicker","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"namehash","type":"bytes32"}],"name":"gasEfficientFetch","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"infoFor","outputs":[{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"url","type":"string"},{"internalType":"string","name":"avatar","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"notice","type":"string"},{"internalType":"string","name":"twitter","type":"string"},{"internalType":"string","name":"github","type":"string"}],"internalType":"struct Ticker.Metadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"}];
const contract = await (new web3.eth.Contract(interface_abi, interface));
const account = '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B'
const uniBalance = await contract.methods.balanceWithTicker(account, "uni").call()
// uniBalance: 1615576470000000000000
pragma solidity ^0.8.4;

contract HelloTicker {
	ITicker ticker;
	constructor() {
		ticker = ITicker(0x8F5007bCDC1870531029C194b31AE1e6005bc30d); 
	}
	
    // Get the caller's balance of a token
    function myBalanceForTicker(string calldata tickerSymbol) public view returns (uint balance) {
        return ticker.balanceWithTicker(msg.sender, tickerSymbol);
    }
}
// Required Interfaces
interface ITicker {
	struct Metadata {
		address contractAddress;
		string name;
		string url;
		string avatar;
		string description;
		string notice;
		string twitter;
		string github;
	}
	function addressFor(string calldata _name) external view returns (address);
	function infoFor(string calldata _name) external view returns (Metadata memory);
	function gasEfficientFetch(bytes32 namehash) external view returns (address);
	function balanceWithTicker(address user, string calldata tickerSymbol) external view returns (uint);
}

interface IERC20 {
	function balanceOf(address account) external view returns (uint256);
	function transfer(address recipient, uint256 amount) external returns (bool);
}