Skip to content

Commit

Permalink
tested transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
d4mr committed Feb 4, 2025
1 parent ee8c926 commit f102ee3
Show file tree
Hide file tree
Showing 13 changed files with 559 additions and 19 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"knex": "^3.1.0",
"mnemonist": "^0.39.8",
"node-cron": "^3.0.2",
"ox": "^0.6.9",
"pg": "^8.11.3",
"prisma": "^5.14.0",
"prom-client": "^15.1.3",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
-- AlterTable
ALTER TABLE "configuration" ADD COLUMN "walletProviderConfigs" JSONB NOT NULL DEFAULT '{}';

-- AlterTable
ALTER TABLE "wallet_details" ADD COLUMN "credentialId" TEXT,
ADD COLUMN "platformIdentifiers" JSONB;

-- CreateTable
CREATE TABLE "wallet_credentials" (
"id" TEXT NOT NULL,
"type" TEXT NOT NULL,
"label" TEXT NOT NULL,
"data" JSONB NOT NULL,
"isDefault" BOOLEAN NOT NULL DEFAULT false,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"deletedAt" TIMESTAMP(3),

CONSTRAINT "wallet_credentials_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE INDEX "wallet_credentials_type_idx" ON "wallet_credentials"("type");

-- CreateIndex
CREATE UNIQUE INDEX "wallet_credentials_type_is_default_key" ON "wallet_credentials"("type", "isDefault");

-- AddForeignKey
ALTER TABLE "wallet_details" ADD CONSTRAINT "wallet_details_credentialId_fkey" FOREIGN KEY ("credentialId") REFERENCES "wallet_credentials"("id") ON DELETE SET NULL ON UPDATE CASCADE;
102 changes: 90 additions & 12 deletions src/server/routes/backend-wallet/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import {
DEFAULT_ACCOUNT_FACTORY_V0_7,
ENTRYPOINT_ADDRESS_v0_7,
} from "thirdweb/wallets/smart";
import { WalletType } from "../../../shared/schemas/wallet";
import {
LegacyWalletType,
WalletType,
CircleWalletType,
} from "../../../shared/schemas/wallet";
import { getConfig } from "../../../shared/utils/cache/get-config";
import { createCustomError } from "../../middleware/error";
import { AddressSchema } from "../../schemas/address";
Expand All @@ -25,16 +29,26 @@ import {
createSmartGcpWalletDetails,
createSmartLocalWalletDetails,
} from "../../utils/wallets/create-smart-wallet";
import {
CircleWalletError,
createCircleWalletDetails,
} from "../../utils/wallets/circle";

const requestBodySchema = Type.Object({
label: Type.Optional(Type.String()),
type: Type.Optional(
Type.Enum(WalletType, {
description:
"Type of new wallet to create. It is recommended to always provide this value. If not provided, the default wallet type will be used.",
}),
),
});
const requestBodySchema = Type.Union([
// Base schema for non-circle wallet types
Type.Object({
label: Type.Optional(Type.String()),
type: Type.Optional(Type.Union([Type.Enum(LegacyWalletType)])),
}),

// Schema for circle and smart:circle wallet types
Type.Object({
label: Type.Optional(Type.String()),
type: Type.Union([Type.Enum(CircleWalletType)]),
credentialId: Type.String(),
walletSetId: Type.Optional(Type.String()),
}),
]);

const responseSchema = Type.Object({
result: Type.Object({
Expand Down Expand Up @@ -73,7 +87,7 @@ export const createBackendWallet = async (fastify: FastifyInstance) => {
handler: async (req, reply) => {
const { label } = req.body;

let walletAddress: string;
let walletAddress: string | undefined = undefined;
const config = await getConfig();

const walletType =
Expand Down Expand Up @@ -112,6 +126,66 @@ export const createBackendWallet = async (fastify: FastifyInstance) => {
throw e;
}
break;
case CircleWalletType.circle:
{
// we need this if here for typescript to statically type the credentialId and walletSetId
if (req.body.type !== "circle")
throw new Error("Invalid Circle wallet type"); // invariant

const { credentialId, walletSetId } = req.body;

try {
const wallet = await createCircleWalletDetails({
label,
isSmart: false,
credentialId,
walletSetId,
});

walletAddress = getAddress(wallet.address);
} catch (e) {
if (e instanceof CircleWalletError) {
throw createCustomError(
e.message,
StatusCodes.BAD_REQUEST,
"CREATE_CIRCLE_WALLET_ERROR",
);
}
throw e;
}
}
break;

case CircleWalletType.smartCircle:
{
// we need this if here for typescript to statically type the credentialId and walletSetId
if (req.body.type !== "smart:circle")
throw new Error("Invalid Circle wallet type"); // invariant

const { credentialId, walletSetId } = req.body;

try {
const wallet = await createCircleWalletDetails({
label,
isSmart: true,
credentialId,
walletSetId,
});

walletAddress = getAddress(wallet.address);
} catch (e) {
if (e instanceof CircleWalletError) {
throw createCustomError(
e.message,
StatusCodes.BAD_REQUEST,
"CREATE_CIRCLE_WALLET_ERROR",
);
}
throw e;
}
}
break;

case WalletType.smartAwsKms:
try {
const smartAwsWallet = await createSmartAwsWalletDetails({
Expand Down Expand Up @@ -163,10 +237,14 @@ export const createBackendWallet = async (fastify: FastifyInstance) => {
break;
}

if (!walletAddress) {
throw new Error("Invalid state"); // invariant, typescript cannot exhaustive check because enums
}

reply.status(StatusCodes.OK).send({
result: {
walletAddress,
type: walletType,
type: walletType as WalletType,
status: "success",
},
});
Expand Down
18 changes: 18 additions & 0 deletions src/server/routes/configuration/wallets/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ const requestBodySchema = Type.Union([
gcpApplicationCredentialEmail: Type.String(),
gcpApplicationCredentialPrivateKey: Type.String(),
}),
Type.Object({
awsAccessKeyId: Type.String(),
awsSecretAccessKey: Type.String(),
awsRegion: Type.String(),
}),
Type.Object({
circleApiKey: Type.String(),
}),
]);

requestBodySchema.examples = [
Expand Down Expand Up @@ -107,6 +115,16 @@ export async function updateWalletsConfiguration(fastify: FastifyInstance) {
});
}

if ("circleApiKey" in req.body) {
await updateConfiguration({
walletProviderConfigs: {
circle: {
apiKey: req.body.circleApiKey,
},
},
});
}

const config = await getConfig(false);

const { legacyWalletType_removeInNextBreakingChange, aws, gcp } =
Expand Down
8 changes: 8 additions & 0 deletions src/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ import { revokeWebhook } from "./webhooks/revoke";
import { testWebhookRoute } from "./webhooks/test";
import { readBatchRoute } from "./contract/read/read-batch";
import { sendTransactionBatchAtomicRoute } from "./backend-wallet/send-transaction-batch-atomic";
import { createWalletCredentialRoute } from "./wallet-credentials/create";
import { getWalletCredentialRoute } from "./wallet-credentials/get";
import { getAllWalletCredentialsRoute } from "./wallet-credentials/get-all";

export async function withRoutes(fastify: FastifyInstance) {
// Backend Wallets
Expand All @@ -137,6 +140,11 @@ export async function withRoutes(fastify: FastifyInstance) {
await fastify.register(getBackendWalletNonce);
await fastify.register(simulateTransaction);

// Credentials
await fastify.register(createWalletCredentialRoute);
await fastify.register(getWalletCredentialRoute);
await fastify.register(getAllWalletCredentialsRoute);

// Configuration
await fastify.register(getWalletsConfiguration);
await fastify.register(updateWalletsConfiguration);
Expand Down
2 changes: 1 addition & 1 deletion src/server/routes/wallet-credentials/get-all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ responseSchema.example = {
],
};

export async function getAllWalletCredentialsEndpoint(fastify: FastifyInstance) {
export async function getAllWalletCredentialsRoute(fastify: FastifyInstance) {
fastify.route<{
Querystring: Static<typeof QuerySchema>;
Reply: Static<typeof responseSchema>;
Expand Down
2 changes: 1 addition & 1 deletion src/server/routes/wallet-credentials/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ responseSchema.example = {
},
};

export async function getWalletCredentialEndpoint(fastify: FastifyInstance) {
export async function getWalletCredentialRoute(fastify: FastifyInstance) {
fastify.route<{
Params: Static<typeof ParamsSchema>;
Reply: Static<typeof responseSchema>;
Expand Down
Loading

0 comments on commit f102ee3

Please sign in to comment.