import { Anchor, Buffer28, Buffer32, RawAnchor, RawTxId, UtxoId } from "../types"; import { Credential } from "./address"; export enum Vote { Yes = 0, No = 1, Abstain, } /** * * Cbor object format for RawVote: * * voter = [0, addr_keyhash * // 1, scripthash * // 2, addr_keyhash * // 3, scripthash * // 4, addr_keyhash] * */ export type RawVoter = [0 | 1 | 2 | 3 | 4, Buffer]; /** * Cbor Structure * * anchor = [anchor_url : url, anchor_data_hash : $hash32] * vote = 0 .. 2 * gov_action_id = [transaction_id : $hash32, gov_action_index : uint .size 2] * * voting_procedure = [vote, anchor / nil] * */ export type RawVoteData = [Vote, RawAnchor | undefined]; /** * voting_procedures = {+ voter => {+ gov_action_id => voting_procedure}} */ export type RawVoteMap = Map>; class VoterCredential { committee?: Credential; dRep?: Credential; poolKeyHash?: Buffer28; bytes: Buffer; private constructor(bytes: Buffer) { this.bytes = bytes; } public static fromDrepCredential(cred: Credential) { const voter = new VoterCredential(cred.bytes); voter.dRep = cred; return voter; } public static fromCommitteeCredential(cred: Credential) { const voter = new VoterCredential(cred.bytes); voter.committee = cred; return voter; } public static fromPollKeyHash(keyHash: Buffer28) { const voter = new VoterCredential(keyHash); voter.poolKeyHash = keyHash; return voter; } get isScript(): boolean { return !this.isPubKey; } get isPubKey(): boolean { return !(this.committee?.isScript || this.dRep?.isScript); } public static fromCborObject(obj: RawVoter) { const hash = obj[1]; switch (obj[0]) { case 0: return VoterCredential.fromCommitteeCredential(Credential.fromKeyHash(hash)); case 1: return VoterCredential.fromCommitteeCredential(Credential.fromScriptHash(hash)); case 2: return VoterCredential.fromDrepCredential(Credential.fromKeyHash(hash)); case 3: return VoterCredential.fromDrepCredential(Credential.fromScriptHash(hash)); case 4: return VoterCredential.fromPollKeyHash(hash); default: throw new Error(`VoterCredential.fromCborObject: Invalid voter tag: ${obj[0]}`); } } } export class VotingProcedure { constructor( public voter: VoterCredential, public vote: Vote, public proposalId: UtxoId, public anchor?: Anchor ) {} public static fromRawVoteMap(voteObject: RawVoteMap): VotingProcedure[] { const proceures: VotingProcedure[] = []; voteObject.forEach((govActionMap, voter) => { const credential = VoterCredential.fromCborObject(voter); govActionMap.forEach((rawVoteData, govActionId) => { const proposalId = UtxoId.fromCborObject(govActionId); proceures.push( new VotingProcedure(credential, rawVoteData[0], proposalId, Anchor.fromCborObject(rawVoteData[1]!)) ); }); }); return proceures; } }