Skip to content

Commit

Permalink
chore: added get_links, get_proposals and get_actions
Browse files Browse the repository at this point in the history
  • Loading branch information
dafuga committed Sep 21, 2023
1 parent f26d558 commit eaef62e
Show file tree
Hide file tree
Showing 10 changed files with 1,646 additions and 184 deletions.
76 changes: 70 additions & 6 deletions src/endpoints.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
import {ABI, APIClient} from '@wharfkit/antelope'
import {GetVotersResponse} from './types'
import {APIClient, NameType} from '@wharfkit/antelope'
import {GetABISnapshotResponse, GetActionsResponse, GetLinksResponse, GetProposalsResponse, GetVotersResponse} from './types'

export class HyperionAPIClient {
constructor(private client: APIClient) {}

async get_abi_snapshot(contract: string, block?: number, fetch = false): Promise<ABI.Def> {
async get_abi_snapshot(contract: string, block?: number, fetch = false): Promise<GetABISnapshotResponse> {
if (!block) {
const info = await this.client.v1.chain.get_info()

block = Number(info.last_irreversible_block_num)
}

return this.client.call<ABI.Def>({
return this.client.call({
path: `/v2/history/get_abi_snapshot?contract=${encodeURIComponent(
contract
)}&block=${block}&fetch=${fetch}`,
method: 'GET',
responseType: GetABISnapshotResponse
})
}

async get_voters(
producer?: string,
producer?: NameType,
proxy?: boolean,
skip?: number,
limit?: number
): Promise<GetVotersResponse> {
let queryParams = ''
const queryParts: string[] = []

if (producer) queryParts.push(`producer=${encodeURIComponent(producer)}`)
if (producer) queryParts.push(`producer=${producer}`)
if (proxy !== undefined) queryParts.push(`proxy=${proxy}`)
if (skip !== undefined) queryParts.push(`skip=${skip}`)
if (limit !== undefined) queryParts.push(`limit=${limit}`)
Expand All @@ -41,4 +42,67 @@ export class HyperionAPIClient {
responseType: GetVotersResponse,
})
}

async get_links(account?: NameType): Promise<GetLinksResponse> {
const queryParams = account ? `?account=${account}` : '';

return this.client.call({
path: `/v2/state/get_links${queryParams}`,
method: 'GET',
responseType: GetLinksResponse,
});
}

async get_proposals(options?: {
proposer?: NameType,
proposal?: NameType,
account?: NameType,
requested?: string,
provided?: string,
track?: number | boolean,
skip?: number,
limit?: number
}): Promise<GetProposalsResponse> {
const queryParts: string[] = [];

for (const [key, value] of Object.entries(options || {})) {
queryParts.push(`${key}=${value}`);
}

const queryParams = queryParts.length ? '?' + queryParts.join('&') : '';

return this.client.call({
path: `/v2/state/get_proposals${queryParams}`,
method: 'GET',
responseType: GetProposalsResponse,
});
}

async get_actions(account: string, options?: {
filter?: string,
skip?: number,
limit?: number,
sort?: string,
after?: string,
before?: string,
transfer_to?: string,
transfer_from?: string,
transfer_symbol?: string,
act_name?: string,
act_account?: string
}): Promise<GetActionsResponse> {
const queryParts: string[] = [`account=${account}`];

for (const [key, value] of Object.entries(options || {})) {
queryParts.push(`${key}=${value}`);
}

const queryParams = queryParts.length ? '?' + queryParts.join('&') : '';

return this.client.call({
path: `/v2/history/get_actions${queryParams}`,
method: 'GET',
responseType: GetActionsResponse,
});
}
}
101 changes: 94 additions & 7 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,100 @@
import {Float64, Name, Struct, UInt32} from '@wharfkit/antelope'
import {ABI, Authority, BlockTimestamp, Checksum256, Float64, Name, PermissionLevel, PermissionLevelType, Struct, TimePoint, UInt32, UInt64} from '@wharfkit/antelope'

@Struct.type('voter')
export class Voter extends Struct {
@Struct.field('name') declare account: Name
@Struct.field('float64') declare weight: Float64
@Struct.field('uint32') declare last_vote: UInt32
@Struct.type('get_abi_snapshot_response')
export class GetABISnapshotResponse extends Struct {
@Struct.field(UInt32) declare block_num: UInt32
@Struct.field(ABI) declare abi: ABI
@Struct.field(Float64) declare query_time_ms: Float64
}

@Struct.type('get_voters_response_voter')
export class GetVotersResponseVoter extends Struct {
@Struct.field(Name) declare account: Name
@Struct.field(Float64) declare weight: Float64
@Struct.field(UInt32) declare last_vote: UInt32
}

@Struct.type('get_voters_response')
export class GetVotersResponse extends Struct {
@Struct.field(Voter, {array: true}) declare voters: Voter[]
@Struct.field(GetVotersResponseVoter, {array: true}) declare voters: GetVotersResponseVoter[]
}

@Struct.type('get_links_response_link')
export class GetLinksResponseLink extends Struct {
@Struct.field(UInt32) declare block_num: UInt32
@Struct.field(BlockTimestamp) declare timestamp: BlockTimestamp
@Struct.field(Name) declare account: Name
@Struct.field('string') declare permission: string
@Struct.field('string') declare code: string
@Struct.field('string') declare action: string
@Struct.field("bool", { optional: true }) declare irreversible?: boolean
}

@Struct.type('total_count')
export class TotalCount extends Struct {
@Struct.field(UInt32) declare value: UInt32
@Struct.field('string') declare relation: string
}

@Struct.type('get_links_response')
export class GetLinksResponse extends Struct {
@Struct.field(Float64) declare query_time_ms: Float64
@Struct.field('bool') declare cached: boolean
@Struct.field('bool', { optional: true }) declare hot_only?: boolean
@Struct.field(UInt32, { optional: true }) declare lib?: UInt32
@Struct.field(TotalCount) declare total: TotalCount
@Struct.field(GetLinksResponseLink, {array: true}) declare links: GetLinksResponseLink[]
}

@Struct.type('approval')
export class Approval extends Struct {
@Struct.field(Name) declare actor: Name;
@Struct.field(Name) declare permission: Name;
@Struct.field(TimePoint) declare time: TimePoint;
}

@Struct.type('proposal')
export class Proposal extends Struct {
@Struct.field(Approval, {array: true}) declare provided_approvals: Approval[];
@Struct.field(Approval, {array: true}) declare requested_approvals: Approval[];
@Struct.field(UInt32) declare block_num: UInt32;
@Struct.field(Name) declare proposer: Name;
@Struct.field(Name) declare proposal_name: Name;
@Struct.field(UInt64) declare primary_key: UInt64;
@Struct.field('bool') declare executed: boolean;
}


@Struct.type('get_proposals_response')
export class GetProposalsResponse extends Struct {
@Struct.field(Float64, {optional: true}) declare query_time?: Float64;
@Struct.field('bool') declare cached: boolean;
@Struct.field(TotalCount) declare total: TotalCount;
@Struct.field(Proposal, {array: true}) declare proposals: Proposal[];
@Struct.field(Float64) declare query_time_ms: Float64;
}

@Struct.type('act')
export class ActionAct extends Struct {
@Struct.field(Name) declare account: Name;
@Struct.field(Name) declare name: Name;
@Struct.field(PermissionLevel, { array: true }) declare authorization: PermissionLevel[];
@Struct.field('any') declare data: any;
}

@Struct.type('action')
export class Action extends Struct {
@Struct.field(UInt32) declare block_num: UInt32
@Struct.field(BlockTimestamp) declare timestamp: BlockTimestamp
@Struct.field(Checksum256) declare trx_id: Checksum256
@Struct.field(ActionAct) declare act: ActionAct
}

@Struct.type('get_actions_response')
export class GetActionsResponse extends Struct {
@Struct.field(Float64) declare query_time_ms: Float64;
@Struct.field('bool') declare cached: boolean;
@Struct.field(UInt32, { optional: true }) declare lib?: UInt32;
@Struct.field(TotalCount) declare total: TotalCount;
@Struct.field(Action, { array: true }) declare actions: Action[];
}
58 changes: 42 additions & 16 deletions test/api.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {assert} from 'chai'

import {APIClient, FetchProvider} from '@wharfkit/antelope'
import {APIClient, FetchProvider, Name} from '@wharfkit/antelope'
import {mockFetch} from '@wharfkit/mock-data'

import {HyperionAPIClient, Types} from '$lib'
import {HyperionAPIClient} from '$lib'

const ABIResponse = {
// Add mock data that mimics the actual ABI snapshot structure
};

const client = new APIClient({
provider: new FetchProvider('https://eos.hyperion.eosrio.io/', {fetch: mockFetch}),
provider: new FetchProvider('https://wax.blokcrafters.io/', {fetch: mockFetch}),
})

const hyperion = new HyperionAPIClient(client)
Expand All @@ -21,21 +21,47 @@ suite('Hyperion API', function () {

test('get_abi_snapshot', async function () {
const response = await hyperion.get_abi_snapshot("eosio.token", 2000, true);
assert.deepEqual(response, {
"block_num": null,
"error": "abi not found for eosio.token until block 2000",
"last_indexed_block": 331963268,
"last_indexed_block_time": "2023-09-20T00:35:04.500",
"present": false,
"query_time_ms": 4,
});
assert.equal(response.abi.version, "eosio::abi/1.1")
})

test('get_voters', async function () {
const response = await hyperion.get_voters('eoscafeblock', true, 100, 200);
assert.equal(response.voters.length, 24);
assert(response.voters[0].account.equals('killc.ftw'));
assert(response.voters[0].weight.equals(20161076275.827435));
assert(response.voters[0].last_vote.equals(297527904));
const response = await hyperion.get_voters('teamgreymass', true, 100, 200);
assert.equal(response.voters.length, 100);
assert.instanceOf(response.voters[0].account, Name);
assert.equal(String(response.voters[0].account), 'j3.rq.wam');
assert.equal(Number(response.voters[0].weight), 1.5044807131168136e+39);
assert.equal(Number(response.voters[0].last_vote), 266448316);
});

test('get_links', async function () {
const response = await hyperion.get_links('teamgreymass');
assert.isArray(response.links);
assert.equal(response.links.length, 10);
assert.instanceOf(response.links[0].account, Name);
});

test('get_proposals', async function () {
const response = await hyperion.get_proposals({
skip: 1,
limit: 10
});

assert.isArray(response.proposals);
assert.equal(response.proposals.length, 10);
assert.instanceOf(response.proposals[0].proposer, Name);
})

test('get_actions', async function () {
const response = await hyperion.get_actions("teamgreymass", {
filter: "eosio.token:*",
skip: 100,
limit: 5
});


assert.isArray(response.actions);
assert.equal(response.actions.length, 5);
assert.instanceOf(response.actions[0].act.name, Name);
assert.instanceOf(response.actions[0].act.authorization[0].actor, Name);
});
})
Loading

0 comments on commit eaef62e

Please sign in to comment.