import { BlockTag } from "@ethersproject/abstract-provider"; import { CollateralGainTransferDetails, Decimal, Decimalish, FailedReceipt, Fees, FrontendStatus, LiquidationDetails, ARTHStore, RedemptionDetails, StabilityDeposit, StabilityDepositChangeDetails, StabilityPoolGainsWithdrawalDetails, TransactableARTH, TransactionFailedError, Trove, TroveAdjustmentDetails, TroveAdjustmentParams, TroveClosureDetails, TroveCreationDetails, TroveCreationParams, TroveListingParams, TroveWithPendingRedistribution, UserTrove } from "@mahadao/arth-base"; import { EthersARTHConnection, EthersARTHConnectionOptionalParams, EthersARTHStoreOption, _connect, _usingStore } from "./EthersARTHConnection"; import { EthersCallOverrides, EthersProvider, EthersSigner, EthersTransactionOverrides, EthersTransactionReceipt } from "./types"; import { BorrowingOperationOptionalParams, PopulatableEthersARTH, SentEthersARTHTransaction } from "./PopulatableEthersARTH"; import { ReadableEthersARTH, ReadableEthersARTHWithStore } from "./ReadableEthersARTH"; import { SendableEthersARTH } from "./SendableEthersARTH"; import { BlockPolledARTHStore } from "./BlockPolledARTHStore"; /** * Thrown by {@link EthersARTH} in case of transaction failure. * * @public */ export class EthersTransactionFailedError extends TransactionFailedError< FailedReceipt > { constructor(message: string, failedReceipt: FailedReceipt) { super("EthersTransactionFailedError", message, failedReceipt); } } const waitForSuccess = async (tx: SentEthersARTHTransaction) => { const receipt = await tx.waitForReceipt(); if (receipt.status !== "succeeded") { throw new EthersTransactionFailedError("Transaction failed", receipt); } return receipt.details; }; /** * Convenience class that combines multiple interfaces of the library in one object. * * @public */ export class EthersARTH implements ReadableEthersARTH, TransactableARTH { /** Information about the connection to the ARTH protocol. */ readonly connection: EthersARTHConnection; /** Can be used to create populated (unsigned) transactions. */ readonly populate: PopulatableEthersARTH; /** Can be used to send transactions without waiting for them to be mined. */ readonly send: SendableEthersARTH; private _readable: ReadableEthersARTH; /** @internal */ constructor(readable: ReadableEthersARTH) { this._readable = readable; this.connection = readable.connection; this.populate = new PopulatableEthersARTH(readable); this.send = new SendableEthersARTH(this.populate); } /** @internal */ static _from( connection: EthersARTHConnection & { useStore: "blockPolled" } ): EthersARTHWithStore; /** @internal */ static _from(connection: EthersARTHConnection): EthersARTH; /** @internal */ static _from(connection: EthersARTHConnection): EthersARTH { if (_usingStore(connection)) { return new _EthersARTHWithStore(ReadableEthersARTH._from(connection)); } else { return new EthersARTH(ReadableEthersARTH._from(connection)); } } /** @internal */ static connect( signerOrProvider: EthersSigner | EthersProvider, optionalParams: EthersARTHConnectionOptionalParams & { useStore: "blockPolled" } ): Promise>; /** * Connect to the ARTH protocol and create an `EthersARTH` object. * * @param signerOrProvider - Ethers `Signer` or `Provider` to use for connecting to the Ethereum * network. * @param optionalParams - Optional parameters that can be used to customize the connection. */ static connect( signerOrProvider: EthersSigner | EthersProvider, optionalParams?: EthersARTHConnectionOptionalParams ): Promise; static async connect( signerOrProvider: EthersSigner | EthersProvider, optionalParams?: EthersARTHConnectionOptionalParams ): Promise { return EthersARTH._from(await _connect(signerOrProvider, optionalParams)); } /** * Check whether this `EthersARTH` is an {@link EthersARTHWithStore}. */ hasStore(): this is EthersARTHWithStore; /** * Check whether this `EthersARTH` is an * {@link EthersARTHWithStore}\<{@link BlockPolledARTHStore}\>. */ hasStore(store: "blockPolled"): this is EthersARTHWithStore; hasStore(): boolean { return false; } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getTotalRedistributed} */ getTotalRedistributed(overrides?: EthersCallOverrides): Promise { return this._readable.getTotalRedistributed(overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getTroveBeforeRedistribution} */ getTroveBeforeRedistribution( address?: string, overrides?: EthersCallOverrides ): Promise { return this._readable.getTroveBeforeRedistribution(address, overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getTrove} */ getTrove(address?: string, overrides?: EthersCallOverrides): Promise { return this._readable.getTrove(address, overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getNumberOfTroves} */ getNumberOfTroves(overrides?: EthersCallOverrides): Promise { return this._readable.getNumberOfTroves(overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getPrice} */ getPrice(overrides?: EthersCallOverrides): Promise { return this._readable.getPrice(overrides); } /** @internal */ _getActivePool(overrides?: EthersCallOverrides): Promise { return this._readable._getActivePool(overrides); } /** @internal */ _getDefaultPool(overrides?: EthersCallOverrides): Promise { return this._readable._getDefaultPool(overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getTotal} */ getTotal(overrides?: EthersCallOverrides): Promise { return this._readable.getTotal(overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getStabilityDeposit} */ getStabilityDeposit(address?: string, overrides?: EthersCallOverrides): Promise { return this._readable.getStabilityDeposit(address, overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getRemainingStabilityPoolMAHAReward} */ getRemainingStabilityPoolMAHAReward(overrides?: EthersCallOverrides): Promise { return this._readable.getRemainingStabilityPoolMAHAReward(overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getARTHInStabilityPool} */ getARTHInStabilityPool(overrides?: EthersCallOverrides): Promise { return this._readable.getARTHInStabilityPool(overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getARTHBalance} */ getARTHBalance(address?: string, overrides?: EthersCallOverrides): Promise { return this._readable.getARTHBalance(address, overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getMAHABalance} */ getMAHABalance(address?: string, overrides?: EthersCallOverrides): Promise { return this._readable.getMAHABalance(address, overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getCollateralSurplusBalance} */ getCollateralSurplusBalance(address?: string, overrides?: EthersCallOverrides): Promise { return this._readable.getCollateralSurplusBalance(address, overrides); } /** @internal */ getTroves( params: TroveListingParams & { beforeRedistribution: true }, overrides?: EthersCallOverrides ): Promise; /** {@inheritDoc @mahadao/arth-base#ReadableARTH.(getTroves:2)} */ getTroves(params: TroveListingParams, overrides?: EthersCallOverrides): Promise; getTroves(params: TroveListingParams, overrides?: EthersCallOverrides): Promise { return this._readable.getTroves(params, overrides); } /** @internal */ _getBlockTimestamp(blockTag?: BlockTag): Promise { return this._readable._getBlockTimestamp(blockTag); } /** @internal */ _getFeesFactory( overrides?: EthersCallOverrides ): Promise<(blockTimestamp: number, recoveryMode: boolean) => Fees> { return this._readable._getFeesFactory(overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getFees} */ getFees(overrides?: EthersCallOverrides): Promise { return this._readable.getFees(overrides); } /** {@inheritDoc @mahadao/arth-base#ReadableARTH.getFrontendStatus} */ getFrontendStatus(address?: string, overrides?: EthersCallOverrides): Promise { return this._readable.getFrontendStatus(address, overrides); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.openTrove} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ openTrove( params: TroveCreationParams, maxBorrowingRateOrOptionalParams?: Decimalish | BorrowingOperationOptionalParams, overrides?: EthersTransactionOverrides ): Promise { return this.send .openTrove(params, maxBorrowingRateOrOptionalParams, overrides) .then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.closeTrove} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ closeTrove(overrides?: EthersTransactionOverrides): Promise { return this.send.closeTrove(overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.adjustTrove} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ adjustTrove( params: TroveAdjustmentParams, maxBorrowingRateOrOptionalParams?: Decimalish | BorrowingOperationOptionalParams, overrides?: EthersTransactionOverrides ): Promise { return this.send .adjustTrove(params, maxBorrowingRateOrOptionalParams, overrides) .then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.depositCollateral} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ depositCollateral( amount: Decimalish, overrides?: EthersTransactionOverrides ): Promise { return this.send.depositCollateral(amount, overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.withdrawCollateral} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ withdrawCollateral( amount: Decimalish, overrides?: EthersTransactionOverrides ): Promise { return this.send.withdrawCollateral(amount, overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.borrowARTH} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ borrowARTH( amount: Decimalish, maxBorrowingRate?: Decimalish, overrides?: EthersTransactionOverrides ): Promise { return this.send.borrowARTH(amount, maxBorrowingRate, overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.repayARTH} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ repayARTH( amount: Decimalish, overrides?: EthersTransactionOverrides ): Promise { return this.send.repayARTH(amount, overrides).then(waitForSuccess); } /** @internal */ setPrice(price: Decimalish, overrides?: EthersTransactionOverrides): Promise { return this.send.setPrice(price, overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.liquidate} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ liquidate( address: string | string[], overrides?: EthersTransactionOverrides ): Promise { return this.send.liquidate(address, overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.liquidateUpTo} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ liquidateUpTo( maximumNumberOfTrovesToLiquidate: number, overrides?: EthersTransactionOverrides ): Promise { return this.send.liquidateUpTo(maximumNumberOfTrovesToLiquidate, overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.depositARTHInStabilityPool} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ depositARTHInStabilityPool( amount: Decimalish, frontendTag?: string, overrides?: EthersTransactionOverrides ): Promise { return this.send.depositARTHInStabilityPool(amount, frontendTag, overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.withdrawARTHFromStabilityPool} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ withdrawARTHFromStabilityPool( amount: Decimalish, overrides?: EthersTransactionOverrides ): Promise { return this.send.withdrawARTHFromStabilityPool(amount, overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.withdrawGainsFromStabilityPool} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ withdrawGainsFromStabilityPool( overrides?: EthersTransactionOverrides ): Promise { return this.send.withdrawGainsFromStabilityPool(overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.transferCollateralGainToTrove} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ transferCollateralGainToTrove( overrides?: EthersTransactionOverrides ): Promise { return this.send.transferCollateralGainToTrove(overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.sendARTH} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ sendARTH( toAddress: string, amount: Decimalish, overrides?: EthersTransactionOverrides ): Promise { return this.send.sendARTH(toAddress, amount, overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.sendMAHA} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ sendMAHA( toAddress: string, amount: Decimalish, overrides?: EthersTransactionOverrides ): Promise { return this.send.sendMAHA(toAddress, amount, overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.redeemARTH} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ redeemARTH( amount: Decimalish, maxRedemptionRate?: Decimalish, overrides?: EthersTransactionOverrides ): Promise { return this.send.redeemARTH(amount, maxRedemptionRate, overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.claimCollateralSurplus} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ claimCollateralSurplus(overrides?: EthersTransactionOverrides): Promise { return this.send.claimCollateralSurplus(overrides).then(waitForSuccess); } /** * {@inheritDoc @mahadao/arth-base#TransactableARTH.registerFrontend} * * @throws * Throws {@link EthersTransactionFailedError} in case of transaction failure. * Throws {@link EthersTransactionCancelledError} if the transaction is cancelled or replaced. */ registerFrontend(kickbackRate: Decimalish, overrides?: EthersTransactionOverrides): Promise { return this.send.registerFrontend(kickbackRate, overrides).then(waitForSuccess); } } /** * Variant of {@link EthersARTH} that exposes a {@link @mahadao/arth-base#ARTHStore}. * * @public */ export interface EthersARTHWithStore extends EthersARTH { /** An object that implements ARTHStore. */ readonly store: T; } class _EthersARTHWithStore extends EthersARTH implements EthersARTHWithStore { readonly store: T; constructor(readable: ReadableEthersARTHWithStore) { super(readable); this.store = readable.store; } hasStore(store?: EthersARTHStoreOption): boolean { return store === undefined || store === this.connection.useStore; } }