Skip to content

Commit

Permalink
feat(billing): resolve with valid only grants and allowances from htt…
Browse files Browse the repository at this point in the history
…p service
  • Loading branch information
ygrishajev committed Dec 19, 2024
1 parent 2de62dc commit 77a0ffc
Show file tree
Hide file tree
Showing 21 changed files with 215 additions and 196 deletions.
2 changes: 1 addition & 1 deletion apps/api/mvm.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"dependencies": {
"@akashnetwork/database": "1.0.0",
"@akashnetwork/env-loader": "1.0.1",
"@akashnetwork/http-sdk": "1.0.8",
"@akashnetwork/http-sdk": "1.1.0",
"@akashnetwork/logging": "2.0.2"
}
}
38 changes: 14 additions & 24 deletions apps/api/src/billing/services/balances/balances.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AllowanceHttpService } from "@akashnetwork/http-sdk";
import { AuthzHttpService } from "@akashnetwork/http-sdk";
import { singleton } from "tsyringe";

import { BillingConfig, InjectBillingConfig } from "@src/billing/providers";
Expand All @@ -12,7 +12,7 @@ export class BalancesService {
@InjectBillingConfig() private readonly config: BillingConfig,
private readonly userWalletRepository: UserWalletRepository,
@InjectWallet("MANAGED") private readonly masterWallet: Wallet,
private readonly allowanceHttpService: AllowanceHttpService
private readonly authzHttpService: AuthzHttpService
) {}

async refreshUserWalletLimits(userWallet: UserWalletOutput, options?: { endTrial: boolean }): Promise<void> {
Expand Down Expand Up @@ -45,39 +45,29 @@ export class BalancesService {
}

async getFreshLimits(userWallet: UserWalletOutput): Promise<{ fee: number; deployment: number }> {
const [fee, deployment] = await Promise.all([this.retrieveAndCalcFeeLimit(userWallet), this.retrieveAndCalcDeploymentLimit(userWallet)]);
const [fee, deployment] = await Promise.all([this.retrieveAndCalcFeeLimit(userWallet), this.retrieveDeploymentLimit(userWallet)]);
return { fee, deployment };
}

private async retrieveAndCalcFeeLimit(userWallet: UserWalletOutput): Promise<number> {
const feeAllowance = await this.allowanceHttpService.getFeeAllowancesForGrantee(userWallet.address);
const masterWalletAddress = await this.masterWallet.getFirstAddress();
const feeAllowance = await this.authzHttpService.getFeeAllowanceForGranterAndGrantee(masterWalletAddress, userWallet.address);

return feeAllowance.reduce((acc, allowance) => {
if (allowance.granter !== masterWalletAddress) {
return acc;
}

return allowance.allowance.spend_limit.reduce((acc, { denom, amount }) => {
if (denom !== "uakt") {
return acc;
}
if (!feeAllowance) {
return 0;
}

return acc + parseInt(amount);
}, 0);
}, 0);
return feeAllowance.allowance.spend_limit.reduce((acc, { denom, amount }) => (denom === "uakt" ? acc + parseInt(amount) : acc), 0);
}

async retrieveAndCalcDeploymentLimit(userWallet: Pick<UserWalletOutput, "address">): Promise<number> {
const deploymentAllowance = await this.allowanceHttpService.getDeploymentAllowancesForGrantee(userWallet.address);
async retrieveDeploymentLimit(userWallet: Pick<UserWalletOutput, "address">): Promise<number> {
const masterWalletAddress = await this.masterWallet.getFirstAddress();
const depositDeploymentGrant = await this.authzHttpService.getDepositDeploymentGrantsForGranterAndGrantee(masterWalletAddress, userWallet.address);

return deploymentAllowance.reduce((acc, allowance) => {
if (allowance.granter !== masterWalletAddress || allowance.authorization.spend_limit.denom !== this.config.DEPLOYMENT_GRANT_DENOM) {
return acc;
}
if (!depositDeploymentGrant || depositDeploymentGrant.authorization.spend_limit.denom !== this.config.DEPLOYMENT_GRANT_DENOM) {
return 0;
}

return acc + parseInt(allowance.authorization.spend_limit.amount);
}, 0);
return parseInt(depositDeploymentGrant.authorization.spend_limit.amount);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AllowanceHttpService } from "@akashnetwork/http-sdk";
import { AuthzHttpService } from "@akashnetwork/http-sdk";
import { LoggerService } from "@akashnetwork/logging";
import { stringToPath } from "@cosmjs/crypto";
import { DirectSecp256k1HdWallet, EncodeObject } from "@cosmjs/proto-signing";
Expand Down Expand Up @@ -38,7 +38,7 @@ export class ManagedUserWalletService {
@InjectWallet("MANAGED") private readonly masterWallet: Wallet,
private readonly managedSignerService: ManagedSignerService,
private readonly rpcMessageService: RpcMessageService,
private readonly allowanceHttpService: AllowanceHttpService
private readonly authzHttpService: AuthzHttpService
) {}

async createAndAuthorizeTrialSpending({ addressIndex }: { addressIndex: number }) {
Expand Down Expand Up @@ -94,8 +94,9 @@ export class ManagedUserWalletService {

private async authorizeFeeSpending(options: Omit<SpendingAuthorizationMsgOptions, "denom">) {
const messages: EncodeObject[] = [];
const hasValidFeeAllowance = await this.authzHttpService.hasValidFeeAllowance(options.granter, options.grantee);

if (await this.allowanceHttpService.hasFeeAllowance(options.granter, options.grantee)) {
if (hasValidFeeAllowance) {
messages.push(this.rpcMessageService.getRevokeAllowanceMsg(options));
}

Expand All @@ -118,12 +119,12 @@ export class ManagedUserWalletService {
deploymentGrant: false
};

if (await this.allowanceHttpService.hasFeeAllowance(params.granter, params.grantee)) {
if (await this.authzHttpService.hasValidFeeAllowance(params.granter, params.grantee)) {
revokeSummary.feeAllowance = true;
messages.push(this.rpcMessageService.getRevokeAllowanceMsg(params));
}

if (await this.allowanceHttpService.hasDeploymentGrant(params.granter, params.grantee)) {
if (await this.authzHttpService.hasValidDepositDeploymentGrant(params.granter, params.grantee)) {
revokeSummary.deploymentGrant = true;
messages.push(this.rpcMessageService.getRevokeDepositDeploymentGrantMsg(params));
}
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/billing/services/refill/refill.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class RefillService {
let currentLimit: number = 0;

if (userWallet) {
currentLimit = await this.balancesService.retrieveAndCalcDeploymentLimit(userWallet);
currentLimit = await this.balancesService.retrieveDeploymentLimit(userWallet);
} else {
userWallet = await this.walletInitializerService.initialize(userId);
}
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/core/providers/http-sdk.provider.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { AllowanceHttpService, BalanceHttpService, BlockHttpService } from "@akashnetwork/http-sdk";
import { AuthzHttpService, BalanceHttpService, BlockHttpService } from "@akashnetwork/http-sdk";
import { container } from "tsyringe";

import { apiNodeUrl } from "@src/utils/constants";

const SERVICES = [BalanceHttpService, AllowanceHttpService, BlockHttpService];
const SERVICES = [BalanceHttpService, AuthzHttpService, BlockHttpService];

SERVICES.forEach(Service => container.register(Service, { useValue: new Service({ baseURL: apiNodeUrl }) }));
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "@test/mocks/logger-service.mock";

import { AllowanceHttpService, BalanceHttpService, Denom } from "@akashnetwork/http-sdk";
import { AuthzHttpService, BalanceHttpService, Denom } from "@akashnetwork/http-sdk";
import { MsgExec } from "cosmjs-types/cosmos/authz/v1beta1/tx";
import { secondsInWeek } from "date-fns/constants";
import { describe } from "node:test";
Expand Down Expand Up @@ -42,7 +42,7 @@ describe(TopUpCustodialDeploymentsService.name, () => {
});
};

const allowanceHttpService = new AllowanceHttpService();
const authzHttpService = new AuthzHttpService();
const balanceHttpService = new BalanceHttpService();
const blockHttpService = stub<BlockHttpService>({ getCurrentHeight: jest.fn() });
const uaktMasterWallet = mockManagedWallet(UAKT_TOP_UP_MASTER_WALLET_ADDRESS);
Expand All @@ -58,7 +58,7 @@ describe(TopUpCustodialDeploymentsService.name, () => {

const topUpDeploymentsService = new TopUpCustodialDeploymentsService(
topUpToolsService,
allowanceHttpService,
authzHttpService,
balanceHttpService,
drainingDeploymentService,
new RpcMessageService(),
Expand Down Expand Up @@ -177,10 +177,10 @@ describe(TopUpCustodialDeploymentsService.name, () => {
})
];

jest.spyOn(allowanceHttpService, "paginateDeploymentGrants").mockImplementation(async (params, cb) => {
jest.spyOn(authzHttpService, "paginateDepositDeploymentGrants").mockImplementation(async (params, cb) => {
return await cb(data.filter(({ grant }) => "grantee" in params && grant.grantee === params.grantee).map(({ grant }) => grant));
});
jest.spyOn(allowanceHttpService, "getFeeAllowanceForGranterAndGrantee").mockImplementation(async (granter: string, grantee: string) => {
jest.spyOn(authzHttpService, "getFeeAllowanceForGranterAndGrantee").mockImplementation(async (granter: string, grantee: string) => {
return data.find(({ grant }) => grant.granter === granter && grant.grantee === grantee)?.feeAllowance;
});
jest.spyOn(balanceHttpService, "getBalance").mockImplementation(async (address: string, denom: Denom) => {
Expand Down Expand Up @@ -271,7 +271,6 @@ describe(TopUpCustodialDeploymentsService.name, () => {
],
{ fee: { granter: owner } }
);

console.log("DEBUG res", res);
} catch (e) {
console.log("DEBUG e", e);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AllowanceHttpService, BalanceHttpService, DeploymentAllowance } from "@akashnetwork/http-sdk";
import { AuthzHttpService, BalanceHttpService, DepositDeploymentGrant } from "@akashnetwork/http-sdk";
import { LoggerService } from "@akashnetwork/logging";
import { singleton } from "tsyringe";

Expand Down Expand Up @@ -36,7 +36,7 @@ export class TopUpCustodialDeploymentsService implements DeploymentsRefiller {

constructor(
private readonly topUpToolsService: TopUpToolsService,
private readonly allowanceHttpService: AllowanceHttpService,
private readonly authzHttpService: AuthzHttpService,
private readonly balanceHttpService: BalanceHttpService,
private readonly drainingDeploymentService: DrainingDeploymentService,
private readonly rpcClientService: RpcMessageService,
Expand All @@ -50,7 +50,7 @@ export class TopUpCustodialDeploymentsService implements DeploymentsRefiller {

const topUpAllCustodialDeployments = this.topUpToolsService.pairs.map(async ({ wallet, client }) => {
const address = await wallet.getFirstAddress();
await this.allowanceHttpService.paginateDeploymentGrants({ grantee: address, limit: this.CONCURRENCY }, async grants => {
await this.authzHttpService.paginateDepositDeploymentGrants({ grantee: address, limit: this.CONCURRENCY }, async grants => {
await Promise.all(
grants.map(async grant => {
await this.errorService.execWithErrorHandler(
Expand All @@ -69,7 +69,7 @@ export class TopUpCustodialDeploymentsService implements DeploymentsRefiller {
}

private async topUpForGrant(
grant: DeploymentAllowance,
grant: DepositDeploymentGrant,
client: BatchSigningClientService,
options: TopUpDeploymentsOptions,
summary: TopUpSummarizer
Expand Down Expand Up @@ -120,7 +120,7 @@ export class TopUpCustodialDeploymentsService implements DeploymentsRefiller {
}
}

private async collectWalletBalances(grant: DeploymentAllowance): Promise<Balances> {
private async collectWalletBalances(grant: DepositDeploymentGrant): Promise<Balances> {
const denom = grant.authorization.spend_limit.denom;
const deploymentLimit = parseFloat(grant.authorization.spend_limit.amount);

Expand All @@ -140,7 +140,7 @@ export class TopUpCustodialDeploymentsService implements DeploymentsRefiller {
}

private async retrieveFeesLimit(granter: string, grantee: string) {
const feesAllowance = await this.allowanceHttpService.getFeeAllowanceForGranterAndGrantee(granter, grantee);
const feesAllowance = await this.authzHttpService.getFeeAllowanceForGranterAndGrantee(granter, grantee);
const feesSpendLimit = feesAllowance.allowance.spend_limit.find(limit => limit.denom === "uakt");

return feesSpendLimit ? parseFloat(feesSpendLimit.amount) : 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { stub } from "@test/services/stub";
describe(TopUpManagedDeploymentsService.name, () => {
const CURRENT_BLOCK_HEIGHT = 7481457;
const MANAGED_MASTER_WALLET_ADDRESS = AkashAddressSeeder.create();
const balancesService = stub<BalancesService>({ retrieveAndCalcDeploymentLimit: jest.fn() });
const balancesService = stub<BalancesService>({ retrieveDeploymentLimit: jest.fn() });
const userWalletRepository = stub<UserWalletRepository>({ paginate: jest.fn() });
const blockHttpService = stub<BlockHttpService>({ getCurrentHeight: () => CURRENT_BLOCK_HEIGHT });
const managedSignerService = stub<ManagedSignerService>({ executeManagedTx: jest.fn() });
Expand Down Expand Up @@ -93,7 +93,7 @@ describe(TopUpManagedDeploymentsService.name, () => {
return data.find(({ wallet }) => wallet.address == owner)?.drainingDeployments?.map(({ deployment }) => deployment) || [];
});
jest.spyOn(drainingDeploymentService, "calculateTopUpAmount").mockImplementation(async () => faker.number.int({ min: 3500000, max: 4000000 }));
balancesService.retrieveAndCalcDeploymentLimit.mockImplementation(async wallet => {
balancesService.retrieveDeploymentLimit.mockImplementation(async wallet => {
return parseInt(data.find(({ wallet: w }) => w.address == wallet.address)?.balance);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class TopUpManagedDeploymentsService implements DeploymentsRefiller {
return;
}

let balance = await this.balancesService.retrieveAndCalcDeploymentLimit(wallet);
let balance = await this.balancesService.retrieveDeploymentLimit(wallet);
let hasTopUp = false;

for (const deployment of drainingDeployments) {
Expand Down
16 changes: 8 additions & 8 deletions apps/api/test/functional/stale-anonymous-users-cleanup.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AllowanceHttpService } from "@akashnetwork/http-sdk";
import { AuthzHttpService } from "@akashnetwork/http-sdk";
import subDays from "date-fns/subDays";
import { container } from "tsyringe";

Expand All @@ -19,7 +19,7 @@ describe("Users", () => {
const userWalletRepository = container.resolve(UserWalletRepository);
const walletService = new WalletTestingService(app);
const controller = container.resolve(UserController);
const allowanceHttpService = container.resolve(AllowanceHttpService);
const authzHttpService = container.resolve(AuthzHttpService);
const masterWalletService = resolveWallet("MANAGED");
let masterAddress: string;

Expand Down Expand Up @@ -71,14 +71,14 @@ describe("Users", () => {
);

await Promise.all([
expect(allowanceHttpService.hasFeeAllowance(recent.wallet.address, masterAddress)).resolves.toBeFalsy(),
expect(allowanceHttpService.hasDeploymentGrant(recent.wallet.address, masterAddress)).resolves.toBeFalsy(),
expect(authzHttpService.hasValidFeeAllowance(recent.wallet.address, masterAddress)).resolves.toBeFalsy(),
expect(authzHttpService.hasValidDepositDeploymentGrant(recent.wallet.address, masterAddress)).resolves.toBeFalsy(),

expect(allowanceHttpService.hasFeeAllowance(reactivated.wallet.address, masterAddress)).resolves.toBeFalsy(),
expect(allowanceHttpService.hasDeploymentGrant(reactivated.wallet.address, masterAddress)).resolves.toBeFalsy(),
expect(authzHttpService.hasValidFeeAllowance(reactivated.wallet.address, masterAddress)).resolves.toBeFalsy(),
expect(authzHttpService.hasValidDepositDeploymentGrant(reactivated.wallet.address, masterAddress)).resolves.toBeFalsy(),

expect(allowanceHttpService.hasFeeAllowance(stale.wallet.address, masterAddress)).resolves.toBeFalsy(),
expect(allowanceHttpService.hasDeploymentGrant(stale.wallet.address, masterAddress)).resolves.toBeFalsy()
expect(authzHttpService.hasValidFeeAllowance(stale.wallet.address, masterAddress)).resolves.toBeFalsy(),
expect(authzHttpService.hasValidDepositDeploymentGrant(stale.wallet.address, masterAddress)).resolves.toBeFalsy()
]);
});
});
Expand Down
8 changes: 4 additions & 4 deletions apps/api/test/functional/start-trial.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AllowanceHttpService } from "@akashnetwork/http-sdk";
import { AuthzHttpService } from "@akashnetwork/http-sdk";
import { faker } from "@faker-js/faker";
import { eq } from "drizzle-orm";
import { container } from "tsyringe";
Expand All @@ -16,7 +16,7 @@ describe("start trial", () => {
const config = container.resolve<BillingConfig>(BILLING_CONFIG);
const db = container.resolve<ApiPgDatabase>(POSTGRES_DB);
const userWalletsQuery = db.query.UserWallets;
const allowanceHttpService = container.resolve(AllowanceHttpService);
const authzHttpService = container.resolve(AuthzHttpService);
const dbService = container.resolve(DbTestingService);

afterEach(async () => {
Expand All @@ -42,8 +42,8 @@ describe("start trial", () => {
const getWalletsResponse = await app.request(`/v1/wallets?userId=${userId}`, { headers });
const userWallet = await userWalletsQuery.findFirst({ where: eq(userWalletsTable.userId, userId) });
const allowances = await Promise.all([
allowanceHttpService.getDeploymentAllowancesForGrantee(userWallet.address),
allowanceHttpService.getFeeAllowancesForGrantee(userWallet.address)
authzHttpService.getDepositDeploymentGrantsForGrantee(userWallet.address),
authzHttpService.getFeeAllowancesForGrantee(userWallet.address)
]);

expect(createWalletResponse.status).toBe(200);
Expand Down
4 changes: 2 additions & 2 deletions apps/api/test/seeders/deployment-grant.seeder.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { DeploymentAllowance } from "@akashnetwork/http-sdk";
import type { DepositDeploymentGrant } from "@akashnetwork/http-sdk";
import { faker } from "@faker-js/faker";
import { merge } from "lodash";
import type { PartialDeep } from "type-fest";
Expand All @@ -8,7 +8,7 @@ import { AkashAddressSeeder } from "./akash-address.seeder";
import { DenomSeeder } from "@test/seeders/denom.seeder";

export class DeploymentGrantSeeder {
static create(input: PartialDeep<DeploymentAllowance> = {}): DeploymentAllowance {
static create(input: PartialDeep<DepositDeploymentGrant> = {}): DepositDeploymentGrant {
return merge(
{
granter: AkashAddressSeeder.create(),
Expand Down
2 changes: 1 addition & 1 deletion apps/deploy-web/mvm.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"dependencies": {
"@akashnetwork/env-loader": "1.0.1",
"@akashnetwork/http-sdk": "1.0.8",
"@akashnetwork/http-sdk": "1.1.0",
"@akashnetwork/logging": "2.0.2",
"@akashnetwork/network-store": "1.0.1",
"@akashnetwork/ui": "1.0.0"
Expand Down
4 changes: 2 additions & 2 deletions apps/deploy-web/src/hooks/useAllowanceService.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useMemo } from "react";
import { AllowanceHttpService } from "@akashnetwork/http-sdk";
import { AuthzHttpService } from "@akashnetwork/http-sdk";

import { useSettings } from "@src/context/SettingsProvider";

export const useAllowanceService = () => {
const { settings } = useSettings();
return useMemo(() => new AllowanceHttpService({ baseURL: settings.apiEndpoint }), [settings.apiEndpoint]);
return useMemo(() => new AuthzHttpService({ baseURL: settings.apiEndpoint }), [settings.apiEndpoint]);
};
4 changes: 2 additions & 2 deletions apps/deploy-web/src/hooks/useAutoTopUpLimits.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useMemo } from "react";
import { ExactDeploymentAllowance, FeeAllowance } from "@akashnetwork/http-sdk";
import { ExactDepositDeploymentGrant, FeeAllowance } from "@akashnetwork/http-sdk";
import { isFuture } from "date-fns";
import invokeMap from "lodash/invokeMap";

Expand Down Expand Up @@ -62,7 +62,7 @@ export const useAutoTopUpLimits = () => {
};
};

function extractDeploymentLimit(deploymentGrant?: ExactDeploymentAllowance) {
function extractDeploymentLimit(deploymentGrant?: ExactDepositDeploymentGrant) {
if (!deploymentGrant) {
return undefined;
}
Expand Down
10 changes: 7 additions & 3 deletions apps/deploy-web/src/queries/useExactDeploymentGrantsQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import { QueryKeys } from "@src/queries/queryKeys";

export function useExactDeploymentGrantsQuery(granter: string, grantee: string, { enabled = true } = {}) {
const allowanceHttpService = useAllowanceService();
return useQuery(QueryKeys.getDeploymentGrantsKey(granter, grantee), () => allowanceHttpService.getDeploymentGrantsForGranterAndGrantee(granter, grantee), {
enabled
});
return useQuery(
QueryKeys.getDeploymentGrantsKey(granter, grantee),
() => allowanceHttpService.getDepositDeploymentGrantsForGranterAndGrantee(granter, grantee),
{
enabled
}
);
}
Loading

0 comments on commit 77a0ffc

Please sign in to comment.