UNPKG

@ajna-finance/sdk

Version:

A typescript SDK that can be used to create Dapps in Ajna ecosystem.

195 lines 9.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FungiblePool = void 0; const tslib_1 = require("tslib"); const ethers_1 = require("ethers"); const constants_1 = require("../constants"); const erc20_1 = require("../contracts/erc20"); const erc20_pool_1 = require("../contracts/erc20-pool"); const pool_1 = require("../contracts/pool"); const types_1 = require("../types"); const numeric_1 = require("../utils/numeric"); const pricing_1 = require("../utils/pricing"); const time_1 = require("../utils/time"); const FungibleBucket_1 = require("./FungibleBucket"); const Pool_1 = require("./Pool"); /** * Models a pool with ERC-20 collateral. */ class FungiblePool extends Pool_1.Pool { constructor(provider, poolAddress, ajnaAddress) { super(provider, poolAddress, ajnaAddress, (0, erc20_pool_1.getErc20PoolContract)(poolAddress, provider), (0, erc20_pool_1.getErc20PoolContractMulti)(poolAddress)); } initialize() { const _super = Object.create(null, { initialize: { get: () => super.initialize } }); return tslib_1.__awaiter(this, void 0, void 0, function* () { yield _super.initialize.call(this); try { const collateralToken = (0, erc20_1.getErc20Contract)(this.collateralAddress, this.provider); this.collateralSymbol = (yield collateralToken.symbol()).replace(/"+/g, ''); } catch (e) { const collateralToken = (0, erc20_1.getDSTokenContract)(this.collateralAddress, this.provider); this.collateralSymbol = ethers_1.utils .parseBytes32String(yield collateralToken.symbol()) .replace(/"+/g, ''); } this.name = this.collateralSymbol + '-' + this.quoteSymbol; }); } toString() { return this.name + ' pool'; } /** * Approve this pool to manage collateral token. * @param signer pool user * @param allowance normalized approval amount (or MaxUint256) * @returns promise to transaction */ collateralApprove(signer, allowance) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const denormalizedAllowance = allowance.eq(ethers_1.constants.MaxUint256) ? allowance : allowance.div(yield (0, erc20_pool_1.collateralScale)(this.contract)); return (0, erc20_pool_1.approve)(signer, this.poolAddress, this.collateralAddress, denormalizedAllowance); }); } /** * Pledges collateral and draws debt. * @param signer borrower * @param amountToBorrow new debt to draw * @param collateralToPledge new collateral to deposit * @param limitIndex revert if loan would drop LUP below this bucket (or pass MAX_FENWICK_INDEX) * @returns promise to transaction */ drawDebt(signer, amountToBorrow, collateralToPledge, limitIndex) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const contractPoolWithSigner = this.contract.connect(signer); const borrowerAddress = yield signer.getAddress(); return (0, erc20_pool_1.drawDebt)(contractPoolWithSigner, borrowerAddress, amountToBorrow, limitIndex !== null && limitIndex !== void 0 ? limitIndex : constants_1.MAX_FENWICK_INDEX, collateralToPledge); }); } /** * Repays debt and pulls collateral. * @param signer borrower * @param maxQuoteTokenAmountToRepay amount for partial repayment, MaxUint256 for full repayment, 0 for no repayment * @param collateralAmountToPull amount of collateral to withdraw after repayment * @param limitIndex revert if LUP has moved below this bucket by the time the transaction is processed * @returns promise to transaction */ repayDebt(signer, maxQuoteTokenAmountToRepay, collateralAmountToPull, limitIndex) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const contractPoolWithSigner = this.contract.connect(signer); const sender = yield signer.getAddress(); return (0, erc20_pool_1.repayDebt)(contractPoolWithSigner, sender, maxQuoteTokenAmountToRepay, collateralAmountToPull, sender, limitIndex !== null && limitIndex !== void 0 ? limitIndex : constants_1.MAX_FENWICK_INDEX); }); } /** * Deposit collateral token into a bucket (not for borrowers). * @param signer address to be awarded LP * @param collateralAmountToAdd deposit amount * @param bucketIndex identifies the price bucket * @param ttlSeconds revert if not processed in this amount of time * @returns promise to transaction */ addCollateral(signer, bucketIndex, collateralAmountToAdd, ttlSeconds) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const contractPoolWithSigner = this.contract.connect(signer); return (0, erc20_pool_1.addCollateral)(contractPoolWithSigner, collateralAmountToAdd, bucketIndex, yield (0, time_1.getExpiry)(this.provider, ttlSeconds)); }); } /** * Withdraw collateral from a bucket (not for borrowers). * @param signer address to redeem LP * @param bucketIndex identifies the price bucket * @param maxAmount optionally limits amount to remove * @returns promise to transaction */ removeCollateral(signer_1, bucketIndex_1) { return tslib_1.__awaiter(this, arguments, void 0, function* (signer, bucketIndex, maxAmount = ethers_1.constants.MaxUint256) { const contractPoolWithSigner = this.contract.connect(signer); return (0, erc20_pool_1.removeCollateral)(contractPoolWithSigner, bucketIndex, maxAmount); }); } /** * @param bucketIndex fenwick index of the desired bucket * @returns {@link FungibleBucket} modeling bucket at specified index */ getBucketByIndex(bucketIndex) { const bucket = new FungibleBucket_1.FungibleBucket(this.provider, this, bucketIndex); return bucket; } /** * @param price price within range supported by Ajna * @returns {@link FungibleBucket} modeling bucket at nearest to specified price */ getBucketByPrice(price) { const bucketIndex = (0, pricing_1.priceToIndex)(price); // priceToIndex should throw upon invalid price const bucket = new FungibleBucket_1.FungibleBucket(this.provider, this, bucketIndex); return bucket; } /** * @param minPrice lowest desired price * @param maxPrice highest desired price * @returns array of {@link FungibleBucket}s between specified prices */ getBucketsByPriceRange(minPrice, maxPrice) { if (minPrice.gt(maxPrice)) throw new types_1.SdkError('maxPrice must exceed minPrice'); const buckets = new Array(); for (let index = (0, pricing_1.priceToIndex)(maxPrice); index <= (0, pricing_1.priceToIndex)(minPrice); index++) { buckets.push(new FungibleBucket_1.FungibleBucket(this.provider, this, index)); } return buckets; } /** * Withdraw all available liquidity from the given buckets using multicall transaction (first quote token, then - collateral if LP is left). * @param signer address to redeem LP * @param bucketIndices array of bucket indices to withdraw liquidity from * @returns promise to transaction */ withdrawLiquidity(signer, bucketIndices) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const signerAddress = yield signer.getAddress(); const callData = []; // get buckets const bucketPromises = bucketIndices.map(bucketIndex => this.getBucketByIndex(bucketIndex)); const buckets = yield Promise.all(bucketPromises); // get bucket details const bucketStatusPromises = buckets.map(bucket => bucket.getStatus()); const bucketStatuses = yield Promise.all(bucketStatusPromises); // determine lender's LP balance const lpBalancePromises = bucketIndices.map(bucketIndex => (0, pool_1.lenderInfo)(this.contract, signerAddress, bucketIndex)); const lpBalances = yield Promise.all(lpBalancePromises); for (let i = 0; i < bucketIndices.length; ++i) { const [lpBalance] = lpBalances[i]; const bucketStatus = bucketStatuses[i]; const bucketIndex = bucketIndices[i]; // if there is any quote token in the bucket, redeem LP for deposit first if (lpBalance && bucketStatus.deposit.gt(0)) { callData.push({ methodName: 'removeQuoteToken', args: [ethers_1.constants.MaxUint256, bucketIndex], }); } const depositWithdrawnEstimate = (0, numeric_1.wmul)(lpBalance, bucketStatus.exchangeRate); // CAUTION: This estimate may cause revert because we cannot predict exchange rate for an // arbitrary future block where the TX will be processed. const withdrawCollateral = (bucketStatus.deposit.eq(0) || depositWithdrawnEstimate.gt(bucketStatus.deposit)) && bucketStatus.collateral.gt(0); if (withdrawCollateral) { callData.push({ methodName: 'removeCollateral', args: [ethers_1.constants.MaxUint256, bucketIndex], }); } } return this.multicall(signer, callData); }); } } exports.FungiblePool = FungiblePool; //# sourceMappingURL=FungiblePool.js.map