@stricahq/cardano-codec
Version:
Cardano Codec library for parsing Cardano CBOR data types
860 lines (859 loc) • 31 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseTransaction = void 0;
const cbors = __importStar(require("@stricahq/cbors"));
const _ = __importStar(require("lodash"));
const constants_1 = require("../../constants");
const conwayTypes_1 = require("../../types/conwayTypes");
const utils = __importStar(require("../../utils/utils"));
const common_1 = require("../common");
const getMultiAsset = function (ma) {
const tokens = [];
if (_.isEmpty(ma)) {
return tokens;
}
for (const [policyId, assets] of ma.entries()) {
for (const [assetName, value] of assets.entries()) {
tokens.push({
policyId: policyId.toString("hex"),
assetName: assetName.toString("hex"),
amount: value.toString(),
});
}
}
return tokens;
};
const getCredentialType = (key) => {
if (key === 0) {
return conwayTypes_1.HashType.ADDRESS;
}
// key == 1 is script
return conwayTypes_1.HashType.SCRIPT;
};
const parseCostMdls = (costMdls) => {
const parsedCostMdls = {
plutusV1: undefined,
plutusV2: undefined,
plutusV3: undefined,
};
parsedCostMdls.plutusV1 = costMdls.get(0);
parsedCostMdls.plutusV2 = costMdls.get(1);
parsedCostMdls.plutusV3 = costMdls.get(2);
return parsedCostMdls;
};
const parseRelays = function (relays) {
const relaysFinal = [];
for (const relay of relays) {
switch (relay[0]) {
case 0: {
relaysFinal.push({
port: relay[1],
ipv4: relay[2] ? relay[2].toString("hex") : null,
ipv6: relay[3] ? relay[3].toString("hex") : null,
});
break;
}
case 1: {
relaysFinal.push({
port: relay[1],
dnsName: relay[2],
});
break;
}
case 2: {
relaysFinal.push({
srvName: relay[1],
});
break;
}
default: {
throw new Error("Unknown type of pool relay");
}
}
}
return relaysFinal;
};
const parseCredential = (cred) => {
return {
key: cred[1].toString("hex"),
type: getCredentialType(cred[0]),
};
};
const parseDRep = (dRep) => {
const dRepDeleg = {
type: dRep[0],
key: dRep[1] ? dRep[1].toString("hex") : undefined,
};
return dRepDeleg;
};
const parseAnchor = (anc) => {
let anchor = null;
if (anc) {
anchor = {
url: anc[0],
hash: anc[1].toString("hex"),
};
}
return anchor;
};
const parseCertificates = function (certificates) {
const certs = [];
for (const certificate of certificates) {
let cert;
switch (certificate[0]) {
case 0:
cert = {
type: constants_1.CertificateType.STAKE_KEY_REG,
cert: {
stakeCredential: parseCredential(certificate[1]),
},
};
certs.push(cert);
break;
case 1:
cert = {
type: constants_1.CertificateType.STAKE_KEY_DE_REG,
cert: {
stakeCredential: parseCredential(certificate[1]),
},
};
certs.push(cert);
break;
case 2:
cert = {
type: constants_1.CertificateType.STAKE_DELEGATION,
cert: {
stakeCredential: parseCredential(certificate[1]),
poolKeyHash: certificate[2].toString("hex"),
},
};
certs.push(cert);
break;
case 3: {
// support for optional cbor tag in conway
let owners = certificate[7];
if (!Array.isArray(owners)) {
owners = owners.value;
}
cert = {
type: constants_1.CertificateType.POOL_REG,
cert: {
operator: certificate[1].toString("hex"),
vrfKeyHash: certificate[2].toString("hex"),
pledge: certificate[3].toString(),
cost: certificate[4].toString(),
margin: [certificate[5].value[0], certificate[5].value[1]],
rewardAccount: certificate[6].toString("hex"),
poolOwners: owners.map((owner) => owner.toString("hex")),
relays: parseRelays(certificate[8]),
poolMetadata: certificate[9]
? {
url: certificate[9][0],
metadataHash: certificate[9][1].toString("hex"),
}
: null,
},
};
certs.push(cert);
break;
}
case 4:
cert = {
type: constants_1.CertificateType.POOL_DE_REG,
cert: {
poolKeyHash: certificate[1].toString("hex"),
epoch: certificate[2],
},
};
certs.push(cert);
break;
case 7: {
cert = {
type: constants_1.CertificateType.STAKE_REG,
cert: {
stakeCredential: parseCredential(certificate[1]),
deposit: certificate[2].toString(),
},
};
certs.push(cert);
break;
}
case 8: {
cert = {
type: constants_1.CertificateType.STAKE_DE_REG,
cert: {
stakeCredential: parseCredential(certificate[1]),
deposit: certificate[2].toString(),
},
};
certs.push(cert);
break;
}
case 9: {
cert = {
type: constants_1.CertificateType.VOTE_DELEG,
cert: {
stakeCredential: parseCredential(certificate[1]),
dRep: parseDRep(certificate[2]),
},
};
certs.push(cert);
break;
}
case 10: {
cert = {
type: constants_1.CertificateType.STAKE_VOTE_DELEG,
cert: {
stakeCredential: parseCredential(certificate[1]),
poolKeyHash: certificate[2].toString("hex"),
dRep: parseDRep(certificate[3]),
},
};
certs.push(cert);
break;
}
case 11: {
cert = {
type: constants_1.CertificateType.STAKE_REG_DELEG,
cert: {
stakeCredential: parseCredential(certificate[1]),
poolKeyHash: certificate[2].toString("hex"),
deposit: certificate[3].toString(),
},
};
certs.push(cert);
break;
}
case 12: {
cert = {
type: constants_1.CertificateType.VOTE_REG_DELEG,
cert: {
stakeCredential: parseCredential(certificate[1]),
dRep: parseDRep(certificate[2]),
deposit: certificate[3].toString(),
},
};
certs.push(cert);
break;
}
case 13: {
cert = {
type: constants_1.CertificateType.STAKE_VOTE_REG_DELEG,
cert: {
stakeCredential: parseCredential(certificate[1]),
poolKeyHash: certificate[2].toString("hex"),
dRep: parseDRep(certificate[3]),
deposit: certificate[4].toString(),
},
};
certs.push(cert);
break;
}
case 14: {
cert = {
type: constants_1.CertificateType.COMMITTEE_AUTH_HOT,
cert: {
coldCredential: parseCredential(certificate[1]),
hotCredential: parseCredential(certificate[2]),
},
};
certs.push(cert);
break;
}
case 15: {
cert = {
type: constants_1.CertificateType.COMMITTEE_RESIGN_COLD,
cert: {
coldCredential: parseCredential(certificate[1]),
anchor: parseAnchor(certificate[2]),
},
};
certs.push(cert);
break;
}
case 16: {
cert = {
type: constants_1.CertificateType.DREP_REG,
cert: {
dRepCredential: parseCredential(certificate[1]),
deposit: certificate[2].toString(),
anchor: parseAnchor(certificate[3]),
},
};
certs.push(cert);
break;
}
case 17: {
cert = {
type: constants_1.CertificateType.DREP_DE_REG,
cert: {
dRepCredential: parseCredential(certificate[1]),
deposit: certificate[2].toString(),
},
};
certs.push(cert);
break;
}
case 18: {
cert = {
type: constants_1.CertificateType.DREP_UPDATE,
cert: {
dRepCredential: parseCredential(certificate[1]),
anchor: parseAnchor(certificate[2]),
},
};
certs.push(cert);
break;
}
default:
throw new Error("unknown transaction certificate");
}
}
return certs;
};
const parseProtocolParamUpdate = function (update) {
const protoParamUpdate = {};
for (const [variable, value] of update) {
switch (variable) {
case 0:
protoParamUpdate.minFeeA = value;
break;
case 1:
protoParamUpdate.minFeeB = value;
break;
case 2:
protoParamUpdate.maxBlockBodySize = value;
break;
case 3:
protoParamUpdate.maxTransactionSize = value;
break;
case 4:
protoParamUpdate.maxBlockHeaderSize = value;
break;
case 5:
protoParamUpdate.stakeKeyDeposit = value;
break;
case 6:
protoParamUpdate.poolDeposit = value;
break;
case 7:
protoParamUpdate.poolRetireMaxEpoch = value;
break;
case 8:
protoParamUpdate.n = value;
break;
case 9:
protoParamUpdate.pledgeInfluence = value.value[0] / value.value[1];
break;
case 10:
protoParamUpdate.expansionRate = value.value[0] / value.value[1];
break;
case 11:
protoParamUpdate.treasuryGrowthRate = value.value[0] / value.value[1];
break;
case 16:
protoParamUpdate.minPoolCost = value;
break;
case 17:
protoParamUpdate.adaPerUtxoByte = value;
break;
case 18:
protoParamUpdate.costMdls = parseCostMdls(value);
break;
case 19:
protoParamUpdate.exUnitPrices = {
mem: [value[0][0], value[0][1]],
steps: [value[1][0], value[1][1]],
};
break;
case 20:
protoParamUpdate.maxTxExUnits = {
mem: value[0],
steps: value[1],
};
break;
case 21:
protoParamUpdate.maxBlockExUnits = {
mem: value[0],
steps: value[1],
};
break;
case 22:
protoParamUpdate.maxValueSize = value;
break;
case 23:
protoParamUpdate.collateralPercent = value;
break;
case 24:
protoParamUpdate.maxCollateralInputs = value;
break;
case 25:
protoParamUpdate.poolVotingThreshold = {
motionNoConfidence: value[0].value[0] / value[0].value[1],
committeeNormal: value[1].value[0] / value[1].value[1],
committeeNoConfidence: value[2].value[0] / value[2].value[1],
hfInitiation: value[3].value[0] / value[3].value[1],
securityParamVoting: value[4].value[0] / value[4].value[1],
};
break;
case 26:
protoParamUpdate.dRepVotingThreshold = {
motionNoConfidence: value[0].value[0] / value[0].value[1],
committeeNormal: value[1].value[0] / value[1].value[1],
committeeNoConfidence: value[2].value[0] / value[2].value[1],
updateConstitution: value[3].value[0] / value[3].value[1],
hfInitiation: value[4].value[0] / value[4].value[1],
networkParamVoting: value[5].value[0] / value[5].value[1],
economicParamVoting: value[6].value[0] / value[6].value[1],
technicalParamVoting: value[7].value[0] / value[7].value[1],
govParamVoting: value[8].value[0] / value[8].value[1],
treasuryWithdrawal: value[9].value[0] / value[9].value[1],
};
break;
case 27:
protoParamUpdate.minCommitteeSize = value;
break;
case 28:
protoParamUpdate.committeeTermLimit = value;
break;
case 29:
protoParamUpdate.govActionValidity = value;
break;
case 30:
protoParamUpdate.govActionDeposit = value;
break;
case 31:
protoParamUpdate.dRepDeposit = value;
break;
case 32:
protoParamUpdate.dRepInactivity = value;
break;
case 33:
protoParamUpdate.govActionValidity = value.value[0] / value.value[1];
break;
default:
throw new Error("Unknown protocol parameter update");
}
}
return protoParamUpdate;
};
const parseGovAction = function (govAction) {
let action;
switch (govAction[0]) {
case 0:
action = {
type: conwayTypes_1.GovActionType.PARAM_CHANGE_ACTION,
action: {
prevActionId: govAction[1]
? {
txId: govAction[1][0].toString("hex"),
index: govAction[1][1],
}
: null,
protocolParamUpdate: parseProtocolParamUpdate(govAction[2]),
policyHash: govAction[3] ? govAction[3].toString("hex") : null,
},
};
return action;
case 1:
action = {
type: conwayTypes_1.GovActionType.HF_INIT_ACTION,
action: {
prevActionId: govAction[1]
? {
txId: govAction[1][0].toString("hex"),
index: govAction[1][1],
}
: null,
protocolVersion: [govAction[2][0], govAction[2][1]],
},
};
return action;
case 2:
const withdrawals = [];
for (const [ra, val] of govAction[1]) {
withdrawals.push({
rewardAccount: ra.toString("hex"),
amount: val.toString(),
});
}
action = {
type: conwayTypes_1.GovActionType.TREASURY_WITHDRAW_ACTION,
action: {
withdrawals: withdrawals,
policyHash: govAction[2] ? govAction[2].toString("hex") : null,
},
};
return action;
case 3:
action = {
type: conwayTypes_1.GovActionType.NO_CONFIDENCE_ACTION,
action: {
prevActionId: govAction[1]
? {
txId: govAction[1][0].toString("hex"),
index: govAction[1][1],
}
: null,
},
};
return action;
case 4:
// support for optional cbor tag in conway
let coldCreds = govAction[2];
if (!Array.isArray(coldCreds)) {
coldCreds = coldCreds.value;
}
action = {
type: conwayTypes_1.GovActionType.UPDATE_COMMITTEE_ACTION,
action: {
prevActionId: govAction[1]
? {
txId: govAction[1][0].toString("hex"),
index: govAction[1][1],
}
: null,
removeColdCred: coldCreds.map((cert) => {
return {
key: cert[1].toString("hex"),
type: getCredentialType(cert[0]),
};
}),
addColdCred: Array.from(govAction[3]).map(([cred, epoch]) => ({
credential: {
key: cred[1].toString("hex"),
type: getCredentialType(cred[0]),
},
epoch: epoch,
})),
threshold: govAction[4].value[0] / govAction[4].value[1],
},
};
return action;
case 5:
action = {
type: conwayTypes_1.GovActionType.NEW_CONSTITUTION_ACTION,
action: {
prevActionId: govAction[1]
? {
txId: govAction[1][0].toString("hex"),
index: govAction[1][1],
}
: null,
constitution: {
anchor: parseAnchor(govAction[2][0]),
scriptHash: govAction[2][1] ? govAction[2][1].toString("hex") : govAction[2][1],
},
},
};
return action;
case 6: {
action = {
type: conwayTypes_1.GovActionType.INFO_ACTION,
};
return action;
}
default:
throw new Error("unknown gov action");
}
};
const parseOutput = (output, cborBuf) => {
let address;
let outputValue;
let plutusDataHash;
let plutusData;
let scriptRef;
if (Array.isArray(output)) {
address = output[0];
outputValue = output[1];
if (output[2]) {
plutusDataHash = output[2].toString("hex");
}
}
else {
address = output.get(0);
outputValue = output.get(1);
const datumOption = output.get(2);
const rawScriptRef = output.get(3);
if (datumOption) {
if (datumOption[0] === 0) {
plutusDataHash = datumOption[1].toString("hex");
}
else if (datumOption[0] === 1) {
const pdBuff = datumOption[1].value;
plutusData = pdBuff.toString("hex");
plutusDataHash = utils.createHash32(pdBuff);
}
}
if (rawScriptRef) {
const script = cbors.Decoder.decode(rawScriptRef.value).value;
if (script[0] === 0) {
const ns = script[1];
const nsCborHex = cbors.Encoder.encode(ns).toString('hex');
const hash = utils.createHash28(Buffer.from(`00${nsCborHex}`, "hex"));
scriptRef = {
type: conwayTypes_1.ScriptType.NATIVE_SCRIPT,
script: (0, common_1.parseNativeScript)(script[1]),
hash: hash,
};
}
else if (script[0] === 1) {
const scriptHex = script[1].toString("hex");
const hash = utils.createHash28(Buffer.from(`01${scriptHex}`, "hex"));
scriptRef = {
type: conwayTypes_1.ScriptType.PLUTUS_V1,
script: scriptHex,
hash: hash,
};
}
else if (script[0] === 2) {
const scriptHex = script[1].toString("hex");
const hash = utils.createHash28(Buffer.from(`02${scriptHex}`, "hex"));
scriptRef = {
type: conwayTypes_1.ScriptType.PLUTUS_V2,
script: scriptHex,
hash: hash,
};
}
else if (script[0] === 3) {
const scriptHex = script[1].toString("hex");
const hash = utils.createHash28(Buffer.from(`03${scriptHex}`, "hex"));
scriptRef = {
type: conwayTypes_1.ScriptType.PLUTUS_V3,
script: scriptHex,
hash: hash,
};
}
}
}
let adaAmount;
let tokens;
if (Array.isArray(outputValue)) {
adaAmount = outputValue[0].toString();
tokens = getMultiAsset(outputValue[1]);
}
else {
adaAmount = outputValue.toString();
}
const out = {
address: address.toString("hex"),
amount: adaAmount,
tokens,
plutusDataHash,
plutusData,
scriptRef,
};
return out;
};
const parseTransaction = (trx, cborBuf) => {
const trxBuf = utils.getCborSpanBuffer(cborBuf, trx);
const hash = utils.createHash32(trxBuf);
const transaction = {
hash,
inputs: [],
outputs: [],
fee: "",
};
for (const [key, value] of trx) {
switch (key) {
case 0: {
transaction.inputs = [];
// support for optional cbor tag in conway
let inputs = value;
if (!Array.isArray(inputs)) {
inputs = inputs.value;
}
for (const input of inputs) {
transaction.inputs.push({
txId: input[0].toString("hex"),
index: input[1],
});
}
break;
}
case 1: {
transaction.outputs = [];
if (value && value.length > 0) {
for (const output of value) {
const out = parseOutput(output, cborBuf);
transaction.outputs.push(out);
}
}
break;
}
case 2: {
transaction.fee = value.toString();
break;
}
case 3: {
transaction.ttl = value;
break;
}
case 4: {
// support for optional cbor tag in conway
let certs = value;
if (!Array.isArray(certs)) {
certs = certs.value;
}
const certificates = parseCertificates(certs);
transaction.certificates = certificates;
break;
}
case 5: {
const withdrawal = [];
for (const [ra, val] of value) {
withdrawal.push({
rewardAccount: ra.toString("hex"),
amount: val.toString(),
});
}
transaction.withdrawals = withdrawal;
break;
}
case 7: {
transaction.auxiliaryDataHash = value.toString("hex");
break;
}
case 8: {
transaction.validityIntervalStart = value;
break;
}
case 9: {
transaction.mint = getMultiAsset(value);
break;
}
case 11: {
transaction.scriptDataHash = value.toString("hex");
break;
}
case 13: {
transaction.collaterals = [];
// support for optional cbor tag in conway
let inputs = value;
if (!Array.isArray(inputs)) {
inputs = inputs.value;
}
for (const input of inputs) {
transaction.collaterals.push({
txId: input[0].toString("hex"),
index: input[1],
});
}
break;
}
case 14: {
// support for optional cbor tag in conway
let reqSigners = value;
if (!Array.isArray(reqSigners)) {
reqSigners = reqSigners.value;
}
transaction.requiredSigners = reqSigners.map((v) => v.toString("hex"));
break;
}
case 15: {
transaction.networkId = value;
break;
}
case 16: {
transaction.collateralOutput = parseOutput(value, cborBuf);
break;
}
case 17: {
transaction.totalCollateral = value.toString();
break;
}
case 18: {
transaction.referenceInputs = [];
let inputs = value;
if (!Array.isArray(inputs)) {
inputs = inputs.value;
}
for (const input of inputs) {
transaction.referenceInputs.push({
txId: input[0].toString("hex"),
index: input[1],
});
}
break;
}
case 19: {
transaction.votingProcedures = [];
for (const [voter, voteMap] of value) {
const procedure = {
voter: {
key: voter[1].toString("hex"),
type: voter[0],
},
votes: [],
};
for (const [govActionIdAry, vote] of voteMap) {
procedure.votes.push({
govActionId: {
txId: govActionIdAry[0].toString("hex"),
index: govActionIdAry[1],
},
vote: vote[0],
anchor: parseAnchor(vote[1]),
});
}
transaction.votingProcedures.push(procedure);
}
break;
}
case 20: {
transaction.proposalProcedures = [];
// support for optional cbor tag in conway
let procedures = value;
if (!Array.isArray(procedures)) {
procedures = procedures.value;
}
for (const procedure of procedures) {
transaction.proposalProcedures.push({
deposit: procedure[0],
rewardAccount: procedure[1].toString("hex"),
govAction: parseGovAction(procedure[2]),
anchor: parseAnchor(procedure[3]),
});
}
break;
}
case 21: {
transaction.treasuryAmount = value.toString();
break;
}
case 22: {
transaction.donation = value.toString();
break;
}
default: {
throw new Error("Unknown transaction field");
}
}
}
return transaction;
};
exports.parseTransaction = parseTransaction;
exports.default = exports.parseTransaction;