Skip to content

Commit

Permalink
Smart Backend Wallets (#709)
Browse files Browse the repository at this point in the history
* smart backend wallet creation + initial flow

* refactor wallet detail decryption
- add sbw flow for v4 sdk getWallet

* change names

* Refactor import statement for TransactionReceipt in sdk.ts

* Refactor biome.json to ignore the "sdk" directory

* Fix smart backend wallet functionality for both v4 and v5 SDK
- Refactor walletDetailsToAccount function and add caching for admin accounts

* use v6 factory default

* consistent naming

* remove redundant comment

* entrypoint updates

* chainId in sign + thirdweb client in e2e tests

* worker refactors

* more tests

* consistent naming

* conditionally require chainId for signing smart account messsages

* naming consistencies

* reject transaction if unsupported chain

* fix userop tests

* fix: only transform QueuedTransaction if sbw

* Refactor SWRCache to log errors during cache revalidation
  • Loading branch information
d4mr authored Nov 4, 2024
1 parent 07b29de commit 94afe24
Show file tree
Hide file tree
Showing 39 changed files with 1,970 additions and 5,981 deletions.
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;
},
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;
}
| {
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

0 comments on commit 94afe24

Please sign in to comment.