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

Release/v2.22.0 #1492

Merged
merged 15 commits into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Default code owners for entire repository
* @danielakhterov @mehcode @SimiHunjan
* @SimiHunjan @ochikov @petreze
1,419 changes: 729 additions & 690 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/account-alias.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ async function main() {
);

/*
* Hedera supports a form of lazy account creation.
* 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
Expand Down
58 changes: 58 additions & 0 deletions examples/account-creation-ways.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { AccountId, PrivateKey } from "@hashgraph/sdk";

import dotenv from "dotenv";

dotenv.config();

function main() {
/* Source and context: https://hips.hedera.com/hip/hip-583

In hedera Hedera, we have the concept of 4 different account representations
- An account can have an account ID in shard.realm.accountNumber format (0.0.10)
- An account can have a public key alias in 0.0.CIQNOWUYAGBLCCVX2VF75U6JMQDTUDXBOLZ5VJRDEWXQEGTI64DVCGQ format
- An account can have an AccountId that is represented in 0x000000000000000000000000000000000000000a (for account ID 0.0.10) long zero format
- An account have be represented by an Ethereum public address 0xb794f5ea0ba39494ce839613fffba74279579268
*/

/*
Account ID - shard.realm.number format, i.e. `0.0.10` with the corresponding `0x000000000000000000000000000000000000000a` ethereum address
*/
const hederaFormat = AccountId.fromString("0.0.10");
console.log(`Account ID: ${hederaFormat.toString()}`);
console.log(
`Account 0.0.10 corresponding Long-Zero address: ${hederaFormat.toSolidityAddress()}`
);

/*
Hedera Long-Form Account ID - 0.0.aliasPublicKey, i.e. `0.0.CIQNOWUYAGBLCCVX2VF75U6JMQDTUDXBOLZ5VJRDEWXQEGTI64DVCGQ`
*/
const privateKey = PrivateKey.generateECDSA();
const publicKey = privateKey.publicKey;

// Assuming that the target shard and realm are known.
// For now they are virtually always 0 and 0.
const aliasAccountId = publicKey.toAccountId(0, 0);
console.log(`Hedera Long-Form Account ID: ${aliasAccountId.toString()}`);

/*
Hedera Account Long-Zero address - 0x000000000000000000000000000000000000000a (for accountId 0.0.10)
*/
const longZeroAddress = AccountId.fromString(
"0x000000000000000000000000000000000000000a"
);
console.log(
`Hedera Account Long-Zero address: ${longZeroAddress.toString()}`
);

/*
Ethereum Account Address / public-address - 0xb794f5ea0ba39494ce839613fffba74279579268
*/
const evmAddress = AccountId.fromString(
"0xb794f5ea0ba39494ce839613fffba74279579268"
);
console.log(
`Ethereum Account Address / public-address: ${evmAddress.toString()}`
);
}

void main();
3 changes: 1 addition & 2 deletions examples/create-stateful-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,7 @@ async function main() {
.setGas(75000)
// Set the function to call on the contract
.setFunction("get_message")
// Set the query payment explicitly since sometimes automatic payment calculated
// is too low
// Set query payment explicitly
.setQueryPayment(new Hbar(3))
.executeWithSigner(wallet);

Expand Down
2 changes: 1 addition & 1 deletion examples/get-address-book.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ async function main() {

if (process.env.HEDERA_NETWORK.toLowerCase() === "mainnet") {
client
.setMirrorNetwork(["mainnet-public.mirrornode.hedera.com:5600"])
.setMirrorNetwork(["mainnet-public.mirrornode.hedera.com:443"])
.setTransportSecurity(true);
}

Expand Down
186 changes: 186 additions & 0 deletions examples/lazy-create-transfer-tx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import {
AccountId,
PrivateKey,
Client,
TransferTransaction,
AccountInfoQuery,
TransactionReceiptQuery,
TopicCreateTransaction,
} from "@hashgraph/sdk";

import dotenv from "dotenv";

dotenv.config();

/*
Lazy-create a new account using a public-address via a `TransferTransaction`.

Reference: [HIP-583 Expand alias support in CryptoCreate & CryptoTransfer Transactions](https://hips.hedera.com/hip/hip-583)

## Example 2
- Create an ECSDA private key
- Extract the ECDSA public key
- Extract the Ethereum public address
- Add function to calculate the Ethereum Address to in SDK
- Ethereum account address / public-address - This is the rightmost 20 bytes of the 32 byte Keccak-256 hash of the ECDSA public key of the account. This calculation is in the manner described by the Ethereum Yellow Paper.
- Use the `TransferTransaction`
- Populate the `FromAddress` with the sender Hedera AccountID
- Populate the `ToAddress` with Ethereum public address
- Note: Can transfer from public address to public address in the `TransferTransaction` for complete accounts. Transfers from hollow accounts will not work because the hollow account does not have a public key assigned to authorize transfers out of the account
- Sign the `TransferTransaction` transaction using an existing Hedera account and key paying for the transaction fee
- The `AccountCreateTransaction` is executed as a child transaction triggered by the `TransferTransaction`
- The Hedera Account that was created has a public address the user specified in the TransferTransaction ToAddress
- Will not have a public key at this stage
- Cannot do anything besides receive tokens or hbars
- The alias property of the account does not have the public address
- Referred to as a hollow account
- To get the new account ID ask for the child receipts or child records for the parent transaction ID of the `TransferTransaction`
- Get the `AccountInfo` and verify the account is a hollow account with the supplied public address (may need to verify with mirror node API)
- To enhance the hollow account to have a public key the hollow account needs to be specified as a transaction fee payer in a HAPI transaction
- Create a HAPI transaction and assign the new hollow account as the transaction fee payer
- Sign with the private key that corresponds to the public key on the hollow account
- Get the `AccountInfo` for the account and return the public key on the account to show it is a complete account
*/

async function main() {
if (process.env.OPERATOR_ID == null || process.env.OPERATOR_KEY == null) {
throw new Error(
"Environment variables OPERATOR_ID, and OPERATOR_KEY are required."
);
}
const operatorId = AccountId.fromString(process.env.OPERATOR_ID);
const operatorKey = PrivateKey.fromString(process.env.OPERATOR_KEY);

const client = Client.forTestnet().setOperator(operatorId, operatorKey);

/**
* Step 1
*
* Create an ECSDA private key
*/
const privateKey = PrivateKey.generateECDSA();
console.log(`Private key: ${privateKey.toStringDer()}`);

/**
* Step 2
*
* Extract the ECDSA public key
*/
const publicKey = privateKey.publicKey;
console.log(`Public key: ${publicKey.toStringDer()}`);

/**
*
* Step 3
*
* Extract the Ethereum public address
*/
const evmAddress = publicKey.toEvmAddress();
console.log(`New account ID: ${evmAddress}`);

/**
*
* Step 4
*
* Use the `TransferTransaction`
* - Populate the `FromAddress` with the sender Hedera AccountID
* - Populate the `ToAddress` with Ethereum public address
*/
const transferTx = new TransferTransaction()
.addHbarTransfer(operatorId, -10)
.addHbarTransfer(evmAddress, 10)
.freezeWith(client);

/**
*
* Step 5
*
* Sign the `TransferTransaction` transaction using an existing Hedera account and key paying for the transaction fee
*/
const transferTxSign = await transferTx.sign(operatorKey);
const transferTxSubmit = await transferTxSign.execute(client);

/**
*
* Step 6
*
* To get the new account ID ask for the child receipts or child records for the parent transaction ID of the `TransferTransaction`
* - The `AccountCreateTransaction` is executed as a child transaction triggered by the `TransferTransaction`
*/
const receipt = await new TransactionReceiptQuery()
.setTransactionId(transferTxSubmit.transactionId)
.setIncludeChildren(true)
.execute(client);

const newAccountId = receipt.children[0].accountId.toString();
console.log(`Account ID of the newly created account: ${newAccountId}`);

/**
*
* Step 7
*
* Get the `AccountInfo` and verify the account is a hollow account with the supplied public address
*
* The Hedera Account that was created has a public address the user specified in the TransferTransaction ToAddress
- Will not have a public key at this stage
- Cannot do anything besides receive tokens or hbars
- The alias property of the account does not have the public address
- Referred to as a hollow account
*/
const hollowAccountInfo = await new AccountInfoQuery()
.setAccountId(newAccountId)
.execute(client);

console.log(`Check if it is a hollow account with 'AccountInfoQuery'`);
hollowAccountInfo.aliasKey === null &&
hollowAccountInfo.key._toProtobufKey().keyList.keys.length == 0 &&
hollowAccountInfo.contractAccountId !== null
? console.log(`The newly created account is a hollow account`)
: console.log(`Not a hollow account`);

/**
*
* Step 8
*
* Create a HAPI transaction and assign the new hollow account as the transaction fee payer
* - To enhance the hollow account to have a public key the hollow account needs to be specified as a transaction fee payer in a HAPI transaction
*/

// set the accound id of the hollow account and its private key as an operator
// in order to be a transaction fee payer in a HAPI transaction
client.setOperator(newAccountId, privateKey);

let transaction = new TopicCreateTransaction()
.setTopicMemo("HIP-583")
.freezeWith(client);

/**
*
* Step 9
*
* Sign with the private key that corresponds to the public key on the hollow account
*/
const transactionSign = await transaction.sign(privateKey);
const transactionSubmit = await transactionSign.execute(client);
const status = (
await transactionSubmit.getReceipt(client)
).status.toString();
console.log(`HAPI transaction status: ${status}`);

/**
*
* Step 10
*
* Get the `AccountInfo` for the account and return the public key on the account to show it is a complete account
*/
const completeAccountInfo = await new AccountInfoQuery()
.setAccountId(newAccountId)
.execute(client);
completeAccountInfo.key !== null
? console.log(
`The public key of the newly created and now complete account: ${completeAccountInfo.key.toString()}`
)
: console.log(`Account ${newAccountId} is still a hollow account`);
}

void main();
Loading