Skip to content

Commit

Permalink
chore: charge fees as per zoeFeesConfig. Add tests to confirm fees ch…
Browse files Browse the repository at this point in the history
…arged (#3683)

* chore: chargeFees

Co-authored-by: Mark S. Miller <[email protected]>
  • Loading branch information
2 people authored and michaelfig committed Aug 17, 2021
1 parent ef8df3f commit 3682116
Show file tree
Hide file tree
Showing 14 changed files with 270 additions and 71 deletions.
13 changes: 11 additions & 2 deletions packages/zoe/src/zoeService/feeMint.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check

import { makeIssuerKit } from '@agoric/ertp';
import { makeIssuerKit, AmountMath } from '@agoric/ertp';

import { makeHandle } from '../makeHandle.js';

Expand All @@ -11,7 +11,10 @@ const { details: X } = assert;
* @returns {{
* feeMintAccess: FeeMintAccess,
* getFeeIssuerKit: GetFeeIssuerKit,
* feeIssuer: Issuer }}
* feeIssuer: Issuer,
* feeBrand: Brand,
* initialFeeFunds: Payment,
* }}
*/
const createFeeMint = (feeIssuerConfig, shutdownZoeVat) => {
/** @type {IssuerKit} */
Expand All @@ -34,10 +37,16 @@ const createFeeMint = (feeIssuerConfig, shutdownZoeVat) => {
return feeIssuerKit;
};

const initialFeeFunds = feeIssuerKit.mint.mintPayment(
AmountMath.make(feeIssuerKit.brand, feeIssuerConfig.initialFunds),
);

return harden({
feeMintAccess,
getFeeIssuerKit,
feeIssuer: feeIssuerKit.issuer,
feeBrand: feeIssuerKit.brand,
initialFeeFunds,
});
};

Expand Down
21 changes: 12 additions & 9 deletions packages/zoe/src/zoeService/feePurse.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ const { details: X } = assert;
* @param {Issuer} feeIssuer
* @returns {{
* makeFeePurse: MakeFeePurse,
* assertFeePurse: AssertFeePurse,
* chargeZoeFee: ChargeZoeFee,
* feeCollectionPurse: Purse,
* }}
*/
const setupMakeFeePurse = feeIssuer => {
const feePurses = new WeakSet();

const feeCollectionPurse = feeIssuer.makeEmptyPurse();

/** @type {MakeFeePurse} */
const makeFeePurse = async () => {
const purse = feeIssuer.makeEmptyPurse();
Expand All @@ -29,18 +32,18 @@ const setupMakeFeePurse = feeIssuer => {
return feePurse;
};

/** @type {IsFeePurse} */
const isFeePurse = feePurse => E.when(feePurse, fp => feePurses.has(fp));

/** @type {AssertFeePurse} */
const assertFeePurse = async feePurse => {
const feePurseProvided = await isFeePurse(feePurse);
assert(feePurseProvided, X`A feePurse must be provided, not ${feePurse}`);
/** @type {ChargeZoeFee} */
const chargeZoeFee = (feePurse, feeAmount) => {
return E.when(feePurse, fp => {
assert(feePurses.has(fp), X`A feePurse must be provided, not ${fp}`);
feeCollectionPurse.deposit(fp.withdraw(feeAmount));
});
};

return {
makeFeePurse,
assertFeePurse,
chargeZoeFee,
feeCollectionPurse,
};
};

Expand Down
8 changes: 4 additions & 4 deletions packages/zoe/src/zoeService/installationStorage.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { Far } from '@agoric/marshal';
import { E } from '@agoric/eventual-send';

/**
* @param {AssertFeePurse} assertFeePurse
* @param {ChargeZoeFee} chargeZoeFee
* @param {Amount} installFeeAmount
*/

export const makeInstallationStorage = assertFeePurse => {
export const makeInstallationStorage = (chargeZoeFee, installFeeAmount) => {
/** @type {WeakSet<Installation>} */
const installations = new WeakSet();

Expand All @@ -19,7 +19,7 @@ export const makeInstallationStorage = assertFeePurse => {
/** @type {InstallFeePurseRequired} */
const install = async (bundle, feePurse) => {
assert.typeof(bundle, 'object', X`a bundle must be provided`);
await assertFeePurse(feePurse);
await chargeZoeFee(feePurse, installFeeAmount);
/** @type {Installation} */
const installation = Far('Installation', {
getBundle: () => bundle,
Expand Down
11 changes: 7 additions & 4 deletions packages/zoe/src/zoeService/instanceAdminStorage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
import { makeWeakStore } from '@agoric/store';

/**
* @param {AssertFeePurse} assertFeePurse
* @param {ChargeZoeFee} chargeZoeFee
* @param {Amount} getPublicFacetFeeAmount
*/

export const makeInstanceAdminStorage = assertFeePurse => {
export const makeInstanceAdminStorage = (
chargeZoeFee,
getPublicFacetFeeAmount,
) => {
/** @type {WeakStore<Instance,InstanceAdmin>} */
const instanceToInstanceAdmin = makeWeakStore('instance');

/** @type {GetPublicFacetFeePurseRequired} */
const getPublicFacet = async (instance, feePurse) => {
await assertFeePurse(feePurse);
await chargeZoeFee(feePurse, getPublicFacetFeeAmount);
return instanceToInstanceAdmin.get(instance).getPublicFacet();
};

Expand Down
10 changes: 4 additions & 6 deletions packages/zoe/src/zoeService/internal-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,11 @@
*/

/**
* @callback IsFeePurse
* @param {ERef<FeePurse>} feePurse
* @returns {Promise<boolean>}
* @callback ChargeZoeFee
* @param {ERef<Purse>} feePurse
* @param {Amount} feeAmount
* @returns {Promise<void>}
*/

/**
* @callback AssertFeePurse
* @param {ERef<FeePurse>} feePurse
* @returns {Promise<void>}
*/
8 changes: 5 additions & 3 deletions packages/zoe/src/zoeService/offer/offer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ const { details: X, quote: q } = assert;
* @param {GetInstanceAdmin} getInstanceAdmin
* @param {DepositPayments} depositPayments
* @param {GetAssetKindByBrand} getAssetKindByBrand
* @param {AssertFeePurse} assertFeePurse
* @param {ChargeZoeFee} chargeZoeFee
* @param {Amount} offerFeeAmount
* @returns {Offer}
*/
export const makeOffer = (
invitationIssuer,
getInstanceAdmin,
depositPayments,
getAssetKindByBrand,
assertFeePurse,
chargeZoeFee,
offerFeeAmount,
) => {
/** @type {OfferFeePurseRequired} */
const offer = async (
Expand All @@ -40,7 +42,7 @@ export const makeOffer = (
);
// AWAIT ///

await assertFeePurse(feePurse);
await chargeZoeFee(feePurse, offerFeeAmount);

const instanceAdmin = getInstanceAdmin(instanceHandle);
instanceAdmin.assertAcceptingOffers();
Expand Down
9 changes: 5 additions & 4 deletions packages/zoe/src/zoeService/startInstance.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ import { handlePKitWarning } from '../handleWarning.js';
* @param {Promise<ZoeService>} zoeServicePromise
* @param {MakeZoeInstanceStorageManager} makeZoeInstanceStorageManager
* @param {UnwrapInstallation} unwrapInstallation
* @param {AssertFeePurse} assertFeePurse
* @param {ChargeZoeFee} chargeZoeFee
* @param {Amount} startInstanceFeeAmount
* @returns {StartInstance}
*/
export const makeStartInstance = (
zoeServicePromise,
makeZoeInstanceStorageManager,
unwrapInstallation,
assertFeePurse,
chargeZoeFee,
startInstanceFeeAmount,
) => {
/** @type {StartInstanceFeePurseRequired} */
const startInstance = async (
Expand All @@ -31,8 +33,7 @@ export const makeStartInstance = (
privateArgs = undefined,
feePurse,
) => {
await assertFeePurse(feePurse);

await chargeZoeFee(feePurse, startInstanceFeeAmount);
/** @type {WeakStore<SeatHandle, ZoeSeatAdmin>} */
const seatHandleToZoeSeatAdmin = makeWeakStore('seatHandle');

Expand Down
9 changes: 9 additions & 0 deletions packages/zoe/src/zoeService/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@
* @property {string} name
* @property {AssetKind} assetKind
* @property {DisplayInfo} displayInfo
* @property {Value} initialFunds
*/

/**
Expand All @@ -375,3 +376,11 @@
* @property {MakeFeePurse} makeFeePurse
* @property {BindDefaultFeePurse} bindDefaultFeePurse
*/

/**
* @typedef {Object} ZoeFeesConfig
* @property {NatValue} getPublicFacetFee
* @property {NatValue} installFee
* @property {NatValue} startInstanceFee
* @property {NatValue} offerFee
*/
70 changes: 60 additions & 10 deletions packages/zoe/src/zoeService/zoe.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import '@agoric/store/exported.js';
import '../../exported.js';
import '../internal-types.js';

import { AmountMath, AssetKind } from '@agoric/ertp';
import { Far } from '@agoric/marshal';
import { makePromiseKit } from '@agoric/promise-kit';
import { AssetKind } from '@agoric/ertp';

import { makeZoeStorageManager } from './zoeStorageManager.js';
import { makeStartInstance } from './startInstance.js';
Expand All @@ -36,8 +36,14 @@ import { bindDefaultFeePurse, setupMakeFeePurse } from './feePurse.js';
* shutdown the Zoe Vat. This function needs to use the vatPowers
* available to a vat.
* @param {FeeIssuerConfig} feeIssuerConfig
* @param {ZoeFeesConfig} zoeFees
* @param {string} [zcfBundleName] - The name of the contract facet bundle.
* @returns {{ zoeService: ZoeService, feeMintAccess: FeeMintAccess }}
* @returns {{
* zoeService: ZoeService,
* feeMintAccess: FeeMintAccess,
* initialFeeFunds: Payment,
* feeCollectionPurse: Purse,
* }}
*/
const makeZoeKit = (
vatAdminSvc,
Expand All @@ -46,6 +52,13 @@ const makeZoeKit = (
name: 'RUN',
assetKind: AssetKind.NAT,
displayInfo: { decimalPlaces: 6, assetKind: AssetKind.NAT },
initialFunds: 0n,
},
zoeFees = {
getPublicFacetFee: 0n,
installFee: 0n,
startInstanceFee: 0n,
offerFee: 0n,
},
zcfBundleName = undefined,
) => {
Expand All @@ -54,12 +67,40 @@ const makeZoeKit = (
/** @type {PromiseRecord<ZoeService>} */
const zoeServicePromiseKit = makePromiseKit();

const { feeMintAccess, getFeeIssuerKit, feeIssuer } = createFeeMint(
feeIssuerConfig,
shutdownZoeVat,
const {
feeMintAccess,
getFeeIssuerKit,
feeIssuer,
feeBrand,
initialFeeFunds,
} = createFeeMint(feeIssuerConfig, shutdownZoeVat);

// The initial funds should be enough to pay for launching the
// Agoric economy.
assert(
AmountMath.isGTE(
AmountMath.make(feeBrand, feeIssuerConfig.initialFunds),
AmountMath.add(
AmountMath.make(feeBrand, zoeFees.installFee),
AmountMath.make(feeBrand, zoeFees.startInstanceFee),
),
),
);

const { makeFeePurse, assertFeePurse } = setupMakeFeePurse(feeIssuer);
const getPublicFacetFeeAmount = AmountMath.make(
feeBrand,
zoeFees.getPublicFacetFee,
);
const installFeeAmount = AmountMath.make(feeBrand, zoeFees.installFee);
const startInstanceFeeAmount = AmountMath.make(
feeBrand,
zoeFees.startInstanceFee,
);
const offerFeeAmount = AmountMath.make(feeBrand, zoeFees.offerFee);

const { makeFeePurse, chargeZoeFee, feeCollectionPurse } = setupMakeFeePurse(
feeIssuer,
);

// This method contains the power to create a new ZCF Vat, and must
// be closely held. vatAdminSvc is even more powerful - any vat can
Expand All @@ -85,15 +126,18 @@ const makeZoeKit = (
createZCFVat,
getFeeIssuerKit,
shutdownZoeVat,
assertFeePurse,
chargeZoeFee,
getPublicFacetFeeAmount,
installFeeAmount,
);

// Pass the capabilities necessary to create E(zoe).startInstance
const startInstance = makeStartInstance(
zoeServicePromiseKit.promise,
makeZoeInstanceStorageManager,
unwrapInstallation,
assertFeePurse,
chargeZoeFee,
startInstanceFeeAmount,
);

// Pass the capabilities necessary to create E(zoe).offer
Expand All @@ -102,7 +146,8 @@ const makeZoeKit = (
getInstanceAdmin,
depositPayments,
getAssetKindByBrand,
assertFeePurse,
chargeZoeFee,
offerFeeAmount,
);

// Make the methods that allow users to easily and credibly get
Expand Down Expand Up @@ -141,7 +186,12 @@ const makeZoeKit = (
// defined. So, we pass a promise and then resolve the promise here.
zoeServicePromiseKit.resolve(zoeService);

return harden({ zoeService, feeMintAccess });
return harden({
zoeService,
feeMintAccess,
initialFeeFunds,
feeCollectionPurse,
});
};

export { makeZoeKit };
13 changes: 9 additions & 4 deletions packages/zoe/src/zoeService/zoeStorageManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,18 @@ import { makeInstallationStorage } from './installationStorage.js';
* ZCF Vat
* @param {GetFeeIssuerKit} getFeeIssuerKit
* @param {ShutdownWithFailure} shutdownZoeVat
* @param {AssertFeePurse} assertFeePurse
* @param {ChargeZoeFee} chargeZoeFee
* @param {Amount} getPublicFacetFeeAmount
* @param {Amount} installFeeAmount
* @returns {ZoeStorageManager}
*/
export const makeZoeStorageManager = (
createZCFVat,
getFeeIssuerKit,
shutdownZoeVat,
assertFeePurse,
chargeZoeFee,
getPublicFacetFeeAmount,
installFeeAmount,
) => {
// issuerStorage contains the issuers that the ZoeService knows
// about, as well as information about them such as their brand,
Expand Down Expand Up @@ -68,13 +72,14 @@ export const makeZoeStorageManager = (
getInstanceAdmin,
initInstanceAdmin,
deleteInstanceAdmin,
} = makeInstanceAdminStorage(assertFeePurse);
} = makeInstanceAdminStorage(chargeZoeFee, getPublicFacetFeeAmount);

// Zoe stores "installations" - identifiable bundles of contract
// code that can be reused again and again to create new contract
// instances
const { install, unwrapInstallation } = makeInstallationStorage(
assertFeePurse,
chargeZoeFee,
installFeeAmount,
);

/** @type {MakeZoeInstanceStorageManager} */
Expand Down
Loading

0 comments on commit 3682116

Please sign in to comment.