Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,8 @@
"noStaticOnlyClass": "off"
}
}
},
"files": {
"ignore": ["sdk"]
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@bull-board/fastify": "^5.21.1",
"@cloud-cryptographic-wallet/cloud-kms-signer": "^0.1.2",
"@cloud-cryptographic-wallet/signer": "^0.0.5",
"@ethersproject/json-wallets": "^5.7.0",
"@fastify/basic-auth": "^5.1.1",
"@fastify/cookie": "^8.3.0",
"@fastify/express": "^2.3.0",
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/Engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class EngineLogic {

constructor(config?: Partial<OpenAPIConfig>, HttpRequest: HttpRequestConstructor = FetchHttpRequest) {
this.request = new HttpRequest({
BASE: config?.BASE ?? 'https://YOUR_ENGINE_URL',
BASE: config?.BASE ?? '',
VERSION: config?.VERSION ?? '1.0.0',
WITH_CREDENTIALS: config?.WITH_CREDENTIALS ?? false,
CREDENTIALS: config?.CREDENTIALS ?? 'include',
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/core/OpenAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export type OpenAPIConfig = {
};

export const OpenAPI: OpenAPIConfig = {
BASE: 'https://YOUR_ENGINE_URL',
BASE: '',
VERSION: '1.0.0',
WITH_CREDENTIALS: false,
CREDENTIALS: 'include',
Expand Down
6 changes: 4 additions & 2 deletions sdk/src/services/BackendWalletService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ export class BackendWalletService {
requestBody?: {
label?: string;
/**
* Optional wallet type. If not provided, the default wallet type will be used.
* Type of new wallet to create. It is recommended to always provide this value. If not provided, the default wallet type will be used.
*/
type?: ('local' | 'aws-kms' | 'gcp-kms');
type?: ('local' | 'aws-kms' | 'gcp-kms' | 'smart:aws-kms' | 'smart:gcp-kms' | 'smart:local');
},
): CancelablePromise<{
result: {
Expand All @@ -31,6 +31,7 @@ export class BackendWalletService {
*/
walletAddress: string;
status: string;
type: ('local' | 'aws-kms' | 'gcp-kms' | 'smart:aws-kms' | 'smart:gcp-kms' | 'smart:local');
};
}> {
return this.httpRequest.request({
Expand Down Expand Up @@ -664,6 +665,7 @@ export class BackendWalletService {
requestBody: {
message: string;
isBytes?: boolean;
chainId?: number;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note from our convo: can you check if signing on different chains result in the same output. If so, we could default to a testnet (Sepolia?).

},
xIdempotencyKey?: string,
): CancelablePromise<{
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/services/ConfigurationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class ConfigurationService {
*/
public getWalletsConfiguration(): CancelablePromise<{
result: {
type: ('local' | 'aws-kms' | 'gcp-kms');
type: ('local' | 'aws-kms' | 'gcp-kms' | 'smart:aws-kms' | 'smart:gcp-kms' | 'smart:local');
awsAccessKeyId: (string | null);
awsRegion: (string | null);
gcpApplicationProjectId: (string | null);
Expand Down Expand Up @@ -58,7 +58,7 @@ export class ConfigurationService {
}),
): CancelablePromise<{
result: {
type: ('local' | 'aws-kms' | 'gcp-kms');
type: ('local' | 'aws-kms' | 'gcp-kms' | 'smart:aws-kms' | 'smart:gcp-kms' | 'smart:local');
awsAccessKeyId: (string | null);
awsRegion: (string | null);
gcpApplicationProjectId: (string | null);
Expand Down
116 changes: 105 additions & 11 deletions src/db/wallets/createWalletDetails.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Address } from "thirdweb";
import type { PrismaTransaction } from "../../schema/prisma";
import { encrypt } from "../../utils/crypto";
import { getPrismaWithPostgresTx } from "../client";
Expand All @@ -8,13 +9,17 @@ type CreateWalletDetailsParams = {
address: string;
label?: string;
} & (
| {
type: "local";
encryptedJson: string; // ENCRYPTION IS NOT HANDLED HERE, process privatekey with legacyLocalCrytpo before passing to this function
}
| {
type: "aws-kms";
awsKmsKeyId?: string; // depcrecated and unused, todo: remove with next breaking change
awsKmsArn: string;

awsKmsSecretAccessKey?: string; // will be encrypted and stored, pass plaintext to this function
awsKmsAccessKeyId?: string;
awsKmsSecretAccessKey: string; // will be encrypted and stored, pass plaintext to this function
awsKmsAccessKeyId: string;
Comment on lines +21 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't making these fields non-optional be a breaking change? We could ofc update the dashboard, but it'll impact anyone in the slim chance they're automating KMS backend wallet creation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decided to always denormalize and store credentials in the DB row, regardless of it being an override or coming from config. Users don't have to pass it in, the route fills in this from the config.

}
| {
type: "gcp-kms";
Expand All @@ -24,11 +29,42 @@ type CreateWalletDetailsParams = {
gcpKmsKeyVersionId?: string; // depcrecated and unused, todo: remove with next breaking change
gcpKmsLocationId?: string; // depcrecated and unused, todo: remove with next breaking change

gcpApplicationCredentialPrivateKey?: string; // encrypted
gcpApplicationCredentialEmail?: string;
gcpApplicationCredentialPrivateKey: string; // will be encrypted and stored, pass plaintext to this function
gcpApplicationCredentialEmail: string;
}
| {
type: "smart:aws-kms";
awsKmsArn: string;
awsKmsSecretAccessKey: string; // will be encrypted and stored, pass plaintext to this function
awsKmsAccessKeyId: string;
accountSignerAddress: Address;

accountFactoryAddress: Address | undefined;
entrypointAddress: Address | undefined;
}
| {
type: "smart:gcp-kms";
gcpKmsResourcePath: string;
gcpApplicationCredentialPrivateKey: string; // will be encrypted and stored, pass plaintext to this function
gcpApplicationCredentialEmail: string;
accountSignerAddress: Address;

accountFactoryAddress: Address | undefined;
entrypointAddress: Address | undefined;
}
| {
type: "smart:local";
encryptedJson: string; // ENCRYPTION IS NOT HANDLED HERE, process privatekey with legacyLocalCrytpo before passing to this function
accountSignerAddress: Address;

accountFactoryAddress: Address | undefined;
entrypointAddress: Address | undefined;
}
);

/**
* Create a new WalletDetails row in DB
*/
export const createWalletDetails = async ({
pgtx,
...walletDetails
Expand All @@ -47,15 +83,23 @@ export const createWalletDetails = async ({
);
}

if (walletDetails.type === "local") {
return prisma.walletDetails.create({
data: {
...walletDetails,
address: walletDetails.address.toLowerCase(),
encryptedJson: walletDetails.encryptedJson,
},
});
}

if (walletDetails.type === "aws-kms") {
return prisma.walletDetails.create({
data: {
...walletDetails,
address: walletDetails.address.toLowerCase(),

awsKmsSecretAccessKey: walletDetails.awsKmsSecretAccessKey
? encrypt(walletDetails.awsKmsSecretAccessKey)
: undefined,
awsKmsSecretAccessKey: encrypt(walletDetails.awsKmsSecretAccessKey),
},
});
}
Expand All @@ -66,11 +110,61 @@ export const createWalletDetails = async ({
...walletDetails,
address: walletDetails.address.toLowerCase(),

gcpApplicationCredentialPrivateKey:
walletDetails.gcpApplicationCredentialPrivateKey
? encrypt(walletDetails.gcpApplicationCredentialPrivateKey)
: undefined,
gcpApplicationCredentialPrivateKey: encrypt(
walletDetails.gcpApplicationCredentialPrivateKey,
),
},
});
}

if (walletDetails.type === "smart:aws-kms") {
return prisma.walletDetails.create({
data: {
...walletDetails,

address: walletDetails.address.toLowerCase(),
awsKmsSecretAccessKey: encrypt(walletDetails.awsKmsSecretAccessKey),
accountSignerAddress: walletDetails.accountSignerAddress.toLowerCase(),

accountFactoryAddress:
walletDetails.accountFactoryAddress?.toLowerCase(),
entrypointAddress: walletDetails.entrypointAddress?.toLowerCase(),
},
});
}

if (walletDetails.type === "smart:gcp-kms") {
return prisma.walletDetails.create({
data: {
...walletDetails,

address: walletDetails.address.toLowerCase(),
accountSignerAddress: walletDetails.accountSignerAddress.toLowerCase(),

gcpApplicationCredentialPrivateKey: encrypt(
walletDetails.gcpApplicationCredentialPrivateKey,
),

accountFactoryAddress:
walletDetails.accountFactoryAddress?.toLowerCase(),
entrypointAddress: walletDetails.entrypointAddress?.toLowerCase(),
},
});
}

if (walletDetails.type === "smart:local") {
return prisma.walletDetails.create({
data: {
...walletDetails,
address: walletDetails.address.toLowerCase(),
accountSignerAddress: walletDetails.accountSignerAddress.toLowerCase(),

accountFactoryAddress:
walletDetails.accountFactoryAddress?.toLowerCase(),
entrypointAddress: walletDetails.entrypointAddress?.toLowerCase(),
},
});
}

throw new Error("Unsupported wallet type");
};
Loading