Skip to content

Commit

Permalink
#41 #43 Implemented the corresponding test for package-3 contract code.
Browse files Browse the repository at this point in the history
  • Loading branch information
anilhelvaci committed Nov 29, 2022
1 parent 96afb17 commit 8218d9b
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 11 deletions.
12 changes: 8 additions & 4 deletions contract/src/lendingPool/lendingPool.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,22 +112,24 @@ export const start = async (zcf, privateArgs) => {

const { brand: govBrand, issuer: govIssuer } = govMint.getIssuerRecord();
const { zcfSeat: govSeat } = zcf.makeEmptySeatKit();
const totalSupply = AmountMath.make(govBrand, units * 10n ** decimals);
const totalSupply = AmountMath.make(govBrand, units * 10n ** BigInt(decimals));
const proposalThreshold = ceilMultiplyBy(totalSupply, makeRatio(2n, govBrand));
govMint.mintGains({ [keyword]: totalSupply }, govSeat);
const supplyRatio = makeRatio(1n, govBrand, committeeSize, govBrand);
const supplyRatio = makeRatio(1n, govBrand, BigInt(committeeSize), govBrand);
const memberSupplyAmount = floorMultiplyBy(totalSupply, supplyRatio);

const makeFetchGovInvitation = () => {
/** @type OfferHandler */
const govFaucet = (committeeMemberSeat) => {
const memberShareAmount = floorMultiplyBy(totalSupply, supplyRatio);
committeeMemberSeat.incrementBy(
govSeat.decrementBy(
harden({ [keyword]: memberShareAmount })
harden({ [keyword]: memberSupplyAmount })
)
);
zcf.reallocate(committeeMemberSeat, govSeat);
committeeMemberSeat.exit();

return 'Thanks for participating in the protocol governance';
};

return zcf.makeInvitation(govFaucet, 'Governance Faucet');
Expand Down Expand Up @@ -360,6 +362,8 @@ export const start = async (zcf, privateArgs) => {
getGovernanceKeyword: () => keyword,
getTotalSupply: () => totalSupply,
getProposalTreshold: () => proposalThreshold,
getGovBalance: () => govSeat.getAmountAllocated(keyword, govBrand),
getMemberSupplyAmount: () => memberSupplyAmount,
});

const getParamMgrRetriever = () =>
Expand Down
11 changes: 8 additions & 3 deletions contract/src/lendingPool/params.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,12 @@ const makeElectorateParamManager = async (zoe, storageNode, marshaller, electora
* @param {Rates} rates
* @param {XYKAMMPublicFacet} ammPublicFacet
* @param {Brand} compareCurrencyBrand
* @param {bigint=} bootstrapPaymentValue
* @param {{
* keyword: String,
* units: BigInt,
* decimals: Number,
* committeeSize: Number
* }} governance
*/
const makeGovernedTerms = (
{ storageNode, marshaller },
Expand All @@ -127,7 +132,7 @@ const makeGovernedTerms = (
rates,
ammPublicFacet,
compareCurrencyBrand,
bootstrapPaymentValue = 0n,
governance
) => {
const timingParamMgr = makeLoanTimingManager(storageNode, marshaller, loanTiming);

Expand All @@ -141,7 +146,7 @@ const makeGovernedTerms = (
timerService,
liquidationInstall,
governedParams: makeElectorateParams(invitationAmount),
bootstrapPaymentValue,
governance,
compareCurrencyBrand
});
};
Expand Down
5 changes: 3 additions & 2 deletions contract/src/lendingPool/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
* underlyingKeyword: string,
* rates: Object, priceAuthority:
* PriceAuthority) => ERef<PoolManager>} addPoolType
* @property {(index: Number) => Invitation} getGovernanceInvitation
*/

/**
Expand All @@ -166,8 +167,8 @@
* @property {{
* keyword: String,
* units: BigInt,
* decimals: BigInt,
* committeeSize: BigInt
* decimals: Number,
* committeeSize: Number
* }} governance
*/

Expand Down
48 changes: 48 additions & 0 deletions contract/test/lendingPool/lendingPoolAssertions.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,52 @@ export const makeLendingPoolAssertions = t => {
t.truthy(AmountMath.isEmpty(loanColUnderlying));
};

/**
*
* @param {LendingPoolPublicFacet} lendingPoolPublicFacet
* @param {Instance} lendingPoolInstance
* @returns {Promise<void>}
*/
const assertGovTokenInitializedCorrectly = async ({ lendingPoolPublicFacet, lendingPoolInstance }) => {
const { farZoeKit: { /** @type ZoeService */ zoe } } = t.context;
const [{
governance: {
units,
decimals,
},
}, govBrand, govBalance, actualTotalSupply] = await Promise.all([
E(zoe).getTerms(lendingPoolInstance),
E(lendingPoolPublicFacet).getGovernanceBrand(),
E(lendingPoolPublicFacet).getGovBalance(),
E(lendingPoolPublicFacet).getTotalSupply(),

]);

const expectedTotalSupply = AmountMath.make(govBrand, units * 10n ** BigInt(decimals));

t.deepEqual(expectedTotalSupply, govBalance);
t.deepEqual(expectedTotalSupply, actualTotalSupply);
};

const assertGovFetchedCorrectly = async (userSeatP, { lendingPoolPublicFacet, keyword, expectedBalanceValue, expectedSupplyValue }) => {
const govIssuerP = E(lendingPoolPublicFacet).getGovernanceIssuer();
const offerResult = await E(userSeatP).getOfferResult();

const [govBalance, payout, govBrand] = await Promise.all([
E(lendingPoolPublicFacet).getGovBalance(),
E(userSeatP).getPayout(keyword),
E(lendingPoolPublicFacet).getGovernanceBrand(),
]);

const receivedAmount = await E(govIssuerP).getAmountOf(payout);
const expectedBalanceAmount = AmountMath.make(govBrand, expectedBalanceValue);
const expectedSupplyAmount = AmountMath.make(govBrand, expectedSupplyValue);

t.deepEqual(offerResult, 'Thanks for participating in the protocol governance');
t.deepEqual(expectedBalanceAmount, govBalance);
t.deepEqual(expectedSupplyAmount, receivedAmount);
}

return harden({
assertPoolAddedCorrectly,
assertDepositedCorrectly,
Expand All @@ -336,5 +382,7 @@ export const makeLendingPoolAssertions = t => {
assertRedeemSuccessful,
assertLiquidation,
assertActiveLoan,
assertGovTokenInitializedCorrectly,
assertGovFetchedCorrectly,
})
}
10 changes: 10 additions & 0 deletions contract/test/lendingPool/lendingPoolScenrioHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,12 +411,22 @@ export const makeLendingPoolScenarioHelpers = (
else if (poolType === POOL_TYPES.DEBT) debtPoolProtocolFaucet = newFaucet;
else throw new Error('Invalid PoolType');
}

const fetchGovTokens = index => {
const invitationP = E(lendingPoolCreatorFacet).getGovernanceInvitation(index);

return E(zoe).offer(
invitationP,
)
};

return harden({
addPool,
depositMoney,
borrow,
adjust,
closeLoan,
redeem,
fetchGovTokens
})
};
12 changes: 10 additions & 2 deletions contract/test/lendingPool/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,12 @@ export const setupServices = async (
governorInstance,
lendingPoolCreatorFacet,
lendingPoolPublicFacet,
lendingPoolInstance
] = await Promise.all([
instance.consume.lendingPoolGovernor,
lendingPoolCreatorFacetP,
E(governorCreatorFacet).getPublicFacet(),
instance.consume.lendingPool,
]);

const { g, l } = {
Expand All @@ -130,6 +132,7 @@ export const setupServices = async (
l: {
lendingPoolCreatorFacet,
lendingPoolPublicFacet,
lendingPoolInstance,
},
};

Expand Down Expand Up @@ -235,7 +238,7 @@ export const startLendingPool = async (
const marshaller = await E(board).getReadonlyMarshaller();

const loanFactoryTerms = makeGovernedTerms(
{storageNode, marshaller},
{ storageNode, marshaller },
priceManager, // priceMan here
loanParams,
installations.liquidate,
Expand All @@ -244,7 +247,12 @@ export const startLendingPool = async (
poolManagerParams,
ammPublicFacet,
compareBrand,
undefined
{
keyword: 'LPT',
units: 100_000n,
decimals: 6,
committeeSize: 5,
},
);

const governorTerms = harden({
Expand Down
179 changes: 179 additions & 0 deletions contract/test/lendingPool/test-expandedLendingPool.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// @ts-check
import { makeTracer } from '@agoric/inter-protocol/src/makeTracer.js';
import '@agoric/zoe/exported.js';
import '@agoric/zoe/tools/prepare-test-env.js';
import test from 'ava';
import { deeplyFulfilled } from '@endo/marshal';

import { E } from '@endo/far';
import { makeIssuerKit, AssetKind, AmountMath } from '@agoric/ertp';
import buildManualTimer from '@agoric/zoe/tools/manualTimer.js';
import {
makeRatio,
floorDivideBy,
floorMultiplyBy,
} from '@agoric/zoe/src/contractSupport/index.js';
import { makePromiseKit } from '@endo/promise-kit';
import { makeScriptedPriceAuthority } from '@agoric/zoe/tools/scriptedPriceAuthority.js';
import { makePriceManager } from '../../src/lendingPool/priceManager.js';
import {
makeRates,
setupAssets,
makeMarketStateChecker,
getPoolMetadata,
calculateUnderlyingFromProtocol,
calculateProtocolFromUnderlying,
splitCollateral,
} from './helpers.js';
import { eventLoopIteration } from '@agoric/zoe/tools/eventLoopIteration.js';
import {
setupServices,
CONTRACT_ROOTS,
getPath,
startLendingPool,
setupAmmAndElectorate,
} from './setup.js';
import { setUpZoeForTest } from '@agoric/inter-protocol/test/amm/vpool-xyk-amm/setup.js';
import { objectMap } from '@agoric/internal';
import { SECONDS_PER_YEAR } from '../../src/interest.js';
import * as Collect from '@agoric/inter-protocol/src/collect.js';
import { unsafeMakeBundleCache } from '@agoric/swingset-vat/tools/bundleTool.js';
import { makeManualPriceAuthority } from '@agoric/zoe/tools/manualPriceAuthority.js';
import { LoanPhase } from '../../src/lendingPool/loan.js';
import { oneMinus } from '@agoric/zoe/src/contractSupport/ratio.js';
import { makeLendingPoolAssertions } from './lendingPoolAssertions.js';
import { ADJUST_PROPOSAL_TYPE, makeLendingPoolScenarioHelpers, POOL_TYPES } from './lendingPoolScenrioHelpers.js';

test.before(async t => {
const farZoeKit = setUpZoeForTest();

const bundleCache = await unsafeMakeBundleCache('./bundles/'); // package-relative
// note that the liquidation might be a different bundle name
const bundles = await Collect.allValues({
faucet: bundleCache.load(await getPath(CONTRACT_ROOTS.faucet), 'faucet'),
liquidate: bundleCache.load(await getPath(CONTRACT_ROOTS.liquidate), 'liquidateMinimum'),
LendingPool: bundleCache.load(await getPath(CONTRACT_ROOTS.LendingPool), 'lendingPool'),
amm: bundleCache.load(await getPath(CONTRACT_ROOTS.amm), 'amm'),
reserve: bundleCache.load(await getPath(CONTRACT_ROOTS.reserve), 'reserve'),
});
const installations = objectMap(bundles, bundle => E(farZoeKit.zoe).install(bundle));

const { vanKit, usdKit, panKit, agVanKit } = setupAssets();

const contextPs = {
farZoeKit,
bundles,
installations,
electorateTerms: undefined,
loanTiming: {
chargingPeriod: 2n,
recordingPeriod: 6n,
priceCheckPeriod: 6n,
},
minInitialDebt: 50n,
// All values are in units
ammPoolsConfig: {
compareVanInitialLiquidityValue: 100n,
comparePanInitialLiquidityValue: 100n,
vanInitialLiquidityValue: 90n * 100n,
panInitialLiquidityValue: 100n * 100n,
},
};
const frozenCtx = await deeplyFulfilled(harden(contextPs));
t.context = {
...frozenCtx,
bundleCache,
vanKit,
compareCurrencyKit: usdKit,
panKit,
agVanKit,
vanRates: makeRates(vanKit.brand, usdKit.brand),
panRates: makeRates(panKit.brand, usdKit.brand),
};
// trace(t, 'CONTEXT');
});

test('initial', async t => {
const services = await setupServices(t);
console.log('services', services);
t.is('is', 'is');
});

/**
* Scenario - 1
* - Start the contract with the contract with the gov token data in the terms
* - Check govSeat allocations
* - Alice uses inv 0 to fetch some gov tokens. Assert;
* - Correct amount received
* - govSeat allocation decreases
* - Repeat above process for 4 more times
* - Try to fetch again with a used invitation. Assert;
* - Should throw
* Try to get an invitation with an index greater than the committee size. Assert;
* - Should throw
*/
test('scenario-1', async t => {
const {
lendingPool: {
lendingPoolPublicFacet,
lendingPoolInstance
},
assertions: {
assertGovTokenInitializedCorrectly,
assertGovFetchedCorrectly,
},
scenarioHelpers: {
fetchGovTokens,
},
} = await setupServices(t);

await assertGovTokenInitializedCorrectly({ lendingPoolPublicFacet, lendingPoolInstance });

const aliceFetchGovSeatP = fetchGovTokens(0);
await assertGovFetchedCorrectly(aliceFetchGovSeatP, {
lendingPoolPublicFacet,
keyword: 'LPT',
expectedBalanceValue: 80_000n * 10n ** 6n,
expectedSupplyValue: 20_000n * 10n ** 6n,
});

const bobFetchGovSeatP = fetchGovTokens(1);
await assertGovFetchedCorrectly(bobFetchGovSeatP, {
lendingPoolPublicFacet,
keyword: 'LPT',
expectedBalanceValue: 60_000n * 10n ** 6n,
expectedSupplyValue: 20_000n * 10n ** 6n,
});

const maggieFetchGovSeatP = fetchGovTokens(2);
await assertGovFetchedCorrectly(maggieFetchGovSeatP, {
lendingPoolPublicFacet,
keyword: 'LPT',
expectedBalanceValue: 40_000n * 10n ** 6n,
expectedSupplyValue: 20_000n * 10n ** 6n,
});

const peterFetchGovSeatP = fetchGovTokens(3);
await assertGovFetchedCorrectly(peterFetchGovSeatP, {
lendingPoolPublicFacet,
keyword: 'LPT',
expectedBalanceValue: 20_000n * 10n ** 6n,
expectedSupplyValue: 20_000n * 10n ** 6n,
});

const chrisFetchGovSeatP = fetchGovTokens(4);
await assertGovFetchedCorrectly(chrisFetchGovSeatP, {
lendingPoolPublicFacet,
keyword: 'LPT',
expectedBalanceValue: 0n * 10n ** 6n,
expectedSupplyValue: 20_000n * 10n ** 6n,
});

const invalidInvIndexFetchGovSeatP = fetchGovTokens(5);
await t.throwsAsync(() => E(invalidInvIndexFetchGovSeatP).getOfferResult());

const usedInvIndexFetchGovSeatP = fetchGovTokens(0);
await t.throwsAsync(() => E(usedInvIndexFetchGovSeatP).getOfferResult());

});

0 comments on commit 8218d9b

Please sign in to comment.