Skip to content

Commit

Permalink
fix(PE-7080): add apis for fetching paginated delegates
Browse files Browse the repository at this point in the history
  • Loading branch information
dtfiedler committed Nov 7, 2024
1 parent acee2a0 commit e3d4af2
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 32 deletions.
54 changes: 54 additions & 0 deletions src/common/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
AoEpochData,
AoEpochSettings,
AoGateway,
AoGatewayDelegate,
AoIORead,
AoIOWrite,
AoRegistrationFees,
Expand Down Expand Up @@ -313,6 +314,54 @@ export class IOReadable implements AoIORead {
});
}

async getGatewayDelegates(
params?: { address: WalletAddress } & PaginationParams,
): Promise<PaginationResult<AoGatewayDelegate>> {
const allTags = [
{ name: 'Action', value: 'Paginated-Delegates' },
{ name: 'Address', value: params?.address },
{ name: 'Cursor', value: params?.cursor?.toString() },
{ name: 'Limit', value: params?.limit?.toString() },
{ name: 'Sort-By', value: params?.sortBy },
{ name: 'Sort-Order', value: params?.sortOrder },
];

const prunedTags: { name: string; value: string }[] = allTags.filter(
(tag: {
name: string;
value: string | undefined;
}): tag is { name: string; value: string } => tag.value !== undefined,
);

return this.process.read<PaginationResult<AoGatewayDelegate>>({
tags: prunedTags,
});
}

async getGatewayDelegateAllowList(
params?: Omit<PaginationParams, 'sortBy'> & { address: WalletAddress },
): Promise<PaginationResult<WalletAddress>> {
const allTags = [
{ name: 'Action', value: 'Paginated-Allowed-Delegates' },
{ name: 'Address', value: params?.address },
{ name: 'Cursor', value: params?.cursor?.toString() },
{ name: 'Limit', value: params?.limit?.toString() },
{ name: 'Sort-Order', value: params?.sortOrder },
// note: sortBy is omitted because it's not supported for this action as table is an of addresses
];

const prunedTags: { name: string; value: string }[] = allTags.filter(
(tag: {
name: string;
value: string | undefined;
}): tag is { name: string; value: string } => tag.value !== undefined,
);

return this.process.read<PaginationResult<WalletAddress>>({
tags: prunedTags,
});
}

async getGateways(
pageParams?: PaginationParams,
): Promise<PaginationResult<AoGatewayWithAddress>> {
Expand Down Expand Up @@ -751,6 +800,7 @@ export class IOWriteable extends IOReadable implements AoIOWrite {
{
operatorStake,
allowDelegatedStaking,
allowedDelegates,
delegateRewardShareRatio,
fqdn,
label,
Expand All @@ -776,6 +826,10 @@ export class IOWriteable extends IOReadable implements AoIOWrite {
name: 'Allow-Delegated-Staking',
value: allowDelegatedStaking?.toString(),
},
{
name: 'Allowed-Delegates',
value: allowedDelegates?.join(','),
},
{
name: 'Delegate-Reward-Share-Ratio',
value: delegateRewardShareRatio?.toString(),
Expand Down
48 changes: 18 additions & 30 deletions src/types/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export type PaginationResult<T> = {
items: T[];
nextCursor: string | undefined;
totalItems: number;
sortBy: keyof T;
sortBy?: keyof T;
sortOrder: 'asc' | 'desc';
hasMore: boolean;
};
Expand Down Expand Up @@ -188,10 +188,12 @@ export type AoGatewayServices =
}
| undefined; // not required, for now

export type AoGatewayDelegates = Record<WalletAddress, AoGatewayDelegate>;
export type AoGatewayDelegateAllowList = WalletAddress[];

export type AoGateway = {
settings: AoGatewaySettings;
stats: AoGatewayStats;
delegates: Record<WalletAddress, AoGatewayDelegate>;
totalDelegatedStake: number;
vaults: Record<WalletAddress, AoVaultData>;
startTimestamp: Timestamp;
Expand Down Expand Up @@ -240,8 +242,9 @@ export type AoGatewayDelegate = {
};

export type AoGatewaySettings = {
allowDelegatedStaking: boolean;
allowDelegatedStaking: boolean | 'allowlist';
delegateRewardShareRatio: number;
allowedDelegates: WalletAddress[];
minDelegatedStake: number;
autoStake: boolean;
label: string;
Expand Down Expand Up @@ -312,6 +315,14 @@ export interface AoIORead {
}: {
address: WalletAddress;
}): Promise<AoGateway | undefined>;
// TODO: these could be moved to a separate Gateways class that implements gateway specific interactions
getGatewayDelegates(
params?: PaginationParams,
): Promise<PaginationResult<AoGatewayDelegate>>;
getGatewayDelegateAllowList(
params?: PaginationParams,
): Promise<PaginationResult<WalletAddress>>;
// END OF GATEWAY SPECIFIC INTERACTIONS
getGateways(
params?: PaginationParams,
): Promise<PaginationResult<AoGatewayWithAddress>>;
Expand Down Expand Up @@ -387,38 +398,14 @@ export interface AoIOWrite extends AoIORead {
},
options?: WriteOptions,
): Promise<AoMessageResult>;
// TODO: these could be moved to a separate Gateways class that implements gateway specific interactions
joinNetwork(
{
operatorStake,
allowDelegatedStaking,
delegateRewardShareRatio,
fqdn,
label,
minDelegatedStake,
note,
port,
properties,
protocol,
autoStake,
observerAddress,
}: AoJoinNetworkParams,
params: AoJoinNetworkParams,
options?: WriteOptions,
): Promise<AoMessageResult>;
leaveNetwork(options?: WriteOptions): Promise<AoMessageResult>;
updateGatewaySettings(
{
allowDelegatedStaking,
delegateRewardShareRatio,
fqdn,
label,
minDelegatedStake,
note,
port,
properties,
protocol,
autoStake,
observerAddress,
}: AoUpdateGatewaySettingsParams,
params: AoUpdateGatewaySettingsParams,
options?: WriteOptions,
): Promise<AoMessageResult>;
increaseOperatorStake(
Expand Down Expand Up @@ -462,6 +449,7 @@ export interface AoIOWrite extends AoIORead {
},
options?: WriteOptions,
): Promise<AoMessageResult>;
// END OF GATEWAY SPECIFIC INTERACTIONS
buyRecord(
params: {
name: string;
Expand Down
67 changes: 65 additions & 2 deletions tests/e2e/esm/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@ describe('e2e esm tests', async () => {
assert(typeof gateway.weights.tenureWeight === 'number');
assert(typeof gateway.weights.observerRewardRatioWeight === 'number');
assert(typeof gateway.weights.gatewayRewardRatioWeight === 'number');
if (gateway.vaults?.length > 0) {
gateway.vaults.forEach((vault) => {
assert(typeof vault.balance === 'number');
assert(typeof vault.startTimestamp === 'number');
});
}
});
});

Expand Down Expand Up @@ -191,14 +197,71 @@ describe('e2e esm tests', async () => {
assert(typeof gateway.weights.tenureWeight === 'number');
assert(typeof gateway.weights.observerRewardRatioWeight === 'number');
assert(typeof gateway.weights.gatewayRewardRatioWeight === 'number');
if (gateway.vaults?.length > 0) {
gateway.vaults.forEach((vault) => {
assert(typeof vault.balance === 'number');
assert(typeof vault.startTimestamp === 'number');
});
}
});
});

it('should be able to get a single gateway', async () => {
const gateways = await io.getGateway({
const gateway = await io.getGateway({
address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
});
assert.ok(gateways);
assert.ok(gateway);
});

it('should be able to get gateway delegates', async () => {
const delegates = await io.getGatewayDelegates({
address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
limit: 1,
sortBy: 'startTimestamp',
sortOrder: 'desc',
});
assert.ok(delegates);
assert(delegates.limit === 1);
assert(delegates.sortOrder === 'desc');
assert(delegates.sortBy === 'startTimestamp');
assert(typeof delegates.totalItems === 'number');
assert(typeof delegates.sortBy === 'string');
assert(typeof delegates.sortOrder === 'string');
assert(typeof delegates.limit === 'number');
assert(typeof delegates.hasMore === 'boolean');
if (delegates.nextCursor) {
assert(typeof delegates.nextCursor === 'string');
}
assert(Array.isArray(delegates.items));
delegates.items.forEach((delegate) => {
assert(Array.isArray(delegate.vaults));
assert(typeof delegate.delegatedStake === 'number');
assert(typeof delegate.startTimestamp === 'number');
});
});

it('should be able to get gateway delegate allow list', async () => {
const allowList = await io.getGatewayDelegateAllowList({
address: 'QGWqtJdLLgm2ehFWiiPzMaoFLD50CnGuzZIPEdoDRGQ',
limit: 1,
sortBy: 'startTimestamp',
sortOrder: 'desc',
});
assert.ok(allowList);
// note: sortBy is omitted because it's not supported for the contract handler
assert(allowList.limit === 1);
assert(allowList.sortOrder === 'desc');
assert(typeof allowList.totalItems === 'number');
assert(typeof allowList.sortOrder === 'string');
assert(typeof allowList.limit === 'number');
assert(typeof allowList.hasMore === 'boolean');
if (allowList.nextCursor) {
assert(typeof allowList.nextCursor === 'string');
}
assert(Array.isArray(allowList.items));
allowList.items.forEach((address) => {
assert(typeof address === 'string');
});
});

it('should be able to get balances, defaulting to first page', async () => {
Expand Down

0 comments on commit e3d4af2

Please sign in to comment.