I am sending some smart contracts using the Cardano Serialization Lib and the nami wallet for signing, everything works fine, but I am not able to get the script address of a Plutus Script. I have managed it out using cardano-cli command 'address build'. But I think there most be some equivalent in Cardano Serialization Lib, is it posible? I tried with the method Address.from_bytes() using the hex-decoded CBOR from the plutus script but it says it is not the right kind of CBOR.
3 Answers
Here is a javascript snippet that uses the cardano-serialization-lib to go from CBORHex to addr_test...
const {
ScriptHash,
NetworkInfo,
EnterpriseAddress,
StakeCredential
} = require("@emurgo/cardano-serialization-lib-nodejs")
...
const addrFromHash = (hash) => {
const scripthash = ScriptHash.from_bytes(Buffer.from(hash,"hex"));
const cred = StakeCredential.from_scripthash(scripthash);
const networkId = NetworkInfo.testnet().network_id();
const baseAddr = EnterpriseAddress.new(networkId, cred);
const addr = baseAddr.to_address();
const addrBech32 = addr.to_bech32();
return addrBech32;
}
Plutus-Core script bytes are wrapped twice in a CBOR bytearray.
Use the following steps to calculate the script address:
- unwrap one layer of CBOR
- prepend a byte representing the PlutusScript version: 0x01 for PlutusScriptV1, 0x02 for PlutusScriptV2
- calculate the 28-byte (224-bit) blake2b digest to get the payment part of the address
- form the full script address using CIP19 (so for script addresses without a staking part simply prepend 0x70 to the digest)
- encode the script address bytes using bech32 ("addr_test" prefix for testnet, "addr" prefix for mainnet)
The pseudo code of these steps would look as follows:
encodeBech32("addr_test", prepend(hashBlake2b224(prepend(unwrapCborBytes(hexToBytes(cborHex)), 0x01)), 0x70))
As an example consider the commonly used AlwaysSucceeds script. It has the following hexadecimal representation: "4e4d01000033222220051200120011".
- Unwrapping one layer of CBOR bytearray would give: "4d01000033222220051200120011".
- Prepend 0x01: "014d01000033222220051200120011"
- Blake2b 28-byte digest: "67f33146617a5e61936081db3b2117cbf59bd2123748f58ac9678656"
- Prepend 0x70: "7067f33146617a5e61936081db3b2117cbf59bd2123748f58ac9678656"
- Bech32 encoding of testnet address: "addr_test1wpnlxv2xv9a9ucvnvzqakwepzl9ltx7jzgm53av2e9ncv4sysemm8"
Don't ask me why Plutus-Core scripts are wrapped twice in CBOR, and then unwrapped once to calculate the address. Some smart guys somewhere must have a good reason.
If you'd like to do these calculations in Javascript without some complicated Rust/Haskell dependencies check out the Helios Lang library. The library is UNLICENSEd so you can copy the relevant functionality as you please.
Script addresses are basically just addresses that uses the key hash instead of payment key hash, see the CIP19: Cardano Addresses.
However, the cardano-serialization-lib does not support fee estimation for these, but Alessandro from Nami has a patch for that.