Skip to content

Commit

Permalink
Type IStakingApi responses as "raw" (#2099)
Browse files Browse the repository at this point in the history
Types all the IStakingApi responses as "raw". These responses can therefore not be used directly unless they are validated:

- Add Raw utility type to IStakingApi
- Update validation where appropriate
  • Loading branch information
iamacook authored Nov 8, 2024
1 parent 3d9cf07 commit d51ef03
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ export const DefiVaultStatsSchema = z.object({
updated_at_block: z.number(),
});

export const DefiVaultsStateSchema = z.array(DefiVaultStatsSchema);

export type DefiVaultStats = z.infer<typeof DefiVaultStatsSchema>;
2 changes: 2 additions & 0 deletions src/datasources/staking-api/entities/deployment.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ export const DeploymentSchema = z.object({
product_fee: NumericStringSchema.nullish().default(null),
});

export const DeploymentsSchema = z.array(DeploymentSchema);

export type Deployment = z.infer<typeof DeploymentSchema>;
2 changes: 2 additions & 0 deletions src/datasources/staking-api/entities/stake.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@ export const StakeSchema = z.object({
net_claimable_consensus_rewards: NumericStringSchema.nullish().default(null),
});

export const StakesSchema = z.array(StakeSchema);

export type Stake = z.infer<typeof StakeSchema>;
33 changes: 19 additions & 14 deletions src/datasources/staking-api/kiln-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ import type { PooledStakingStats } from '@/datasources/staking-api/entities/pool
import type { Stake } from '@/datasources/staking-api/entities/stake.entity';
import type { TransactionStatus } from '@/datasources/staking-api/entities/transaction-status.entity';
import type { IStakingApi } from '@/domain/interfaces/staking-api.interface';
import type { Raw } from '@/validation/entities/raw.entity';

/**
* TODO: Move all usage of Raw to NetworkService after fully migrated
* to "Raw" type implementation.
*/
export class KilnApi implements IStakingApi {
public static DefiVaultStatsChains: {
[key in (typeof DefiVaultStatsChains)[number]]: string;
Expand Down Expand Up @@ -50,13 +55,13 @@ export class KilnApi implements IStakingApi {

// Important: there is no hook which invalidates this endpoint,
// Therefore, this data will live in cache until [stakingExpirationTimeInSeconds]
async getDeployments(): Promise<Array<Deployment>> {
async getDeployments(): Promise<Raw<Array<Deployment>>> {
try {
const url = `${this.baseUrl}/v1/deployments`;
const cacheDir = CacheRouter.getStakingDeploymentsCacheDir();
// Note: Kiln always return { data: T }
const { data } = await this.dataSource.get<{
data: Array<Deployment>;
data: Raw<Array<Deployment>>;
}>({
cacheDir,
url,
Expand All @@ -76,12 +81,12 @@ export class KilnApi implements IStakingApi {

// Important: there is no hook which invalidates this endpoint,
// Therefore, this data will live in cache until [stakingExpirationTimeInSeconds]
async getNetworkStats(): Promise<NetworkStats> {
async getNetworkStats(): Promise<Raw<NetworkStats>> {
try {
const url = `${this.baseUrl}/v1/eth/network-stats`;
const cacheDir = CacheRouter.getStakingNetworkStatsCacheDir();
// Note: Kiln always return { data: T }
const { data } = await this.dataSource.get<{ data: NetworkStats }>({
const { data } = await this.dataSource.get<{ data: Raw<NetworkStats> }>({
cacheDir,
url,
networkRequest: {
Expand All @@ -100,13 +105,13 @@ export class KilnApi implements IStakingApi {

// Important: there is no hook which invalidates this endpoint,
// Therefore, this data will live in cache until [stakingExpirationTimeInSeconds]
async getDedicatedStakingStats(): Promise<DedicatedStakingStats> {
async getDedicatedStakingStats(): Promise<Raw<DedicatedStakingStats>> {
try {
const url = `${this.baseUrl}/v1/eth/kiln-stats`;
const cacheDir = CacheRouter.getStakingDedicatedStakingStatsCacheDir();
// Note: Kiln always return { data: T }
const { data } = await this.dataSource.get<{
data: DedicatedStakingStats;
data: Raw<DedicatedStakingStats>;
}>({
cacheDir,
url,
Expand All @@ -128,13 +133,13 @@ export class KilnApi implements IStakingApi {
// Therefore, this data will live in cache until [stakingExpirationTimeInSeconds]
async getPooledStakingStats(
pool: `0x${string}`,
): Promise<PooledStakingStats> {
): Promise<Raw<PooledStakingStats>> {
try {
const url = `${this.baseUrl}/v1/eth/onchain/v2/network-stats`;
const cacheDir = CacheRouter.getStakingPooledStakingStatsCacheDir(pool);
// Note: Kiln always return { data: T }
const { data } = await this.dataSource.get<{
data: PooledStakingStats;
data: Raw<PooledStakingStats>;
}>({
cacheDir,
url,
Expand All @@ -159,7 +164,7 @@ export class KilnApi implements IStakingApi {
// Therefore, this data will live in cache until [stakingExpirationTimeInSeconds]
async getDefiVaultStats(
vault: `0x${string}`,
): Promise<Array<DefiVaultStats>> {
): Promise<Raw<Array<DefiVaultStats>>> {
try {
const url = `${this.baseUrl}/v1/defi/network-stats`;
const cacheDir = CacheRouter.getStakingDefiVaultStatsCacheDir({
Expand All @@ -168,7 +173,7 @@ export class KilnApi implements IStakingApi {
});
// Note: Kiln always return { data: T }
const { data } = await this.dataSource.get<{
data: Array<DefiVaultStats>;
data: Raw<Array<DefiVaultStats>>;
}>({
cacheDir,
url,
Expand Down Expand Up @@ -203,7 +208,7 @@ export class KilnApi implements IStakingApi {
async getStakes(args: {
safeAddress: `0x${string}`;
validatorsPublicKeys: Array<`0x${string}`>;
}): Promise<Stake[]> {
}): Promise<Raw<Stake[]>> {
try {
const url = `${this.baseUrl}/v1/eth/stakes`;
const cacheDir = CacheRouter.getStakingStakesCacheDir({
Expand All @@ -213,7 +218,7 @@ export class KilnApi implements IStakingApi {
});
// Note: Kiln always return { data: T }
const { data } = await this.dataSource.get<{
data: Array<Stake>;
data: Raw<Array<Stake>>;
}>({
cacheDir,
url,
Expand Down Expand Up @@ -251,7 +256,7 @@ export class KilnApi implements IStakingApi {

async getTransactionStatus(
txHash: `0x${string}`,
): Promise<TransactionStatus> {
): Promise<Raw<TransactionStatus>> {
try {
const url = `${this.baseUrl}/v1/eth/transaction/status`;
const cacheDir = CacheRouter.getStakingTransactionStatusCacheDir({
Expand All @@ -260,7 +265,7 @@ export class KilnApi implements IStakingApi {
});
// Note: Kiln always return { data: T }
const { data } = await this.dataSource.get<{
data: TransactionStatus;
data: Raw<TransactionStatus>;
}>({
cacheDir,
url,
Expand Down
15 changes: 8 additions & 7 deletions src/domain/interfaces/staking-api.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,27 @@ import type { PooledStakingStats } from '@/datasources/staking-api/entities/pool
import type { DefiVaultStats } from '@/datasources/staking-api/entities/defi-vault-stats.entity';
import type { Stake } from '@/datasources/staking-api/entities/stake.entity';
import type { TransactionStatus } from '@/datasources/staking-api/entities/transaction-status.entity';
import type { Raw } from '@/validation/entities/raw.entity';

export const IStakingApi = Symbol('IStakingApi');

export interface IStakingApi {
getDeployments(): Promise<Array<Deployment>>;
getDeployments(): Promise<Raw<Array<Deployment>>>;

getNetworkStats(): Promise<NetworkStats>;
getNetworkStats(): Promise<Raw<NetworkStats>>;

getDedicatedStakingStats(): Promise<DedicatedStakingStats>;
getDedicatedStakingStats(): Promise<Raw<DedicatedStakingStats>>;

getPooledStakingStats(pool: `0x${string}`): Promise<PooledStakingStats>;
getPooledStakingStats(pool: `0x${string}`): Promise<Raw<PooledStakingStats>>;

getDefiVaultStats(vault: `0x${string}`): Promise<Array<DefiVaultStats>>;
getDefiVaultStats(vault: `0x${string}`): Promise<Raw<Array<DefiVaultStats>>>;

getStakes(args: {
safeAddress: `0x${string}`;
validatorsPublicKeys: Array<`0x${string}`>;
}): Promise<Stake[]>;
}): Promise<Raw<Stake[]>>;

clearStakes(safeAddress: `0x${string}`): Promise<void>;

getTransactionStatus(txHash: `0x${string}`): Promise<TransactionStatus>;
getTransactionStatus(txHash: `0x${string}`): Promise<Raw<TransactionStatus>>;
}
14 changes: 6 additions & 8 deletions src/domain/staking/staking.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ import {
} from '@/datasources/staking-api/entities/dedicated-staking-stats.entity';
import {
Deployment,
DeploymentSchema,
DeploymentsSchema,
} from '@/datasources/staking-api/entities/deployment.entity';
import {
DefiVaultsStateSchema,
DefiVaultStats,
DefiVaultStatsSchema,
} from '@/datasources/staking-api/entities/defi-vault-stats.entity';
import {
Stake,
StakeSchema,
StakesSchema,
} from '@/datasources/staking-api/entities/stake.entity';
import {
TransactionStatus,
Expand Down Expand Up @@ -57,7 +57,7 @@ export class StakingRepository implements IStakingRepository {
private async getDeployments(chainId: string): Promise<Array<Deployment>> {
const stakingApi = await this.stakingApiFactory.getApi(chainId);
const deployments = await stakingApi.getDeployments();
return deployments.map((deployment) => DeploymentSchema.parse(deployment));
return DeploymentsSchema.parse(deployments);
}

public async getNetworkStats(chainId: string): Promise<NetworkStats> {
Expand Down Expand Up @@ -90,9 +90,7 @@ export class StakingRepository implements IStakingRepository {
const stakingApi = await this.stakingApiFactory.getApi(args.chainId);
const defiStats = await stakingApi.getDefiVaultStats(args.vault);
// Cannot be >1 contract deployed at the same address so return first element
return defiStats.map((defiStats) =>
DefiVaultStatsSchema.parse(defiStats),
)[0];
return DefiVaultsStateSchema.parse(defiStats)[0];
}

public async getStakes(args: {
Expand All @@ -102,7 +100,7 @@ export class StakingRepository implements IStakingRepository {
}): Promise<Stake[]> {
const stakingApi = await this.stakingApiFactory.getApi(args.chainId);
const stakes = await stakingApi.getStakes(args);
return stakes.map((stake) => StakeSchema.parse(stake));
return StakesSchema.parse(stakes);
}

public async clearStakes(args: {
Expand Down

0 comments on commit d51ef03

Please sign in to comment.