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.
| Category | Description |
|---|---|
Marketplace/DEX/Liquidity Pool/Uniswap V3-style | Uniswap 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-style | Uniswap 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/Token | An 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/NFT | An 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/veToken | A 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 proxiesIn 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:
| Feature | Description |
|---|---|
includes_logs | Contract can emit events. |
includes_delegatecall | Contract can delegate, i.e. is a proxy. |
includes_selfdestruct | Contract 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_create | Contract 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_transfer | The 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.
| Key | Description |
|---|---|
name | Typically ERC-20 token name (String) |
symbol | Typically ERC-20 token symbol (String) |
decimals | Typically ERC-20 supported decimal precision. Use to format token quantities. (Integer) |
owner | Address of owner for ownable contracts (Address) |
admin | Admin address for EIP-1967-style upgradeable proxies (Address) |
beacon | Beacon address for beacon-style proxies (Address) |
token0, token1, etc. | Address of underlying tokens in multisided DEX liquidity pools. (Address) |
fee | Typically 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"
}
}Updated about 1 year ago