UNPKG

@hashgraph/hedera-identify-snap

Version:

A snap for managing Decentralized Identifiers(DIDs)

160 lines (133 loc) 4.7 kB
/*- * * Hedera Identify Snap * * Copyright (C) 2024 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. * */ import { Client, Hbar, PrivateKey, Status, StatusError, TransferTransaction, } from '@hashgraph/sdk'; import type { Wallet } from '../domain/wallet/abstract'; import { PrivateKeySoftwareWallet } from '../domain/wallet/software-private-key'; import type { HederaClientFactory } from '../interfaces/HederaClientFactory'; import { SimpleHederaClientImpl } from './SimpleHederaClientImpl'; /** * To HederaAccountInfo. * @param _curve - Curve that was used to derive the keys('ECDSA_SECP256K1' | 'ED25519'). * @param _privateKey - Private Key. * @param _accountId - Account Id. * @param _network - Network. */ export class HederaClientImplFactory implements HederaClientFactory { readonly #wallet: Wallet | null; readonly #keyIndex: number; readonly #accountId: string; readonly #network: string; readonly #curve: string; readonly #privateKey: string; constructor( accountId: string, network: string, curve: string, privateKey: string, keyIndex = 0, // note that 0 is default here for the first key in a HD wallet ) { this.#keyIndex = keyIndex; this.#accountId = accountId; this.#network = network; this.#curve = curve; this.#privateKey = privateKey; this.#wallet = this.walletFromPrivateKeyString(); } walletFromPrivateKeyString(): Wallet | null { let myPrivateKey: PrivateKey; if (this.#curve === 'Secp256k1') { myPrivateKey = PrivateKey.fromStringECDSA(this.#privateKey); } else if (this.#curve === 'Ed25519') { myPrivateKey = PrivateKey.fromStringED25519(this.#privateKey); } else { console.error('Invalid curve type'); return null; } return new PrivateKeySoftwareWallet(myPrivateKey); } public async createClient(): Promise<SimpleHederaClientImpl | null> { if (this.#wallet === null) { return null; } let client: Client; if (this.#network === 'testnet') { client = Client.forTestnet(); } else if (this.#network === 'previewnet') { client = Client.forPreviewnet(); } else { client = Client.forMainnet(); } client.setNetworkUpdatePeriod(2000); const transactionSigner = await this.#wallet.getTransactionSigner( this.#keyIndex, ); const privateKey = await this.#wallet.getPrivateKey(this.#keyIndex); const publicKey = await this.#wallet.getPublicKey(this.#keyIndex); if (publicKey === null) { return null; } // TODO: Fix client.setOperatorWith(this.#accountId, publicKey ?? '', transactionSigner); if (!(await this.testClientOperatorMatch(client))) { return null; } return new SimpleHederaClientImpl(client, privateKey); } /** * Does the operator key belong to the operator account. * @param client - Hedera Client. * @returns True if the operator key belongs to the operator account. */ async testClientOperatorMatch(client: Client) { const tx = new TransferTransaction() /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */ .addHbarTransfer(client.operatorAccountId!, Hbar.fromTinybars(0)) .setMaxTransactionFee(Hbar.fromTinybars(1)); try { await tx.execute(client); } catch (error: any) { if (error instanceof StatusError) { // If the transaction fails with Insufficient Tx Fee, this means // that the account ID verification succeeded before this point // Same for Insufficient Payer Balance return ( error.status === Status.InsufficientTxFee || error.status === Status.InsufficientPayerBalance ); } const errMessage = 'The account id does not belong to the associated private key'; console.log(errMessage, String(error)); throw new Error(errMessage); } // under *no* cirumstances should this transaction succeed const errMessage = 'Unexpected success of intentionally-erroneous transaction to confirm account ID'; console.log(errMessage); throw new Error(errMessage); } }