Skip to main content

VEP-1111: Contract indexation

VEP: 1111
author: Danil Naumov <ds0r0san@proton.me>
status: Draft
type: Contract
created: 2023-07-20

Abstract

The following standard describes the on-chain smart contracts indexing and provides basic functionality to create, search and destruct indexes.

Motivation

A common pattern in the Venom blockchain is to search for contracts with the same code by its hash. This can be useful if we want to find all contracts of the same type.

Furthermore, TVM includes an instruction to salt the contract code (tvm.setCodeSalt(code, salt)). With the knowledge of both the Index contract's source code and the associated salt parameters, it becomes possible to compute the hash code off-chain. This allows for efficient filtering of all contracts that fulfill the set criteria.

This approach finds its application in the TIP-4.3 [Non-Fungible Token on-chain indexes].

The proposition at hand aims to extend the scope of this standard to incorporate any family of contracts. By doing so, it provides a generalized standard fit for a broad range of contract families.

Specification

The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

Contracts

  • IndexFactory - Contract responsible for deploying indexes.
  • Index - Contract that store the address of the indexed contract.

IndexFactory

The IndexFactory contract is responsible for handling the deployment and uniqueness enforcement of Index contracts. It stores the Index contract code and handle the code salting process, which ensures the creation of distinct instances of each Index contract.

pragma ever-solidity >=0.62.0;

interface IIndexFactory {
/**
* @notice This event emits when Index is deployed
* @param index Index address
* @param indexedContract Indexed contract address
* @param indexCodeHash Hash of the Index code, that can be used to find Indexes with the same parameters
* @param saltKey The name of the salt parameters
* @param saltValue Parameters of the salt packed into cell
*/
event IndexDeployed(address index, address indexedContract, uint256 indexCodeHash, string saltKey, TvmCell saltValue);

/**
* @notice Returns the code of the Index contract
* @return TvmCell representing the index code of the contract
*/
function getIndexCode() external view responsible returns (TvmCell);

/**
* @notice Calculates and returns the code hash of the Index contract based on the provided salt parameters
* @param saltKey The name of the salt parameters
* @param saltValue Parameters of the salt packed into cell
* @return The calculated code hash for the Index contract
*/
function resolveIndexCodeHash(string saltKey, TvmCell saltValue) external view responsible returns (uint256);
}

IIndexFactory.getIndexCode()

function getIndexCode() external view returns (TvmCell indexCode);

Returns the address of the owner of the contract

IIndexFactory.resolveIndexCodeHash()

function resolveIndexCodeHash(string saltKey, TvmCell saltValue) external view responsible returns (uint256);
  • saltKey(string) - The name of the salt parameters
  • saltValue(TvmCell) - Parameters used to uniqueize the hash of the contract code. It can contain any set of parameters.

Calculates and returns the code hash of the Index contract based on the provided salt parameters

IIndexFactory.deployIndex()

function deployIndex(address indexedContract, string saltKey, TvmCell saltValue) internal view;
  • indexedContract(address) - Indexed contract address
  • saltKey(string) - The name of the salt parameters
  • saltValue(TvmCell) - Parameters used to uniqueize the hash of the contract code. It can contain any set of parameters.

Deploys an Index contract for a specified indexed contract and salt parameters.

To create salt, the _buildSalt function is used. It packs the salt parameters into a cell and returns it. This function MUST use IndexFactory address as the first parameter, to guarantee uniqueness of the salt between different IndexFactory contracts.

/**
* @notice Builds a TvmCell using the provided salt parameters.
* @param saltKey The name of the salt parameters
* @param saltValue Parameters of the salt packed into cell
* @return TvmCell built using the provided salt parameters.
*/
function _buildSalt(string saltKey, TvmCell saltValue) internal pure returns (TvmCell) {
TvmBuilder salt;
// salt with index factory address
salt.store(address(this));
// salt with salt key
salt.store(saltKey);
// salt with salt value
salt.store(saltValue);

return salt.toCell();
}

IIndexFactory.destructIndex()

/**
* @notice Destroys a specified Index contract and sends its remaining gas to a specified address
* @param index The address of the Index contract to be destroyed
* @param sendGasTo The address to which the remaining gas of the Index contract will be sent
*/
function destructIndex(address index, address sendGasTo) internal view virtual {
Index(index).destruct{ value: _indexDestroyValue }(sendGasTo);
}
  • index(address) - The address of the Index contract to be destroyed
  • sendGasTo(address) - The address to which the remaining gas of the Index contract will be sent

destructIndex function is used to destroy the Index contract. It sends the remaining gas of the Index contract to the specified address. This function MUST be overridden in the child contract to specify the value of the gas to be sent to the Index contract.

Index

The Index contract is responsible for storing the address of the indexed contract. Its code hash can be restored provided the parameters used for code salting are known. Thus, by knowing these parameters, all Index contracts that satisfy these parameters can be located. Furthermore, by knowing the address of the Index contract, the address of the desired contract can be retrieved. This facilitates efficient contract management and accessibility within the blockchain environment.

pragma ever-solidity >=0.62.0;

pragma AbiHeader expire;
pragma AbiHeader pubkey;

interface IIndex {
/**
* @notice Get indexed contract
* @return address of the indexed contract
*/
function getIndexedContract() external view responsible returns (address);

/**
* @notice Get IndexFactory address
* @return address of the IndexFactory contract
*/
function getIndexFactory() external view responsible returns (address);

/**
* @notice Get code hash
* @return hash of the code
*/
function getCodeHash() external view responsible returns (uint256);

/**
* @notice Destruct the contract
* @param gasReceiver Address to receive leftover gas from the destructed contract
*/
function destruct(address gasReceiver) external;
}

Static variables

Static variables form a part of the InitState and therefore affect the contract's address.

address static _indexedContract;
uint256 static _saltHash;

_indexedContract(address) - Indexed contract address. _saltHash(uint256) - Hash of the salt parameters used to create the Index contract. Since the salt always incorporates the IndexFactory's address, including the salt hash allows for the unique differentiation of Index contract addresses between various IndexFactory contracts.

IIndex.getIndexedContract()

function getIndexedContract() external view returns (address);

Returns indexed contract address

IIndex.getIndexFactory()

function getIndexFactory() external view returns (address);

Returns IndexFactory address

IIndex.getCodeHash()

function getCodeHash() external view returns (uint256);

Returns Index code hash

IIndex.destruct()

function destruct(address gasReceiver) external;
  • sendGasTo(address) - The address to which the remaining gas of the Index contract will be sent

Destroys the Index contract and sends its remaining gas to a specified address

Rationale

The primary rationale for this extension arises from the recurring pattern in the Venom blockchain, where contracts of the same type are frequently searched based on their shared code hash. Such an approach is often essential when identifying all instances of a specific contract type is required.

However, this approach becomes limited when contracts have salted codes, leading to different hash codes. But, if both the Index contract's source code and the associated salt parameters are known, it becomes possible to calculate the hash code off-chain. This capability can significantly enhance the efficiency of the search process, allowing for precise filtering of all contracts matching the set criteria. This is particularly applicable in scenarios that require a broad range of contracts to be identifiable by their common characteristics or functionalities, thus necessitating an efficient and robust filtering process.

Considering the above, this proposal advocates for the generalization of the TIP-4.3 [Non-Fungible Token on-chain indexes] standard. By extending the scope of this standard to accommodate any family of contracts, it paves the way for a more flexible, efficient, and generalized approach to contract identification and filtering on the Venom blockchain. The aim is to create a standard that caters to the requirements of a diverse range of contract families, thereby enhancing the overall functionality and usability of the Venom blockchain.

Copyright and related rights waived via CC0.

References