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

Add account management controller and accounts folder #532

Merged
merged 10 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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 src/abi/interaction.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Account } from "../account";
import { Account } from "../accounts";
import { Address } from "../address";
import { Compatibility } from "../compatibility";
import { TRANSACTION_VERSION_DEFAULT } from "../constants";
Expand Down
64 changes: 0 additions & 64 deletions src/account.ts

This file was deleted.

62 changes: 62 additions & 0 deletions src/accountManagement/accountController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { IAccount } from "../accounts/interfaces";
import { Transaction } from "../transaction";
import { TransactionComputer } from "../transactionComputer";
import { TransactionsFactoryConfig } from "../transactionsFactories";
import { AccountTransactionsFactory } from "./accountTransactionsFactory";
import { SaveKeyValueInput, SetGuardianInput } from "./resources";

export class AccountController {
private factory: AccountTransactionsFactory;
private txComputer: TransactionComputer;

constructor(options: { chainID: string }) {
this.factory = new AccountTransactionsFactory({
config: new TransactionsFactoryConfig(options),
});
this.txComputer = new TransactionComputer();
}

async createTransactionForSavingKeyValue(
sender: IAccount,
nonce: bigint,
options: SaveKeyValueInput,
): Promise<Transaction> {
const transaction = this.factory.createTransactionForSavingKeyValue(sender.address, options);

transaction.nonce = nonce;
transaction.signature = await sender.sign(this.txComputer.computeBytesForSigning(transaction));

return transaction;
}

async createTransactionForSettingGuardian(
sender: IAccount,
nonce: bigint,
options: SetGuardianInput,
): Promise<Transaction> {
const transaction = this.factory.createTransactionForSettingGuardian(sender.address, options);

transaction.nonce = nonce;
transaction.signature = await sender.sign(this.txComputer.computeBytesForSigning(transaction));

return transaction;
}

async createTransactionForGuardingAccount(sender: IAccount, nonce: bigint): Promise<Transaction> {
const transaction = this.factory.createTransactionForGuardingAccount(sender.address);

transaction.nonce = nonce;
transaction.signature = await sender.sign(this.txComputer.computeBytesForSigning(transaction));

return transaction;
}

async createTransactionForUnguardingAccount(sender: IAccount, nonce: bigint): Promise<Transaction> {
const transaction = this.factory.createTransactionForUnguardingAccount(sender.address);

transaction.nonce = nonce;
transaction.signature = await sender.sign(this.txComputer.computeBytesForSigning(transaction));

return transaction;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { assert } from "chai";
import { Address } from "../address";
import { TransactionsFactoryConfig } from "./transactionsFactoryConfig";
import { TransactionsFactoryConfig } from "../transactionsFactories";
import { AccountTransactionsFactory } from "./accountTransactionsFactory";

describe("test account transactions factory", function () {
Expand All @@ -11,8 +11,7 @@ describe("test account transactions factory", function () {
const sender = Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th");
const keyValuePairs = new Map([[Buffer.from("key0"), Buffer.from("value0")]]);

const transaction = factory.createTransactionForSavingKeyValue({
sender: sender,
const transaction = factory.createTransactionForSavingKeyValue(sender, {
keyValuePairs: keyValuePairs,
});

Expand All @@ -29,8 +28,7 @@ describe("test account transactions factory", function () {
const guardian = Address.fromBech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx");
const serviceID = "MultiversXTCSService";

const transaction = factory.createTransactionForSettingGuardian({
sender: sender,
const transaction = factory.createTransactionForSettingGuardian(sender, {
guardianAddress: guardian,
serviceID: serviceID,
});
Expand All @@ -49,9 +47,7 @@ describe("test account transactions factory", function () {
it("should create 'Transaction' for guarding account", async function () {
const sender = Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th");

const transaction = factory.createTransactionForGuardingAccount({
sender: sender,
});
const transaction = factory.createTransactionForGuardingAccount(sender);

assert.equal(transaction.sender, "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th");
assert.equal(transaction.receiver, "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th");
Expand All @@ -64,9 +60,7 @@ describe("test account transactions factory", function () {
it("should create 'Transaction' for unguarding account", async function () {
const sender = Address.fromBech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th");

const transaction = factory.createTransactionForUnguardingAccount({
sender: sender,
});
const transaction = factory.createTransactionForUnguardingAccount(sender);

assert.equal(transaction.sender, "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th");
assert.equal(transaction.receiver, "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Address } from "../address";
import { IAddress } from "../interface";
import { Transaction } from "../transaction";
import { TransactionBuilder } from "./transactionBuilder";
import { TransactionBuilder } from "../transactionsFactories/transactionBuilder";
import { SaveKeyValueInput, SetGuardianInput } from "./resources";

interface IConfig {
chainID: string;
Expand All @@ -22,19 +23,16 @@ export class AccountTransactionsFactory {
this.config = options.config;
}

createTransactionForSavingKeyValue(options: {
sender: IAddress;
keyValuePairs: Map<Uint8Array, Uint8Array>;
}): Transaction {
createTransactionForSavingKeyValue(sender: IAddress, options: SaveKeyValueInput): Transaction {
const functionName = "SaveKeyValue";
const keyValueParts = this.computeDataPartsForSavingKeyValue(options.keyValuePairs);
const dataParts = [functionName, ...keyValueParts];
const extraGas = this.computeExtraGasForSavingKeyValue(options.keyValuePairs);

return new TransactionBuilder({
config: this.config,
sender: options.sender,
receiver: options.sender,
sender: sender,
receiver: sender,
dataParts: dataParts,
gasLimit: extraGas,
addDataMovementGas: true,
Expand Down Expand Up @@ -63,11 +61,7 @@ export class AccountTransactionsFactory {
return dataParts;
}

createTransactionForSettingGuardian(options: {
sender: IAddress;
guardianAddress: IAddress;
serviceID: string;
}): Transaction {
createTransactionForSettingGuardian(sender: IAddress, options: SetGuardianInput): Transaction {
const dataParts = [
"SetGuardian",
Address.fromBech32(options.guardianAddress.bech32()).toHex(),
Expand All @@ -76,34 +70,34 @@ export class AccountTransactionsFactory {

return new TransactionBuilder({
config: this.config,
sender: options.sender,
receiver: options.sender,
sender: sender,
receiver: sender,
dataParts: dataParts,
gasLimit: this.config.gasLimitSetGuardian,
addDataMovementGas: true,
}).build();
}

createTransactionForGuardingAccount(options: { sender: IAddress }): Transaction {
createTransactionForGuardingAccount(sender: IAddress): Transaction {
const dataParts = ["GuardAccount"];

return new TransactionBuilder({
config: this.config,
sender: options.sender,
receiver: options.sender,
sender: sender,
receiver: sender,
dataParts: dataParts,
gasLimit: this.config.gasLimitGuardAccount,
addDataMovementGas: true,
}).build();
}

createTransactionForUnguardingAccount(options: { sender: IAddress }): Transaction {
createTransactionForUnguardingAccount(sender: IAddress): Transaction {
const dataParts = ["UnGuardAccount"];

return new TransactionBuilder({
config: this.config,
sender: options.sender,
receiver: options.sender,
sender: sender,
receiver: sender,
dataParts: dataParts,
gasLimit: this.config.gasLimitUnguardAccount,
addDataMovementGas: true,
Expand Down
2 changes: 2 additions & 0 deletions src/accountManagement/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./accountController";
export * from "./accountTransactionsFactory";
4 changes: 4 additions & 0 deletions src/accountManagement/resources.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { IAddress } from "../interface";

export type SetGuardianInput = { guardianAddress: IAddress; serviceID: string };
export type SaveKeyValueInput = { keyValuePairs: Map<Uint8Array, Uint8Array> };
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";
Loading
Loading