Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Commit

Permalink
feat: Added pool breakdown of operator vs member stake, added option …
Browse files Browse the repository at this point in the history
…to add… (#202)

* Added pool breakdown of operator vs member stake, added option to add fees to epoch

* Prettier

* Added schema validation for epoch requests, fixed object naming
  • Loading branch information
alexkroeger authored May 2, 2020
1 parent d19ad19 commit e20daa5
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 11 deletions.
37 changes: 28 additions & 9 deletions src/handlers/staking_handlers.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import * as express from 'express';
import * as HttpStatus from 'http-status-codes';

import { schemas } from '../schemas/schemas';
import { StakingDataService } from '../services/staking_data_service';
import {
StakingDelegatorResponse,
StakingEpochsResponse,
StakingEpochsWithFeesResponse,
StakingPoolResponse,
StakingPoolsResponse,
StakingStatsResponse,
} from '../types';
import { schemaUtils } from '../utils/schema_utils';

export class StakingHandlers {
private readonly _stakingDataService: StakingDataService;
Expand Down Expand Up @@ -38,15 +41,31 @@ export class StakingHandlers {

res.status(HttpStatus.OK).send(response);
}
public async getStakingEpochsAsync(_req: express.Request, res: express.Response): Promise<void> {
const [currentEpoch, nextEpoch] = await Promise.all([
this._stakingDataService.getCurrentEpochAsync(),
this._stakingDataService.getNextEpochAsync(),
]);
const response: StakingEpochsResponse = {
currentEpoch,
nextEpoch,
};
public async getStakingEpochsAsync(req: express.Request, res: express.Response): Promise<void> {
// optional query string to include fees
schemaUtils.validateSchema(req.query, schemas.stakingEpochRequestSchema as any);
const isWithFees = req.query.withFees ? req.query.withFees === 'true' : false;

let response: StakingEpochsResponse | StakingEpochsWithFeesResponse;
if (isWithFees) {
const [currentEpoch, nextEpoch] = await Promise.all([
this._stakingDataService.getCurrentEpochWithFeesAsync(),
this._stakingDataService.getNextEpochWithFeesAsync(),
]);
response = {
currentEpoch,
nextEpoch,
};
} else {
const [currentEpoch, nextEpoch] = await Promise.all([
this._stakingDataService.getCurrentEpochAsync(),
this._stakingDataService.getNextEpochAsync(),
]);
response = {
currentEpoch,
nextEpoch,
};
}
res.status(HttpStatus.OK).send(response);
}
public async getStakingStatsAsync(_req: express.Request, res: express.Response): Promise<void> {
Expand Down
60 changes: 59 additions & 1 deletion src/queries/staking_queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,41 @@ export const currentEpochQuery = `
, zs.zrx_staked
FROM staking.current_epoch ce
CROSS JOIN zrx_deposited zd
CROSS JOIN zrx_staked zs;`;
CROSS JOIN zrx_staked zs`;

export const currentEpochWithFeesQuery = `
WITH zrx_staked AS (
SELECT
SUM(esps.zrx_delegated) AS zrx_staked
FROM staking.epoch_start_pool_status esps
JOIN staking.current_epoch ce ON ce.epoch_id = esps.epoch_id
)
, zrx_deposited AS (
SELECT
SUM(scc.amount) AS zrx_deposited
FROM staking.zrx_staking_contract_changes scc
JOIN staking.current_epoch ce
ON scc.block_number < ce.starting_block_number
OR (scc.block_number = ce.starting_block_number AND scc.transaction_index < ce.starting_transaction_index)
)
, protocol_fees AS (
SELECT
SUM(protocol_fee_paid) / 1e18::NUMERIC AS protocol_fees_generated_in_eth
FROM events.fill_events fe
JOIN staking.current_epoch ce
ON fe.block_number > ce.starting_block_number
OR (fe.block_number = ce.starting_block_number AND fe.transaction_index > ce.starting_transaction_index)
)
SELECT
ce.*
, zd.zrx_deposited
, zs.zrx_staked
, pf.protocol_fees_generated_in_eth
FROM staking.current_epoch ce
CROSS JOIN zrx_deposited zd
CROSS JOIN zrx_staked zs
CROSS JOIN protocol_fees pf;
`;

export const nextEpochQuery = `
WITH
Expand Down Expand Up @@ -239,6 +273,8 @@ export const currentEpochPoolsStatsQuery = `
, cebs.operator_share AS operator_share
, cebs.zrx_delegated AS zrx_staked
, ts.total_staked
, cebs.operator_zrx_delegated AS operator_zrx_staked
, cebs.member_zrx_delegated AS member_zrx_staked
, cebs.zrx_delegated / ts.total_staked AS share_of_stake
, fbp.protocol_fees AS total_protocol_fees_generated_in_eth
, fbp.num_fills AS number_of_fills
Expand Down Expand Up @@ -294,6 +330,8 @@ export const currentEpochPoolStatsQuery = `
, cebs.maker_addresses AS maker_addresses
, cebs.operator_share AS operator_share
, cebs.zrx_delegated AS zrx_staked
, cebs.operator_zrx_delegated AS operator_zrx_staked
, cebs.member_zrx_delegated AS member_zrx_staked
, ts.total_staked
, cebs.zrx_delegated / ts.total_staked AS share_of_stake
, fbp.protocol_fees AS total_protocol_fees_generated_in_eth
Expand All @@ -318,6 +356,14 @@ export const nextEpochPoolsStatsQuery = `
SELECT
pi.pool_id
, SUM(zsc.amount) AS zrx_staked
, SUM(CASE
WHEN pi.operator = zsc.staker THEN zsc.amount
ELSE 0.00
END) AS operator_zrx_staked
, SUM(CASE
WHEN pi.operator <> zsc.staker THEN zsc.amount
ELSE 0.00
END) AS member_zrx_staked
FROM staking.pool_info pi
LEFT JOIN staking.zrx_staking_changes zsc ON zsc.pool_id = pi.pool_id
GROUP BY 1
Expand Down Expand Up @@ -366,6 +412,8 @@ export const nextEpochPoolsStatsQuery = `
, pi.maker_addresses
, os.operator_share
, cs.zrx_staked
, cs.operator_zrx_staked
, cs.member_zrx_staked
, ts.total_staked
, cs.zrx_staked / ts.total_staked AS share_of_stake
, 0.00 AS total_protocol_fees_generated_in_eth
Expand All @@ -387,6 +435,14 @@ export const nextEpochPoolStatsQuery = `
SELECT
pi.pool_id
, SUM(zsc.amount) AS zrx_staked
, SUM(CASE
WHEN pi.operator = zsc.staker THEN zsc.amount
ELSE 0.00
END) AS operator_zrx_staked
, SUM(CASE
WHEN pi.operator <> zsc.staker THEN zsc.amount
ELSE 0.00
END) AS member_zrx_staked
FROM staking.pool_info pi
LEFT JOIN staking.zrx_staking_changes zsc ON zsc.pool_id = pi.pool_id
GROUP BY 1
Expand Down Expand Up @@ -435,6 +491,8 @@ export const nextEpochPoolStatsQuery = `
, pi.maker_addresses
, os.operator_share
, cs.zrx_staked
, cs.operator_zrx_staked
, cs.member_zrx_staked
, ts.total_staked
, cs.zrx_staked / ts.total_staked AS share_of_stake
, 0.00 AS total_protocol_fees_generated_in_eth
Expand Down
2 changes: 2 additions & 0 deletions src/schemas/schemas.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import * as metaTransactionFillRequestSchema from './meta_transaction_fill_request_schema.json';
import * as metaTransactionQuoteRequestSchema from './meta_transaction_quote_request_schema.json';
import * as sraPostOrderRequestSchema from './sra_post_order_request_schema.json';
import * as stakingEpochRequestSchema from './staking_epoch_request_schema.json';
import * as swapQuoteRequestSchema from './swap_quote_request_schema.json';

export const schemas = {
swapQuoteRequestSchema,
sraPostOrderRequestSchema,
metaTransactionFillRequestSchema,
metaTransactionQuoteRequestSchema,
stakingEpochRequestSchema,
};
11 changes: 11 additions & 0 deletions src/schemas/staking_epoch_request_schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"id": "/StakingEpochRequestSchema",
"properties": {
"withFees": {
"type": "string",
"enum": ["true", "false"]
}
},
"required": [],
"type": "object"
}
24 changes: 23 additions & 1 deletion src/services/staking_data_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
DelegatorEvent,
Epoch,
EpochDelegatorStats,
EpochWithFees,
Pool,
PoolEpochRewards,
PoolWithStats,
Expand All @@ -19,6 +20,7 @@ import {
RawDelegatorEvent,
RawDelegatorStaked,
RawEpoch,
RawEpochWithFees,
RawPool,
RawPoolEpochRewards,
RawPoolTotalProtocolFeesGenerated,
Expand All @@ -41,15 +43,35 @@ export class StakingDataService {
return epoch;
}

public async getCurrentEpochWithFeesAsync(): Promise<EpochWithFees> {
const rawEpochWithFees: RawEpochWithFees | undefined = _.head(
await this._connection.query(queries.currentEpochWithFeesQuery),
);
if (!rawEpochWithFees) {
throw new Error('Could not find the current epoch.');
}
const epoch = stakingUtils.getEpochWithFeesFromRaw(rawEpochWithFees);
return epoch;
}

public async getNextEpochAsync(): Promise<Epoch> {
const rawEpoch: RawEpoch | undefined = _.head(await this._connection.query(queries.nextEpochQuery));
if (!rawEpoch) {
throw new Error('Could not find the next current epoch.');
throw new Error('Could not find the next epoch.');
}
const epoch = stakingUtils.getEpochFromRaw(rawEpoch);
return epoch;
}

public async getNextEpochWithFeesAsync(): Promise<EpochWithFees> {
const rawEpoch: RawEpochWithFees | undefined = _.head(await this._connection.query(queries.nextEpochQuery));
if (!rawEpoch) {
throw new Error('Could not find the next epoch.');
}
const epoch = stakingUtils.getEpochWithFeesFromRaw(rawEpoch);
return epoch;
}

public async getStakingPoolsAsync(): Promise<Pool[]> {
const rawPools: RawPool[] = await this._connection.query(queries.stakingPoolsQuery);
const pools = stakingUtils.getPoolsFromRaw(rawPools);
Expand Down
18 changes: 18 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ export interface RawEpoch {
zrx_staked?: string;
}

// Separating out the response with fees
// As this is a significantly heavier query (it has to sum over fills)
export interface RawEpochWithFees extends RawEpoch {
protocol_fees_generated_in_eth: string;
}

export interface TransactionDate {
blockNumber: number;
txHash: string;
Expand All @@ -89,6 +95,10 @@ export interface Epoch {
zrxDeposited: number;
}

export interface EpochWithFees extends Epoch {
protocolFeesGeneratedInEth: number;
}

export interface RawPool {
pool_id: string;
operator: string;
Expand Down Expand Up @@ -153,6 +163,8 @@ export interface RawEpochPoolStats {
maker_addresses: string[];
operator_share?: string;
zrx_staked?: string;
operator_zrx_staked?: string;
member_zrx_staked?: string;
total_staked?: string;
share_of_stake?: string;
total_protocol_fees_generated_in_eth?: string;
Expand All @@ -165,6 +177,8 @@ export interface RawEpochPoolStats {
export interface EpochPoolStats {
poolId: string;
zrxStaked: number;
operatorZrxStaked: number;
memberZrxStaked: number;
shareOfStake: number;
operatorShare?: number;
makerAddresses: string[];
Expand Down Expand Up @@ -291,6 +305,10 @@ export interface StakingEpochsResponse {
currentEpoch: Epoch;
nextEpoch: Epoch;
}
export interface StakingEpochsWithFeesResponse {
currentEpoch: EpochWithFees;
nextEpoch: EpochWithFees;
}
export interface StakingStatsResponse {
allTime: AllTimeStakingStats;
}
Expand Down
40 changes: 40 additions & 0 deletions src/utils/staking_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
DelegatorEvent,
Epoch,
EpochPoolStats,
EpochWithFees,
Pool,
PoolAvgRewards,
PoolEpochDelegatorStats,
Expand All @@ -20,6 +21,7 @@ import {
RawDelegatorStaked,
RawEpoch,
RawEpochPoolStats,
RawEpochWithFees,
RawPool,
RawPoolAvgRewards,
RawPoolEpochRewards,
Expand Down Expand Up @@ -61,6 +63,40 @@ export const stakingUtils = {
zrxStaked: Number(zrx_staked || 0),
};
},
getEpochWithFeesFromRaw: (rawEpochWithFees: RawEpochWithFees): EpochWithFees => {
const {
epoch_id,
starting_transaction_hash,
starting_block_number,
starting_block_timestamp,
ending_transaction_hash,
ending_block_number,
ending_block_timestamp,
zrx_deposited,
zrx_staked,
protocol_fees_generated_in_eth,
} = rawEpochWithFees;
let epochEnd: TransactionDate | undefined;
if (ending_transaction_hash && ending_block_number) {
epochEnd = {
blockNumber: parseInt(ending_block_number, 10),
txHash: ending_transaction_hash,
timestamp: ending_block_timestamp || undefined,
};
}
return {
epochId: parseInt(epoch_id, 10),
epochStart: {
blockNumber: parseInt(starting_block_number, 10),
txHash: starting_transaction_hash,
timestamp: starting_block_timestamp || undefined,
},
epochEnd,
zrxDeposited: Number(zrx_deposited || 0),
zrxStaked: Number(zrx_staked || 0),
protocolFeesGeneratedInEth: Number(protocol_fees_generated_in_eth || 0),
};
},
getPoolFromRaw: (rawPool: RawPool): Pool => {
const {
pool_id,
Expand Down Expand Up @@ -100,6 +136,8 @@ export const stakingUtils = {
maker_addresses,
operator_share,
zrx_staked,
operator_zrx_staked,
member_zrx_staked,
share_of_stake,
total_protocol_fees_generated_in_eth,
share_of_fees,
Expand All @@ -110,6 +148,8 @@ export const stakingUtils = {
return {
poolId: pool_id,
zrxStaked: Number(zrx_staked || 0),
operatorZrxStaked: Number(operator_zrx_staked || 0),
memberZrxStaked: Number(member_zrx_staked || 0),
shareOfStake: Number(share_of_stake),
operatorShare: _.isNil(operator_share) ? undefined : Number(operator_share),
approximateStakeRatio: approximate_stake_ratio ? Number(approximate_stake_ratio) : 0,
Expand Down

0 comments on commit e20daa5

Please sign in to comment.