From 6118232048f9b0d7577a74fd61a6a01515aab8cf Mon Sep 17 00:00:00 2001 From: Anil Helvaci Date: Mon, 16 May 2022 12:26:46 +0300 Subject: [PATCH] #7 Local chain deployment refactored, commands for the borrow offer being done via repl is added. --- contract/deploy/deploy.js | 67 +++++++++++- contract/deploy/replCommands.md | 102 ++++++++++++++++++ .../src/lendingPool/debtsPerCollateral.js | 5 +- contract/src/lendingPool/lendingPool.js | 14 ++- contract/src/lendingPool/poolManager.js | 4 +- .../src/lendingPool/priceManagerContract.js | 58 ++++++++++ contract/src/lendingPool/vault.js | 2 +- contract/test/lendingPool/helpers.js | 19 ++++ 8 files changed, 260 insertions(+), 11 deletions(-) create mode 100644 contract/src/lendingPool/priceManagerContract.js diff --git a/contract/deploy/deploy.js b/contract/deploy/deploy.js index a4d9778..e3ea64e 100644 --- a/contract/deploy/deploy.js +++ b/contract/deploy/deploy.js @@ -7,7 +7,7 @@ import { } from '../test/lendingPool/setup.js'; import { E } from '@agoric/eventual-send'; import '@agoric/zoe/src/contractSupport/index.js'; -import { depositMoney, addPool, makeRates, setupAssets, makeBundle, getLiquidityFromFaucet } from '../test/lendingPool/helpers.js'; +import { depositMoney, addPool, makeRates, setupAssets, makeBundle, getLiquidityFromFaucet, startPriceManager } from '../test/lendingPool/helpers.js'; import { makePriceManager } from '../src/lendingPool/priceManager.js'; import { startLendingPool, startFaucets } from '../test/lendingPool/helpers.js'; import { AmountMath, AssetKind, makeIssuerKit } from '@agoric/ertp'; @@ -18,6 +18,7 @@ const contractRoots = { priceAuthorityFaucet: './priceAuthorityFaucet.js', liquidate: '../../src/lendingPool/liquidateMinimum.js', LendingPool: '../../src/lendingPool/lendingPool.js', + priceManagerContract: '../../src/lendingPool/priceManagerContract.js', }; const setupAmmAndElectorate = async (timer, @@ -108,6 +109,7 @@ export default async function deployContract( priceAuthorityFaucet: makeBundle(bundleSource, contractRoots.priceAuthorityFaucet), liquidate: makeBundle(bundleSource, contractRoots.liquidate), LendingPool: makeBundle(bundleSource, contractRoots.LendingPool), + priceManagerContract: makeBundle(bundleSource, contractRoots.priceManagerContract), }; const faucetBundles = await Collect.allValues({ @@ -147,6 +149,12 @@ export default async function deployContract( quoteInterval: secondsPerDay * 7n, }); + const priceManBundle = await Collect.allValues({ + priceManagerContract: bundlePs.priceManagerContract, + }); + + const { priceAuthorityManagerPublicFacet: priceManager, priceAuthorityManagerInstance } = await startPriceManager(zoe, priceManBundle); + // console.log("vanUsdPriceAuthority", vanUsdPriceAuthority); // console.log("panUsdPriceAuthority", panUsdPriceAuthority); @@ -199,7 +207,7 @@ export default async function deployContract( const { consume, produce } = space; const quoteMint = makeIssuerKit('quote', AssetKind.SET).mint; - const priceManager = makePriceManager({}); + // const priceManager = makePriceManager({}); produce.priceManager.resolve(priceManager); const vaultBundles = await Collect.allValues({ LendingPool: bundlePs.LendingPool, @@ -248,6 +256,7 @@ export default async function deployContract( AGPAN_ISSUER_BOARD_ID, PRICE_AUTHORITY_FAUCET_INSTALL_BOARD_ID, LENDING_POOL_FAUCET_INSTALL_BOARD_ID, + PRICE_MANAGER_INSTANCE_BOARD_ID, ] = await Promise.all([ E(board).getId(lendingPoolInstance), E(board).getId(lendingPoolInstallations.LendingPool), @@ -262,6 +271,7 @@ export default async function deployContract( E(board).getId(agPanIssuer), E(board).getId(installations.priceAuthorityFaucet), E(board).getId(installations.lendingPoolFaucet), + E(board).getId(priceAuthorityManagerInstance), ]); const walletBridge = await E(wallet).getBridge(); @@ -291,6 +301,27 @@ export default async function deployContract( const vanLiquidityOfferID = await E(walletBridge).addOffer(vanLiquidityOfferConfig); + let panLiqInvitation = await E(panAsset.creatorFacet).makeFaucetInvitation(); + + const panLiquidityOfferConfig = { + id: `${Date.now()}`, + invitation: panLiqInvitation, + installationHandleBoardId: LENDING_POOL_FAUCET_INSTALL_BOARD_ID, + instanceHandleBoardId: PAN_ASSET_INSTANCE_BOARD_ID, + proposalTemplate: { + give: {}, + want: { + PAN: { + // The pursePetname identifies which purse we want to use + pursePetname: 'PAN Purse', + value: 10n * 10n ** 8n , + }, + }, + }, + }; + + const panLiquidityOfferID = await E(walletBridge).addOffer(panLiquidityOfferConfig); + const depositVanOfferConfig = { id: `${Date.now()}`, invitation: E(vanPoolMan).makeDepositInvitation(), @@ -317,6 +348,32 @@ export default async function deployContract( console.log("depositVanOfferConfig", depositVanOfferConfig); const depositVanfferID = await E(walletBridge).addOffer(depositVanOfferConfig); + const depositPanOfferConfig = { + id: `${Date.now()}`, + invitation: E(panPoolMan).makeDepositInvitation(), + installationHandleBoardId: LENDING_POOL_INSTALL_BOARD_ID, + instanceHandleBoardId: LENDING_POOL_INSTANCE_BOARD_ID, + proposalTemplate: { + want: { + Protocol: { + // The pursePetname identifies which purse we want to uselib + pursePetname: 'AgPAN Purse', + value: 10n * 10n ** 8n * 50n , + }, + }, + give: { + Underlying: { + // The pursePetname identifies which purse we want to use + pursePetname: 'PAN Purse', + value: 10n * 10n ** 8n , + }, + }, + }, + }; + + console.log("depositPanOfferConfig", depositPanOfferConfig); + const depositPanOfferID = await E(walletBridge).addOffer(depositPanOfferConfig); + console.log(`-- LENDING_POOL_INSTANCE_BOARD_ID: ${LENDING_POOL_INSTANCE_BOARD_ID} --`); console.log(`-- LENDING_POOL_INSTALL_BOARD_ID: ${LENDING_POOL_INSTALL_BOARD_ID} --`); console.log(`-- VAN_ASSET_INSTANCE_BOARD_ID: ${VAN_ASSET_INSTANCE_BOARD_ID} --`); @@ -330,6 +387,10 @@ export default async function deployContract( console.log(`-- AGPAN_ISSUER_BOARD_ID: ${AGPAN_ISSUER_BOARD_ID} --`); console.log(`-- PRICE_AUTHORITY_FAUCET_INSTALL_BOARD_ID: ${PRICE_AUTHORITY_FAUCET_INSTALL_BOARD_ID} --`); console.log(`-- LENDING_POOL_FAUCET_INSTALL_BOARD_ID: ${LENDING_POOL_FAUCET_INSTALL_BOARD_ID} --`); - console.log(`-- LIQUIDITY_OFFER_ID: ${vanLiquidityOfferID} --`); + console.log(`-- VAN_LIQUIDITY_OFFER_ID: ${vanLiquidityOfferID} --`); + console.log(`-- PAN_LIQUIDITY_OFFER_ID: ${panLiquidityOfferID} --`); console.log(`-- DEPOSIT_VAN_OFFER_ID: ${depositVanfferID} --`); + console.log(`-- DEPOSIT_PAN_OFFER_ID: ${depositPanOfferID} --`); + console.log(`-- PRICE_MANAGER_INSTANCE_BOARD_ID: ${PRICE_MANAGER_INSTANCE_BOARD_ID} --`); + // console.log(`-- BORROW_PAN_OFFER_ID: ${borrowPanOfferID} --`); } \ No newline at end of file diff --git a/contract/deploy/replCommands.md b/contract/deploy/replCommands.md index 97ea55f..7e23099 100644 --- a/contract/deploy/replCommands.md +++ b/contract/deploy/replCommands.md @@ -74,4 +74,106 @@ command[23] E(vanPoolMan).getUnderlyingLiquidity() history[23] 200000000n command[24] E(vanPoolMan).getProtocolLiquidity() history[24] 10000000000n +```` + +### Borrow +Here we are taking a different approach from the walletBridge approach we used for the deposit functionality. The reason for that +is the agoric verion we currently have does not support sending optional offerArgs to the contract and we need the offerArgs +for out borrowing function to work. In the upcoming versions this is fixed and the below interaction with contract is +only for demonstration purpuses. A real dapp will never use E(zoe).offer() by itself. + +All board IDs you see here is taken from the console output of the ./deploy.js. + +````js +// Get Brands and issuers + +// VAN +command[24] E(home.board).getValue("board00443") +history[24] [Object Alleged: VAN issuer]{} +command[25] vanIssuer = history[24] +history[25] [Object Alleged: VAN issuer]{} +command[26] E(vanIssuer).getBrand() +history[26] [Object Alleged: VAN brand]{} +command[27] vanBrand = history[26] +history[27] [Object Alleged: VAN brand]{} + + +// PAN +command[28] E(home.board).getValue("board01744") +history[28] [Object Alleged: PAN issuer]{} +command[29] panIssuer = history[28] +history[29] [Object Alleged: PAN issuer]{} +command[30] E(panIssuer).getBrand() +history[30] [Object Alleged: PAN brand]{} +command[31] panBrand = history[30] +history[31] [Object Alleged: PAN brand]{} + +// AgVAN +command[37] E(home.board).getValue("board03446") +history[37] [Object Alleged: AgVAN issuer]{} +command[38] agVanIssuer = history[37] +history[38] [Object Alleged: AgVAN issuer]{} +command[39] E(agVanIssuer).getBrand() +history[39] [Object Alleged: AgVAN brand]{} +command[42] agVanBrand = history[39] +history[42] [Object Alleged: AgVAN brand]{} + +// Get the purse for AgVAN +command[36] E(home.wallet).getPurse("AgVAN Purse-1") +history[36] [Object Alleged: AgVAN purse]{} + +// Build the proposal + +// Get lendingPoolPublicFacet +command[21] E(home.board).getValue("board02437") +history[21] [Object Alleged: InstanceHandle]{} +command[22] E(home.zoe).getPublicFacet(history[21]) +history[22] [Object Alleged: lending pool public facet]{} +command[23] lendingPoolPublicFacet = history[22] +history[23] [Object Alleged: lending pool public facet]{} + +// AmountKeywordRecord for give +command[43] E(lendingPoolPublicFacet).getAmountKeywordRecord("Collateral", agVanBrand, 10n ** 8n * 50n) +history[43] {"Collateral":{"brand":[Object Alleged: AgVAN brand]{},"value":5000000000n}} + +// AmountKeywordRecord for want +command[44] E(lendingPoolPublicFacet).getAmountKeywordRecord("Debt", panBrand, 4n * 10n ** 6n) +history[44] {"Debt":{"brand":[Object Alleged: PAN brand]{},"value":4000000n}} + +borrowProposalOne = {want: history[44], give: history[43]} + +//Prepare the payment +command[47] E(history[36]).withdraw(borrowProposalOne.give.Collateral) // history[36] corresponds to the purse we got from the wallet +history[47] [Object Alleged: AgVAN payment]{} + +// Build the offer +command[48] E(home.zoe).offer(E(lendingPoolPublicFacet).makeBorrowInvitation(), borrowProposalOne, {Collateral: history[47]}, {collateralUnderlyingBrand: vanBrand}) +history[48] [Object Alleged: userSeat]{} +// Check for results +command[52] E(history[48]).getOfferResult() // This might take a while +history[52] {"assetNotifier":[Object Alleged: notifier]{},"invitationMakers":[Object Alleged: invitation makers]{},"vault":[Object Alleged: vault]{},"vaultNotifier":[Object Alleged: notifier]{},"vaultUpdater":[Object Alleged: updater]{}} + +// Get payout +command[51] E(history[48]).getPayout("Debt") +history[51] [Object Alleged: PAN payment]{} + +// Check Payment +command[53] E(panIssuer).getAmountOf(history[51]) +history[53] {"brand":[Object Alleged: PAN brand]{},"value":4000000n} + +// Get purse for PAN +command[54] E(home.wallet).getPurse("PAN Purse-1") +history[54] [Object Alleged: PAN purse]{} + +// Put the money inside the purse +command[55] E(history[54]).deposit(history[51]) +history[55] {"brand":[Object Alleged: PAN brand]{},"value":4000000n} + +// Check the parameters +command[59] E(panPoolMan).getTotalDebt() +history[59] {"brand":[Object Alleged: PAN brand]{},"value":4003920n} +command[60] E(panPoolMan).getCurrentBorrowingRate() +history[60] {"denominator":{"brand":[Object Alleged: PAN brand]{},"value":10000n},"numerator":{"brand":[Object Alleged: PAN brand]{},"value":259n}} +command[61] E(panPoolMan).getExchangeRate() +history[61] {"denominator":{"brand":[Object Alleged: AgPAN brand]{},"value":10000n},"numerator":{"brand":[Object Alleged: PAN brand]{},"value":201n}} ```` \ No newline at end of file diff --git a/contract/src/lendingPool/debtsPerCollateral.js b/contract/src/lendingPool/debtsPerCollateral.js index 56a39ea..c621ac4 100644 --- a/contract/src/lendingPool/debtsPerCollateral.js +++ b/contract/src/lendingPool/debtsPerCollateral.js @@ -29,13 +29,14 @@ export const makeDebtsPerCollateral = ( timer, timingParams, ) => { + console.log("making makeDebtsPerCollateral") const collateralDisplayInfoP = E(collateralBrand).getDisplayInfo(); const debtDisplayInfoP = E(manager.getUnderlyingBrand()).getDisplayInfo(); let vaultCounter = 0; /** @type {MapStore} */ const vaults = makeScalarMap('vaults'); const vaultsToLiquidate = makeScalarMap('vaultsToLiquidate'); - + console.log("making makeQuoteManager") const quoteManager = makeQuoteManager(); // initialize notifiers @@ -78,7 +79,7 @@ export const makeDebtsPerCollateral = ( const addNewVault = async (seat, underlyingAssetSeat, exchangeRate) => { vaultCounter += 1; const vaultId = String(vaultCounter); - + console.log("addNewVault") const innerVault = makeInnerVault( zcf, manager, diff --git a/contract/src/lendingPool/lendingPool.js b/contract/src/lendingPool/lendingPool.js index d857daa..b32e074 100644 --- a/contract/src/lendingPool/lendingPool.js +++ b/contract/src/lendingPool/lendingPool.js @@ -144,10 +144,11 @@ export const start = async (zcf, privateArgs) => { want: { Debt: null }, }); - assert(typeof offerArgs == 'object'); - assert(offerArgs.hasOwnProperty('collateralUnderlyingBrand')); + console.log("*[OFFER_ARGS]*", offerArgs); + assert(typeof offerArgs == 'object', "[NO_OFFER_ARGS]"); + assert(offerArgs.hasOwnProperty('collateralUnderlyingBrand'), "[NO_OFFER_ARGS]"); const collateralUnderlyingBrand = offerArgs.collateralUnderlyingBrand; - + console.log("*[collateralUnderlyingBrand]*", collateralUnderlyingBrand); const currentCollateralExchangeRate = getExchangeRateForPool(collateralUnderlyingBrand); const { @@ -178,7 +179,12 @@ export const start = async (zcf, privateArgs) => { hasPool, hasKeyword, getPool: (brand) => poolTypes.get(brand), - makeBorrowInvitation + makeBorrowInvitation, + getAmountKeywordRecord: (keyword, brand, value) => { + const amountKeywordRecord = {}; + amountKeywordRecord[keyword] = AmountMath.make(brand, value); + return amountKeywordRecord; + } }); const getParamMgrRetriever = () => diff --git a/contract/src/lendingPool/poolManager.js b/contract/src/lendingPool/poolManager.js index 5414d43..391b964 100644 --- a/contract/src/lendingPool/poolManager.js +++ b/contract/src/lendingPool/poolManager.js @@ -173,6 +173,7 @@ export const makePoolManager = ( underlyingBrand), X`Requested ${q(proposedDebtAmount)} exceeds the total liquidity ${q(totalLiquidity)}`, ); + console.log("assertEnoughLiquidtyExists: Enough!") }; const getExchangeRate = () => { @@ -409,7 +410,7 @@ export const makePoolManager = ( const collateralBrand = exchangeRate.numerator.brand; const wrappedCollateralPriceAuthority = await E(priceManager).getPriceAuthority(collateralBrand); // should change the method name - + console.log("wrappedCollateralPriceAuthority: ", wrappedCollateralPriceAuthority) if (!debtsPerCollateralStore.has(collateralBrand)) { debtsPerCollateralStore.init(collateralBrand, makeDebtsPerCollateral( zcf, @@ -425,6 +426,7 @@ export const makePoolManager = ( } const debtsPerCollateral = debtsPerCollateralStore.get(collateralBrand); + console.log("debtsPerCollateral: ", debtsPerCollateral) const vaultKit = await E(debtsPerCollateral).addNewVault(seat, underlyingAssetSeat, exchangeRate); trace('VaultKit', vaultKit); return vaultKit; diff --git a/contract/src/lendingPool/priceManagerContract.js b/contract/src/lendingPool/priceManagerContract.js new file mode 100644 index 0000000..f730fff --- /dev/null +++ b/contract/src/lendingPool/priceManagerContract.js @@ -0,0 +1,58 @@ +// @ts-check +import { Far } from '@endo/marshal'; +import { AmountMath, AssetKind, makeIssuerKit } from '@agoric/ertp'; +import { Nat } from '@agoric/nat'; +import '@agoric/zoe/exported.js'; +import { makeScalarMap } from '@agoric/store'; +import { E } from '@agoric/eventual-send'; + +/** + * This is a faucet that provides liquidity for the ertp asset created + * using the parameter in terms. Just for demonstration purposes. + */ + +/** @type {ContractStartFn} */ +export async function start(zcf) { + + const priceAuthorities = makeScalarMap('priceAuthorities'); + /** @type {MapStore} */ + const supportedAssetPublicFacets = makeScalarMap('supportedAssetPublicFacets'); + + /** + * @param {Brand} brandIn + * @param {PriceAuthority} priceAuthority + * @param {Brand} compareBrand + */ + const addNewWrappedPriceAuthority = async (brandIn, priceAuthority, compareBrand) => { + const displayInfo = await E(brandIn).getDisplayInfo(); + const decimalPlaces = displayInfo?.decimalPlaces || 0n; + console.log('[DISPLAY_INFO]', displayInfo); + const notifier = E(priceAuthority).makeQuoteNotifier(AmountMath.make(brandIn, 10n ** Nat(decimalPlaces)), compareBrand); + priceAuthorities.init(brandIn, harden({ priceAuthority, notifier })); + console.log('[PRICE_AUTHS]', priceAuthorities.keys()); + return notifier; + } + + const addNewSupportedAssetPublicFacet = (key, value) => { + supportedAssetPublicFacets.init(key, value); + } + + const getPriceAuthority = (key) => { + return priceAuthorities.get(key); + } + + const getsupportedAssetPublicFacets = (key) => { + return supportedAssetPublicFacets.get(key); + } + + const publicFacet = Far('PriceManager', { + addNewWrappedPriceAuthority, + addNewSupportedAssetPublicFacet, + getPriceAuthority, + getsupportedAssetPublicFacets + }) + + const creatorFacet = Far('faucetInvitationMaker', {}); + + return harden({ creatorFacet, publicFacet }); +} diff --git a/contract/src/lendingPool/vault.js b/contract/src/lendingPool/vault.js index 6ab5589..23be1a9 100644 --- a/contract/src/lendingPool/vault.js +++ b/contract/src/lendingPool/vault.js @@ -124,7 +124,7 @@ export const makeInnerVault = ( // CONSTANTS const collateralBrand = manager.getCollateralBrand(); // const { brand: debtBrand } = mint.getIssuerRecord(); - + console.log("makeInnerVault") /** * State object to support virtualization when available * diff --git a/contract/test/lendingPool/helpers.js b/contract/test/lendingPool/helpers.js index b2b87d8..e4e435c 100644 --- a/contract/test/lendingPool/helpers.js +++ b/contract/test/lendingPool/helpers.js @@ -323,6 +323,25 @@ export const startFaucets = async (zoe, faucetBundles) => { } } +export const startPriceManager = async (zoe, priceManBundle) => { + const installations = await Collect.allValues({ + priceManagerContract: E(zoe).install(priceManBundle.priceManagerContract), + }); + + const { + creatorFacet: priceAuthorityManagerCreatorFacet, + publicFacet: priceAuthorityManagerPublicFacet, + instance: priceAuthorityManagerInstance, + } = await E(zoe).startInstance( + installations.priceManagerContract + ); + + return { + priceAuthorityManagerPublicFacet, + priceAuthorityManagerInstance + } +} + export const getLiquidityFromFaucet = async (zoe, invitation, unit, brand, keyword) => { const displayInfo = await E(brand).getDisplayInfo(); const proposalAmountKeywordRecord = {};