Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: improve examples #1935

Merged
merged 35 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
96f276d
chore: update examples (added `Client#close`)
thenswan Aug 5, 2024
6b6fb63
chore: update examples (optimize exception handling)
thenswan Aug 5, 2024
d618e1c
chore: update examples (optimize num values readability)
thenswan Aug 5, 2024
2576d72
chore: update examples (improve clean up section)
thenswan Aug 6, 2024
e9609b8
Merge branch 'refs/heads/main' into 01631-improve-java-examples
thenswan Aug 7, 2024
6c6e7e6
fix: ExemptCustomFeesExample
thenswan Aug 7, 2024
ca14652
fix: ExemptCustomFeesExample
thenswan Aug 7, 2024
c3d41f0
chore: updated structure in example resources folder
thenswan Aug 7, 2024
ab82dff
chore: update example resources
thenswan Aug 7, 2024
367aad4
chore: update example (pass private keys as a parameter only if needed)
thenswan Aug 7, 2024
184b553
chore: update example (align by a template)
thenswan Aug 9, 2024
6b656b5
chore: update ConsensusPubSubWithSubmitKeyExample example (increase l…
thenswan Aug 11, 2024
e865a7e
chore: update examples (align the approach for handling null values)
thenswan Aug 11, 2024
df1f03e
revert: gradle.properties
thenswan Aug 11, 2024
f7f8ebe
chore: update examples (update error handling)
thenswan Aug 12, 2024
5ad4476
chore: update examples (implement logging)
thenswan Aug 13, 2024
1e00710
fix: ConsensusPubSubWithSubmitKeyExample
thenswan Aug 13, 2024
5045e36
chore: examples (align logging/printing approach)
thenswan Aug 14, 2024
40aace4
docs: update examples README.md
thenswan Aug 15, 2024
baee41b
chore: align examples documentation
thenswan Aug 15, 2024
3644837
chore: optimize wait time in examples
thenswan Aug 16, 2024
0dd72d2
chore: optimize tokens and gas spendings in examples
thenswan Aug 16, 2024
b06f702
chore: remove errorprone from examples
thenswan Aug 16, 2024
1c4c847
chore: revisit variable names in examples
thenswan Aug 16, 2024
edda3f6
chore: revisit Hedera objects memos, names, etc. in examples
thenswan Aug 16, 2024
38ae862
chore: revisited structure in example resources folder
thenswan Aug 16, 2024
cc75d44
chore: add contracts which used in examples to the resources folder
thenswan Aug 16, 2024
04be75d
chore: additional handling of null values in examples
thenswan Aug 20, 2024
3d8add9
chore: update from main
0xivanov Sep 9, 2024
eb19467
chore: fix TODOs
0xivanov Sep 9, 2024
e172a84
chore: fix solidity example
0xivanov Sep 9, 2024
595afaf
chore: refactor resources folder
0xivanov Sep 9, 2024
c543836
chore: revert gradle.kts changes
0xivanov Sep 9, 2024
5e9c585
chore: update from main
0xivanov Sep 9, 2024
3cae803
chore: fix typo
0xivanov Sep 9, 2024
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
2 changes: 2 additions & 0 deletions examples/.env.sample
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
OPERATOR_KEY="<PRIVATE_KEY>"
OPERATOR_ID="<ACCOUNT_ID>"
HEDERA_NETWORK="<localhost|testnet|previewnet|mainnet>"
SDK_LOG_LEVEL="<TRACE|DEBUG|INFO|WARN|ERROR|SILENT>"
19 changes: 15 additions & 4 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,22 +75,33 @@
## Usage

### Configuration
Running the examples requires `.env` file to exist in the [`examples`](.) folder:
Running the examples requires `.env` file to exist in the [`examples`](.) folder if running with Gradle:

```sh
cp .env.sample .env
```
And in the root project folder if running with Intellij IDEA:
```sh
cp .env.sample ../.env
```

The `OPERATOR_ID` and `OPERATOR_KEY` variables should be set in a `.env` file.
Optionally, you can set the `HEDERA_NETWORK` variable to `testnet`, `previewnet`, or `mainnet`
for configuring the network. If the `HEDERA_NETWORK` is not set, it will default to `testnet`.\
Optionally, you can set the `HEDERA_NETWORK` and `SDK_LOG_LEVEL` variables:
- You can set the `HEDERA_NETWORK` to `localhost`, `testnet`, `previewnet` or `mainnet`
for configuring the network. If the `HEDERA_NETWORK` is not set, it will default to `testnet`.
- You can set the `SDK_LOG_LEVEL` to `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR` or `SILENT`
for configuring the logging. If the `SDK_LOG_LEVEL` is not set, it will default to `SILENT`.
Important pre-requisite to see logs: set simple logger log level to same level as the `SDK_LOG_LEVEL`,
for example via VM options: `-Dorg.slf4j.simpleLogger.log.com.hedera.hashgraph=trace`.

Therefore, the format of the configuration file should be as follows:

```.properties
OPERATOR_ID=0.0.102...
OPERATOR_KEY=0xeae...
# Optionally set HEDERA_NETWORK
# Optionally set HEDERA_NETWORK and SDK_LOG_LEVEL
HEDERA_NETWORK=previewnet
SDK_LOG_LEVEL=WARN
```

### Running with Gradle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,126 +19,173 @@
*/
package com.hedera.hashgraph.sdk.examples;

import com.hedera.hashgraph.sdk.AccountBalance;
import com.hedera.hashgraph.sdk.AccountBalanceQuery;
import com.hedera.hashgraph.sdk.AccountId;
import com.hedera.hashgraph.sdk.AccountInfo;
import com.hedera.hashgraph.sdk.AccountInfoQuery;
import com.hedera.hashgraph.sdk.Client;
import com.hedera.hashgraph.sdk.Hbar;
import com.hedera.hashgraph.sdk.PrecheckStatusException;
import com.hedera.hashgraph.sdk.PrivateKey;
import com.hedera.hashgraph.sdk.PublicKey;
import com.hedera.hashgraph.sdk.ReceiptStatusException;
import com.hedera.hashgraph.sdk.TransferTransaction;
import com.hedera.hashgraph.sdk.*;
import com.hedera.hashgraph.sdk.logger.LogLevel;
import com.hedera.hashgraph.sdk.logger.Logger;
import io.github.cdimascio.dotenv.Dotenv;

import java.util.Objects;
import java.util.concurrent.TimeoutException;

public class AccountAliasExample {
/**
* How to use auto account creation (HIP-32).
* <p>
* You can "create" an account by generating a private key, and then deriving the public key,
* without any need to interact with the Hedera network. The public key more or less acts as the user's
* account ID. This public key is an account's aliasKey: a public key that aliases (or will eventually alias)
* to a Hedera account.
* <p>
* An AccountId takes one of two forms: a normal AccountId with a null aliasKey member takes the form 0.0.123,
* while an account ID with a non-null aliasKey member takes the form
* 0.0.302a300506032b6570032100114e6abc371b82dab5c15ea149f02d34a012087b163516dd70f44acafabf7777
* Note the prefix of "0.0." indicating the shard and realm. Also note that the aliasKey is stringified
* as a hex-encoded ASN1 DER representation of the key.
* <p>
* An AccountId with an aliasKey can be used just like a normal AccountId for the purposes of queries and
* transactions, however most queries and transactions involving such an AccountId won't work until Hbar has
* been transferred to the aliasKey account.
* <p>
* There is no record in the Hedera network of an account associated with a given aliasKey
* until an amount of Hbar is transferred to the account. The moment that Hbar is transferred to that aliasKey
* AccountId is the moment that that account actually begins to exist in the Hedera ledger.
*/
class AccountAliasExample {

/*
* See .env.sample in the examples folder root for how to specify values below
* or set environment variables with the same names.
*/

// see `.env.sample` in the repository root for how to specify these values
// or set environment variables with the same names
/**
* Operator's account ID.
* Used to sign and pay for operations on Hedera.
*/
private static final AccountId OPERATOR_ID = AccountId.fromString(Objects.requireNonNull(Dotenv.load().get("OPERATOR_ID")));

/**
* Operator's private key.
*/
private static final PrivateKey OPERATOR_KEY = PrivateKey.fromString(Objects.requireNonNull(Dotenv.load().get("OPERATOR_KEY")));
// HEDERA_NETWORK defaults to testnet if not specified in dotenv

/**
* HEDERA_NETWORK defaults to testnet if not specified in dotenv file.
* Network can be: localhost, testnet, previewnet or mainnet.
*/
private static final String HEDERA_NETWORK = Dotenv.load().get("HEDERA_NETWORK", "testnet");

public static void main(String[] args)
throws TimeoutException, PrecheckStatusException, ReceiptStatusException, InterruptedException {
Client client = ClientHelper.forName(HEDERA_NETWORK);
/**
* SDK_LOG_LEVEL defaults to SILENT if not specified in dotenv file.
* Log levels can be: TRACE, DEBUG, INFO, WARN, ERROR, SILENT.
* <p>
* Important pre-requisite: set simple logger log level to same level as the SDK_LOG_LEVEL,
* for example via VM options: -Dorg.slf4j.simpleLogger.log.com.hedera.hashgraph=trace
*/
private static final String SDK_LOG_LEVEL = Dotenv.load().get("SDK_LOG_LEVEL", "SILENT");

// Defaults the operator account ID and key such that all generated transactions will be paid for
// by this account and be signed by this key
client.setOperator(OPERATOR_ID, OPERATOR_KEY);
public static void main(String[] args) throws Exception {
System.out.println("Account Alias Example (HIP-32) Start!");

/*
* Hedera supports a form of auto account creation.
*
* You can "create" an account by generating a private key, and then deriving the public key,
* without any need to interact with the Hedera network. The public key more or less acts as the user's
* account ID. This public key is an account's aliasKey: a public key that aliases (or will eventually alias)
* to a Hedera account.
*
* An AccountId takes one of two forms: a normal AccountId with a null aliasKey member takes the form 0.0.123,
* while an account ID with a non-null aliasKey member takes the form
* 0.0.302a300506032b6570032100114e6abc371b82dab5c15ea149f02d34a012087b163516dd70f44acafabf7777
* Note the prefix of "0.0." indicating the shard and realm. Also note that the aliasKey is stringified
* as a hex-encoded ASN1 DER representation of the key.
*
* An AccountId with an aliasKey can be used just like a normal AccountId for the purposes of queries and
* transactions, however most queries and transactions involving such an AccountId won't work until Hbar has
* been transferred to the aliasKey account.
*
* There is no record in the Hedera network of an account associated with a given aliasKey
* until an amount of Hbar is transferred to the account. The moment that Hbar is transferred to that aliasKey
* AccountId is the moment that that account actually begins to exist in the Hedera ledger.
* Step 0:
* Create and configure the SDK Client.
*/
Client client = ClientHelper.forName(HEDERA_NETWORK);
// All generated transactions will be paid by this account and signed by this key.
client.setOperator(OPERATOR_ID, OPERATOR_KEY);
// Attach logger to the SDK Client.
client.setLogger(new Logger(LogLevel.valueOf(SDK_LOG_LEVEL)));

System.out.println("\"Creating\" a new account");

/*
* Step 1:
* Generate ED25519 key pair.
*/
System.out.println("Generating ED25519 key pair...");
PrivateKey privateKey = PrivateKey.generateED25519();
PublicKey publicKey = privateKey.getPublicKey();

// Assuming that the target shard and realm are known.
// For now they are virtually always 0 and 0.
AccountId aliasAccountId = publicKey.toAccountId(0, 0);

System.out.println("New account ID: " + aliasAccountId);
System.out.println("Just the aliasKey: " + aliasAccountId.aliasKey);

/*
* Step 2:
* Create a couple of example Account Ids.
*
* Note that no queries or transactions have taken place yet.
* This account "creation" process is entirely local.
*
* AccountId.fromString() can construct an AccountId with an aliasKey.
* It expects a string of the form 0.0.123 in the case of a normal AccountId, or of the form
* 0.0.302a300506032b6570032100114e6abc371b82dab5c15ea149f02d34a012087b163516dd70f44acafabf7777
* in the case of an AccountId with aliasKey. Note the prefix of "0.0." to indicate the shard and realm.
* in the case of an AccountId with aliasKey. Note the prefix of '0.0.' to indicate the shard and realm.
*
* If the shard and realm are known, you may use PublicKey.fromString().toAccountId() to construct the
* aliasKey AccountId
* aliasKey AccountId.
*/
System.out.println("\"Creating\" new account...");

AccountId fromString = AccountId.fromString("0.0.302a300506032b6570032100114e6abc371b82dab5c15ea149f02d34a012087b163516dd70f44acafabf7777");
// Assuming that the target shard and realm are known.
// For now, they are virtually always 0 and 0.
AccountId aliasAccountId = publicKey.toAccountId(0, 0);

AccountId fromKeyString = PublicKey
System.out.println("New account ID: " + aliasAccountId);
System.out.println("Just the aliasKey: " + aliasAccountId.aliasKey);

AccountId fromStringExample = AccountId.fromString("0.0.302a300506032b6570032100114e6abc371b82dab5c15ea149f02d34a012087b163516dd70f44acafabf7777");

AccountId fromKeyStringExample = PublicKey
.fromString("302a300506032b6570032100114e6abc371b82dab5c15ea149f02d34a012087b163516dd70f44acafabf7777")
.toAccountId(0, 0);


System.out.println("Transferring some Hbar to the new account");
/*
* Step 3:
* Transfer Hbar to the new account.
*
* Transfer will actually create an actual Hedera account,
* deducting the creation fee from the amount transferred.
*/
System.out.println("Transferring Hbar to the new account...");
new TransferTransaction()
.addHbarTransfer(OPERATOR_ID, new Hbar(10).negated())
.addHbarTransfer(aliasAccountId, new Hbar(10))
.addHbarTransfer(OPERATOR_ID, Hbar.from(1).negated())
.addHbarTransfer(aliasAccountId, Hbar.from(1))
.execute(client)
.getReceipt(client);

AccountBalance balance = new AccountBalanceQuery()
/*
* Step 4:
* Query and output info about the new account.
*
* Note that once an account exists in the ledger, it is assigned a normal AccountId, which can be retrieved
* via an AccountInfoQuery.
*
* Users may continue to refer to the account by its aliasKey AccountId, but they may also
* now refer to it by its normal AccountId
*/
AccountBalance newAccountBalance = new AccountBalanceQuery()
.setAccountId(aliasAccountId)
.execute(client);

System.out.println("Balances of the new account: " + balance);
System.out.println("Balances of the new account: " + newAccountBalance);

AccountInfo info = new AccountInfoQuery()
AccountInfo newAccountInfo = new AccountInfoQuery()
.setAccountId(aliasAccountId)
.execute(client);

System.out.println("Info about the new account: " + info);
Objects.requireNonNull(newAccountInfo.accountId);

System.out.println("Info about the new account: " + newAccountInfo);
System.out.println("The normal account ID: " + newAccountInfo.accountId);
System.out.println("The alias key: " + newAccountInfo.aliasKey);

/*
* Note that once an account exists in the ledger, it is assigned a normal AccountId, which can be retrieved
* via an AccountInfoQuery.
*
* Users may continue to refer to the account by its aliasKey AccountId, but they may also
* now refer to it by its normal AccountId
* Clean up:
* Delete created account and close the client.
*/
new AccountDeleteTransaction()
.setAccountId(newAccountInfo.accountId)
.setTransferAccountId(OPERATOR_ID)
.freezeWith(client)
.sign(privateKey)
.execute(client)
.getReceipt(client);

System.out.println("The normal account ID: " + info.accountId);
System.out.println("The alias key: " + info.aliasKey);

System.out.println("Example complete!");
client.close();

System.out.println("Account Alias Example (HIP-32) Complete!");
}
}
Loading
Loading