Contract Catalog Data Fields

General Information

Protocol

Field: belongs_to

Example : Curve

Hashless can automatically assign contracts as belonging to a specific application, or protocol, based on assessing the technical characteristics of the contract's code and deployment, as well as observed on-chain behavior. (We've also manually labeled protocols for a small number of key contracts in the Ethereum ecosystem.)

Generally, contracts are assigned when they are unambiguously part of a protocol, and not otherwise. For example, all Uniswap liquidity pools (those deployed by a Uniswap-owned factory) are commonly understood to be part of the Uniswap protocol. On the other hand, Safe (formerly Gnosis) multi-signature vaults are deployed by a Safe-owned factory, but are commonly used as components of other protocols, so deployed vaults are not grouped into the "Gnosis" protocol by default.

Category

Field: category

Example: Marketplace/DEX/Liquidity Pool/Uniswap V3-style

Hashless assigns contracts to a category based on their technical characteristics (for engineers: based on statically analyzing their bytecode.)

Categories are hierarchical, so, for example, the category Lending/ Collateral Token/cToken should be interpreted "Compound cToken-style, which is a type of collateral token, which is associated with Lending".

Categories are definitive: when a contract has a category, that category captures the primary functionality of the contract.

Hashless currently supports the following categories, with more being added all the time.

CategoryDescription
Marketplace/DEX/Liquidity Pool/Uniswap V3-styleUniswap V3-style liquidity pool with concentrated liquidity / liquidity ranges. Positions are not fungibly transferable but are associated with / tracked by a separate NFT.
Marketplace/DEX/Liquidity Pool/Uniswap V2-styleUniswap V2-style liquidity pool. Fractional positions in the pool are represented via fungible LP token (which is the pool itself.) Uniswap V2 and Sushiswap pools are both in this category, as are many other Uniswap forks.
Asset/TokenAn ERC-20 token that has no significant other functionality built into its implementing contract. (So, for example, governance tokens that are useable in conjunction with on-chain voting, where that voting is implemented separately, fall into this category.)
Asset/NFTAn NFT that has no significant purpose or logic built into it. NFTs that include paid minting logic or airdrop logic are included. However, NFTs that include significant marketplace functionality in the NFT contract itself may be assigned into another category.
Nontransferable Asset/veTokenA vote-escrowed style "token" that can't be transferred. Typically a transferable governance token is staked and a veToken is provided to represent the staked position.

Names

Field: name

Example: Uniswap V2 Pool: ELON-WETH

Hashless determines the human-readable name for many contracts automatically. For contracts implementing an asset, such as an ERC-20 token or NFT, we source names and symbol data from the on-chain name() and symbol() functions typically implemented by those contracts.

For liquidity pools or derivative assets (such as those associated with lending), Hashless also applies templatized naming for popular categories. In cases where such a contract is technically a fungible asset or NFT with on-chain name information, we will prefer the more informative name. For example, for a SushiSwap liquidity pool we will display a name like SushiSwap Pool: DAI-USDC instead of the less informative SushiSwap LP Token or SLP.

Labels

Field: labels

Example: ["Token", "Liquidity Pool"]

In addition to categories, we also apply human labels to contracts based on their capabilities. For example, the aforementioned SushiSwap DAI-USDC pool would would have the category Marketplace/DEX/Uniswap V2-style Liquidity Pool, but it would include the Token label indicating that is also a transferable ERC-20 token.

📘

Pass-through of implementation labels to proxies

In cases where the implementation contract of a proxy can be determined, any labels from the implementation will be "passed through" to the proxy, since the implementation typically determines the on-chain behavior of the proxy.

Technical Information

Proxy and Implementation Information

Proxy Type

Field: program.proxy_type

Hashless detects proxy contracts (those that use the Ethereum DELEGATECALL operation to delegate their implementation to another contract.) In addition, Hashless detects the type of proxy in most cases.

Supported proxy types are eip_1967, legacy_oz (an upgradeable proxy predating, but very similar to, EIP-1967-style proxies), hardcoded (a non-upgradeable proxy that has a fixed implementation address in its deployed bytecode, for example an EIP-1167 minimal proxy) or unknown

Proxy Delegates

Field: program.delegates

In cases where Hashless can statically determine the implementation contract (from bytecode or storage analysis), the address of the implementation will be listed. In rare cases, a proxy may have more than one contract it delegates to.

Features

Field: program.features

In addition to human-readable labels about the financial behavior of a contract (see Labels), the Hashless contract analyzer summarizes certain technical characteristics, or features, of a contract's code that we've found to be useful for assessment.

Currently supported features are:

FeatureDescription
includes_logsContract can emit events.
includes_delegatecallContract can delegate, i.e. is a proxy.
includes_selfdestructContract can self-destruct, which is a deprecated Ethereum feature that destroys the contract's bytecode and refunds any Ether balance held by the contract back to a specified address. This is very uncommon in contracts / protocols that are widely used.
includes_createContract can deploy other contracts via CREATE or CREATE2. This is typically used for factories that deploy templatized contracts, such as liquidity pools, but may also be used for "DevOps"-type support contracts.
can_transferThe contract can emit the ERC-20 / ERC-721 Transfer event.

Functions

Field: program.functions

Hashless can determine the function table for most contracts without needing a published or verified ABI (application binary interface.) This function table can be used similarly to (or converted into) an ABI in cases where you need to programmatically interface with a contract.

Note that functions do not "pass through" to proxy contracts from their implementation. To retrieve the implementation's functions, call the Get Address Details API on the address(es) returned in delegates. For this same reason, minimal proxy contracts that dispatch all functions to an implementation will have an empty functions list.

📘

Hashless determines a contract's functions by extracting function jump tables from the contract's bytecode. This means the Hashless Catalog can produce function tables (and effectively, ABIs) for most closed-source or unverified contracts as long as they use the standard Solidity-style calling convention (this is true whether they are technically implemented in Solidity, Vyper or EVM assembly.)

For similar reasons, this is also the case for most other Hashless technical data, such as Emitted Topics.

🚧

Hashless does not currently filter detected functions based on whether they are accessible by the general public or only by allowlisted addresses (for example, via Solidity function modifiers.) Access-controlled functions will generally revert if called by an address other than the authorized user.

In a future release, Hashless will detect common access control patterns and denote them in the function metadata.

Emitted Topics

Field: program.topics_emitted

Hashless can determine the topic signatures that a contract can emit. As with functions, proxies do not include the topics emitted by their implementation contract -- call the Get Address Details API on the implementation address to retrieve them.

Contract Metadata, State and Storage

Field: chain_metadata

Hashless extracts certain useful on-chain state when it detects contract deployments or upgrades. Typically this state is accessible via "getter" functions on the contract that may return either a hardcoded value or a value from Ethereum persistent storage. Metadata is returned in key-value form, where the key is typically the name of the getter function.

A partial list of extracted on-chain state supported is below.

KeyDescription
nameTypically ERC-20 token name (String)
symbolTypically ERC-20 token symbol (String)
decimalsTypically ERC-20 supported decimal precision. Use to format token quantities. (Integer)
ownerAddress of owner for ownable contracts (Address)
adminAdmin address for EIP-1967-style upgradeable proxies (Address)
beaconBeacon address for beacon-style proxies (Address)
token0, token1, etc.Address of underlying tokens in multisided DEX liquidity pools. (Address)
feeTypically the trade fee expressed as a percentage (or bips, etc.) for a liquidity pool. (Integer)

Illustrative Response

{
  "address": "0x5777d92f208679db4b9778590fa3cab3ac9e2168",
  "name": "Uniswap V3 Pool: DAI-USDC 0.01% Fee",
  "belongs_to": "Uniswap",
  "category": "Marketplace/DEX/Liquidity Pool/Uniswap V3-style",
  "contract": {
    "creator": "0xce9cde38b04b7030510190f6a5048808a2e7c7df",
    "created_by_contract": "0x1f98431c8ad98523631ae4a59f267346ea31f984",
    "created_in_transaction": "0x8ec5ce93f18d7d0c46cf371aba63baab1656b113af7a9e7a7419da9724c9add6",
    "creation_timestamp": 1636771503000,
    "bytecode_hash": "0x745c067e705970688ce6589a8f7d4512df75e9203fb8e2f1a09a07ab11dcec7b"
  },
  "program": {
    "functions": [
      {
        "selector": "0xddca3f43",
        "signature": "fee()",
        "name": "fee"
      },
      {
        "selector": "0xf3058399",
        "signature": "feeGrowthGlobal0X128()",
        "name": "feeGrowthGlobal0X128"
      },
      {
        "selector": "0xf30dba93",
        "signature": "ticks(int24)",
        "name": "ticks"
      },
     	// Additional functions...
      {
        "selector": "0x0dfe1681",
        "signature": "token0()",
        "name": "token0"
      },
      {
        "selector": "0x128acb08",
        "signature": "swap(address,bool,int256,uint160,bytes)",
        "name": "swap"
      },
      {
        "selector": "0x1a686502",
        "signature": "liquidity()",
        "name": "liquidity"
      }
    ],
    "topics_emitted": [
      "Collect(address,address,int24,int24,uint128,uint128)",
      "Swap(address,address,int256,int256,uint160,uint128,int24)",
      "IncreaseObservationCardinalityNext(uint16,uint16)",
      "Burn(address,int24,int24,uint128,uint256,uint256)",
      "CollectProtocol(address,address,uint128,uint128)",
      "Initialize(uint160,int24)"
    ]
  },
  "chain_metadata": {
    "fee": "100",
    "token0": "0x6b175474e89094c44da98b954eedeac495271d0f",
    "token1": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
  }
}

Did this page help you?