Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.
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
5 changes: 3 additions & 2 deletions packages/web3-common/src/web3_base_wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,17 @@ export interface Web3AccountProvider<T> {
decrypt: (keystore: string, password: string, options?: Record<string, unknown>) => Promise<T>;
}

export abstract class Web3BaseWallet<T extends Web3BaseWalletAccount> {
export abstract class Web3BaseWallet<T extends Web3BaseWalletAccount> extends Array<T> {
protected readonly _accountProvider: Web3AccountProvider<T>;

public constructor(accountProvider: Web3AccountProvider<T>) {
super();
this._accountProvider = accountProvider;
}

public abstract create(numberOfAccounts: number): this;
public abstract add(account: T | string): boolean;
public abstract get(addressOrIndex: string | number): T;
public abstract get(addressOrIndex: string | number): T | undefined;
public abstract remove(addressOrIndex: string | number): boolean;
public abstract clear(): this;
public abstract encrypt(
Expand Down
25 changes: 24 additions & 1 deletion packages/web3-common/src/web3_promi_event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

import { Web3EventEmitter, Web3EventMap } from './web3_event_emitter';
import {
Web3EventCallback,
Web3EventEmitter,
Web3EventKey,
Web3EventMap,
} from './web3_event_emitter';

export type PromiseExecutor<T> = (
resolve: (data: T) => void,
Expand Down Expand Up @@ -52,4 +57,22 @@ export class Web3PromiEvent<ResolveType, EventMap extends Web3EventMap>
public async finally(onfinally?: (() => void) | undefined): Promise<ResolveType> {
return this._promise.finally(onfinally);
}

public on<K extends Web3EventKey<EventMap>>(
eventName: K,
fn: Web3EventCallback<EventMap[K]>,
): this {
super.on(eventName, fn);

return this;
}

public once<K extends Web3EventKey<EventMap>>(
eventName: K,
fn: Web3EventCallback<EventMap[K]>,
): this {
super.once(eventName, fn);

return this;
}
}
52 changes: 45 additions & 7 deletions packages/web3-common/test/unit/web3_promi_event.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,16 @@ describe('Web3PromiEvent', () => {
});

p.on('data', data => {
// eslint-disable-next-line jest/no-conditional-expect
expect(data).toBe('resolved value');
done(undefined);
});
})
.then(data => {
p.emit('data', data);
})
.catch(e => done(e));

p.then(data => {
p.emit('data', data);
}).catch(e => {
throw e;
});
expect.assertions(1);
});
});

Expand All @@ -69,10 +70,47 @@ describe('Web3PromiEvent', () => {

const p = func();

p.on('data', data => {
// eslint-disable-next-line no-void
void p.on('data', data => {
expect(data).toBe('emitted data');
done(undefined);
});
});
});

it('should return the promi-event object from "on" handler', async () => {
const p = new Web3PromiEvent<string, { event1: string; event2: number }>(resolve => {
resolve('resolved value');
})
.on('event1', data => {
expect(data).toBe('string value');
})
.on('event2', data => {
expect(data).toBe(3);
});

p.emit('event1', 'string value');
p.emit('event2', 3);

await expect(p).resolves.toBe('resolved value');
expect.assertions(3);
});

it('should return the promi-event object from "once" handler', async () => {
const p = new Web3PromiEvent<string, { event1: string; event2: number }>(resolve => {
resolve('resolved value');
})
.once('event1', data => {
expect(data).toBe('string value');
})
.once('event2', data => {
expect(data).toBe(3);
});

p.emit('event1', 'string value');
p.emit('event2', 3);

await expect(p).resolves.toBe('resolved value');
expect.assertions(3);
});
});
64 changes: 32 additions & 32 deletions packages/web3-eth-accounts/src/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,17 @@ You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

import {
Web3BaseWallet,
Web3BaseWalletAccount,
Web3AccountProvider,
Web3EncryptedWallet,
} from 'web3-common';
import { Web3BaseWallet, Web3BaseWalletAccount, Web3EncryptedWallet } from 'web3-common';
import { isNullish } from 'web3-validator';

type BrowserError = { code: number; name: string };

export class Wallet<
T extends Web3BaseWalletAccount = Web3BaseWalletAccount,
> extends Web3BaseWallet<T> {
private readonly _accounts: { [key: string]: T };
private readonly _addressMap = new Map<string, number>();
private readonly _defaultKeyName = 'web3js_wallet';

public constructor(accountProvider: Web3AccountProvider<T>) {
super(accountProvider);
this._accounts = {};
}

public static getStorage(): Storage | undefined {
let storage: Storage | undefined;

Expand Down Expand Up @@ -65,10 +55,6 @@ export class Wallet<
}
}

public get length() {
return Object.keys(this._accounts).length;
}

public create(numberOfAccounts: number) {
for (let i = 0; i < numberOfAccounts; i += 1) {
this.add(this._accountProvider.create());
Expand All @@ -82,45 +68,59 @@ export class Wallet<
return this.add(this._accountProvider.privateKeyToAccount(account));
}

this._accounts[account.address.toLowerCase()] = account;
const index = this.length;
this._addressMap.set(account.address.toLowerCase(), index);

this[index] = account;

return true;
}

public get(addressOrIndex: string | number): T {
public get(addressOrIndex: string | number): T | undefined {
if (typeof addressOrIndex === 'string') {
return this._accounts[addressOrIndex];
const index = this._addressMap.get(addressOrIndex);

if (!isNullish(index)) {
return this[index];
}

return undefined;
}

return Object.values(this._accounts)[addressOrIndex];
return this[addressOrIndex];
}

public remove(addressOrIndex: string | number): boolean {
const result =
typeof addressOrIndex === 'string'
? { address: addressOrIndex }
: Object.values(this._accounts)[addressOrIndex];
if (typeof addressOrIndex === 'string') {
const index = this._addressMap.get(addressOrIndex.toLowerCase());
if (isNullish(index)) {
return false;
}
this._addressMap.delete(addressOrIndex.toLowerCase());
this.splice(index, 1);

return true;
}

if (result && this._accounts[result.address]) {
delete this._accounts[result.address];
if (this[addressOrIndex]) {
this.splice(addressOrIndex, 1);
return true;
}

return false;
}

public clear() {
for (const key of Object.keys(this._accounts)) {
delete this._accounts[key];
}
this._addressMap.clear();

// Setting length clears the Array in JS.
this.length = 0;

return this;
}

public async encrypt(password: string, options?: Record<string, unknown> | undefined) {
return Promise.all(
Object.values(this._accounts).map(async account => account.encrypt(password, options)),
);
return Promise.all(this.map(async account => account.encrypt(password, options)));
}

public async decrypt(
Expand Down
42 changes: 42 additions & 0 deletions packages/web3-eth-accounts/test/unit/wallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ describe('Wallet', () => {
expect(wallet.get('my_address')).toEqual(account);
expect(wallet.get('my_Address')).toBeUndefined();
});

it('should get account with index', () => {
const account = { address: 'my_Address' } as never;

wallet.add(account);

expect(wallet[0]).toEqual(account);
});
});

describe('remove', () => {
Expand Down Expand Up @@ -190,6 +198,40 @@ describe('Wallet', () => {
expect(result).toBeFalsy();
expect(wallet).toHaveLength(1);
});

it('should remove account with the index', () => {
const account = { address: 'my_address' } as never;
wallet.add(account);
expect(wallet).toHaveLength(1);

delete wallet[0];

// Deleting objects dees not change the length
expect(wallet).toHaveLength(1);
expect(wallet[0]).toBeUndefined();
});

it('should remove account with array methods', () => {
const account = { address: 'my_address' } as never;
wallet.add(account);
expect(wallet).toHaveLength(1);

wallet.splice(0, 1);

expect(wallet).toHaveLength(0);
expect(wallet[0]).toBeUndefined();
});

it('should remove account added with private key with array methods', () => {
const privateKey = 'private_key';
wallet.add(privateKey);
expect(wallet).toHaveLength(1);

wallet.splice(0, 1);

expect(wallet).toHaveLength(0);
expect(wallet[0]).toBeUndefined();
});
});

describe('clear', () => {
Expand Down
10 changes: 7 additions & 3 deletions packages/web3-eth-contract/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,9 @@ export class Contract<Abi extends ContractAbi>
*
* The methods of this smart contract are available through:
*
* * The name: `myContract.methods.myMethod(123)`
* * The name with parameters: `myContract.methods['myMethod(uint256)'](123)`
* * The signature `myContract.methods['0x58cf5f10'](123)`
* The name: `myContract.methods.myMethod(123)`
* The name with parameters: `myContract.methods['myMethod(uint256)'](123)`
* The signature `myContract.methods['0x58cf5f10'](123)`
*
* This allows calling functions with same name but different parameters from the JavaScript contract object.
*
Expand Down Expand Up @@ -574,6 +574,9 @@ export class Contract<Abi extends ContractAbi>
* });
* ```
*
* @param deployOptions
* @param deployOptions.data
* @param deployOptions.arguments
* @returns - The transaction object
*/
public deploy(deployOptions?: {
Expand Down Expand Up @@ -685,6 +688,7 @@ export class Contract<Abi extends ContractAbi>
*
* @param eventName - The name of the event in the contract, or `allEvents` to get all events.
* @param filter - The filter options used to get events.
* @param returnFormat
* @returns - An array with the past event `Objects`, matching the given event name and filter.
*/
public async getPastEvents<ReturnFormat extends DataFormat = typeof DEFAULT_RETURN_FORMAT>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,10 @@ describe('contract', () => {
const receiptHandler = jest.fn();

// We didn't specify "from" in this call
const tx = contract.deploy(deployOptions).send({ gas: '1000000' });

tx.on('receipt', receiptHandler);

await tx;
await contract
.deploy(deployOptions)
.send({ gas: '1000000' })
.on('receipt', receiptHandler);

// We didn't specify "from" in this call
expect(receiptHandler).toHaveBeenCalledWith(
Expand Down
Loading