UNPKG

@sovryn-zero/lib-ethers

Version:
368 lines 17.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReadableEthersLiquity = void 0; const lib_base_1 = require("@sovryn-zero/lib-base"); const EthersLiquityConnection_1 = require("./EthersLiquityConnection"); const BlockPolledLiquityStore_1 = require("./BlockPolledLiquityStore"); // 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 // them once after deployment and save them to LiquityDeployment. const MINUTE_DECAY_FACTOR = lib_base_1.Decimal.from("0.999037758833783000"); const BETA = lib_base_1.Decimal.from(2); var BackendTroveStatus; (function (BackendTroveStatus) { BackendTroveStatus[BackendTroveStatus["nonExistent"] = 0] = "nonExistent"; BackendTroveStatus[BackendTroveStatus["active"] = 1] = "active"; BackendTroveStatus[BackendTroveStatus["closedByOwner"] = 2] = "closedByOwner"; BackendTroveStatus[BackendTroveStatus["closedByLiquidation"] = 3] = "closedByLiquidation"; BackendTroveStatus[BackendTroveStatus["closedByRedemption"] = 4] = "closedByRedemption"; })(BackendTroveStatus || (BackendTroveStatus = {})); const panic = (error) => { throw error; }; const userTroveStatusFrom = (backendStatus) => backendStatus === BackendTroveStatus.nonExistent ? "nonExistent" : backendStatus === BackendTroveStatus.active ? "open" : backendStatus === BackendTroveStatus.closedByOwner ? "closedByOwner" : backendStatus === BackendTroveStatus.closedByLiquidation ? "closedByLiquidation" : backendStatus === BackendTroveStatus.closedByRedemption ? "closedByRedemption" : panic(new Error(`invalid backendStatus ${backendStatus}`)); const decimalify = (bigNumber) => lib_base_1.Decimal.fromBigNumberString(bigNumber.toHexString()); const convertToDate = (timestamp) => new Date(timestamp * 1000); const validSortingOptions = ["ascendingCollateralRatio", "descendingCollateralRatio"]; const expectPositiveInt = (obj, key) => { if (obj[key] !== undefined) { if (!Number.isInteger(obj[key])) { throw new Error(`${key} must be an integer`); } if (obj[key] < 0) { throw new Error(`${key} must not be negative`); } } }; /** * Ethers-based implementation of {@link @sovryn-zero/lib-base#ReadableLiquity}. * * @public */ class ReadableEthersLiquity { /** @internal */ constructor(connection) { this.connection = connection; } /** @internal */ static _from(connection) { const readable = new ReadableEthersLiquity(connection); return connection.useStore === "blockPolled" ? new _BlockPolledReadableEthersLiquity(readable) : readable; } /** * Connect to the Zero protocol and create a `ReadableEthersLiquity` 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 async connect(signerOrProvider, optionalParams) { return ReadableEthersLiquity._from(await EthersLiquityConnection_1._connect(signerOrProvider, optionalParams)); } hasStore() { return false; } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getTotalRedistributed} */ async getTotalRedistributed(overrides) { const { troveManager } = EthersLiquityConnection_1._getContracts(this.connection); const [collateral, debt] = await Promise.all([ troveManager.L_ETH({ ...overrides }).then(decimalify), troveManager.L_ZUSDDebt({ ...overrides }).then(decimalify) ]); return new lib_base_1.Trove(collateral, debt); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getTroveBeforeRedistribution} */ async getTroveBeforeRedistribution(address, overrides) { address !== null && address !== void 0 ? address : (address = EthersLiquityConnection_1._requireAddress(this.connection)); const { troveManager } = EthersLiquityConnection_1._getContracts(this.connection); const [trove, snapshot] = await Promise.all([ troveManager.Troves(address, { ...overrides }), troveManager.rewardSnapshots(address, { ...overrides }) ]); if (trove.status === BackendTroveStatus.active) { return new lib_base_1.TroveWithPendingRedistribution(address, userTroveStatusFrom(trove.status), decimalify(trove.coll), decimalify(trove.debt), decimalify(trove.stake), new lib_base_1.Trove(decimalify(snapshot.ETH), decimalify(snapshot.ZUSDDebt))); } else { return new lib_base_1.TroveWithPendingRedistribution(address, userTroveStatusFrom(trove.status)); } } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getTrove} */ async getTrove(address, overrides) { const [trove, totalRedistributed] = await Promise.all([ this.getTroveBeforeRedistribution(address, overrides), this.getTotalRedistributed(overrides) ]); return trove.applyRedistribution(totalRedistributed); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getNumberOfTroves} */ async getNumberOfTroves(overrides) { const { troveManager } = EthersLiquityConnection_1._getContracts(this.connection); return (await troveManager.getTroveOwnersCount({ ...overrides })).toNumber(); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getPrice} */ getPrice(overrides) { const { priceFeed } = EthersLiquityConnection_1._getContracts(this.connection); return priceFeed.callStatic.fetchPrice({ ...overrides }).then(decimalify); } /** @internal */ async _getActivePool(overrides) { const { activePool } = EthersLiquityConnection_1._getContracts(this.connection); const [activeCollateral, activeDebt] = await Promise.all([ activePool.getETH({ ...overrides }), activePool.getZUSDDebt({ ...overrides }) ].map(getBigNumber => getBigNumber.then(decimalify))); return new lib_base_1.Trove(activeCollateral, activeDebt); } /** @internal */ async _getDefaultPool(overrides) { const { defaultPool } = EthersLiquityConnection_1._getContracts(this.connection); const [liquidatedCollateral, closedDebt] = await Promise.all([ defaultPool.getETH({ ...overrides }), defaultPool.getZUSDDebt({ ...overrides }) ].map(getBigNumber => getBigNumber.then(decimalify))); return new lib_base_1.Trove(liquidatedCollateral, closedDebt); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getTotal} */ async getTotal(overrides) { const [activePool, defaultPool] = await Promise.all([ this._getActivePool(overrides), this._getDefaultPool(overrides) ]); return activePool.add(defaultPool); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getStabilityDeposit} */ async getStabilityDeposit(address, overrides) { address !== null && address !== void 0 ? address : (address = EthersLiquityConnection_1._requireAddress(this.connection)); const { stabilityPool } = EthersLiquityConnection_1._getContracts(this.connection); const [{ frontEndTag, initialValue }, currentZUSD, collateralGain, zeroReward] = await Promise.all([ stabilityPool.deposits(address, { ...overrides }), stabilityPool.getCompoundedZUSDDeposit(address, { ...overrides }), stabilityPool.getDepositorETHGain(address, { ...overrides }), stabilityPool.getDepositorSOVGain(address, { ...overrides }) ]); return new lib_base_1.StabilityDeposit(decimalify(initialValue), decimalify(currentZUSD), decimalify(collateralGain), decimalify(zeroReward), frontEndTag); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getZUSDInStabilityPool} */ getZUSDInStabilityPool(overrides) { const { stabilityPool } = EthersLiquityConnection_1._getContracts(this.connection); return stabilityPool.getTotalZUSDDeposits({ ...overrides }).then(decimalify); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getZUSDBalance} */ getZUSDBalance(address, overrides) { address !== null && address !== void 0 ? address : (address = EthersLiquityConnection_1._requireAddress(this.connection)); const { zusdToken } = EthersLiquityConnection_1._getContracts(this.connection); return zusdToken.balanceOf(address, { ...overrides }).then(decimalify); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getZEROBalance} */ getZEROBalance(address, overrides) { address !== null && address !== void 0 ? address : (address = EthersLiquityConnection_1._requireAddress(this.connection)); const { zeroToken } = EthersLiquityConnection_1._getContracts(this.connection); return zeroToken.balanceOf(address, { ...overrides }).then(decimalify); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getCollateralSurplusBalance} */ getCollateralSurplusBalance(address, overrides) { address !== null && address !== void 0 ? address : (address = EthersLiquityConnection_1._requireAddress(this.connection)); const { collSurplusPool } = EthersLiquityConnection_1._getContracts(this.connection); return collSurplusPool.getCollateral(address, { ...overrides }).then(decimalify); } async getTroves(params, overrides) { var _a, _b; const { multiTroveGetter } = EthersLiquityConnection_1._getContracts(this.connection); expectPositiveInt(params, "first"); expectPositiveInt(params, "startingAt"); if (!validSortingOptions.includes(params.sortedBy)) { throw new Error(`sortedBy must be one of: ${validSortingOptions.map(x => `"${x}"`).join(", ")}`); } const [totalRedistributed, backendTroves] = await Promise.all([ params.beforeRedistribution ? undefined : this.getTotalRedistributed({ ...overrides }), multiTroveGetter.getMultipleSortedTroves(params.sortedBy === "descendingCollateralRatio" ? (_a = params.startingAt) !== null && _a !== void 0 ? _a : 0 : -(((_b = params.startingAt) !== null && _b !== void 0 ? _b : 0) + 1), params.first, { ...overrides }) ]); const troves = mapBackendTroves(backendTroves); if (totalRedistributed) { return troves.map(trove => trove.applyRedistribution(totalRedistributed)); } else { return troves; } } /** @internal */ async _getFeesFactory(overrides) { const { troveManager } = EthersLiquityConnection_1._getContracts(this.connection); const [lastFeeOperationTime, baseRateWithoutDecay] = await Promise.all([ troveManager.lastFeeOperationTime({ ...overrides }), troveManager.baseRate({ ...overrides }).then(decimalify) ]); return (blockTimestamp, recoveryMode) => new lib_base_1.Fees(baseRateWithoutDecay, MINUTE_DECAY_FACTOR, BETA, convertToDate(lastFeeOperationTime.toNumber()), convertToDate(blockTimestamp), recoveryMode); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getFees} */ async getFees(overrides) { const [createFees, total, price, blockTimestamp] = await Promise.all([ this._getFeesFactory(overrides), this.getTotal(overrides), this.getPrice(overrides), EthersLiquityConnection_1._getBlockTimestamp(this.connection, overrides === null || overrides === void 0 ? void 0 : overrides.blockTag) ]); return createFees(blockTimestamp, total.collateralRatioIsBelowCritical(price)); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getZEROStake} */ async getZEROStake(address, overrides) { address !== null && address !== void 0 ? address : (address = EthersLiquityConnection_1._requireAddress(this.connection)); const { zeroStaking } = EthersLiquityConnection_1._getContracts(this.connection); const [stakedZERO, collateralGain, zusdGain] = await Promise.all([ zeroStaking.stakes(address, { ...overrides }), zeroStaking.getPendingETHGain(address, { ...overrides }), zeroStaking.getPendingZUSDGain(address, { ...overrides }) ].map(getBigNumber => getBigNumber.then(decimalify))); return new lib_base_1.ZEROStake(stakedZERO, collateralGain, zusdGain); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getTotalStakedZERO} */ async getTotalStakedZERO(overrides) { const { zeroStaking } = EthersLiquityConnection_1._getContracts(this.connection); return zeroStaking.totalZEROStaked({ ...overrides }).then(decimalify); } /** {@inheritDoc @sovryn-zero/lib-base#ReadableLiquity.getFrontendStatus} */ async getFrontendStatus(address, overrides) { address !== null && address !== void 0 ? address : (address = EthersLiquityConnection_1._requireFrontendAddress(this.connection)); const { stabilityPool } = EthersLiquityConnection_1._getContracts(this.connection); const { registered, kickbackRate } = await stabilityPool.frontEnds(address, { ...overrides }); return registered ? { status: "registered", kickbackRate: decimalify(kickbackRate) } : { status: "unregistered" }; } } exports.ReadableEthersLiquity = ReadableEthersLiquity; const mapBackendTroves = (troves) => troves.map(trove => new lib_base_1.TroveWithPendingRedistribution(trove.owner, "open", // These Troves are coming from the SortedTroves list, so they must be open decimalify(trove.coll), decimalify(trove.debt), decimalify(trove.stake), new lib_base_1.Trove(decimalify(trove.snapshotETH), decimalify(trove.snapshotZUSDDebt)))); class BlockPolledLiquityStoreBasedCache { constructor(store) { this._store = store; } _blockHit(overrides) { return (!overrides || overrides.blockTag === undefined || overrides.blockTag === this._store.state.blockTag); } _userHit(address, overrides) { return (this._blockHit(overrides) && (address === undefined || address === this._store.connection.userAddress)); } _frontendHit(address, overrides) { return (this._blockHit(overrides) && (address === undefined || address === this._store.connection.frontendTag)); } getTotalRedistributed(overrides) { if (this._blockHit(overrides)) { return this._store.state.totalRedistributed; } } getTroveBeforeRedistribution(address, overrides) { if (this._userHit(address, overrides)) { return this._store.state.troveBeforeRedistribution; } } getTrove(address, overrides) { if (this._userHit(address, overrides)) { return this._store.state.trove; } } getNumberOfTroves(overrides) { if (this._blockHit(overrides)) { return this._store.state.numberOfTroves; } } getPrice(overrides) { if (this._blockHit(overrides)) { return this._store.state.price; } } getTotal(overrides) { if (this._blockHit(overrides)) { return this._store.state.total; } } getStabilityDeposit(address, overrides) { if (this._userHit(address, overrides)) { return this._store.state.stabilityDeposit; } } getZUSDInStabilityPool(overrides) { if (this._blockHit(overrides)) { return this._store.state.zusdInStabilityPool; } } getZUSDBalance(address, overrides) { if (this._userHit(address, overrides)) { return this._store.state.zusdBalance; } } getZEROBalance(address, overrides) { if (this._userHit(address, overrides)) { return this._store.state.zeroBalance; } } getCollateralSurplusBalance(address, overrides) { if (this._userHit(address, overrides)) { return this._store.state.collateralSurplusBalance; } } getFees(overrides) { if (this._blockHit(overrides)) { return this._store.state.fees; } } getZEROStake(address, overrides) { if (this._userHit(address, overrides)) { return this._store.state.zeroStake; } } getTotalStakedZERO(overrides) { if (this._blockHit(overrides)) { return this._store.state.totalStakedZERO; } } getFrontendStatus(address, overrides) { if (this._frontendHit(address, overrides)) { return this._store.state.frontend; } } getTroves() { return undefined; } } class _BlockPolledReadableEthersLiquity extends lib_base_1._CachedReadableLiquity { constructor(readable) { const store = new BlockPolledLiquityStore_1.BlockPolledLiquityStore(readable); super(readable, new BlockPolledLiquityStoreBasedCache(store)); this.store = store; this.connection = readable.connection; } hasStore(store) { return store === undefined || store === "blockPolled"; } _getActivePool() { throw new Error("Method not implemented."); } _getDefaultPool() { throw new Error("Method not implemented."); } _getFeesFactory() { throw new Error("Method not implemented."); } _getRemainingLiquidityMiningZERORewardCalculator() { throw new Error("Method not implemented."); } } //# sourceMappingURL=ReadableEthersLiquity.js.map