Validator Owner Badge Access Management

At the time of writing, and prior to multi-sig support for the Radix wallet, validator owner management requires the signer to have soul possession of the Validator Owner Badge - an NFT that conveys the authorisation to update validator fees, change metadata and registration/deregistration.

I have provided a thread here (Validator Transaction Manifests) that details some of the common manifest instructions for managing a validator for reference.

This approach of having a single validator badge raises a specific problem -

How does a validator owner delegate the management of their node to a third party, such as a business partner, friend or indeed another node-runner?

The purpose of this post is to introduce an Access Management Component, built by Ahmed, owner of the RadixPlanet node which we have tested and incorporated into the Planet Node, allowing us to both manage the validator.

In simple terms, the Access Management Component requires the node-owner to deposit the Owner Badge into the component, and then mint any number of ‘Access Key’ badges which can be used as the authorisation for the component to perform the validator actions.

This allows multiple users to interact with the validator methods, but gives the node-owner ultimate control of the validator owner badge, as it’s withdrawal is restricted to the holder of the ‘Access Management Component Owner’ badge. This component owner badge can also recall, mint and burn ‘Access Key’ badges if permission needs to be revoked for any reason.

Note: The primary use case of this component is for managing validator owner badges, but it can be used for any case where a single NFT is required for performing actions (such as token minting authority for example).

Usage

Note: the Github repo containing the source code can be found here: Github Link

The blueprint package address for mainnet is as follows:

package_rdx1p4m04kkm8tw3fefwrf7zvgxjw8k0n9t30vawgq2kl90q3r77nf59w8
  1. Firstly, we must create a new component to hold our validator owner badge. Use the following manifest with the package address above to do so:
CALL_FUNCTION
    Address("package_rdx1p4m04kkm8tw3fefwrf7zvgxjw8k0n9t30vawgq2kl90q3r77nf59w8")
    "AccessManager"
    "new"
    Address("resource_rdx1nfxxxxxxxxxxvdrwnrxxxxxxxxx004365253834xxxxxxxxxvdrwnr")
    Address("account_rdx128zppem3e77cwc7j9faw0j79rd627vflvt7mkqgahx728chplp2rey");

CALL_METHOD 
Address("account_rdx128zppem3e77cwc7j9faw0j79rd627vflvt7mkqgahx728chplp2rey") 
"deposit_batch" 
Expression("ENTIRE_WORKTOP");

This manifest creates a new Access Manager component, and we have specified the validator owner badge resource address, along with the account that is to be designated as owner. On submitting this tx, an ‘Access Manager Owner’ badge will be deposited to the owner’s account.

Once the tx is confirmed, review the tx details in the dashboard and observe the ‘created entities’ in the details tab. Here you can find the address of the newly created component. In this example, the component address is:

component_rdx1crkh4nn47vug24t26xfp6sqt28acx8qtwk9sg73rcn5tht5d34a860
  1. Once the component is created, the next step is to deposit the validator owner badge into the component. The manifest to do this is as follows:
CALL_METHOD 
Address("account_rdx128zppem3e77cwc7j9faw0j79rd627vflvt7mkqgahx728chplp2rey") 
"withdraw_non_fungibles" 
Address("resource_rdx1nfxxxxxxxxxxvdrwnrxxxxxxxxx004365253834xxxxxxxxxvdrwnr") 
Array<NonFungibleLocalId>(NonFungibleLocalId("[8361508c284bc2aa0795a1d28ae8f37146b701bd7390575697425eb2d08d]"));

TAKE_NON_FUNGIBLES_FROM_WORKTOP 
Address("resource_rdx1nfxxxxxxxxxxvdrwnrxxxxxxxxx004365253834xxxxxxxxxvdrwnr") 
Array<NonFungibleLocalId>(NonFungibleLocalId("[8361508c284bc2aa0795a1d28ae8f37146b701bd7390575697425eb2d08d]")) 
Bucket("auth_badge_bucket");

CALL_METHOD 
Address("account_rdx128zppem3e77cwc7j9faw0j79rd627vflvt7mkqgahx728chplp2rey") 
"create_proof_of_non_fungibles" 
Address("resource_rdx1n2r24wvth7ul7jjqtnpm6s9a52lfq7a32lx6ez9chrjq4mgsp8cf6e") 
Array<NonFungibleLocalId>(NonFungibleLocalId("{6f654d2d58611380-a3b3b32537ca549f-02b25f6411497e41-b1de3f49f2dadedb}"));

CALL_METHOD
    Address("component_rdx1crkh4nn47vug24t26xfp6sqt28acx8qtwk9sg73rcn5tht5d34a860")
    "deposit_auth_badge"
    Bucket("auth_badge_bucket");

This manifest withdraws the validator owner badge from the account and places it into a bucket. It then creates a proof of the ‘Access Manager Owner’ badge created in step 1, before calling a method on the ‘Access Manager’ component to deposit the validator owner badge.

Once the tx is confirmed, the Validator Owner badge will now be deposited into the component.

  1. In order to interact with the Validator Owner badge through the component, we need to create any number of ‘Access Key’ badges. These badges can be provided to anyone whom we wish to delegate the control of the validator to. To create an ‘Access Key’ badge, the following manifest is used:
CALL_METHOD 
Address("account_rdx128zppem3e77cwc7j9faw0j79rd627vflvt7mkqgahx728chplp2rey") 
"create_proof_of_non_fungibles" 
Address("resource_rdx1n2r24wvth7ul7jjqtnpm6s9a52lfq7a32lx6ez9chrjq4mgsp8cf6e") 
Array<NonFungibleLocalId>(NonFungibleLocalId("{6f654d2d58611380-a3b3b32537ca549f-02b25f6411497e41-b1de3f49f2dadedb}"));

CALL_METHOD
Address("component_rdx1crkh4nn47vug24t26xfp6sqt28acx8qtwk9sg73rcn5tht5d34a860")
    "create_access_key_badge";

CALL_METHOD 
Address("account_rdx12yugeppnu2sul2qnry7nscpc9aglm922ygzkvvplp37p3rwvr4z7xz") 
"try_deposit_batch_or_abort" 
Expression("ENTIRE_WORKTOP") 
None;

The manifest above provides a proof of the ‘Access Manager Owner’ badge, in order to mint a new access key badge by the component. This is then deposited into the delegates account, in this example, account_rdx12yugeppnu2sul2qnry7nscpc9aglm922ygzkvvplp37p3rwvr4z7xz

  1. Once the validator owner badge is in the component and your delegated validator managers have an ‘Access Key’ badge, they can then conduct any actions on the validator using the proof of this key badge. In order to do this, the following manifest should be used in conjunction with any of the standard validator manifests:
CALL_METHOD 
Address("account_rdx12yugeppnu2sul2qnry7nscpc9aglm922ygzkvvplp37p3rwvr4z7xz") 
"create_proof_of_non_fungibles" 
Address("resource_rdx1n2ufdpyuundgtu68nvfdygyj74n7sqs32lsu76smvnt8j3v9976tmw") 
Array<NonFungibleLocalId>(NonFungibleLocalId("{33a834fe1e62c7ce-d5ed40abff224b74-6dd84f924959af76-d78010d7932dd06b}"));

CALL_METHOD
    Address("component_rdx1crkh4nn47vug24t26xfp6sqt28acx8qtwk9sg73rcn5tht5d34a860")
    "create_auth_badge_proof";

The above manifest provides a proof of the ‘Access Key’ badge and presents it to the component. This will then allow the validator actions to be performed by the component itself. The above manifest can be used in conjunction with any of the validator manifest actions detailed in the Validator Transaction Manifest thread. For example, if we want to update the validator’s fee, we would combine the manifest above with the “update_fee” method to give:

CALL_METHOD 
Address("account_rdx12yugeppnu2sul2qnry7nscpc9aglm922ygzkvvplp37p3rwvr4z7xz") 
"create_proof_of_non_fungibles" 
Address("resource_rdx1n2ufdpyuundgtu68nvfdygyj74n7sqs32lsu76smvnt8j3v9976tmw") 
Array<NonFungibleLocalId>(NonFungibleLocalId("{33a834fe1e62c7ce-d5ed40abff224b74-6dd84f924959af76-d78010d7932dd06b}"));

CALL_METHOD
    Address("component_rdx1crkh4nn47vug24t26xfp6sqt28acx8qtwk9sg73rcn5tht5d34a860")
    "create_auth_badge_proof";

CALL_METHOD
    Address("validator_rdx1sds4prpgf0p25pu458fg468nw9rtwqdawwg9w45hgf0t95yd3ncs09")
    "update_fee"
    Decimal("0.0199");

From the manifest above, we can see that instead of providing a proof of the validator owner badge (as is normally the case), we are providing a proof of the ‘Access Key’ to the component before calling the method to update the fee on the validator.

As you can hopefully see from the example above, this blueprint allows teams to share the responsibility for managing a validator, without having to pass the owner badge between signers. This is particularly useful in the case where an automatic failover might need the use of a hot wallet, whilst safeguarding the custody of the validator owner badge. The ‘Access Key’ badge can be held by the hot wallet and call the component methods, whereas the ‘Access Manager Owner’ badge can be secured separately in a hardware wallet.

Whilst the example shown here relates to validator management, this blueprint can be used wherever a single NFT providing authorisation to component methods needs to be delegated to multiple users.

Revoking Access

Naturally it may be necessary to revoke access to the validator. This is made possible as the ‘Access Key’ badges are recallable by the ‘Access Manager Owner’ badge. Access Keys can also be burned if required. The example below shows how an ‘Access Key’ badge can be recalled and burned.

  1. Firstly, the vault containing the ‘Access Key’ badge needs to be determined. This is obtained using the following Gateway API end point with the body shown:
https://mainnet.radixdlt.com/state/entity/page/non-fungible-vaults/
{
  "address": "account_rdx12yugeppnu2sul2qnry7nscpc9aglm922ygzkvvplp37p3rwvr4z7xz",
  "resource_address": "resource_rdx1n2ufdpyuundgtu68nvfdygyj74n7sqs32lsu76smvnt8j3v9976tmw"
}

Note: for full details of this Gateway API call, refer to the Gateway documentation

The above API call returns the vault address containing the ‘Access Key’ badge. In this example, the vault is:

internal_vault_rdx1nzk0lnsld67t4vwzg2345ad03am5tnnw8rgeztt2czs8v4h72hcfga
  1. In order to now recall and burn this ‘Access Key’ badge, the following manifest should be used:
CALL_METHOD 
Address("account_rdx128zppem3e77cwc7j9faw0j79rd627vflvt7mkqgahx728chplp2rey") 
"create_proof_of_non_fungibles" Address("resource_rdx1n2r24wvth7ul7jjqtnpm6s9a52lfq7a32lx6ez9chrjq4mgsp8cf6e") 
Array<NonFungibleLocalId>(NonFungibleLocalId("{6f654d2d58611380-a3b3b32537ca549f-02b25f6411497e41-b1de3f49f2dadedb}"));

CALL_METHOD
    Address("component_rdx1crkh4nn47vug24t26xfp6sqt28acx8qtwk9sg73rcn5tht5d34a860")
    "recall_key_badge"
    Address("internal_vault_rdx1nzk0lnsld67t4vwzg2345ad03am5tnnw8rgeztt2czs8v4h72hcfga");

TAKE_NON_FUNGIBLES_FROM_WORKTOP 
    Address("resource_rdx1n2ufdpyuundgtu68nvfdygyj74n7sqs32lsu76smvnt8j3v9976tmw") 
Array<NonFungibleLocalId>(NonFungibleLocalId("{33a834fe1e62c7ce-d5ed40abff224b74-6dd84f924959af76-d78010d7932dd06b}")) 
Bucket("access_key_badge_bucket");

CALL_METHOD
    Address("component_rdx1crkh4nn47vug24t26xfp6sqt28acx8qtwk9sg73rcn5tht5d34a860")
    "burn_key_badge"
    Bucket("access_key_badge_bucket");

The manifest above creates a proof of the ‘Access Manager Owner’ badge and presents this to the component. The “recall_key_badge” method is used with the internal vault address we determined in the previous step which passes the ‘Access Key’ badge into a bucket. Finally, the “burn_key_badge” method is called which destroys the ‘Access Key’ badge.

Retrieval of the Validator Owner Badge

  1. In the case that the validator owner badge needs to be retrieved from the component and returned to the validator owner, the following manifest can be used:
CALL_METHOD 
Address("account_rdx128zppem3e77cwc7j9faw0j79rd627vflvt7mkqgahx728chplp2rey") 
"create_proof_of_non_fungibles" Address("resource_rdx1n2r24wvth7ul7jjqtnpm6s9a52lfq7a32lx6ez9chrjq4mgsp8cf6e") 
Array<NonFungibleLocalId>(NonFungibleLocalId("{6f654d2d58611380-a3b3b32537ca549f-02b25f6411497e41-b1de3f49f2dadedb}"));

CALL_METHOD
    Address("component_rdx1crkh4nn47vug24t26xfp6sqt28acx8qtwk9sg73rcn5tht5d34a860")
    "withdraw_auth_badge";

CALL_METHOD 
Address("account_rdx128zppem3e77cwc7j9faw0j79rd627vflvt7mkqgahx728chplp2rey") 
"deposit_batch" 
Expression("ENTIRE_WORKTOP");

This manifest provides a proof of the ‘Access Manager Owner’ badge before calling the “withdraw_auth_badge” method. The validator owner badge is then deposited directly back into the account shown.

Myself and Ahmed hope that this blueprint may be of use to the community, particularly those with multiple users managing their validator node. If you have any questions about it’s use or suggestions for improvements, please do leave your feedback in reply or contact me on Telegram (@Radstakes).

2 Likes