Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(fast-usdc): prune testBorrow, testRepay methods #10607

Merged
merged 2 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 5 additions & 39 deletions packages/fast-usdc/src/fast-usdc.contract.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { AssetKind } from '@agoric/ertp';
import {
assertAllDefined,
deeplyFulfilledObject,
makeTracer,
} from '@agoric/internal';
import { assertAllDefined, makeTracer } from '@agoric/internal';
import { observeIteration, subscribeEach } from '@agoric/notifier';
import {
CosmosChainInfoShape,
Expand All @@ -12,20 +8,19 @@ import {
registerChainsAndAssets,
withOrchestration,
} from '@agoric/orchestration';
import { makeZoeTools } from '@agoric/orchestration/src/utils/zoe-tools.js';
import { provideSingleton } from '@agoric/zoe/src/contractSupport/durability.js';
import { prepareRecorderKitMakers } from '@agoric/zoe/src/contractSupport/recorder.js';
import { makeZoeTools } from '@agoric/orchestration/src/utils/zoe-tools.js';
import { depositToSeat } from '@agoric/zoe/src/contractSupport/zoeHelpers.js';
import { E } from '@endo/far';
import { M, objectMap } from '@endo/patterns';
import { M } from '@endo/patterns';
import { prepareAdvancer } from './exos/advancer.js';
import { prepareLiquidityPoolKit } from './exos/liquidity-pool.js';
import { prepareSettler } from './exos/settler.js';
import { prepareStatusManager } from './exos/status-manager.js';
import { prepareTransactionFeedKit } from './exos/transaction-feed.js';
import { defineInertInvitation } from './utils/zoe.js';
import { FastUSDCTermsShape, FeeConfigShape } from './type-guards.js';
import * as flows from './fast-usdc.flows.js';
import { FastUSDCTermsShape, FeeConfigShape } from './type-guards.js';
import { defineInertInvitation } from './utils/zoe.js';

const trace = makeTracer('FastUsdc');

Expand Down Expand Up @@ -151,35 +146,6 @@ export const contract = async (zcf, privateArgs, zone, tools) => {
async makeOperatorInvitation(operatorId) {
return feedKit.creator.makeOperatorInvitation(operatorId);
},
/**
* @param {{ USDC: Amount<'nat'>}} amounts
*/
testBorrow(amounts) {
console.log('🚧🚧 UNTIL: borrow is integrated (#10388) 🚧🚧', amounts);
const { zcfSeat: tmpAssetManagerSeat } = zcf.makeEmptySeatKit();
poolKit.borrower.borrow(tmpAssetManagerSeat, amounts);
return tmpAssetManagerSeat.getCurrentAllocation();
},
/**
*
* @param {RepayAmountKWR} amounts
* @param {RepayPaymentKWR} payments
* @returns {Promise<AmountKeywordRecord>}
*/
async testRepay(amounts, payments) {
console.log('🚧🚧 UNTIL: repay is integrated (#10388) 🚧🚧', amounts);
const { zcfSeat: tmpAssetManagerSeat } = zcf.makeEmptySeatKit();
await depositToSeat(
zcf,
tmpAssetManagerSeat,
await deeplyFulfilledObject(
objectMap(payments, pmt => E(terms.issuers.USDC).getAmountOf(pmt)),
),
payments,
);
poolKit.repayer.repay(tmpAssetManagerSeat, amounts);
return tmpAssetManagerSeat.getCurrentAllocation();
},
});

const publicFacet = zone.exo('Fast USDC Public', undefined, {
Expand Down
229 changes: 0 additions & 229 deletions packages/fast-usdc/test/fast-usdc.contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,235 +317,6 @@ const makeLP = async (
return me;
};

test.skip('LP borrow - TODO: move to exo test', async t => {
const common = await commonSetup(t);
const {
brands: { usdc },
utils,
} = common;

const { instance, creatorFacet, zoe, metricsSub, terms } =
await startContract(common);

const usdcPurse = purseOf(terms.issuers.USDC, utils);
const lps = {
alice: makeLP('Alice', usdcPurse(100n), zoe, instance),
};
// seed pool with funds
await E(lps.alice).deposit(t, 100n);

const { value } = await E(metricsSub).getUpdateSince();
const { shareWorth, encumberedBalance } = value;
const poolSeatAllocation = subtract(
subtract(shareWorth.numerator, encumberedBalance),
usdc.make(1n),
);
t.log('Attempting to borrow entire pool seat allocation', poolSeatAllocation);
await t.throwsAsync(
E(creatorFacet).testBorrow({ USDC: poolSeatAllocation }),
{
message: /Cannot borrow/,
},
'borrow fails when requested equals pool seat allocation',
);

await t.throwsAsync(
E(creatorFacet).testBorrow({ USDC: usdc.make(200n) }),
{
message: /Cannot borrow/,
},
'borrow fails when requested exceeds pool seat allocation',
);

await t.throwsAsync(E(creatorFacet).testBorrow({ USDC: usdc.make(0n) }), {
message: /arg 1: USDC: value: "\[0n\]" - Must be >= "\[1n\]"/,
});

await t.throwsAsync(
E(creatorFacet).testBorrow(
// @ts-expect-error intentionally incorrect KW
{ Fee: usdc.make(1n) },
),
{
message: /Must have missing properties \["USDC"\]/,
},
);

// LPs can still withdraw (contract did not shutdown)
await E(lps.alice).withdraw(t, 0.5);

const amt = await E(creatorFacet).testBorrow({ USDC: usdc.make(30n) });
t.deepEqual(amt, { USDC: usdc.make(30n) }, 'borrow succeeds');

await eventLoopIteration();
t.like(await E(metricsSub).getUpdateSince(), {
value: {
encumberedBalance: {
value: 30n,
},
totalBorrows: {
value: 30n,
},
totalRepays: {
value: 0n,
},
},
});
});

test.skip('LP repay - TODO: move to exo test', async t => {
const common = await commonSetup(t);
const {
commonPrivateArgs,
brands: { usdc },
utils,
} = common;

const { instance, creatorFacet, zoe, metricsSub, terms } =
await startContract(common);
const usdcPurse = purseOf(terms.issuers.USDC, utils);
const lps = {
alice: makeLP('Alice', usdcPurse(100n), zoe, instance),
};
// seed pool with funds
await E(lps.alice).deposit(t, 100n);

// borrow funds from pool to increase encumbered balance
await E(creatorFacet).testBorrow({ USDC: usdc.make(50n) });
const feeTools = makeFeeTools(commonPrivateArgs.feeConfig);
{
t.log('cannot repay more than encumbered balance');
const repayAmounts = feeTools.calculateSplit(usdc.make(100n));
const repayPayments = await deeplyFulfilledObject(
objectMap(repayAmounts, utils.pourPayment),
);
await t.throwsAsync(
E(creatorFacet).testRepay(repayAmounts, repayPayments),
{
message: /Cannot repay. Principal .* exceeds encumberedBalance/,
},
);
}

{
const pmt = utils.pourPayment(usdc.make(50n));
await t.throwsAsync(
E(creatorFacet).testRepay(
// @ts-expect-error intentionally incorrect KWR
{ USDC: usdc.make(50n) },
{ USDC: pmt },
),
{
message:
/Must have missing properties \["Principal","PoolFee","ContractFee"\]/,
},
);
}
{
const pmt = utils.pourPayment(usdc.make(50n));
await t.throwsAsync(
E(creatorFacet).testRepay(
// @ts-expect-error intentionally incorrect KWR
{ Principal: usdc.make(50n) },
{ Principal: pmt },
),
{
message: /Must have missing properties \["PoolFee","ContractFee"\]/,
},
);
}
{
const amts = {
Principal: usdc.make(0n),
ContractFee: usdc.make(0n),
PoolFee: usdc.make(0n),
};
const pmts = await deeplyFulfilledObject(
objectMap(amts, utils.pourPayment),
);
await t.throwsAsync(E(creatorFacet).testRepay(amts, pmts), {
message: /arg 1: Principal: value: "\[0n\]" - Must be >= "\[1n\]"/,
});
}

{
t.log('repay fails when amounts do not match seat allocation');
const amts = {
Principal: usdc.make(25n),
ContractFee: usdc.make(1n),
PoolFee: usdc.make(2n),
};
const pmts = await deeplyFulfilledObject(
harden({
Principal: utils.pourPayment(usdc.make(24n)),
ContractFee: utils.pourPayment(usdc.make(1n)),
PoolFee: utils.pourPayment(usdc.make(2n)),
}),
);
await t.throwsAsync(E(creatorFacet).testRepay(amts, pmts), {
message: /Cannot repay. From seat allocation .* does not equal amounts/,
});
}

{
t.log('repay succeeds with no Pool or Contract Fee');
const amts = {
Principal: usdc.make(25n),
ContractFee: usdc.make(0n),
PoolFee: usdc.make(0n),
};
const pmts = await deeplyFulfilledObject(
objectMap(amts, utils.pourPayment),
);
const repayResult = await E(creatorFacet).testRepay(amts, pmts);

for (const r of Object.values(repayResult)) {
t.is(r.value, 0n, 'testRepay consumes all payments');
}
}

const amts = {
Principal: usdc.make(25n),
ContractFee: usdc.make(1n),
PoolFee: usdc.make(2n),
};
const pmts = await deeplyFulfilledObject(objectMap(amts, utils.pourPayment));
const repayResult = await E(creatorFacet).testRepay(amts, pmts);

for (const r of Object.values(repayResult)) {
t.is(r.value, 0n, 'testRepay consumes all payments');
}

await eventLoopIteration();
t.like(await E(metricsSub).getUpdateSince(), {
value: {
encumberedBalance: {
value: 0n,
},
totalBorrows: {
value: 50n,
},
totalRepays: {
value: 50n,
},
totalContractFees: {
value: 1n,
},
totalPoolFees: {
value: 2n,
},
shareWorth: {
numerator: {
value: 103n, // 100n (alice lp) + 1n (dust) + 2n (pool fees)
},
},
},
});

// LPs can still withdraw (contract did not shutdown)
await E(lps.alice).withdraw(t, 1);
});

const makeEVM = (template = MockCctpTxEvidences.AGORIC_PLUS_OSMO()) => {
const [settleAddr] = template.aux.recipientAddress.split('?');
let nonce = 0;
Expand Down
30 changes: 30 additions & 0 deletions packages/fast-usdc/test/pool-share-math.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,3 +494,33 @@ test('repay fails when seat allocation does not equal amounts', t => {
},
);
});

test('repay succeeds with no Pool or Contract Fee', t => {
const { USDC } = brands;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of scope: consider using withAmountUtils to make the brands, issuers and amounts easier to work with

const encumberedBalance = make(USDC, 100n);
const shareWorth = makeParity(make(USDC, 1n), brands.PoolShares);

const amounts = {
Principal: make(USDC, 25n),
ContractFee: make(USDC, 0n),
PoolFee: make(USDC, 0n),
};
const poolStats = {
...makeInitialPoolStats(),
totalBorrows: make(USDC, 100n),
};
const fromSeatAllocation = amounts;
const actual = repayCalc(
shareWorth,
fromSeatAllocation,
amounts,
encumberedBalance,
poolStats,
);
t.like(actual, {
shareWorth,
encumberedBalance: {
value: 75n,
},
});
});
Loading