Skip to content

Commit

Permalink
chore: cip129 id in dreps list and proposal's votes list
Browse files Browse the repository at this point in the history
  • Loading branch information
slowbackspace committed Dec 12, 2024
1 parent c0795de commit 3939d71
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 28 deletions.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ module.exports = {
CardanoDbSync: true,
getDbSync: true,
clientDbSync: true,
dbSyncDRepToCIP129: true,
},
},
],
Expand Down
13 changes: 10 additions & 3 deletions src/routes/governance/dreps/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as ResponseTypes from '../../../types/responses/governance.js';
import { getDbSync, gracefulRelease } from '../../../utils/database.js';
import { getSchemaForEndpoint } from '@blockfrost/openapi';
import { isUnpaged } from '../../../utils/routes.js';
import { dbSyncDRepToCIP129 as databaseSyncDRepToCIP129 } from '../../../utils/governance.js';

async function route(fastify: FastifyInstance) {
fastify.route({
Expand All @@ -16,7 +17,7 @@ async function route(fastify: FastifyInstance) {

try {
const unpaged = isUnpaged(request);
const { rows }: { rows: ResponseTypes.DReps } = unpaged
const { rows } = unpaged
? await clientDbSync.query<QueryTypes.DReps>(SQLQuery.get('governance_dreps_unpaged'), [
request.query.order,
])
Expand All @@ -28,9 +29,15 @@ async function route(fastify: FastifyInstance) {

gracefulRelease(clientDbSync);

// TODO: how to handle cip-0129 in list of dreps?
for (const row of rows) {
// Convert drep ids to cip129 format
const cip129DRep = databaseSyncDRepToCIP129(row);

return reply.send(rows);
row.drep_id = cip129DRep.id;
row.hex = cip129DRep.hex ?? '';
}

return reply.send(rows as ResponseTypes.DReps);
} catch (error) {
gracefulRelease(clientDbSync);
throw error;
Expand Down
16 changes: 13 additions & 3 deletions src/routes/governance/proposals/tx-hash/cert-index/votes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as ResponseTypes from '../../../../../types/responses/governance.js';
import { getDbSync, gracefulRelease } from '../../../../../utils/database.js';
import { SQLQuery } from '../../../../../sql/index.js';
import { getSchemaForEndpoint } from '@blockfrost/openapi';
import { dbSyncDRepToCIP129 } from '../../../../../utils/governance.js';
import { isUnpaged } from '../../../../../utils/routes.js';

async function route(fastify: FastifyInstance) {
Expand All @@ -17,7 +18,7 @@ async function route(fastify: FastifyInstance) {

try {
const unpaged = isUnpaged(request);
const { rows }: { rows: ResponseTypes.ProposalsProposalVotes } = unpaged
const { rows } = unpaged
? await clientDbSync.query<QueryTypes.ProposalsProposalVotes>(
SQLQuery.get('governance_proposals_proposal_votes_unpaged'),
[request.query.order, request.params.tx_hash, request.params.cert_index],
Expand All @@ -35,8 +36,17 @@ async function route(fastify: FastifyInstance) {

gracefulRelease(clientDbSync);

// TODO: CIP-0129 compatible voter field
return reply.send(rows);
for (const row of rows) {
// Convert voter id to cip129 format
const cip129DRep = dbSyncDRepToCIP129({
drep_id: row.voter,
has_script: row.voter_has_script,
});

row.voter = cip129DRep.id;
}

return reply.send(rows as ResponseTypes.ProposalsProposalVotes);
} catch (error) {
gracefulRelease(clientDbSync);
throw error;
Expand Down
6 changes: 4 additions & 2 deletions src/sql/governance/dreps.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
SELECT dh.view AS "drep_id",
encode(dh.raw, 'hex') AS "hex"
SELECT
dh.view AS "drep_id",
encode(dh.raw, 'hex') AS "hex",
dh.has_script AS "has_script"
FROM drep_hash dh
ORDER BY CASE
WHEN LOWER($1) = 'desc' THEN dh.id
Expand Down
1 change: 1 addition & 0 deletions src/sql/governance/proposals_proposal_votes.sql
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ SELECT encode(tx.hash, 'hex') AS "tx_hash",
(
COALESCE(encode(ch.raw, 'hex'), dh.view, ph.view)
) AS "voter",
dh.has_script AS "voter_has_script",
LOWER(vote::TEXT) AS "vote" -- Yes, No, Abstain -> yes,no,abstain
FROM voting_procedure vp
JOIN gov_action_proposal gap ON (gap.id = vp.gov_action_proposal_id)
Expand Down
3 changes: 2 additions & 1 deletion src/sql/governance/unpaged/dreps.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
SELECT dh.view AS "drep_id",
encode(dh.raw, 'hex') AS "hex"
encode(dh.raw, 'hex') AS "hex",
dh.has_script AS "has_script"
FROM drep_hash dh
ORDER BY CASE
WHEN LOWER($1) = 'desc' THEN dh.id
Expand Down
1 change: 1 addition & 0 deletions src/sql/governance/unpaged/proposals_proposal_votes.sql
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ SELECT encode(tx.hash, 'hex') AS "tx_hash",
(
COALESCE(encode(ch.raw, 'hex'), dh.view, ph.view)
) AS "voter",
dh.has_script AS "voter_has_script",
LOWER(vote::TEXT) AS "vote" -- Yes, No, Abstain -> yes,no,abstain
FROM voting_procedure vp
JOIN gov_action_proposal gap ON (gap.id = vp.gov_action_proposal_id)
Expand Down
2 changes: 2 additions & 0 deletions src/types/queries/governance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface RequestDRepID {
export interface DReps {
drep_id: string;
hex: string;
has_script: boolean;
}

export interface DRepsDrepID {
Expand Down Expand Up @@ -142,6 +143,7 @@ export interface ProposalsProposalVotes {
cert_index: number;
voter_role: 'constitutional_committee' | 'drep' | 'spo';
voter: string;
voter_has_script: boolean;
vote: 'yes' | 'no' | 'abstain';
}

Expand Down
63 changes: 44 additions & 19 deletions src/utils/governance.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,42 @@
import { bech32 } from 'bech32';

const SPECIAL_DREP_IDS = new Set(['drep_always_abstain', 'drep_always_no_confidence']);

// eslint-disable-next-line unicorn/prevent-abbreviations
export const dbSyncDRepToCIP129 = <T extends { drep_id: string; has_script: boolean }>(dRep: T) => {
if (SPECIAL_DREP_IDS.has(dRep.drep_id)) {
return {
id: dRep.drep_id,
hex: null,
};
}

const { prefix, words } = bech32.decode(dRep.drep_id);

if (prefix !== 'drep' && prefix !== 'drep_script') {
throw new Error('Invalid drep id prefix');
}

const hexBuf = Buffer.from(bech32.fromWords(words));

const keyTypeNibble = 0x2 << 4; // set keyType to dRep
const credentialTypeNibble = dRep.has_script ? 0x3 : 0x2;

const header = keyTypeNibble | credentialTypeNibble;

const headerBuff = Buffer.alloc(1); // Allocate a 1-byte buffer (adjust size as needed)

headerBuff.writeUInt8(header, 0);

const hexWithHeader = Buffer.concat([headerBuff, hexBuf]);
const idWithHeader = bech32.encode('drep', bech32.toWords(hexWithHeader));

return {
id: idWithHeader,
hex: hexWithHeader.toString('hex'),
};
};

export interface DRepValidationResult {
// TODO: maybe rename to raw, raw prop to hex,
dbSync: {
Expand Down Expand Up @@ -28,9 +65,7 @@ export interface DRepValidationResult {
* @throws {Error} If the DRep ID prefix is invalid, an error is thrown.
*/
export const validateDRepId = (bechDrepId: string): DRepValidationResult => {
const SPECIAL_DREP_IDS = ['drep_always_abstain', 'drep_always_no_confidence'];

if (SPECIAL_DREP_IDS.includes(bechDrepId)) {
if (SPECIAL_DREP_IDS.has(bechDrepId)) {
return {
dbSync: {
id: bechDrepId,
Expand All @@ -56,31 +91,21 @@ export const validateDRepId = (bechDrepId: string): DRepValidationResult => {
// 28 bytes of keyHash/scriptHash
// Legacy dbSync-compatible format
const drepIdRaw = `\\x${hexBuf.toString('hex')}`;

const hasScript = prefix === 'drep_script';

const keyTypeNibble = 0x2 << 4; // set keyType to dRep
const credentialTypeNibble = hasScript ? 0x3 : 0x2;

const header = keyTypeNibble | credentialTypeNibble;

const headerBuff = Buffer.alloc(1); // Allocate a 1-byte buffer (adjust size as needed)

headerBuff.writeUInt8(header, 0);

const hexWithHeader = Buffer.concat([headerBuff, hexBuf]);
const idWithHeader = bech32.encode('drep', bech32.toWords(hexWithHeader));
const cip129Id = dbSyncDRepToCIP129({
drep_id: bechDrepId,
hex: hexBuf.toString('hex'),
has_script: hasScript,
});

return {
dbSync: {
id: bechDrepId,
raw: drepIdRaw,
hasScript: hasScript,
},
cip129: {
id: idWithHeader,
hex: hexWithHeader.toString('hex'),
},
cip129: cip129Id,
isCip129: false,
};
} else {
Expand Down

0 comments on commit 3939d71

Please sign in to comment.