Skip to content

Commit 6462ef1

Browse files
authored
refactor: improves encapsulation of console-api (#2249)
1 parent e541a25 commit 6462ef1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+285
-226
lines changed

apps/api/env/.env.mainnet

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
RPC_NODE_ENDPOINT=https://consolerpc.akashnet.net
2+
REST_API_NODE_URL=https://consoleapi.akashnet.net
23
DEPLOYMENT_GRANT_DENOM=ibc/170C677610AC31DF0904FFE09CD3B5C657492170E7E52372E48756B71E56F2F1

apps/api/env/.env.sandbox

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
RPC_NODE_ENDPOINT=https://rpc.sandbox-2.aksh.pw:443
2-
DEPLOYMENT_GRANT_DENOM=uakt
2+
REST_API_NODE_URL=https://api.sandbox-2.aksh.pw:443
3+
DEPLOYMENT_GRANT_DENOM=uakt

apps/api/src/billing/lib/wallet/wallet.ts

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,54 @@ import type { DirectSignResponse, OfflineDirectSigner } from "@cosmjs/proto-sign
44
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
55
import type { DirectSecp256k1HdWalletOptions } from "@cosmjs/proto-signing/build/directsecp256k1hdwallet";
66

7+
export const WALLET_ADDRESS_PREFIX = "akash";
8+
79
export class Wallet implements OfflineDirectSigner {
810
static create(mnemonic?: string, index?: number): Wallet {
911
return new Wallet(mnemonic, index);
1012
}
1113

12-
private readonly PREFIX = "akash";
13-
14-
private readonly instanceAsPromised: Promise<DirectSecp256k1HdWallet>;
15-
private aminoSignerPromise?: Promise<OfflineAminoSigner>;
16-
private readonly walletIndex?: number;
14+
readonly #instanceAsPromised: Promise<DirectSecp256k1HdWallet>;
15+
#aminoSignerPromise?: Promise<OfflineAminoSigner>;
16+
#walletIndex?: number;
1717

1818
constructor(mnemonic?: string, index?: number) {
19-
this.walletIndex = index;
19+
this.#walletIndex = index;
2020
if (typeof mnemonic === "undefined") {
21-
this.instanceAsPromised = DirectSecp256k1HdWallet.generate(24, this.getInstanceOptions(index));
21+
this.#instanceAsPromised = DirectSecp256k1HdWallet.generate(24, this.getInstanceOptions(index));
2222
} else {
23-
this.instanceAsPromised = DirectSecp256k1HdWallet.fromMnemonic(mnemonic, this.getInstanceOptions(index));
23+
this.#instanceAsPromised = DirectSecp256k1HdWallet.fromMnemonic(mnemonic, this.getInstanceOptions(index));
2424
}
2525
}
2626

2727
private getInstanceOptions(index?: number): Partial<DirectSecp256k1HdWalletOptions> {
2828
if (typeof index === "undefined") {
29-
return { prefix: this.PREFIX };
29+
return { prefix: WALLET_ADDRESS_PREFIX };
3030
}
3131

3232
return {
33-
prefix: this.PREFIX,
33+
prefix: WALLET_ADDRESS_PREFIX,
3434
hdPaths: [makeCosmoshubPath(index)]
3535
};
3636
}
3737

3838
async getAccounts() {
39-
return (await this.instanceAsPromised).getAccounts();
39+
return (await this.#instanceAsPromised).getAccounts();
4040
}
4141

4242
async signDirect(...args: Parameters<DirectSecp256k1HdWallet["signDirect"]>): Promise<DirectSignResponse> {
43-
return (await this.instanceAsPromised).signDirect(...args);
43+
return (await this.#instanceAsPromised).signDirect(...args);
4444
}
4545

4646
async signAmino(address: string, data: StdSignDoc): Promise<AminoSignResponse> {
47-
const wallet = await this.instanceAsPromised;
48-
this.aminoSignerPromise ??= Secp256k1HdWallet.fromMnemonic(wallet.mnemonic, this.getInstanceOptions(this.walletIndex));
49-
const aminoSigner = await this.aminoSignerPromise;
47+
const wallet = await this.#instanceAsPromised;
48+
this.#aminoSignerPromise ??= Secp256k1HdWallet.fromMnemonic(wallet.mnemonic, this.getInstanceOptions(this.#walletIndex));
49+
const aminoSigner = await this.#aminoSignerPromise;
5050
return aminoSigner.signAmino(address, data);
5151
}
5252

53-
async getFirstAddress() {
53+
async getFirstAddress(): Promise<string> {
5454
const accounts = await this.getAccounts();
5555
return accounts[0].address;
5656
}
57-
58-
async getMnemonic() {
59-
return (await this.instanceAsPromised).mnemonic;
60-
}
61-
62-
async getInstance() {
63-
return await this.instanceAsPromised;
64-
}
6557
}

apps/api/src/billing/services/financial-stats/financial-stats.service.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import { Provider } from "@akashnetwork/database/dbSchemas/akash";
2-
import { CosmosDistributionCommunityPoolResponse, CosmosHttpService } from "@akashnetwork/http-sdk";
3-
import axios from "axios";
2+
import { CosmosHttpService } from "@akashnetwork/http-sdk";
43
import { Op, QueryTypes } from "sequelize";
54
import { singleton } from "tsyringe";
65

76
import { USDC_IBC_DENOMS } from "@src/billing/config/network.config";
87
import { UserWalletRepository } from "@src/billing/repositories";
98
import { chainDb } from "@src/db/dbConnection";
10-
import { apiNodeUrl } from "@src/utils/constants";
119
import { TxManagerService } from "../tx-manager/tx-manager.service";
1210

1311
@singleton()
@@ -48,9 +46,9 @@ export class FinancialStatsService {
4846
return balances;
4947
}
5048

51-
async getCommunityPoolUsdc() {
52-
const communityPoolData = await axios.get<CosmosDistributionCommunityPoolResponse>(`${apiNodeUrl}/cosmos/distribution/v1beta1/community_pool`);
53-
return parseFloat(communityPoolData.data.pool.find(x => x.denom === USDC_IBC_DENOMS.mainnetId)?.amount || "0");
49+
async getCommunityPoolUsdc(): Promise<number> {
50+
const pool = await this.cosmosHttpService.getCommunityPool();
51+
return parseFloat(pool.find(x => x.denom === USDC_IBC_DENOMS.mainnetId)?.amount || "0");
5452
}
5553

5654
async getProviderRevenues() {

apps/api/src/billing/services/managed-user-wallet/managed-user-wallet.service.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ interface SpendingAuthorizationOptions {
2525

2626
@singleton()
2727
export class ManagedUserWalletService {
28-
private readonly PREFIX = "akash";
29-
30-
private readonly HD_PATH = "m/44'/118'/0'/0";
31-
3228
private readonly logger = LoggerService.forContext(ManagedUserWalletService.name);
3329

3430
constructor(
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
import "@test/mocks/logger-service.mock";
22

3-
import { BlockHttpService as BlockHttpServiceCommon } from "@akashnetwork/http-sdk";
3+
import type { BlockHttpService as BlockHttpServiceCommon } from "@akashnetwork/http-sdk";
44
import { faker } from "@faker-js/faker";
5+
import { mock } from "jest-mock-extended";
56

67
import { BlockHttpService } from "./block-http.service";
78

89
describe(BlockHttpService.name, () => {
9-
let service: BlockHttpService;
10-
let blockHttpService: BlockHttpServiceCommon;
11-
12-
beforeEach(() => {
13-
blockHttpService = new BlockHttpServiceCommon();
14-
service = new BlockHttpService(blockHttpService);
15-
});
16-
1710
it("should get current height", async () => {
11+
const { blockHttpService, service } = setup();
1812
const height = faker.number.int({ min: 1000000, max: 10000000 });
1913
jest.spyOn(blockHttpService, "getCurrentHeight").mockResolvedValue(height);
2014
const result = await service.getCurrentHeight();
2115

2216
expect(result).toBe(height);
2317
});
18+
19+
function setup() {
20+
const blockHttpService = mock<BlockHttpServiceCommon>();
21+
const service = new BlockHttpService(blockHttpService);
22+
return { blockHttpService, service };
23+
}
2424
});

apps/api/src/console.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,7 @@ async function executeCliHandler(name: string, handler: () => Promise<unknown>,
105105
}
106106

107107
const shutdown = once(async () => {
108-
// eslint-disable-next-line @typescript-eslint/no-var-requires
109-
const { closeConnections } = require("./core/providers/postgres.provider");
110-
111-
await Promise.all([closeConnections(), chainDb.close(), container.dispose()]);
108+
await container.dispose();
112109
});
113110
process.on("SIGTERM", shutdown);
114111
process.on("SIGINT", shutdown);

apps/api/src/core/config/env.config.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { netConfig } from "@akashnetwork/net";
12
import { z } from "zod";
23

34
export const envSchema = z
@@ -23,7 +24,11 @@ export const envSchema = z
2324
FEATURE_FLAGS_ENABLE_ALL: z
2425
.string()
2526
.default("false")
26-
.transform(value => value === "true")
27+
.transform(value => value === "true"),
28+
REST_API_NODE_URL: z
29+
.string()
30+
.url()
31+
.default(() => netConfig.getBaseAPIUrl(process.env.NETWORK || "mainnet"))
2732
})
2833
.superRefine((value, ctx) => {
2934
if (!value.FEATURE_FLAGS_ENABLE_ALL && (!value.UNLEASH_SERVER_API_URL || !value.UNLEASH_SERVER_API_TOKEN)) {
@@ -34,4 +39,4 @@ export const envSchema = z
3439
}
3540
});
3641

37-
export const envConfig = envSchema.parse(process.env);
42+
export type CoreConfig = z.infer<typeof envSchema>;

apps/api/src/core/config/index.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

apps/api/src/core/lib/disposable-registry/disposable-registry.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ export class DisposableRegistry implements Disposable {
2424
return container.resolve(DisposableRegistry).registerFromFactory(factory);
2525
}
2626

27-
private isDisposed = false;
28-
29-
private readonly disposes: Array<() => Promise<void> | void> = [];
27+
#isDisposed = false;
28+
readonly #disposables: Disposable[] = [];
3029

3130
/**
3231
* Wraps a factory function to automatically register disposable instances.
@@ -41,15 +40,18 @@ export class DisposableRegistry implements Disposable {
4140
registerFromFactory<T>(factory: FactoryProvider<T>["useFactory"]): FactoryProvider<T>["useFactory"] {
4241
return container => {
4342
const value = factory(container);
44-
4543
if (this.isDisposable(value)) {
46-
this.disposes.push(() => value.dispose());
44+
this.register(value as Disposable);
4745
}
4846

4947
return value;
5048
};
5149
}
5250

51+
register(item: Disposable): void {
52+
this.#disposables.push(item);
53+
}
54+
5355
/**
5456
* Disposes all registered disposable instances.
5557
*
@@ -65,17 +67,17 @@ export class DisposableRegistry implements Disposable {
6567
* @returns A promise that resolves when all dispose operations complete successfully.
6668
* @throws AggregateError if any dispose operations failed, containing all failure reasons.
6769
*/
68-
async dispose() {
69-
if (this.isDisposed) {
70+
async dispose(): Promise<void> {
71+
if (this.#isDisposed) {
7072
return;
7173
}
7274

73-
this.isDisposed = true;
75+
this.#isDisposed = true;
7476

75-
const results = await Promise.allSettled(this.disposes.map(dispose => dispose()));
77+
const results = await Promise.allSettled(this.#disposables.map(item => item.dispose()));
7678
const errors = results.filter((r): r is PromiseRejectedResult => r.status === "rejected");
7779

78-
this.disposes.length = 0;
80+
this.#disposables.length = 0;
7981

8082
if (errors.length > 0) {
8183
throw new AggregateError(

0 commit comments

Comments
 (0)