Skip to content

Commit

Permalink
Add accounts folder
Browse files Browse the repository at this point in the history
  • Loading branch information
danielailie committed Nov 14, 2024
1 parent 404b714 commit 3092ab2
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 21 deletions.
113 changes: 113 additions & 0 deletions src/accounts/account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Address } from "../address";
import { LibraryConfig } from "../config";
import { IAccountBalance, INonce } from "../interface";
import { Mnemonic, UserSigner, UserWallet } from "../wallet";
import { IAccount } from "./interfaces";

/**
* An abstraction representing an account (user or Smart Contract) on the Network.
*/
export class Account implements IAccount {
/**
* The address of the account.
*/
readonly address: Address = Address.empty();

/**
* The nonce of the account (the account sequence number).
*/
nonce: INonce = 0;

/**
* @deprecated This will be remove with the next release as not needed anymore.
*/
/**
* The balance of the account.
*/
balance: IAccountBalance = "0";

/**
* The signer of the account.
*/
private signer?: UserSigner;

/**
* Creates an account object from an address
*/
constructor(address: Address, signer?: UserSigner) {
this.address = address;
this.signer = signer;
}

/**
* @deprecated This will be remove with the next release as not needed anymore.
*/
/**
* Updates account properties (such as nonce, balance).
*/
update(obj: { nonce: INonce; balance: IAccountBalance }) {
this.nonce = obj.nonce;
this.balance = obj.balance;
}

/**
* Increments (locally) the nonce (the account sequence number).
*/
incrementNonce() {
this.nonce = this.nonce.valueOf() + 1;
}

/**
* Gets then increments (locally) the nonce (the account sequence number).
*/
getNonceThenIncrement(): INonce {
let nonce = this.nonce;
this.nonce = this.nonce.valueOf() + 1;
return nonce;
}

/**
* Converts the account to a pretty, plain JavaScript object.
*/
toJSON(): any {
return {
address: this.address.bech32(),
nonce: this.nonce.valueOf(),
balance: this.balance.toString(),
};
}

sign(data: Uint8Array): Promise<Uint8Array> {
if (!this.signer) {
throw new Error("Signer not initialiezed, please provide the signer when account is instantiated");
}
return this.signer.sign(data);
}

static newFromPem(path: string, index: number = 0, hrp: string = LibraryConfig.DefaultAddressHrp): Account {
const userSigner = UserSigner.fromPem(path, index);
return new Account(userSigner.getAddress(hrp), userSigner);
}

static newFromMnemonic(
mnemonic: string,
addressIndex: number = 0,
hrp: string = LibraryConfig.DefaultAddressHrp,
): Account {
const mnemonicHandler = Mnemonic.fromString(mnemonic);
const secretKey = mnemonicHandler.deriveKey(addressIndex);
const userSigner = new UserSigner(secretKey);
return new Account(userSigner.getAddress(hrp), userSigner);
}

static newFromKeystore(
filePath: string,
password: string,
addressIndex?: number,
hrp: string = LibraryConfig.DefaultAddressHrp,
): Account {
const secretKey = UserWallet.loadSecretKey(filePath, password, addressIndex);
const userSigner = new UserSigner(secretKey);
return new Account(userSigner.getAddress(hrp), userSigner);
}
}
2 changes: 2 additions & 0 deletions src/accounts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./account";
export * from "./interfaces";
7 changes: 7 additions & 0 deletions src/accounts/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Address } from "../address";

export interface IAccount {
readonly address: Address;

sign(data: Uint8Array): Promise<Uint8Array>;
}
39 changes: 18 additions & 21 deletions src/wallet/userVerifier.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,28 @@
import { Address } from "../address";
import { UserPublicKey } from "./userKeys";

interface IAddress {
pubkey(): Buffer;
}

/**
* ed25519 signature verification
*/
export class UserVerifier {
publicKey: UserPublicKey;
publicKey: UserPublicKey;

constructor(publicKey: UserPublicKey) {
this.publicKey = publicKey;
}
constructor(publicKey: UserPublicKey) {
this.publicKey = publicKey;
}

static fromAddress(address: IAddress): UserVerifier {
let publicKey = new UserPublicKey(address.pubkey());
return new UserVerifier(publicKey);
}
static fromAddress(address: Address): UserVerifier {
let publicKey = new UserPublicKey(address.getPublicKey());
return new UserVerifier(publicKey);
}

/**
*
* @param data the raw data to be verified (e.g. an already-serialized enveloped message)
* @param signature the signature to be verified
* @returns true if the signature is valid, false otherwise
*/
verify(data: Buffer | Uint8Array, signature: Buffer | Uint8Array): boolean {
return this.publicKey.verify(data, signature);
}
/**
*
* @param data the raw data to be verified (e.g. an already-serialized enveloped message)
* @param signature the signature to be verified
* @returns true if the signature is valid, false otherwise
*/
verify(data: Buffer | Uint8Array, signature: Buffer | Uint8Array): boolean {
return this.publicKey.verify(data, signature);
}
}
28 changes: 28 additions & 0 deletions src/wallet/userWallet.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { readFileSync } from "fs";
import path from "path";
import { Err } from "../errors";
import { Logger } from "../logger";
import { CipherAlgorithm, Decryptor, EncryptedData, Encryptor, KeyDerivationFunction, Randomness } from "./crypto";
import { ScryptKeyDerivationParams } from "./crypto/derivationParams";
import { Mnemonic } from "./mnemonic";
Expand Down Expand Up @@ -77,6 +80,31 @@ export class UserWallet {
});
}

static loadSecretKey(filePath: string, password: string, addressIndex?: number): UserSecretKey {
// Load and parse the keystore file
const keyFileJson = readFileSync(path.resolve(filePath), "utf8");
const keyFileObject = JSON.parse(keyFileJson);
const kind = keyFileObject.kind || UserWalletKind.SecretKey.valueOf();

Logger.debug(`UserWallet.loadSecretKey(), kind = ${kind}`);

let secretKey: UserSecretKey;

if (kind === UserWalletKind.SecretKey.valueOf()) {
if (addressIndex !== undefined) {
throw new Error("address_index must not be provided when kind == 'secretKey'");
}
secretKey = UserWallet.decryptSecretKey(keyFileObject, password);
} else if (kind === UserWalletKind.Mnemonic.valueOf()) {
const mnemonic = UserWallet.decryptMnemonic(keyFileObject, password);
secretKey = mnemonic.deriveKey(addressIndex || 0);
} else {
throw new Error(`Unknown kind: ${kind}`);
}

return secretKey;
}

static decrypt(keyFileObject: any, password: string, addressIndex?: number): UserSecretKey {
const kind = keyFileObject.kind || UserWalletKind.SecretKey;

Expand Down

0 comments on commit 3092ab2

Please sign in to comment.