From 7ae15ed39fa83b3974b3ee8e74ff17be5bc35dfb Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Wed, 7 Aug 2024 15:28:55 -0700 Subject: [PATCH] fixup! restore previous buggy behavior with better error --- packages/vats/src/virtual-purse.js | 20 +++++++- packages/vats/test/vpurse.test.js | 80 ++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/packages/vats/src/virtual-purse.js b/packages/vats/src/virtual-purse.js index 8b8ac1ff9150..155f29e31a92 100644 --- a/packages/vats/src/virtual-purse.js +++ b/packages/vats/src/virtual-purse.js @@ -1,7 +1,7 @@ import { Fail } from '@endo/errors'; import { E } from '@endo/far'; import { isPromise } from '@endo/promise-kit'; -import { getInterfaceGuardPayload } from '@endo/patterns'; +import { getInterfaceGuardPayload, matches } from '@endo/patterns'; import { M } from '@agoric/store'; import { @@ -105,6 +105,22 @@ export const makeVirtualPurseKitIKit = ( * current balance iterable for a given brand. */ +/** + * Until https://github.com/Agoric/agoric-sdk/issues/9407 is fixed, this + * function restricts the `optAmountShape`, if provided, to be a concrete + * `Amount` rather than a `Pattern` as it is supposed to be. + * + * TODO: Once https://github.com/Agoric/agoric-sdk/issues/9407 is fixed, remove + * this function and all calls to it. + * + * @param {Pattern} [optAmountShape] + */ +const legacyRestrictAmountShapeArg = optAmountShape => { + if (optAmountShape && !matches(optAmountShape, AmountShape)) { + throw Fail`optAmountShape if provided, must still be a concrete Amount due to https://github.com/Agoric/agoric-sdk/issues/9407`; + } +}; + /** @param {import('@agoric/zone').Zone} zone */ const prepareVirtualPurseKit = zone => zone.exoClassKit( @@ -142,6 +158,7 @@ const prepareVirtualPurseKit = zone => * @returns {Promise>} */ async recoverableClaim(payment, optAmountShape) { + legacyRestrictAmountShapeArg(optAmountShape); const { state: { recoveryPurse }, } = this; @@ -169,6 +186,7 @@ const prepareVirtualPurseKit = zone => minter: { /** @type {Retain} */ async retain(payment, optAmountShape) { + legacyRestrictAmountShapeArg(optAmountShape); !!this.state.mint || Fail`minter cannot retain without a mint.`; return E(this.state.issuer).burn(payment, optAmountShape); }, diff --git a/packages/vats/test/vpurse.test.js b/packages/vats/test/vpurse.test.js index 4e7572660d88..ca0da5744ea5 100644 --- a/packages/vats/test/vpurse.test.js +++ b/packages/vats/test/vpurse.test.js @@ -169,6 +169,86 @@ test('makeVirtualPurse', async t => { ); }; + expected.pushAmount(fungible837); + await E(vpurse) + .deposit(payment, fungible837) + .then(checkDeposit) + .then(performWithdrawal) + .then(checkWithdrawal); +}); + +// TODO Once https://github.com/Agoric/agoric-sdk/issues/9407 is fixed, +// This test should replace the similar one above. +test.failing('makeVirtualPurse with optAmountShape pattern', async t => { + t.plan(22); + const { baggage } = t.context; + const zone = makeDurableZone(baggage).subZone('makeVirtualPurse'); + + const { expected, balanceUpdater, issuer, mint, brand, vpurse } = setup( + t, + zone, + ); + + const payment = mint.mintPayment(AmountMath.make(brand, 837n)); + + const notifier = E(vpurse).getCurrentAmountNotifier(); + let nextUpdateP = E(notifier).getUpdateSince(); + + const checkNotifier = async () => { + const { value: balance, updateCount } = await nextUpdateP; + t.assert( + AmountMath.isEqual(await E(vpurse).getCurrentAmount(), balance), + `the notifier balance is the same as the purse`, + ); + nextUpdateP = E(notifier).getUpdateSince(updateCount); + }; + + balanceUpdater.updateState(AmountMath.makeEmpty(brand)); + await checkNotifier(); + t.assert( + AmountMath.isEqual( + await E(vpurse).getCurrentAmount(), + AmountMath.makeEmpty(brand), + ), + `empty purse is empty`, + ); + t.is(await E(vpurse).getAllegedBrand(), brand, `purse's brand is correct`); + const fungible837 = AmountMath.make(brand, 837n); + + const checkDeposit = async newPurseBalance => { + t.assert( + AmountMath.isEqual(newPurseBalance, fungible837), + `the amount returned is the payment amount`, + ); + await checkNotifier(); + t.assert( + AmountMath.isEqual(await E(vpurse).getCurrentAmount(), fungible837), + `the new purse balance is the payment's old balance`, + ); + }; + + const performWithdrawal = () => { + expected.pullAmount(fungible837); + return E(vpurse).withdraw(fungible837); + }; + + const checkWithdrawal = async newPayment => { + await issuer.getAmountOf(newPayment).then(amount => { + t.assert( + AmountMath.isEqual(amount, fungible837), + `the withdrawn payment has the right balance`, + ); + }); + await checkNotifier(); + t.assert( + AmountMath.isEqual( + await E(vpurse).getCurrentAmount(), + AmountMath.makeEmpty(brand), + ), + `the purse is empty again`, + ); + }; + expected.pushAmount(fungible837); await E(vpurse) .deposit(payment, M.and(fungible837))