multiversx

How to calculate pending APR rewards on delegated validators on MultiversX


Background

In MultiversX users can delegate their funds to a staking provider and earn staking rewards by delegating their funds to a validator smart contract.

Let's assume a user account has delegated 100 EGLD to the following smart contract

erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqd8llllslmf3hu

Explorer link

Pending Rewards Calculation

How can the pending rewards for the user be calculated since the last claimrewards operation or if no such operation took place, since the delegation date of the funds.

For the purpose of the example, lets assume that the last operation was 180 days ago.


Solution

  • A delegation contract contains a view function called getClaimableRewards which takes a sole address parameter (the one we want to get rewards for)

    Let's suppose we want to get the pending rewards for the address erd107x49me2mggc2cd3rgr588d7mgps4nyhn2u5tep9qw3vsdf4l2cqc9ntrf

    1) Via a HTTP request on the gateway

    We first need to convert erd107x49me2mggc2cd3rgr588d7mgps4nyhn2u5tep9qw3vsdf4l2cqc9ntrf to hexadecimal, this tools is useful to do so: https://utils.multiversx.com/converters

    The hex value of erd107x49me2mggc2cd3rgr588d7mgps4nyhn2u5tep9qw3vsdf4l2cqc9ntrf is 7f8d52ef2ada118561b11a07439dbeda030acc979ab945e42503a2c83535fab0

    curl -X POST https://gateway.multiversx.com/vm-values/query \
    -H 'Content-Type: application/json' \
    -d '{
        "scAddress": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqd8llllslmf3hu",
        "funcName": "getClaimableRewards",
        "args": ["7f8d52ef2ada118561b11a07439dbeda030acc979ab945e42503a2c83535fab0"]
    }'
    

    The result:

    {
      "data": {
        "blockInfo": {
          "nonce": 18528828,
          "hash": "ae8446c1dfbba9b6302071042df2de472439563a087c9aba84ab1ac1634aa10d",
          "rootHash": "3d954d6df6689ec53f14cc9b628eb1fd4a78b6835a44b6eff3b5feb0f55e6bb4"
        },
        "data": {
          "returnData": [
            "e1lP8VQRKg=="
          ],
          "returnCode": "ok",
          "returnMessage": "",
          "gasRemaining": 299999000000,
          "gasRefund": 0,
          "outputAccounts": {
            "0000000000000000000100000000000000000000000000000000000034ffffff": {
              "address": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqd8llllslmf3hu",
              "nonce": 0,
              "balance": null,
              "balanceDelta": 0,
              "storageUpdates": {},
              "code": null,
              "codeMetaData": null,
              "outputTransfers": [],
              "callType": 0
            }
          },
          "deletedAccounts": null,
          "touchedAccounts": null,
          "logs": []
        }
      },
      "error": "",
      "code": "successful"
    }
    

    Using the same tool as above we can convert the base64 value e1lP8VQRKg== to decimals: 34719622021517610 = 0.034719622021517610 EGLD

    2) Via mxpy

    You can use the following command:

    mxpy contract query erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqd8llllslmf3hu \
    --function "getClaimableRewards" \
    --proxy https://gateway.multiversx.com \
    --arguments "erd107x49me2mggc2cd3rgr588d7mgps4nyhn2u5tep9qw3vsdf4l2cqc9ntrf"
    

    The result:

    [
        {
            "base64": "e1lP8VQRKg==",
            "hex": "7b594ff154112a",
            "number": 34719622021517610
        }
    ]
    

    Same as above: 34719622021517610 = 0.034719622021517610 EGLD

    You can of course use any SDK (JavaScript, Go, Rust, ...) you want to perform this query