From b34ef89c340d9b670a67ff5d407a5ed72dedb19d Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Thu, 31 Oct 2024 14:05:09 +0100 Subject: [PATCH] feat: add DReps endpoints --- .vscode/settings.json | 3 +- CHANGELOG.MD | 4 + src/BlockFrostAPI.ts | 21 ++ src/endpoints/api/governance/dreps/index.ts | 252 +++++++++++++++++ test/fixtures/endpoints.ts | 297 ++++++++++++++++++++ 5 files changed, 576 insertions(+), 1 deletion(-) create mode 100644 src/endpoints/api/governance/dreps/index.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index d57d4141..2fda706d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,6 +14,8 @@ "commitlint", "delegators", "deregistrations", + "drep", + "dreps", "emurgo", "id", "io", @@ -41,5 +43,4 @@ "**/.pnp.*": true }, "eslint.nodePath": ".yarn/sdks", - "prettier.prettierPath": ".yarn/sdks/prettier/index.js" } diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 1c6254a0..b967b185 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- methods for querying governance DReps endpoints - `dreps`, `drepsById`, `drepsByIdDelegators`, `drepsByIdDelegatorsAll`, `drepsByIdMetadata`, `drepsByIdUpdates`, `drepsByIdUpdatesAll`, `drepsByIdVotes`, `drepsByIdVotesAll` + ## [5.6.0] - 2024-10-03 ### Added diff --git a/src/BlockFrostAPI.ts b/src/BlockFrostAPI.ts index 7c57c611..679d81ee 100644 --- a/src/BlockFrostAPI.ts +++ b/src/BlockFrostAPI.ts @@ -60,6 +60,17 @@ import { blocksAddressesAll, } from './endpoints/api/blocks'; +import { + dreps, + drepsById, + drepsByIdDelegators, + drepsByIdDelegatorsAll, + drepsByIdMetadata, + drepsByIdUpdates, + drepsByIdUpdatesAll, + drepsByIdVotes, + drepsByIdVotesAll, +} from './endpoints/api/governance/dreps'; import { epochs, epochsBlocks, @@ -257,6 +268,16 @@ class BlockFrostAPI { blocksAddresses = blocksAddresses; blocksAddressesAll = blocksAddressesAll; + dreps = dreps; + drepsById = drepsById; + drepsByIdDelegators = drepsByIdDelegators; + drepsByIdDelegatorsAll = drepsByIdDelegatorsAll; + drepsByIdMetadata = drepsByIdMetadata; + drepsByIdUpdates = drepsByIdUpdates; + drepsByIdUpdatesAll = drepsByIdUpdatesAll; + drepsByIdVotes = drepsByIdVotes; + drepsByIdVotesAll = drepsByIdVotesAll; + epochs = epochs; epochsBlocks = epochsBlocks; epochsBlocksAll = epochsBlocksAll; diff --git a/src/endpoints/api/governance/dreps/index.ts b/src/endpoints/api/governance/dreps/index.ts new file mode 100644 index 00000000..d8e17446 --- /dev/null +++ b/src/endpoints/api/governance/dreps/index.ts @@ -0,0 +1,252 @@ +import { getPaginationOptions, paginateMethod } from '../../../../utils'; +import { components } from '@blockfrost/openapi'; +import { BlockFrostAPI } from '../../../../index'; +import { AllMethodOptions, PaginationOptions } from '../../../../types'; +import { handleError } from '../../../../utils/errors'; + +/** + * Obtains list of Delegate Representatives (DReps). + * @see {@link https://docs.blockfrost.io/#tag/cardano--governance/GET/governance/dreps | API docs for of Delegate Representatives (DReps)} + * + * @param pagination - Optional, Pagination options + * @returns List of registered stake pools. + * + */ +export async function dreps( + this: BlockFrostAPI, + pagination?: PaginationOptions, +): Promise { + const paginationOptions = getPaginationOptions(pagination); + + try { + const res = await this.instance( + `governance/dreps`, + { + searchParams: { + page: paginationOptions.page, + count: paginationOptions.count, + order: paginationOptions.order, + }, + }, + ); + return res.body; + } catch (error) { + throw handleError(error); + } +} + +/** + * Obtains information of a specific DRep. + * @see {@link https://docs.blockfrost.io/#tag/cardano--governance/GET/governance/dreps/%7Bdrep_id%7D | API docs for Stake Pool} + * + * @param drepId - DRep ID + * @returns Information of a specific DRep + * + */ +export async function drepsById( + this: BlockFrostAPI, + drepId: string, +): Promise { + try { + const res = await this.instance( + `governance/dreps/${drepId}`, + ); + return res.body; + } catch (error) { + throw handleError(error); + } +} + +/** + * Obtains DRep metadata. + * @see {@link https://docs.blockfrost.io/#tag/cardano--governance/GET/governance/dreps/%7Bdrep_id%7D/metadata | API docs for DRep Metadata} + * + * @param drepId - DRep ID + * @returns DRep Metadata + * + */ +export async function drepsByIdMetadata( + this: BlockFrostAPI, + drepId: string, + pagination?: PaginationOptions, +): Promise { + const paginationOptions = getPaginationOptions(pagination); + + try { + const res = await this.instance( + `governance/dreps/${drepId}/metadata`, + { + searchParams: { + page: paginationOptions.page, + count: paginationOptions.count, + order: paginationOptions.order, + }, + }, + ); + return res.body; + } catch (error) { + throw handleError(error); + } +} + +/** + * Obtains current DRep delegators. + * @see {@link https://docs.blockfrost.io/#tag/cardano--governance/GET/governance/dreps/%7Bdrep_id%7D/delegators | API docs for DRep Delegators} + * + * @param drepId - DRep ID + * @returns Current DRep delegators + * + */ +export async function drepsByIdDelegators( + this: BlockFrostAPI, + drepId: string, + pagination?: PaginationOptions, +): Promise { + const paginationOptions = getPaginationOptions(pagination); + + try { + const res = await this.instance( + `governance/dreps/${drepId}/delegators`, + { + searchParams: { + page: paginationOptions.page, + count: paginationOptions.count, + order: paginationOptions.order, + }, + }, + ); + return res.body; + } catch (error) { + throw handleError(error); + } +} + +/** + * Obtains current DRep delegators. + * @see {@link https://docs.blockfrost.io/#tag/cardano--governance/GET/governance/dreps/%7Bdrep_id%7D/delegators | API docs for DRep Delegators} + * @remarks + * Variant of `drepsByIdDelegators` method for fetching all pages with built-in requests batching + * + * @param drepId - DRep ID + * @param allMethodOptions - Optional, Options for request batching + * @returns Current DRep delegators + * + */ +export async function drepsByIdDelegatorsAll( + this: BlockFrostAPI, + drepId: string, + allMethodOptions?: AllMethodOptions, +): Promise { + return paginateMethod( + pagination => this.drepsByIdDelegators(drepId, pagination), + allMethodOptions, + ); +} + +/** + * Obtains List of certificate updates to the DRep. + * @see {@link https://docs.blockfrost.io/#tag/cardano--governance/GET/governance/dreps/%7Bdrep_id%7D/updates | API docs for DRep Updates} + * + * @param drepId - DRep ID + * @returns List of certificate updates to the DRep + * + */ +export async function drepsByIdUpdates( + this: BlockFrostAPI, + drepId: string, + pagination?: PaginationOptions, +): Promise { + const paginationOptions = getPaginationOptions(pagination); + + try { + const res = await this.instance( + `governance/dreps/${drepId}/updates`, + { + searchParams: { + page: paginationOptions.page, + count: paginationOptions.count, + order: paginationOptions.order, + }, + }, + ); + return res.body; + } catch (error) { + throw handleError(error); + } +} + +/** + * Obtains List of certificate updates to the DRep. + * @see {@link https://docs.blockfrost.io/#tag/cardano--governance/GET/governance/dreps/%7Bdrep_id%7D/updates | API docs for History of DRep updates} + * @remarks + * Variant of `drepsByIdUpdates` method for fetching all pages with built-in requests batching + * + * @param drepId - DRep ID + * @param allMethodOptions - Optional, Options for request batching + * @returns List of certificate updates to the DRep + * + */ +export async function drepsByIdUpdatesAll( + this: BlockFrostAPI, + drepId: string, + allMethodOptions?: AllMethodOptions, +): Promise { + return paginateMethod( + pagination => this.drepsByIdUpdates(drepId, pagination), + allMethodOptions, + ); +} + +/** + * Obtains History of DRep votes. + * @see {@link https://docs.blockfrost.io/#tag/cardano--governance/GET/governance/dreps/%7Bdrep_id%7D/votes | API docs for History of DRep votes} + * + * @param drepId - DRep ID + * @returns History of DRep votes + * + */ +export async function drepsByIdVotes( + this: BlockFrostAPI, + drepId: string, + pagination?: PaginationOptions, +): Promise { + const paginationOptions = getPaginationOptions(pagination); + + try { + const res = await this.instance( + `governance/dreps/${drepId}/votes`, + { + searchParams: { + page: paginationOptions.page, + count: paginationOptions.count, + order: paginationOptions.order, + }, + }, + ); + return res.body; + } catch (error) { + throw handleError(error); + } +} + +/** + * Obtains History of DRep votes. + * @see {@link https://docs.blockfrost.io/#tag/cardano--governance/GET/governance/dreps/%7Bdrep_id%7D/votes | API docs for History of DRep votes} + * @remarks + * Variant of `drepsByIdVotes` method for fetching all pages with built-in requests batching + * + * @param drepId - DRep ID + * @param allMethodOptions - Optional, Options for request batching + * @returns History of DRep votes + * + */ +export async function drepsByIdVotesAll( + this: BlockFrostAPI, + drepId: string, + allMethodOptions?: AllMethodOptions, +): Promise { + return paginateMethod( + pagination => this.drepsByIdVotes(drepId, pagination), + allMethodOptions, + ); +} diff --git a/test/fixtures/endpoints.ts b/test/fixtures/endpoints.ts index 07ff9d31..2109b856 100644 --- a/test/fixtures/endpoints.ts +++ b/test/fixtures/endpoints.ts @@ -983,4 +983,301 @@ export default [ }, }, }, + { + command: (SDK: BlockFrostAPI) => SDK.dreps(), + path: mainnetUrl(`governance/dreps`), + endpointMock: [ + { + drep_id: 'drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn', + hex: 'db1bc3c3f99ce68977ceaf27ab4dd917123ef9e73f85c304236eab23', + }, + { + drep_id: 'drep1cxayn4fgy27yaucvhamsvqj3v6835mh3tjjx6x8hdnr4', + hex: 'c1ba49d52822bc4ef30cbf77060251668f1a6ef15ca46d18f76cc758', + }, + ], + response: [ + { + drep_id: 'drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn', + hex: 'db1bc3c3f99ce68977ceaf27ab4dd917123ef9e73f85c304236eab23', + }, + { + drep_id: 'drep1cxayn4fgy27yaucvhamsvqj3v6835mh3tjjx6x8hdnr4', + hex: 'c1ba49d52822bc4ef30cbf77060251668f1a6ef15ca46d18f76cc758', + }, + ], + }, + { + command: (SDK: BlockFrostAPI) => + SDK.drepsById('drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn'), + path: mainnetUrl( + `governance/dreps/drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn`, + ), + endpointMock: { + drep_id: 'drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc', + hex: 'a61261172624e8333ceff098648d90f8e404e2e36d5b5f5985cbd35d', + amount: '2000000', + active: true, + active_epoch: 420, + has_script: true, + }, + response: { + drep_id: 'drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc', + hex: 'a61261172624e8333ceff098648d90f8e404e2e36d5b5f5985cbd35d', + amount: '2000000', + active: true, + active_epoch: 420, + has_script: true, + }, + }, + { + command: (SDK: BlockFrostAPI) => + SDK.drepsByIdMetadata( + 'drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn', + ), + path: mainnetUrl( + `governance/dreps/drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn/metadata`, + ), + endpointMock: { + drep_id: 'drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc', + hex: 'a61261172624e8333ceff098648d90f8e404e2e36d5b5f5985cbd35d', + url: 'https://aaa.xyz/drep.json', + hash: 'a14a5ad4f36bddc00f92ddb39fd9ac633c0fd43f8bfa57758f9163d10ef916de', + json_metadata: { + '@context': { + CIP100: + 'https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#', + CIP119: + 'https://github.com/cardano-foundation/CIPs/blob/master/CIP-0119/README.md#', + hashAlgorithm: 'CIP100:hashAlgorithm', + body: { + '@id': 'CIP119:body', + '@context': { + references: { + '@id': 'CIP119:references', + '@container': '@set', + '@context': { + GovernanceMetadata: 'CIP100:GovernanceMetadataReference', + Other: 'CIP100:OtherReference', + label: 'CIP100:reference-label', + uri: 'CIP100:reference-uri', + }, + }, + paymentAddress: 'CIP119:paymentAddress', + givenName: 'CIP119:givenName', + image: { + '@id': 'CIP119:image', + '@context': { + ImageObject: 'https://schema.org/ImageObject', + }, + }, + objectives: 'CIP119:objectives', + motivations: 'CIP119:motivations', + qualifications: 'CIP119:qualifications', + }, + }, + }, + hashAlgorithm: 'blake2b-256', + body: { + paymentAddress: + 'addr1q86dnpkva4mm859c8ur7tjxn57zgsu6vg8pdetkdve3fsacnq7twy06u2ev5759vutpjgzfryx0ud8hzedhzerava35qwh3x34', + givenName: 'Ryan Williams', + image: { + '@type': 'ImageObject', + contentUrl: 'https://avatars.githubusercontent.com/u/44342099?v=4', + sha256: + '2a21e4f7b20c8c72f573707b068fb8fc6d8c64d5035c4e18ecae287947fe2b2e', + }, + objectives: 'Buy myself an island.', + motivations: 'I really would like to own an island.', + qualifications: + 'I have my 100m swimming badge, so I would be qualified to be able to swim around island.', + references: [ + { + '@type': 'Other', + label: 'A cool island for Ryan', + uri: "https://www.google.com/maps/place/World's+only+5th+order+recursive+island/@62.6511465,-97.7946829,15.75z/data=!4m14!1m7!3m6!1s0x5216a167810cee39:0x11431abdfe4c7421!2sWorld's+only+5th+order+recursive+island!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n!3m5!1s0x5216a167810cee39:0x11431abdfe4c7421!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n?authuser=0&entry=ttu", + }, + { + '@type': 'Link', + label: "Ryan's Twitter", + uri: 'https://twitter.com/Ryun1_', + }, + ], + }, + }, + bytes: + '\\x7b0a20202240636f6e74657874223a207b0a2020202022406c616e6775616765223a2022656e2d7573222c0a2020202022434950313030223a202268747470733a2f2f6769746875622e636f6d2f63617264616e6f2d666f756e646174696f6e2f434950732f626c6f622f6d61737465722f4349502d303130302f524541444d452e6', + }, + response: { + drep_id: 'drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc', + hex: 'a61261172624e8333ceff098648d90f8e404e2e36d5b5f5985cbd35d', + url: 'https://aaa.xyz/drep.json', + hash: 'a14a5ad4f36bddc00f92ddb39fd9ac633c0fd43f8bfa57758f9163d10ef916de', + json_metadata: { + '@context': { + CIP100: + 'https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#', + CIP119: + 'https://github.com/cardano-foundation/CIPs/blob/master/CIP-0119/README.md#', + hashAlgorithm: 'CIP100:hashAlgorithm', + body: { + '@id': 'CIP119:body', + '@context': { + references: { + '@id': 'CIP119:references', + '@container': '@set', + '@context': { + GovernanceMetadata: 'CIP100:GovernanceMetadataReference', + Other: 'CIP100:OtherReference', + label: 'CIP100:reference-label', + uri: 'CIP100:reference-uri', + }, + }, + paymentAddress: 'CIP119:paymentAddress', + givenName: 'CIP119:givenName', + image: { + '@id': 'CIP119:image', + '@context': { + ImageObject: 'https://schema.org/ImageObject', + }, + }, + objectives: 'CIP119:objectives', + motivations: 'CIP119:motivations', + qualifications: 'CIP119:qualifications', + }, + }, + }, + hashAlgorithm: 'blake2b-256', + body: { + paymentAddress: + 'addr1q86dnpkva4mm859c8ur7tjxn57zgsu6vg8pdetkdve3fsacnq7twy06u2ev5759vutpjgzfryx0ud8hzedhzerava35qwh3x34', + givenName: 'Ryan Williams', + image: { + '@type': 'ImageObject', + contentUrl: 'https://avatars.githubusercontent.com/u/44342099?v=4', + sha256: + '2a21e4f7b20c8c72f573707b068fb8fc6d8c64d5035c4e18ecae287947fe2b2e', + }, + objectives: 'Buy myself an island.', + motivations: 'I really would like to own an island.', + qualifications: + 'I have my 100m swimming badge, so I would be qualified to be able to swim around island.', + references: [ + { + '@type': 'Other', + label: 'A cool island for Ryan', + uri: "https://www.google.com/maps/place/World's+only+5th+order+recursive+island/@62.6511465,-97.7946829,15.75z/data=!4m14!1m7!3m6!1s0x5216a167810cee39:0x11431abdfe4c7421!2sWorld's+only+5th+order+recursive+island!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n!3m5!1s0x5216a167810cee39:0x11431abdfe4c7421!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n?authuser=0&entry=ttu", + }, + { + '@type': 'Link', + label: "Ryan's Twitter", + uri: 'https://twitter.com/Ryun1_', + }, + ], + }, + }, + bytes: + '\\x7b0a20202240636f6e74657874223a207b0a2020202022406c616e6775616765223a2022656e2d7573222c0a2020202022434950313030223a202268747470733a2f2f6769746875622e636f6d2f63617264616e6f2d666f756e646174696f6e2f434950732f626c6f622f6d61737465722f4349502d303130302f524541444d452e6', + }, + }, + { + command: (SDK: BlockFrostAPI) => + SDK.drepsByIdDelegators( + 'drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn', + ), + path: mainnetUrl( + `governance/dreps/drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn/delegators`, + ), + endpointMock: [ + { + address: 'stake1ux4vspfvwuus9uwyp5p3f0ky7a30jq5j80jxse0fr7pa56sgn8kha', + amount: '1137959159981411', + }, + { + address: 'stake1uylayej7esmarzd4mk4aru37zh9yz0luj3g9fsvgpfaxulq564r5u', + amount: '16958865648', + }, + ], + response: [ + { + address: 'stake1ux4vspfvwuus9uwyp5p3f0ky7a30jq5j80jxse0fr7pa56sgn8kha', + amount: '1137959159981411', + }, + { + address: 'stake1uylayej7esmarzd4mk4aru37zh9yz0luj3g9fsvgpfaxulq564r5u', + amount: '16958865648', + }, + ], + }, + { + command: (SDK: BlockFrostAPI) => + SDK.drepsByIdUpdates( + 'drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn', + ), + path: mainnetUrl( + `governance/dreps/drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn/updates`, + ), + endpointMock: [ + { + tx_hash: + 'f4097fbdb87ab7c7ab44b30d4e2b81713a058488975d1ab8b05c381dd946a393', + cert_index: 0, + action: 'registered', + }, + { + tx_hash: + 'dd3243af975be4b5bedce4e5f5b483b2386d5ad207d05e0289c1df0eb261447e', + cert_index: 0, + action: 'deregistered', + }, + ], + response: [ + { + tx_hash: + 'f4097fbdb87ab7c7ab44b30d4e2b81713a058488975d1ab8b05c381dd946a393', + cert_index: 0, + action: 'registered', + }, + { + tx_hash: + 'dd3243af975be4b5bedce4e5f5b483b2386d5ad207d05e0289c1df0eb261447e', + cert_index: 0, + action: 'deregistered', + }, + ], + }, + { + command: (SDK: BlockFrostAPI) => + SDK.drepsByIdVotes( + 'drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn', + ), + path: mainnetUrl( + `governance/dreps/drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn/votes`, + ), + endpointMock: [ + { + tx_hash: 'b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5', + cert_index: 2, + vote: 'yes', + }, + { + tx_hash: 'b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5', + cert_index: 3, + vote: 'abstain', + }, + ], + response: [ + { + tx_hash: 'b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5', + cert_index: 2, + vote: 'yes', + }, + { + tx_hash: 'b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5', + cert_index: 3, + vote: 'abstain', + }, + ], + }, ] as const;