Flextesa: Adaptive Issuance

Phillip Saxton
The Aleph
Published in
4 min readSep 19, 2023

The latest release of Flextesa now includes options for testing adaptive issuance in a local sandbox environment.

Introduced in the Oxford protocol proposal, Adaptive Issuance differs from the typical protocol upgrade features. Its activation depends on the outcome of separate a feature activation vote. Therefore, its activation isn’t guaranteed. A detailed explanation of Adaptive Issuance can be found in Tezos documentation.

“LEGO accountant” by Pest15 is licensed under CC BY-SA 2.0.

Flextesa now offers users the capability to simulate and test Adaptive Issuance in a sandbox setting, potentially shaping their vote. This guide demonstrates how to test Adaptive Issuance in a Flextesa sandbox, operating in a docker container. The release image, oxheadaplha/flextesa:20230915, and its included scripts (nairobibox, oxfordbox and alphabox) provide two new commands for testing adaptive issuance. Refer to the Flextesa repository for their implementations and documentation.

Note: Only the Oxford and alpha protocols support adaptive issuance.

The start_adaptive_issuance Command.

In this sandbox, all bakers cast an “on” vote for the “Adaptive Issuance Vote.” Additionally, the activation threshold is set to 1. This ensures that Adaptive Issuance is activated by the end of the first cycle and launches a few cycles later.

$ image=oxheadalpha/flextesa:20230915
$ docker run --rm --name my-sandbox --detach \
-e block_time=3 \
"$image" oxfordbox start_adaptive_issuance

After its activation, adaptive issuance will launch five cycles later. Issuance modifications will take effect a few cycles after this initial launch.

To interact with the sandbox, create an alias for the octez-client, already configured within the container.

$ alias tcli='docker exec my-sandbox octez-client'

Using the tcli command, find the launch cycle and view the expected issuance for upcoming cycles.

$ tcli rpc get /chains/main/blocks/head/context/adaptive_issuance_launch_cycle
5
$ tcli rpc get /chains/main/blocks/head/context/issuance/expected_issuance | jq
[
{
"cycle": 6,
"baking_reward_fixed_portion": "999999",
"baking_reward_bonus_per_slot": "3906",
"attesting_reward_per_slot": "7812",
"liquidity_baking_subsidy": "249999",
"seed_nonce_revelation_tip": "781",
"vdf_revelation_tip": "781"
},
{
"cycle": 7,
"baking_reward_fixed_portion": "999999",
"baking_reward_bonus_per_slot": "3906",
"attesting_reward_per_slot": "7812",
"liquidity_baking_subsidy": "249999",
"seed_nonce_revelation_tip": "781",
"vdf_revelation_tip": "781"
},
{
"cycle": 8,
"baking_reward_fixed_portion": "587510",
"baking_reward_bonus_per_slot": "2294",
"attesting_reward_per_slot": "4589",
"liquidity_baking_subsidy": "146877",
"seed_nonce_revelation_tip": "458",
"vdf_revelation_tip": "458"
}
]

Here issuance changes occur on cycle 8.

The Staking Mechanism

Preparing a Baker for Accepting Stakers

By default, bakers won’t accept co-stakers. You can see this in the active_staking_parameters.

First, record the baker’s public key hash:

$ tcli show address baker0
Hash: tz1YPSCGWXwBdTncK2aCctSZAXWvGsGwVJqU
Public Key: edpkuTpUWcNgn4QYcBVGDLy6rmpJ3WSTSV2bdiJFwyoDk5fSwxyV5k
$ baker_hash=tz1YPSCGWXwBdTncK2aCctSZAXWvGsGwVJqUsh

Now check the active_staking_parameter.

$ tcli rpc get "chains/main/blocks/head/context/delegates/${baker_hash}/active_staking_parameters" | jq
{
"limit_of_staking_over_baking_millionth": 0,
"edge_of_baking_over_staking_billionth": 1000000000
}

Now set the limit-of-staking-over-baking to 5. This change will take effect after 3 cycles.

$ tcli set delegate parameters for baker0 --limit-of-staking-over-baking 5 --edge-of-baking-over-staking 1
...
$ tcli rpc get "chains/main/blocks/head/context/delegates/${baker_hash}/active_staking_parameters" | jq
{
"limit_of_staking_over_baking_millionth": 5000000,
"edge_of_baking_over_staking_billionth": 1000000000
}

Now baker0 is ready to accept co-stakers.

Staking Tez with the Baker

In this sandbox you’ll find two bootstrap accounts, alice and bob, neither of which are staking. Create a new account and fund it by transferring tez from one of the bootstrap accounts.

$ tcli gen keys staker
...
$ tcli get balance for alice
1900000
$ tcli transfer 1000001 from alice to staker --burn-cap 1
...

Once the new account is funded, staking is a two step process. First, set the delegate for the staker, followed by "staking".

$ tcli set delegate for staker to baker0
...
$ tcli stake 1000000 for staker
...
$ tcli get balance for staker
0.998943 ꜩz

With the stake balance is frozen, the free balance has been reduced. Furthermore, by transferring some non-staked tez from alice and staking those funds, the total stake amount increases, causing a shift in total issuance.

$ tcli rpc get /chains/main/blocks/head/context/issuance/expected_issuance | jq
[
{
"cycle": 110,
"baking_reward_fixed_portion": "587521",
"baking_reward_bonus_per_slot": "2294",
"attesting_reward_per_slot": "4589",
"liquidity_baking_subsidy": "146880",
"seed_nonce_revelation_tip": "458",
"vdf_revelation_tip": "458"
},
{
"cycle": 111,
"baking_reward_fixed_portion": "218960",
"baking_reward_bonus_per_slot": "855",
"attesting_reward_per_slot": "1710",
"liquidity_baking_subsidy": "54739",
"seed_nonce_revelation_tip": "171",
"vdf_revelation_tip": "171"
},
{
"cycle": 112,
"baking_reward_fixed_portion": "218960",
"baking_reward_bonus_per_slot": "855",
"attesting_reward_per_slot": "1710",
"liquidity_baking_subsidy": "54739",
"seed_nonce_revelation_tip": "171",
"vdf_revelation_tip": "171"
}
]

Unstaking from baker0 will follow a two-step process. After the initial “unstake” operation, the staked balance remains frozen for 5 cycles (7 on mainnet). You can check the cycle number while you wait for the necessary cycle. Then, finalize the unstake.

$ tcli unstake everything for staker
...
$ tcli rpc get "/chains/main/blocks/head/metadata" | jq .level_info.cycle
120
$ tcli finalize unstake for staker0
...
$ tcli get balance for staker
3599999.997503

The start_upgrade_with_adaptive_issuance command.

This command is similar to the start_adaptive_issuance but differs in that the sandbox network undergoes a complete governance upgrade before activating adaptive issuance.

Use the command:

$ docker run --rm --name my-sandbox --detach \
-e block_time=3 \
"$image" oxfordbox start_upgrade_with_adaptive_issuance

Once the protocol has upgraded from Oxford to Alpha, replicate the staking steps as outlined above.

A note on nairobibox: to expedite the activation of adaptive issuance, the protocol constant adaptive_issuance_ema_threshold is set to 1. This facilitates immediate activation in most tests, with a singular exception: it's not possible to adjust protocol constants for a future protocol. Thus, when using the command start_upgrade_with_adaptive_issuance combined with the nairobibox script, after upgrading to the Oxford protocol, the adaptive_issuance_ema_threshold will be determined by the protocol.

To verify its value, use:

$ tcli rpc get /chains/main/blocks/head/context/constants | jq .adaptive_issuance_launch_ema_threshold
100000000

This means that activating adaptive issuance on nairobibox@ will require more than an hour with one second block times and possibly several hours with longer block-times.

Conclusion

By integrating this feature we aim to help users better familiarize themselves with Adaptive Issuance. For more information on Flextesa and its varied uses, please visit the repository.

--

--