Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modified getStrategyHolders in Census3 and using new queue endpoint #393

Merged
merged 1 commit into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 51 additions & 22 deletions src/api/census3/strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum Census3StrategyAPIMethods {
VALIDATE_PREDICATE = '/strategies/predicate/validate',
OPERATORS = '/strategies/predicate/operators',
HOLDERS = '/strategies/{id}/holders',
HOLDERS_QUEUE = '/strategies/{id}/holders/queue/{queueId}',
}

export interface ICensus3StrategiesListResponse {
Expand All @@ -29,20 +30,6 @@ export interface ICensus3StrategiesListResponsePaginated extends ICensus3Strateg
pagination: Census3Pagination;
}

export interface ICensus3StrategyHoldersResponse {
/**
* The list of the strategy holders
*/
holders: { [key: string]: string };
}

export interface ICensus3StrategyHoldersResponsePaginated extends ICensus3StrategyHoldersResponse {
/**
* The pagination information
*/
pagination: Census3Pagination;
}

export type Census3Strategy = {
/**
* The strategy identifier
Expand Down Expand Up @@ -183,6 +170,38 @@ export interface ICensus3StrategyImportQueueResponse {
progress: number;
}

export interface ICensus3StrategyHoldersQueueResponse {
/**
* If the queue has been done
*/
done: boolean;

/**
* The error of the queue
*/
error: {
/**
* The code of the error
*/
code: number;

/**
* The string of the error
*/
error: string;
};

/**
* The list of the strategy holders
*/
data: { [key: string]: string };

/**
* The importing progress
*/
progress: number;
}

export interface ICensus3StrategyToken {
/**
* The id (address) of the token.
Expand Down Expand Up @@ -290,16 +309,26 @@ export abstract class Census3StrategyAPI extends Census3API {
*
* @param url - API endpoint URL
* @param id - The identifier of the strategy
* @param pagination - Pagination options
* @returns The queue identifier
*/
public static holders(
url: string,
id: number,
pagination?: Census3Pagination
): Promise<ICensus3StrategyHoldersResponsePaginated> {
public static holders(url: string, id: number): Promise<ICensus3QueueResponse> {
return axios
.get<ICensus3QueueResponse>(url + Census3StrategyAPIMethods.HOLDERS.replace('{id}', String(id)))
.then((response) => response.data)
.catch(this.isApiError);
}

/**
* Returns the information of the strategy holders queue
*
* @param url - API endpoint URL
* @param id - The identifier of the strategy
* @param queueId - The identifier of the strategy holders queue
*/
public static holdersQueue(url: string, id: number, queueId: string): Promise<ICensus3StrategyHoldersQueueResponse> {
return axios
.get<ICensus3StrategyHoldersResponsePaginated>(
url + Census3StrategyAPIMethods.HOLDERS.replace('{id}', String(id)) + this.serializePagination(pagination)
.get<ICensus3StrategyHoldersQueueResponse>(
url + Census3StrategyAPIMethods.HOLDERS_QUEUE.replace('{id}', String(id)).replace('{queueId}', queueId)
)
.then((response) => response.data)
.catch(this.isApiError);
Expand Down
39 changes: 29 additions & 10 deletions src/census3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,14 @@ import {
} from './api';
import invariant from 'tiny-invariant';
import { isAddress } from '@ethersproject/address';
import { TokenCensus } from './types';
import { TokenCensus, StrategyCensus } from './types';
import { delay } from './util/common';
import { Census3Pagination } from './api/census3/api';
import { StrategyCensus } from './types/census/census3/strategy';

export type Token = Omit<Census3Token, 'tags'> & { tags: string[] };
export type TokenSummary = Omit<Census3SummaryToken, 'tags'> & { tags: string[] };
export type Strategy = Census3Strategy;
export type StrategyHolder = { holder: string; weight: bigint };
export type StrategyHolders = { holders: StrategyHolder[]; pagination: Census3Pagination };
export type StrategyHolders = StrategyHolder[];
export type StrategyToken = Census3CreateStrategyToken;
export type Census3Census = ICensus3CensusResponse;
export type SupportedChain = ICensus3SupportedChain;
Expand Down Expand Up @@ -187,14 +185,35 @@ export class VocdoniCensus3Client {
* Returns the strategy holders
*
* @param id - The id of the strategy
* @param pagination - Pagination options
* @returns The list strategy holders
*/
getStrategyHolders(id: number, pagination: Census3Pagination = { pageSize: -1 }): Promise<StrategyHolders> {
return Census3StrategyAPI.holders(this.url, id, pagination).then((response) => ({
holders: Object.entries(response.holders).map(([key, value]) => ({ holder: key, weight: BigInt(value) })) ?? [],
pagination: response.pagination,
}));
getStrategyHolders(id: number): Promise<StrategyHolders> {
invariant(id, 'No id set');
const waitForQueue = (queueId: string, wait?: number, attempts?: number): Promise<StrategyHolders> => {
const waitTime = wait ?? this.queueWait?.retryTime;
const attemptsNum = attempts ?? this.queueWait?.attempts;
invariant(waitTime, 'No queue wait time set');
invariant(attemptsNum >= 0, 'No queue attempts set');

return attemptsNum === 0
? Promise.reject('Time out waiting for queue with id: ' + queueId)
: Census3StrategyAPI.holdersQueue(this.url, id, queueId).then((queue) => {
switch (true) {
case queue.done && queue.error?.code?.toString().length > 0:
return Promise.reject(new Error('Could not get the strategy holders'));
case queue.done:
return Promise.resolve(
Object.entries(queue.data).map(([key, value]) => ({ holder: key, weight: BigInt(value) })) ?? []
);
default:
return delay(waitTime).then(() => waitForQueue(queueId, waitTime, attemptsNum - 1));
}
});
};

return Census3StrategyAPI.holders(this.url, id)
.then((queueResponse) => queueResponse.queueID)
.then((queueId) => waitForQueue(queueId));
}

/**
Expand Down
9 changes: 3 additions & 6 deletions test/census3/integration/strategy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,13 @@ describe('Census3 strategies integration tests', () => {
const client = new VocdoniCensus3Client({ env: EnvOptions.DEV });
const strategies = await client.getStrategies();
if (strategies.length > 1) {
const holders = await client.getStrategyHolders(strategies[1].ID, { pageSize: 10 });
holders.holders.forEach((holder) => {
const holders = await client.getStrategyHolders(strategies[1].ID);
holders.forEach((holder) => {
expect(isAddress(holder.holder)).toBe(true);
expect(typeof holder.weight).toBe('bigint');
});
expect(holders.pagination.pageSize).toBe(10);
expect(isAddress(holders.pagination.nextCursor)).toBe(true);
expect(isAddress(holders.pagination.prevCursor)).toBe(true);
}
}, 5000);
}, 85000);
it('should return the given strategy', async () => {
const client = new VocdoniCensus3Client({ env: EnvOptions.DEV });
const strategies = await client.getStrategies();
Expand Down
Loading