Skip to content

Commit

Permalink
feat(deployment): add new endpoint to query filtered bids for trial a…
Browse files Browse the repository at this point in the history
…ccounts
  • Loading branch information
baktun14 committed Oct 22, 2024
1 parent 48ad3f0 commit 5f196a5
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 15 deletions.
3 changes: 2 additions & 1 deletion apps/api/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,11 @@ if (BILLING_ENABLED === "true") {
const { AuthInterceptor } = require("./auth/services/auth.interceptor");
appHono.use(container.resolve<HonoInterceptor>(AuthInterceptor).intercept());
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { startTrialRouter, getWalletListRouter, signAndBroadcastTxRouter, checkoutRouter, stripeWebhook } = require("./billing");
const { startTrialRouter, getWalletListRouter, signAndBroadcastTxRouter, checkoutRouter, stripeWebhook, trialBidsRouter } = require("./billing");
appHono.route("/", startTrialRouter);
appHono.route("/", getWalletListRouter);
appHono.route("/", signAndBroadcastTxRouter);
appHono.route("/", trialBidsRouter);
appHono.route("/", checkoutRouter);
appHono.route("/", stripeWebhook);
// eslint-disable-next-line @typescript-eslint/no-var-requires
Expand Down
7 changes: 7 additions & 0 deletions apps/api/src/billing/controllers/wallet/wallet.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { Protected } from "@src/auth/services/auth.service";
import type { WalletListOutputResponse, WalletOutputResponse } from "@src/billing/http-schemas/wallet.schema";
import type { SignTxRequestInput, SignTxResponseOutput, StartTrialRequestInput } from "@src/billing/routes";
import { GetWalletQuery } from "@src/billing/routes/get-wallet-list/get-wallet-list.router";
import { GetTrialBidListRequestInput } from "@src/billing/routes/trial-bids/trial-bids.router";
import { WalletInitializerService } from "@src/billing/services";
import { RefillService } from "@src/billing/services/refill/refill.service";
import { TrialValidationService } from "@src/billing/services/trial-validation/trial-validation.service";
import { TxSignerService } from "@src/billing/services/tx-signer/tx-signer.service";
import { GetWalletOptions, WalletReaderService } from "@src/billing/services/wallet-reader/wallet-reader.service";
import { WithTransaction } from "@src/core";
Expand All @@ -17,6 +19,7 @@ export class WalletController {
private readonly walletInitializer: WalletInitializerService,
private readonly signerService: TxSignerService,
private readonly refillService: RefillService,
private readonly trialValidationService: TrialValidationService,
private readonly walletReaderService: WalletReaderService
) {}

Expand Down Expand Up @@ -45,4 +48,8 @@ export class WalletController {
async refillWallets() {
await this.refillService.refillAllFees();
}

async getTrialBidList({ address, dseq }: GetTrialBidListRequestInput) {
return this.trialValidationService.getTrialBidList(address, dseq);
}
}
30 changes: 30 additions & 0 deletions apps/api/src/billing/http-schemas/bids.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { z } from "zod";

// TODO: Extract into a types package
const BidOutputSchema = z.object({
bid_id: z.object({
owner: z.string().openapi({}),
dseq: z.string().openapi({}),
gseq: z.number().openapi({}),
oseq: z.number().openapi({}),
provider: z.string().openapi({})
}),
state: z.string().openapi({}),
price: z.object({
denom: z.string().openapi({}),
amount: z.string().openapi({})
}),
created_at: z.string().openapi({}),
resources_offer: z.array(
z.object({
resources: z.object({
id: z.number().openapi({})
})
})
)
});

export const BidListResponseOutputSchema = z.object({
bids: z.array(BidOutputSchema)
});
export type BidListOutputResponse = z.infer<typeof BidListResponseOutputSchema>;
1 change: 1 addition & 0 deletions apps/api/src/billing/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from "@src/billing/routes/get-wallet-list/get-wallet-list.router";
export * from "@src/billing/routes/checkout/checkout.router";
export * from "@src/billing/routes/sign-and-broadcast-tx/sign-and-broadcast-tx.router";
export * from "@src/billing/routes/stripe-webhook/stripe-webhook.router";
export * from "@src/billing/routes/trial-bids/trial-bids.router";
38 changes: 38 additions & 0 deletions apps/api/src/billing/routes/trial-bids/trial-bids.router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { createRoute } from "@hono/zod-openapi";
import { container } from "tsyringe";
import { z } from "zod";

import { WalletController } from "@src/billing/controllers/wallet/wallet.controller";
import { BidListResponseOutputSchema } from "@src/billing/http-schemas/bids.schema";
import { OpenApiHonoHandled } from "@src/core/services/open-api-hono-handled/open-api-hono-handled";

export const GetTrialBidListRequestInputSchema = z.object({
address: z.string().openapi({}),
dseq: z.string().openapi({})
});
export type GetTrialBidListRequestInput = z.infer<typeof GetTrialBidListRequestInputSchema>;

const route = createRoute({
method: "get",
path: "/v1/trial-bids",
summary: "Get a list of bids for trial accounts",
tags: ["Bids"],
request: {
query: GetTrialBidListRequestInputSchema
},
responses: {
200: {
description: "Returns a list of bids for trial accounts",
content: {
"application/json": {
schema: BidListResponseOutputSchema
}
}
}
}
});
export const trialBidsRouter = new OpenApiHonoHandled();

trialBidsRouter.openapi(route, async function routeGetTrialBidList(c) {
return c.json(await container.resolve(WalletController).getTrialBidList(c.req.valid("query")), 200);
});
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import * as v1beta4 from "@akashnetwork/akash-api/v1beta4";
import { EncodeObject } from "@cosmjs/proto-signing";
import axios from "axios";
import { singleton } from "tsyringe";

import { UserWalletOutput } from "@src/billing/repositories";
import { apiNodeUrl, betaTypeVersionMarket } from "@src/utils/constants";
import { ChainErrorService } from "../chain-error/chain-error.service";

@singleton()
export class AnonymousValidateService {
private readonly authorizedProviders = [
export class TrialValidationService {
readonly authorizedProviders = [
"akash1824w2vqx57n8zr8707dnyh85kjrkfkrrs94pk9",
"akash19ah5c95kq4kz2g6q5rdkdgt80kc3xycsd8plq8",
"akash1g7az2pus6atgeufgttlcnl0wzlzwd0lrsy6d7s",
Expand All @@ -33,4 +35,19 @@ export class AnonymousValidateService {

return true;
}

async getTrialBidList(address: string, dseq: string): Promise<{ bids: any[] }> {

Check warning on line 39 in apps/api/src/billing/services/trial-validation/trial-validation.service.ts

View workflow job for this annotation

GitHub Actions / validate-n-build

Unexpected any. Specify a different type
const response = await axios.get(`${apiNodeUrl}/akash/market/${betaTypeVersionMarket}/bids/list`, {
params: {
"filters.owner": address,
"filters.dseq": dseq
}
});

if (response.data.bids.length === 0) {
return { bids: [] };
}

return { bids: response.data.bids.filter((bid: { bid: { bid_id: { provider: string } } }) => this.authorizedProviders.includes(bid.bid.bid_id.provider)) };
}
}
4 changes: 2 additions & 2 deletions apps/api/src/billing/services/tx-signer/tx-signer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import { InjectTypeRegistry } from "@src/billing/providers/type-registry.provide
import { UserWalletOutput, UserWalletRepository } from "@src/billing/repositories";
import { MasterWalletService } from "@src/billing/services";
import { BalancesService } from "@src/billing/services/balances/balances.service";
import { AnonymousValidateService } from "../anonymous-validate/anonymous-validate";
import { ChainErrorService } from "../chain-error/chain-error.service";
import { TrialValidationService } from "../trial-validation/trial-validation.service";

type StringifiedEncodeObject = Omit<EncodeObject, "value"> & { value: string };
type SimpleSigningStargateClient = {
Expand All @@ -34,7 +34,7 @@ export class TxSignerService {
private readonly balancesService: BalancesService,
private readonly authService: AuthService,
private readonly chainErrorService: ChainErrorService,
private readonly anonymousValidateService: AnonymousValidateService
private readonly anonymousValidateService: TrialValidationService
) {}

async signAndBroadcast(userId: UserWalletOutput["userId"], messages: StringifiedEncodeObject[]) {
Expand Down
9 changes: 4 additions & 5 deletions apps/deploy-web/src/components/new-deployment/CreateLease.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ export const CreateLease: React.FunctionComponent<Props> = ({ dseq }) => {
const [selectedBids, setSelectedBids] = useState<{ [gseq: string]: BidDto }>({});
const [filteredBids, setFilteredBids] = useState<Array<string>>([]);
const [search, setSearch] = useState("");
const { address, signAndBroadcastTx } = useWallet();
const { address, signAndBroadcastTx, isTrialing, isManaged } = useWallet();
const { localCert } = useCertificate();
const router = useRouter();
const [numberOfRequests, setNumberOfRequests] = useState(0);
const { data: providers } = useProviderList();
const warningRequestsReached = numberOfRequests > WARNING_NUM_OF_BID_REQUESTS;
const maxRequestsReached = numberOfRequests > MAX_NUM_OF_BID_REQUESTS;
const { favoriteProviders } = useLocalNotes();
const { data: bids, isLoading: isLoadingBids } = useBidList(address, dseq, {
const { data: bids, isLoading: isLoadingBids } = useBidList(isTrialing, address, dseq, {
initialData: [],
refetchInterval: REFRESH_BIDS_INTERVAL,
onSuccess: () => {
Expand All @@ -92,7 +92,6 @@ export const CreateLease: React.FunctionComponent<Props> = ({ dseq }) => {

const allClosed = (bids?.length || 0) > 0 && bids?.every(bid => bid.state === "closed");
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
const wallet = useWallet();
const { closeDeploymentConfirm } = useManagedDeploymentConfirm();

useEffect(() => {
Expand All @@ -118,7 +117,7 @@ export const CreateLease: React.FunctionComponent<Props> = ({ dseq }) => {
}

const sendManifestNotification =
!wallet.isManaged &&
!isManaged &&
enqueueSnackbar(<Snackbar title="Deploying! 🚀" subTitle="Please wait a few seconds..." showLoading />, {
variant: "info",
autoHideDuration: null
Expand Down Expand Up @@ -148,7 +147,7 @@ export const CreateLease: React.FunctionComponent<Props> = ({ dseq }) => {

setIsSendingManifest(false);
}
}, [selectedBids, dseq, providers, localCert, wallet.isManaged, enqueueSnackbar, closeSnackbar, router]);
}, [selectedBids, dseq, providers, localCert, isManaged, enqueueSnackbar, closeSnackbar, router]);

// Filter bids
useEffect(() => {
Expand Down
15 changes: 10 additions & 5 deletions apps/deploy-web/src/queries/useBidQuery.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { useQuery } from "react-query";
import { QueryKey, useQuery, UseQueryOptions } from "react-query";
import axios from "axios";

import { BidDto, RpcBid } from "@src/types/deployment";
import { ApiUrlService } from "@src/utils/apiUtils";
import { useSettings } from "../context/SettingsProvider";
import { QueryKeys } from "./queryKeys";

async function getBidList(apiEndpoint: string, address: string, dseq: string): Promise<Array<BidDto> | null> {
async function getBidList(apiEndpoint: string, isTrialing: boolean, address: string, dseq: string): Promise<Array<BidDto> | null> {
if (!address || !dseq) return null;

const response = await axios.get(ApiUrlService.bidList(apiEndpoint, address, dseq));
const response = await axios.get(isTrialing ? ApiUrlService.trialBidList(address, dseq) : ApiUrlService.bidList(apiEndpoint, address, dseq));

return response.data.bids.map((b: RpcBid) => ({
id: b.bid.bid_id.provider + b.bid.bid_id.dseq + b.bid.bid_id.gseq + b.bid.bid_id.oseq,
Expand All @@ -24,9 +24,14 @@ async function getBidList(apiEndpoint: string, address: string, dseq: string): P
}));
}

export function useBidList(address: string, dseq: string, options) {
export function useBidList(
isTrialing: boolean,
address: string,
dseq: string,
options?: Omit<UseQueryOptions<BidDto[], Error, any, QueryKey>, "queryKey" | "queryFn">
) {
const { settings } = useSettings();
return useQuery(QueryKeys.getBidListKey(address, dseq), () => getBidList(settings.apiEndpoint, address, dseq), options);
return useQuery(QueryKeys.getBidListKey(address, dseq), () => getBidList(settings.apiEndpoint, isTrialing, address, dseq), options);
}

async function getBidInfo(apiEndpoint: string, address: string, dseq: string, gseq: number, oseq: number, provider: string): Promise<RpcBid | null> {
Expand Down
3 changes: 3 additions & 0 deletions apps/deploy-web/src/utils/apiUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export class ApiUrlService {
static bidList(apiEndpoint: string, address: string, dseq: string) {
return `${apiEndpoint}/akash/market/${networkStore.marketApiVersion}/bids/list?filters.owner=${address}&filters.dseq=${dseq}`;
}
static trialBidList(address: string, dseq: string) {
return `${this.baseApiUrl}/v1/trial-bids?address=${address}&dseq=${dseq}`;
}
static bidInfo(apiEndpoint: string, address: string, dseq: string, gseq: number, oseq: number, provider: string) {
return `${apiEndpoint}/akash/market/${networkStore.marketApiVersion}/bids/info?id.owner=${address}&id.dseq=${dseq}&id.gseq=${gseq}&id.oseq=${oseq}&id.provider=${provider}`;
}
Expand Down

0 comments on commit 5f196a5

Please sign in to comment.