Skip to content

Commit 0a6d6b2

Browse files
authored
Create EOA + Sign & Send Tx (#103)
* updated code to use from, AWS KMS EOA wallets * updated end-points to include web3api overrides & creation of eoa on AWS, wallet end-points * fixed e2e * fix for value field, e2e fixed too * removed comment * using ethers gcp signer to get walletAddress. But having issues, so commented
1 parent be977b7 commit 0a6d6b2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+3362
-434
lines changed

.env.benchmark

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
THIRDWEB_SDK_SECRET_KEY=klRsqmatrdlEpik_pHKgYy_q2YzGe3bTewO1VC26eY_H184Kc7xOVqKVj0mHwOOW2AOx2N-a3GqLCQ7Z9s9-sw
2+
3+
# benchmark vars
4+
NODE_ENV=benchmark
5+
BENCHMARK_HOST='http://0.0.0.0:3005'
6+
BENCHMARK_URL_PATH='/contract/mumbai/0x365b83D67D5539C6583b9c0266A548926Bf216F4/write'
7+
BENCHMARK_POST_BODY='{
8+
"function_name": "transfer",
9+
"args": ["0x1946267d81Fb8aDeeEa28e6B98bcD446c8248473", 100000]
10+
}'
11+
# Total request has to be more than the total concurrency
12+
BENCHMARK_CONCURRENCY=10
13+
BENCHMARK_REQUESTS=10

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,8 @@ swagger.yml
135135
worker/distWorker/
136136
.DS_Store
137137
post_data.json
138-
benchmark.local.sh
138+
benchmark.local.sh
139+
140+
# GCP Service Account JSON
141+
thrdweb-biyvmatstwcbrb08y692g-41baca7a34a1.json
142+
thrdweb-biyvmatstwcbrb08y692g-7762eca4411b.json

core/database/dbOperation.ts

Lines changed: 157 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,167 @@
1+
import { getChainBySlug } from "@thirdweb-dev/chains";
2+
import { getSupportedChains } from "@thirdweb-dev/sdk";
3+
import { BigNumber } from "ethers";
4+
import { FastifyInstance } from "fastify";
15
import { Knex } from "knex";
6+
import { getInstanceAdminWalletType, getWalletBackUpType } from "../helpers";
27
import { WalletData } from "../interfaces";
8+
import { getSDK } from "../sdk/sdk";
9+
import { getWalletNonce } from "../services/blockchain";
10+
import { connectWithDatabase } from "./dbConnect";
11+
12+
interface WalletExtraData {
13+
awsKmsKeyId?: string;
14+
awsKmsArn?: string;
15+
walletType?: string;
16+
gcpKmsKeyId?: string;
17+
gcpKmsKeyRingId?: string;
18+
}
319

420
export const insertIntoWallets = async (
521
walletData: WalletData,
622
database: Knex,
7-
): Promise<void> => {
8-
await database("wallets")
23+
): Promise<number[]> => {
24+
return database("wallets")
925
.insert(walletData)
1026
.onConflict(["walletAddress", "chainId"])
1127
.merge();
1228
};
29+
30+
export const getWalletDetails = async (
31+
walletAddress: string,
32+
chainId: string,
33+
database?: Knex,
34+
): Promise<any> => {
35+
try {
36+
let passedAsParameter = true;
37+
if (!database) {
38+
passedAsParameter = false;
39+
database = await connectWithDatabase();
40+
}
41+
const walletDetails = await database("wallets")
42+
.select("*")
43+
.where({ walletAddress: walletAddress.toLowerCase(), chainId })
44+
.orWhere({ walletAddress: walletAddress.toLowerCase(), slug: chainId })
45+
.first();
46+
47+
if (!passedAsParameter) {
48+
await database.destroy();
49+
}
50+
return walletDetails;
51+
} catch (error) {
52+
throw error;
53+
}
54+
};
55+
56+
export const addWalletToDB = async (
57+
chainId: string,
58+
walletAddress: string,
59+
slug: string,
60+
dbInstance: Knex,
61+
): Promise<void> => {
62+
try {
63+
const sdk = await getSDK(chainId);
64+
const walletNonce = await getWalletNonce(
65+
walletAddress.toLowerCase(),
66+
sdk.getProvider(),
67+
);
68+
69+
const walletData = {
70+
walletAddress: walletAddress.toLowerCase(),
71+
chainId: chainId.toLowerCase(),
72+
blockchainNonce: BigNumber.from(walletNonce ?? 0).toNumber(),
73+
lastSyncedTimestamp: new Date(),
74+
lastUsedNonce: -1,
75+
walletType: slug,
76+
};
77+
78+
await insertIntoWallets(walletData, dbInstance);
79+
} catch (error) {
80+
throw error;
81+
}
82+
};
83+
84+
export const addWalletDataWithSupportChainsNonceToDB = async (
85+
server: FastifyInstance,
86+
dbInstance: Knex,
87+
isWeb3APIInitWallet?: boolean,
88+
walletAddress?: string,
89+
extraTableData?: WalletExtraData,
90+
): Promise<void> => {
91+
try {
92+
server.log.info("Setting up wallet Table");
93+
const supportedChains = await getSupportedChains();
94+
const promises = supportedChains.map(async (chain) => {
95+
try {
96+
const { slug } = chain;
97+
let lastUsedNonce = -1;
98+
let walletType = isWeb3APIInitWallet
99+
? getInstanceAdminWalletType()
100+
: getWalletBackUpType();
101+
const sdk = await getSDK(slug, {
102+
walletAddress,
103+
walletType,
104+
awsKmsKeyId: extraTableData?.awsKmsKeyId,
105+
});
106+
walletAddress =
107+
(await sdk.getSigner()?.getAddress())?.toLowerCase() ?? "";
108+
server.log.debug(`Setting up wallet for chain ${slug}`);
109+
if (walletAddress.length === 0) {
110+
// server.log.warn(`Wallet address not found for chain ${slug}.`);
111+
throw new Error(`Wallet address not found for chain ${slug}.`);
112+
}
113+
const walletBlockchainNonce = await getWalletNonce(
114+
walletAddress,
115+
sdk.getProvider(),
116+
);
117+
const walletDataInDB = await getWalletDetails(
118+
walletAddress,
119+
BigNumber.from(chain.chainId).toString(),
120+
dbInstance,
121+
);
122+
123+
if (walletDataInDB) {
124+
lastUsedNonce = walletDataInDB.lastUsedNonce;
125+
}
126+
127+
// lastUsedNonce should be set to -1 if blockchainNonce is 0
128+
if (
129+
BigNumber.from(walletBlockchainNonce).eq(BigNumber.from(0)) &&
130+
BigNumber.from(lastUsedNonce).eq(BigNumber.from(0))
131+
) {
132+
lastUsedNonce = -1;
133+
}
134+
135+
if (
136+
extraTableData?.walletType &&
137+
extraTableData?.walletType.length > 0
138+
) {
139+
walletType = extraTableData.walletType;
140+
delete extraTableData.walletType;
141+
}
142+
143+
const walletData = {
144+
...extraTableData,
145+
walletAddress: walletAddress.toLowerCase(),
146+
chainId: getChainBySlug(slug).chainId.toString(),
147+
blockchainNonce: BigNumber.from(
148+
walletBlockchainNonce ?? 0,
149+
).toNumber(),
150+
lastSyncedTimestamp: new Date(),
151+
lastUsedNonce,
152+
slug,
153+
walletType,
154+
};
155+
return insertIntoWallets(walletData, dbInstance);
156+
} catch (error) {
157+
server.log.error((error as any).message);
158+
return Promise.resolve();
159+
}
160+
});
161+
162+
await Promise.all(promises);
163+
server.log.info(`Wallet Table setup completed`);
164+
} catch (error) {
165+
throw error;
166+
}
167+
};

core/database/dbPrereqs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export const checkTablesExistence = async (
4848
// Disconnect from DB
4949
await knex.destroy();
5050
} catch (error: any) {
51+
server.log.error(error);
5152
const customError = createCustomError(
5253
"Error while executing Table SQLs on startup",
5354
StatusCodes.INTERNAL_SERVER_ERROR,

core/database/sql-schemas/transactions.sql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ CREATE TABLE IF NOT EXISTS transactions (
2323
"gasPrice" VARCHAR(255),
2424
"gasLimit" VARCHAR(255),
2525
"maxPriorityFeePerGas" VARCHAR(255),
26-
"maxFeePerGas" VARCHAR(255)
26+
"maxFeePerGas" VARCHAR(255),
27+
"txValue" VARCHAR(100)
2728
);
2829

2930
ALTER TABLE transactions
@@ -41,5 +42,6 @@ ALTER COLUMN "txType" TYPE VARCHAR(255),
4142
ADD COLUMN IF NOT EXISTS "deployedContractAddress" VARCHAR(255),
4243
ADD COLUMN IF NOT EXISTS "contractType" VARCHAR(255),
4344
ADD COLUMN IF NOT EXISTS "errorMessage" TEXT DEFAULT NULL,
45+
ADD COLUMN IF NOT EXISTS "txValue" VARCHAR(100) DEFAULT NULL,
4446
ADD COLUMN IF NOT EXISTS "txMinedTimestamp" TIMESTAMP,
45-
ADD COLUMN IF NOT EXISTS "blockNumber" BIGINT;
47+
ADD COLUMN IF NOT EXISTS "blockNumber" BIGINT;

core/database/sql-schemas/wallets.sql

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,27 @@ CREATE TABLE IF NOT EXISTS wallets (
22
"walletAddress" VARCHAR(255) NOT NULL,
33
"chainId" VARCHAR(255) NOT NULL,
44
"walletType" VARCHAR(255) NOT NULL,
5+
"slug" VARCHAR(255),
56
"blockchainNonce" BIGINT NOT NULL,
67
"lastSyncedTimestamp" TIMESTAMP,
78
"lastUsedNonce" BIGINT NOT NULL,
9+
"awsKmsKeyId" VARCHAR(255),
10+
"awsKmsArn" VARCHAR(255),
11+
-- "gcpKmsKeyRingId" VARCHAR(50),
12+
-- "gcpKmsKeyId" VARCHAR(50),
13+
-- "gcpKmsKeyVersion" VARCHAR(20),
814
PRIMARY KEY ("walletAddress", "chainId")
915
);
1016

1117
ALTER TABLE wallets
1218
ALTER COLUMN "chainId" TYPE VARCHAR(255),
1319
ALTER COLUMN "walletType" TYPE VARCHAR(255),
1420
ALTER COLUMN "blockchainNonce" TYPE BIGINT,
15-
ALTER COLUMN "lastUsedNonce" TYPE BIGINT;
21+
ALTER COLUMN "lastUsedNonce" TYPE BIGINT,
22+
ADD COLUMN IF NOT EXISTS "awsKmsKeyId" VARCHAR(255),
23+
ADD COLUMN IF NOT EXISTS "awsKmsArn" VARCHAR(255),
24+
ADD COLUMN IF NOT EXISTS "slug" VARCHAR(255),
25+
DROP COLUMN IF EXISTS "chainName";
26+
-- ADD COLUMN IF NOT EXISTS "gcpKmsKeyRingId" VARCHAR(50),
27+
-- ADD COLUMN IF NOT EXISTS "gcpKmsKeyId" VARCHAR(50),
28+
-- ADD COLUMN IF NOT EXISTS "gcpKmsKeyVersion" VARCHAR(20);

core/env.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ export const env = createEnv({
2929
WALLET_PRIVATE_KEY: z.string().min(1),
3030
}),
3131
z.object({
32-
AWS_ACCESS_KEY_ID: z.string().min(1),
33-
AWS_SECRET_ACCESS_KEY: z.string().min(1),
3432
AWS_KMS_KEY_ID: z.string().min(1),
35-
AWS_REGION: z.string().min(1),
3633
}),
3734
]),
35+
AWS_ACCESS_KEY_ID: z.string().min(1).optional(),
36+
AWS_SECRET_ACCESS_KEY: z.string().min(1).optional(),
37+
AWS_REGION: z.string().min(1).optional(),
3838
THIRDWEB_SDK_SECRET_KEY: z.string().min(1),
3939
THIRDWEB_API_ORIGIN: z.string().default("http://api.thirdweb.com"),
4040
POSTGRES_HOST: z.string().default("localhost"),
@@ -56,8 +56,13 @@ export const env = createEnv({
5656
CHAIN_OVERRIDES: z.string().default(""),
5757
ACCESS_CONTROL_ALLOW_ORIGIN: z.string().default("*"),
5858
MINED_TX_CRON_ENABLED: boolSchema("true"),
59-
MINED_TX_CRON_SCHEDULE: z.string().default("*/30 * * * * *"),
59+
MINED_TX_CRON_SCHEDULE: z.string().default("*/5 * * * * *"),
6060
MIN_TX_TO_CHECK_FOR_MINED_STATUS: z.coerce.number().default(50),
61+
GCP_PROJECT_ID: z.string().min(1).optional(),
62+
GCP_KEY_RING_ID: z.string().min(1).optional(),
63+
GCP_LOCATION_ID: z.string().min(1).optional(),
64+
GOOGLE_APPLICATION_CREDENTIAL_EMAIL: z.string().min(1).optional(),
65+
GOOGLE_APPLICATION_CREDENTIAL_PRIVATE_KEY: z.string().min(1).optional(),
6166
},
6267
clientPrefix: "NEVER_USED",
6368
client: {},
@@ -67,11 +72,11 @@ export const env = createEnv({
6772
WALLET_KEYS: {
6873
// The sdk expects a primitive type but we can overload it here to be an object
6974
WALLET_PRIVATE_KEY: process.env.WALLET_PRIVATE_KEY,
70-
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID,
71-
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY,
7275
AWS_KMS_KEY_ID: process.env.AWS_KMS_KEY_ID,
73-
AWS_REGION: process.env.AWS_REGION,
7476
} as any,
77+
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID,
78+
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY,
79+
AWS_REGION: process.env.AWS_REGION,
7580
THIRDWEB_SDK_SECRET_KEY: process.env.THIRDWEB_SDK_SECRET_KEY,
7681
THIRDWEB_API_ORIGIN: process.env.THIRDWEB_API_ORIGIN,
7782
POSTGRES_HOST: process.env.POSTGRES_HOST,
@@ -94,6 +99,13 @@ export const env = createEnv({
9499
MINED_TX_CRON_SCHEDULE: process.env.MINED_TX_CRON_SCHEDULE,
95100
MIN_TX_TO_CHECK_FOR_MINED_STATUS:
96101
process.env.MIN_TX_TO_CHECK_FOR_MINED_STATUS,
102+
GCP_PROJECT_ID: process.env.GCP_PROJECT_ID,
103+
GCP_KEY_RING_ID: process.env.GCP_KEY_RING_ID,
104+
GCP_LOCATION_ID: process.env.GCP_LOCATION_ID,
105+
GOOGLE_APPLICATION_CREDENTIAL_EMAIL:
106+
process.env.GOOGLE_APPLICATION_CREDENTIAL_EMAIL,
107+
GOOGLE_APPLICATION_CREDENTIAL_PRIVATE_KEY:
108+
process.env.GOOGLE_APPLICATION_CREDENTIAL_PRIVATE_KEY,
97109
},
98110
onValidationError: (error: ZodError) => {
99111
if ("WALLET_KEYS" in error.format()) {

core/helpers/index.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
import { env } from "../env";
2+
3+
const AWS_ACCESS_KEY_ID = env.AWS_ACCESS_KEY_ID;
4+
const AWS_SECRET_ACCESS_KEY = env.AWS_SECRET_ACCESS_KEY;
5+
const AWS_REGION = env.AWS_REGION;
6+
7+
const WALLET_PRIVATE_KEY =
8+
"WALLET_PRIVATE_KEY" in env.WALLET_KEYS
9+
? env.WALLET_KEYS.WALLET_PRIVATE_KEY
10+
: undefined;
11+
112
export const isValidHttpUrl = (urlString: string): boolean => {
213
let url;
314

@@ -9,3 +20,25 @@ export const isValidHttpUrl = (urlString: string): boolean => {
920

1021
return url.protocol === "http:" || url.protocol === "https:";
1122
};
23+
24+
export const getInstanceAdminWalletType = (): string => {
25+
if (WALLET_PRIVATE_KEY) {
26+
return "ppk";
27+
}
28+
29+
if (AWS_ACCESS_KEY_ID && AWS_SECRET_ACCESS_KEY && AWS_REGION) {
30+
return "aws_kms";
31+
}
32+
33+
// ToDo GCP KMS
34+
return "";
35+
};
36+
37+
export const getWalletBackUpType = (): string => {
38+
if (AWS_ACCESS_KEY_ID && AWS_SECRET_ACCESS_KEY && AWS_REGION) {
39+
return "aws_kms";
40+
}
41+
42+
// ToDo GCP KMS
43+
return "ppk";
44+
};

core/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from "./database/dbConnect";
2+
export * from "./database/dbOperation";
23
export * from "./database/dbPrereqs";
34
export * from "./env";
45
export * from "./error/customError";

core/interfaces/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,10 @@ export interface WalletData {
44
lastUsedNonce: number;
55
blockchainNonce: number;
66
lastSyncedTimestamp: Date;
7+
walletType: string;
8+
awsKmsKeyId?: string;
9+
gcpKmsKeyId?: string;
10+
awsKmsKeyArn?: string;
11+
gcpKmsKeyRingId?: string;
12+
gcpKmsKeyVersion?: string;
713
}

0 commit comments

Comments
 (0)