Skip to content

Commit

Permalink
Use helper throughout KilnApi (#2165)
Browse files Browse the repository at this point in the history
Removes redundant code, using the helper everywhere:

- Move all validation/error handling inside helper
- Use helper in all methods
  • Loading branch information
iamacook authored Dec 4, 2024
1 parent 6491f13 commit 77f0e72
Showing 1 changed file with 136 additions and 163 deletions.
299 changes: 136 additions & 163 deletions src/datasources/staking-api/kiln-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ 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';
import { z } from 'zod';
import { z, ZodError } from 'zod';

export class KilnApi implements IStakingApi {
public static DefiVaultStatsChains: {
Expand Down Expand Up @@ -53,137 +53,112 @@ 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<Raw<Array<Deployment>>> {
try {
const url = `${this.baseUrl}/v1/deployments`;
const cacheDir = CacheRouter.getStakingDeploymentsCacheDir();
const { data } = await this.get<{
data: Array<Deployment>;
}>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
const url = `${this.baseUrl}/v1/deployments`;
const cacheDir = CacheRouter.getStakingDeploymentsCacheDir();
return await this.get<{
data: Array<Deployment>;
}>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
});
return data;
} catch (error) {
throw this.httpErrorFactory.from(error);
}
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
});
}

// Important: there is no hook which invalidates this endpoint,
// Therefore, this data will live in cache until [stakingExpirationTimeInSeconds]
async getNetworkStats(): Promise<Raw<NetworkStats>> {
try {
const url = `${this.baseUrl}/v1/eth/network-stats`;
const cacheDir = CacheRouter.getStakingNetworkStatsCacheDir();
const { data } = await this.get<{ data: NetworkStats }>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
const url = `${this.baseUrl}/v1/eth/network-stats`;
const cacheDir = CacheRouter.getStakingNetworkStatsCacheDir();
return await this.get<{ data: NetworkStats }>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
});
return data;
} catch (error) {
throw this.httpErrorFactory.from(error);
}
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
});
}

// Important: there is no hook which invalidates this endpoint,
// Therefore, this data will live in cache until [stakingExpirationTimeInSeconds]
async getDedicatedStakingStats(): Promise<Raw<DedicatedStakingStats>> {
try {
const url = `${this.baseUrl}/v1/eth/kiln-stats`;
const cacheDir = CacheRouter.getStakingDedicatedStakingStatsCacheDir();
const { data } = await this.get<{
data: DedicatedStakingStats;
}>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
const url = `${this.baseUrl}/v1/eth/kiln-stats`;
const cacheDir = CacheRouter.getStakingDedicatedStakingStatsCacheDir();
return await this.get<{
data: DedicatedStakingStats;
}>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
}).then((res) => z.object({ data: z.any() }).parse(res));
return data;
} catch (error) {
throw this.httpErrorFactory.from(error);
}
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
});
}

// Important: there is no hook which invalidates this endpoint,
// Therefore, this data will live in cache until [stakingExpirationTimeInSeconds]
async getPooledStakingStats(
pool: `0x${string}`,
): Promise<Raw<PooledStakingStats>> {
try {
const url = `${this.baseUrl}/v1/eth/onchain/v2/network-stats`;
const cacheDir = CacheRouter.getStakingPooledStakingStatsCacheDir(pool);
const { data } = await this.get<{
data: PooledStakingStats;
}>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
params: {
integration: pool,
},
const url = `${this.baseUrl}/v1/eth/onchain/v2/network-stats`;
const cacheDir = CacheRouter.getStakingPooledStakingStatsCacheDir(pool);
return await this.get<{
data: PooledStakingStats;
}>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
}).then((res) => z.object({ data: z.any() }).parse(res));
return data;
} catch (error) {
throw this.httpErrorFactory.from(error);
}
params: {
integration: pool,
},
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
});
}

// Important: there is no hook which invalidates this endpoint,
// Therefore, this data will live in cache until [stakingExpirationTimeInSeconds]
async getDefiVaultStats(
vault: `0x${string}`,
): Promise<Raw<Array<DefiVaultStats>>> {
try {
const url = `${this.baseUrl}/v1/defi/network-stats`;
const cacheDir = CacheRouter.getStakingDefiVaultStatsCacheDir({
chainId: this.chainId,
vault,
});
const { data } = await this.get<{
data: Array<DefiVaultStats>;
}>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
params: {
vaults: this.getDefiVaultIdentifier(vault),
},
const url = `${this.baseUrl}/v1/defi/network-stats`;
const cacheDir = CacheRouter.getStakingDefiVaultStatsCacheDir({
chainId: this.chainId,
vault,
});
return await this.get<{
data: Array<DefiVaultStats>;
}>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
}).then((res) => z.object({ data: z.any() }).parse(res));
return data;
} catch (error) {
throw this.httpErrorFactory.from(error);
}
params: {
vaults: this.getDefiVaultIdentifier(vault),
},
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
});
}

/**
Expand All @@ -201,35 +176,30 @@ export class KilnApi implements IStakingApi {
safeAddress: `0x${string}`;
validatorsPublicKeys: Array<`0x${string}`>;
}): Promise<Raw<Stake[]>> {
try {
const url = `${this.baseUrl}/v1/eth/stakes`;
const cacheDir = CacheRouter.getStakingStakesCacheDir({
chainId: this.chainId,
safeAddress: args.safeAddress,
validatorsPublicKeys: args.validatorsPublicKeys,
});
const { data } = await this.get<{
data: Array<Stake>;
}>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
params: {
validators: args.validatorsPublicKeys.join(','),
// Adds net_claimable_consensus_rewards to response
onchain_v1_include_net_rewards: true,
},
const url = `${this.baseUrl}/v1/eth/stakes`;
const cacheDir = CacheRouter.getStakingStakesCacheDir({
chainId: this.chainId,
safeAddress: args.safeAddress,
validatorsPublicKeys: args.validatorsPublicKeys,
});
return await this.get<{
data: Array<Stake>;
}>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
}).then((res) => z.object({ data: z.any() }).parse(res));
return data;
} catch (error) {
throw this.httpErrorFactory.from(error);
}
params: {
validators: args.validatorsPublicKeys.join(','),
// Adds net_claimable_consensus_rewards to response
onchain_v1_include_net_rewards: true,
},
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
});
}

/**
Expand All @@ -248,30 +218,25 @@ export class KilnApi implements IStakingApi {
async getTransactionStatus(
txHash: `0x${string}`,
): Promise<Raw<TransactionStatus>> {
try {
const url = `${this.baseUrl}/v1/eth/transaction/status`;
const cacheDir = CacheRouter.getStakingTransactionStatusCacheDir({
chainId: this.chainId,
txHash,
});
const { data } = await this.get<TransactionStatus>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
params: {
tx_hash: txHash,
},
const url = `${this.baseUrl}/v1/eth/transaction/status`;
const cacheDir = CacheRouter.getStakingTransactionStatusCacheDir({
chainId: this.chainId,
txHash,
});
return await this.get<TransactionStatus>({
cacheDir,
url,
networkRequest: {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
});
return data;
} catch (error) {
throw this.httpErrorFactory.from(error);
}
params: {
tx_hash: txHash,
},
},
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
expireTimeSeconds: this.stakingExpirationTimeInSeconds,
});
}

/**
Expand All @@ -281,15 +246,23 @@ export class KilnApi implements IStakingApi {
*/
private async get<T>(
args: Parameters<typeof this.dataSource.get>[0],
): Promise<{ data: Raw<T> }> {
return this.dataSource
.get<{
data: TransactionStatus;
}>(args)
.then((res) => {
// Ensuring response is { data: T }, the data is parsed in the domain
return z.object({ data: z.unknown() }).parse(res) as { data: Raw<T> };
});
): Promise<Raw<T>> {
try {
const { data } = await this.dataSource
.get<{
data: TransactionStatus;
}>(args)
.then((res) => {
// Ensuring response is { data: T }, the data is parsed in the domain
return z.object({ data: z.unknown() }).parse(res) as { data: Raw<T> };
});
return data;
} catch (error) {
if (error instanceof ZodError) {
throw error;
}
throw this.httpErrorFactory.from(error);
}
}

/**
Expand Down

0 comments on commit 77f0e72

Please sign in to comment.