6

When reading operations from a block, implicit accounts and contracts are returned with a key bytes and in hexadecimal format.

"parameters": {
    "entrypoint": "transfer",
    "value": {
      "prim": "Pair",
      "args": [
        {
          "bytes": "0000861299624c9a3b52be10762c64bac282b1c02316"
        },
        {
          "prim": "Pair",
          "args": [
            {
              "bytes": "0139c8ade2617663981fa2b87592c9ad92714d14c200"
            },
            {
              "int": "11446"
            }
          ]
        }
      ]
    }
  }

There are few details here:

  007-PsDELPH1.contract_id (22 bytes, 8-bit tag)
  **********************************************
  Implicit (tag 0)
  ================

  +---------------------------+----------+------------------------+
  | Name                      | Size     | Contents               |
  +===========================+==========+========================+
  | Tag                       | 1 byte   | unsigned 8-bit integer |
  +---------------------------+----------+------------------------+
  | Signature.Public_key_hash | 21 bytes | $public_key_hash       |
  +---------------------------+----------+------------------------+

  Originated (tag 1)
  ==================

  +---------------+----------+------------------------+
  | Name          | Size     | Contents               |
  +===============+==========+========================+
  | Tag           | 1 byte   | unsigned 8-bit integer |
  +---------------+----------+------------------------+
  | Contract_hash | 20 bytes | bytes                  |
  +---------------+----------+------------------------+
  | padding       | 1 byte   | padding                |
  +---------------+----------+------------------------+
  public_key_hash (21 bytes, 8-bit tag)
  *************************************

  public_key_hash (21 bytes, 8-bit tag)
  *************************************

  Ed25519 (tag 0)
  ===============

  +-------------------------+----------+------------------------+
  | Name                    | Size     | Contents               |
  +=========================+==========+========================+
  | Tag                     | 1 byte   | unsigned 8-bit integer |
  +-------------------------+----------+------------------------+
  | Ed25519.Public_key_hash | 20 bytes | bytes                  |
  +-------------------------+----------+------------------------+


  Secp256k1 (tag 1)
  =================

  +---------------------------+----------+------------------------+
  | Name                      | Size     | Contents               |
  +===========================+==========+========================+
  | Tag                       | 1 byte   | unsigned 8-bit integer |
  +---------------------------+----------+------------------------+
  | Secp256k1.Public_key_hash | 20 bytes | bytes                  |
  +---------------------------+----------+------------------------+


  P256 (tag 2)
  ============

  +----------------------+----------+------------------------+
  | Name                 | Size     | Contents               |
  +======================+==========+========================+
  | Tag                  | 1 byte   | unsigned 8-bit integer |
  +----------------------+----------+------------------------+
  | P256.Public_key_hash | 20 bytes | bytes                  |
  +----------------------+----------+------------------------+

But I am still unclear what these bytes are (b58?) and what the next steps are to convert them to KT1 or tz1.

6

Those 22 bytes are:

  • 2 bytes - encoded prefix (tz1, tz2, tz3, KT1);
  • 20 bytes - depending on the address type:
    • for tz-addresses it's public key hash;
    • for KT-addresses it's hash of the origination operation (see details in @enforser's answer).

Here is a code on C#, I believe you will understand it :)

var bytes = Hex.Parse("0000861299624c9a3b52be10762c64bac282b1c02316");
            
var prefix = (bytes[0], bytes[1], bytes[21]) switch
{
    (0, 0, _) => new byte[] { 6, 161, 159 }, // tz1
    (0, 1, _) => new byte[] { 6, 161, 161 }, // tz2
    (0, 2, _) => new byte[] { 6, 161, 164 }, // tz3
    (1, _, 0) => new byte[] { 2, 90, 121 }   // KT1
};

var pkh = bytes[0] == 0 ? bytes[2..22] : bytes[1..21];

var address = Base58.Convert(pkh, prefix); // tz1XrwX7i9Nzh8e6UmG3VnFkAeoyWdTqDf3U
3

Something to note from the accepted answer is that the KT1 addresses do not have a "public key hash". The hash used there is the blake2b 20 byte digest hash of the operation group hash and the index of the origination operation within that group that created the address.

More details here: https://tezos.stackexchange.com/a/2270/5435.

@Groxan is right that it can be computed in the same way in this context, just the words used to describe the parts of the address are a bit misleading in this case. Only addresses which have a corresponding private and public key may have a public key hash (tz addresses for Tezos).

Would have replied to the answer directly but I don't meet the points required to comment yet :)

1
  • 1
    Reasonable note. I've corrected my answer, thanks!
    – Groxan
    Dec 13 '20 at 23:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.