Skip to content

Commit f915a53

Browse files
0xFirekeeperclaude
andauthored
[Dashboard] Create vault service accounts through api-server (#8918)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 808f1bd commit f915a53

6 files changed

Lines changed: 128 additions & 309 deletions

File tree

‎apps/dashboard/src/@/actions/vault.ts‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ type RotateVaultServiceAccountResult = {
4545
walletAccessToken?: string;
4646
};
4747

48+
type CreateVaultServiceAccountResult = RotateVaultServiceAccountResult & {
49+
/** The project's default server wallet, null when none was created. */
50+
projectWalletAddress: string | null;
51+
};
52+
4853
/**
4954
* Credentials the caller supplies to unlock a vault. A managed vault takes the
5055
* project secret key, an ejected one takes the vault admin key.
@@ -153,6 +158,38 @@ export async function setVaultProjectWallet(params: {
153158
return res.data.data;
154159
}
155160

161+
/**
162+
* Creates the project's vault service account and its access tokens.
163+
*
164+
* A managed vault seals its admin key and wallet token with the project secret
165+
* key and returns neither. An ejected vault returns both, once.
166+
*/
167+
export async function createVaultServiceAccount(params: {
168+
project: ProjectRef;
169+
mode: "managed" | "ejected";
170+
projectSecretKey?: string;
171+
skipWalletCreation?: boolean;
172+
}): Promise<CreateVaultServiceAccountResult> {
173+
const res = await apiServerProxy<{
174+
data: CreateVaultServiceAccountResult;
175+
}>({
176+
body: JSON.stringify({
177+
mode: params.mode,
178+
projectSecretKey: params.projectSecretKey,
179+
skipWalletCreation: params.skipWalletCreation,
180+
}),
181+
headers: { "Content-Type": "application/json" },
182+
method: "POST",
183+
pathname: vaultPath(params.project, "/service-account"),
184+
});
185+
186+
if (!res.ok) {
187+
throw new Error(errorMessage(res.error, "Failed to create vault"));
188+
}
189+
190+
return res.data.data;
191+
}
192+
156193
export async function rotateVaultServiceAccount(params: {
157194
project: ProjectRef;
158195
projectSecretKey?: string;

‎apps/dashboard/src/@/components/project/create-project-modal/index.tsx‎

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useState } from "react";
77
import { useForm } from "react-hook-form";
88
import { toast } from "sonner";
99
import { z } from "zod";
10+
import { createVaultServiceAccount } from "@/actions/vault";
1011
import type { Project } from "@/api/project/projects";
1112
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
1213
import { Button } from "@/components/ui/button";
@@ -38,7 +39,6 @@ import { createProjectClient } from "@/hooks/useApi";
3839
import { useDashboardRouter } from "@/lib/DashboardRouter";
3940
import { projectDomainsSchema, projectNameSchema } from "@/schema/validations";
4041
import { toArrFromList } from "@/utils/string";
41-
import { createVaultAccountAndAccessToken } from "../../../../app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client";
4242

4343
const ALL_PROJECT_SERVICES = SERVICES.filter(
4444
(srv) => srv.name !== "relayer" && srv.name !== "chainsaw",
@@ -64,8 +64,12 @@ const CreateProjectDialog = (props: CreateProjectDialogProps) => {
6464
<CreateProjectDialogUI
6565
createProject={async (params) => {
6666
const res = await createProjectClient(props.teamId, params);
67-
const vaultTokens = await createVaultAccountAndAccessToken({
68-
project: res.project,
67+
await createVaultServiceAccount({
68+
mode: "managed",
69+
project: {
70+
projectId: res.project.id,
71+
teamId: res.project.teamId,
72+
},
6973
projectSecretKey: res.secret,
7074
}).catch((error) => {
7175
console.error(
@@ -75,12 +79,6 @@ const CreateProjectDialog = (props: CreateProjectDialogProps) => {
7579
throw error;
7680
});
7781

78-
const managementAccessToken = vaultTokens.managementToken?.accessToken;
79-
80-
if (!managementAccessToken) {
81-
throw new Error("Missing management access token for project wallet");
82-
}
83-
8482
return {
8583
project: res.project,
8684
secret: res.secret,

‎apps/dashboard/src/app/(app)/get-started/team/[team_slug]/create-project/_components/create-project-form.tsx‎

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useState } from "react";
88
import { useForm } from "react-hook-form";
99
import { toast } from "sonner";
1010
import { z } from "zod";
11+
import { createVaultServiceAccount } from "@/actions/vault";
1112
import { reportOnboardingCompleted } from "@/analytics/report";
1213
import type { Project } from "@/api/project/projects";
1314
import type { CreateProjectPrefillOptions } from "@/components/project/create-project-modal";
@@ -33,7 +34,6 @@ import { createProjectClient } from "@/hooks/useApi";
3334
import { useDashboardRouter } from "@/lib/DashboardRouter";
3435
import { projectDomainsSchema, projectNameSchema } from "@/schema/validations";
3536
import { toArrFromList } from "@/utils/string";
36-
import { createVaultAccountAndAccessToken } from "../../../../../team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client";
3737

3838
const ALL_PROJECT_SERVICES = SERVICES.filter(
3939
(srv) => srv.name !== "relayer" && srv.name !== "chainsaw",
@@ -55,8 +55,12 @@ export function CreateProjectFormOnboarding(props: {
5555
<CreateProjectForm
5656
createProject={async (params) => {
5757
const res = await createProjectClient(props.teamId, params);
58-
const vaultTokens = await createVaultAccountAndAccessToken({
59-
project: res.project,
58+
await createVaultServiceAccount({
59+
mode: "managed",
60+
project: {
61+
projectId: res.project.id,
62+
teamId: res.project.teamId,
63+
},
6064
projectSecretKey: res.secret,
6165
}).catch((error) => {
6266
console.error(
@@ -66,15 +70,6 @@ export function CreateProjectFormOnboarding(props: {
6670
throw error;
6771
});
6872

69-
const managementAccessToken =
70-
vaultTokens.managementToken?.accessToken;
71-
72-
if (!managementAccessToken) {
73-
throw new Error(
74-
"Missing management access token for project wallet",
75-
);
76-
}
77-
7873
return {
7974
project: res.project,
8075
secret: res.secret,

0 commit comments

Comments
 (0)