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

feat: added alias utils for parsing from/to public address #2066

Merged
merged 5 commits into from
Jan 2, 2024
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/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ jobs:
id: start-local-node
if: ${{ steps.build-sdk.conclusion == 'success' && !cancelled() && always() }}
run: |
npx @hashgraph/hedera-local start -d --network local
npx @hashgraph/hedera-local start -d --network local --balance=100000
# Wait for the network to fully start
sleep 30

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@
"pino": "^8.14.1",
"pino-pretty": "^10.0.0",
"protobufjs": "^7.2.5",
"utf8": "^3.0.0"
"utf8": "^3.0.0",
"rfc4648": "^1.5.3"
},
"devDependencies": {
"@babel/cli": "^7.23.4",
Expand Down
7 changes: 7 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

136 changes: 136 additions & 0 deletions src/EntityIdHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
import * as hex from "./encoding/hex.js";
import BadEntityIdError from "./BadEntityIdError.js";
import * as util from "./util.js";
import base32 from "./base32.js";
import * as HashgraphProto from "@hashgraph/proto";
import PublicKey from "./PublicKey.js";
import { arrayify } from "@ethersproject/bytes";

/**
* @typedef {import("./client/Client.js").default<*, *>} Client
Expand Down Expand Up @@ -408,3 +412,135 @@

return `${string}-${checksum}`;
}

/**
* Append Buffers.
* @param {Uint8Array} buffer1
* @param {Uint8Array} buffer2
* @returns {Uint8Array}
*/
function appendBuffer(buffer1, buffer2) {
var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
tmp.set(new Uint8Array(buffer1), 0);
tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
return tmp;
}

/**
* Convert bytes to hex string.
* @param {Uint8Array} bytes
* @returns {string}
*/
function toHexString(bytes) {
var s = "0x";
bytes.forEach(function (byte) {
s += ("0" + (byte & 0xff).toString(16)).slice(-2);
});
return s;
}

/**
* Deserialize the alias to public key.
* Alias is created from ed25519 or ECDSASecp256k1 types of accounts. If hollow account is used, the alias is created from evm address.
* For hollow accounts, please use aliasToEvmAddress.
*
* @param {string} alias
* @returns {PublicKey | null}
*/
export function aliasToPublicKey(alias) {
const bytes = base32.decode(alias);
if (!bytes) {
return null;
}

Check warning on line 454 in src/EntityIdHelper.js

View check run for this annotation

Codecov / codecov/patch

src/EntityIdHelper.js#L453-L454

Added lines #L453 - L454 were not covered by tests
let key;
try {
key = HashgraphProto.proto.Key.decode(bytes);
} catch (e) {
throw new Error(
"The alias is created with hollow account. Please use aliasToEvmAddress!",
);
}

if (key.ed25519 != null && key.ed25519.byteLength > 0) {
return PublicKey.fromBytes(key.ed25519);
}

if (key.ECDSASecp256k1 != null && key.ECDSASecp256k1.byteLength > 0) {
return PublicKey.fromBytes(key.ECDSASecp256k1);
}

return null;

Check warning on line 472 in src/EntityIdHelper.js

View check run for this annotation

Codecov / codecov/patch

src/EntityIdHelper.js#L471-L472

Added lines #L471 - L472 were not covered by tests
}

/**
* Deserialize the alias to evm address.
* Alias is created from hollow account.
* For ed25519 or ECDSASecp256k1 accounts, please use aliasToPublicKey.
*
* @param {string} alias
* @returns {string | null}
*/
export function aliasToEvmAddress(alias) {
const bytes = base32.decode(alias);
if (!bytes) {
return null;
}

Check warning on line 487 in src/EntityIdHelper.js

View check run for this annotation

Codecov / codecov/patch

src/EntityIdHelper.js#L486-L487

Added lines #L486 - L487 were not covered by tests
try {
HashgraphProto.proto.Key.decode(bytes);
throw new Error(
"The alias is created with ed25519 or ECDSASecp256k1 account. Please use aliasToPublicKey!",
);
} catch (e) {
return toHexString(bytes);
}
}

/**
* Serialize the public key to alias.
* Alias is created from ed25519 or ECDSASecp256k1 types of accounts. If hollow account is used, the alias is created from evm address.
*
* @param {string | PublicKey} publicKey
* @returns {string | null}
*/
export function publicKeyToAlias(publicKey) {
if (
typeof publicKey === "string" &&
((publicKey.startsWith("0x") && publicKey.length == 42) ||
publicKey.length == 40)
) {
if (!publicKey.startsWith("0x")) {
publicKey = `0x${publicKey}`;
}

Check warning on line 513 in src/EntityIdHelper.js

View check run for this annotation

Codecov / codecov/patch

src/EntityIdHelper.js#L512-L513

Added lines #L512 - L513 were not covered by tests

const bytes = arrayify(publicKey);
if (!bytes) {
return null;
}

Check warning on line 518 in src/EntityIdHelper.js

View check run for this annotation

Codecov / codecov/patch

src/EntityIdHelper.js#L517-L518

Added lines #L517 - L518 were not covered by tests
return base32.encode(bytes);
}

const publicKeyRaw =
typeof publicKey === "string"
? PublicKey.fromString(publicKey)
: publicKey;
let publicKeyHex = publicKeyRaw.toStringRaw();
let leadingHex = "";

if (publicKeyRaw._key._type === "secp256k1") {
leadingHex = "0x3A21"; // LEADING BYTES FROM PROTOBUFS
}

if (publicKeyRaw._key._type === "ED25519") {
leadingHex = "0x1220"; // LEADING BYTES FROM PROTOBUFS
}

if (!publicKeyHex.startsWith("0x")) {
publicKeyHex = `0x${publicKeyHex}`;
}

const leadingBytes = arrayify(leadingHex);
const publicKeyBytes = arrayify(publicKeyHex);
const publicKeyInBytes = appendBuffer(leadingBytes, publicKeyBytes);
const alias = base32.encode(publicKeyInBytes);
return alias;
}
43 changes: 43 additions & 0 deletions src/base32.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2019-2023 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// HIP-32: https://hips.hedera.com/hip/hip-32
import { base32 } from "rfc4648";

const decodeOpts = { loose: true };
const encodeOpts = { pad: false };

/**
* Decodes the rfc4648 base32 string into a {@link Uint8Array}. If the input string is null, returns null.
* @param {string} str the base32 string.
* @returns {Uint8Array | ''}
*/
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
const decode = (str) => str && base32.parse(str, decodeOpts);

/**
* Encodes the byte array into a rfc4648 base32 string without padding. If the input is null, returns null. Note with
* the rfc4648 loose = true option, it allows lower case letters, padding, and auto corrects 0 -> O, 1 -> L, 8 -> B
* @param {Buffer|Uint8Array} data
* @returns {string}
*/
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
const encode = (data) => data && base32.stringify(data, encodeOpts);

export default {
decode,
encode,
};
2 changes: 1 addition & 1 deletion test/integration/ContractBytecodeIntegrationTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe("ContractBytecode", function () {
receipt = await (
await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down
8 changes: 4 additions & 4 deletions test/integration/ContractCallIntegrationTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe("ContractCallIntegration", function () {
receipt = await (
await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down Expand Up @@ -131,7 +131,7 @@ describe("ContractCallIntegration", function () {
receipt = await (
await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down Expand Up @@ -200,7 +200,7 @@ describe("ContractCallIntegration", function () {
receipt = await (
await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down Expand Up @@ -268,7 +268,7 @@ describe("ContractCallIntegration", function () {
receipt = await (
await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down
2 changes: 1 addition & 1 deletion test/integration/ContractCreateFlowIntegrationTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe("ContractCreateFlow", function () {
await new ContractCreateFlow()
.setBytecode(smartContractBytecode)
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down
4 changes: 2 additions & 2 deletions test/integration/ContractCreateIntegrationTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe("ContractCreate", function () {

response = await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down Expand Up @@ -109,7 +109,7 @@ describe("ContractCreate", function () {
const file = receipt.fileId;

response = await new ContractCreateTransaction()
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down
4 changes: 2 additions & 2 deletions test/integration/ContractDeleteIntegrationTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe("ContractDelete", function () {

response = await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down Expand Up @@ -110,7 +110,7 @@ describe("ContractDelete", function () {

response = await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down
10 changes: 5 additions & 5 deletions test/integration/ContractExecuteIntegrationTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe("ContractExecute", function () {

response = await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down Expand Up @@ -101,7 +101,7 @@ describe("ContractExecute", function () {

response = await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down Expand Up @@ -175,7 +175,7 @@ describe("ContractExecute", function () {

response = await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down Expand Up @@ -244,7 +244,7 @@ describe("ContractExecute", function () {

response = await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down Expand Up @@ -318,7 +318,7 @@ describe("ContractExecute", function () {

response = await new ContractCreateTransaction()
.setAdminKey(operatorKey)
.setGas(100000)
.setGas(200000)
.setConstructorParameters(
new ContractFunctionParameters().addString(
"Hello from Hedera.",
Expand Down
4 changes: 2 additions & 2 deletions test/integration/ContractFunctionParametersIntegrationTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ describe("ContractFunctionParameters", function () {
let newContractId;

before(async function () {
env = await IntegrationTestEnv.new({ balance: 100000 });
env = await IntegrationTestEnv.new({ balance: 10000 });
// Create a file on Hedera and store the bytecode
const fileCreateTx = new FileCreateTransaction()
.setKeys([env.operatorKey])
Expand Down Expand Up @@ -152,7 +152,7 @@ describe("ContractFunctionParameters", function () {
//Set the file ID of the Hedera file storing the bytecode
.setBytecodeFileId(bytecodeFileId)
//Set the gas to instantiate the contract
.setGas(100000)
.setGas(500000)
//Provide the constructor parameters for the contract
.setConstructorParameters();

Expand Down
Loading
Loading