Skip to content

Commit

Permalink
fix(deployment): set owner of custodial wallet as fee granter for top up
Browse files Browse the repository at this point in the history
refs #395
  • Loading branch information
ygrishajev committed Nov 13, 2024
1 parent 72c346c commit 9b99257
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 25 deletions.
16 changes: 6 additions & 10 deletions apps/api/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ interface ShortAccountInfo {
sequence: number;
}

interface ExecutedTxOptions {
fee: {
granter: string;
};
}

export class MasterSigningClientService {
private readonly FEES_DENOM = "uakt";

Expand All @@ -32,8 +38,8 @@ export class MasterSigningClientService {
private chainId: string;

private execTxLoader = new DataLoader(
async (batchedMessages: readonly EncodeObject[][]) => {
return this.executeTxBatchBlocking(batchedMessages);
async (batchedInputs: { messages: readonly EncodeObject[]; options?: ExecutedTxOptions }[]) => {
return this.executeTxBatchBlocking(batchedInputs);
},
{ cache: false, batchScheduleFn: callback => setTimeout(callback, this.config.MASTER_WALLET_BATCHING_INTERVAL_MS) }
);
Expand Down Expand Up @@ -75,24 +81,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?: ExecutedTxOptions) {
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<IndexedTx[]> {
private async executeTxBatchBlocking(inputs: { messages: readonly EncodeObject[]; options?: ExecutedTxOptions }[]): Promise<IndexedTx[]> {
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;
Expand All @@ -101,16 +107,18 @@ export class MasterSigningClientService {
}
}

private async executeTxBatch(messages: readonly EncodeObject[][]): Promise<IndexedTx[]> {
private async executeTxBatch(inputs: { messages: readonly EncodeObject[]; options?: ExecutedTxOptions }[]): Promise<IndexedTx[]> {
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
Expand All @@ -134,11 +142,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
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -182,4 +187,36 @@ describe(TopUpCustodialDeploymentsService.name, () => {
});
});
});

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 = "<REPLACE_WITH_OWNER_ADDRESS>";
const dseq = "<REPLACE_WITH_DEPLOYMENT_DSEQ_NUMBER>" as unknown as number;
const wallet = container.resolve<MasterWalletService>(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);
}
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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" });
}
}
Expand Down
2 changes: 2 additions & 0 deletions apps/api/test/mocks/hello-world-sdl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ profiles:
- size: 512Mi
placement:
dcloud:
attributes:
console/trials: "true"
pricing:
web:
denom: uakt
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9b99257

Please sign in to comment.