Principles
Rosetta is a universal layer for interacting with blockchains, regardless of the blockchain specifics. Rosetta standardizes and structures deployment, communication, and data formats while providing extensive flexibility to developers to innovate without needing to appeal to a gatekeeper.
Standard Data Format
The Rosetta API is specified in the OpenAPI 3.0 format. Requests and responses can be crafted with autogenerated code using Swagger Codegen or OpenAPI Generator. You can find the downloadable JSON spec in the rosetta-specifications repository in GitHub.
No Required Languages
Because all usage occurs over a JSON-based specification instead of through some specialized protocol, or relies on an SDK (with support in only a few languages), it is possible to provide an implementation of the Rosetta APIs in any language.
No Master Repository
When creating an implementation of the Rosetta APIs, there is no repository where finished implementations must be merged. Any developer can use an implementation of the Rosetta APIs for a particular blockchain if they determine it meets their needs. Multiple teams can create implementations for a given blockchain and no implementation will be given preference for gaining favor with the repository maintainer.
Universal Transactions
Transacting on blockchains today poses unique challenges. Each often requires unique context to do well. For example, recognizing and accounting for a staking transaction on-chain can involve making multiple RPC requests and combining the results of multiple data models. Constructing a staking transaction may require fetching a collection of on-chain data and an understanding of a particular SDK used to construct transactions for that particular network.
In Rosetta, a single abstraction is used to represent on-chain activity and to construct transactions. There is only one notion of an account, transaction, and transaction operation for both reading and writing from a blockchain. This single notion is used for all blockchains with Rosetta implementations.
The Data API and Construction API share a standard data format that is based on a series of low-level abstractions. These abstractions can be combined to form the building blocks of more complex operations. However, these formats are generic enough to natively support sharded blockchains, staking, and smart contracts.
Other complex operations that Rosetta's low-level abstractions simplify are transaction fees. It's complicated to represent a fee payment as a transaction property in blockchains where there is no explicit fee payer, where there are multiple fee payers, where fees can be paid in multiple currencies, or where fee payment is made by one of many parties in a transaction. This is why, with Rosetta's API, all transaction fees are represented exclusively as operations.
Sharded Blockchain Support
To support sharding, Rosetta introduces the sub-network identifier, which allows developers to specify a particular sub-network on any request to the Data API. This allows for very explicit querying of blockchain data across a vast network of shards.
Staking and Smart Contract Support
When designing Rosetta, we considered seamless interaction with staking mechanisms and powerful contracts to be a critical feature. To provide first-class support for these paradigms, the rosetta-specifications define a very expressive notion of accounts that can be used in blockchain data and in account balance queries.
In blockchains with generalized smart contracting, the notion of account state can be much more nuanced than a single token balance at a single height at a single address. The specifications introduce the sub-accounts identifier to allow developers to identify a state that is specific to a certain contract or lockup restriction (for example, a delegated stake or payment channel). It is possible to specify an account's sub-account in any block operation, in a request to get a balance, and in transaction construction.
Modules
For blockchains with smart contracts, it is usually not possible to add high fidelity support for each deployed contract to the "core" Rosetta implementation. Accessing any contract often requires generating some SDK and making very contract-specific access decisions that can introduce significant complexity into the "core" implementation.
To empower developers to build Rosetta API implementations for a given smart contract on top of your "core" implementation, we recommend implementing the /call
endpoint and providing support for common network-specific endpoints that would be used to read or modify contract state. In theory, you could stack any number of Rosetta API implementations on top of each other, where each child implementation calls some set of primitives exposed in this /call
endpoint.
In the case of Ethereum, a group of developers could implement a core rosetta-ethereum
implementation that provides the ability to track and create ETH transfers, while another group of developers could write a rosetta-erc20
that allows for tracking and creating ERC-20 token transfers using the eth_call
method exposed by rosetta-ethereum
. Another group of developers could write an implementation that tracks DEX trades, lending activity, or even validator performance. You can see an example of how this would work in the following illustration: