diff --git a/apps/api/src/app.ts b/apps/api/src/app.ts index 165321250..7fb26eb37 100644 --- a/apps/api/src/app.ts +++ b/apps/api/src/app.ts @@ -3,11 +3,7 @@ import "@src/core/providers/sentry.provider"; import { LoggerService } from "@akashnetwork/logging"; import { serve } from "@hono/node-server"; -// TODO: find out how to properly import this -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-expect-error -import { sentry } from "@hono/sentry"; -import { Hono } from "hono"; +import { Context, Hono, Next } from "hono"; import { cors } from "hono/cors"; import { container } from "tsyringe"; @@ -49,16 +45,16 @@ const scheduler = new Scheduler({ appHono.use(container.resolve(HttpLoggerService).intercept()); appHono.use(container.resolve(RequestContextInterceptor).intercept()); -appHono.use( - "*", - sentry({ +appHono.use("*", async (c: Context, next: Next) => { + const { sentry } = await import("@hono/sentry"); + return sentry({ ...sentryOptions, beforeSend: event => { event.server_name = config.SENTRY_SERVER_NAME; return event; } - }) -); + })(c, next); +}); appHono.route("/", legacyRouter); appHono.route("/", apiRouter); diff --git a/apps/api/src/billing/services/master-signing-client/master-signing-client.service.ts b/apps/api/src/billing/services/master-signing-client/master-signing-client.service.ts index d9f018f01..75d881b92 100644 --- a/apps/api/src/billing/services/master-signing-client/master-signing-client.service.ts +++ b/apps/api/src/billing/services/master-signing-client/master-signing-client.service.ts @@ -20,6 +20,17 @@ interface ShortAccountInfo { sequence: number; } +interface ExecuteTxOptions { + fee: { + granter: string; + }; +} + +interface ExecuteTxInput { + messages: readonly EncodeObject[]; + options?: ExecuteTxOptions; +} + export class MasterSigningClientService { private readonly FEES_DENOM = "uakt"; @@ -32,8 +43,8 @@ export class MasterSigningClientService { private chainId: string; private execTxLoader = new DataLoader( - async (batchedMessages: readonly EncodeObject[][]) => { - return this.executeTxBatchBlocking(batchedMessages); + async (batchedInputs: ExecuteTxInput[]) => { + return this.executeTxBatchBlocking(batchedInputs); }, { cache: false, batchScheduleFn: callback => setTimeout(callback, this.config.MASTER_WALLET_BATCHING_INTERVAL_MS) } ); @@ -75,24 +86,24 @@ export class MasterSigningClientService { return (await this.clientAsPromised).simulate(await this.masterWalletService.getFirstAddress(), messages, memo); } - async executeTx(messages: EncodeObject[]) { - const tx = await this.execTxLoader.load(messages); + async executeTx(messages: readonly EncodeObject[], options?: ExecuteTxOptions) { + const tx = await this.execTxLoader.load({ messages, options }); assert(tx.code === 0, 500, "Failed to sign and broadcast tx", { data: tx }); return tx; } - private async executeTxBatchBlocking(messages: readonly EncodeObject[][]): Promise { + private async executeTxBatchBlocking(inputs: ExecuteTxInput[]): Promise { await this.semaphore.acquire(); try { - return await this.executeTxBatch(messages); + return await this.executeTxBatch(inputs); } catch (error) { if (error.message.includes("account sequence mismatch")) { this.logger.debug("Account sequence mismatch, retrying..."); this.clientAsPromised = this.initClient(); - return await this.executeTxBatch(messages); + return await this.executeTxBatch(inputs); } throw error; @@ -101,16 +112,18 @@ export class MasterSigningClientService { } } - private async executeTxBatch(messages: readonly EncodeObject[][]): Promise { + private async executeTxBatch(inputs: ExecuteTxInput[]): Promise { const txes: TxRaw[] = []; let txIndex: number = 0; const client = await this.clientAsPromised; const masterAddress = await this.masterWalletService.getFirstAddress(); - while (txIndex < messages.length) { + while (txIndex < inputs.length) { + const { messages, options } = inputs[txIndex]; + const fee = await this.estimateFee(messages, this.FEES_DENOM, options?.fee.granter, { mock: true }); txes.push( - await client.sign(masterAddress, messages[txIndex], await this.estimateFee(messages[txIndex], this.FEES_DENOM, { mock: true }), "", { + await client.sign(masterAddress, messages, fee, "", { accountNumber: this.accountInfo.accountNumber, sequence: this.accountInfo.sequence++, chainId: this.chainId @@ -134,11 +147,12 @@ export class MasterSigningClientService { return await Promise.all(hashes.map(hash => client.getTx(hash))); } - private async estimateFee(messages: readonly EncodeObject[], denom: string, options?: { mock?: boolean }) { + private async estimateFee(messages: readonly EncodeObject[], denom: string, granter?: string, options?: { mock?: boolean }) { if (options?.mock) { return { amount: [{ denom: this.FEES_DENOM, amount: "15000" }], - gas: "500000" + gas: "500000", + granter }; } diff --git a/apps/api/src/deployment/services/top-up-custodial-deployments/top-up-custodial-deployments.service.spec.ts b/apps/api/src/deployment/services/top-up-custodial-deployments/top-up-custodial-deployments.service.spec.ts index 53d9447f7..0e9e20f78 100644 --- a/apps/api/src/deployment/services/top-up-custodial-deployments/top-up-custodial-deployments.service.spec.ts +++ b/apps/api/src/deployment/services/top-up-custodial-deployments/top-up-custodial-deployments.service.spec.ts @@ -1,7 +1,12 @@ import { AllowanceHttpService, BalanceHttpService, Denom } from "@akashnetwork/http-sdk"; import { faker } from "@faker-js/faker"; import { MsgExec } from "cosmjs-types/cosmos/authz/v1beta1/tx"; +import { describe } from "node:test"; +import { container } from "tsyringe"; +import { BILLING_CONFIG } from "@src/billing/providers"; +import { TYPE_REGISTRY } from "@src/billing/providers/type-registry.provider"; +import { UAKT_TOP_UP_MASTER_WALLET } from "@src/billing/providers/wallet.provider"; import { MasterSigningClientService, MasterWalletService, RpcMessageService } from "@src/billing/services"; import { BlockHttpService } from "@src/chain/services/block-http/block-http.service"; import { ErrorService } from "@src/core/services/error/error.service"; @@ -164,22 +169,57 @@ describe(TopUpCustodialDeploymentsService.name, () => { drainingDeployments.forEach(({ isExpectedToTopUp, deployment }) => { if (isExpectedToTopUp) { const client = deployment.denom === "uakt" ? uaktMasterSigningClientService : usdtMasterSigningClientService; - expect(client.executeTx).toHaveBeenCalledWith([ - { - typeUrl: MsgExec.typeUrl, - value: { - grantee: grant.grantee, - msgs: [ - { - typeUrl: "/akash.deployment.v1beta3.MsgDepositDeployment", - value: expect.any(Buffer) - } - ] + expect(client.executeTx).toHaveBeenCalledWith( + [ + { + typeUrl: MsgExec.typeUrl, + value: { + grantee: grant.grantee, + msgs: [ + { + typeUrl: "/akash.deployment.v1beta3.MsgDepositDeployment", + value: expect.any(Buffer) + } + ] + } } - } - ]); + ], + { fee: { granter: grant.granter } } + ); } }); }); }); + + xdescribe("actual top up deployment tx on demand", () => { + jest.setTimeout(30000); + + it("should top up or not depending on parameters below", async () => { + const denom = "uakt"; + const owner = ""; + const dseq = "" as unknown as number; + const wallet = container.resolve(UAKT_TOP_UP_MASTER_WALLET); + const signer = new MasterSigningClientService(container.resolve(BILLING_CONFIG), wallet, container.resolve(TYPE_REGISTRY)); + const grantee = await wallet.getFirstAddress(); + + try { + const res = await signer.executeTx( + [ + container.resolve(RpcMessageService).getExecDepositDeploymentMsg({ + dseq, + amount: 1000000, + denom, + owner: owner, + grantee + }) + ], + { fee: { granter: owner } } + ); + + console.log("DEBUG res", res); + } catch (e) { + console.log("DEBUG e", e); + } + }); + }); }); diff --git a/apps/api/src/deployment/services/top-up-custodial-deployments/top-up-custodial-deployments.service.ts b/apps/api/src/deployment/services/top-up-custodial-deployments/top-up-custodial-deployments.service.ts index df9899a24..cefe05f74 100644 --- a/apps/api/src/deployment/services/top-up-custodial-deployments/top-up-custodial-deployments.service.ts +++ b/apps/api/src/deployment/services/top-up-custodial-deployments/top-up-custodial-deployments.service.ts @@ -152,7 +152,7 @@ export class TopUpCustodialDeploymentsService implements DeploymentsRefiller { this.logger.info({ event: "TOP_UP_DEPLOYMENT", params: { ...messageInput, masterWallet: grantee }, dryRun: options.dryRun }); if (!options.dryRun) { - await client.executeTx([message]); + await client.executeTx([message], { fee: { granter: messageInput.owner } }); this.logger.info({ event: "TOP_UP_DEPLOYMENT_SUCCESS" }); } } diff --git a/apps/api/test/mocks/hello-world-sdl.yml b/apps/api/test/mocks/hello-world-sdl.yml index efd2fddc1..3849e5a3e 100644 --- a/apps/api/test/mocks/hello-world-sdl.yml +++ b/apps/api/test/mocks/hello-world-sdl.yml @@ -20,6 +20,8 @@ profiles: - size: 512Mi placement: dcloud: + attributes: + console/trials: "true" pricing: web: denom: uakt diff --git a/package-lock.json b/package-lock.json index 7b265ab75..575b2bf78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ }, "apps/api": { "name": "@akashnetwork/console-api", - "version": "2.28.0", + "version": "2.28.1-beta.0", "license": "Apache-2.0", "dependencies": { "@akashnetwork/akash-api": "^1.3.0", @@ -224,7 +224,7 @@ }, "apps/deploy-web": { "name": "@akashnetwork/console-web", - "version": "2.21.1-beta.0", + "version": "2.21.1-beta.1", "license": "Apache-2.0", "dependencies": { "@akashnetwork/akash-api": "^1.3.0",