diff --git a/api-extractor.base.json b/api-extractor.base.json index c75daef86..7c59d51ae 100644 --- a/api-extractor.base.json +++ b/api-extractor.base.json @@ -330,14 +330,17 @@ "default": { "logLevel": "warning" // "addToApiReportFile": false - } + }, - // "ae-extra-release-tag": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . + "ae-forgotten-export": { + "logLevel": "warning", + "addToApiReportFile": false + }, + + "ae-internal-missing-underscore": { + "logLevel": "warning", + "addToApiReportFile": false + } }, /** diff --git a/docs/sdk/lib-ethers.blockpolledliquitystore._constructor_.md b/docs/sdk/lib-ethers.blockpolledliquitystore._constructor_.md index 223e5a395..57ffecd14 100644 --- a/docs/sdk/lib-ethers.blockpolledliquitystore._constructor_.md +++ b/docs/sdk/lib-ethers.blockpolledliquitystore._constructor_.md @@ -9,15 +9,15 @@ Constructs a new instance of the `BlockPolledLiquityStore` class Signature: ```typescript -constructor(provider: Provider, account: string, liquity: ReadableEthersLiquity, frontendTag?: string); +constructor(connection: LiquityConnection, readableLiquity?: ReadableEthersLiquity, frontendTag?: string, userAddress?: string); ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| provider | Provider | | -| account | string | | -| liquity | [ReadableEthersLiquity](./lib-ethers.readableethersliquity.md) | | +| connection | [LiquityConnection](./lib-ethers.liquityconnection.md) | | +| readableLiquity | [ReadableEthersLiquity](./lib-ethers.readableethersliquity.md) | | | frontendTag | string | | +| userAddress | string | | diff --git a/docs/sdk/lib-ethers.blockpolledliquitystore.md b/docs/sdk/lib-ethers.blockpolledliquitystore.md index 4e2242485..3ccbcc67c 100644 --- a/docs/sdk/lib-ethers.blockpolledliquitystore.md +++ b/docs/sdk/lib-ethers.blockpolledliquitystore.md @@ -17,7 +17,7 @@ export declare class BlockPolledLiquityStore extends LiquityStoreBlockPolledLiquityStore class | +| [(constructor)(connection, readableLiquity, frontendTag, userAddress)](./lib-ethers.blockpolledliquitystore._constructor_.md) | | Constructs a new instance of the BlockPolledLiquityStore class | ## Methods diff --git a/packages/dev-frontend/src/hooks/LiquityContext.tsx b/packages/dev-frontend/src/hooks/LiquityContext.tsx index f8eb774ec..efa508173 100644 --- a/packages/dev-frontend/src/hooks/LiquityContext.tsx +++ b/packages/dev-frontend/src/hooks/LiquityContext.tsx @@ -96,7 +96,7 @@ export const LiquityProvider: React.FC = ({ } const readable = new ReadableEthersLiquity(connection, account); - const store = new BlockPolledLiquityStore(provider, account, readable, config.frontendTag); + const store = new BlockPolledLiquityStore(connection, readable, config.frontendTag, account); const populatable = new PopulatableEthersLiquity(connection, readable, store); const liquity = new EthersLiquity(readable, populatable); diff --git a/packages/lib-ethers/etc/lib-ethers.api.md b/packages/lib-ethers/etc/lib-ethers.api.md index bd46726c3..cc9e61674 100644 --- a/packages/lib-ethers/etc/lib-ethers.api.md +++ b/packages/lib-ethers/etc/lib-ethers.api.md @@ -45,12 +45,12 @@ import { TroveWithPendingRedistribution } from '@liquity/lib-base'; // @public export class BlockPolledLiquityStore extends LiquityStore { - constructor(provider: Provider, account: string, liquity: ReadableEthersLiquity, frontendTag?: string); + constructor(connection: LiquityConnection, readableLiquity?: ReadableEthersLiquity, frontendTag?: string, userAddress?: string); // @override (undocumented) protected _doStart(): () => void; // @override (undocumented) protected _reduceExtra(oldState: BlockPolledLiquityStoreExtraState, stateUpdate: Partial): BlockPolledLiquityStoreExtraState; -} + } // @public export interface BlockPolledLiquityStoreExtraState { @@ -71,8 +71,6 @@ export interface EthersCallOverrides { from?: string; } -// Warning: (ae-forgotten-export) The symbol "GluedEthersLiquity" needs to be exported by the entry point index.d.ts -// // @public export class EthersLiquity extends GluedEthersLiquity { constructor(readable: ReadableEthersLiquity, populatable: PopulatableEthersLiquity); @@ -215,14 +213,14 @@ export class PopulatableEthersLiquity extends _PopulatableEthersLiquityBase impl export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { constructor(connection: LiquityConnection, readableLiquity: ReadableLiquity, store?: LiquityStore); // (undocumented) + protected readonly _connection: LiquityConnection; + // (undocumented) protected _findHints(trove: Trove): Promise<[string, string]>; // (undocumented) protected _findRedemptionHints(amount: Decimal): Promise<[string, string, string, Decimal]>; // (undocumented) protected readonly _readableLiquity: ReadableLiquity; // (undocumented) - protected readonly _signer: Signer; - // (undocumented) protected readonly _store?: LiquityStore; // (undocumented) protected _wrapCollateralGainTransfer(rawPopulatedTransaction: EthersPopulatedTransaction): PopulatedEthersLiquityTransaction; @@ -249,11 +247,11 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { // @public export class PopulatedEthersLiquityTransaction implements PopulatedLiquityTransaction> { // @internal - constructor(rawPopulatedTransaction: EthersPopulatedTransaction, parse: (rawReceipt: EthersTransactionReceipt) => T, signer: Signer, connection: LiquityConnection); + constructor(rawPopulatedTransaction: EthersPopulatedTransaction, connection: LiquityConnection, parse: (rawReceipt: EthersTransactionReceipt) => T); readonly rawPopulatedTransaction: EthersPopulatedTransaction; // (undocumented) send(): Promise>; - } +} // Warning: (ae-incompatible-release-tags) The symbol "ReadableEthersLiquity" is marked as @public, but its signature references "_EthersLiquityBase" which is marked as @internal // @@ -351,7 +349,7 @@ export class SendableEthersLiquity implements _SendableFrom implements SentLiquityTransaction> { // @internal - constructor(rawSentTransaction: EthersTransactionResponse, parse: (rawReceipt: EthersTransactionReceipt) => T, provider: Provider, connection: LiquityConnection); + constructor(rawSentTransaction: EthersTransactionResponse, connection: LiquityConnection, parse: (rawReceipt: EthersTransactionReceipt) => T); // (undocumented) getReceipt(): Promise>; readonly rawSentTransaction: EthersTransactionResponse; diff --git a/packages/lib-ethers/index.ts b/packages/lib-ethers/index.ts index 70e08eec4..8400afef8 100644 --- a/packages/lib-ethers/index.ts +++ b/packages/lib-ethers/index.ts @@ -1,4 +1,4 @@ -export { connectToLiquity, LiquityConnection, UnsupportedNetworkError } from "./src/contracts"; +export { connectToLiquity, LiquityConnection, UnsupportedNetworkError } from "./src/connection"; export * from "./src/types"; export * from "./src/ReadableEthersLiquity"; diff --git a/packages/lib-ethers/src/BlockPolledLiquityStore.ts b/packages/lib-ethers/src/BlockPolledLiquityStore.ts index 92c989533..c31016596 100644 --- a/packages/lib-ethers/src/BlockPolledLiquityStore.ts +++ b/packages/lib-ethers/src/BlockPolledLiquityStore.ts @@ -1,11 +1,18 @@ -import { AddressZero } from "@ethersproject/constants"; import { BigNumber } from "@ethersproject/bignumber"; import { Provider } from "@ethersproject/abstract-provider"; import { Decimal } from "@liquity/decimal"; -import { LiquityStore, LiquityStoreState, LiquityStoreBaseState } from "@liquity/lib-base"; +import { + LiquityStore, + LiquityStoreState, + LiquityStoreBaseState, + TroveWithPendingRedistribution, + StabilityDeposit, + LQTYStake +} from "@liquity/lib-base"; import { ReadableEthersLiquity } from "./ReadableEthersLiquity"; +import { LiquityConnection, _getProvider } from "./connection"; /** * Extra state added to {@link @liquity/lib-base#LiquityStoreState} by @@ -51,45 +58,66 @@ const decimalify = (bigNumber: BigNumber) => new Decimal(bigNumber); * @public */ export class BlockPolledLiquityStore extends LiquityStore { - private _provider: Provider; - private _account: string; - private _liquity: ReadableEthersLiquity; - private _frontendTag: string; + private readonly _provider: Provider; + private readonly _readableLiquity: ReadableEthersLiquity; + private readonly _frontendTag?: string; + private readonly _userAddress?: string; constructor( - provider: Provider, - account: string, - liquity: ReadableEthersLiquity, - frontendTag = AddressZero + connection: LiquityConnection, + readableLiquity?: ReadableEthersLiquity, + frontendTag?: string, + userAddress?: string ) { super(); - this._provider = provider; - this._account = account; - this._liquity = liquity; + this._provider = _getProvider(connection); + this._readableLiquity = readableLiquity ?? new ReadableEthersLiquity(connection); this._frontendTag = frontendTag; + this._userAddress = userAddress; } private _get(blockTag?: number): Promise { return promiseAllValues({ - frontend: this._liquity.getFrontendStatus(this._frontendTag, { blockTag }), - ownFrontend: this._liquity.getFrontendStatus(this._account, { blockTag }), - accountBalance: this._provider.getBalance(this._account, blockTag).then(decimalify), - lusdBalance: this._liquity.getLUSDBalance(this._account, { blockTag }), - lqtyBalance: this._liquity.getLQTYBalance(this._account, { blockTag }), - collateralSurplusBalance: this._liquity.getCollateralSurplusBalance(this._account, { - blockTag - }), - price: this._liquity.getPrice({ blockTag }), - numberOfTroves: this._liquity.getNumberOfTroves({ blockTag }), - troveWithoutRedistribution: this._liquity.getTroveWithoutRewards(this._account, { blockTag }), - totalRedistributed: this._liquity.getTotalRedistributed({ blockTag }), - deposit: this._liquity.getStabilityDeposit(this._account, { blockTag }), - total: this._liquity.getTotal({ blockTag }), - lusdInStabilityPool: this._liquity.getLUSDInStabilityPool({ blockTag }), - fees: this._liquity.getFees({ blockTag }), - lqtyStake: this._liquity.getLQTYStake(this._account, { blockTag }), - totalStakedLQTY: this._liquity.getTotalStakedLQTY({ blockTag }) + price: this._readableLiquity.getPrice({ blockTag }), + numberOfTroves: this._readableLiquity.getNumberOfTroves({ blockTag }), + totalRedistributed: this._readableLiquity.getTotalRedistributed({ blockTag }), + total: this._readableLiquity.getTotal({ blockTag }), + lusdInStabilityPool: this._readableLiquity.getLUSDInStabilityPool({ blockTag }), + fees: this._readableLiquity.getFees({ blockTag }), + totalStakedLQTY: this._readableLiquity.getTotalStakedLQTY({ blockTag }), + + frontend: this._frontendTag + ? this._readableLiquity.getFrontendStatus(this._frontendTag, { blockTag }) + : { status: "unregistered" }, + + ...(this._userAddress + ? { + accountBalance: this._provider.getBalance(this._userAddress, blockTag).then(decimalify), + lusdBalance: this._readableLiquity.getLUSDBalance(this._userAddress, { blockTag }), + lqtyBalance: this._readableLiquity.getLQTYBalance(this._userAddress, { blockTag }), + collateralSurplusBalance: this._readableLiquity.getCollateralSurplusBalance( + this._userAddress, + { blockTag } + ), + troveWithoutRedistribution: this._readableLiquity.getTroveWithoutRewards( + this._userAddress, + { blockTag } + ), + deposit: this._readableLiquity.getStabilityDeposit(this._userAddress, { blockTag }), + lqtyStake: this._readableLiquity.getLQTYStake(this._userAddress, { blockTag }), + ownFrontend: this._readableLiquity.getFrontendStatus(this._userAddress, { blockTag }) + } + : { + accountBalance: Decimal.ZERO, + lusdBalance: Decimal.ZERO, + lqtyBalance: Decimal.ZERO, + collateralSurplusBalance: Decimal.ZERO, + troveWithoutRedistribution: new TroveWithPendingRedistribution(), + deposit: new StabilityDeposit(), + lqtyStake: new LQTYStake(), + ownFrontend: { status: "unregistered" } + }) }); } diff --git a/packages/lib-ethers/src/EthersLiquity.ts b/packages/lib-ethers/src/EthersLiquity.ts index 2b28c84e3..96152ab25 100644 --- a/packages/lib-ethers/src/EthersLiquity.ts +++ b/packages/lib-ethers/src/EthersLiquity.ts @@ -4,7 +4,7 @@ import { Signer } from "@ethersproject/abstract-signer"; import { _glue } from "@liquity/lib-base"; -import { LiquityConnection, connectToLiquity } from "./contracts"; +import { LiquityConnection, connectToLiquity } from "./connection"; import { PopulatableEthersLiquity, diff --git a/packages/lib-ethers/src/EthersLiquityBase.ts b/packages/lib-ethers/src/EthersLiquityBase.ts index fb9a9a29b..57318ab1e 100644 --- a/packages/lib-ethers/src/EthersLiquityBase.ts +++ b/packages/lib-ethers/src/EthersLiquityBase.ts @@ -1,4 +1,4 @@ -import { LiquityConnection } from "./contracts"; +import { LiquityConnection } from "./connection"; /** @internal */ export class _EthersLiquityBase { diff --git a/packages/lib-ethers/src/ObservableEthersLiquity.ts b/packages/lib-ethers/src/ObservableEthersLiquity.ts index b430bb820..c843048fb 100644 --- a/packages/lib-ethers/src/ObservableEthersLiquity.ts +++ b/packages/lib-ethers/src/ObservableEthersLiquity.ts @@ -9,7 +9,7 @@ import { TroveWithPendingRedistribution } from "@liquity/lib-base"; -import { LiquityConnection, _getContracts } from "./contracts"; +import { LiquityConnection, _getContracts } from "./connection"; import { _EthersLiquityBase } from "./EthersLiquityBase"; import { ReadableEthersLiquity } from "./ReadableEthersLiquity"; diff --git a/packages/lib-ethers/src/PopulatableEthersLiquity.ts b/packages/lib-ethers/src/PopulatableEthersLiquity.ts index 482774097..507ecd36a 100644 --- a/packages/lib-ethers/src/PopulatableEthersLiquity.ts +++ b/packages/lib-ethers/src/PopulatableEthersLiquity.ts @@ -2,9 +2,7 @@ import assert from "assert"; import { AddressZero } from "@ethersproject/constants"; import { BigNumber, BigNumberish } from "@ethersproject/bignumber"; -import { Provider, Log } from "@ethersproject/abstract-provider"; -import { Signer } from "@ethersproject/abstract-signer"; -import { Contract } from "@ethersproject/contracts"; +import { Log } from "@ethersproject/abstract-provider"; import { Decimal, Decimalish } from "@liquity/decimal"; @@ -46,7 +44,8 @@ import { EthersTransactionResponse } from "./types"; -import { LiquityConnection, _getContracts, _priceFeedIsTestnet } from "./contracts"; +import { _priceFeedIsTestnet } from "./contracts"; +import { LiquityConnection, _getContracts, _getProvider, _getSigner } from "./connection"; import { logsToString } from "./parseLogs"; import { _EthersLiquityBase } from "./EthersLiquityBase"; @@ -118,28 +117,25 @@ export class SentEthersLiquityTransaction /** Ethers' representation of a sent transaction. */ readonly rawSentTransaction: EthersTransactionResponse; - private readonly _parse: (rawReceipt: EthersTransactionReceipt) => T; - private readonly _provider: Provider; private readonly _connection: LiquityConnection; + private readonly _parse: (rawReceipt: EthersTransactionReceipt) => T; /** @internal */ constructor( rawSentTransaction: EthersTransactionResponse, - parse: (rawReceipt: EthersTransactionReceipt) => T, - provider: Provider, - connection: LiquityConnection + connection: LiquityConnection, + parse: (rawReceipt: EthersTransactionReceipt) => T ) { this.rawSentTransaction = rawSentTransaction; - this._parse = parse; - this._provider = provider; this._connection = connection; + this._parse = parse; } private _receiptFrom(rawReceipt: EthersTransactionReceipt | null) { return rawReceipt ? rawReceipt.status ? _successfulReceipt(rawReceipt, this._parse(rawReceipt), () => - logsToString(rawReceipt, (this._connection as unknown) as Record) + logsToString(rawReceipt, _getContracts(this._connection)) ) : _failedReceipt(rawReceipt) : _pendingReceipt; @@ -148,14 +144,14 @@ export class SentEthersLiquityTransaction /** {@inheritDoc @liquity/lib-base#SentLiquityTransaction.getReceipt} */ async getReceipt(): Promise> { return this._receiptFrom( - await this._provider.getTransactionReceipt(this.rawSentTransaction.hash) + await _getProvider(this._connection).getTransactionReceipt(this.rawSentTransaction.hash) ); } /** {@inheritDoc @liquity/lib-base#SentLiquityTransaction.waitForReceipt} */ async waitForReceipt(): Promise> { const receipt = this._receiptFrom( - await this._provider.waitForTransaction(this.rawSentTransaction.hash) + await _getProvider(this._connection).waitForTransaction(this.rawSentTransaction.hash) ); assert(receipt.status !== "pending"); @@ -177,34 +173,26 @@ export class PopulatedEthersLiquityTransaction /** Unsigned transaction object populated by Ethers. */ readonly rawPopulatedTransaction: EthersPopulatedTransaction; - private readonly _parse: (rawReceipt: EthersTransactionReceipt) => T; - private readonly _signer: Signer; private readonly _connection: LiquityConnection; + private readonly _parse: (rawReceipt: EthersTransactionReceipt) => T; /** @internal */ constructor( rawPopulatedTransaction: EthersPopulatedTransaction, - parse: (rawReceipt: EthersTransactionReceipt) => T, - signer: Signer, - connection: LiquityConnection + connection: LiquityConnection, + parse: (rawReceipt: EthersTransactionReceipt) => T ) { this.rawPopulatedTransaction = rawPopulatedTransaction; - this._parse = parse; - this._signer = signer; this._connection = connection; + this._parse = parse; } /** {@inheritDoc @liquity/lib-base#PopulatedLiquityTransaction.send} */ async send(): Promise> { - if (!this._signer.provider) { - throw new Error("Signer must have a Provider"); - } - return new SentEthersLiquityTransaction( - await this._signer.sendTransaction(this.rawPopulatedTransaction), - this._parse, - this._signer.provider, - this._connection + await _getSigner(this._connection).sendTransaction(this.rawPopulatedTransaction), + this._connection, + this._parse ); } } @@ -218,23 +206,19 @@ export interface _TroveChangeWithFees { /** @internal */ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { + protected readonly _connection: LiquityConnection; protected readonly _readableLiquity: ReadableLiquity; protected readonly _store?: LiquityStore; - protected readonly _signer: Signer; constructor( connection: LiquityConnection, readableLiquity: ReadableLiquity, store?: LiquityStore ) { - if (!Signer.isSigner(connection.signerOrProvider)) { - throw new Error("Must be connected through a Signer"); - } - super(connection); + this._connection = connection; this._readableLiquity = readableLiquity; - this._signer = connection.signerOrProvider; this._store = store; } @@ -243,9 +227,8 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { ): PopulatedEthersLiquityTransaction { return new PopulatedEthersLiquityTransaction( rawPopulatedTransaction, - noDetails, - this._signer, - this._connection + this._connection, + noDetails ); } @@ -257,6 +240,7 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { return new PopulatedEthersLiquityTransaction( rawPopulatedTransaction, + this._connection, ({ logs }) => { const [newTrove] = borrowerOperations @@ -272,10 +256,7 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { newTrove, fee }; - }, - - this._signer, - this._connection + } ); } @@ -283,12 +264,12 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { rawPopulatedTransaction: EthersPopulatedTransaction ): Promise> { const { activePool, lusdToken } = _getContracts(this._connection); - const userAddress = await this._signer.getAddress(); return new PopulatedEthersLiquityTransaction( rawPopulatedTransaction, + this._connection, - ({ logs }) => { + ({ logs, from: userAddress }) => { const [repayLUSD] = lusdToken .extractEvents(logs, "Transfer") .filter(({ args: { from, to } }) => from === userAddress && to === AddressZero) @@ -302,10 +283,7 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { return { params: repayLUSD.nonZero ? { withdrawCollateral, repayLUSD } : { withdrawCollateral } }; - }, - - this._signer, - this._connection + } ); } @@ -316,6 +294,7 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { return new PopulatedEthersLiquityTransaction( rawPopulatedTransaction, + this._connection, ({ logs }) => { const liquidatedAddresses = troveManager @@ -338,10 +317,7 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { liquidatedAddresses, ...totals }; - }, - - this._signer, - this._connection + } ); } @@ -352,6 +328,7 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { return new PopulatedEthersLiquityTransaction( rawPopulatedTransaction, + this._connection, ({ logs }) => troveManager @@ -361,10 +338,7 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { actualLUSDAmount: new Decimal(_actualLUSDAmount), collateralTaken: new Decimal(_ETHSent), fee: new Decimal(_ETHFee) - }))[0], - - this._signer, - this._connection + }))[0] ); } @@ -398,9 +372,8 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { ): PopulatedEthersLiquityTransaction { return new PopulatedEthersLiquityTransaction( rawPopulatedTransaction, - ({ logs }) => this._extractStabilityPoolGainsWithdrawalDetails(logs), - this._signer, - this._connection + this._connection, + ({ logs }) => this._extractStabilityPoolGainsWithdrawalDetails(logs) ); } @@ -410,14 +383,12 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { ): PopulatedEthersLiquityTransaction { return new PopulatedEthersLiquityTransaction( rawPopulatedTransaction, + this._connection, ({ logs }) => ({ ...this._extractStabilityPoolGainsWithdrawalDetails(logs), change - }), - - this._signer, - this._connection + }) ); } @@ -425,12 +396,12 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { rawPopulatedTransaction: EthersPopulatedTransaction ): Promise> { const { stabilityPool, lusdToken } = _getContracts(this._connection); - const userAddress = await this._signer.getAddress(); return new PopulatedEthersLiquityTransaction( rawPopulatedTransaction, + this._connection, - ({ logs }) => { + ({ logs, from: userAddress }) => { const gainsWithdrawalDetails = this._extractStabilityPoolGainsWithdrawalDetails(logs); const [withdrawLUSD] = lusdToken @@ -442,10 +413,7 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { ...gainsWithdrawalDetails, change: { withdrawLUSD, withdrawAllLUSD: gainsWithdrawalDetails.newLUSDDeposit.isZero } }; - }, - - this._signer, - this._connection + } ); } @@ -456,6 +424,7 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { return new PopulatedEthersLiquityTransaction( rawPopulatedTransaction, + this._connection, ({ logs }) => { const [newTrove] = borrowerOperations @@ -466,10 +435,7 @@ export class _PopulatableEthersLiquityBase extends _EthersLiquityBase { ...this._extractStabilityPoolGainsWithdrawalDetails(logs), newTrove }; - }, - - this._signer, - this._connection + } ); } diff --git a/packages/lib-ethers/src/ReadableEthersLiquity.ts b/packages/lib-ethers/src/ReadableEthersLiquity.ts index 996fdcbcd..c4f65c9c1 100644 --- a/packages/lib-ethers/src/ReadableEthersLiquity.ts +++ b/packages/lib-ethers/src/ReadableEthersLiquity.ts @@ -12,9 +12,10 @@ import { } from "@liquity/lib-base"; import { MultiTroveGetter } from "../types"; + import { EthersCallOverrides } from "./types"; +import { LiquityConnection, _getContracts } from "./connection"; import { _EthersLiquityBase } from "./EthersLiquityBase"; -import { LiquityConnection, _getContracts } from "./contracts"; // TODO: these are constant in the contracts, so it doesn't make sense to make a call for them, // but to avoid having to update them here when we change them in the contracts, we could read diff --git a/packages/lib-ethers/src/connection.ts b/packages/lib-ethers/src/connection.ts new file mode 100644 index 000000000..c2fe5f371 --- /dev/null +++ b/packages/lib-ethers/src/connection.ts @@ -0,0 +1,137 @@ +import { Signer } from "@ethersproject/abstract-signer"; +import { Provider } from "@ethersproject/abstract-provider"; + +import { + _connectToContracts, + _LiquityContractAddresses, + _LiquityContracts, + _LiquityDeploymentJSON +} from "./contracts"; + +import devOrNull from "../deployments/dev.json"; +import goerli from "../deployments/goerli.json"; +import kovan from "../deployments/kovan.json"; +import rinkeby from "../deployments/rinkeby.json"; +import ropsten from "../deployments/ropsten.json"; + +const dev: _LiquityDeploymentJSON | null = devOrNull; + +const deployments: { + [network: string]: _LiquityDeploymentJSON; + [chainId: number]: _LiquityDeploymentJSON; +} = { + goerli, + kovan, + rinkeby, + ropsten, + + 3: ropsten, + 4: rinkeby, + 5: goerli, + 42: kovan, + + ...(dev !== null ? { [17]: dev, dev } : {}) +}; + +declare const brand: unique symbol; + +const branded = (t: Omit): T => t as T; + +export interface LiquityConnection { + readonly signerOrProvider: Signer | Provider; + + readonly addresses: Record; + readonly version: string; + readonly deploymentDate: number; + + /** @internal */ + readonly _priceFeedIsTestnet: boolean; + + /** @internal */ + readonly _isDev: boolean; + + /** @internal */ + readonly [brand]: unique symbol; +} + +/** @internal */ +export interface _LiquityConnection extends LiquityConnection { + readonly addresses: _LiquityContractAddresses; + readonly _contracts: _LiquityContracts; +} + +const connectedDeploymentFrom = ( + deployment: _LiquityDeploymentJSON, + signerOrProvider: Signer | Provider, + _contracts: _LiquityContracts +): _LiquityConnection => + branded({ + ...deployment, + signerOrProvider, + _contracts + }); + +/** @internal */ +export const _getContracts = (connection: LiquityConnection): _LiquityContracts => + (connection as _LiquityConnection)._contracts; + +/** @internal */ +export const _getSigner = (connection: LiquityConnection): Signer => { + if (!Signer.isSigner(connection.signerOrProvider)) { + throw new Error("Must be connected through a Signer"); + } + + return connection.signerOrProvider; +}; + +/** @internal */ +export const _getProvider = (connection: LiquityConnection): Provider => { + if (Signer.isSigner(connection.signerOrProvider)) { + if (!connection.signerOrProvider.provider) { + throw new Error("Signer must be connected to a Provider"); + } + + return connection.signerOrProvider.provider; + } else { + return connection.signerOrProvider; + } +}; + +export class UnsupportedNetworkError extends Error { + readonly unsupportedNetwork: string | number; + + /** @internal */ + constructor(unsupportedNetwork: string | number) { + super(`Unsupported network ${unsupportedNetwork}`); + this.name = "UnsupportedNetworkError"; + this.unsupportedNetwork = unsupportedNetwork; + } +} + +/** @internal */ +export const _connectToDeployment = ( + deployment: _LiquityDeploymentJSON, + signerOrProvider: Signer | Provider +): LiquityConnection => + connectedDeploymentFrom( + deployment, + signerOrProvider, + _connectToContracts(signerOrProvider, deployment) + ); + +export function connectToLiquity( + signerOrProvider: Signer | Provider, + network: string | number = "mainnet" +): LiquityConnection { + if (!(network in deployments)) { + throw new UnsupportedNetworkError(network); + } + + const deployment = deployments[network]; + + return connectedDeploymentFrom( + deployment, + signerOrProvider, + _connectToContracts(signerOrProvider, deployment) + ); +} diff --git a/packages/lib-ethers/src/contracts.ts b/packages/lib-ethers/src/contracts.ts index c3ac488db..6488c6b8a 100644 --- a/packages/lib-ethers/src/contracts.ts +++ b/packages/lib-ethers/src/contracts.ts @@ -30,12 +30,6 @@ import sortedTrovesAbi from "../abi/SortedTroves.json"; import stabilityPoolAbi from "../abi/StabilityPool.json"; import gasPoolAbi from "../abi/GasPool.json"; -import devOrNull from "../deployments/dev.json"; -import goerli from "../deployments/goerli.json"; -import kovan from "../deployments/kovan.json"; -import rinkeby from "../deployments/rinkeby.json"; -import ropsten from "../deployments/ropsten.json"; - import { ActivePool, BorrowerOperations, @@ -82,7 +76,7 @@ type EstimatedContractFunction = TypeSafeContract & +type TypedContract = TypeSafeContract & U & { [P in keyof V]: V[P] extends (...args: infer A) => unknown @@ -208,33 +202,6 @@ const mapLiquityContracts = ( Object.entries(contracts).map(([key, t]) => [key, f(t, key as LiquityContractsKey)]) ) as Record; -declare const brand: unique symbol; - -const branded = (t: Omit): T => t as T; - -export interface LiquityConnection { - readonly signerOrProvider: Signer | Provider; - - readonly addresses: Record; - readonly version: string; - readonly deploymentDate: number; - - /** @internal */ - readonly _priceFeedIsTestnet: boolean; - - /** @internal */ - readonly _isDev: boolean; - - /** @internal */ - readonly [brand]: unique symbol; -} - -/** @internal */ -export interface _LiquityConnection extends LiquityConnection { - readonly addresses: _LiquityContractAddresses; - readonly _contracts: _LiquityContracts; -} - /** @internal */ export interface _LiquityDeploymentJSON { readonly addresses: _LiquityContractAddresses; @@ -257,76 +224,3 @@ export const _connectToContracts = ( new LiquityContract(address, abi[key], signerOrProvider) as _TypedLiquityContract ) as _LiquityContracts; }; - -const dev = devOrNull as _LiquityDeploymentJSON | null; - -const deployments: { - [network: string]: _LiquityDeploymentJSON; - [chainId: number]: _LiquityDeploymentJSON; -} = { - goerli, - kovan, - rinkeby, - ropsten, - - 3: ropsten, - 4: rinkeby, - 5: goerli, - 42: kovan, - - ...(dev !== null ? { [17]: dev, dev } : {}) -}; - -const connectedDeploymentFrom = ( - deployment: _LiquityDeploymentJSON, - signerOrProvider: Signer | Provider, - _contracts: _LiquityContracts -): _LiquityConnection => - branded({ - ...deployment, - signerOrProvider, - _contracts - }); - -/** @internal */ -export const _getContracts = (connection: LiquityConnection): _LiquityContracts => - (connection as _LiquityConnection)._contracts; - -export class UnsupportedNetworkError extends Error { - readonly unsupportedNetwork: string | number; - - /** @internal */ - constructor(unsupportedNetwork: string | number) { - super(`Unsupported network ${unsupportedNetwork}`); - this.name = "UnsupportedNetworkError"; - this.unsupportedNetwork = unsupportedNetwork; - } -} - -/** @internal */ -export const _connectToDeployment = ( - deployment: _LiquityDeploymentJSON, - signerOrProvider: Signer | Provider -): LiquityConnection => - connectedDeploymentFrom( - deployment, - signerOrProvider, - _connectToContracts(signerOrProvider, deployment) - ); - -export function connectToLiquity( - signerOrProvider: Signer | Provider, - network: string | number = "mainnet" -): LiquityConnection { - if (!(network in deployments)) { - throw new UnsupportedNetworkError(network); - } - - const deployment = deployments[network]; - - return connectedDeploymentFrom( - deployment, - signerOrProvider, - _connectToContracts(signerOrProvider, deployment) - ); -} diff --git a/packages/lib-ethers/src/parseLogs.ts b/packages/lib-ethers/src/parseLogs.ts index 3d341730f..c286f766e 100644 --- a/packages/lib-ethers/src/parseLogs.ts +++ b/packages/lib-ethers/src/parseLogs.ts @@ -1,11 +1,16 @@ import { BigNumber } from "@ethersproject/bignumber"; import { AddressZero } from "@ethersproject/constants"; import { Log, TransactionReceipt } from "@ethersproject/abstract-provider"; -import { Contract } from "@ethersproject/contracts"; import { LogDescription, Interface } from "@ethersproject/abi"; import { Decimal } from "@liquity/decimal"; +import { _LiquityContracts, _TypedLiquityContract } from "./contracts"; + +type ContractLookup = { + [name: string]: _TypedLiquityContract; +}; + type InterfaceLookup = { [address: string]: Interface; }; @@ -14,15 +19,15 @@ type NameLookup = { [address: string]: string; }; -const interfaceLookupFrom = (contracts: Record): InterfaceLookup => { +const interfaceLookupFrom = (contractLookup: ContractLookup): InterfaceLookup => { return Object.fromEntries( - Object.entries(contracts).map(([, contract]) => [contract.address, contract.interface]) + Object.entries(contractLookup).map(([, contract]) => [contract.address, contract.interface]) ); }; -const nameLookupFrom = (contracts: Record): NameLookup => { +const nameLookupFrom = (contractLookup: ContractLookup): NameLookup => { return Object.fromEntries( - Object.entries(contracts).map(([name, contract]) => [contract.address, name]) + Object.entries(contractLookup).map(([name, contract]) => [contract.address, name]) ); }; @@ -94,12 +99,10 @@ const logDescriptionToString = (logDescription: LogDescription, nameLookup: Name return `${logDescription.name}({ ${prettyEntries.join(", ")} })`; }; -export const logsToString = ( - receipt: TransactionReceipt, - contracts: Record -): string => { - const interfaceLookup = interfaceLookupFrom(contracts); - const contractNameLookup = nameLookupFrom(contracts); +export const logsToString = (receipt: TransactionReceipt, contracts: _LiquityContracts): string => { + const contractLookup = (contracts as unknown) as ContractLookup; + const interfaceLookup = interfaceLookupFrom(contractLookup); + const contractNameLookup = nameLookupFrom(contractLookup); const nameLookup = { [receipt.from]: "user",