From 5f39ddfec4cff3f7563a825ef76209c5a013c505 Mon Sep 17 00:00:00 2001 From: b-l-u-e Date: Mon, 14 Oct 2024 15:49:11 +0300 Subject: [PATCH 1/7] Add create-account-with-threshold-key file example Signed-off-by: b-l-u-e --- examples/create-account-with-thresholdkey.js | 145 +++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 examples/create-account-with-thresholdkey.js diff --git a/examples/create-account-with-thresholdkey.js b/examples/create-account-with-thresholdkey.js new file mode 100644 index 000000000..b7a8fbb4a --- /dev/null +++ b/examples/create-account-with-thresholdkey.js @@ -0,0 +1,145 @@ +import { + Client, + PrivateKey, + AccountId, + Hbar, + AccountCreateTransaction, + TransferTransaction, + AccountBalanceQuery, + AccountDeleteTransaction, + KeyList, +} from "@hashgraph/sdk"; +import dotenv from "dotenv"; + +dotenv.config(); + +async function main() { + if ( + process.env.OPERATOR_ID == null || + process.env.OPERATOR_KEY == null || + process.env.HEDERA_NETWORK == null + ) { + throw new Error( + "Environment variables OPERATOR_ID, HEDERA_NETWORK, and OPERATOR_KEY are required.", + ); + } + + const operatorId = AccountId.fromString(process.env.OPERATOR_ID); + const operatorKey = PrivateKey.fromStringED25519(process.env.OPERATOR_KEY); + + // Create a client for the local Hedera network + const client = Client.forNetwork({ + [process.env.HEDERA_NETWORK]: new AccountId(3) + }); + client.setOperator(operatorId, operatorKey); + + try { + console.log("Create Account With Threshold Key Example Start!"); + + /* + * Step 1: + * Generate three new Ed25519 private, public key pairs. + * + * You do not need the private keys to create the Threshold Key List, + * you only need the public keys, and if you're doing things correctly, + * you probably shouldn't have these private keys. + */ + + // Generate 3 new Ed25519 private, public key pairs + const privateKeys = []; + const publicKeys = []; + for (let i = 0; i < 3; i++) { + const key = PrivateKey.generateED25519(); + privateKeys.push(key); + publicKeys.push(key.publicKey); + } + + console.log("Generating public keys..."); + publicKeys.forEach((publicKey, index) => { + console.log(`Generated public key ${index + 1}: ${publicKey.toString()}`); + }); + + /* + * Step 2: + * Create a Key List. + * + * Require 2 of the 3 keys we generated to sign on anything modifying this account. + */ + const thresholdKey = new KeyList(); + thresholdKey.setThreshold(2); + publicKeys.forEach((publicKey) => thresholdKey.push(publicKey)); + + /* + * Step 3: + * Create a new account setting a Key List from a previous step as an account's key. + */ + console.log("Creating new account..."); + const accountCreateTxResponse = await new AccountCreateTransaction() + .setKey(thresholdKey) + .setInitialBalance(new Hbar(1)) + .execute(client); + + const accountCreateTxReceipt = await accountCreateTxResponse.getReceipt(client); + const newAccountId = accountCreateTxReceipt.accountId; + if (!newAccountId) { + throw new Error("Failed to retrieve new account ID"); + } + console.log(`Created account with ID: ${newAccountId.toString()}`); + + /* + * Step 4: + * Create a transfer transaction from a newly created account to demonstrate the signing process (threshold). + */ + console.log("Transferring 1 Hbar from a newly created account..."); + let transferTx = new TransferTransaction() + .addHbarTransfer(newAccountId, new Hbar(-1)) // 1 Hbar in negative + .addHbarTransfer(new AccountId(3), new Hbar(1)) // 1 Hbar + .freezeWith(client); // Freeze with client + + // Sign with 2 of the 3 keys + transferTx = await transferTx.sign(privateKeys[0]); + transferTx = await transferTx.sign(privateKeys[1]); + + // Execute the transaction + const transferTxResponse = await transferTx.execute(client); + + // Wait for the transfer to reach consensus + await transferTxResponse.getReceipt(client); + + // Query the account balance after the transfer + const accountBalanceAfterTransfer = await new AccountBalanceQuery() + .setAccountId(newAccountId) + .execute(client); + + console.log("New account's Hbar balance after transfer: " + accountBalanceAfterTransfer.hbars.toString()); + + /* + * Step 5: + * Clean up: Delete created account. + */ + let accountDeleteTx = new AccountDeleteTransaction() + .setTransferAccountId(operatorId) + .setAccountId(newAccountId) + .freezeWith(client); + + accountDeleteTx = await accountDeleteTx.sign(privateKeys[0]); + accountDeleteTx = await accountDeleteTx.sign(privateKeys[1]); + + const accountDeleteTxResponse = await accountDeleteTx.execute(client); + await accountDeleteTxResponse.getReceipt(client); + + console.log("Account deleted successfully"); + + console.log("Create Account With Threshold Key Example Complete!"); + } catch (error) { + console.error("Error occurred:", error); + } finally { + // Close the client + client.close(); + } +} + +main().catch((error) => { + console.error("Unhandled error:", error); + process.exit(1); +}); \ No newline at end of file From dc67d870b2cdd71b1ae28fda7aee3ed147209c30 Mon Sep 17 00:00:00 2001 From: b-l-u-e Date: Tue, 15 Oct 2024 14:34:47 +0300 Subject: [PATCH 2/7] updated client configuration, removed unnecessary console logs and implemented logger Signed-off-by: b-l-u-e --- examples/create-account-with-thresholdkey.js | 108 +++++++++++-------- 1 file changed, 66 insertions(+), 42 deletions(-) diff --git a/examples/create-account-with-thresholdkey.js b/examples/create-account-with-thresholdkey.js index b7a8fbb4a..4dba1809d 100644 --- a/examples/create-account-with-thresholdkey.js +++ b/examples/create-account-with-thresholdkey.js @@ -9,43 +9,70 @@ import { AccountDeleteTransaction, KeyList, } from "@hashgraph/sdk"; + import dotenv from "dotenv"; dotenv.config(); +// Removed pino logger initialization +const logger = console; + +/** + * Step 0: Set up client connection to Hedera network + */ + async function main() { if ( - process.env.OPERATOR_ID == null || - process.env.OPERATOR_KEY == null || - process.env.HEDERA_NETWORK == null + !process.env.OPERATOR_ID || + !process.env.OPERATOR_KEY || + !process.env.HEDERA_NETWORK ) { - throw new Error( - "Environment variables OPERATOR_ID, HEDERA_NETWORK, and OPERATOR_KEY are required.", + logger.error( + "Environment variables OPERATOR_ID, OPERATOR_KEY, and HEDERA_NETWORK are required.", ); + throw new Error("Missing required environment variables."); } const operatorId = AccountId.fromString(process.env.OPERATOR_ID); const operatorKey = PrivateKey.fromStringED25519(process.env.OPERATOR_KEY); - // Create a client for the local Hedera network - const client = Client.forNetwork({ - [process.env.HEDERA_NETWORK]: new AccountId(3) - }); + let client; + + // Adjust this as needed for your local network + const localNetworkConfig = { + "127.0.0.1:50211": new AccountId(3), + } + + switch (process.env.HEDERA_NETWORK) { + case "mainnet": + client = Client.forMainnet(); + break; + case "testnet": + client = Client.forTestnet(); + break; + case "previewnet": + client = Client.forPreviewnet(); + break; + case "local-node": + client = Client.forNetwork(localNetworkConfig); + break; + default: + logger.error("Unsupported HEDERA_NETWORK value."); + throw new Error( + "Unsupported HEDERA_NETWORK value. Set to 'mainnet', 'testnet', 'previewnet', or 'local-node'.", + ); + } client.setOperator(operatorId, operatorKey); try { - console.log("Create Account With Threshold Key Example Start!"); + logger.info("Create Account With Threshold Key Example Start!"); /* * Step 1: * Generate three new Ed25519 private, public key pairs. * - * You do not need the private keys to create the Threshold Key List, - * you only need the public keys, and if you're doing things correctly, - * you probably shouldn't have these private keys. */ - // Generate 3 new Ed25519 private, public key pairs const privateKeys = []; const publicKeys = []; for (let i = 0; i < 3; i++) { @@ -54,9 +81,11 @@ async function main() { publicKeys.push(key.publicKey); } - console.log("Generating public keys..."); + logger.info("Generating public keys..."); publicKeys.forEach((publicKey, index) => { - console.log(`Generated public key ${index + 1}: ${publicKey.toString()}`); + console.log( + `Generated public key ${index + 1}: ${publicKey.toString()}`, + ); }); /* @@ -65,36 +94,33 @@ async function main() { * * Require 2 of the 3 keys we generated to sign on anything modifying this account. */ - const thresholdKey = new KeyList(); - thresholdKey.setThreshold(2); - publicKeys.forEach((publicKey) => thresholdKey.push(publicKey)); + const thresholdKey = new KeyList(publicKeys, 2); /* * Step 3: * Create a new account setting a Key List from a previous step as an account's key. */ - console.log("Creating new account..."); + logger.info("Creating new account..."); const accountCreateTxResponse = await new AccountCreateTransaction() .setKey(thresholdKey) - .setInitialBalance(new Hbar(1)) + .setInitialBalance(new Hbar(100)) .execute(client); - const accountCreateTxReceipt = await accountCreateTxResponse.getReceipt(client); + const accountCreateTxReceipt = + await accountCreateTxResponse.getReceipt(client); const newAccountId = accountCreateTxReceipt.accountId; - if (!newAccountId) { - throw new Error("Failed to retrieve new account ID"); - } - console.log(`Created account with ID: ${newAccountId.toString()}`); + + logger.info(`Created account with ID: ${newAccountId.toString()}`); /* * Step 4: * Create a transfer transaction from a newly created account to demonstrate the signing process (threshold). */ - console.log("Transferring 1 Hbar from a newly created account..."); - let transferTx = new TransferTransaction() - .addHbarTransfer(newAccountId, new Hbar(-1)) // 1 Hbar in negative - .addHbarTransfer(new AccountId(3), new Hbar(1)) // 1 Hbar - .freezeWith(client); // Freeze with client + logger.info("Transferring 1 Hbar from a newly created account..."); + let transferTx = new TransferTransaction() + .addHbarTransfer(newAccountId, new Hbar(-50)) + .addHbarTransfer(new AccountId(3), new Hbar(50)) + .freezeWith(client); // Sign with 2 of the 3 keys transferTx = await transferTx.sign(privateKeys[0]); @@ -111,13 +137,16 @@ async function main() { .setAccountId(newAccountId) .execute(client); - console.log("New account's Hbar balance after transfer: " + accountBalanceAfterTransfer.hbars.toString()); + logger.info( + "New account's Hbar balance after transfer: " + + accountBalanceAfterTransfer.hbars.toString(), + ); /* * Step 5: * Clean up: Delete created account. */ - let accountDeleteTx = new AccountDeleteTransaction() + let accountDeleteTx = new AccountDeleteTransaction() .setTransferAccountId(operatorId) .setAccountId(newAccountId) .freezeWith(client); @@ -128,18 +157,13 @@ async function main() { const accountDeleteTxResponse = await accountDeleteTx.execute(client); await accountDeleteTxResponse.getReceipt(client); - console.log("Account deleted successfully"); - - console.log("Create Account With Threshold Key Example Complete!"); + logger.info("Account deleted successfully"); } catch (error) { - console.error("Error occurred:", error); + logger.error("Error occurred during account creation:", error); } finally { - // Close the client client.close(); + logger.info("Create Account With Threshold Key Example Complete!"); } } -main().catch((error) => { - console.error("Unhandled error:", error); - process.exit(1); -}); \ No newline at end of file +void main(); From 54badd6a8bd905eae6e2ce6cbc1a6117e97af359 Mon Sep 17 00:00:00 2001 From: b-l-u-e Date: Tue, 15 Oct 2024 21:20:59 +0300 Subject: [PATCH 3/7] client configuration and logger updated Signed-off-by: b-l-u-e --- examples/create-account-with-thresholdkey.js | 48 ++++++++------------ 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/examples/create-account-with-thresholdkey.js b/examples/create-account-with-thresholdkey.js index 4dba1809d..3493a2673 100644 --- a/examples/create-account-with-thresholdkey.js +++ b/examples/create-account-with-thresholdkey.js @@ -1,3 +1,4 @@ +/* eslint-disable n/no-extraneous-import */ import { Client, PrivateKey, @@ -11,11 +12,25 @@ import { } from "@hashgraph/sdk"; import dotenv from "dotenv"; +import pino from "pino"; +import pinoPretty from "pino-pretty"; dotenv.config(); -// Removed pino logger initialization -const logger = console; +// Set default log level to 'silent' if SDK_LOG_LEVEL is not specified in .env +const SDK_LOG_LEVEL = process.env.SDK_LOG_LEVEL || "SILENT"; + +// Logger configuration based on SDK_LOG_LEVEL +const logger = pino( + { + level: SDK_LOG_LEVEL.toUpperCase(), + }, + pinoPretty({ + colorize: true, + translateTime: "SYS:standard", + ignore: "pid,hostname", + }), +); /** * Step 0: Set up client connection to Hedera network @@ -36,32 +51,9 @@ async function main() { const operatorId = AccountId.fromString(process.env.OPERATOR_ID); const operatorKey = PrivateKey.fromStringED25519(process.env.OPERATOR_KEY); - let client; + // Create the client based on the HEDERA_NETWORK environment variable + let client = Client.forName(process.env.HEDERA_NETWORK); - // Adjust this as needed for your local network - const localNetworkConfig = { - "127.0.0.1:50211": new AccountId(3), - } - - switch (process.env.HEDERA_NETWORK) { - case "mainnet": - client = Client.forMainnet(); - break; - case "testnet": - client = Client.forTestnet(); - break; - case "previewnet": - client = Client.forPreviewnet(); - break; - case "local-node": - client = Client.forNetwork(localNetworkConfig); - break; - default: - logger.error("Unsupported HEDERA_NETWORK value."); - throw new Error( - "Unsupported HEDERA_NETWORK value. Set to 'mainnet', 'testnet', 'previewnet', or 'local-node'.", - ); - } client.setOperator(operatorId, operatorKey); try { @@ -83,7 +75,7 @@ async function main() { logger.info("Generating public keys..."); publicKeys.forEach((publicKey, index) => { - console.log( + logger.info( `Generated public key ${index + 1}: ${publicKey.toString()}`, ); }); From 13d31d7655bc9a82841eff979248972b481f353d Mon Sep 17 00:00:00 2001 From: b-l-u-e Date: Wed, 16 Oct 2024 16:25:07 +0300 Subject: [PATCH 4/7] logger updated Signed-off-by: b-l-u-e --- examples/create-account-with-thresholdkey.js | 22 +++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/examples/create-account-with-thresholdkey.js b/examples/create-account-with-thresholdkey.js index 3493a2673..4978cf821 100644 --- a/examples/create-account-with-thresholdkey.js +++ b/examples/create-account-with-thresholdkey.js @@ -1,4 +1,3 @@ -/* eslint-disable n/no-extraneous-import */ import { Client, PrivateKey, @@ -9,28 +8,19 @@ import { AccountBalanceQuery, AccountDeleteTransaction, KeyList, + Logger, + LogLevel, } from "@hashgraph/sdk"; import dotenv from "dotenv"; -import pino from "pino"; -import pinoPretty from "pino-pretty"; dotenv.config(); // Set default log level to 'silent' if SDK_LOG_LEVEL is not specified in .env const SDK_LOG_LEVEL = process.env.SDK_LOG_LEVEL || "SILENT"; -// Logger configuration based on SDK_LOG_LEVEL -const logger = pino( - { - level: SDK_LOG_LEVEL.toUpperCase(), - }, - pinoPretty({ - colorize: true, - translateTime: "SYS:standard", - ignore: "pid,hostname", - }), -); +// Initialize Logger with the specified log level from the environment variable +const logger = new Logger(LogLevel._fromString(SDK_LOG_LEVEL)); /** * Step 0: Set up client connection to Hedera network @@ -55,6 +45,8 @@ async function main() { let client = Client.forName(process.env.HEDERA_NETWORK); client.setOperator(operatorId, operatorKey); + // Attach your custom logger to the SDK client + client.setLogger(logger); try { logger.info("Create Account With Threshold Key Example Start!"); @@ -151,7 +143,7 @@ async function main() { logger.info("Account deleted successfully"); } catch (error) { - logger.error("Error occurred during account creation:", error); + logger.error("Error occurred during account creation"); } finally { client.close(); logger.info("Create Account With Threshold Key Example Complete!"); From 8c7fd7f00cc4a6462634febab6f05240ad783e3e Mon Sep 17 00:00:00 2001 From: b-l-u-e Date: Wed, 16 Oct 2024 16:30:59 +0300 Subject: [PATCH 5/7] made some changes logger info to console log Signed-off-by: b-l-u-e --- examples/create-account-with-thresholdkey.js | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/create-account-with-thresholdkey.js b/examples/create-account-with-thresholdkey.js index 4978cf821..6a3532eea 100644 --- a/examples/create-account-with-thresholdkey.js +++ b/examples/create-account-with-thresholdkey.js @@ -32,7 +32,7 @@ async function main() { !process.env.OPERATOR_KEY || !process.env.HEDERA_NETWORK ) { - logger.error( + console.error( "Environment variables OPERATOR_ID, OPERATOR_KEY, and HEDERA_NETWORK are required.", ); throw new Error("Missing required environment variables."); @@ -49,7 +49,7 @@ async function main() { client.setLogger(logger); try { - logger.info("Create Account With Threshold Key Example Start!"); + console.log("Create Account With Threshold Key Example Start!"); /* * Step 1: @@ -65,9 +65,9 @@ async function main() { publicKeys.push(key.publicKey); } - logger.info("Generating public keys..."); + console.log("Generating public keys..."); publicKeys.forEach((publicKey, index) => { - logger.info( + console.log( `Generated public key ${index + 1}: ${publicKey.toString()}`, ); }); @@ -84,7 +84,7 @@ async function main() { * Step 3: * Create a new account setting a Key List from a previous step as an account's key. */ - logger.info("Creating new account..."); + console.log("Creating new account..."); const accountCreateTxResponse = await new AccountCreateTransaction() .setKey(thresholdKey) .setInitialBalance(new Hbar(100)) @@ -94,13 +94,13 @@ async function main() { await accountCreateTxResponse.getReceipt(client); const newAccountId = accountCreateTxReceipt.accountId; - logger.info(`Created account with ID: ${newAccountId.toString()}`); + console.log(`Created account with ID: ${newAccountId.toString()}`); /* * Step 4: * Create a transfer transaction from a newly created account to demonstrate the signing process (threshold). */ - logger.info("Transferring 1 Hbar from a newly created account..."); + console.log("Transferring 1 Hbar from a newly created account..."); let transferTx = new TransferTransaction() .addHbarTransfer(newAccountId, new Hbar(-50)) .addHbarTransfer(new AccountId(3), new Hbar(50)) @@ -121,7 +121,7 @@ async function main() { .setAccountId(newAccountId) .execute(client); - logger.info( + console.log( "New account's Hbar balance after transfer: " + accountBalanceAfterTransfer.hbars.toString(), ); @@ -141,12 +141,12 @@ async function main() { const accountDeleteTxResponse = await accountDeleteTx.execute(client); await accountDeleteTxResponse.getReceipt(client); - logger.info("Account deleted successfully"); + console.log("Account deleted successfully"); } catch (error) { - logger.error("Error occurred during account creation"); + console.error("Error occurred during account creation"); } finally { client.close(); - logger.info("Create Account With Threshold Key Example Complete!"); + console.log("Create Account With Threshold Key Example Complete!"); } } From 4806b5091dc5d1163eed9c174c102d7919e7977d Mon Sep 17 00:00:00 2001 From: b-l-u-e Date: Wed, 16 Oct 2024 16:39:29 +0300 Subject: [PATCH 6/7] updated client declaration from let to constant Signed-off-by: b-l-u-e --- examples/create-account-with-thresholdkey.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/create-account-with-thresholdkey.js b/examples/create-account-with-thresholdkey.js index 6a3532eea..a599468a9 100644 --- a/examples/create-account-with-thresholdkey.js +++ b/examples/create-account-with-thresholdkey.js @@ -42,7 +42,7 @@ async function main() { const operatorKey = PrivateKey.fromStringED25519(process.env.OPERATOR_KEY); // Create the client based on the HEDERA_NETWORK environment variable - let client = Client.forName(process.env.HEDERA_NETWORK); + const client = Client.forName(process.env.HEDERA_NETWORK); client.setOperator(operatorId, operatorKey); // Attach your custom logger to the SDK client From 740d567c718e13ebbe0e37d1d62a514d3c2f0426 Mon Sep 17 00:00:00 2001 From: b-l-u-e Date: Thu, 17 Oct 2024 08:49:01 +0300 Subject: [PATCH 7/7] updated logger Signed-off-by: b-l-u-e --- examples/create-account-with-thresholdkey.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/examples/create-account-with-thresholdkey.js b/examples/create-account-with-thresholdkey.js index a599468a9..ff918badf 100644 --- a/examples/create-account-with-thresholdkey.js +++ b/examples/create-account-with-thresholdkey.js @@ -16,12 +16,6 @@ import dotenv from "dotenv"; dotenv.config(); -// Set default log level to 'silent' if SDK_LOG_LEVEL is not specified in .env -const SDK_LOG_LEVEL = process.env.SDK_LOG_LEVEL || "SILENT"; - -// Initialize Logger with the specified log level from the environment variable -const logger = new Logger(LogLevel._fromString(SDK_LOG_LEVEL)); - /** * Step 0: Set up client connection to Hedera network */ @@ -45,8 +39,10 @@ async function main() { const client = Client.forName(process.env.HEDERA_NETWORK); client.setOperator(operatorId, operatorKey); - // Attach your custom logger to the SDK client - client.setLogger(logger); + + // Set logger + const infoLogger = new Logger(LogLevel.Info); + client.setLogger(infoLogger); try { console.log("Create Account With Threshold Key Example Start!");