3

I'm looking for a Javascript implementation of the CLI's cardano-cli transaction policyid function, can anyone point me in the right direction here?

Trying to replicate it with blakejs (https://github.com/dcposch/blakejs) and cbor-web (https://github.com/hildjj/node-cbor/tree/main/packages/cbor-web), but failing to get the hashes to match the output of the CLI.

Eg I want to create a PolicyID / ScriptHash from this policy script:

{
  "type": "all",
  "scripts":
  [
   {
     "type": "before",
     "slot": 42863577
   },
   {
     "type": "sig",
     "keyHash": "46a26617f9b59cc48945ccc6c0aecee732f7698fadbe8b5624b44b9e"
   }
  ]
}

(CLI gives me this policyid: 463e9264962cea64efafa576d44c8d2821d09c0c7495c253d4101a9a)

In JS I'm trying something along these lines:

[removed, see correct answer below]

(gives me this: 5db35cd45775e7d7b0d1bd5491a9baea7ac54b41772a8c96ce587579)

Any guidance is very much appreciated

2 Answers 2

1

You can do this using the 10.0 beta version of cardano-serialization-lib which should make it into stable pretty soon (I'm in the process of testing this, you can follow the status on this Github issue).

This should be enough to get you started:

const ttl = protocolParameters.slot+invalidHereafter
const timelockExpiry = S.TimelockExpiry.new(ttl)
const timeLockedPolicyScript = S.NativeScript.new_timelock_expiry(timelockExpiry)
const policyScripts = S.NativeScripts.new()
const policyScripts.add(timeLockedPolicyScript)
const scriptHash = S.ScriptHash.from_bytes(timeLockedPolicyScript.hash().to_bytes())
const policyID = bytesToString(timeLockedPolicyScript.hash().to_bytes())

In order for that code to work, you'll need some valid protocolParameters object which can be retrieved from Blockfrost using this code from Nami wallet, as well as the bytesToString function which is defined using Buffer:

export const bytesToString = (bytes) => {
  return Buffer.from(bytes, "hex").toString("hex")
}
1
  • 2
    Nice, thanks, that looks pretty elegant! 👍
    – sean
    Commented Nov 22, 2021 at 16:11
3

Finally got my head around this, thanks to this version in Python: Re-Implementing Policy Hashing in Python by @tycl.

Basically we need to

  1. Parse the policy (JSON)
  2. Follow the CDDL specifications to translate the policy to an array (see link below)
  3. Use the array as input to cbor.encode().
  4. Prepend a "0" byte to the result.
  5. Run that new byte array through blake2bHex.

And we're done.

Here's an example:

The policy used is the one from above and I translate it manually to the array via https://github.com/input-output-hk/cardano-ledger/blob/683bef2e40cbd10339452c9f2009867c855baf1a/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L228-L246;

Cbor-Web used from here: https://github.com/hildjj/node-cbor/tree/main/packages/cbor-web

Blakejs package from here: https://github.com/dcposch/blakejs

// Values from policy json
const keyhash = "46a26617f9b59cc48945ccc6c0aecee732f7698fadbe8b5624b44b9e";
const slot = 42863577;

// Translation via CDDL link above
// [1, [X]] => "script_all"
// [5, slot] => "invalid_hereafter" (~ "valid before")
// [0, keyHashBytes] => "script_pubkey"
// Remember: 1) Buffer conversion and 2) Order matters.
const cborInput = [1, [[5, slot], [0, Buffer.from(hexToBytes(keyhash))]]]

// Cbor encode
let cborResult = cbor.encode(cborInput);

// Prepend the 0 byte
let tmp = new Uint8Array(cborResult.length + 1);
tmp.set(Uint8Array.of(0), 0);
tmp.set(cborResult, 1);
cborResult = tmp;

// Run the result through blake2d with digest size / output length of 28
const blakeHexResult = Blake.blake2bHex(cborResult, null, 28);
console.log(blakeHexResult);
1
  • awesome, thanks for linking to cddl!
    – andycandy
    Commented Nov 22, 2021 at 8:19

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