Direct RC delegation documentation

Direct RC delegations

Forewords:

You may have heard about RC pools, direct RC delegations are not the same. RC pools got deprecated in favor of RC delegations. Although they are quite similar in name, their function is very different. If you're interested in the difference between the two see this post: @howo/direct-rc-delegations-vs-rc-pools-and-tentative-direct-rc-delegations-spec

Direct RC delegations

Direct RC delegations are the simplest version of RC delegation you can think of:
Bob is out of RC, Alice has 200 RC, so she uses her posting key to delegate 100 RC to Bob. Bob now has 100 rc that he is free to use.

Now while this is a basic example, I'll dive into some more specifics.

Max RC vs RC

It's important to differentiate between the two resources we are dealing with:

Here I have 77 million RC out of 87 million max RC. When a user executes a direct RC delegation, they delegate max RC. This has two effects:

  • Once spent, the delegated RC will regenerate on the delegatee's account
  • Delegating RC will increase the amount of RC you regenerate. The more max RC you have the more you regenerate RC over time, in theory you could delegate 100 million RC on someone with 10k RC to make him regenerate his RC much more quickly and then undelegate. (Although this is unpractical due to the fact that undelegating burns unspent RC).

Constraints & details

  • You cannot delegate delegated RC, this is to avoid expensive chain computations.
  • You delegate max RC and RC, so you can't do a delegation when you are out of RC.
  • When undelegating, the delegator only gets his max RC back, all unspent RC is burned. The delegator will regenerate the RC over time.
  • Delegating is done over custom_json and requires posting authority (more on that later)
  • You can delegate to as many accounts as you want.
  • You can't delegate all your RC (and end up with 0 RC), you have to always keep the RC equivalent of the account creation fee (3 HIVE as the time of writing).
  • You can delegate up to 100 accounts in a single operation.

RC reserve

When an account is created, the account_creation_fee is burned (as the time of writing, 3 HIVE), that amount is converted in RC, this is why even 0 HP account have some RC. (this is also true for accounts created with account creation tokens).

This "RC reserve" is not delegatable, this is to prevent a bad actor from delegating all your RC away effectively soft-locking your account.

RC delegations in action

There is only one operation used for everything. delegate_rc the operations is sent in the form a custom json, here's an example where howo delegates 100 max RC to alice.

{
  "id": "rc",
  "json": [
    "delegate_rc",
    {
      "from": "howo",
      "delegatees": [
        "alice"
      ],
      "max_rc": 100
    }
  ]
}

I will be basing the rest of this guide using hive-js, all the examples, also note that all the keys in this example are from a testnet, they are worthless.

Creating an RC delegation

The parameters are pretty straightforward:

from: Person who delegates the max RC
delegatees: array of account names that you want to delegate to (max 100)
max_rc: max RC amount you want to delegate.

function delegate_rc(delegator, posting_key, delegatees, max_rc) {
    return new Promise(resolve => {
        const json = JSON.stringify(['delegate_rc', {
            from: delegator,
            delegatees: delegatees,
            max_rc: max_rc,
        }]);

        hive.broadcast.customJson(posting_key, [], [delegator], 'rc', json, function (err, result) {
            resolve(err)
        });
    });
}

Updating a delegation

Updating a delegation is done with the same operation, just input a different max RC amount and the delegation will be increased/reduced.

Keep in mind that if you reduce the delegation, the max RC will come back to you but the RC will be burned.

Deleting a delegation

Deleting a delegation is done by calling delegate_rc with max_rc set to 0.

Getting RC from an account

This api endpoint has existed since HF20 but has been updated with RC delegations, it's simply called by passing in an array of accounts

function get_rc(accounts) {
    return new Promise(resolve => {
        hive.api.call('rc_api.find_rc_accounts', {accounts: accounts}, function (err, result) {
            return resolve(result)
        })
    });
}
async function main() {
    let rc_accounts = await get_rc(["initminer", "miners"])
}

output is an array of rc_account objects, note the new fields: delegated_rc and received_delegated_rc

[
  {
    "account": "initminer",
    "rc_manabar": {
      "current_mana": 3153959569,
      "last_update_time": 1660535262
    },
    "max_rc_creation_adjustment": {
      "amount": "2020748973",
      "precision": 6,
      "nai": "@@000000037"
    },
    "max_rc": 3153959569,
    "delegated_rc": 150,
    "received_delegated_rc": 0
  },
  {
    "account": "miners",
    "rc_manabar": {
      "current_mana": 2020748983,
      "last_update_time": 1660535259
    },
    "max_rc_creation_adjustment": {
      "amount": "2020748973",
      "precision": 6,
      "nai": "@@000000037"
    },
    "max_rc": 2020748983,
    "delegated_rc": 0,
    "received_delegated_rc": 10
  }
]

Listing RC accounts:

If you don't have the full list, you can request the RC accounts:

function list_rc_accounts(start, limit) {
    return new Promise(resolve => {
        hive.api.call('rc_api.list_rc_accounts', {start:start, limit: limit}, function (err, result) {
            return resolve(result)
        })
    });
}

async function main() {
    let rc_accounts = await list_rc_accounts("initminer", 2)
}

The ordering is alphabetical, so you input the start and how many users you want to fetch (limited to 1000) and there you go, think of it as pagination.
If you reach the end of the 1000 and didn't find your account, put the last account as "start" and get the next 1000.

Listing all delegations

So this is where it gets a tad tricky, the start param is an array.

  • The first element of the array is from, who is delegating
  • The second element of the array is to, who is delegated to

The second parameter, limit is pretty self explanatory. it's limited to 1000 elements per query.

Both parameters are used for pagination.

If you want to fetch a specific delegation, fill both from and to
If you want to get all the delegations from an account, set from as the account and leave to as empty

If you only input from and reach the end of limit (for instance if an account delegated more than 1000 users), you can continue by inputting the last delegatee in the to field.

Here's a few examples:

function list_rc_direct_delegations(from, to, limit) {
    return new Promise(resolve => {
        hive.api.call('rc_api.list_rc_direct_delegations', {start:[from, to], limit: limit}, function (err, result) {
            return resolve(result)
        })
    });
}

async function main() {
    // List the first 100 delegations from initminer 
    await list_rc_direct_delegations("initminer", "", 100)
    // get the delegation from initminer to howo
    await list_rc_direct_delegations("initminer", "howo", 1)
    // List 100 delegations starting with the initminer -> howo delegation
    await list_rc_direct_delegations("initminer", "howo", 100)
}

The output is an array of delegation objects:

[
  {
    "from": "initminer",
    "to": "howo",
    "delegated_rc": 70
  },
  {
    "from": "initminer",
    "to": "alice",
    "delegated_rc": 70
  }
]

Important tidbit about the ordering, you may be confused that this list is not in alphabetical order, this is because under the hood, we index with account numbers, not account names.

So the reason why howo comes up before alice in this testnet, is because if you look at the get_account api call:

[{
    "id": 6,
    "name": "howo",
    ...
  },{
    "id": 7,
    "name": "alice",
    ....
  }
]

alice's id is 7 and howo's id is 6. If you want to get a bit more in depth, I talk about it in this issue (among other things): https://gitlab.syncad.com/hive/hive/-/issues/271

Note that due to technical limitations, it's not possible to only input to and get all the inbound delegations, this has to be built on an L2 api (eg: HAF/hivemind/hiveSQL).

Conclusion

I hope you found this documentation useful, if you want to check the direct RC delegation code yourself it's here: https://gitlab.syncad.com/hive/hive/-/merge_requests/245/diffs

I'll be glad to answer any questions that come up in the comments and hope to see a lot of use for rc delegations once hard fork 26 hits !

@howo


You can vote for our witness directly using Hivesigner here.

H2
H3
H4
3 columns
2 columns
1 column
Join the conversation now
Logo
Center