Tezos Protocol upgrades commonly introduce new operations. Mumbai introduces Smart Rollup operations on L1. Here are examples of operations that have been added in the past:
- Lima
Update_consensus_key
Drain_delegate
- Kathmandu
Increase_paid_storage
- Ithaca
Preendorsement
Double_preendorsement_evidence
Set_deposits_limit
There are many reasons why new operations are included. Sometimes, an operation affects the network in general. Sometimes, an operation affects a specifc manager account.
Let’s take a fictitious dummy example: some Tezos accounts participate in a random draw. At the beginning of every cycle, the protocol picks an account from the list and stores its address in a special place in the context as a winner. You can query the winner with a RPC call.
You can do that with a smart contract; that’s not the point. Here, we want to make a meta-point about protocol development. So, let’s say there is special protocol code dedicated to picking a winner.
How do we want accounts to register to this draw? We can create operations Register_draw
and Unregister_draw
: operations are sent to the mempool and included into blocks.
But adding new operations to the protocol is expensive:
- new encodings need to be created
- libraries need to add support
- indexers need to parse them
Also, only manager accounts can send an operation. If we want smart contracts to be able to participate in the draw, a change in michelson is required as well.
A different semantic for interacting with the protocol are virtual contracts. Similar to precompiled contracts on Ethereum, virtual contracts have a fixed address on-chain. For example KT1000000000000000000000000000000001
could be a virtual contract. It has two entrypoints register()
and unregister()
. No token transfer is required to call these entrypoints.
Calling these contracts is functionally equivalent to calling a new operation:
- contract parameters are operation parameters
- a rejected operation is a backtracked contract
What are the benefits?
First, it makes it easier on the library developers such as Taquito: an operation may not affect the library, but they still have to add logic to allow sending it. If it’s a virtual contract, is it de facto supported. The same goes for wallet developers: wallets already support contract calls and would have no problem calling a special address.
Second, it’s more composable: indeed, you can have other smart contracts call this contract. But only if it makes sense. You can as well make sure that any such call will be backtracked.
An example where it makes sense is the cobaking operation: instead of two new operations cobake/uncobake, you simply call a virtual contract with two entrypoints cobake/uncobake and a value as a parameter. Contracts can also call them.
Any future protocol features that pertain to only one manager account can be represented with such virtual contracts, with each contract associated with an unique increasing address.
When virtual contracts exist, the only way to interact with the protocol feature that they represent is to run the TRANSFER_TOKENS
Michelson instruction. This instruction is therefore poorly named, as the relevant part of it is not the transfer, but its effects.