Rotating Voting Keys
Similarly to how the membership group can rotate the keys in the cold NFT, the delegation group can rotate the voting keys in the hot NFT.
Step 1: Creating the assets
In this example, we are going to add child-7’s key back to the voting group and remove child-8.
As usual, use orchestrator-cli to prepare the transaction assets:
$ fetch-hot-nft-utxo
$ orchestrator-cli rotate-hot \
--utxo-file hot-nft.utxo \
--voting-cert example-certificates/child-7.cert \
--voting-cert example-certificates/child-9.cert \
--out-dir rotate-hot
As before, let’s see what assets were prepared:
$ ls rotate-hot -1
datum.json
redeemer.json
value
We have the familiar datum.json, redeemer.json, and value files:
$ diff <(jq 'to_entries | .[0].value.inlineDatum' < hot-nft.utxo) <(jq '.' < rotate-hot/datum.json)
7c7
< "bytes": "c6d6ffd8e93b1b8352c297d528c958b982098dc8a08025bbb8d864cf"
---
> "bytes": "c6731b9c6de6bf11d91f08099953cb393505806ff522e5cc3a7574ab"
10c10
< "bytes": "e3340359f5d25c051e4dd160e4cb4d75074c537905f07eb9a2e24db881246ee0"
---
> "bytes": "e50384c655f9a33cabf64e41df7282e765a242aef182130f1db01bce8859e0aa"
In the datum, child-7 has been added back, and child-8 has been removed.
The redeemer is less interesting, as it takes no arguments:
cat rotate-hot/redeemer.json
{
"constructor": 9,
"fields": []
}
Step 2: Create the Transaction
This is the first instance of the delegation group needing to sign off on a hot NFT script action. The attentive reader will have noticed that the hot NFT datum does not include the delegation group however, so it would be reasonable to ask how the script knows who is in the delegation group?
Recall that when we initialized the hot NFT script, we provided the cold NFT’s policy ID as a parameter. When it needs the delegation group to sign the transaction, the hot NFT script uses this information to look for the current cold NFT script output in the transaction’s reference inputs. It can decode the datum from this reference input to get the current delegation group. As such, we need to include this input as a reference input when building the transaction. Otherwise, it is the same as it was for cold-nft rotate.
$ tx-bundle build \
--tx-in "$(get-orchestrator-ada-only | jq -r '.key')" \
--tx-in-collateral "$(get-orchestrator-ada-only | jq -r '.key')" \
--read-only-tx-in-reference $(cardano-cli query utxo --address $(cat init-cold/nft.addr) --output-json | jq -r 'keys[0]') \
--tx-in $(cardano-cli query utxo --address $(cat init-hot/nft.addr) --output-json | jq -r 'keys[0]') \
--tx-in-script-file init-hot/nft.plutus \
--tx-in-inline-datum-present \
--tx-in-redeemer-file rotate-hot/redeemer.json \
--tx-out "$(cat rotate-hot/value)" \
--tx-out-inline-datum-file rotate-hot/datum.json \
--required-signer-group-name delegation \
--required-signer-group-threshold 2 \
--required-signer-hash $(orchestrator-cli extract-pub-key-hash example-certificates/child-1.cert) \
--required-signer-hash $(orchestrator-cli extract-pub-key-hash example-certificates/child-2.cert) \
--required-signer-hash $(orchestrator-cli extract-pub-key-hash example-certificates/child-3.cert) \
--required-signer-hash $(orchestrator-cli extract-pub-key-hash example-certificates/child-7.cert) \
--change-address $(cat orchestrator.addr) \
--out-file rotate-hot/body.txbundle
Estimated transaction fee: Coin 528607
Recall that in the previous section, we swapped the membership and delegation roles, so child-1 through child-3 are now in the delegation group.
As before, any added members need to sign the transaction too.
Since we are adding child-7 to the voting group, they need to sign as well.
This is also the first time we’ve seen tx-bundle used to create a
transaction with more than one signing group. In this case, two groups of
signatures are needed: any two of the three delegators, and all the new voters
who were added in the rotation.
Step 3. Distribute the Transaction to Signatories
$ cc-sign -q \
--tx-bundle-file rotate-hot/body.txbundle \
--private-key-file example-certificates/children/child-1/child-1.private \
--out-file rotate-hot/child-1.witbundle
$ cc-sign -q \
--tx-bundle-file rotate-hot/body.txbundle \
--private-key-file example-certificates/children/child-2/child-2.private \
--out-file rotate-hot/child-2.witbundle
$ cc-sign -q \
--tx-bundle-file rotate-hot/body.txbundle \
--private-key-file example-certificates/children/child-7/child-7.private \
--out-file rotate-hot/child-7.witbundle
$ tx-bundle witness \
--all \
--tx-bundle-file rotate-hot/body.txbundle \
--signing-key-file orchestrator.skey \
--out-file rotate-hot/orchestrator.witbundle
Step 4. Assemble and Submit the Transaction
$ tx-bundle assemble \
--tx-bundle-file rotate-hot/body.txbundle \
--witness-bundle-file rotate-hot/child-1.witbundle \
--witness-bundle-file rotate-hot/child-2.witbundle \
--witness-bundle-file rotate-hot/child-7.witbundle \
--witness-bundle-file rotate-hot/orchestrator.witbundle \
--out-file rotate-hot/tx.json
$ cardano-cli conway transaction submit --tx-file rotate-hot/tx.json
Transaction successfully submitted.
Step 5. Verify the change on chain
$ cardano-cli conway query utxo --address $(cat init-hot/nft.addr) --output-json
{
"7c96fe0d24c5bcc398c051569a5a079b1242ec8d6f18eede663f9fd6c4f54eac#0": {
"address": "addr_test1wzn8zkvkvaex4nnvften2aejpgt3calqwmgmrzwj95vukcs0map8t",
"datum": null,
"inlineDatum": {
"list": [
{
"constructor": 0,
"fields": [
{
"bytes": "c6731b9c6de6bf11d91f08099953cb393505806ff522e5cc3a7574ab"
},
{
"bytes": "e50384c655f9a33cabf64e41df7282e765a242aef182130f1db01bce8859e0aa"
}
]
},
{
"constructor": 0,
"fields": [
{
"bytes": "2faaa04cee79d9abfa3149c814617e860567a8609bbfbd044566a5cd"
},
{
"bytes": "ae8eef56d67350b247ab77be48dad121ae18d473386f59b3fda9fccbd665422a"
}
]
}
]
},
"inlineDatumhash": "78e128e204031b114f7e3b3b4f4de71b547d5189d6166a3b43370a13bbe9fba5",
"referenceScript": null,
"value": {
"bf3bbf5a8539663eddd53364a9fd90e468c0182fcf6f0642ac16d65f": {
"93fdf1b28aefd28ed13b268653c03dd86872063d58434a2c83d68e6c2301": 1
},
"lovelace": 5000000
}
}
}