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

address feedback from team #5

Merged
merged 3 commits into from
Jan 15, 2025
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
7 changes: 3 additions & 4 deletions src/controllers/applicationController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import { catchError, validateRequest } from '@/utils';
import { IsNullError, NotFoundError } from '@/errors';
import { createLogger } from '@/logger';
import { indexerClient } from '@/ext/indexer';
import { type PoolIdChainId } from './types';

const logger = createLogger();

interface CreateApplicationRequest {
chainId: number;
alloPoolId: string;
interface CreateApplicationRequest extends PoolIdChainId {
alloApplicationId: string;
}

Expand Down Expand Up @@ -70,7 +69,7 @@ export const createApplication = async (
);

// Handle errors
if (error !== null || application === null) {
if (error !== undefined || application === null) {
logger.error(`Failed to create application: ${error?.message}`);
res
.status(500)
Expand Down
38 changes: 31 additions & 7 deletions src/controllers/metricController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ const logger = createLogger();
const isMetric = (obj: any): obj is Metric => {
return (
typeof obj === 'object' &&
typeof obj.identifier === 'string' &&
typeof obj.name === 'string' &&
typeof obj.description === 'string' &&
(obj.orientation === MetricOrientation.Increase ||
obj.orientation === MetricOrientation.Decrease) &&
typeof obj.active === 'boolean'
typeof obj.enabled === 'boolean'
);
};

Expand All @@ -32,7 +33,7 @@ export const addMetrics = async (

// TODO: ensure caller is admin

const data = req.body;
const data = req.body as Metric[];

// Combined validation to check if req.body is Metric[]
if (!isValidMetricsData(data)) {
Expand All @@ -42,18 +43,41 @@ export const addMetrics = async (

const metricsData: Metric[] = data;

const [error, metrics] = await catchError(
metricService.saveMetrics(metricsData)
);
const [error] = await catchError(metricService.saveMetrics(metricsData));

if (error != null || metrics == null) {
if (error !== undefined) {
logger.error(`Failed to save metrics: ${error?.message}`);
res
.status(500)
.json({ message: 'Error saving metrics', error: error?.message });
throw new IsNullError('Error saving metrics');
}

logger.info('successfully saved metrics', metrics);
logger.info('successfully saved metrics');
res.status(201).json({ message: 'Metrics saved successfully.' });
};

export const updateMetric = async (
req: Request,
res: Response
): Promise<void> => {
validateRequest(req, res);

const identifier = req.params.identifier;
const metric = req.body as Partial<Metric>;

const [error, metrics] = await catchError(
metricService.updateMetric(identifier, metric)
);

if (error !== undefined) {
logger.error(`Failed to update metric: ${error?.message}`);
res
.status(500)
.json({ message: 'Error updating metric', error: error?.message });
throw new IsNullError('Error updating metric');
}

logger.info('successfully updated metric', metrics);
res.status(200).json({ message: 'Metric updated successfully.' });
};
103 changes: 44 additions & 59 deletions src/controllers/poolController.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Request, Response } from 'express';
import poolService from '@/service/PoolService';
import applicationService from '@/service/ApplicationService';
import { catchError, isPoolManager, validateRequest } from '@/utils';
import { catchError, validateRequest } from '@/utils';
import { createLogger } from '@/logger';
import {
indexerClient,
Expand All @@ -13,31 +13,23 @@ import {
IsNullError,
NotFoundError,
ServerError,
UnauthorizedError,
} from '@/errors';
import { EligibilityType } from '@/entity/EligibilityCriteria';
import { calculate } from '@/utils/calculate';
import { type Hex } from 'viem';
import eligibilityCriteriaService from '@/service/EligibilityCriteriaService';
import { type PoolIdChainId } from './types';

const logger = createLogger();

interface CreatePoolRequest {
chainId: number;
alloPoolId: string;
metricsIds: number[];
interface CreatePoolRequest extends PoolIdChainId {
metricIdentifiers: string[];
eligibilityType: EligibilityType;
eligibilityData: object;
}

interface ChainIdAlloPoolIdRequest {
chainId: number;
alloPoolId: string;
}

interface FinalizePoolRequest {
chainId: number;
alloPoolId: string;
signature: Hex;
interface EligibilityCriteriaRequest extends PoolIdChainId {
eligibilityType: EligibilityType;
data: object;
}

/**
Expand All @@ -53,9 +45,13 @@ export const createPool = async (
// Validate the incoming request
validateRequest(req, res);

// Extract chainId and alloPoolId from the request body
const { chainId, alloPoolId, eligibilityType, eligibilityData, metricsIds } =
req.body as CreatePoolRequest;
const {
chainId,
alloPoolId,
eligibilityType,
eligibilityData,
metricIdentifiers,
} = req.body as CreatePoolRequest;

logger.info(
`Received create pool request for chainId: ${chainId}, alloPoolId: ${alloPoolId}`
Expand All @@ -75,33 +71,32 @@ export const createPool = async (
})
);

if (errorFetching !== null || indexerPoolData === null) {
if (errorFetching !== undefined || indexerPoolData === null) {
res.status(404).json({ message: 'Pool not found on indexer' });
throw new NotFoundError('Pool not found on indexer');
}

// Get or create the pool
// Create the pool with the fetched data
const [error, pool] = await catchError(
const [error] = await catchError(
poolService.createNewPool(
chainId,
alloPoolId,
eligibilityType,
eligibilityData,
metricsIds
metricIdentifiers
)
);

// Handle errors during the create operation
if (error != null || pool == null) {
if (error !== undefined) {
logger.error(`Failed to create pool: ${error?.message}`);
res
.status(500)
.json({ message: 'Error creating pool', error: error?.message });
throw new IsNullError(`Error creating pool`);
}

logger.info('successfully created pool', pool);
logger.info('successfully created pool');
res.status(200).json({ message: 'pool created successfully' });
};

Expand All @@ -116,7 +111,7 @@ export const syncPool = async (req: Request, res: Response): Promise<void> => {
validateRequest(req, res);

// Extract chainId and alloPoolId from the request body
const { chainId, alloPoolId } = req.body as ChainIdAlloPoolIdRequest;
const { chainId, alloPoolId } = req.body as PoolIdChainId;

// Log the receipt of the update request
logger.info(
Expand All @@ -132,7 +127,7 @@ export const syncPool = async (req: Request, res: Response): Promise<void> => {
);

// Handle errors or missing data from the indexer
if (errorFetching != null || indexerPoolData == null) {
if (errorFetching !== undefined || indexerPoolData == null) {
logger.warn(
`No pool found for chainId: ${chainId}, alloPoolId: ${alloPoolId}`
);
Expand Down Expand Up @@ -175,7 +170,7 @@ const updateApplications = async (
* @param res - Express response object
*/
export const calculateDistribution = async (req, res): Promise<void> => {
const { chainId, alloPoolId } = req.body as ChainIdAlloPoolIdRequest;
const { chainId, alloPoolId } = req.body as PoolIdChainId;

const [errorFetching, distribution] = await catchError(
calculate(chainId, alloPoolId)
Expand Down Expand Up @@ -205,43 +200,33 @@ export const calculateDistribution = async (req, res): Promise<void> => {
res.status(200).json({ message: 'Distribution updated successfully' });
};

/**
* Finalizes the distribution of a pool based on chainId and alloPoolId
*
* @param req - Express request object
* @param res - Express response object
*/
export const finalizeDistribution = async (
req: Request,
res: Response
): Promise<void> => {
const { chainId, alloPoolId, signature } = req.body as FinalizePoolRequest;
export const updateEligibilityCriteria = async (req, res): Promise<void> => {
const { eligibilityType, alloPoolId, chainId, data } =
req.body as EligibilityCriteriaRequest;

if (
!(await isPoolManager(
{ chainId, alloPoolId },
signature,
chainId,
alloPoolId
))
) {
res.status(401).json({ message: 'Unauthorized' });
throw new UnauthorizedError('Unauthorized');
}
// Log the receipt of the update request
logger.info(
`Received update eligibility criteria request for chainId: ${chainId}, alloPoolId: ${alloPoolId}`
);

const [errorFinalizing, finalizedDistribution] = await catchError(
poolService.finalizePoolDistribution(alloPoolId, chainId)
const [error] = await catchError(
eligibilityCriteriaService.saveEligibilityCriteria({
chainId,
alloPoolId,
eligibilityType,
data,
})
);

if (errorFinalizing !== null || finalizedDistribution === null) {
logger.error(
`Failed to finalize distribution: ${errorFinalizing?.message}`
);
if (error !== undefined) {
logger.error(`Failed to update eligibility criteria: ${error?.message}`);
res.status(500).json({
message: 'Error finalizing distribution',
error: errorFinalizing?.message,
message: 'Error updating eligibility criteria',
error: error?.message,
});
}

res.status(200).json({ message: 'Distribution finalized successfully' });
res.status(200).json({
message: 'Eligibility criteria updated successfully',
});
};
23 changes: 15 additions & 8 deletions src/controllers/voteController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@ import { BadRequestError, ServerError, UnauthorizedError } from '@/errors';
import { createLogger } from '@/logger';
import { calculate } from '@/utils/calculate';
import { type Pool } from '@/entity/Pool';
import { type Vote } from '@/entity/Vote';
import { type Ballot, type Vote } from '@/entity/Vote';
import eligibilityCriteriaService from '@/service/EligibilityCriteriaService';
import { type Hex } from 'viem';
import { env } from 'process';
import { type PoolIdChainId } from './types';
const logger = createLogger();

interface SubmitVoteRequest extends PoolIdChainId {
voter: string;
ballot: Ballot[];
signature: Hex;
}

/**
* Submits a vote for a given pool
*
Expand All @@ -25,7 +32,8 @@ export const submitVote = async (
// Validate the incoming request
validateRequest(req, res);

const { voter, alloPoolId, chainId, ballot, signature } = req.body;
const { voter, alloPoolId, chainId, ballot, signature } =
req.body as SubmitVoteRequest;
if (
typeof voter !== 'string' ||
typeof alloPoolId !== 'string' ||
Expand All @@ -34,8 +42,7 @@ export const submitVote = async (
(Array.isArray(ballot) &&
ballot.every(
item =>
typeof item.metricName === 'string' &&
(item.metricId === undefined || typeof item.metricId === 'number') &&
typeof item.metricIdentifier === 'string' &&
typeof item.voteShare === 'number'
))
) {
Expand All @@ -56,7 +63,7 @@ export const submitVote = async (
if (
!(await checkVoterEligibility(
{ alloPoolId, chainId },
signature as Hex,
signature,
pool,
voter
))
Expand All @@ -65,7 +72,7 @@ export const submitVote = async (
throw new BadRequestError('Not Authorzied');
}

const [error, result] = await catchError(
const [error] = await catchError(
voteService.saveVote({
voter,
alloPoolId,
Expand All @@ -76,7 +83,7 @@ export const submitVote = async (
})
);

if (error !== null || result === null) {
if (error !== null) {
res
.status(500)
.json({ message: 'Error submitting vote', error: error?.message });
Expand All @@ -86,7 +93,7 @@ export const submitVote = async (
// Trigger the distribution without waiting
void calculate(chainId, alloPoolId);

logger.info('Vote submitted successfully', result);
logger.info('Vote submitted successfully');
res.status(201).json({ message: 'Vote submitted successfully' });
};

Expand Down
5 changes: 1 addition & 4 deletions src/entity/EligibilityCriteria.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export enum EligibilityType {
}

@Entity()
@Unique(['poolId'])
@Unique(['chainId', 'alloPoolId'])
export class EligibilityCriteria {
@PrimaryGeneratedColumn()
id: number;
Expand All @@ -37,7 +37,4 @@ export class EligibilityCriteria {

@Column('json')
data: any;

@Column() // Explicitly define the foreign key column for pool
poolId: number;
}
Loading
Loading