diff --git a/docs/api/classes/stakingpool.md b/docs/api/classes/stakingpool.md index 29161587..36948613 100644 --- a/docs/api/classes/stakingpool.md +++ b/docs/api/classes/stakingpool.md @@ -29,13 +29,14 @@ Abstraction over staking pool smart contract ### constructor -\+ **new StakingPool**(`pool`: StakingPoolContract): [StakingPool](stakingpool.md) +\+ **new StakingPool**(`patron`: Required\, `address`: string): [StakingPool](stakingpool.md) #### Parameters: Name | Type | ------ | ------ | -`pool` | StakingPoolContract | +`patron` | Required\ | +`address` | string | **Returns:** [StakingPool](stakingpool.md) diff --git a/docs/api/enums/error_messages.md b/docs/api/enums/error_messages.md index 7ffc2df5..7d2aa16a 100644 --- a/docs/api/enums/error_messages.md +++ b/docs/api/enums/error_messages.md @@ -16,6 +16,7 @@ * [ENS\_REGISTRY\_NOT\_INITIALIZED](error_messages.md#ens_registry_not_initialized) * [ENS\_RESOLVER\_NOT\_INITIALIZED](error_messages.md#ens_resolver_not_initialized) * [ENS\_TYPE\_NOT\_SUPPORTED](error_messages.md#ens_type_not_supported) +* [INSUFFICIENT\_BALANCE](error_messages.md#insufficient_balance) * [JWT\_NOT\_INITIALIZED](error_messages.md#jwt_not_initialized) * [METAMASK\_EXTENSION\_NOT\_AVAILABLE](error_messages.md#metamask_extension_not_available) * [NATS\_NOT\_CONNECTED](error_messages.md#nats_not_connected) @@ -100,6 +101,12 @@ ___ ___ +### INSUFFICIENT\_BALANCE + +• **INSUFFICIENT\_BALANCE**: = "Signer has insufficient balance" + +___ + ### JWT\_NOT\_INITIALIZED • **JWT\_NOT\_INITIALIZED**: = "JWT was not initialized" diff --git a/src/errors/ErrorMessages.ts b/src/errors/ErrorMessages.ts index 4877303b..7daf51a6 100644 --- a/src/errors/ErrorMessages.ts +++ b/src/errors/ErrorMessages.ts @@ -29,5 +29,6 @@ export enum ERROR_MESSAGES { ONCHAIN_ROLE_VERSION_NOT_SPECIFIED = "On-chain role version not specified", CACHE_SERVER_NOT_REGISTERED = "Cache server for this chain is not registered", WITHDRAWAL_WAS_NOT_REQUESTED = "Stake withdrawal was not requested", - STAKE_WAS_NOT_PUT = "Stake was not put" + STAKE_WAS_NOT_PUT = "Stake was not put", + INSUFFICIENT_BALANCE = "Signer has insufficient balance" } diff --git a/src/staking/index.ts b/src/staking/index.ts index 9ded2c2f..8808c7ca 100644 --- a/src/staking/index.ts +++ b/src/staking/index.ts @@ -103,12 +103,11 @@ export class StakingPoolService { * @param org ENS name of organization */ async getPool(org: string): Promise { - const service = await this._stakingPoolFactory.services(namehash(org)); - if (service.pool === emptyAddress) { + const { pool } = await this._stakingPoolFactory.services(namehash(org)); + if (pool === emptyAddress) { return null; } - const pool = new StakingPool__factory(this._signer).attach(service.pool); - return new StakingPool(pool); + return new StakingPool(this._signer, pool); } } @@ -116,7 +115,10 @@ export class StakingPoolService { * Abstraction over staking pool smart contract */ export class StakingPool { - constructor(private pool: StakingPoolContract) { } + private pool: StakingPoolContract; + constructor(private patron: Required, address: string) { + this.pool = new StakingPool__factory(patron).attach(address); + } /** * @description Locks stake and starts accumulating reward @@ -129,6 +131,9 @@ export class StakingPool { if (typeof stake === "number") { stake = new BigNumber(stake); } + if ((await this.getBalance()).lt(stake)) { + throw new Error(ERROR_MESSAGES.INSUFFICIENT_BALANCE); + } await (await this.pool.putStake({ value: stake })).wait(); @@ -206,7 +211,10 @@ export class StakingPool { * @param signer Signer connected to provider */ connect(signer: Signer): StakingPool { - return new StakingPool(this.pool.connect(signer)); + if (!signer.provider) { + throw new Error("StakingPoolService.init: Signer is not connected to provider"); + } + return new StakingPool(signer as Required, this.pool.address); } private async now(): Promise { @@ -215,4 +223,10 @@ export class StakingPool { (await this.pool.provider.getBlock(lastBlock)).timestamp ); } + + private async getBalance(): Promise { + return await this.patron.provider.getBalance( + await this.patron.getAddress() + ); + } } diff --git a/test/staking.ts b/test/staking.ts index 95cb897c..005d710b 100644 --- a/test/staking.ts +++ b/test/staking.ts @@ -3,7 +3,7 @@ import { StakingPoolFactory } from "@energyweb/iam-contracts/dist/ethers-v4/Stak import { StakingPool as StakingPoolContract } from "@energyweb/iam-contracts/dist/ethers-v4/StakingPool"; import { EventFilter, Contract, Wallet, utils, providers } from "ethers"; import { Methods } from "@ew-did-registry/did"; -import { IAM, RegistrationTypes, setChainConfig, StakingPool, StakingPoolService } from "../src/iam-client-lib"; +import { ERROR_MESSAGES, IAM, RegistrationTypes, setChainConfig, StakingPool, StakingPoolService } from "../src/iam-client-lib"; import { claimManager, ensRegistry, replenish, provider, deployer } from "./setup_contracts"; import { createIam, root, rootOwner } from "./iam.test"; import { mockJsonCodec, mockNats } from "./testUtils/mocks"; @@ -306,13 +306,22 @@ export const stakingTests = (): void => { )).rejects.toThrow("StakingPool: patron is not registered with patron role"); }); - it("stake amount must be provided", async () => { + it("should reject when stake amount isn't provided", async () => { return expect( pool.putStake(parseEther("0")) ) .rejects.toThrow("StakingPool: stake amount is not provided"); }); + it("should not be able to stake with insufficient balance", async () => { + const balance = await patron.getBalance(); + + return expect( + pool.putStake(balance.add(1)) + ) + .rejects.toThrow(ERROR_MESSAGES.INSUFFICIENT_BALANCE); + }); + it("stake should not be replenished", async () => { await pool.putStake(parseEther("0.1")); @@ -320,7 +329,7 @@ export const stakingTests = (): void => { .rejects.toThrow("StakingPool: Replenishment of the stake is not allowed"); }); - it("staker should be able to request withdraw", async () => { + it("staker should be able to request withdraw", async () => { await pool.putStake(parseEther("0.1")); const requestDelay = await pool.requestWithdrawDelay(); await new Promise((resolve) => setTimeout(resolve, 1000 * requestDelay.toNumber()));