diff --git a/packages/zoe/src/contractFacet/contractFacet.js b/packages/zoe/src/contractFacet/contractFacet.js index f616035ff67..5b344ab1448 100644 --- a/packages/zoe/src/contractFacet/contractFacet.js +++ b/packages/zoe/src/contractFacet/contractFacet.js @@ -145,6 +145,50 @@ export function buildRootObject(_powers, _params, testJigSetter = undefined) { E(zoeInstanceAdmin).replaceAllocations(seatHandleAllocations); }; + const makeEmptySeatKit = (exit = undefined) => { + const initialAllocation = harden({}); + const proposal = cleanProposal(getAmountMath, harden({ exit })); + const { notifier, updater } = makeNotifierKit(); + /** @type {PromiseRecord} */ + const zoeSeatAdminPromiseKit = makePromiseKit(); + // Don't trigger Node.js's UnhandledPromiseRejectionWarning + zoeSeatAdminPromiseKit.promise.catch(_ => {}); + const userSeatPromiseKit = makePromiseKit(); + // Don't trigger Node.js's UnhandledPromiseRejectionWarning + userSeatPromiseKit.promise.catch(_ => {}); + const seatHandle = makeHandle('SeatHandle'); + + const seatData = harden({ + proposal, + initialAllocation, + notifier, + }); + const { zcfSeat, zcfSeatAdmin } = makeZcfSeatAdminKit( + allSeatStagings, + zoeSeatAdminPromiseKit.promise, + seatData, + getAmountMath, + ); + zcfSeatToZCFSeatAdmin.init(zcfSeat, zcfSeatAdmin); + zcfSeatToSeatHandle.init(zcfSeat, seatHandle); + + const exitObj = makeExitObj( + seatData.proposal, + zoeSeatAdminPromiseKit.promise, + zcfSeatAdmin, + ); + + E(zoeInstanceAdmin) + .makeNoEscrowSeat(initialAllocation, proposal, exitObj, seatHandle) + .then(({ zoeSeatAdmin, notifier: zoeNotifier, userSeat }) => { + updateFromNotifier(updater, zoeNotifier); + zoeSeatAdminPromiseKit.resolve(zoeSeatAdmin); + userSeatPromiseKit.resolve(userSeat); + }); + + return { zcfSeat, userSeat: userSeatPromiseKit.promise }; + }; + /** @type {MakeZCFMint} */ const makeZCFMint = async (keyword, amountMathKind = MathKind.NAT) => { assert( @@ -172,11 +216,9 @@ export function buildRootObject(_powers, _params, testJigSetter = undefined) { return mintyIssuerRecord; }, mintGains: (gains, zcfSeat = undefined) => { - // TODO unimplemented - assert( - zcfSeat !== undefined, - details`On demand seat creation not yet implemented`, - ); + if (zcfSeat === undefined) { + zcfSeat = makeEmptySeatKit().zcfSeat; + } let totalToMint = mintyAmountMath.getEmpty(); const oldAllocation = zcfSeat.getCurrentAllocation(); const updates = objectMap(gains, ([seatKeyword, amountToAdd]) => { @@ -305,49 +347,7 @@ export function buildRootObject(_powers, _params, testJigSetter = undefined) { // Shutdown the entire vat and give payouts shutdown: () => E(zoeInstanceAdmin).shutdown(), makeZCFMint, - makeEmptySeatKit: (exit = undefined) => { - const initialAllocation = harden({}); - const proposal = cleanProposal(getAmountMath, harden({ exit })); - const { notifier, updater } = makeNotifierKit(); - /** @type {PromiseRecord} */ - const zoeSeatAdminPromiseKit = makePromiseKit(); - // Don't trigger Node.js's UnhandledPromiseRejectionWarning - zoeSeatAdminPromiseKit.promise.catch(_ => {}); - const userSeatPromiseKit = makePromiseKit(); - // Don't trigger Node.js's UnhandledPromiseRejectionWarning - userSeatPromiseKit.promise.catch(_ => {}); - const seatHandle = makeHandle('SeatHandle'); - - const seatData = harden({ - proposal, - initialAllocation, - notifier, - }); - const { zcfSeat, zcfSeatAdmin } = makeZcfSeatAdminKit( - allSeatStagings, - zoeSeatAdminPromiseKit.promise, - seatData, - getAmountMath, - ); - zcfSeatToZCFSeatAdmin.init(zcfSeat, zcfSeatAdmin); - zcfSeatToSeatHandle.init(zcfSeat, seatHandle); - - const exitObj = makeExitObj( - seatData.proposal, - zoeSeatAdminPromiseKit.promise, - zcfSeatAdmin, - ); - - E(zoeInstanceAdmin) - .makeNoEscrowSeat(initialAllocation, proposal, exitObj, seatHandle) - .then(({ zoeSeatAdmin, notifier: zoeNotifier, userSeat }) => { - updateFromNotifier(updater, zoeNotifier); - zoeSeatAdminPromiseKit.resolve(zoeSeatAdmin); - userSeatPromiseKit.resolve(userSeat); - }); - - return { zcfSeat, userSeat: userSeatPromiseKit.promise }; - }, + makeEmptySeatKit, // The methods below are pure and have no side-effects // getZoeService: () => zoeService, diff --git a/packages/zoe/test/unitTests/zcf/test-zcf.js b/packages/zoe/test/unitTests/zcf/test-zcf.js index 9ac42ed520b..0d25d3ad2c4 100644 --- a/packages/zoe/test/unitTests/zcf/test-zcf.js +++ b/packages/zoe/test/unitTests/zcf/test-zcf.js @@ -428,16 +428,23 @@ test(`zcf.makeZCFMint - SET`, async t => { test(`zcf.makeZCFMint - mintGains - no args`, async t => { const { zcf } = await setupZCFTest(); const zcfMint = await zcf.makeZCFMint('A', MathKind.SET); - // TODO: create seat if one is not provided - // https://github.com/Agoric/agoric-sdk/issues/1696 // TODO: improve messages // https://github.com/Agoric/agoric-sdk/issues/1708 // @ts-ignore t.throws(() => zcfMint.mintGains(), { - message: 'On demand seat creation not yet implemented', + message: 'Cannot convert undefined or null to object', }); }); +test(`zcf.makeZCFMint - mintGains - no seat`, async t => { + const { zcf } = await setupZCFTest(); + const zcfMint = await zcf.makeZCFMint('A', MathKind.NAT); + const { amountMath, brand } = zcfMint.getIssuerRecord(); + const zcfSeat = zcfMint.mintGains({ A: amountMath.make(4) }); + t.truthy(zcfSeat); + t.deepEqual(zcfSeat.getAmountAllocated('A', brand), amountMath.make(4)); +}); + test(`zcf.makeZCFMint - mintGains - no gains`, async t => { const { zcf } = await setupZCFTest(); const zcfMint = await zcf.makeZCFMint('A', MathKind.SET);