How to Change the Liquidity Baking Asset Pair

Sophia Gold
The Aleph
Published in
4 min readAug 24, 2021

Some members of the Tezos community have proposed alternative assets to tzBTC to trade against tez in the liquidity baking market making contract. Since any baker can inject a protocol proposal, we’ve prepared this short guide on how to modify the protocol to change the token used in liquidity baking. It turns out it’s pretty easy!

This covers only how to modify the protocol itself. Ideally, developers should update the protocol documentation as well as any relevant tests (although we do not believe any of the tests included with Granada should break due to changing the LB token contract).

How to version, hash, test, and inject a protocol is also outside our scope. For information on this please refer to the relevant documentation.

Token Contract Requirements

While certain properties are desirable for an asset used in liquidity baking, e.g. depth of liquidity and price correlation with tez, all that is required of the actual token contract is that it is FA1.2 compliant. Please refer to the FA1.2 standard in TZIP-7 for more information as well as a reference contract in Michelson. Another example of an FA1.2 compliant token contract is the liquidity baking LQT contract. In fact, this is used on test networks as a stand-in for the mainnet token contract.

We would also like to note that it’s ideal for the token contract to have gone through a third-party security audit.

FA2 Support

Although the current liquidity baking CPMM only supports FA1.2 tokens, the Dexter 2.0 contract from which it was adapted does have a version that supports FA2 tokens. We leave how to change the CPMM script used in liquidity baking as an exercise for the reader, or perhaps a subject for a future blog post.

Originating a New Exchange Contract

Recall that the liquidity baking exchange and LQT contracts were originated by the protocol itself during Granada activation. At this time, the exchange contract’s address was initialized in storage. At the beginning of every block, an operation is applied to this address that credits the tez subsidy and executes the contract’s %default entrypoint in order to update its xtz_pool value in storage.

Therefore, all that needs to be done to change the token is to originate the exchange and LQT contracts again at different addresses and with a different token contract address in the exchange contract’s storage. Then, the tzBTC liquidity pool will remain, a new one with the new pair will be created, and the liquidity baking subsidy will be automatically redirected to the latter.

The Tezos protocol contains a module Init_storage with a function that prepares the first block of a protocol depending on whether it was activated from the Genesis protocol or the current mainnet protocol. In Granada, you’ll see the following lines at the end of both branches:

(* Must be called after other originations since it unsets the origination nonce.*)
Liquidity_baking_migration.init ctxt ~typecheck
>>=? fun (ctxt, operation_results) ->
Storage.Pending_migration.Operation_results.init ctxt operation_results

Liquidity_baking_migration.init takes the context and Michelson typechecker, originates the LB contracts, initializes the exchange address in storage, and returns operation results for the originations. The operation results are then initialized in storage.

Jumping to this function’s definition, we see the first thing it does is initialize a custom origination nonce using a string at line 172:

let init ctxt ~typecheck =
(* We use a custom origination nonce because it is unset when stitching from 009 *)
let nonce =
Operation_hash.hash_bytes [Bytes.of_string “Drip, drip, drip.”]
in
let ctxt = Raw_context.init_origination_nonce ctxt nonce in

Origination nonces are used to generate addresses for contracts originated in each block according to their order of origination. Using a custom nonce for the liquidity baking contracts allows us to know their addresses before they’re originated and makes it so that the addresses are the same on mainnet as on test networks.

This origination nonce must be changed when changing the liquidity baking asset so that the protocol originates the new exchange and LQT contracts at new addresses. Any vanity string less than or equal to 64 bytes can be used as long as it is different from the Granada liquidity baking nonce “Drip, drip, drip.” and the bootstrap nonce “Un festival de GADT.”.

You may have noticed we use the same init function for mainnet and test networks. On mainnet it originates only the exchange and LQT contracts and uses the tzBTC address as the token address in the exchange contract’s storage, whereas on test networks it additionally originates a test token contract using the same Michelson script as the LQT and uses this address as the token address in the exchange contract’s storage.

Since we need to test protocols migrating from both Genesis and the previous mainnet protocol, we cannot rely on the previous protocol to tell us whether we’re on mainnet. The chain id is not exposed inside the protocol so instead we call a function check_tzBTC that first checks for the existence of the tzBTC contract using the address at line 56:

let mainnet_tzBTC_address = “KT1PWx2mnDueood7fEmfbBDKx1D9BAnnXitn”

and, if found, returns this address to be used as the token address in the exchange contract’s storage. This is the second line that must be changed in order to change the address. If this contract is not found, we then check that the level is sufficiently low as an extra guarantee we’re not on mainnet before originating the test token contract and using that as the token address in the exchange contract’s storage.

Conclusion

As we’ve shown, changing the asset used in liquidity baking requires only changing two strings in the Granada protocol: the mainnet token contract address and the liquidity baking origination nonce. We encourage anyone interested in alternative assets for liquidity baking to try this themselves.

--

--