diff --git a/packages/ERTP/package.json b/packages/ERTP/package.json index f29190a597f..b319be6f27b 100644 --- a/packages/ERTP/package.json +++ b/packages/ERTP/package.json @@ -86,6 +86,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 90.62 + "atLeast": 91.21 } } diff --git a/packages/ERTP/src/amountMath.js b/packages/ERTP/src/amountMath.js index 314a5644a78..a6e362ba045 100644 --- a/packages/ERTP/src/amountMath.js +++ b/packages/ERTP/src/amountMath.js @@ -6,7 +6,10 @@ import { setMathHelpers } from './mathHelpers/setMathHelpers.js'; import { copySetMathHelpers } from './mathHelpers/copySetMathHelpers.js'; import { copyBagMathHelpers } from './mathHelpers/copyBagMathHelpers.js'; -/** @import {Amount, AssetKind, AmountValue, AssetKindForValue, AssetValueForKind, Brand, MathHelpers} from './types.js' */ +/** + * @import {CopyBag, CopySet} from '@endo/patterns'; + * @import {Amount, AssetKind, AmountValue, AssetKindForValue, AssetValueForKind, Brand, CopyBagAmount, CopySetAmount, MathHelpers, NatAmount, NatValue, SetAmount, SetValue} from './types.js'; + */ const { quote: q, Fail } = assert; @@ -76,26 +79,19 @@ const helpers = { copyBag: copyBagMathHelpers, }; -/** - * @template {AmountValue} V - * @type {(value: V) => AssetKindForValue} - */ +/** @type {(value: unknown) => 'nat' | 'set' | 'copySet' | 'copyBag'} } */ const assertValueGetAssetKind = value => { const passStyle = passStyleOf(value); if (passStyle === 'bigint') { - // @ts-expect-error cast return 'nat'; } if (passStyle === 'copyArray') { - // @ts-expect-error cast return 'set'; } if (matches(value, M.set())) { - // @ts-expect-error cast return 'copySet'; } if (matches(value, M.bag())) { - // @ts-expect-error cast return 'copyBag'; } // TODO This isn't quite the right error message, in case valuePassStyle @@ -113,7 +109,7 @@ const assertValueGetAssetKind = value => { * * Made available only for testing, but it is harmless for other uses. * - * @template {AmountValue} V + * @template V * @param {V} value * @returns {MathHelpers} */ @@ -198,29 +194,44 @@ const isGTE = (leftAmount, rightAmount, brand = undefined) => { * the abstract right to participate in a particular exchange. */ const AmountMath = { + // TODO use overloading to handle when Brand has an AssetKind and when it doesn't. + // a AmountForValue utility could help DRY those cases. /** * Make an amount from a value by adding the brand. * - * @template {AssetKind} K - * @param {Brand} brand - * @param {AssetValueForKind} allegedValue - * @returns {Amount} + * Does not verify that the Brand's AssetKind matches the value's. + * + * @template {Brand} B + * @template {NatValue | CopySet | CopyBag | SetValue} V + * @param {B} brand + * @param {V} allegedValue + * @returns {B extends Brand<'nat'> + * ? NatAmount + * : V extends NatValue + * ? NatAmount + * : V extends CopySet + * ? CopySetAmount + * : V extends CopyBag + * ? CopyBagAmount + * : V extends SetValue + * ? SetAmount + * : never} */ - // allegedValue has a conditional expression for type widening, to prevent V being bound to a a literal like 1n make: (brand, allegedValue) => { assertRemotable(brand, 'brand'); const h = assertValueGetHelpers(allegedValue); const value = h.doCoerce(allegedValue); + // @ts-expect-error cast return harden({ brand, value }); }, /** * Make sure this amount is valid enough, and return a corresponding valid * amount if so. * - * @template {AssetKind} K - * @param {Brand} brand - * @param {Amount} allegedAmount - * @returns {Amount} + * @template {Amount} A + * @param {Brand} brand + * @param {A} allegedAmount + * @returns {A} */ coerce: (brand, allegedAmount) => { assertRemotable(brand, 'brand'); @@ -229,15 +240,16 @@ const AmountMath = { brand === allegedBrand || Fail`The brand in the allegedAmount ${allegedAmount} in 'coerce' didn't match the specified brand ${brand}.`; // Will throw on inappropriate value + // @ts-expect-error cast return AmountMath.make(brand, allegedValue); }, /** * Extract and return the value. * - * @template {AssetKind} K - * @param {Brand} brand - * @param {Amount} amount - * @returns {AssetValueForKind} + * @template {Amount} A + * @param {Brand} brand + * @param {A} amount + * @returns {A['value']} */ getValue: (brand, amount) => AmountMath.coerce(brand, amount).value, /** @@ -246,29 +258,29 @@ const AmountMath = { * * @type {{ * (brand: Brand): Amount<'nat'>; - * (brand: Brand, assetKind: K): Amount; + * (brand: Brand, assetKind: K): Amount; * }} */ makeEmpty: (brand, assetKind = /** @type {const} */ ('nat')) => { assertRemotable(brand, 'brand'); assertAssetKind(assetKind); const value = helpers[assetKind].doMakeEmpty(); + // @ts-expect-error XXX narrowing from function overload return harden({ brand, value }); }, /** * Return the amount representing an empty amount, using another amount as the * template for the brand and assetKind. * - * @template {AssetKind} K - * @param {Amount} amount - * @returns {Amount} + * @template {Amount} A + * @param {A} amount + * @returns {A} */ makeEmptyFromAmount: amount => { assertRecord(amount, 'amount'); const { brand, value } = amount; - // @ts-expect-error cast const assetKind = assertValueGetAssetKind(value); - // @ts-expect-error cast (ignore b/c erroring in CI but not my IDE) + // @ts-expect-error different subtype return AmountMath.makeEmpty(brand, assetKind); }, /** @@ -291,10 +303,10 @@ const AmountMath = { * Returns true if the leftAmount equals the rightAmount. We assume that if * isGTE is true in both directions, isEqual is also true * - * @template {AssetKind} K - * @param {Amount} leftAmount - * @param {Amount} rightAmount - * @param {Brand} [brand] + * @template {Amount} A + * @param {A} leftAmount + * @param {A} rightAmount + * @param {Brand} [brand] * @returns {boolean} */ isEqual: (leftAmount, rightAmount, brand = undefined) => { @@ -308,15 +320,16 @@ const AmountMath = { * amount, it usually means including all of the elements from both left and * right. * - * @template {AssetKind} K - * @param {Amount} leftAmount - * @param {Amount} rightAmount - * @param {Brand} [brand] - * @returns {Amount} + * @template {Amount} A + * @param {A} leftAmount + * @param {A} rightAmount + * @param {Brand} [brand] + * @returns {A} */ add: (leftAmount, rightAmount, brand = undefined) => { const h = checkLRAndGetHelpers(leftAmount, rightAmount, brand); const value = h.doAdd(...coerceLR(h, leftAmount, rightAmount)); + // @ts-expect-error different subtype return harden({ brand: leftAmount.brand, value }); }, /** @@ -326,25 +339,27 @@ const AmountMath = { * error. Because the left amount must include the right amount, this is NOT * equivalent to set subtraction. * - * @template {AssetKind} K - * @param {Amount} leftAmount - * @param {Amount} rightAmount - * @param {Brand} [brand] - * @returns {Amount} + * @template {Amount} L + * @template {Amount} R + * @param {L} leftAmount + * @param {R} rightAmount + * @param {Brand} [brand] + * @returns {L extends R ? L : never} */ subtract: (leftAmount, rightAmount, brand = undefined) => { const h = checkLRAndGetHelpers(leftAmount, rightAmount, brand); const value = h.doSubtract(...coerceLR(h, leftAmount, rightAmount)); + // @ts-expect-error different subtype return harden({ brand: leftAmount.brand, value }); }, /** * Returns the min value between x and y using isGTE * - * @template {AssetKind} K - * @param {Amount} x - * @param {Amount} y - * @param {Brand} [brand] - * @returns {Amount} + * @template {Amount} A + * @param {A} x + * @param {A} y + * @param {Brand} [brand] + * @returns {A} */ min: (x, y, brand = undefined) => // eslint-disable-next-line no-nested-ternary @@ -356,11 +371,11 @@ const AmountMath = { /** * Returns the max value between x and y using isGTE * - * @template {AssetKind} K - * @param {Amount} x - * @param {Amount} y - * @param {Brand} [brand] - * @returns {Amount} + * @template {Amount} A + * @param {A} x + * @param {A} y + * @param {Brand} [brand] + * @returns {A} */ max: (x, y, brand = undefined) => // eslint-disable-next-line no-nested-ternary @@ -376,7 +391,6 @@ harden(AmountMath); const getAssetKind = amount => { assertRecord(amount, 'amount'); const { value } = amount; - // @ts-expect-error cast (ignore b/c erroring in CI but not my IDE) return assertValueGetAssetKind(value); }; harden(getAssetKind); diff --git a/packages/ERTP/src/issuerKit.js b/packages/ERTP/src/issuerKit.js index 107e245f842..0a4ee145b7a 100644 --- a/packages/ERTP/src/issuerKit.js +++ b/packages/ERTP/src/issuerKit.js @@ -325,7 +325,7 @@ harden(prepareIssuerKit); * anything else is corrupted by that corrupted state. See * https://github.com/Agoric/agoric-sdk/issues/3434 * @param {IssuerOptionsRecord} [options] - * @returns {IssuerKit} + * @returns {IssuerKit} */ export const makeIssuerKit = ( name, diff --git a/packages/ERTP/src/legacy-payment-helpers.js b/packages/ERTP/src/legacy-payment-helpers.js index af53e22a628..55dccaae538 100644 --- a/packages/ERTP/src/legacy-payment-helpers.js +++ b/packages/ERTP/src/legacy-payment-helpers.js @@ -5,7 +5,7 @@ import { E } from '@endo/far'; import { AmountMath } from './amountMath.js'; /** - * @import {ERef} from '@endo/far'); + * @import {ERef} from '@endo/far'; * @import {Amount, AssetKind, AmountValue, AssetKindForValue, Payment, Brand, Purse} from './types.js' */ @@ -26,11 +26,11 @@ const { Fail } = assert; */ /** - * @template {AssetKind} K - * @param {ERef>} recoveryPurse - * @param {ERef>} srcPaymentP + * @template {Payment} P + * @param {ERef} recoveryPurse + * @param {ERef

} srcPaymentP * @param {Pattern} [optAmountShape] - * @returns {Promise>} + * @returns {Promise

} */ export const claim = async ( recoveryPurse, @@ -38,6 +38,7 @@ export const claim = async ( optAmountShape = undefined, ) => { const srcPayment = await srcPaymentP; + // @ts-expect-error XXX could be instantiated with a different subtype return E.when(E(recoveryPurse).deposit(srcPayment, optAmountShape), amount => E(recoveryPurse).withdraw(amount), ); diff --git a/packages/ERTP/src/paymentLedger.js b/packages/ERTP/src/paymentLedger.js index 5b9645f7e06..33ae4c658f0 100644 --- a/packages/ERTP/src/paymentLedger.js +++ b/packages/ERTP/src/paymentLedger.js @@ -15,6 +15,7 @@ import { BrandI, makeIssuerInterfaces } from './typeGuards.js'; /** * @import {Amount, AssetKind, DisplayInfo, PaymentLedger, Payment, Brand, RecoverySetsOption, Purse, Issuer, Mint} from './types.js' * @import {ShutdownWithFailure} from '@agoric/swingset-vat' + * @import {Key} from '@endo/patterns'; */ const { details: X, quote: q, Fail } = assert; @@ -93,11 +94,7 @@ export const preparePaymentLedger = ( optShutdownWithFailure = undefined, ) => { /** @type {Brand} */ - // Should be - // at-ts-expect-error XXX callWhen - // but ran into the usual disagreement between local lint and CI - - // @ts-expect-error + // @ts-expect-error XXX callWhen const brand = issuerZone.exo(`${name} brand`, BrandI, { isMyIssuer(allegedIssuer) { // BrandI delays calling this method until `allegedIssuer` is a Remotable @@ -299,7 +296,7 @@ export const preparePaymentLedger = ( }; /** @type {() => Purse} */ - // @ts-expect-error type parameter confusion + // @ts-expect-error XXX amount kinds const makeEmptyPurse = preparePurseKind( issuerZone, name, @@ -315,11 +312,7 @@ export const preparePaymentLedger = ( ); /** @type {Issuer} */ - // Should be - // at-ts-expect-error cast due to callWhen discrepancy - // but ran into the usual disagreement between local lint and CI - - // @ts-expect-error + // @ts-expect-error XXX callWhen const issuer = issuerZone.exo(`${name} issuer`, IssuerI, { getBrand() { return brand; @@ -374,11 +367,6 @@ export const preparePaymentLedger = ( * `makeIssuerKit` drops it on the floor, it can still be recovered in an * emergency upgrade. */ - // Should be - // at-ts-expect-error checked cast - // but ran into the usual disagreement between local lint and IDE lint. - // Don't know yet about lint under CI. - const mintRecoveryPurse = /** @type {Purse} */ ( issuerZone.makeOnce('mintRecoveryPurse', () => makeEmptyPurse()) ); @@ -389,10 +377,6 @@ export const preparePaymentLedger = ( return issuer; }, mintPayment(newAmount) { - // Should be - // at-ts-expect-error checked cast - // but ran into the usual disagreement between local lint and CI - newAmount = coerce(newAmount); mustMatch(newAmount, amountShape, 'minted amount'); // `rawPayment` is not associated with any recovery set, and diff --git a/packages/ERTP/src/transientNotifier.js b/packages/ERTP/src/transientNotifier.js index a01eaeb28c1..a445a365e66 100644 --- a/packages/ERTP/src/transientNotifier.js +++ b/packages/ERTP/src/transientNotifier.js @@ -6,7 +6,7 @@ import { makeNotifierKit } from '@agoric/notifier'; /** * @import {Purse} from './types.js'; - * @import {LatestTopic, NotifierRecord} from '@agoric/notifier'); + * @import {NotifierRecord} from '@agoric/notifier'; */ // Note: Virtual for high cardinality, but *not* durable, and so diff --git a/packages/ERTP/src/types.js b/packages/ERTP/src/types.js index 91a97b288b1..d26934d942a 100644 --- a/packages/ERTP/src/types.js +++ b/packages/ERTP/src/types.js @@ -5,23 +5,45 @@ export {}; /// /** - * @import {ERef} from '@endo/far'); - * @import {CopySet, Key} from '@endo/patterns'); - * @import {LatestTopic, NotifierRecord} from '@agoric/notifier'); + * @import {Passable, RemotableObject} from '@endo/pass-style'; + * @import {CopyBag, CopySet, Key} from '@endo/patterns'; + * @import {LatestTopic, NotifierRecord} from '@agoric/notifier'; */ +/** @typedef {{ brand: Brand<'nat'>; value: bigint }} NatAmount */ +/** + * @template {Key} K + * @typedef {{ brand: Brand<'set'>; value: K[] }} SetAmount + */ +/** + * @template {Key} K + * @typedef {{ brand: Brand<'copySet'>; value: CopySet }} CopySetAmount + */ +/** + * @template {Key} K + * @typedef {{ brand: Brand<'copyBag'>; value: CopyBag }} CopyBagAmount + */ +/** @typedef {{ brand: Brand; value: any }} AnyAmount */ + /** * @template {AssetKind} [K=AssetKind] - * @typedef {object} Amount Amounts are descriptions of digital assets, - * answering the questions "how much" and "of what kind". Amounts are values - * labeled with a brand. AmountMath executes the logic of how amounts are - * changed when digital assets are merged, separated, or otherwise - * manipulated. For example, a deposit of 2 bucks into a purse that already - * has 3 bucks gives a new purse balance of 5 bucks. An empty purse has 0 - * bucks. AmountMath relies heavily on polymorphic MathHelpers, which - * manipulate the unbranded portion. - * @property {Brand} brand - * @property {AssetValueForKind} value + * @template {Key} [M=Key] + * @typedef {K extends 'nat' + * ? NatAmount + * : K extends 'set' + * ? SetAmount + * : K extends 'copySet' + * ? CopySetAmount + * : K extends 'copyBag' + * ? CopyBagAmount + * : AnyAmount} Amount + * Amounts are descriptions of digital assets, answering the questions "how + * much" and "of what kind". Amounts are values labeled with a brand. + * AmountMath executes the logic of how amounts are changed when digital + * assets are merged, separated, or otherwise manipulated. For example, a + * deposit of 2 bucks into a purse that already has 3 bucks gives a new purse + * balance of 5 bucks. An empty purse has 0 bucks. AmountMath relies heavily + * on polymorphic MathHelpers, which manipulate the unbranded portion. */ /** @@ -54,14 +76,15 @@ export {}; /** * @template {AssetKind} K + * @template {Key} [M=Key] member kind, for Amounts that have member values * @typedef {K extends 'nat' * ? NatValue * : K extends 'set' - * ? SetValue + * ? SetValue * : K extends 'copySet' - * ? CopySet + * ? CopySet * : K extends 'copyBag' - * ? import('@endo/patterns').CopyBag + * ? CopyBag * : never} AssetValueForKind */ @@ -94,18 +117,11 @@ export {}; * or AssetKind.SET or AssetKind.COPY_SET (non-fungible) */ +// XXX hack around JSDoc union handling /** - * @template {AssetKind} [K=AssetKind] - * @typedef {object} Brand The brand identifies the kind of issuer, and has a - * function to get the alleged name for the kind of asset described. The - * alleged name (such as 'BTC' or 'moola') is provided by the maker of the - * issuer and should not be trusted as accurate. - * - * Every amount created by a particular AmountMath will share the same brand, - * but recipients cannot rely on the brand to verify that a purported amount - * represents the issuer they intended, since the same brand can be reused by - * a misbehaving issuer. - * @property {(allegedIssuer: ERef) => Promise} isMyIssuer + * @template {AssetKind} K + * @typedef {object} BrandMethods + * @property {(allegedIssuer: ERef>) => Promise} isMyIssuer * Should be used with `issuer.getBrand` to ensure an issuer and brand match. * @property {() => string} getAllegedName * @property {() => DisplayInfo} getDisplayInfo Give information to UI on how @@ -113,6 +129,19 @@ export {}; * @property {() => Pattern} getAmountShape */ +/** + * @template {AssetKind} [K=AssetKind] + * @typedef {RemotableObject & BrandMethods} Brand The brand identifies the + * kind of issuer, and has a function to get the alleged name for the kind of + * asset described. The alleged name (such as 'BTC' or 'moola') is provided by + * the maker of the issuer and should not be trusted as accurate. + * + * Every amount created by a particular issuer will share the same brand, but + * recipients cannot rely on the brand to verify that a purported amount + * represents the issuer they intended, since the same brand can be reused by + * a misbehaving issuer. + */ + // /////////////////////////// Issuer ////////////////////////////////////////// /** @@ -124,13 +153,14 @@ export {}; */ /** * @template {AssetKind} K + * @template {Key} [M=Key] member kind, for Amounts that have member values * @callback IssuerGetAmountOf Get the amount of digital assets in the payment. * Because the payment is not trusted, we cannot call a method on it directly, * and must use the issuer instead. * * If the payment is a promise, the operation will proceed upon fulfillment. - * @param {ERef} payment - * @returns {Promise>} + * @param {ERef>} payment + * @returns {Promise>} */ /** @@ -153,13 +183,9 @@ export {}; */ /** - * @template {AssetKind} [K=AssetKind] - * @typedef {object} Issuer The issuer cannot mint a new amount, but it can - * create empty purses and payments. The issuer can also transform payments - * (splitting payments, combining payments, burning payments, and claiming - * payments exclusively). The issuer should be gotten from a trusted source - * and then relied upon as the decider of whether an untrusted payment is - * valid. + * @template {AssetKind} K + * @template {Key} M + * @typedef {object} IssuerMethods Work around JSDoc union handling * @property {() => Brand} getBrand Get the Brand for this Issuer. The Brand * indicates the type of digital asset and is shared by the mint, the issuer, * and any purses and payments of this particular kind. The brand is not @@ -167,16 +193,28 @@ export {}; * alone. Fake digital assets and amount can use another issuer's brand. * @property {() => string} getAllegedName Get the allegedName for this * mint/issuer - * @property {() => AssetKind} getAssetKind Get the kind of MathHelpers used by - * this Issuer. + * @property {() => K} getAssetKind Get the kind of MathHelpers used by this + * Issuer. * @property {() => DisplayInfo} getDisplayInfo Give information to UI on how * to display amounts for this issuer. - * @property {() => Purse} makeEmptyPurse Make an empty purse of this brand. + * @property {() => Purse} makeEmptyPurse Make an empty purse of this + * brand. * @property {IssuerIsLive} isLive - * @property {IssuerGetAmountOf} getAmountOf + * @property {IssuerGetAmountOf} getAmountOf * @property {IssuerBurn} burn */ +/** + * @template {AssetKind} [K=AssetKind] + * @template {Key} [M=Key] member kind, for Amounts that have member values + * @typedef {RemotableObject & IssuerMethods} Issuer The issuer cannot + * mint a new payment, but it can create empty purses and payments. The issuer + * can also transform payments (splitting payments, combining payments, + * burning payments, and claiming payments exclusively). The issuer should be + * gotten from a trusted source and then relied upon as the decider of whether + * an untrusted payment is valid. + */ + /** * @template {AssetKind} [K=AssetKind] * @typedef {object} PaymentLedger @@ -190,12 +228,13 @@ export {}; /** * @template {AssetKind} [K=AssetKind] + * @template {Key} [M=Key] member kind, for Amounts that have member values * @typedef {object} IssuerKit - * @property {Mint} mint - * @property {Purse} mintRecoveryPurse Externally useful only if this issuer - * uses recovery sets. Can be used to get the recovery set associated with - * minted payments that are still live. - * @property {Issuer} issuer + * @property {Mint} mint + * @property {Purse} mintRecoveryPurse Externally useful only if this + * issuer uses recovery sets. Can be used to get the recovery set associated + * with minted payments that are still live. + * @property {Issuer} issuer * @property {Brand} brand * @property {DisplayInfo} displayInfo */ @@ -216,10 +255,11 @@ export {}; /** * @template {AssetKind} [K=AssetKind] + * @template {Key} [M=Key] member kind, for Amounts that have member values * @typedef {object} Mint Holding a Mint carries the right to issue new digital * assets. These assets all have the same kind, which is called a Brand. - * @property {() => Issuer} getIssuer Gets the Issuer for this mint. - * @property {(newAmount: Amount) => Payment} mintPayment Creates a new + * @property {() => Issuer} getIssuer Gets the Issuer for this mint. + * @property {(newAmount: Amount) => Payment} mintPayment Creates a new * Payment containing newly minted amount. */ @@ -261,40 +301,42 @@ export {}; */ /** - * @template {AssetKind} K - * @callback PurseDeposit - * @param {Payment} payment - * @param {Pattern} [optAmountShape] - * @returns {Amount} + * @template {AssetKind} [K=AssetKind] + * @template {Key} [M=Key] member kind, for Amounts that have member values + * @typedef {RemotableObject & PurseMethods} Purse Purses hold amount of + * digital assets of the same brand, but unlike Payments, they are not meant + * to be sent to others. To transfer digital assets, a Payment should be + * withdrawn from a Purse. The amount of digital assets in a purse can change + * through the action of deposit() and withdraw(). */ /** * @template {AssetKind} [K=AssetKind] - * @typedef {object} Purse Purses hold amount of digital assets of the same - * brand, but unlike Payments, they are not meant to be sent to others. To - * transfer digital assets, a Payment should be withdrawn from a Purse. The - * amount of digital assets in a purse can change through the action of - * deposit() and withdraw(). - * - * The primary use for Purses and Payments is for currency-like and goods-like - * digital assets, but they can also be used to represent other kinds of - * rights, such as the right to participate in a particular contract. + * @template {Key} [M=Key] member kind, for Amounts that have member values + * @typedef {object} PurseMethods The primary use for Purses and Payments is for + * currency-like and goods-like digital assets, but they can also be used to + * represent other kinds of rights, such as the right to participate in a + * particular contract. * @property {() => Brand} getAllegedBrand Get the alleged Brand for this * Purse - * @property {() => Amount} getCurrentAmount Get the amount contained in this - * purse. - * @property {() => LatestTopic>} getCurrentAmountNotifier Get a lossy - * notifier for changes to this purse's balance. - * @property {PurseDeposit} deposit Deposit all the contents of payment into - * this purse, returning the amount. If the optional argument `optAmount` does - * not equal the amount of digital assets in the payment, throw an error. + * @property {() => Amount} getCurrentAmount Get the amount contained in + * this purse. + * @property {() => LatestTopic>} getCurrentAmountNotifier Get a + * lossy notifier for changes to this purse's balance. + * @property {

>( + * payment: P, + * optAmountShape?: Pattern, + * ) => P extends Payment ? Amount : never} deposit + * Deposit all the contents of payment into this purse, returning the amount. If + * the optional argument `optAmount` does not equal the amount of digital + * assets in the payment, throw an error. * * If payment is a promise, throw an error. * @property {() => DepositFacet} getDepositFacet Return an object whose * `receive` method deposits to the current Purse. - * @property {(amount: Amount) => Payment} withdraw Withdraw amount from - * this purse into a new Payment. - * @property {() => CopySet>} getRecoverySet The set of payments + * @property {(amount: Amount) => Payment} withdraw Withdraw amount + * from this purse into a new Payment. + * @property {() => CopySet>} getRecoverySet The set of payments * withdrawn from this purse that are still live. These are the payments that * can still be recovered in emergencies by, for example, depositing into this * purse. Such a deposit action is like canceling an outstanding check because @@ -304,22 +346,23 @@ export {}; * fails. * * Returns an empty set if this issuer does not support recovery sets. - * @property {() => Amount} recoverAll For use in emergencies, such as coming - * back from a traumatic crash and upgrade. This deposits all the payments in - * this purse's recovery set into the purse itself, returning the total amount - * of assets recovered. + * @property {() => Amount} recoverAll For use in emergencies, such as + * coming back from a traumatic crash and upgrade. This deposits all the + * payments in this purse's recovery set into the purse itself, returning the + * total amount of assets recovered. * * Returns an empty amount if this issuer does not support recovery sets. */ /** * @template {AssetKind} [K=AssetKind] - * @typedef {object} Payment Payments hold amount of digital assets of the same - * brand in transit. Payments can be deposited in purses, split into multiple - * payments, combined, and claimed (getting an exclusive payment). Payments - * are linear, meaning that either a payment has the same amount of digital - * assets it started with, or it is used up entirely. It is impossible to - * partially use a payment. + * @template {Key} [M=Key] member kind, for Amounts that have member values + * @typedef {RemotableObject & PaymentMethods} Payment Payments hold amount + * of digital assets of the same brand in transit. Payments can be deposited + * in purses, split into multiple payments, combined, and claimed (getting an + * exclusive payment). Payments are linear, meaning that either a payment has + * the same amount of digital assets it started with, or it is used up + * entirely. It is impossible to partially use a payment. * * Payments are often received from other actors and therefore should not be * trusted themselves. To get the amount of digital assets in a payment, use @@ -328,6 +371,11 @@ export {}; * Payments can be converted to Purses by getting a trusted issuer and calling * `issuer.makeEmptyPurse()` to create a purse, then * `purse.deposit(payment)`. + */ + +/** + * @template {AssetKind} [K=AssetKind] + * @typedef {object} PaymentMethods * @property {() => Brand} getAllegedBrand Get the allegedBrand, indicating * the type of digital asset this payment purports to be, and which issuer to * use. Because payments are not trusted, any method calls on payments should @@ -366,4 +414,7 @@ export {}; /** @typedef {bigint} NatValue */ -/** @typedef {Key[]} SetValue */ +/** + * @template {Key} [K=Key] + * @typedef {K[]} SetValue + */ diff --git a/packages/ERTP/test/swingsetTests/basicFunctionality/bootstrap.js b/packages/ERTP/test/swingsetTests/basicFunctionality/bootstrap.js index 1e70311929d..7fc825aff33 100644 --- a/packages/ERTP/test/swingsetTests/basicFunctionality/bootstrap.js +++ b/packages/ERTP/test/swingsetTests/basicFunctionality/bootstrap.js @@ -9,7 +9,8 @@ export function buildRootObject(vatPowers, vatParameters) { function testBasicFunctionality(aliceMaker) { vatPowers.testLog('start test basic functionality'); const { mint: moolaMint, issuer, brand } = makeIssuerKit('moola'); - const moolaPayment = moolaMint.mintPayment(AmountMath.make(brand, 1000n)); + const amt = AmountMath.make(brand, 1000n); + const moolaPayment = moolaMint.mintPayment(amt); const aliceP = E(aliceMaker).make(issuer, brand, moolaPayment); return E(aliceP).testBasicFunctionality(); diff --git a/packages/ERTP/test/types.test-d.ts b/packages/ERTP/test/types.test-d.ts index 35d024da98e..41102e8629e 100644 --- a/packages/ERTP/test/types.test-d.ts +++ b/packages/ERTP/test/types.test-d.ts @@ -1,11 +1,12 @@ import { Far } from '@endo/marshal'; +import type { Key } from '@endo/patterns'; import { expectType } from 'tsd'; - import { AmountMath, AssetKind } from '../src/index.js'; import type { Amount, AssetValueForKind, Brand, + Issuer, SetValue, } from '../src/types.js'; @@ -18,7 +19,7 @@ import type { expectType(AmountMath.makeEmpty(brand, AssetKind.SET)); expectType>(AmountMath.make(brand, 1n)); - // @ts-expect-error invalid value for brand + // @ts-expect-error invalid value for amount AmountMath.make(brand, {}); } @@ -26,10 +27,10 @@ import type { const brand: Brand<'set'> = Far('setbrand'); expectType>(AmountMath.makeEmpty(brand, 'set')); expectType>(AmountMath.make(brand, [])); - // @ts-expect-error TODO - expectType(AmountMath.make(brand, AssetKind.NAT)); - // @ts-expect-error invalid value for brand + // @ts-expect-error invalid value for amount + AmountMath.make(brand, AssetKind.NAT); + // @ts-expect-error invalid value for amount AmountMath.make(brand, {}); } @@ -43,3 +44,8 @@ import type { // @ts-expect-error 'n' doesn't satisfy AssetKind const n: AssetValueForKind<'n'> = null; } + +{ + const issuer: Issuer = null as any; + expectType(issuer); +} diff --git a/packages/ERTP/test/unitTests/mathHelpers/mockBrand.js b/packages/ERTP/test/unitTests/mathHelpers/mockBrand.js index 14f21b5c7ed..a4ad9feeeeb 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/mockBrand.js +++ b/packages/ERTP/test/unitTests/mathHelpers/mockBrand.js @@ -1,15 +1,52 @@ import { Far } from '@endo/marshal'; import { AssetKind } from '../../../src/index.js'; -/** @import {Brand} from '../../../src/types.js'; */ +/** @import {Brand} from '@agoric/ertp/src/types.js'; */ -/** @type {Brand} */ -export const mockBrand = Far('brand', { +/** @type {Brand<'nat'>} */ +// @ts-expect-error FIXME losing PASS_STYLE +export const mockNatBrand = Far('brand', { // eslint-disable-next-line no-unused-vars isMyIssuer: async allegedIssuer => false, getAllegedName: () => 'mock', - getAmountShape: () => {}, + getAmountShape: () => ({}), getDisplayInfo: () => ({ assetKind: AssetKind.NAT, }), }); + +/** @type {Brand<'set'>} */ +// @ts-expect-error FIXME losing PASS_STYLE +export const mockSetBrand = Far('brand', { + // eslint-disable-next-line no-unused-vars + isMyIssuer: async allegedIssuer => false, + getAllegedName: () => 'mock', + getAmountShape: () => ({}), + getDisplayInfo: () => ({ + assetKind: AssetKind.SET, + }), +}); + +/** @type {Brand<'copySet'>} */ +// @ts-expect-error FIXME losing PASS_STYLE +export const mockCopySetBrand = Far('brand', { + // eslint-disable-next-line no-unused-vars + isMyIssuer: async allegedIssuer => false, + getAllegedName: () => 'mock', + getAmountShape: () => ({}), + getDisplayInfo: () => ({ + assetKind: AssetKind.COPY_SET, + }), +}); + +/** @type {Brand<'copyBag'>} */ +// @ts-expect-error FIXME losing PASS_STYLE +export const mockCopyBagBrand = Far('brand', { + // eslint-disable-next-line no-unused-vars + isMyIssuer: async allegedIssuer => false, + getAllegedName: () => 'mock', + getAmountShape: () => ({}), + getDisplayInfo: () => ({ + assetKind: AssetKind.COPY_BAG, + }), +}); diff --git a/packages/ERTP/test/unitTests/mathHelpers/test-copyBagMathHelpers.js b/packages/ERTP/test/unitTests/mathHelpers/test-copyBagMathHelpers.js index b3e7e6df9cf..1f71539d790 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/test-copyBagMathHelpers.js +++ b/packages/ERTP/test/unitTests/mathHelpers/test-copyBagMathHelpers.js @@ -6,7 +6,7 @@ import { } from '@agoric/store'; import { AmountMath as m, AssetKind } from '../../../src/index.js'; -import { mockBrand } from './mockBrand.js'; +import { mockCopyBagBrand as mockBrand } from './mockBrand.js'; // The "unit tests" for MathHelpers actually make the calls through // AmountMath so that we can test that any duplication is handled diff --git a/packages/ERTP/test/unitTests/mathHelpers/test-copySetMathHelpers.js b/packages/ERTP/test/unitTests/mathHelpers/test-copySetMathHelpers.js index d100c50938b..a0171c5fa38 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/test-copySetMathHelpers.js +++ b/packages/ERTP/test/unitTests/mathHelpers/test-copySetMathHelpers.js @@ -2,7 +2,7 @@ import { test } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js'; import { getCopySetKeys, makeCopySet } from '@agoric/store'; import { AmountMath as m, AssetKind } from '../../../src/index.js'; -import { mockBrand } from './mockBrand.js'; +import { mockCopySetBrand as mockBrand } from './mockBrand.js'; /** @import {CopySet} from '@endo/patterns' */ @@ -209,6 +209,7 @@ test('copySet with strings add', t => { () => m.add( harden({ brand: mockBrand, value: makeCopySet(['a', 'a']) }), + // @ts-expect-error deliberate invalid arguments for testing harden({ brand: mockBrand, value: makeCopySet(['b']) }), ), { message: /value has duplicate(| key)s: "a"/ }, @@ -218,6 +219,7 @@ test('copySet with strings add', t => { () => m.add( harden({ brand: mockBrand, value: makeCopySet(['a']) }), + // @ts-expect-error deliberate invalid arguments for testing harden({ brand: mockBrand, value: makeCopySet(['b', 'b']) }), ), { message: /value has duplicate(| key)s: "b"/ }, diff --git a/packages/ERTP/test/unitTests/mathHelpers/test-natMathHelpers.js b/packages/ERTP/test/unitTests/mathHelpers/test-natMathHelpers.js index d43164ce474..9e19389a8b4 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/test-natMathHelpers.js +++ b/packages/ERTP/test/unitTests/mathHelpers/test-natMathHelpers.js @@ -3,7 +3,7 @@ import { M } from '@agoric/store'; import { Far } from '@endo/marshal'; import { AmountMath as m, AssetKind } from '../../../src/index.js'; -import { mockBrand } from './mockBrand.js'; +import { mockNatBrand as mockBrand } from './mockBrand.js'; // The "unit tests" for MathHelpers actually make the calls through // AmountMath so that we can test that any duplication is handled diff --git a/packages/ERTP/test/unitTests/mathHelpers/test-setMathHelpers.js b/packages/ERTP/test/unitTests/mathHelpers/test-setMathHelpers.js index 716df4ea092..35c58878150 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/test-setMathHelpers.js +++ b/packages/ERTP/test/unitTests/mathHelpers/test-setMathHelpers.js @@ -3,7 +3,7 @@ import { test } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js'; import { Far } from '@endo/marshal'; import { AmountMath as m, AssetKind } from '../../../src/index.js'; -import { mockBrand } from './mockBrand.js'; +import { mockSetBrand as mockBrand } from './mockBrand.js'; // The "unit tests" for MathHelpers actually make the calls through // AmountMath so that we can test that any duplication is handled diff --git a/packages/ERTP/test/unitTests/mathHelpers/test-strSetMathHelpers.js b/packages/ERTP/test/unitTests/mathHelpers/test-strSetMathHelpers.js index 8dd4e886e9a..0677b9b81bf 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/test-strSetMathHelpers.js +++ b/packages/ERTP/test/unitTests/mathHelpers/test-strSetMathHelpers.js @@ -1,7 +1,7 @@ import { test } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js'; import { AmountMath as m, AssetKind } from '../../../src/index.js'; -import { mockBrand } from './mockBrand.js'; +import { mockSetBrand as mockBrand } from './mockBrand.js'; // The "unit tests" for MathHelpers actually make the calls through // AmountMath so that we can test that any duplication is handled diff --git a/packages/ERTP/test/unitTests/test-amountProperties.js b/packages/ERTP/test/unitTests/test-amountProperties.js index 6bfa2d71878..fabe0ebb3f3 100644 --- a/packages/ERTP/test/unitTests/test-amountProperties.js +++ b/packages/ERTP/test/unitTests/test-amountProperties.js @@ -3,7 +3,7 @@ import { makeCopyBag } from '@agoric/store'; import { fc } from '@fast-check/ava'; import { AmountMath as m, AssetKind } from '../../src/index.js'; -import { mockBrand } from './mathHelpers/mockBrand.js'; +import { mockCopyBagBrand as mockBrand } from './mathHelpers/mockBrand.js'; // Perhaps makeCopyBag should coalesce duplicate labels, but for now, it does // not. diff --git a/packages/ERTP/test/unitTests/test-inputValidation.js b/packages/ERTP/test/unitTests/test-inputValidation.js index a1c14adcd50..1f87699fc6d 100644 --- a/packages/ERTP/test/unitTests/test-inputValidation.js +++ b/packages/ERTP/test/unitTests/test-inputValidation.js @@ -144,7 +144,7 @@ test('brand.isMyIssuer bad issuer', async t => { message: /In "isMyIssuer" method of \(myTokens brand\): arg 0: .*"not an issuer" - Must be a remotable/, }); - const fakeIssuer = /** @type {Issuer} */ ( + const fakeIssuer = /** @type {Issuer<'nat'>} */ ( /** @type {unknown} */ (Far('myTokens issuer', {})) ); const result = await brand.isMyIssuer(fakeIssuer); diff --git a/packages/ERTP/test/unitTests/test-legacy-payment-helpers.js b/packages/ERTP/test/unitTests/test-legacy-payment-helpers.js index 2776d06f2dd..43eee8e7e6d 100644 --- a/packages/ERTP/test/unitTests/test-legacy-payment-helpers.js +++ b/packages/ERTP/test/unitTests/test-legacy-payment-helpers.js @@ -9,6 +9,7 @@ const { isEqual } = AmountMath; test('no lost assets on non-atomic combine failure', async t => { const { issuer, mint, brand } = makeIssuerKit('precious'); const recoveryPurse = issuer.makeEmptyPurse(); + /** @param {bigint} num */ const precious = num => AmountMath.make(brand, num); const payment1 = mint.mintPayment(precious(39n)); const payment2 = payment1; // "accidental" aliasing @@ -26,6 +27,7 @@ test('no lost assets on non-atomic combine failure', async t => { test('no lost assets on non-atomic split failure', async t => { const { issuer, mint, brand } = makeIssuerKit('precious'); const recoveryPurse = issuer.makeEmptyPurse(); + /** @param {bigint} num */ const precious = num => AmountMath.make(brand, num); const srcPayment = mint.mintPayment(precious(78n)); await t.throwsAsync(() => split(recoveryPurse, srcPayment, precious(100n)), { diff --git a/packages/ERTP/test/unitTests/test-recovery.js b/packages/ERTP/test/unitTests/test-recovery.js index 3ed6ef326a7..92713b8ef83 100644 --- a/packages/ERTP/test/unitTests/test-recovery.js +++ b/packages/ERTP/test/unitTests/test-recovery.js @@ -8,6 +8,7 @@ const emptySet = makeCopySet([]); test('payment recovery from purse recovery set', async t => { const { issuer, mint, brand } = makeIssuerKit('precious'); + /** @param {bigint} num */ const precious = num => AmountMath.make(brand, num); const payment1 = mint.mintPayment(precious(37n)); const payment2 = mint.mintPayment(precious(41n)); @@ -42,6 +43,7 @@ test('payment recovery from purse recovery set', async t => { test('payment recovery from mint recovery set', async t => { const { issuer, mint, mintRecoveryPurse, brand } = makeIssuerKit('precious'); + /** @param {bigint} num */ const precious = num => AmountMath.make(brand, num); const mindyPurse = issuer.makeEmptyPurse(); const bobPurse = issuer.makeEmptyPurse(); diff --git a/packages/SwingSet/misc-tools/classify-promises.js b/packages/SwingSet/misc-tools/classify-promises.js index 63bafaaf998..410d2b9dbd8 100755 --- a/packages/SwingSet/misc-tools/classify-promises.js +++ b/packages/SwingSet/misc-tools/classify-promises.js @@ -1,4 +1,5 @@ #!/usr/bin/env node +// @ts-nocheck XXX /* eslint no-labels: "off", no-extra-label: "off", no-underscore-dangle: "off" */ import process from 'process'; import sqlite3 from 'better-sqlite3'; diff --git a/packages/SwingSet/package.json b/packages/SwingSet/package.json index 53a803a78ff..425ddcbe761 100644 --- a/packages/SwingSet/package.json +++ b/packages/SwingSet/package.json @@ -100,6 +100,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 75.02 + "atLeast": 74.99 } } diff --git a/packages/SwingSet/src/controller/initializeKernel.js b/packages/SwingSet/src/controller/initializeKernel.js index 67552acf629..3378a28c39f 100644 --- a/packages/SwingSet/src/controller/initializeKernel.js +++ b/packages/SwingSet/src/controller/initializeKernel.js @@ -212,6 +212,7 @@ export async function initializeKernel(config, kernelStorage, options = {}) { // See https://github.com/Agoric/agoric-sdk/issues/2780 errorIdNum: 60_000, }); + // @ts-expect-error xxx const args = kunser(m.serialize(harden([vatObj0s, deviceObj0s]))); const rootKref = exportRootObject(kernelKeeper, bootstrapVatID); const resultKpid = queueToKref(rootKref, 'bootstrap', args, 'panic'); diff --git a/packages/SwingSet/src/devices/bundle/device-bundle.js b/packages/SwingSet/src/devices/bundle/device-bundle.js index d4038c9d935..1b3dfa74d77 100644 --- a/packages/SwingSet/src/devices/bundle/device-bundle.js +++ b/packages/SwingSet/src/devices/bundle/device-bundle.js @@ -103,6 +103,7 @@ export function buildDevice(tools, endowments) { const dispatch = { invoke: (dnid, method, argsCapdata) => { + /** @type {any} */ const args = unserialize(argsCapdata); if (dnid === ROOT) { diff --git a/packages/SwingSet/src/devices/vat-admin/device-vat-admin.js b/packages/SwingSet/src/devices/vat-admin/device-vat-admin.js index 59e9d583852..7e2667d87b3 100644 --- a/packages/SwingSet/src/devices/vat-admin/device-vat-admin.js +++ b/packages/SwingSet/src/devices/vat-admin/device-vat-admin.js @@ -172,6 +172,7 @@ export function buildDevice(tools, endowments) { // D(devices.vatAdmin).addMeterRemaining(meterID, delta) if (method === 'addMeterRemaining') { + /** @type {any} */ const args = unserialize(argsCapdata); const [meterID, delta] = args; assert.typeof(meterID, 'string', 'addMeterRemaining() meterID'); @@ -182,6 +183,7 @@ export function buildDevice(tools, endowments) { // D(devices.vatAdmin).setMeterThreshold(meterID, threshold) if (method === 'setMeterThreshold') { + /** @type {any} */ const args = unserialize(argsCapdata); const [meterID, threshold] = args; assert.typeof(meterID, 'string', 'setMeterThreshold() meterID'); @@ -192,6 +194,7 @@ export function buildDevice(tools, endowments) { // D(devices.vatAdmin).getMeter(meterID) -> { remaining, threshold } if (method === 'getMeter') { + /** @type {any} */ const args = unserialize(argsCapdata); const [meterID] = args; assert.typeof(meterID, 'string', 'getMeter() meterID'); @@ -265,6 +268,7 @@ export function buildDevice(tools, endowments) { // D(devices.bundle).getBundleCap(id) -> bundlecap if (method === 'getBundleCap') { const args = unserialize(argsCapdata); + /** @type {any} */ const [bundleID] = args; assert.typeof(bundleID, 'string', 'getBundleCap() bundleID'); assert(bundleIDRE.test(bundleID), 'getBundleCap() not a bundleID'); @@ -273,6 +277,7 @@ export function buildDevice(tools, endowments) { // D(devices.bundle).getNamedBundleCap(name) -> bundlecap if (method === 'getNamedBundleCap') { const args = unserialize(argsCapdata); + /** @type {any} */ const [name] = args; assert.typeof(name, 'string', 'getNamedBundleCap() name'); let bundleID; @@ -287,6 +292,7 @@ export function buildDevice(tools, endowments) { // D(devices.bundle).getBundleIDByName(name) -> id if (method === 'getBundleIDByName') { const args = unserialize(argsCapdata); + /** @type {any} */ const [name] = args; assert.typeof(name, 'string', 'getBundleIDByName() name'); let bundleID; diff --git a/packages/SwingSet/src/types-external.js b/packages/SwingSet/src/types-external.js index b27d225eacb..3c856bbc399 100644 --- a/packages/SwingSet/src/types-external.js +++ b/packages/SwingSet/src/types-external.js @@ -2,6 +2,11 @@ export {}; +/** + * @import {Guarded} from '@endo/exo'; + * @import {Passable, RemotableObject} from '@endo/pass-style'; + */ + /* This file defines types that part of the external API of swingset. That * includes standard services which user-provided vat code might interact * with, like VatAdminService. */ @@ -350,9 +355,7 @@ export {}; * incarnation. * * - * @typedef {object} CreateVatResults - * @property {object} root - * @property {VatAdminFacet} adminNode + * @typedef {{ adminNode: Guarded, root: object }} CreateVatResults * * @typedef {object} VatAdminSvc * @property {(id: BundleID) => ERef} waitForBundleCap diff --git a/packages/SwingSet/src/vats/timer/vat-timer.js b/packages/SwingSet/src/vats/timer/vat-timer.js index 9dfb411c62f..e9ed5d987b7 100644 --- a/packages/SwingSet/src/vats/timer/vat-timer.js +++ b/packages/SwingSet/src/vats/timer/vat-timer.js @@ -15,6 +15,11 @@ import { import { makeScalarWeakMapStore } from '@agoric/store'; import { TimeMath } from '@agoric/time'; +/** + * @import {Passable, RemotableObject} from '@endo/pass-style'; + * @import {Key} from '@endo/patterns'; + */ + // This consumes O(N) RAM only for outstanding promises, via wakeAt(), // delay(), and Notifiers/Iterators (for each actively-waiting // client). Everything else should remain in the DB. @@ -31,10 +36,10 @@ import { TimeMath } from '@agoric/time'; * Handler is a user-provided Far object with .wake(time) used for callbacks * @property {(scheduled: Timestamp) => unknown} wake * - * @typedef {unknown} CancelToken + * @typedef {Key} CancelToken * CancelToken must be pass-by-reference and durable, either local or remote * - * @typedef {{ + * @typedef {RemotableObject & { * scheduleYourself: () => void, * fired: (now: TimestampValue) => void, * cancel: () => void, @@ -42,7 +47,7 @@ import { TimeMath } from '@agoric/time'; * * @typedef {MapStore} Schedule * - * @typedef {{ cancel: () => void }} Cancellable + * @typedef {RemotableObject & { cancel: () => void }} Cancellable * * @typedef {WeakMapStore} CancelTable * diff --git a/packages/SwingSet/test/devices/device-raw-0.js b/packages/SwingSet/test/devices/device-raw-0.js index 63e673f3dd3..d4e1ff1021b 100644 --- a/packages/SwingSet/test/devices/device-raw-0.js +++ b/packages/SwingSet/test/devices/device-raw-0.js @@ -17,6 +17,7 @@ export function buildDevice(tools, endowments) { const dispatch = { invoke: (dnid, method, argsCapdata) => { + /** @type {any} */ const args = unserialize(argsCapdata); if (dnid === ROOT) { diff --git a/packages/agoric-cli/package.json b/packages/agoric-cli/package.json index 2bf0150b58d..bbf2447c283 100644 --- a/packages/agoric-cli/package.json +++ b/packages/agoric-cli/package.json @@ -98,6 +98,6 @@ "workerThreads": false }, "typeCoverage": { - "atLeast": 76.98 + "atLeast": 76.88 } } diff --git a/packages/agoric-cli/src/commands/auction.js b/packages/agoric-cli/src/commands/auction.js index 78e3d8a8515..a056c6805e5 100644 --- a/packages/agoric-cli/src/commands/auction.js +++ b/packages/agoric-cli/src/commands/auction.js @@ -156,6 +156,7 @@ export const makeAuctionCommand = ( previousOffer: opts.charterAcceptOfferId, invitationMakerName: 'VoteOnParamChange', }, + // @ts-expect-error XXX governance types offerArgs, proposal: {}, }; diff --git a/packages/agoric-cli/src/commands/inter.js b/packages/agoric-cli/src/commands/inter.js index f8353d41c8b..ff181d5d0ec 100644 --- a/packages/agoric-cli/src/commands/inter.js +++ b/packages/agoric-cli/src/commands/inter.js @@ -147,7 +147,7 @@ export const fmtBid = (bid, assets) => { /** @type {{ price: string } | { discount: number }} */ const spec = 'offerPrice' in offerArgs - ? { price: fmt.price(offerArgs.offerPrice) } + ? { price: fmt.price(/** @type {Ratio} */ (offerArgs.offerPrice)) } : { discount: fmt.discount(offerArgs.offerBidScaling) }; const { diff --git a/packages/agoric-cli/src/commands/psm.js b/packages/agoric-cli/src/commands/psm.js index 1daaa99f503..3142fbdbc0e 100644 --- a/packages/agoric-cli/src/commands/psm.js +++ b/packages/agoric-cli/src/commands/psm.js @@ -262,6 +262,7 @@ export const makePsmCommand = logger => { invitationMakerName: 'VoteOnParamChange', }, proposal: {}, + // @ts-expect-error XXX governance types offerArgs: { instance: psmInstance, params: { MintLimit: scaledAmount }, diff --git a/packages/agoric-cli/src/lib/format.js b/packages/agoric-cli/src/lib/format.js index cad70a023dc..9e50c4d6e33 100644 --- a/packages/agoric-cli/src/lib/format.js +++ b/packages/agoric-cli/src/lib/format.js @@ -54,7 +54,9 @@ export const makeAmountFormatter = assets => amt => { return [issuerName, Number(value) / 10 ** decimalPlaces]; case 'set': assert(Array.isArray(value)); + // @ts-expect-error narrowed if (value[0]?.handle?.iface?.includes('InvitationHandle')) { + // @ts-expect-error narrowed return [issuerName, value.map(v => v.description)]; } return [issuerName, value]; diff --git a/packages/agoric-cli/src/lib/wallet.js b/packages/agoric-cli/src/lib/wallet.js index 2aa1e1fe454..610135d2910 100644 --- a/packages/agoric-cli/src/lib/wallet.js +++ b/packages/agoric-cli/src/lib/wallet.js @@ -187,7 +187,7 @@ export const sendAction = async (bridgeAction, opts) => { */ export const findContinuingIds = (current, agoricNames) => { // XXX should runtime type-check - /** @type {{ offerToUsedInvitation: [string, Amount<'set'>][]}} */ + /** @type {{ offerToUsedInvitation: [string, InvitationAmount][]}} */ const { offerToUsedInvitation: entries } = /** @type {any} */ (current); Array.isArray(entries) || Fail`entries must be an array: ${entries}`; diff --git a/packages/base-zone/package.json b/packages/base-zone/package.json index 2dbfe953103..f7ea86438bc 100644 --- a/packages/base-zone/package.json +++ b/packages/base-zone/package.json @@ -56,6 +56,6 @@ "workerThreads": false }, "typeCoverage": { - "atLeast": 88.55 + "atLeast": 89.87 } } diff --git a/packages/base-zone/src/heap.js b/packages/base-zone/src/heap.js index 3445255e8d5..fe6a6a72918 100644 --- a/packages/base-zone/src/heap.js +++ b/packages/base-zone/src/heap.js @@ -12,6 +12,7 @@ import { import { makeOnceKit } from './make-once.js'; import { agoricVatDataKeys as keys } from './keys.js'; +import { watchPromise } from './watch-promise.js'; /** * @type {import('./types.js').Stores} @@ -49,6 +50,7 @@ export const makeHeapZone = (baseLabel = 'heapZone') => { subZone: wrapProvider(makeSubZone), makeOnce, + watchPromise, detached: detachedHeapStores.detached, isStorable: detachedHeapStores.isStorable, diff --git a/packages/base-zone/src/index.js b/packages/base-zone/src/index.js index a7b2ee98e34..7a137f7d54f 100644 --- a/packages/base-zone/src/index.js +++ b/packages/base-zone/src/index.js @@ -10,3 +10,4 @@ export * from './exports.js'; export * from './make-once.js'; export * from './keys.js'; export * from './is-passable.js'; +export * from './watch-promise.js'; diff --git a/packages/base-zone/src/types.js b/packages/base-zone/src/types.js index 207c949837d..26ddc574df4 100644 --- a/packages/base-zone/src/types.js +++ b/packages/base-zone/src/types.js @@ -1,9 +1,16 @@ // eslint-disable-next-line no-unused-vars import { makeExo, defineExoClass, defineExoClassKit } from '@endo/exo'; +// eslint-disable-next-line no-unused-vars +import { watchPromise } from './watch-promise.js'; // Ensure this is a module. export {}; +/** + * @import {Key} from '@endo/patterns'; + * @import {Passable} from '@endo/pass-style'; + */ + /** @typedef {'exoClass' | 'exoClassKit' | 'exo' | 'store' | 'zone'} KeyCategories */ /** @typedef {Record string[]>} KeyMakers */ @@ -19,15 +26,16 @@ export {}; * @property {typeof defineExoClassKit} exoClassKit create a "kit" maker function that can be used to create a record of exo-objects sharing the same state * @property {(key: string, maker: (key: string) => T) => T} makeOnce create or retrieve a singleton object bound to this zone * @property {(label: string, options?: StoreOptions) => Zone} subZone create a new Zone that can be passed to untrusted consumers without exposing the storage of the parent zone + * @property {typeof watchPromise} watchPromise register a promise watcher created by this zone */ /** * @typedef {object} Stores * @property {() => Stores} detached obtain store providers which are detached (the stores are anonymous rather than bound to `label` in the zone) * @property {(specimen: unknown) => boolean} isStorable return true if the specimen can be stored in the zone, whether as exo-object state or in a store - * @property {(label: string, options?: StoreOptions) => MapStore} mapStore provide a Map-like store named `label` in the zone + * @property {(label: string, options?: StoreOptions) => MapStore} mapStore provide a Map-like store named `label` in the zone * @property {(label: string, options?: StoreOptions) => SetStore} setStore provide a Set-like store named `label` in the zone - * @property {( + * @property {( * label: string, options?: StoreOptions) => WeakMapStore * } weakMapStore provide a WeakMap-like store named `label` in the zone * @property {( diff --git a/packages/vow/src/watch-promise.js b/packages/base-zone/src/watch-promise.js similarity index 62% rename from packages/vow/src/watch-promise.js rename to packages/base-zone/src/watch-promise.js index 2b7b403802d..4693bd98377 100644 --- a/packages/vow/src/watch-promise.js +++ b/packages/base-zone/src/watch-promise.js @@ -1,15 +1,36 @@ // @ts-check import { M } from '@endo/patterns'; - -import { basicE } from './vow-utils.js'; +import { E } from '@endo/far'; const { Fail } = assert; const { apply } = Reflect; +/** + * A PromiseWatcher method guard callable with or more arguments, returning void. + */ +export const PromiseWatcherHandler = M.call(M.any()).rest(M.any()).returns(); + +/** + * A PromiseWatcher interface that has both onFulfilled and onRejected handlers. + */ export const PromiseWatcherI = M.interface('PromiseWatcher', { - onFulfilled: M.call(M.any()).rest(M.any()).returns(), - onRejected: M.call(M.any()).rest(M.any()).returns(), + onFulfilled: PromiseWatcherHandler, + onRejected: PromiseWatcherHandler, +}); + +/** + * A PromiseWatcher interface that has only an onFulfilled handler. + */ +export const PromiseWatcherFulfilledI = M.interface('PromiseWatcherFulfilled', { + onFulfilled: PromiseWatcherHandler, +}); + +/** + * A PromiseWatcher interface that has only an onRejected handler. + */ +export const PromiseWatcherRejectedI = M.interface('PromiseWatcherRejected', { + onRejected: PromiseWatcherHandler, }); /** @@ -49,13 +70,13 @@ const callMeMaybe = (that, prop, postArgs) => { * @param {...unknown} watcherArgs * @returns {void} */ -export const watchPromiseShim = (p, watcher, ...watcherArgs) => { +export const watchPromise = (p, watcher, ...watcherArgs) => { Promise.resolve(p) === p || Fail`watchPromise only watches promises`; const onFulfilled = callMeMaybe(watcher, 'onFulfilled', watcherArgs); const onRejected = callMeMaybe(watcher, 'onRejected', watcherArgs); onFulfilled || onRejected || Fail`promise watcher must implement at least one handler method`; - void basicE.when(p, onFulfilled, onRejected); + void E.when(p, onFulfilled, onRejected); }; -harden(watchPromiseShim); +harden(watchPromise); diff --git a/packages/boot/package.json b/packages/boot/package.json index c5723f500f2..a514b9b92e2 100644 --- a/packages/boot/package.json +++ b/packages/boot/package.json @@ -90,6 +90,6 @@ "workerThreads": false }, "typeCoverage": { - "atLeast": 85.88 + "atLeast": 86.47 } } diff --git a/packages/boot/test/bootstrapTests/test-vaults-integration.ts b/packages/boot/test/bootstrapTests/test-vaults-integration.ts index 9d66c9a6f3b..ac78dee6cab 100644 --- a/packages/boot/test/bootstrapTests/test-vaults-integration.ts +++ b/packages/boot/test/bootstrapTests/test-vaults-integration.ts @@ -339,6 +339,7 @@ test('propose change to auction governance param', async t => { previousOffer: 'accept-charter-invitation', invitationMakerName: 'VoteOnParamChange', }, + // @ts-expect-error XXX governance types offerArgs, proposal: {}, }); diff --git a/packages/boot/tools/drivers.ts b/packages/boot/tools/drivers.ts index b2464856d2d..431edc437b3 100644 --- a/packages/boot/tools/drivers.ts +++ b/packages/boot/tools/drivers.ts @@ -96,25 +96,21 @@ export const makeWalletFactoryDriver = async ( }, getCurrentWalletRecord(): CurrentWalletRecord { - const fromCapData = (...args) => - Reflect.apply(marshaller.fromCapData, marshaller, args); return unmarshalFromVstorage( storage.data, `published.wallet.${walletAddress}.current`, - fromCapData, + (...args) => Reflect.apply(marshaller.fromCapData, marshaller, args), -1, - ); + ) as any; }, getLatestUpdateRecord(): UpdateRecord { - const fromCapData = (...args) => - Reflect.apply(marshaller.fromCapData, marshaller, args); return unmarshalFromVstorage( storage.data, `published.wallet.${walletAddress}`, - fromCapData, + (...args) => Reflect.apply(marshaller.fromCapData, marshaller, args), -1, - ); + ) as any; }, }); @@ -286,7 +282,7 @@ export const makeGovernanceDriver = async ( const enactLatestProposal = async () => { const latestQuestionRecord = testKit.readLatest( 'published.committees.Economic_Committee.latestQuestion', - ); + ) as any; const chosenPositions = [latestQuestionRecord.positions[0]]; diff --git a/packages/boot/tools/supports.ts b/packages/boot/tools/supports.ts index 45ca480db63..3f4d2015348 100644 --- a/packages/boot/tools/supports.ts +++ b/packages/boot/tools/supports.ts @@ -283,7 +283,7 @@ export const makeSwingsetTestKit = async ( const { kernelStorage, hostStorage } = swingStore; const { fromCapData } = boardSlottingMarshaller(slotToBoardRemote); - const readLatest = path => { + const readLatest = (path: string): any => { const data = unmarshalFromVstorage(storage.data, path, fromCapData, -1); trace('readLatest', path, 'returning', inspect(data, false, 20, true)); return data; diff --git a/packages/cache/package.json b/packages/cache/package.json index 18959d176a7..5344052b8e5 100644 --- a/packages/cache/package.json +++ b/packages/cache/package.json @@ -47,6 +47,6 @@ "timeout": "20m" }, "typeCoverage": { - "atLeast": 90.97 + "atLeast": 94.12 } } diff --git a/packages/cache/src/cache.js b/packages/cache/src/cache.js index 1788745a74f..19412f78261 100644 --- a/packages/cache/src/cache.js +++ b/packages/cache/src/cache.js @@ -4,9 +4,13 @@ import { E, Far } from '@endo/far'; import { makeScalarStoreCoordinator } from './store.js'; +/** + * @import {Passable, RemotableObject} from '@endo/pass-style'; + */ + /** * @typedef {{ [x: PropertyKey]: any } | string | symbol | bigint | null | - * undefined | number | ((oldValue: any) => ERef)} Update a `newValue` + * undefined | number | ((oldValue: any) => ERef)} Update a `newValue` * to update to. If a function, then it should take an oldValue and return a * `newValue` or promise for `newValue` */ @@ -19,7 +23,7 @@ export const makeCache = (coordinator = makeScalarStoreCoordinator()) => { * The ground state for a cache key value is `undefined`. It is impossible to * distinguish a set value of `undefined` from an unset key * - * @param {unknown} key the cache key (any key type acceptable to the cache) + * @param {Passable} key the cache key (any key type acceptable to the cache) * @param {[] | [Update] | [Update, Pattern]} optUpdateGuardPattern an optional */ const cache = (key, ...optUpdateGuardPattern) => { diff --git a/packages/cache/src/store.js b/packages/cache/src/store.js index 1619641d27c..b3700a284e9 100644 --- a/packages/cache/src/store.js +++ b/packages/cache/src/store.js @@ -7,7 +7,7 @@ import { withGroundState, makeState } from './state.js'; /** @import {Passable} from '@endo/pass-style' */ /** - * @param {(obj: unknown) => unknown} [sanitize] + * @param {(obj: Passable) => Passable} [sanitize] * @returns {(key: Passable) => Promise} */ const makeKeyToString = (sanitize = obj => obj) => { @@ -36,16 +36,16 @@ const makeKeyToString = (sanitize = obj => obj) => { /** * @param {string} keyStr - * @param {(oldValue: unknown) => unknown} txn + * @param {(oldValue: Passable) => Passable} txn * @param {Pattern} guardPattern - * @param {(obj: unknown) => unknown} sanitize Process keys and values with + * @param {(obj: Passable) => Passable} sanitize Process keys and values with * this function before storing them * @param {{ * get(key: string): import('./state.js').State; * set(key: string, value: import('./state.js').State): void; * init(key: string, value: import('./state.js').State): void; * }} stateStore - * @returns {Promise} the value of the updated state + * @returns {Promise} the value of the updated state */ const applyCacheTransaction = async ( keyStr, @@ -112,6 +112,7 @@ const applyCacheTransaction = async ( * @returns {Promise} */ const stringifyStateStore = async (stateStore, marshaller) => { + /** @type {Passable} */ const obj = {}; for (const [key, value] of stateStore.entries()) { obj[key] = E(marshaller).toCapData(value); @@ -126,7 +127,7 @@ const stringifyStateStore = async (stateStore, marshaller) => { * currently enforce any cache eviction, but that would be a useful feature. * * @param {MapStore} [stateStore] - * @param {(obj: unknown) => unknown} [sanitize] Process keys and values with + * @param {(obj: Passable) => Passable} [sanitize] Process keys and values with * this function before storing them. Defaults to deeplyFulfilled. */ export const makeScalarStoreCoordinator = ( diff --git a/packages/cosmic-swingset/package.json b/packages/cosmic-swingset/package.json index 0cf750b91bb..bfc78de8b06 100644 --- a/packages/cosmic-swingset/package.json +++ b/packages/cosmic-swingset/package.json @@ -68,6 +68,6 @@ "timeout": "20m" }, "typeCoverage": { - "atLeast": 80.49 + "atLeast": 80.48 } } diff --git a/packages/deploy-script-support/package.json b/packages/deploy-script-support/package.json index 323234c9559..54c953bcb65 100644 --- a/packages/deploy-script-support/package.json +++ b/packages/deploy-script-support/package.json @@ -73,6 +73,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 81.47 + "atLeast": 81.63 } } diff --git a/packages/deploy-script-support/src/offer.js b/packages/deploy-script-support/src/offer.js index da300ddf9e5..3c03908c865 100644 --- a/packages/deploy-script-support/src/offer.js +++ b/packages/deploy-script-support/src/offer.js @@ -19,7 +19,7 @@ import { AmountMath } from '@agoric/ertp/src/amountMath.js'; * @param {ERef} walletAdmin - an internal type of the * wallet, not defined here * @param {ERef} zoe - * @param {ERef>} zoeInvitationPurse + * @param {ERef>} zoeInvitationPurse */ export const makeOfferAndFindInvitationAmount = ( walletAdmin, @@ -28,7 +28,7 @@ export const makeOfferAndFindInvitationAmount = ( ) => { /** * @param {Record} invitationDetailsCriteria - * @returns {Promise>} invitationAmount + * @returns {Promise} invitationAmount */ const findInvitationAmount = async invitationDetailsCriteria => { const invitationAmount = await E(zoeInvitationPurse).getCurrentAmount(); diff --git a/packages/governance/package.json b/packages/governance/package.json index 5c9dd06f2a8..3e4bf5514d8 100644 --- a/packages/governance/package.json +++ b/packages/governance/package.json @@ -77,6 +77,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 89.25 + "atLeast": 89.31 } } diff --git a/packages/governance/src/contractGovernance/governApi.js b/packages/governance/src/contractGovernance/governApi.js index 386e89e801e..e13debafc73 100644 --- a/packages/governance/src/contractGovernance/governApi.js +++ b/packages/governance/src/contractGovernance/governApi.js @@ -10,6 +10,7 @@ import { } from '../question.js'; /** + * @import {Passable, RemotableObject} from '@endo/pass-style'; * @import {Position, ApiGovernor, ApiInvocationIssue, PoserFacet, VoteOnApiInvocation} from '../types.js'; */ @@ -21,7 +22,7 @@ const { Fail, quote: q } = assert; * arguments that were provided. * * @param {string} apiMethodName - * @param {unknown[]} methodArgs + * @param {Passable[]} methodArgs */ const makeApiInvocationPositions = (apiMethodName, methodArgs) => { const positive = harden({ apiMethodName, methodArgs }); @@ -32,7 +33,7 @@ const makeApiInvocationPositions = (apiMethodName, methodArgs) => { /** * manage contracts that allow governance to invoke functions. * - * @param {ERef<{ [methodName: string]: (...args: any) => unknown }>} governedApis + * @param {ERef<{ [methodName: string]: (...args: any) => Passable }>} governedApis * @param {Array} governedNames names of the governed API methods * @param {ERef} timer * @param {() => Promise} getUpdatedPoserFacet diff --git a/packages/governance/src/contractGovernance/governParam.js b/packages/governance/src/contractGovernance/governParam.js index f06c7d4bb19..789a441d32a 100644 --- a/packages/governance/src/contractGovernance/governParam.js +++ b/packages/governance/src/contractGovernance/governParam.js @@ -78,6 +78,7 @@ const setupParamGovernance = ( paramSpec, ) => { const paramMgr = await E(paramManagerRetriever).get(paramSpec.paramPath); + /** @type {import('@endo/marshal').Passable} */ const changePs = {}; for (const name of Object.keys(paramSpec.changes)) { const proposedValue = E(paramMgr).getVisibleValue( diff --git a/packages/governance/src/contractGovernance/paramManager.js b/packages/governance/src/contractGovernance/paramManager.js index ed96f7cb3df..b9cca051cb5 100644 --- a/packages/governance/src/contractGovernance/paramManager.js +++ b/packages/governance/src/contractGovernance/paramManager.js @@ -49,7 +49,7 @@ const assertElectorateMatches = (paramManager, governedParams) => { * @property {(name: string, value: Invitation) => ParamManagerBuilder} addInvitation * @property {(name: string, value: bigint) => ParamManagerBuilder} addNat * @property {(name: string, value: Ratio) => ParamManagerBuilder} addRatio - * @property {(name: string, value: import('@endo/marshal').CopyRecord) => ParamManagerBuilder} addRecord + * @property {(name: string, value: import('@endo/marshal').CopyRecord) => ParamManagerBuilder} addRecord * @property {(name: string, value: string) => ParamManagerBuilder} addString * @property {(name: string, value: import('@agoric/time').Timestamp) => ParamManagerBuilder} addTimestamp * @property {(name: string, value: import('@agoric/time').RelativeTime) => ParamManagerBuilder} addRelativeTime @@ -184,7 +184,7 @@ const makeParamManagerBuilder = (publisherKit, zoe) => { return builder; }; - /** @type {(name: string, value: import('@endo/marshal').CopyRecord, builder: ParamManagerBuilder) => ParamManagerBuilder} */ + /** @type {(name: string, value: import('@endo/marshal').CopyRecord, builder: ParamManagerBuilder) => ParamManagerBuilder} */ const addRecord = (name, value, builder) => { const assertRecord = v => { passStyleOf(v); diff --git a/packages/governance/src/contractGovernorKit.js b/packages/governance/src/contractGovernorKit.js index 3bdf7e7bf6a..b7b6abe8e5b 100644 --- a/packages/governance/src/contractGovernorKit.js +++ b/packages/governance/src/contractGovernorKit.js @@ -129,7 +129,8 @@ export const prepareContractGovernorKit = (baggage, powers) => { ]); trace('setupApiGovernance'); apiGovernance = governedNames.length - ? setupApiGovernance(governedApis, governedNames, timer, () => + ? // @ts-expect-error FIXME + setupApiGovernance(governedApis, governedNames, timer, () => this.facets.helper.getUpdatedPoserFacet(), ) : { diff --git a/packages/governance/src/types.js b/packages/governance/src/types.js index 23c8e3ddec7..c47b567dc0d 100644 --- a/packages/governance/src/types.js +++ b/packages/governance/src/types.js @@ -1,6 +1,10 @@ export {}; -/** @import {ContractStartFunction} from '@agoric/zoe/src/zoeService/utils.js' */ +/** + * @import {Guarded} from '@endo/exo'; + * @import {Passable, Container} from '@endo/pass-style'; + * @import {ContractStartFunction} from '@agoric/zoe/src/zoeService/utils.js'; + */ /** * @typedef { 'unranked' | 'order' | 'plurality' } ChoiceMethod @@ -34,9 +38,9 @@ export {}; */ /** - * @typedef { Amount | Brand | Installation | Instance | bigint | + * @typedef { Amount | Brand | Installation | Instance | number | bigint | * Ratio | string | import('@agoric/time').TimestampRecord | - * import('@agoric/time').RelativeTimeRecord | unknown } ParamValue + * import('@agoric/time').RelativeTimeRecord | Container } ParamValue */ // XXX better to use the manifest constant ParamTypes @@ -61,7 +65,7 @@ export {}; /** * @template {ParamType} [T=ParamType] - * @typedef {{ type: T, value: ParamValueForType }} ParamValueTyped + * @typedef {{ type: T, value: ParamValueForType }} ParamValueTyped */ /** @@ -73,7 +77,7 @@ export {}; * governedParams: import('./contractGovernance/typedParamManager.js').ParamRecordsFromTypes - * }} GovernanceTerms + * }} GovernanceTerms */ /** @@ -430,7 +434,7 @@ export {}; * @property {(name: string) => Brand} getBrand * @property {(name: string) => Instance} getInstance * @property {(name: string) => Installation} getInstallation - * @property {(name: string) => Amount<'set'>} getInvitationAmount + * @property {(name: string) => InvitationAmount} getInvitationAmount * @property {(name: string) => bigint} getNat * @property {(name: string) => Ratio} getRatio * @property {(name: string) => string} getString @@ -484,7 +488,7 @@ export {}; /** * @typedef {object} ChangeParamsPosition - * @property {Record} changes one or more changes to parameters + * @property {Record} changes one or more changes to parameters */ /** @@ -500,7 +504,7 @@ export {}; /** * @typedef {object} InvokeApiPosition * @property {string} apiMethodName - * @property {unknown[]} methodArgs + * @property {Passable[]} methodArgs */ /** @@ -625,7 +629,7 @@ export {}; /** * @callback VoteOnApiInvocation * @param {string} apiMethodName - * @param {unknown[]} methodArgs + * @param {Passable[]} methodArgs * @param {Installation} voteCounterInstallation * @param {import('@agoric/time').Timestamp} deadline * @returns {Promise} @@ -727,7 +731,7 @@ export {}; * Akin to StartedInstanceKit but designed for the results of starting governed contracts. Used in bootstrap space. * @property {AdminFacet} adminFacet of the governed contract * @property {LimitedCF} creatorFacet creator-like facet within the governed contract (without the powers the governor needs) - * @property {GovernorCreatorFacet} governorCreatorFacet of the governing contract + * @property {Guarded>} governorCreatorFacet of the governing contract * @property {AdminFacet} governorAdminFacet of the governing contract * @property {Awaited>['publicFacet']} publicFacet * @property {Instance} instance diff --git a/packages/governance/test/unitTests/test-typedParamManager.js b/packages/governance/test/unitTests/test-typedParamManager.js index 505d826acfa..a4ef53487db 100644 --- a/packages/governance/test/unitTests/test-typedParamManager.js +++ b/packages/governance/test/unitTests/test-typedParamManager.js @@ -228,6 +228,7 @@ test('Invitation', async t => { const { instance, zcf, zoe } = await setupZCFTest(issuerKeywordRecord, terms); + /** @type {Invitation} */ const invitation = await E(E(zoe).getPublicFacet(instance)).makeInvitation(); const invitationAmount = await E(E(zoe).getInvitationIssuer()).getAmountOf( @@ -251,6 +252,7 @@ test('Invitation', async t => { await eventLoopIteration(); const invitationActualAmount = paramManager.getInvite().value; t.deepEqual(invitationActualAmount, invitationAmount.value); + // @ts-expect-error XXX t.is(invitationActualAmount[0].description, 'simple'); t.is(await paramManager.getInternalParamValue('Invite'), invitation); diff --git a/packages/governance/tools/puppetContractGovernor.js b/packages/governance/tools/puppetContractGovernor.js index 3f6db072a1d..d4edd79883b 100644 --- a/packages/governance/tools/puppetContractGovernor.js +++ b/packages/governance/tools/puppetContractGovernor.js @@ -7,6 +7,7 @@ import { CONTRACT_ELECTORATE } from '../src/contractGovernance/governParam.js'; import { makeApiInvocationPositions } from '../src/contractGovernance/governApi.js'; /** + * @import {Passable, RemotableObject} from '@endo/pass-style'; * @import {GovernableStartFn, ParamChangesSpec} from '../src/types.js'; */ @@ -72,7 +73,7 @@ export const start = async (zcf, privateArgs) => { /** * @param {string} apiMethodName - * @param {unknown[]} methodArgs + * @param {Passable[]} methodArgs */ const invokeAPI = async (apiMethodName, methodArgs) => { const governedNames = await E(governedCF).getGovernedApiNames(); diff --git a/packages/inter-protocol/package.json b/packages/inter-protocol/package.json index ed07d754e13..86f24840e08 100644 --- a/packages/inter-protocol/package.json +++ b/packages/inter-protocol/package.json @@ -83,6 +83,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 95.89 + "atLeast": 95.86 } } diff --git a/packages/inter-protocol/src/auction/auctioneer.js b/packages/inter-protocol/src/auction/auctioneer.js index 8807b00f5a1..88ace013d94 100644 --- a/packages/inter-protocol/src/auction/auctioneer.js +++ b/packages/inter-protocol/src/auction/auctioneer.js @@ -693,7 +693,7 @@ export const start = async (zcf, privateArgs, baggage) => { const creatorFacet = makeFarGovernorFacet( Far('Auctioneer creatorFacet', { /** - * @param {Issuer} issuer + * @param {Issuer<'nat'>} issuer * @param {Keyword} kwd */ async addBrand(issuer, kwd) { diff --git a/packages/inter-protocol/src/auction/sortedOffers.js b/packages/inter-protocol/src/auction/sortedOffers.js index 031c73e3ebe..f1d0e211d49 100644 --- a/packages/inter-protocol/src/auction/sortedOffers.js +++ b/packages/inter-protocol/src/auction/sortedOffers.js @@ -88,6 +88,7 @@ const bidScalingRatioFromKey = (bidScaleFloat, numBrand, useDecimals) => { * @returns {[normalizedPrice: Ratio, sequenceNumber: bigint]} */ export const fromPriceOfferKey = (key, numBrand, denomBrand, useDecimals) => { + // @ts-expect-error XXX const [pricePart, sequenceNumberPart] = decodeData(key); return [ priceRatioFromFloat(pricePart, numBrand, denomBrand, useDecimals), diff --git a/packages/inter-protocol/src/contractSupport.js b/packages/inter-protocol/src/contractSupport.js index 1aec13135a9..3226ce8fddf 100644 --- a/packages/inter-protocol/src/contractSupport.js +++ b/packages/inter-protocol/src/contractSupport.js @@ -21,11 +21,11 @@ export const ratioPattern = harden({ * proposal. We use two Amounts because an Amount cannot represent a negative * number (so we use a "loss" that will be subtracted). * - * @template {AssetKind} K - * @param {Amount} base - * @param {Amount} gain - * @param {Amount} loss - * @returns {Amount} + * @template {Amount} A + * @param {A} base + * @param {A} gain + * @param {A} loss + * @returns {A} */ export const addSubtract = (base, gain, loss) => AmountMath.subtract(AmountMath.add(base, gain), loss); @@ -79,14 +79,14 @@ export const checkDebtLimit = (debtLimit, totalDebt, toMint) => { /** * @template T - * @typedef {object} MetricsPublisherKit + * @typedef {object} MetricsPublisherKit * @property {IterationObserver} metricsPublication * @property {StoredSubscription} metricsSubscription */ /** * @template T - * @typedef {object} MetricsPublishKit + * @typedef {object} MetricsPublishKit * @property {Publisher} metricsPublisher * @property {StoredSubscriber} metricsSubscriber */ diff --git a/packages/inter-protocol/src/econCommitteeCharter.js b/packages/inter-protocol/src/econCommitteeCharter.js index e0ff7192393..6fc146cb167 100644 --- a/packages/inter-protocol/src/econCommitteeCharter.js +++ b/packages/inter-protocol/src/econCommitteeCharter.js @@ -79,6 +79,7 @@ export const start = async (zcf, privateArgs, baggage) => { const governor = instanceToGovernor.get(instance); return E(governor).voteOnParamChanges(counter, deadline, { ...path, + // @ts-expect-error XXX changes: params, }); }; diff --git a/packages/inter-protocol/src/price/fluxAggregatorContract.js b/packages/inter-protocol/src/price/fluxAggregatorContract.js index 3f06800d3e7..0eb968edd2b 100644 --- a/packages/inter-protocol/src/price/fluxAggregatorContract.js +++ b/packages/inter-protocol/src/price/fluxAggregatorContract.js @@ -67,6 +67,7 @@ export const start = async (zcf, privateArgs, baggage) => { // xxx uses contract baggage as issuerBagage, assumes one issuer in this contract /** @type {import('./roundsManager.js').QuoteKit} */ + // @ts-expect-error cast const quoteIssuerKit = prepareIssuerKit( baggage, 'quote', diff --git a/packages/inter-protocol/src/price/roundsManager.js b/packages/inter-protocol/src/price/roundsManager.js index 2d4c1256824..f9436c7b77f 100644 --- a/packages/inter-protocol/src/price/roundsManager.js +++ b/packages/inter-protocol/src/price/roundsManager.js @@ -62,7 +62,7 @@ const validRoundId = roundId => { * @property {number} roundTimeout */ -/** @typedef {IssuerKit<'set'>} QuoteKit */ +/** @typedef {IssuerKit<'set', PriceDescription>} QuoteKit */ /** * @typedef {Readonly< diff --git a/packages/inter-protocol/src/proposals/add-auction.js b/packages/inter-protocol/src/proposals/add-auction.js index 1eafb2e747f..7616e8aac56 100644 --- a/packages/inter-protocol/src/proposals/add-auction.js +++ b/packages/inter-protocol/src/proposals/add-auction.js @@ -121,11 +121,15 @@ export const addAuction = async ({ const { Bid: _istIssuer, ...auctionIssuers } = allIssuers; await Promise.all( Object.keys(auctionIssuers).map(kwd => - E(governedCreatorFacet).addBrand(auctionIssuers[kwd], kwd), + E(governedCreatorFacet).addBrand( + /** @type {Issuer<'nat'>} */ (auctionIssuers[kwd]), + kwd, + ), ), ); newAuctioneerKit.resolve( + // @ts-expect-error XXX governance types harden({ label: 'auctioneer', creatorFacet: governedCreatorFacet, diff --git a/packages/inter-protocol/src/proposals/core-proposal.js b/packages/inter-protocol/src/proposals/core-proposal.js index 11c476629e9..ba31357f616 100644 --- a/packages/inter-protocol/src/proposals/core-proposal.js +++ b/packages/inter-protocol/src/proposals/core-proposal.js @@ -27,7 +27,7 @@ export const storeInterContractStartKits = async ({ }, }) => { /** - * @param {Promise>} storeP + * @param {Promise>} storeP * @param {Promise<{ instance: Instance }>[]} kitPs */ const storeAll = async (storeP, kitPs) => { diff --git a/packages/inter-protocol/src/proposals/econ-behaviors.js b/packages/inter-protocol/src/proposals/econ-behaviors.js index c5fec37281f..c3fbff712bd 100644 --- a/packages/inter-protocol/src/proposals/econ-behaviors.js +++ b/packages/inter-protocol/src/proposals/econ-behaviors.js @@ -166,6 +166,7 @@ export const setupReserve = async ({ ]); reserveKit.resolve( + // @ts-expect-error XXX harden({ label: 'AssetReserve', instance, @@ -350,6 +351,7 @@ export const startVaultFactory = async ( ); vaultFactoryKit.resolve( + // @ts-expect-error XXX harden({ label: 'VaultFactory', creatorFacet: vaultFactoryCreator, @@ -465,6 +467,7 @@ export const startRewardDistributor = async ({ const instanceKit = await E(zoe).startInstance( feeDistributor, { Fee: centralIssuer }, + // @ts-expect-error XXX feeDistributorTerms, undefined, 'feeDistributor', @@ -623,6 +626,7 @@ export const startAuctioneer = async ( ]); auctioneerKit.resolve( + // @ts-expect-error XXX harden({ label: 'auctioneer', creatorFacet: governedCreatorFacet, diff --git a/packages/inter-protocol/src/proposals/startPSM.js b/packages/inter-protocol/src/proposals/startPSM.js index a13e38efc0f..121813acf99 100644 --- a/packages/inter-protocol/src/proposals/startPSM.js +++ b/packages/inter-protocol/src/proposals/startPSM.js @@ -363,6 +363,7 @@ export const makeAnchorAsset = async ( const brand = await E(issuer).getBrand(); const kit = harden({ mint, issuer, brand }); + // @ts-expect-error XXX AssetIssuerKit testFirstAnchorKit.resolve(kit); const toSlotReviver = makeHistoryReviver( @@ -397,6 +398,7 @@ export const makeAnchorAsset = async ( denom, keyword, proposedName, + // @ts-expect-error XXX AssetIssuerKit kit, // with mint ), ]); diff --git a/packages/inter-protocol/src/provisionPool.js b/packages/inter-protocol/src/provisionPool.js index 27a7622cf64..7eb37c61dd1 100644 --- a/packages/inter-protocol/src/provisionPool.js +++ b/packages/inter-protocol/src/provisionPool.js @@ -14,6 +14,8 @@ import { prepareRecorderKitMakers } from '@agoric/zoe/src/contractSupport/record import { TopicsRecordShape } from '@agoric/zoe/src/contractSupport/topics.js'; import { prepareProvisionPoolKit } from './provisionPoolKit.js'; +/** @import {Marshal} from '@endo/marshal'; */ + /** @type {ContractMeta} */ export const meta = { privateArgsShape: M.splitRecord( @@ -45,7 +47,7 @@ harden(meta); * >; * initialPoserInvitation: Invitation; * storageNode: StorageNode; - * marshaller: Marshaller; + * marshaller: Marshal; * metricsOverride?: import('./provisionPoolKit.js').MetricsNotification; * }} privateArgs * @param {import('@agoric/vat-data').Baggage} baggage @@ -84,6 +86,7 @@ export const start = async (zcf, privateArgs, baggage) => { makeProvisionPoolKit({ // XXX governance can change the brand of the amount but should only be able to change the value // NB: changing the brand will break this pool + // @ts-expect-error XXX Brand AssetKind poolBrand: params.getPerAccountInitialAmount().brand, storageNode: privateArgs.storageNode, }), diff --git a/packages/inter-protocol/src/provisionPoolKit.js b/packages/inter-protocol/src/provisionPoolKit.js index 179c562b281..cd87e8571df 100644 --- a/packages/inter-protocol/src/provisionPoolKit.js +++ b/packages/inter-protocol/src/provisionPoolKit.js @@ -1,5 +1,6 @@ // @ts-check import { AmountMath, BrandShape } from '@agoric/ertp'; +import { deeplyFulfilledObject } from '@agoric/internal'; import { UnguardedHelperI } from '@agoric/internal/src/typeGuards.js'; import { observeIteration, @@ -19,7 +20,7 @@ import { } from '@agoric/zoe/src/contractSupport/topics.js'; import { InstanceHandleShape } from '@agoric/zoe/src/typeGuards.js'; import { E } from '@endo/far'; -import { Far, deeplyFulfilled } from '@endo/marshal'; +import { Far } from '@endo/marshal'; const { details: X, quote: q, Fail } = assert; @@ -197,7 +198,7 @@ export const prepareProvisionPoolKit = ( namesByAddressAdmin, walletFactory, }); - const refs = await deeplyFulfilled(obj); + const refs = await deeplyFulfilledObject(obj); Object.assign(this.state, refs); }, makeHandler() { @@ -347,7 +348,6 @@ export const prepareProvisionPoolKit = ( console.log('provisionPool notified of new asset', desc.brand); await zcf.saveIssuer(desc.issuer, desc.issuerName); /** @type {ERef} */ - // @ts-expect-error vbank purse is close enough for our use. const exchangePurse = E(poolBank).getPurse(desc.brand); void observeNotifier( E(exchangePurse).getCurrentAmountNotifier(), diff --git a/packages/inter-protocol/src/vaultFactory/vault.js b/packages/inter-protocol/src/vaultFactory/vault.js index 17ee452ccc7..4a36efccfc3 100644 --- a/packages/inter-protocol/src/vaultFactory/vault.js +++ b/packages/inter-protocol/src/vaultFactory/vault.js @@ -20,7 +20,10 @@ const { quote: q, Fail } = assert; const trace = makeTracer('Vault', true); -/** @import {NormalizedDebt} from './storeUtils.js' */ +/** + * @import {Brand} from '@agoric/ertp/src/types.js'; + * @import {NormalizedDebt} from './storeUtils.js'; + */ /** * @file This has most of the logic for a Vault, to borrow Minted against @@ -301,13 +304,20 @@ export const prepareVault = (baggage, makeRecorderKit, zcf) => { ); }, - /** @param {ZCFSeat} seat */ + /** + * @param {ZCFSeat} seat + * @returns {Amount<'nat'>} + */ getCollateralAllocated(seat) { return seat.getAmountAllocated( 'Collateral', this.facets.helper.collateralBrand(), ); }, + /** + * @param {ZCFSeat} seat + * @returns {Amount<'nat'>} + */ getMintedAllocated(seat) { return seat.getAmountAllocated( 'Minted', diff --git a/packages/inter-protocol/src/vaultFactory/vaultHolder.js b/packages/inter-protocol/src/vaultFactory/vaultHolder.js index 9552d27857f..c4a4acd49b7 100644 --- a/packages/inter-protocol/src/vaultFactory/vaultHolder.js +++ b/packages/inter-protocol/src/vaultFactory/vaultHolder.js @@ -52,6 +52,7 @@ export const prepareVaultHolder = (baggage, makeRecorderKit) => { */ (vault, storageNode) => { // must be the fully synchronous maker because the kit is held in durable state + // @ts-expect-error XXX Patterns const topicKit = makeRecorderKit(storageNode, PUBLIC_TOPICS.vault[1]); return { topicKit, vault }; diff --git a/packages/inter-protocol/src/vaultFactory/vaultManager.js b/packages/inter-protocol/src/vaultFactory/vaultManager.js index fbbde1eb542..c3f74b98bb0 100644 --- a/packages/inter-protocol/src/vaultFactory/vaultManager.js +++ b/packages/inter-protocol/src/vaultFactory/vaultManager.js @@ -439,7 +439,9 @@ export const prepareVaultManagerKit = ( collateralUnit, debtBrand, ); + // @ts-expect-error XXX quotes ephemera.storedQuotesNotifier = makeStoredNotifier( + // @ts-expect-error XXX quotes quoteNotifier, E(storageNode).makeChildNode('quotes'), marshaller, diff --git a/packages/inter-protocol/test/smartWallet/test-psm-integration.js b/packages/inter-protocol/test/smartWallet/test-psm-integration.js index 8aa62f3ae10..65450049c10 100644 --- a/packages/inter-protocol/test/smartWallet/test-psm-integration.js +++ b/packages/inter-protocol/test/smartWallet/test-psm-integration.js @@ -245,7 +245,7 @@ test('govern offerFilter', async t => { invitationBrand, 'invitation brand from context matches zoe', ); - /** @type {Amount<'set'>} */ + /** @type {InvitationAmount} */ const invitationsAmount = NonNullish(balances.get(brand)); t.is(invitationsAmount?.value.length, len, 'invitation count'); return invitationsAmount.value.filter(i => i.description === desc); diff --git a/packages/inter-protocol/test/swingsetTests/psmUpgrade/bootstrap-psm-upgrade.js b/packages/inter-protocol/test/swingsetTests/psmUpgrade/bootstrap-psm-upgrade.js index e3a2d4c9e87..3cb5c471c3d 100644 --- a/packages/inter-protocol/test/swingsetTests/psmUpgrade/bootstrap-psm-upgrade.js +++ b/packages/inter-protocol/test/swingsetTests/psmUpgrade/bootstrap-psm-upgrade.js @@ -131,6 +131,7 @@ export const buildRootObject = async () => { * @param {any} devices */ bootstrap: async (vats, devices) => { + // @ts-expect-error XXX adminNode vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); ({ feeMintAccess, zoeService } = await E(vats.zoe).buildZoe( vatAdmin, @@ -215,6 +216,7 @@ export const buildRootObject = async () => { governorFacets = await E(zoeService).startInstance( NonNullish(installations.puppetContractGovernor), undefined, + // @ts-expect-error XXX timer governorTerms, { governed: { diff --git a/packages/inter-protocol/test/swingsetTests/reserve/bootstrap-assetReserve-upgrade.js b/packages/inter-protocol/test/swingsetTests/reserve/bootstrap-assetReserve-upgrade.js index c6f00c8655a..fce40bbd820 100644 --- a/packages/inter-protocol/test/swingsetTests/reserve/bootstrap-assetReserve-upgrade.js +++ b/packages/inter-protocol/test/swingsetTests/reserve/bootstrap-assetReserve-upgrade.js @@ -188,6 +188,7 @@ export const buildRootObject = async () => { governorFacets = await E(zoeService).startInstance( NonNullish(installations.puppetContractGovernor), undefined, + // @ts-expect-error XXX timer governorTerms, { governed: { diff --git a/packages/inter-protocol/test/vaultFactory/test-replacePriceAuthority.js b/packages/inter-protocol/test/vaultFactory/test-replacePriceAuthority.js index f442a781808..53f04b6bbfc 100644 --- a/packages/inter-protocol/test/vaultFactory/test-replacePriceAuthority.js +++ b/packages/inter-protocol/test/vaultFactory/test-replacePriceAuthority.js @@ -2,13 +2,17 @@ import '@agoric/zoe/exported.js'; import { test as unknownTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import { AmountMath, makeIssuerKit } from '@agoric/ertp'; -import { allValues, makeTracer, objectMap } from '@agoric/internal'; +import { + allValues, + deeplyFulfilledObject, + makeTracer, + objectMap, +} from '@agoric/internal'; import { unsafeMakeBundleCache } from '@agoric/swingset-vat/tools/bundleTool.js'; import { makeRatio } from '@agoric/zoe/src/contractSupport/index.js'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; import { buildManualTimer } from '@agoric/swingset-vat/tools/manual-timer.js'; import { E } from '@endo/eventual-send'; -import { deeplyFulfilled } from '@endo/marshal'; import { TimeMath } from '@agoric/time'; import { providePriceAuthorityRegistry } from '@agoric/vats/src/priceAuthorityRegistry.js'; import { makeScalarMapStore } from '@agoric/vat-data/src/index.js'; @@ -107,11 +111,13 @@ test.before(async t => { referencedUi: undefined, rates: defaultParamValues(run.brand), }; - const frozenCtx = await deeplyFulfilled(harden(contextPs)); + const frozenCtx = await deeplyFulfilledObject(harden(contextPs)); t.context = { ...frozenCtx, bundleCache, + // @ts-expect-error XXX AssetIssuerKit aeth, + // @ts-expect-error XXX AssetIssuerKit run, }; trace(t, 'CONTEXT'); diff --git a/packages/inter-protocol/test/vaultFactory/test-storage.js b/packages/inter-protocol/test/vaultFactory/test-storage.js index 0235c60d91c..a5f579afeaf 100644 --- a/packages/inter-protocol/test/vaultFactory/test-storage.js +++ b/packages/inter-protocol/test/vaultFactory/test-storage.js @@ -147,7 +147,6 @@ test('quotes storage', async t => { quoteValue.amountIn.value, quoteValue.amountOut.value / quoteValue.amountIn.value, ); - // @ts-expect-error thinks the left argument is Number t.is(quoteValue.amountOut.value / quoteValue.amountIn.value, highPrice); }); diff --git a/packages/inter-protocol/test/vaultFactory/test-vaultFactory.js b/packages/inter-protocol/test/vaultFactory/test-vaultFactory.js index 5ab027d7a21..6852667f737 100644 --- a/packages/inter-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/inter-protocol/test/vaultFactory/test-vaultFactory.js @@ -3,7 +3,12 @@ import { test as unknownTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import { AmountMath, AssetKind, makeIssuerKit } from '@agoric/ertp'; import { combine, split } from '@agoric/ertp/src/legacy-payment-helpers.js'; -import { allValues, makeTracer, objectMap } from '@agoric/internal'; +import { + allValues, + deeplyFulfilledObject, + makeTracer, + objectMap, +} from '@agoric/internal'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; import { makeNotifierFromAsyncIterable } from '@agoric/notifier'; import { M, matches } from '@agoric/store'; @@ -21,7 +26,6 @@ import { makeManualPriceAuthority } from '@agoric/zoe/tools/manualPriceAuthority import { documentStorageSchema } from '@agoric/governance/tools/storageDoc.js'; import buildManualTimer from '@agoric/zoe/tools/manualTimer.js'; import { E } from '@endo/eventual-send'; -import { deeplyFulfilled } from '@endo/marshal'; import { calculateCurrentDebt } from '../../src/interest-math.js'; import { SECONDS_PER_YEAR } from '../../src/interest.js'; import { startVaultFactory } from '../../src/proposals/econ-behaviors.js'; @@ -116,11 +120,13 @@ test.before(async t => { referencedUi: undefined, rates: defaultParamValues(run.brand), }; - const frozenCtx = await deeplyFulfilled(harden(contextPs)); + const frozenCtx = await deeplyFulfilledObject(harden(contextPs)); t.context = { ...frozenCtx, bundleCache, + // @ts-expect-error XXX AssetIssuerKit aeth, + // @ts-expect-error XXX AssetIssuerKit run, }; trace(t, 'CONTEXT'); diff --git a/packages/inter-protocol/test/vaultFactory/test-vaultLiquidation.js b/packages/inter-protocol/test/vaultFactory/test-vaultLiquidation.js index 16423355617..45cf37a1bf8 100644 --- a/packages/inter-protocol/test/vaultFactory/test-vaultLiquidation.js +++ b/packages/inter-protocol/test/vaultFactory/test-vaultLiquidation.js @@ -2,7 +2,12 @@ import '@agoric/zoe/exported.js'; import { test as unknownTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import { AmountMath, makeIssuerKit } from '@agoric/ertp'; -import { allValues, makeTracer, objectMap } from '@agoric/internal'; +import { + allValues, + deeplyFulfilledObject, + makeTracer, + objectMap, +} from '@agoric/internal'; import { unsafeMakeBundleCache } from '@agoric/swingset-vat/tools/bundleTool.js'; import { ceilMultiplyBy, @@ -12,7 +17,6 @@ import { import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; import { buildManualTimer } from '@agoric/swingset-vat/tools/manual-timer.js'; import { E } from '@endo/eventual-send'; -import { deeplyFulfilled } from '@endo/marshal'; import { TimeMath } from '@agoric/time'; import { assertPayoutAmount } from '@agoric/zoe/test/zoeTestHelpers.js'; import { multiplyBy } from '@agoric/zoe/src/contractSupport/ratio.js'; @@ -112,11 +116,13 @@ test.before(async t => { referencedUi: undefined, rates: defaultParamValues(run.brand), }; - const frozenCtx = await deeplyFulfilled(harden(contextPs)); + const frozenCtx = await deeplyFulfilledObject(harden(contextPs)); t.context = { ...frozenCtx, bundleCache, + // @ts-expect-error XXX AssetIssuerKit aeth, + // @ts-expect-error XXX AssetIssuerKit run, }; trace(t, 'CONTEXT'); diff --git a/packages/internal/package.json b/packages/internal/package.json index b07150362f0..4801037dd49 100755 --- a/packages/internal/package.json +++ b/packages/internal/package.json @@ -53,6 +53,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 93.01 + "atLeast": 93.81 } } diff --git a/packages/internal/src/lib-chainStorage.js b/packages/internal/src/lib-chainStorage.js index 2591b1370c0..984a72c576e 100644 --- a/packages/internal/src/lib-chainStorage.js +++ b/packages/internal/src/lib-chainStorage.js @@ -5,7 +5,10 @@ import { M } from '@endo/patterns'; import { makeHeapZone } from '@agoric/base-zone/heap.js'; import * as cb from './callback.js'; -/** @import { ERef } from '@endo/far' */ +/** + * @import {ERef} from '@endo/far'; + * @import {PassableCap} from '@endo/marshal'; + */ const { Fail } = assert; @@ -265,7 +268,7 @@ harden(makeStorageNodeChild); /** * @param {ERef} storageNode * @param {ERef} marshaller - * @returns {(value: unknown) => Promise} + * @returns {(value: PassableCap) => Promise} */ export const makeSerializeToStorage = (storageNode, marshaller) => { return async value => { diff --git a/packages/internal/src/marshal.js b/packages/internal/src/marshal.js index fadbfc5d535..a167cf0ea83 100644 --- a/packages/internal/src/marshal.js +++ b/packages/internal/src/marshal.js @@ -72,6 +72,7 @@ harden(assertCapData); * @param {string} key * @param {ReturnType['fromCapData']} fromCapData * @param {number} index index of the desired value in a deserialized stream cell + * @return {any} */ export const unmarshalFromVstorage = (data, key, fromCapData, index) => { const serialized = data.get(key) || Fail`no data for ${key}`; diff --git a/packages/internal/src/storage-test-utils.js b/packages/internal/src/storage-test-utils.js index 3a344e55649..c8765fc3c60 100644 --- a/packages/internal/src/storage-test-utils.js +++ b/packages/internal/src/storage-test-utils.js @@ -6,6 +6,10 @@ import { makeTracer } from './debug.js'; import { isStreamCell, makeChainStorageRoot } from './lib-chainStorage.js'; import { bindAllMethods } from './method-tools.js'; +/** + * @import {Marshaller, StorageEntry, StorageMessage, StorageNode} from './lib-chainStorage.js'; + */ + const { Fail } = assert; const trace = makeTracer('StorTU', false); @@ -113,9 +117,9 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => { } return childEntries; }; - /** @type {import('../src/lib-chainStorage.js').StorageMessage[]} */ + /** @type {StorageMessage[]} */ const messages = []; - /** @param {import('../src/lib-chainStorage.js').StorageMessage} message */ + /** @param {StorageMessage} message */ const toStorage = message => { messages.push(message); @@ -143,7 +147,7 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => { case 'set': case 'setWithoutNotify': { trace('toStorage set', message); - /** @type {import('../src/lib-chainStorage.js').StorageEntry[]} */ + /** @type {StorageEntry[]} */ const newEntries = message.args; for (const [key, value] of newEntries) { if (value != null) { @@ -156,7 +160,7 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => { } case 'append': { trace('toStorage append', message); - /** @type {import('../src/lib-chainStorage.js').StorageEntry[]} */ + /** @type {StorageEntry[]} */ const newEntries = message.args; for (const [key, value] of newEntries) { value != null || Fail`attempt to append with no value`; @@ -203,6 +207,18 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => { harden(makeFakeStorageKit); /** @typedef {ReturnType< typeof makeFakeStorageKit>} FakeStorageKit */ +/** + * @typedef MockChainStorageRootMethods + * @property {(path: string, marshaller?: Marshaller, index?: number) => unknown} getBody + * Defaults to deserializing slot references into plain Remotable + * objects having the specified interface name (as from `Far(iface)`), + * but can accept a different marshaller for producing Remotables + * that e.g. embed the slot string in their iface name. + * @property {() => string[]} keys + */ +/** @typedef {StorageNode & MockChainStorageRootMethods} MockChainStorageRoot */ + +/** @returns {MockChainStorageRoot} */ export const makeMockChainStorageRoot = () => { const { rootNode, data } = makeFakeStorageKit('mockChainStorageRoot'); return Far('mockChainStorage', { @@ -214,7 +230,7 @@ export const makeMockChainStorageRoot = () => { * that e.g. embed the slot string in their iface name. * * @param {string} path - * @param {import('./lib-chainStorage.js').Marshaller} marshaller + * @param {Marshaller} marshaller * @param {number} [index] * @returns {unknown} */ @@ -228,4 +244,3 @@ export const makeMockChainStorageRoot = () => { keys: () => [...data.keys()], }); }; -/** @typedef {ReturnType} MockChainStorageRoot */ diff --git a/packages/internal/test/test-storage-test-utils.js b/packages/internal/test/test-storage-test-utils.js index 5eab748c657..b4d6a76d19b 100644 --- a/packages/internal/test/test-storage-test-utils.js +++ b/packages/internal/test/test-storage-test-utils.js @@ -264,7 +264,7 @@ test('makeFakeStorageKit sequence data', async t => { }); const testUnmarshaller = test.macro((t, format) => { - /** @type {(val: SlottedRemotable) => string} */ + /** @type {(val: import('@endo/marshal').RemotableObject & SlottedRemotable) => string} */ const convertValToSlot = val => val.getBoardId(); const serializeBodyFormat = /** @type {any} */ (format); const m = makeMarshal(convertValToSlot, undefined, { serializeBodyFormat }); diff --git a/packages/kmarshal/src/kmarshal.js b/packages/kmarshal/src/kmarshal.js index b72a204e4d0..707daf6d828 100644 --- a/packages/kmarshal/src/kmarshal.js +++ b/packages/kmarshal/src/kmarshal.js @@ -2,7 +2,10 @@ import { Far, passStyleOf } from '@endo/far'; import { makeMarshal } from '@endo/marshal'; import { assert, Fail } from '@agoric/assert'; -/** @import { ERef } from '@endo/far' */ +/** + * @import { ERef } from '@endo/far'; + * @import {ConvertSlotToVal} from '@endo/marshal'; + */ // Simple wrapper for serializing and unserializing marshalled values inside the // kernel, where we don't actually want to use clists nor actually allocate real @@ -98,9 +101,7 @@ export { makeStandinPromise }; harden(makeStandinPromise); /** - * @param {string} kref - * @param {string} [iface] - * @returns {ERef} + * @type {ConvertSlotToVal} */ export const kslot = (kref, iface = 'undefined') => { assert.typeof(kref, 'string'); diff --git a/packages/network/package.json b/packages/network/package.json index 5a773a6f521..56609704f13 100644 --- a/packages/network/package.json +++ b/packages/network/package.json @@ -68,6 +68,6 @@ "workerThreads": false }, "typeCoverage": { - "atLeast": 89.73 + "atLeast": 89.5 } } diff --git a/packages/network/src/types.js b/packages/network/src/types.js index 204a8a4fcaf..e056672bc5a 100644 --- a/packages/network/src/types.js +++ b/packages/network/src/types.js @@ -3,7 +3,10 @@ // Ensure this is a module. export {}; -/** @import {PromiseVow, Remote} from '@agoric/vow' */ +/** + * @import {Passable, RemotableObject} from '@endo/pass-style'; + * @import {PromiseVow, Remote} from '@agoric/vow'; + */ /** * @template {import('@endo/exo').Methods} M @@ -22,9 +25,12 @@ export {}; */ /** - * @typedef {object} Closable A closable object + * @typedef {object} ClosableI A closable object * @property {() => PromiseVow} close Terminate the object */ +/** + * @typedef {RemotableObject & ClosableI} Closable + */ /** * @typedef {object} Protocol The network Protocol @@ -73,7 +79,7 @@ export {}; */ /** - * @typedef {object} Connection + * @typedef {object} ConnectionI * @property {( * packetBytes: Bytes, * opts?: Record, @@ -84,6 +90,9 @@ export {}; * connection * @property {() => Endpoint} getRemoteAddress Get the name of the counterparty */ +/** + * @typedef {RemotableObject & ConnectionI} Connection + */ /** * @typedef {object} ConnectionHandler A handler for a given Connection diff --git a/packages/notifier/package.json b/packages/notifier/package.json index df54287d709..2113eccd82e 100644 --- a/packages/notifier/package.json +++ b/packages/notifier/package.json @@ -76,6 +76,6 @@ "timeout": "2m" }, "typeCoverage": { - "atLeast": 89.76 + "atLeast": 90.34 } } diff --git a/packages/notifier/src/stored-notifier.js b/packages/notifier/src/stored-notifier.js index ef36fd952c4..0f434ed4789 100644 --- a/packages/notifier/src/stored-notifier.js +++ b/packages/notifier/src/stored-notifier.js @@ -9,6 +9,7 @@ import { observeNotifier } from './asyncIterableAdaptor.js'; * @import {ERef} from '@endo/far'; * @import {BaseNotifier, Notifier} from './types.js'; * @import {Marshaller, StoredFacet, StorageNode, Unserializer} from '@agoric/internal/src/lib-chainStorage.js'; + * @import {PassableCap, RemotableObject} from '@endo/pass-style'; */ /** @@ -25,7 +26,7 @@ import { observeNotifier } from './asyncIterableAdaptor.js'; * the iteration themselves, or obtain information to subscribe to the stored * data out-of-band. * - * @template T + * @template {PassableCap} T * @param {ERef>} notifier * @param {ERef} storageNode * @param {ERef} marshaller diff --git a/packages/notifier/src/storesub.js b/packages/notifier/src/storesub.js index bed0f4e9185..bd9d8ba64a5 100644 --- a/packages/notifier/src/storesub.js +++ b/packages/notifier/src/storesub.js @@ -44,7 +44,7 @@ export const forEachPublicationRecord = async (subscriber, consumeValue) => { * the iteration themselves, or obtain information to subscribe to the stored * data out-of-band. * - * @template T + * @template {import('@endo/marshal').PassableCap} T * @param {Subscriber} subscriber * @param {ERef} storageNode * @param {ERef>} marshaller diff --git a/packages/notifier/src/types.js b/packages/notifier/src/types.js index d8594fb07ee..7533439b677 100644 --- a/packages/notifier/src/types.js +++ b/packages/notifier/src/types.js @@ -226,7 +226,7 @@ export {}; /** * @template T - * @typedef {NotifierInternals & + * @typedef {import('@endo/marshal').RemotableObject & NotifierInternals & * ForkableAsyncIterable & * SharableNotifier * } Notifier an object that can be used to get the current state or updates @@ -249,7 +249,7 @@ export {}; /** * @template T * @typedef {object} NotifierRecord the produced notifier/updater pair - * @property {IterationObserver} updater the (closely-held) notifier producer + * @property {import('@endo/marshal').RemotableObject & IterationObserver} updater the (closely-held) notifier producer * @property {Notifier} notifier the (widely-held) notifier consumer */ diff --git a/packages/notifier/test/iterable-testing-tools.js b/packages/notifier/test/iterable-testing-tools.js index 6849cd80704..1f74a720fa7 100644 --- a/packages/notifier/test/iterable-testing-tools.js +++ b/packages/notifier/test/iterable-testing-tools.js @@ -65,7 +65,7 @@ const refReason = Error('bar'); * * @param {boolean} fails Does the returned async iterable finish successfully * or fail? - * @returns {AsyncIterable} + * @returns {AsyncIterable} */ const makeTestIterable = fails => { return harden({ @@ -251,7 +251,7 @@ export const paula = iterationObserver => { * See the Alice example in the README * * @param {AsyncIterable} asyncIterable - * @returns {Promise} + * @returns {Promise} */ export const alice = async asyncIterable => { const log = []; diff --git a/packages/orchestration/package.json b/packages/orchestration/package.json index ee44b444b45..5ee60428fce 100644 --- a/packages/orchestration/package.json +++ b/packages/orchestration/package.json @@ -80,6 +80,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 96.39 + "atLeast": 96.18 } } diff --git a/packages/orchestration/src/exos/localchainAccountKit.js b/packages/orchestration/src/exos/localchainAccountKit.js index 7a023a96844..37c71421b7e 100644 --- a/packages/orchestration/src/exos/localchainAccountKit.js +++ b/packages/orchestration/src/exos/localchainAccountKit.js @@ -61,6 +61,7 @@ export const prepareLocalchainAccountKit = (baggage, makeRecorderKit, zcf) => { */ (account, storageNode) => { // must be the fully synchronous maker because the kit is held in durable state + // @ts-expect-error XXX Patterns const topicKit = makeRecorderKit(storageNode, PUBLIC_TOPICS.account[1]); return { account, topicKit }; diff --git a/packages/orchestration/src/exos/stakingAccountKit.js b/packages/orchestration/src/exos/stakingAccountKit.js index ba0096e496a..c32f492fcc3 100644 --- a/packages/orchestration/src/exos/stakingAccountKit.js +++ b/packages/orchestration/src/exos/stakingAccountKit.js @@ -117,6 +117,7 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => { */ (account, storageNode, chainAddress, icqConnection, bondDenom) => { // must be the fully synchronous maker because the kit is held in durable state + // @ts-expect-error XXX Patterns const topicKit = makeRecorderKit(storageNode, PUBLIC_TOPICS.account[1]); return { account, chainAddress, topicKit, icqConnection, bondDenom }; diff --git a/packages/pegasus/package.json b/packages/pegasus/package.json index e09454b5b9f..12ab50c5d41 100644 --- a/packages/pegasus/package.json +++ b/packages/pegasus/package.json @@ -70,6 +70,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 91.45 + "atLeast": 90.68 } } diff --git a/packages/pegasus/src/contract.js b/packages/pegasus/src/contract.js index e378b30c104..16d4c33f4c0 100644 --- a/packages/pegasus/src/contract.js +++ b/packages/pegasus/src/contract.js @@ -1,3 +1,4 @@ +// @ts-check import { prepareVowTools } from '@agoric/vat-data/vow.js'; import { makeDurableZone } from '@agoric/zone/durable.js'; import { makePegasus } from './pegasus.js'; @@ -6,10 +7,14 @@ import '@agoric/zoe/exported.js'; import '../exported.js'; +/** + * @import {Remote} from '@agoric/vow'; + */ + /** * @type {ContractStartFn, - * namesByAddress: ERef + * board: Remote, + * namesByAddress: Remote * }>} */ export const start = (zcf, privateArgs, baggage) => { @@ -23,10 +28,12 @@ export const start = (zcf, privateArgs, baggage) => { // start requires that the object passed in must be durable. Given that we // haven't made pegasus durable yet, we'll wrap its non-durable methods within // an exo object to workaround this requirement. + // @ts-expect-error makePegasus returns a remotable object const publicFacet = zone.exo('PublicFacet', undefined, { ...makePegasus({ zcf, board, namesByAddress, when }), }); + // @ts-expect-error XXX durable wrapping non-durable return harden({ publicFacet, }); diff --git a/packages/smart-wallet/package.json b/packages/smart-wallet/package.json index 4548fbcdb9b..93084dbce86 100644 --- a/packages/smart-wallet/package.json +++ b/packages/smart-wallet/package.json @@ -68,6 +68,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 93.99 + "atLeast": 94.36 } } diff --git a/packages/smart-wallet/src/invitations.js b/packages/smart-wallet/src/invitations.js index 34d34a6d872..729686f6718 100644 --- a/packages/smart-wallet/src/invitations.js +++ b/packages/smart-wallet/src/invitations.js @@ -61,7 +61,7 @@ const MAX_PIPE_LENGTH = 2; * @param {ERef} zoe * @param {ERef} agoricNames * @param {Brand<'set'>} invitationBrand - * @param {Purse<'set'>} invitationsPurse + * @param {Purse<'set', InvitationDetails>} invitationsPurse * @param {(fromOfferId: string) => import('./types.js').InvitationMakers} getInvitationContinuation */ export const makeInvitationsHelper = ( @@ -103,9 +103,7 @@ export const makeInvitationsHelper = ( mustMatch(spec, shape.PurseInvitationSpec); const { instance, description } = spec; - // @ts-expect-error TS thinks it's always true. I'm doubtful. (instance && description) || Fail`missing instance or description`; - /** @type {Amount<'set'>} */ const purseAmount = await E(invitationsPurse).getCurrentAmount(); const invitations = AmountMath.getValue(invitationBrand, purseAmount); diff --git a/packages/smart-wallet/src/marshal-contexts.js b/packages/smart-wallet/src/marshal-contexts.js index 475dd4515e5..99789be72e4 100644 --- a/packages/smart-wallet/src/marshal-contexts.js +++ b/packages/smart-wallet/src/marshal-contexts.js @@ -6,7 +6,11 @@ import { DEFAULT_PREFIX } from '@agoric/vats/src/lib-board.js'; const { Fail, quote: q } = assert; -/** @import {BoardId} from '@agoric/vats/src/lib-board.js' */ +/** + * @import {PassableCap} from '@endo/marshal'; + * @import {Key} from '@endo/patterns'; + * @import {BoardId} from '@agoric/vats/src/lib-board.js'; + */ /** * ID from a board made with { prefix: DEFAULT_PREFIX } @@ -23,7 +27,7 @@ const isDefaultBoardId = specimen => { * using prefixes. * * @template {Record>} T - * @typedef {`${string & keyof T}:${Digits}`} WalletSlot + * @typedef {`${string & keyof T}:${Digits}`} WalletSlot */ /** * @template {string} K @@ -70,7 +74,7 @@ const parseWalletSlot = (tables, slot) => { * we an mix them without confusion. * * @template {Record>} T - * @typedef {WalletSlot | BoardId} MixedSlot + * @typedef {WalletSlot | BoardId} MixedSlot */ /** * @typedef {`1` | `12` | `123`} Digits - 1 or more digits. @@ -79,8 +83,8 @@ const parseWalletSlot = (tables, slot) => { */ /** - * @template Slot - * @template Val + * @template {Key} Slot + * @template {PassableCap} Val * * @typedef {{ * bySlot: MapStore, @@ -89,9 +93,9 @@ const parseWalletSlot = (tables, slot) => { */ /** - * @template Slot - * @template Val - * @param {IdTable} table + * @template {Key} Slot + * @template {PassableCap} Val + * @param {IdTable} table * @param {Slot} slot * @param {Val} val */ @@ -126,13 +130,13 @@ export const makeExportContext = () => { byVal: makeScalarMapStore(), }, // TODO: offer, contact, dapp - /** @type {IdTable} */ + /** @type {IdTable} */ unknown: { bySlot: makeScalarMapStore(), byVal: makeScalarMapStore(), }, }; - /** @type {IdTable} */ + /** @type {IdTable} */ const boardObjects = { bySlot: makeScalarMapStore(), byVal: makeScalarMapStore(), @@ -161,7 +165,7 @@ export const makeExportContext = () => { let unknownNonce = 0; /** - * @param {unknown} val + * @param {PassableCap} val * @returns {MixedSlot} */ const valToSlot = val => { @@ -181,7 +185,7 @@ export const makeExportContext = () => { }; /** - * @template V + * @template {PassableCap} V * @param {string & keyof typeof walletObjects} kind * @param {IdTable} table */ @@ -208,14 +212,14 @@ export const makeExportContext = () => { purseEntries: walletObjects.purse.bySlot.entries, /** * @param {BoardId} id - * @param {unknown} val + * @param {PassableCap} val */ initBoardId: (id, val) => { initSlotVal(boardObjects, id, val); }, /** * @param {BoardId} id - * @param {unknown} val + * @param {PassableCap} val */ ensureBoardId: (id, val) => { if (boardObjects.byVal.has(val)) { @@ -238,35 +242,35 @@ const defaultMakePresence = iface => { * Make context for marshalling wallet or board data. * To be imported into the client, which never exports objects. * - * @param {(iface: string) => unknown} [makePresence] + * @param {(iface: string) => PassableCap} [makePresence] */ export const makeImportContext = (makePresence = defaultMakePresence) => { const walletObjects = { - /** @type {IdTable} */ + /** @type {IdTable} */ purse: { bySlot: makeScalarMapStore(), byVal: makeScalarMapStore(), }, - /** @type {IdTable} */ + /** @type {IdTable} */ payment: { bySlot: makeScalarMapStore(), byVal: makeScalarMapStore(), }, - /** @type {IdTable} */ + /** @type {IdTable} */ unknown: { bySlot: makeScalarMapStore(), byVal: makeScalarMapStore(), }, }; - /** @type {IdTable} */ + /** @type {IdTable} */ const boardObjects = { bySlot: makeScalarMapStore(), byVal: makeScalarMapStore(), }; /** - * @template Slot - * @template Val + * @template {Key} Slot + * @template {PassableCap} Val * @param {IdTable} table * @param {Slot} slot * @param {string} iface @@ -308,7 +312,7 @@ export const makeImportContext = (makePresence = defaultMakePresence) => { const valToSlot = { fromBoard: val => boardObjects.byVal.get(val), - /** @param {unknown} val */ + /** @param {PassableCap} val */ fromMyWallet: val => { const kind = findKey(walletObjects, k => walletObjects[k].byVal.has(val)); if (kind === undefined) { @@ -334,14 +338,14 @@ export const makeImportContext = (makePresence = defaultMakePresence) => { return harden({ /** * @param {BoardId} id - * @param {unknown} val + * @param {PassableCap} val */ initBoardId: (id, val) => { initSlotVal(boardObjects, id, val); }, /** * @param {BoardId} id - * @param {unknown} val + * @param {PassableCap} val */ ensureBoardId: (id, val) => { if (boardObjects.byVal.has(val)) { diff --git a/packages/smart-wallet/src/offers.js b/packages/smart-wallet/src/offers.js index bd4b73c0f01..a68536b7dab 100644 --- a/packages/smart-wallet/src/offers.js +++ b/packages/smart-wallet/src/offers.js @@ -10,7 +10,7 @@ import '@agoric/zoe/src/zoeService/types-ambient.js'; * id: OfferId, * invitationSpec: import('./invitations.js').InvitationSpec, * proposal: Proposal, - * offerArgs?: unknown + * offerArgs?: import('@endo/marshal').Passable, * }} OfferSpec */ diff --git a/packages/smart-wallet/src/smartWallet.js b/packages/smart-wallet/src/smartWallet.js index 9ef0da19135..db92dfdbe4d 100644 --- a/packages/smart-wallet/src/smartWallet.js +++ b/packages/smart-wallet/src/smartWallet.js @@ -55,16 +55,7 @@ const trace = makeTracer('SmrtWlt'); * @see {@link ../README.md}} */ -/** @typedef {number | string} OfferId */ - -/** - * @typedef {{ - * id: OfferId, - * invitationSpec: import('./invitations').InvitationSpec, - * proposal: Proposal, - * offerArgs?: unknown - * }} OfferSpec - */ +/** @import {OfferSpec, OfferId} from './offers.js'; */ /** * @typedef {{ @@ -150,7 +141,7 @@ const trace = makeTracer('SmrtWlt'); * address: string, * bank: ERef, * currentStorageNode: StorageNode, - * invitationPurse: Purse<'set'>, + * invitationPurse: Purse<'set', InvitationDetails>, * walletStorageNode: StorageNode, * }} UniqueParams * @@ -770,7 +761,6 @@ export const prepareSmartWallet = (baggage, shared) => { const { registry, invitationBrand } = shared; if (registry.has(brand)) { - // @ts-expect-error virtual purse return E(state.bank).getPurse(brand); } else if (invitationBrand === brand) { return state.invitationPurse; diff --git a/packages/smart-wallet/test/contexts.js b/packages/smart-wallet/test/contexts.js index 7429634122a..728c64a090a 100644 --- a/packages/smart-wallet/test/contexts.js +++ b/packages/smart-wallet/test/contexts.js @@ -62,7 +62,6 @@ export const makeDefaultTestContext = async (t, makeSpace) => { }; const anchor = withAmountUtils( - // @ts-expect-error incomplete typedef await deeplyFulfilledObject(consume.testFirstAnchorKit), ); diff --git a/packages/smart-wallet/test/swingsetTests/upgradeWalletFactory/walletFactory-V2.js b/packages/smart-wallet/test/swingsetTests/upgradeWalletFactory/walletFactory-V2.js index b3282f9f38b..a28040be2ed 100644 --- a/packages/smart-wallet/test/swingsetTests/upgradeWalletFactory/walletFactory-V2.js +++ b/packages/smart-wallet/test/swingsetTests/upgradeWalletFactory/walletFactory-V2.js @@ -27,6 +27,7 @@ export const prepare = async (zcf, privateArgs, baggage) => { const zoe = zcf.getZoeService(); const { storageNode, walletBridgeManager } = privateArgs; + /** @type {MapStore} */ const walletsByAddress = provideDurableMapStore(baggage, 'walletsByAddress'); const provider = makeAtomicProvider(walletsByAddress); diff --git a/packages/smart-wallet/test/test-addAsset.js b/packages/smart-wallet/test/test-addAsset.js index a9072c883b2..0ba36801ba4 100644 --- a/packages/smart-wallet/test/test-addAsset.js +++ b/packages/smart-wallet/test/test-addAsset.js @@ -185,8 +185,9 @@ const makeScenario = t => { const uiBridge = Far('UIBridge', { /** @param {import('@endo/marshal').CapData} offerEncoding */ proposeOffer: async offerEncoding => { - /** @type {import('../src/offers.js').OfferSpec} */ - const offer = ctx.fromBoard.fromCapData(offerEncoding); + const offer = /** @type {import('../src/offers.js').OfferSpec} */ ( + ctx.fromBoard.fromCapData(offerEncoding) + ); const { give, want } = offer.proposal; for await (const [kw, amt] of entries({ ...give, ...want })) { // @ts-expect-error @@ -435,7 +436,6 @@ test.serial('trading in non-vbank asset: game real-estate NFTs', async t => { const { status: { id, result, payouts }, } = update; - // @ts-expect-error cast value to copyBag const names = payouts?.Places.value.payload.map(([name, _qty]) => name); t.log(id, 'result:', result, ', payouts:', names.join(', ')); diff --git a/packages/smart-wallet/test/test-invitation1.js b/packages/smart-wallet/test/test-invitation1.js index 93808a1154a..ad5697b13ff 100644 --- a/packages/smart-wallet/test/test-invitation1.js +++ b/packages/smart-wallet/test/test-invitation1.js @@ -150,7 +150,7 @@ test.before(async t => (t.context = await makeTestContext(t))); test.serial('handle failure to create invitation', async t => { const { powers, makeSmartWallet, spendable, shared } = t.context; const { chainStorage, board } = powers.consume; - /** @type {Issuer<'set'>} */ + /** @type {Issuer<'set', InvitationDetails>} */ // @ts-expect-error cast const invitationIssuer = powers.issuer.consume.Invitation; const address = 'agoric1234'; diff --git a/packages/smart-wallet/test/test-marshal-contexts.js b/packages/smart-wallet/test/test-marshal-contexts.js index 596096da37f..7ee179d0eac 100644 --- a/packages/smart-wallet/test/test-marshal-contexts.js +++ b/packages/smart-wallet/test/test-marshal-contexts.js @@ -62,10 +62,13 @@ test('makeImportContext preserves identity across AMM and wallet', t => { slots: ['board011'], }); - /** @type {Brand[]} */ - const [b1] = context.fromBoard.fromCapData(ammMetricsCapData); - /** @type {Brand[]} */ - const [b2] = context.fromBoard.fromCapData(amm.getMetrics()); + const [b1] = /** @type {Brand[]} */ ( + context.fromBoard.fromCapData(ammMetricsCapData) + ); + + const [b2] = /** @type {Brand[]} */ ( + context.fromBoard.fromCapData(amm.getMetrics()) + ); t.is(b1, b2, 'unserialization twice from same source'); const myWallet = makeOnChainWallet(board); @@ -85,6 +88,7 @@ test('makeImportContext preserves identity across AMM and wallet', t => { slots: ['board011', 'purse:ATOM'], }); + /** @type {any} */ const walletState = context.fromMyWallet.fromCapData(walletCapData); t.is(walletState[0].brand, b1, 'unserialization across sources'); diff --git a/packages/solo/src/pipe-entrypoint.js b/packages/solo/src/pipe-entrypoint.js index 0914ccfa36e..81781f78f9d 100644 --- a/packages/solo/src/pipe-entrypoint.js +++ b/packages/solo/src/pipe-entrypoint.js @@ -29,6 +29,7 @@ const main = async () => { mutex.resolve(undefined); return; } + /** @type {any} */ const as = parse(`${msg}`); deliverator(...as).then(() => send('go')); }); diff --git a/packages/solo/src/pipe.js b/packages/solo/src/pipe.js index 4a743e4144e..ade11381e69 100644 --- a/packages/solo/src/pipe.js +++ b/packages/solo/src/pipe.js @@ -31,6 +31,7 @@ export const connectToPipe = async ({ method, args, deliverInboundToMbx }) => { return; } // console.log('pipe.js', msg); + /** @type {any} */ const as = parse(`${msg}`); deliverInboundToMbx(...as).then(() => cp.send('go')); }); diff --git a/packages/store/package.json b/packages/store/package.json index 56f10b4e2dd..baf5439dd02 100644 --- a/packages/store/package.json +++ b/packages/store/package.json @@ -58,6 +58,6 @@ "timeout": "2m" }, "typeCoverage": { - "atLeast": 86.34 + "atLeast": 89.45 } } diff --git a/packages/store/src/stores/scalarMapStore.js b/packages/store/src/stores/scalarMapStore.js index 63ee0354485..b2c83293183 100644 --- a/packages/store/src/stores/scalarMapStore.js +++ b/packages/store/src/stores/scalarMapStore.js @@ -16,9 +16,9 @@ import { makeWeakMapStoreMethods } from './scalarWeakMapStore.js'; import { makeCurrentKeysKit } from './store-utils.js'; /** - * @import {Passable} from '@endo/pass-style'); - * @import {Key, Pattern} from '@endo/patterns'); - * @import {MapStore, StoreOptions} from '../types.js'; + * @import {Passable} from '@endo/pass-style'; + * @import {Key, Pattern} from '@endo/patterns'; + * @import {MapStore, MapStoreMethods, StoreOptions} from '../types.js'; */ const { quote: q } = assert; @@ -31,7 +31,7 @@ const { quote: q } = assert; * @param {(k: K, v: V) => void} assertKVOkToSet * @param {(k: K) => void} [assertKeyOkToDelete] * @param {string} [tag] - * @returns {MapStore} + * @returns {MapStoreMethods} */ export const makeMapStoreMethods = ( jsmap, @@ -133,11 +133,9 @@ export const makeMapStoreMethods = ( * or remotables. Other storeMaps will accept, for example, copyArrays and * copyRecords, as keys and look them up based on equality of their contents. * - * @template {Key} K - * @template {Passable} V * @param {string} [tag] - the column name for the key * @param {StoreOptions} [options] - * @returns {MapStore} + * @returns {MapStore} */ export const makeScalarMapStore = ( tag = 'key', diff --git a/packages/store/src/stores/scalarSetStore.js b/packages/store/src/stores/scalarSetStore.js index e7698954cd9..620e6ac37ab 100644 --- a/packages/store/src/stores/scalarSetStore.js +++ b/packages/store/src/stores/scalarSetStore.js @@ -11,19 +11,19 @@ import { makeWeakSetStoreMethods } from './scalarWeakSetStore.js'; import { makeCurrentKeysKit } from './store-utils.js'; /** - * @import {Key, Pattern} from '@endo/patterns'); - * @import {SetStore, StoreOptions} from '../types.js'; + * @import {Key, Pattern} from '@endo/patterns'; + * @import {SetStore, SetStoreMethods, StoreOptions} from '../types.js'; */ const { quote: q } = assert; /** - * @template K + * @template {Key} K * @param {Set} jsset * @param {(k: K) => void} assertKeyOkToAdd * @param {(k: K) => void} [assertKeyOkToDelete] * @param {string} [keyName] - * @returns {SetStore} + * @returns {SetStoreMethods} */ export const makeSetStoreMethods = ( jsset, diff --git a/packages/store/src/stores/scalarWeakMapStore.js b/packages/store/src/stores/scalarWeakMapStore.js index ebfee6b9aa6..6bf46df0cbc 100644 --- a/packages/store/src/stores/scalarWeakMapStore.js +++ b/packages/store/src/stores/scalarWeakMapStore.js @@ -6,12 +6,17 @@ import { isCopyMap, } from '@endo/patterns'; -/** @import {WeakMapStore, StoreOptions} from '../types.js'; */ +/** + * @import {Key} from '@endo/patterns'; + * @import {Passable, RemotableObject} from '@endo/pass-style'; + * @import {WeakMapStore, StoreOptions} from '../types.js'; + */ const { quote: q, Fail } = assert; /** - * @template K,V + * @template {Key} K + * @template {Passable} V * @param {WeakMap} jsmap * @param {(k: K, v: V) => void} assertKVOkToAdd * @param {(k: K, v: V) => void} assertKVOkToSet @@ -66,6 +71,7 @@ export const makeWeakMapStoreMethods = ( addAll: entries => { if (typeof entries[Symbol.iterator] !== 'function') { if (Object.isFrozen(entries) && isCopyMap(entries)) { + // @ts-expect-error XXX entries = getCopyMapEntries(entries); } else { Fail`provided data source is not iterable: ${entries}`; @@ -96,7 +102,7 @@ export const makeWeakMapStoreMethods = ( * @template K,V * @param {string} [tag] - tag for debugging * @param {StoreOptions} [options] - * @returns {WeakMapStore} + * @returns {RemotableObject & WeakMapStore} */ export const makeScalarWeakMapStore = ( tag = 'key', diff --git a/packages/store/src/stores/scalarWeakSetStore.js b/packages/store/src/stores/scalarWeakSetStore.js index 8bc8cab8a9c..cc5762b4785 100644 --- a/packages/store/src/stores/scalarWeakSetStore.js +++ b/packages/store/src/stores/scalarWeakSetStore.js @@ -8,15 +8,18 @@ import { const { quote: q, Fail } = assert; -/** @import {StoreOptions, WeakSetStore} from '@agoric/store'; */ +/** + * @import {Key} from '@endo/patterns'; + * @import {StoreOptions, WeakSetStore, WeakSetStoreMethods} from '@agoric/store'; + */ /** - * @template K + * @template {Key} K * @param {WeakSet} jsset * @param {(k: K) => void} assertKeyOkToAdd * @param {(k: K) => void} [assertKeyOkToDelete] * @param {string} [keyName] - * @returns {WeakSetStore} + * @returns {WeakSetStoreMethods} */ export const makeWeakSetStoreMethods = ( jsset, @@ -50,6 +53,7 @@ export const makeWeakSetStoreMethods = ( addAll: keys => { if (typeof keys[Symbol.iterator] !== 'function') { if (Object.isFrozen(keys) && isCopySet(keys)) { + // @ts-expect-error XXX keys = getCopySetKeys(keys); } else { Fail`provided data source is not iterable: ${keys}`; diff --git a/packages/store/src/stores/store-utils.js b/packages/store/src/stores/store-utils.js index 953386589fd..77ca084ee42 100644 --- a/packages/store/src/stores/store-utils.js +++ b/packages/store/src/stores/store-utils.js @@ -1,14 +1,42 @@ import { Far } from '@endo/marshal'; +import { M, matches } from '@endo/patterns'; /** * @import {RankCompare} from '@endo/marshal'; * @import {MapStore, WeakMapStore} from '../types.js'; + * @import {Passable} from '@endo/pass-style'; + * @import {Key} from '@endo/patterns'; */ const { Fail, quote: q } = assert; +// TODO: Undate `@endo/patterns` to export the original, and delete the +// reimplementation here. /** - * @template K,V + * Should behave identically to the one in `@endo/patterns`, but reimplemented + * for now because `@endo/patterns` forgot to export this one. This one is + * simple enough that I prefer a reimplementation to a deep import. + * + * @param {unknown} s + * @returns {s is CopySet} + */ +export const isCopySet = s => matches(s, M.set()); + +// TODO: Undate `@endo/patterns` to export the original, and delete the +// reimplementation here. +/** + * Should behave identically to the one in `@endo/patterns`, but reimplemented + * for now because `@endo/patterns` forgot to export this one. This one is + * simple enough that I prefer a reimplementation to a deep import. + * + * @param {unknown} m + * @returns {m is CopyMap} + */ +export const isCopyMap = m => matches(m, M.map()); + +/** + * @template {Key} K + * @template {Passable} V * @typedef {object} CurrentKeysKit * @property {(k: K, v?: V) => void} assertUpdateOnAdd * @property {(k: K) => void} assertUpdateOnDelete @@ -16,7 +44,8 @@ const { Fail, quote: q } = assert; */ /** - * @template K,V + * @template {Key} K + * @template {Passable} V * @param {() => Iterable} getRawKeys * @param {(k: K) => boolean} checkHas * @param {RankCompare} compare @@ -91,7 +120,8 @@ harden(makeCurrentKeysKit); * already is one, return that. Otherwise, call `makeValue(key)`, remember it as * the value for that key, and return it. * - * @template K,V + * @template {Key} K + * @template {Passable} V * @param {WeakMapStore} mapStore * @param {K} key * @param {(key: K) => V} makeValue @@ -116,8 +146,8 @@ harden(provideLazy); * termination to happen after the make completes and before it reaches durable * storage. * - * @template K - * @template V + * @template {Key} K + * @template {Passable} V * @param {WeakMapStore} store */ export const makeAtomicProvider = store => { @@ -167,13 +197,14 @@ export const makeAtomicProvider = store => { }; harden(makeAtomicProvider); /** - * @template K - * @template V + * @template {Key} K + * @template {Passable} V * @typedef {ReturnType>} AtomicProvider */ /** - * @template K, V + * @template {Key} K + * @template {Passable} V * @param {MapStore} mapStore * @param {K} key * @param {V} item diff --git a/packages/store/src/types.js b/packages/store/src/types.js index f55b6f40047..45978b51cf4 100644 --- a/packages/store/src/types.js +++ b/packages/store/src/types.js @@ -6,7 +6,7 @@ export {}; /** * Note TODO https://github.com/endojs/endo/issues/1488 * - * @import {Passable} from '@endo/pass-style' + * @import {Passable, RemotableObject} from '@endo/pass-style' * @import {CopySet, CopyMap, Pattern} from '@endo/patterns' * @import {Key} from '@endo/patterns' */ @@ -49,9 +49,10 @@ export {}; * WeakStores, but with the additional query and query-update methods. */ +// TODO use Key for K /** - * @template {Key & object} [K=Key] - * @typedef {object} WeakSetStore + * @template K + * @typedef {object} WeakSetStoreMethods * @property {(key: K) => boolean} has Check if a key exists. The key can be any * JavaScript value, though the answer will always be false for keys that * cannot be found in this store. @@ -60,12 +61,17 @@ export {}; * this store. For example a scalar store only allows primitives and * remotables. * @property {(key: K) => void} delete Remove the key. Throws if not found. - * @property {(keys: CopySet | Iterable) => void} addAll + * @property {(keys: CopySet | Iterable) => void} addAll + */ +/** + * @template K + * @typedef {RemotableObject & WeakSetStoreMethods} WeakSetStore */ +// TODO use Key for K /** - * @template {Key} [K=Key] - * @typedef {object} SetStore + * @template K + * @typedef {object} SetStoreMethods * @property {(key: K) => boolean} has Check if a key exists. The key can be any * JavaScript value, though the answer will always be false for keys that * cannot be found in this store. @@ -74,17 +80,23 @@ export {}; * this store. For example a scalar store only allows primitives and * remotables. * @property {(key: K) => void} delete Remove the key. Throws if not found. - * @property {(keys: CopySet | Iterable) => void} addAll + * @property {(keys: CopySet | Iterable) => void} addAll * @property {(keyPatt?: Pattern) => Iterable} keys * @property {(keyPatt?: Pattern) => Iterable} values - * @property {(keyPatt?: Pattern) => CopySet} snapshot + * @property {(keyPatt?: Pattern) => CopySet} snapshot * @property {(keyPatt?: Pattern) => number} getSize * @property {(keyPatt?: Pattern) => void} clear */ +/** + * @template K + * @typedef {RemotableObject & SetStoreMethods} SetStore + */ +// TODO use Key for K +// TODO use Passable for V /** - * @template {Key & object} [K=Key] - * @template {Passable} [V=Passable] + * @template K + * @template V * @typedef {object} WeakMapStore * @property {(key: K) => boolean} has Check if a key exists. The key can be any * JavaScript value, though the answer will always be false for keys that @@ -96,13 +108,15 @@ export {}; * example a scalar store only allows primitives and remotables. * @property {(key: K, value: V) => void} set Set the key. Throws if not found. * @property {(key: K) => void} delete Remove the key. Throws if not found. - * @property {(entries: CopyMap | Iterable<[K, V]>) => void} addAll + * @property {(entries: CopyMap | Iterable<[K, V]>) => void} addAll */ +// TODO use Key for K +// TODO use Passable for V /** - * @template {Key} [K=Key] - * @template {Passable} [V=Passable] - * @typedef {object} MapStore + * @template K + * @template V + * @typedef {object} MapStoreMethods * @property {(key: K) => boolean} has Check if a key exists. The key can be any * JavaScript value, though the answer will always be false for keys that * cannot be found in this map @@ -113,14 +127,22 @@ export {}; * example a scalar store only allows primitives and remotables. * @property {(key: K, value: V) => void} set Set the key. Throws if not found. * @property {(key: K) => void} delete Remove the key. Throws if not found. - * @property {(entries: CopyMap | Iterable<[K, V]>) => void} addAll + * @property {(entries: CopyMap | Iterable<[K, V]>) => void} addAll * @property {(keyPatt?: Pattern, valuePatt?: Pattern) => Iterable} keys * @property {(keyPatt?: Pattern, valuePatt?: Pattern) => Iterable} values * @property {(keyPatt?: Pattern, valuePatt?: Pattern) => Iterable<[K, V]>} entries - * @property {(keyPatt?: Pattern, valuePatt?: Pattern) => CopyMap} snapshot + * @property {( + * keyPatt?: Pattern, + * valuePatt?: Pattern, + * ) => CopyMap} snapshot * @property {(keyPatt?: Pattern, valuePatt?: Pattern) => number} getSize * @property {(keyPatt?: Pattern, valuePatt?: Pattern) => void} clear */ +/** + * @template [K=any] + * @template [V=any] + * @typedef {RemotableObject & MapStoreMethods} MapStore + */ // ///////////////////////// Deprecated Legacy ///////////////////////////////// diff --git a/packages/swing-store/src/exporter.js b/packages/swing-store/src/exporter.js index 799877e7e66..0666c7240ec 100644 --- a/packages/swing-store/src/exporter.js +++ b/packages/swing-store/src/exporter.js @@ -13,11 +13,11 @@ import { validateArtifactMode } from './internal.js'; /** * @template T - * @typedef { Iterable | AsyncIterable } AnyIterable + * @typedef { Iterable | AsyncIterable } AnyIterable */ /** * @template T - * @typedef { IterableIterator | AsyncIterableIterator } AnyIterableIterator + * @typedef { IterableIterator | AsyncIterableIterator } AnyIterableIterator */ /** diff --git a/packages/swing-store/src/snapStore.js b/packages/swing-store/src/snapStore.js index 3d1ac29f743..3d67ad503b8 100644 --- a/packages/swing-store/src/snapStore.js +++ b/packages/swing-store/src/snapStore.js @@ -25,8 +25,7 @@ import { buffer } from './util.js'; */ /** - * @template T - * @typedef { import('./exporter.js').AnyIterableIterator } AnyIterableIterator + * @import {AnyIterableIterator} from './exporter.js' */ /** diff --git a/packages/swingset-liveslots/package.json b/packages/swingset-liveslots/package.json index 655192ee75e..9d5141ecb79 100644 --- a/packages/swingset-liveslots/package.json +++ b/packages/swingset-liveslots/package.json @@ -67,6 +67,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 75.29 + "atLeast": 75.24 } } diff --git a/packages/swingset-liveslots/src/collectionManager.js b/packages/swingset-liveslots/src/collectionManager.js index 3fa8a245be8..178514988f8 100644 --- a/packages/swingset-liveslots/src/collectionManager.js +++ b/packages/swingset-liveslots/src/collectionManager.js @@ -26,6 +26,10 @@ import { } from './vatstore-iterators.js'; import { makeCache } from './cache.js'; +/** + * @import {ToCapData, FromCapData} from '@endo/marshal'; + */ + // XXX TODO: The following key length limit was put in place due to limitations // in LMDB. With the move away from LMDB, it is no longer relevant, but I'm // leaving it in place for the time being as a general defensive measure against @@ -112,8 +116,8 @@ function makeSchemaCache(syscall, unserialize) { * @param {(val: any) => string | undefined} convertValToSlot * @param {*} convertSlotToVal * @param {*} registerValue - * @param {import('@endo/marshal').ToCapData} serialize - * @param {import('@endo/marshal').FromCapData} unserialize + * @param {ToCapData} serialize + * @param {FromCapData} unserialize * @param {(capDatas: any) => void} assertAcceptableSyscallCapdataSize */ export function makeCollectionManager( diff --git a/packages/swingset-liveslots/src/vatDataTypes.d.ts b/packages/swingset-liveslots/src/vatDataTypes.d.ts index 39c3ff7a32d..b1af421557d 100644 --- a/packages/swingset-liveslots/src/vatDataTypes.d.ts +++ b/packages/swingset-liveslots/src/vatDataTypes.d.ts @@ -5,7 +5,6 @@ * Behavior is a description when defining a kind of what facets it will have. * For the non-multi defineKind, there is just one facet so it doesn't have a key. */ -import type { InterfaceGuard, Pattern } from '@endo/patterns'; import type { MapStore, SetStore, @@ -14,6 +13,8 @@ import type { WeakSetStore, } from '@agoric/store'; import type { StateShape } from '@endo/exo'; +import type { RemotableObject } from '@endo/pass-style'; +import type { InterfaceGuard, Pattern } from '@endo/patterns'; import type { makeWatchedPromiseManager } from './watchedPromises.js'; // TODO should be moved into @endo/patterns and eventually imported here @@ -37,7 +38,7 @@ type OmitFirstArg = F extends (x: any, ...args: infer P) => infer R ? (...args: P) => R : never; -export type KindFacet = { +export type KindFacet = RemotableObject & { [K in keyof O]: OmitFirstArg; // omit the 'context' parameter }; diff --git a/packages/swingset-liveslots/src/virtualObjectManager.js b/packages/swingset-liveslots/src/virtualObjectManager.js index 63b653c8354..3a349f483cc 100644 --- a/packages/swingset-liveslots/src/virtualObjectManager.js +++ b/packages/swingset-liveslots/src/virtualObjectManager.js @@ -24,6 +24,7 @@ import { * @import {DurableKindHandle} from '@agoric/swingset-liveslots' * @import {DefineKindOptions} from '@agoric/swingset-liveslots' * @import {ClassContextProvider, KitContextProvider} from '@endo/exo' + * @import {ToCapData, FromCapData} from '@endo/marshal'; */ const { @@ -276,8 +277,8 @@ const insistSameCapData = (oldCD, newCD) => { * @param {(slot: string) => object} requiredValForSlot * @param {*} registerValue Function to register a new slot+value in liveSlot's * various tables - * @param {import('@endo/marshal').ToCapData} serialize Serializer for this vat - * @param {import('@endo/marshal').FromCapData} unserialize Unserializer for this vat + * @param {ToCapData} serialize Serializer for this vat + * @param {FromCapData} unserialize Unserializer for this vat * @param {*} assertAcceptableSyscallCapdataSize Function to check for oversized * syscall params * @param {import('./types.js').LiveSlotsOptions} [liveSlotsOptions] diff --git a/packages/swingset-runner/package.json b/packages/swingset-runner/package.json index e6d0ae3eb12..c61d73a409e 100644 --- a/packages/swingset-runner/package.json +++ b/packages/swingset-runner/package.json @@ -59,6 +59,6 @@ "timeout": "2m" }, "typeCoverage": { - "atLeast": 55.46 + "atLeast": 54.95 } } diff --git a/packages/telemetry/package.json b/packages/telemetry/package.json index a4cf37d3e97..ab45e418d03 100644 --- a/packages/telemetry/package.json +++ b/packages/telemetry/package.json @@ -63,6 +63,6 @@ "workerThreads": false }, "typeCoverage": { - "atLeast": 87.07 + "atLeast": 87.04 } } diff --git a/packages/telemetry/src/slog-to-otel.js b/packages/telemetry/src/slog-to-otel.js index 0cadc4911d0..e53583d1b21 100644 --- a/packages/telemetry/src/slog-to-otel.js +++ b/packages/telemetry/src/slog-to-otel.js @@ -139,7 +139,10 @@ export const makeSlogToOtelKit = (tracer, overrideAttrs = {}) => { serializeBodyFormat: 'smallcaps', }); - /** @param {import('@agoric/swingset-vat').SwingSetCapData} data */ + /** + * @param {import('@agoric/swingset-vat').SwingSetCapData} data + * @returns {any} + */ const unserialize = data => { try { const body = rawUnserialize(data); diff --git a/packages/time/package.json b/packages/time/package.json index 5f284f9a674..3809a3b1d79 100644 --- a/packages/time/package.json +++ b/packages/time/package.json @@ -54,6 +54,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 86.95 + "atLeast": 87.11 } } diff --git a/packages/time/src/types.d.ts b/packages/time/src/types.d.ts index f2efe31c124..d305ae4744e 100644 --- a/packages/time/src/types.d.ts +++ b/packages/time/src/types.d.ts @@ -1,6 +1,6 @@ -import type { ERef } from '@endo/eventual-send'; +import type { ERef, RemotableBrand } from '@endo/eventual-send'; -import type { RankComparison } from '@endo/marshal'; +import type { RankComparison, RemotableObject } from '@endo/marshal'; /// @@ -28,7 +28,7 @@ import type { RankComparison } from '@endo/marshal'; * See https://github.com/Agoric/agoric-sdk/issues/5798 * and https://github.com/Agoric/agoric-sdk/pull/5821 */ -export type TimerBrand = { +export type TimerBrand = RemotableObject & { isMyTimerService: (timer: TimerService) => ERef; isMyClock: (clock: Clock) => ERef; }; @@ -107,7 +107,7 @@ export type CancelToken = object; * schedule a single wake() call, create a repeater that will allow scheduling * of events at regular intervals, or remove scheduled calls. */ -export interface TimerService { +export interface TimerServiceI { /** * Retrieve the latest timestamp */ @@ -181,6 +181,10 @@ export interface TimerService { */ getTimerBrand: () => TimerBrand; } +// XXX copied from Remotable helper return type +export type TimerService = TimerServiceI & + RemotableObject<'TimerService'> & + RemotableBrand<{}, TimerServiceI>; /** * Read-only access to a TimeService's current time. This allows reading the diff --git a/packages/vat-data/package.json b/packages/vat-data/package.json index dbbc8e6750a..b92466dae99 100644 --- a/packages/vat-data/package.json +++ b/packages/vat-data/package.json @@ -21,7 +21,6 @@ "dependencies": { "@agoric/assert": "^0.6.0", "@agoric/base-zone": "^0.1.0", - "@agoric/internal": "^0.3.2", "@agoric/store": "^0.9.2", "@agoric/swingset-liveslots": "^0.10.2", "@agoric/vow": "^0.1.0", @@ -30,7 +29,6 @@ }, "devDependencies": { "@endo/init": "^1.1.1", - "@endo/far": "^1.1.1", "@endo/ses-ava": "^1.2.1", "ava": "^5.3.0", "tsd": "^0.30.7" diff --git a/packages/vat-data/src/exo-utils.js b/packages/vat-data/src/exo-utils.js index a718afa35cc..4c52bf180a7 100644 --- a/packages/vat-data/src/exo-utils.js +++ b/packages/vat-data/src/exo-utils.js @@ -5,8 +5,9 @@ import { initEmpty } from '@agoric/store'; import { provide, VatData as globalVatData } from './vat-data-bindings.js'; /** - * @import {InterfaceGuard} from '@endo/patterns' - * @import {Baggage, DefineKindOptions, DurableKindHandle, InterfaceGuardKit} from '@agoric/swingset-liveslots' + * @import {InterfaceGuard} from '@endo/patterns'; + * @import {RemotableObject} from '@endo/pass-style'; + * @import {Baggage, DefineKindOptions, DurableKindHandle, InterfaceGuardKit} from '@agoric/swingset-liveslots'; */ /** @@ -206,7 +207,7 @@ export const makeExoUtils = VatData => { * @param {InterfaceGuard | undefined} interfaceGuard * @param {I} init * @param {T & ThisType<{ - * self: T, + * self: RemotableObject & T, * state: ReturnType * }>} methods * @param {DefineKindOptions<{ diff --git a/packages/vat-data/src/index.test-d.ts b/packages/vat-data/src/index.test-d.ts index 6f14641539f..4280850379a 100644 --- a/packages/vat-data/src/index.test-d.ts +++ b/packages/vat-data/src/index.test-d.ts @@ -14,7 +14,7 @@ import { defineDurableKind, partialAssign, watchPromise, -} from '.'; +} from './index.js'; // for use in assignments below const anyVal = null as any; diff --git a/packages/vat-data/src/vat-data-bindings.js b/packages/vat-data/src/vat-data-bindings.js index 39e3b5b759a..f336d606ea0 100644 --- a/packages/vat-data/src/vat-data-bindings.js +++ b/packages/vat-data/src/vat-data-bindings.js @@ -9,7 +9,8 @@ import { provideLazy } from '@agoric/store'; let VatDataGlobal; if ('VatData' in globalThis) { globalThis.VatData || Fail`VatData defined in global as null or undefined`; - VatDataGlobal = globalThis.VatData; + // XXX types incompatibility + VatDataGlobal = /** @type {any} */ (globalThis.VatData); } else { // XXX this module has been known to get imported (transitively) in cases that // never use it so we make a version that will satisfy module resolution but diff --git a/packages/vat-data/vow.js b/packages/vat-data/vow.js index 525a7d1fa41..031568326dc 100644 --- a/packages/vat-data/vow.js +++ b/packages/vat-data/vow.js @@ -1,51 +1,2 @@ -/* global globalThis */ -// @ts-check -import { makeE, prepareVowTools as rawPrepareVowTools } from '@agoric/vow'; -import { makeHeapZone } from '@agoric/base-zone/heap.js'; -import { isUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js'; - -/** @type {any} */ -const vatData = globalThis.VatData; - -/** - * Manually-extracted watchPromise so we don't accidentally get the 'unavailable' - * version. If it is `undefined`, `@agoric/vow` will shim it. - * @type {undefined | (( - * p: Promise, - * watcher: import('@agoric/vow/src/watch-promise.js').PromiseWatcher, - * ...args: unknown[] - * ) => void)} - */ -const watchPromise = vatData && vatData.watchPromise; - -/** - * Return truthy if a rejection reason should result in a retry. - * @param {any} reason - * @returns {boolean} - */ -const isRetryableReason = reason => isUpgradeDisconnection(reason); - -export const defaultPowers = harden({ - isRetryableReason, - watchPromise, -}); - -/** - * @type {typeof rawPrepareVowTools} - */ -export const prepareVowTools = (zone, powers = {}) => - rawPrepareVowTools(zone, { ...defaultPowers, ...powers }); - -export const { watch, when, makeVowKit, allVows } = - prepareVowTools(makeHeapZone()); - -/** - * An vow-shortening E. CAVEAT: This produces long-lived ephemeral - * promises that encapsulate the shortening behaviour, and so provides no way - * for `watch` to durably shorten. Use the standard `import('@endo/far').E` if - * you need to `watch` its resulting promises. - */ -export const V = makeE(globalThis.HandledPromise, { - unwrap: when, - additional: { when }, -}); +// Backward-compatibility forwarding to the vow package. +export * from '@agoric/vow/vat.js'; diff --git a/packages/vats/package.json b/packages/vats/package.json index f0c6eef27d4..83f18f5336a 100644 --- a/packages/vats/package.json +++ b/packages/vats/package.json @@ -77,6 +77,6 @@ "workerThreads": false }, "typeCoverage": { - "atLeast": 91.5 + "atLeast": 91.33 } } diff --git a/packages/vats/src/core/basic-behaviors.js b/packages/vats/src/core/basic-behaviors.js index c25922d5ea8..c5cc5dcee13 100644 --- a/packages/vats/src/core/basic-behaviors.js +++ b/packages/vats/src/core/basic-behaviors.js @@ -63,6 +63,7 @@ export const makeVatsFromBundles = async ({ // NOTE: we rely on multiple createVatAdminService calls // to return cooperating services. const svc = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); + // @ts-expect-error XXX vatAdminSvc.resolve(svc); const durableStore = await vatStore; @@ -77,6 +78,7 @@ export const makeVatsFromBundles = async ({ if (bundleName) { console.info(`createVatByName(${bundleName})`); /** @type {Promise} */ + // @ts-expect-error XXX const vatInfo = E(svc).createVatByName(bundleName, { ...defaultVatCreationOptions, name: vatName, @@ -87,6 +89,7 @@ export const makeVatsFromBundles = async ({ assert(bundleID); const bcap = await E(svc).getBundleCap(bundleID); /** @type {Promise} */ + // @ts-expect-error XXX const vatInfo = E(svc).createVat(bcap, { ...defaultVatCreationOptions, name: vatName, diff --git a/packages/vats/src/core/startWalletFactory.js b/packages/vats/src/core/startWalletFactory.js index 9b04c34227d..a2dd87df342 100644 --- a/packages/vats/src/core/startWalletFactory.js +++ b/packages/vats/src/core/startWalletFactory.js @@ -154,10 +154,12 @@ export const startWalletFactory = async ( slotToBoardRemote, ); + /** @type {() => any} */ const reviveOldMetrics = () => { if (!dataReviver.has(OLD_POOL_METRICS_STORAGE_PATH)) { return undefined; } + /** @type {any} */ const oldPoolMetrics = dataReviver.getItem(OLD_POOL_METRICS_STORAGE_PATH); const newBrandFromOldSlotID = makeMap([ [oldPoolMetrics.totalMintedProvided.brand.getBoardId(), feeBrand], diff --git a/packages/vats/src/core/utils.js b/packages/vats/src/core/utils.js index 4256abf1d13..69b7484cc26 100644 --- a/packages/vats/src/core/utils.js +++ b/packages/vats/src/core/utils.js @@ -362,6 +362,7 @@ export const makeVatSpace = ( { get: (_target, name, _rx) => { assert.typeof(name, 'string'); + // @ts-expect-error XXX return provideAsync(name, createVatByName).then(vat => { if (!durableStore.has(name)) { durableStore.init(name, vat); diff --git a/packages/vats/src/ibc.js b/packages/vats/src/ibc.js index a1e0e1c9486..504104801c3 100644 --- a/packages/vats/src/ibc.js +++ b/packages/vats/src/ibc.js @@ -46,7 +46,11 @@ const DEFAULT_PACKET_TIMEOUT_NS = 60n * 60n * 1_000_000_000n; * }} Outbound */ -/** @param {Zone} zone */ +// FIXME(TS9006) remove 'any' +/** + * @param {Zone} zone + * @returns {any} + */ export const prepareIBCConnectionHandler = zone => { /** * @param {IBCChannelID} channelID diff --git a/packages/vats/src/lib-board.js b/packages/vats/src/lib-board.js index 1e655156986..01e8d404062 100644 --- a/packages/vats/src/lib-board.js +++ b/packages/vats/src/lib-board.js @@ -15,7 +15,10 @@ import { makeMarshal } from '@endo/marshal'; import { crc6 } from './crc.js'; -/** @import {Key} from '@endo/patterns') */ +/** + * @import {PassableCap} from '@endo/marshal'; + * @import {Key} from '@endo/patterns'; + */ export const DEFAULT_CRC_DIGITS = 2; export const DEFAULT_PREFIX = 'board0'; @@ -99,13 +102,13 @@ const initDurableBoardState = ( const immutable = { prefix, crcDigits }; const lastSequence = BigInt(initSequence); - /** @type {MapStore} */ + /** @type {MapStore} */ const idToVal = makeScalarBigMapStore('idToVal', { durable: true, keyShape: IdShape, valueShape: ValShape, }); - /** @type {MapStore} */ + /** @type {MapStore} */ const valToId = makeScalarBigMapStore('valToId', { durable: true, keyShape: ValShape, @@ -127,7 +130,7 @@ const initDurableBoardState = ( // transient marshallers that get GCed when the function completes. /** - * @param {Key} value + * @param {PassableCap} value * @param {BoardState} state */ const getId = (value, state) => { @@ -185,7 +188,7 @@ const makeSlotToVal = state => { /** * @param {BoardId} slot * @param {string} iface - * @returns {unknown} + * @returns {any} */ const slotToVal = (slot, iface) => { if (slot !== null) { @@ -264,7 +267,7 @@ export const prepareBoardKit = baggage => { * `value` for its entire lifetime. For a well-known board, this is * essentially forever. * - * @param {Key} value + * @param {PassableCap} value * @throws if `value` is not a Key in the @agoric/store sense */ getId(value) { @@ -295,13 +298,14 @@ export const prepareBoardKit = baggage => { return board; } const [first, ...rest] = path; + /** @type {any} */ const firstValue = board.getValue(/** @type {BoardId} */ (first)); if (rest.length === 0) { return firstValue; } return E(firstValue).lookup(...rest); }, - /** @param {Key} val */ + /** @param {PassableCap} val */ has(val) { const { state } = this; return state.valToId.has(val); diff --git a/packages/vats/src/nameHub.js b/packages/vats/src/nameHub.js index 7f767bc6b2f..d93d449fb13 100644 --- a/packages/vats/src/nameHub.js +++ b/packages/vats/src/nameHub.js @@ -9,7 +9,7 @@ import { prepareGuardedAttenuator, } from '@agoric/internal/src/callback.js'; import { makeHeapZone } from '@agoric/zone'; -import { deeplyFulfilled } from '@endo/marshal'; +import { deeplyFulfilledObject } from '@agoric/internal'; const { Fail, quote: q } = assert; @@ -118,7 +118,7 @@ const updated = (updateCallback, hub, _newValue = undefined) => { } // wait for values to settle before writing - return E.when(deeplyFulfilled(hub.entries()), settledEntries => + return E.when(deeplyFulfilledObject(hub.entries()), settledEntries => E(updateCallback).write(settledEntries), ); }; diff --git a/packages/vats/src/types.d.ts b/packages/vats/src/types.d.ts index 1f33d7c65c2..081567ee76f 100644 --- a/packages/vats/src/types.d.ts +++ b/packages/vats/src/types.d.ts @@ -1,3 +1,5 @@ +import type { Guarded } from '@endo/exo'; + export type Board = ReturnType< ReturnType >['board']; @@ -9,7 +11,7 @@ export type Board = ReturnType< * allow passing a remote iterable, there would be an inordinate number of round * trips for the contents of even the simplest nameHub. */ -export type NameHub = { +export type NameHub = { has: (key: string) => boolean; /** * Look up a path of keys starting from the current NameHub. Wait on any @@ -17,11 +19,11 @@ export type NameHub = { */ lookup: (...path: string[]) => Promise; /** get all the entries available in the current NameHub */ - entries: (includeReserved?: boolean) => [string, unknown][]; + entries: (includeReserved?: boolean) => [string, Value][]; /** get all names available in the current NameHub */ keys: () => string[]; /** get all values available in the current NameHub */ - values: () => unknown[]; + values: () => Value[]; }; /** write access to a node in a name hierarchy */ @@ -39,13 +41,13 @@ export type NameAdmin = { */ default: (key: string, newValue: T, newAdmin?: NameAdmin) => T; /** Update only if already initialized. Reject if not. */ - set: (key: string, newValue: unknown, newAdmin?: NameAdmin) => void; + set: (key: string, newValue: V, newAdmin?: NameAdmin) => void; /** * Fulfill an outstanding reserved promise (if any) to the newValue and set * the key to the newValue. If newAdmin is provided, set that to return via * lookupAdmin. */ - update: (key: string, newValue: unknown, newAdmin?: NameAdmin) => void; + update: (key: string, newValue: V, newAdmin?: NameAdmin) => void; /** * Look up the `newAdmin` from the path of keys starting from the current * NameAdmin. Wait on any reserved promises. @@ -59,7 +61,7 @@ export type NameAdmin = { }; export type NameHubUpdateHandler = { - write: (entries: [string, unknown][]) => void; + write: (entries: [string, V][]) => void; }; /** a node in a name hierarchy */ @@ -91,12 +93,12 @@ export type BridgeHandler = { }; /** An object which handles messages for a specific bridge */ -export type ScopedBridgeManager = { +export type ScopedBridgeManager = Guarded<{ toBridge: (obj: any) => Promise; fromBridge: (obj: any) => PromiseVow; initHandler: (handler: ERef) => void; setHandler: (handler: ERef) => void; -}; +}>; /** The object to manage this bridge */ export type BridgeManager = { diff --git a/packages/vats/src/vat-bank.js b/packages/vats/src/vat-bank.js index f81ad6640e6..b9013818d1f 100644 --- a/packages/vats/src/vat-bank.js +++ b/packages/vats/src/vat-bank.js @@ -21,6 +21,11 @@ import { import '@agoric/notifier/exported.js'; +/** + * @import {Guarded} from '@endo/exo'; + * @import {Passable, RemotableObject} from '@endo/pass-style'; + */ + const { Fail } = assert; const { VirtualPurseControllerI } = makeVirtualPurseKitIKit(); @@ -38,8 +43,9 @@ const BridgeChannelI = M.interface('BridgeChannel', { */ /** - * @typedef {object} BalanceUpdater - * @property {(value: string, nonce?: string) => void} update + * @typedef {Guarded<{ + * update: (value: string, nonce?: string) => void; + * }>} BalanceUpdater */ const BalanceUpdaterI = M.interface('BalanceUpdater', { @@ -348,8 +354,8 @@ const prepareAssetSubscription = zone => { /** * @template {AssetKind} [K=AssetKind] * @typedef {object} AssetIssuerKit - * @property {ERef>} [mint] - * @property {ERef>} issuer + * @property {Mint} [mint] + * @property {Issuer} issuer * @property {Brand} brand */ @@ -362,12 +368,17 @@ const AssetIssuerKitShape = M.splitRecord(BaseIssuerKitShape, { mint: M.remotable('Mint'), }); -/** @typedef {AssetIssuerKit & { denom: string; escrowPurse?: ERef }} AssetRecord */ +/** + * @typedef {AssetIssuerKit & { + * denom: string; + * escrowPurse?: RemotableObject & ERef; + * }} AssetRecord + */ /** * @typedef {object} AssetDescriptor * @property {Brand} brand - * @property {ERef} issuer + * @property {RemotableObject & ERef} issuer * @property {string} issuerName * @property {string} denom * @property {string} proposedName @@ -411,6 +422,7 @@ const prepareBank = ( // (which we emulate, since we know both address and denom are JSONable). If // we decide to partition the provider and use `brandToVPurse` directly, we'd // need ephemera for each `makeBank` call. + /** @type {MapStore} */ const addressDenomToPurse = zone.mapStore('addressDenomToPurse'); /** * @type {import('@agoric/store/src/stores/store-utils.js').AtomicProvider< @@ -584,7 +596,7 @@ const prepareBankManager = ( /** * @type {MapStore< * string, - * { bank: Bank; brandToVPurse: MapStore } + * { bank: Guarded; brandToVPurse: MapStore } * >} */ const addressToBank = detachedZone.mapStore('addressToBank'); diff --git a/packages/vats/src/virtual-purse.js b/packages/vats/src/virtual-purse.js index 8f7e1c97fd4..34064e1acfe 100644 --- a/packages/vats/src/virtual-purse.js +++ b/packages/vats/src/virtual-purse.js @@ -303,6 +303,7 @@ export const prepareVirtualPurse = zone => { recoveryPurse, escrowPurse, }).purse; + // @ts-expect-error XXX return vpurse; }; diff --git a/packages/vats/test/test-bootstrapPayment.js b/packages/vats/test/test-bootstrapPayment.js index e3555282816..b59f636df00 100644 --- a/packages/vats/test/test-bootstrapPayment.js +++ b/packages/vats/test/test-bootstrapPayment.js @@ -10,11 +10,7 @@ import { claim } from '@agoric/ertp/src/legacy-payment-helpers.js'; import centralSupplyBundle from '../bundles/bundle-centralSupply.js'; import { feeIssuerConfig } from '../src/core/utils.js'; -/** - * @template T @typedef - * {import('@agoric/zoe/src/zoeService/utils.js').Installation} - * Installation - */ +/** @import {Installation} from '@agoric/zoe/src/zoeService/utils.js' */ /** * @typedef {import('ava').ExecutionContext<{ * zoe: ZoeService; diff --git a/packages/vats/test/test-lib-board.js b/packages/vats/test/test-lib-board.js index e9ec6d264c3..70e90b15949 100644 --- a/packages/vats/test/test-lib-board.js +++ b/packages/vats/test/test-lib-board.js @@ -51,6 +51,7 @@ test('makeBoard', async t => { test('board values must be scalar keys', async t => { const board = makeFakeBoard(); const nonKey = harden({ a: 1 }); + // @ts-expect-error intentional error await t.throwsAsync(() => E(board).getId(nonKey), { message: /arg 0: A "copyRecord" cannot be a scalar key: {"a":1}/, }); diff --git a/packages/vats/tools/bank-utils.js b/packages/vats/tools/bank-utils.js index 13a0047b78c..b0d95423262 100644 --- a/packages/vats/tools/bank-utils.js +++ b/packages/vats/tools/bank-utils.js @@ -5,7 +5,7 @@ import { Far } from '@endo/marshal'; /** @param {Pick[]} issuerKits */ export const makeFakeBankKit = issuerKits => { - /** @type {MapStore>} */ + /** @type {MapStore} */ const issuers = makeScalarMapStore(); /** * @type {MapStore< diff --git a/packages/vats/tools/boot-test-utils.js b/packages/vats/tools/boot-test-utils.js index 09afd1bae01..5730acabfa6 100644 --- a/packages/vats/tools/boot-test-utils.js +++ b/packages/vats/tools/boot-test-utils.js @@ -132,6 +132,8 @@ export const makePopulatedFakeVatAdmin = () => { return createVat(fakeNameToCap.get(name) || Fail`unknown vat ${name}`); }; + // FIXME(TS9006) remove 'any' + /** @type {any} */ const vatAdminService = Far('vatAdminSvc', { ...fakeVatAdmin, createVat, diff --git a/packages/vow/README.md b/packages/vow/README.md index a0495b84f49..b34dc1db902 100644 --- a/packages/vow/README.md +++ b/packages/vow/README.md @@ -26,12 +26,12 @@ Here they are: { } ``` -On Agoric, you can use `V` exported from `@agoric/vat-data/vow.js`, which +On Agoric, you can use `V` exported from `@agoric/vow/vat.js`, which converts a chain of promises and vows to a promise for its final fulfilment, by unwrapping any intermediate vows: ```js -import { V as E } from '@agoric/vat-data/vow.js'; +import { V as E } from '@agoric/vow/vat.js'; [...] const a = await E.when(w1); const b = await E(w2).something(...args); @@ -45,7 +45,7 @@ On Agoric, use the following to create and resolve a vow: ```js // CAVEAT: `V` uses internal ephemeral promises, so while it is convenient, // it cannot be used by upgradable vats. See "Durability" below: -import { V as E, makeVowKit } from '@agoric/vat-data/vow.js'; +import { V as E, makeVowKit } from '@agoric/vow/vat.js'; [...] const { resolver, vow } = makeVowKit(); // Send vow to a potentially different vat. @@ -56,16 +56,15 @@ resolver.resolve('now you know the answer'); ## Durability -The vow package supports Zones, which are used to integrate Agoric's vat -upgrade mechanism and `watchPromise`. To create vow tools that deal with -durable objects: +The `@agoric/vow/vat.js` module allows vows to integrate Agoric's vat upgrade +mechanism. To create vow tools that deal with durable objects: ```js // NOTE: Cannot use `V` as it has non-durable internal state when unwrapping // vows. Instead, use the default vow-exposing `E` with the `watch` // operator. import { E } from '@endo/far'; -import { prepareVowTools } from '@agoric/vat-data/vow.js'; +import { prepareVowTools } from '@agoric/vow/vat.js'; import { makeDurableZone } from '@agoric/zone'; // Only do the following once at the start of a new vat incarnation: diff --git a/packages/vow/package.json b/packages/vow/package.json index 722f1bbc5c3..f346e36aa9c 100755 --- a/packages/vow/package.json +++ b/packages/vow/package.json @@ -21,6 +21,7 @@ }, "dependencies": { "@agoric/base-zone": "^0.1.0", + "@agoric/internal": "^0.3.2", "@endo/env-options": "^1.1.3", "@endo/eventual-send": "^1.2.1", "@endo/pass-style": "^1.3.1", @@ -28,7 +29,6 @@ "@endo/promise-kit": "^1.1.1" }, "devDependencies": { - "@agoric/internal": "^0.3.2", "@endo/far": "^1.1.1", "@endo/init": "^1.1.1", "ava": "^5.3.0" @@ -47,6 +47,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 89.21 + "atLeast": 89.38 } } diff --git a/packages/vow/src/tools.js b/packages/vow/src/tools.js index 7d0b93f7606..6ca442b7c88 100644 --- a/packages/vow/src/tools.js +++ b/packages/vow/src/tools.js @@ -8,13 +8,12 @@ import { prepareWatchUtils } from './watch-utils.js'; * @param {import('@agoric/base-zone').Zone} zone * @param {object} [powers] * @param {(reason: any) => boolean} [powers.isRetryableReason] - * @param {(p: PromiseLike, watcher: import('./watch-promise.js').PromiseWatcher, ...args: unknown[]) => void} [powers.watchPromise] */ export const prepareVowTools = (zone, powers = {}) => { - const { isRetryableReason = () => false, watchPromise } = powers; - const makeVowKit = prepareVowKit(zone, watchPromise); + const { isRetryableReason = () => false } = powers; + const makeVowKit = prepareVowKit(zone); const when = makeWhen(isRetryableReason); - const watch = prepareWatch(zone, makeVowKit, watchPromise, isRetryableReason); + const watch = prepareWatch(zone, makeVowKit, isRetryableReason); const makeWatchUtils = prepareWatchUtils(zone, watch, makeVowKit); const watchUtils = makeWatchUtils(); diff --git a/packages/vow/src/types.js b/packages/vow/src/types.js index ad582399cb5..dfc1bd4c5bb 100644 --- a/packages/vow/src/types.js +++ b/packages/vow/src/types.js @@ -1,6 +1,11 @@ // @ts-check export {}; +/** + * @import {Passable, RemotableObject} from '@endo/pass-style'; + * @import {PromiseVow, Remote} from '@agoric/vow'; + */ + /** @typedef {(...args: any[]) => any} Callable */ /** @@ -77,7 +82,7 @@ export {}; /** * @template [T=any] * @typedef {object} VowPayload - * @property {Remote>} vowV0 + * @property {RemotableObject & Remote>} vowV0 */ /** diff --git a/packages/vow/src/vow.js b/packages/vow/src/vow.js index 21e6f286cc5..544b53011ce 100644 --- a/packages/vow/src/vow.js +++ b/packages/vow/src/vow.js @@ -2,7 +2,7 @@ import { makePromiseKit } from '@endo/promise-kit'; import { M } from '@endo/patterns'; import { makeTagged } from '@endo/pass-style'; -import { PromiseWatcherI, watchPromiseShim } from './watch-promise.js'; +import { PromiseWatcherI } from '@agoric/base-zone'; const sink = () => {}; harden(sink); @@ -14,9 +14,8 @@ harden(sink); /** * @param {import('@agoric/base-zone').Zone} zone - * @param {typeof watchPromiseShim} [watchPromise] */ -export const prepareVowKit = (zone, watchPromise = watchPromiseShim) => { +export const prepareVowKit = zone => { /** @type {WeakMap} */ const resolverToEphemera = new WeakMap(); @@ -94,7 +93,7 @@ export const prepareVowKit = (zone, watchPromise = watchPromiseShim) => { const { promise, resolve } = getPromiseKitForResolution(resolver); if (resolve) { resolve(value); - watchPromise(promise, this.facets.watchNextStep); + zone.watchPromise(promise, this.facets.watchNextStep); } }, /** diff --git a/packages/vow/src/watch.js b/packages/vow/src/watch.js index b28e3c3a005..91b1d38843a 100644 --- a/packages/vow/src/watch.js +++ b/packages/vow/src/watch.js @@ -1,21 +1,21 @@ // @ts-check +import { PromiseWatcherI } from '@agoric/base-zone'; import { getVowPayload, basicE } from './vow-utils.js'; -import { PromiseWatcherI, watchPromiseShim } from './watch-promise.js'; const { apply } = Reflect; /** - * @param {typeof watchPromiseShim} watchPromise + * @param {import('@agoric/base-zone').Zone} zone */ const makeWatchNextStep = - watchPromise => + zone => /** * If the specimen is a vow, obtain a fresh shortened promise from it, * otherwise coerce the non-vow specimen to a promise. Then, associate a * (usually durable) watcher object with the promise. * * @param {any} specimen - * @param {import('./watch-promise.js').PromiseWatcher} promiseWatcher + * @param {import('@agoric/base-zone').PromiseWatcher} promiseWatcher */ (specimen, promiseWatcher) => { let promise; @@ -25,7 +25,7 @@ const makeWatchNextStep = } else { promise = basicE.resolve(specimen); } - watchPromise(promise, promiseWatcher); + zone.watchPromise(promise, promiseWatcher); }; /** @@ -82,7 +82,7 @@ const preparePromiseWatcher = (zone, isRetryableReason, watchNextStep) => return /** @type {Partial} */ (state); }, { - /** @type {Required['onFulfilled']} */ + /** @type {Required['onFulfilled']} */ onFulfilled(value) { const { watcher, watcherContext, resolver } = this.state; if (getVowPayload(value)) { @@ -95,7 +95,7 @@ const preparePromiseWatcher = (zone, isRetryableReason, watchNextStep) => this.state.resolver = undefined; settle(resolver, watcher, 'onFulfilled', value, watcherContext); }, - /** @type {Required['onRejected']} */ + /** @type {Required['onRejected']} */ onRejected(reason) { const { vow, watcher, watcherContext, resolver } = this.state; if (vow && isRetryableReason(reason)) { @@ -112,16 +112,14 @@ const preparePromiseWatcher = (zone, isRetryableReason, watchNextStep) => /** * @param {import('@agoric/base-zone').Zone} zone * @param {() => import('./types.js').VowKit} makeVowKit - * @param {typeof watchPromiseShim} [watchPromise] * @param {(reason: any) => boolean} [isRetryableReason] */ export const prepareWatch = ( zone, makeVowKit, - watchPromise = watchPromiseShim, isRetryableReason = _reason => false, ) => { - const watchNextStep = makeWatchNextStep(watchPromise); + const watchNextStep = makeWatchNextStep(zone); const makePromiseWatcher = preparePromiseWatcher( zone, isRetryableReason, @@ -150,7 +148,7 @@ export const prepareWatch = ( ); // Coerce the specimen to a promise, and start the watcher cycle. - watchPromise(basicE.resolve(specimenP), promiseWatcher); + zone.watchPromise(basicE.resolve(specimenP), promiseWatcher); return vow; }; diff --git a/packages/vat-data/test/test-vow.js b/packages/vow/test/test-vat.js similarity index 96% rename from packages/vat-data/test/test-vow.js rename to packages/vow/test/test-vat.js index e21e0d14ff2..bbb04e0452b 100644 --- a/packages/vat-data/test/test-vow.js +++ b/packages/vow/test/test-vat.js @@ -2,7 +2,7 @@ import test from 'ava'; import { E, Far } from '@endo/far'; -import { V, makeVowKit } from '../vow.js'; +import { V, makeVowKit } from '../vat.js'; test('heap messages', async t => { const greeter = Far('Greeter', { diff --git a/packages/vow/vat.js b/packages/vow/vat.js new file mode 100644 index 00000000000..f4d268f3166 --- /dev/null +++ b/packages/vow/vat.js @@ -0,0 +1,36 @@ +/* global globalThis */ +// @ts-check +import { isUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js'; +import { makeHeapZone } from '@agoric/base-zone/heap.js'; +import { makeE, prepareVowTools as rawPrepareVowTools } from './src/index.js'; + +/** + * Return truthy if a rejection reason should result in a retry. + * @param {any} reason + * @returns {boolean} + */ +const isRetryableReason = reason => isUpgradeDisconnection(reason); + +export const defaultPowers = harden({ + isRetryableReason, +}); + +/** + * @type {typeof rawPrepareVowTools} + */ +export const prepareVowTools = (zone, powers = {}) => + rawPrepareVowTools(zone, { ...defaultPowers, ...powers }); + +export const { watch, when, makeVowKit, allVows } = + prepareVowTools(makeHeapZone()); + +/** + * A vow-shortening E. CAVEAT: This produces long-lived ephemeral + * promises that encapsulate the shortening behaviour, and so provides no way + * for `watch` to durably shorten. Use the standard `import('@endo/far').E` if + * you need to `watch` its resulting promises. + */ +export const V = makeE(globalThis.HandledPromise, { + unwrap: when, + additional: { when }, +}); diff --git a/packages/wallet/api/src/internal-types.js b/packages/wallet/api/src/internal-types.js index c08258b5642..12c34f82190 100644 --- a/packages/wallet/api/src/internal-types.js +++ b/packages/wallet/api/src/internal-types.js @@ -7,7 +7,10 @@ * @property {PurseActions} actions */ -/** @import {Petname} from '@agoric/deploy-script-support/src/externalTypes.js' */ +/** + * @import {Petname} from '@agoric/deploy-script-support/src/externalTypes.js'; + * @import {Key} from '@endo/patterns'; + */ /** * @typedef {PursesJSONState & PursesAddedState} PursesFullState @@ -51,7 +54,7 @@ */ /** - * @template T + * @template {Key} T * @typedef {object} Mapping * @property {(petname: Petname) => string} implode * @property {(str: string) => Petname} explode diff --git a/packages/wallet/api/src/lib-dehydrate.js b/packages/wallet/api/src/lib-dehydrate.js index 55d0209fe6b..b4f7defb55e 100644 --- a/packages/wallet/api/src/lib-dehydrate.js +++ b/packages/wallet/api/src/lib-dehydrate.js @@ -86,10 +86,9 @@ export const makeDehydrator = (initialUnnamedCount = 0) => { }; /** - * @template T * @param {string} kind * @param {{ useLegacyMap?: boolean }} [legacyOptions] - * @returns {Mapping} + * @returns {Mapping} */ const makeMapping = (kind, { useLegacyMap = false } = {}) => { typeof kind === 'string' || `kind ${kind} must be a string`; @@ -97,9 +96,9 @@ export const makeDehydrator = (initialUnnamedCount = 0) => { // These are actually either a LegacyMap or a MapStore depending on // useLegacyMap. Fortunately, the LegacyMap type is approximately the // intersection of these, so we can just use it. - /** @type {LegacyMap} */ + /** @type {LegacyMap} */ const rawValToPetname = makeMap('value'); - /** @type {LegacyMap} */ + /** @type {LegacyMap} */ const valToPetname = { ...rawValToPetname, set(key, val) { @@ -121,9 +120,9 @@ export const makeDehydrator = (initialUnnamedCount = 0) => { return mapIterable(rawValToPetname.values(), val => explode(val)); }, }; - /** @type {MapStore} */ + /** @type {MapStore} */ const rawPetnameToVal = makeScalarMapStore('petname'); - /** @type {MapStore} */ + /** @type {MapStore} */ const petnameToVal = { ...rawPetnameToVal, init(key, val) { @@ -270,7 +269,7 @@ export const makeDehydrator = (initialUnnamedCount = 0) => { petnameToVal.delete(petname); valToPetname.delete(val); }; - /** @type {Mapping} */ + /** @type {Mapping} */ const mapping = harden({ implode, explode, diff --git a/packages/wallet/api/src/lib-wallet.js b/packages/wallet/api/src/lib-wallet.js index d94f1262397..50793f3fc3e 100644 --- a/packages/wallet/api/src/lib-wallet.js +++ b/packages/wallet/api/src/lib-wallet.js @@ -754,7 +754,9 @@ export function makeWalletRoot({ * @param {string} [address] */ const addContact = async (petname, actions, address = undefined) => { + // @ts-expect-error XXX ERef const already = await E(board).has(actions); + /** @type {any} */ let depositFacet; if (already) { depositFacet = actions; diff --git a/packages/xsnap-lockdown/package.json b/packages/xsnap-lockdown/package.json index 891e539c560..679a311369c 100644 --- a/packages/xsnap-lockdown/package.json +++ b/packages/xsnap-lockdown/package.json @@ -25,7 +25,8 @@ "ava": "^5.3.0", "c8": "^9.1.0", "rollup": "^2.58.0", - "rollup-plugin-string": "^3.0.0" + "rollup-plugin-string": "^3.0.0", + "source-map": "^0.7.4" }, "files": [ "LICENSE*", diff --git a/packages/zoe/package.json b/packages/zoe/package.json index e5f3699fce0..3cf2fb7d911 100644 --- a/packages/zoe/package.json +++ b/packages/zoe/package.json @@ -139,6 +139,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 84.9 + "atLeast": 84.91 } } diff --git a/packages/zoe/src/cleanProposal.js b/packages/zoe/src/cleanProposal.js index 94b5ffc4052..37fd8bef2bd 100644 --- a/packages/zoe/src/cleanProposal.js +++ b/packages/zoe/src/cleanProposal.js @@ -57,6 +57,7 @@ export const coerceAmountPatternKeywordRecord = ( getAssetKindByBrand, ) => { cleanKeywords(allegedAmountKeywordRecord); + // FIXME objectMap should constrain the mapping function by the record's type return objectMap(allegedAmountKeywordRecord, amount => { // Check that each value can be coerced using the AmountMath // indicated by brand. `AmountMath.coerce` throws if coercion fails. @@ -75,6 +76,12 @@ export const coerceAmountPatternKeywordRecord = ( }); }; +/** + * + * @param {unknown} allegedAmountKeywordRecord + * @param {*} getAssetKindByBrand + * @returns {AmountKeywordRecord} + */ export const coerceAmountKeywordRecord = ( allegedAmountKeywordRecord, getAssetKindByBrand, @@ -84,6 +91,7 @@ export const coerceAmountKeywordRecord = ( getAssetKindByBrand, ); assertKey(result); + // @ts-expect-error checked cast return result; }; diff --git a/packages/zoe/src/contractFacet/offerHandlerStorage.js b/packages/zoe/src/contractFacet/offerHandlerStorage.js index 09e2d30bd75..26ff65aaff1 100644 --- a/packages/zoe/src/contractFacet/offerHandlerStorage.js +++ b/packages/zoe/src/contractFacet/offerHandlerStorage.js @@ -6,9 +6,18 @@ import { canBeDurable, provideDurableWeakMapStore } from '@agoric/vat-data'; import { defineDurableHandle } from '../makeHandle.js'; +/** + * @import {RemotableBrand} from '@endo/eventual-send'; + * @import {RemotableObject} from '@endo/pass-style'; + */ + +/** + * @typedef {RemotableBrand & RemotableObject & OfferHandler} PassableOfferHandler + */ + export const makeOfferHandlerStorage = zcfBaggage => { const makeInvitationHandle = defineDurableHandle(zcfBaggage, 'Invitation'); - /** @type {WeakMapStore} */ + /** @type {WeakMapStore} */ // ZCF needs to ephemerally hold on to ephemeral handlers, and durably hold // onto handlers that are intended to be durable. We keep two stores and store @@ -18,13 +27,12 @@ export const makeOfferHandlerStorage = zcfBaggage => { const invitationHandleToEphemeralHandler = makeScalarWeakMapStore( 'invitationHandleToEphemeralHandler', ); - /** @type {WeakMapStore} */ + /** @type {WeakMapStore} */ const invitationHandleToDurableHandler = provideDurableWeakMapStore( zcfBaggage, 'invitationHandleToDurableHandler', ); - /** @type {(offerHandler: OfferHandler) => InvitationHandle} */ const storeOfferHandler = offerHandler => { if (typeof offerHandler === 'function') { offerHandler = ToFarFunction('offerHandler', offerHandler); diff --git a/packages/zoe/src/contractFacet/types-ambient.d.ts b/packages/zoe/src/contractFacet/types-ambient.d.ts index 858a1c89f3d..2dfadbe3be3 100644 --- a/packages/zoe/src/contractFacet/types-ambient.d.ts +++ b/packages/zoe/src/contractFacet/types-ambient.d.ts @@ -6,6 +6,8 @@ type IssuerOptionsRecord = import('@agoric/ertp').IssuerOptionsRecord; type Completion = any; type ZCFMakeEmptySeatKit = (exit?: ExitRule | undefined) => ZcfSeatKit; +type InvitationAmount = Amount<'set', InvitationDetails>; + /** * Zoe Contract Facet * @@ -38,10 +40,10 @@ type ZCF> = { * @returns the AmountMath and brand synchronously accessible after * saving */ - saveIssuer: ( - issuerP: ERef, + saveIssuer: ( + issuerP: ERef, keyword: Keyword, - ) => Promise>; + ) => Promise ? IssuerRecord : never>; /** * Make a credible Zoe invitation for a particular smart contract @@ -162,7 +164,7 @@ type ZCFMint = { * normally an instanceof Error. */ type ZCFSeatFail = (reason: unknown) => Error; -type ZCFSeat = { +type ZCFSeat = import('@endo/pass-style').RemotableObject & { exit: (completion?: Completion) => void; fail: ZCFSeatFail; getSubscriber: () => Promise>; @@ -243,7 +245,10 @@ type AdminFacet = import('../zoeService/utils').AdminFacet; declare const OfferReturn: unique symbol; declare const OfferArgs: unique symbol; -type Invitation = Payment<'set'> & { +type Invitation = Payment< + 'set', + InvitationDetails +> & { // because TS is structural, without this the generic is ignored [OfferReturn]?: R; [OfferArgs]?: A; diff --git a/packages/zoe/src/contractFacet/zcfMint.js b/packages/zoe/src/contractFacet/zcfMint.js index 4522559be23..7fbd2772b72 100644 --- a/packages/zoe/src/contractFacet/zcfMint.js +++ b/packages/zoe/src/contractFacet/zcfMint.js @@ -15,10 +15,9 @@ import './types-ambient.js'; const { Fail } = assert; /** - * @template {AssetKind} K * @param {AmountKeywordRecord} amr - * @param {IssuerRecord} issuerRecord - * @returns {Amount} + * @param {IssuerRecord} issuerRecord + * @returns {Amount} */ export const sumAmountKeywordRecord = (amr, issuerRecord) => { const empty = AmountMath.makeEmpty( diff --git a/packages/zoe/src/contractFacet/zcfSeat.js b/packages/zoe/src/contractFacet/zcfSeat.js index 9658f66512f..452477c943d 100644 --- a/packages/zoe/src/contractFacet/zcfSeat.js +++ b/packages/zoe/src/contractFacet/zcfSeat.js @@ -206,7 +206,7 @@ export const createSeatManager = ( assertActive(self); const currentAllocation = getCurrentAllocation(self); if (currentAllocation[keyword] !== undefined) { - // @ts-expect-error cast + // @ts-expect-error never checks brand return currentAllocation[keyword]; } if (!brand) { diff --git a/packages/zoe/src/contractSupport/durability.js b/packages/zoe/src/contractSupport/durability.js index 644d54401d1..878c5380765 100644 --- a/packages/zoe/src/contractSupport/durability.js +++ b/packages/zoe/src/contractSupport/durability.js @@ -8,7 +8,7 @@ import { E } from '@endo/eventual-send'; * representative also remains. * * @template {{}} E Ephemeral state - * @template {{}} [K=any] key on which to provision + * @template {WeakKey} K key on which to provision * @param {(key: K) => E} init */ export const makeEphemeraProvider = init => { diff --git a/packages/zoe/src/contractSupport/priceAuthority.js b/packages/zoe/src/contractSupport/priceAuthority.js index a3510f7eb23..ba779438a94 100644 --- a/packages/zoe/src/contractSupport/priceAuthority.js +++ b/packages/zoe/src/contractSupport/priceAuthority.js @@ -65,7 +65,7 @@ export const PriceAuthorityI = M.interface('PriceAuthority', { /** * @param {object} opts - * @param {Issuer<'set'>} opts.quoteIssuer + * @param {Issuer<'set', PriceDescription>} opts.quoteIssuer * @param {ERef>} opts.notifier * @param {ERef} opts.timer * @param {PriceQuoteCreate} opts.createQuote diff --git a/packages/zoe/src/contractSupport/priceAuthorityInitial.js b/packages/zoe/src/contractSupport/priceAuthorityInitial.js index 273d375729d..30bf5038158 100644 --- a/packages/zoe/src/contractSupport/priceAuthorityInitial.js +++ b/packages/zoe/src/contractSupport/priceAuthorityInitial.js @@ -23,7 +23,7 @@ import { mintQuote } from './priceAuthorityTransform.js'; * * @param {Ratio} priceOutPerIn * @param {PriceAuthority} priceAuthority - * @param {ERef>} quoteMint + * @param {ERef>} quoteMint * @param {Brand<'nat'>} brandIn * @param {Brand<'nat'>} brandOut * @returns {PriceAuthority} diff --git a/packages/zoe/src/contractSupport/priceAuthorityQuoteMint.js b/packages/zoe/src/contractSupport/priceAuthorityQuoteMint.js index 46531ffc125..de26f9bb0c3 100644 --- a/packages/zoe/src/contractSupport/priceAuthorityQuoteMint.js +++ b/packages/zoe/src/contractSupport/priceAuthorityQuoteMint.js @@ -1,16 +1,23 @@ import { AssetKind, prepareIssuerKit } from '@agoric/ertp'; import { provideDurableMapStore } from '@agoric/vat-data'; +/** + * @import {EOnly} from '@endo/eventual-send'; + * @import {MutableQuote, PriceAuthority, PriceDescription, PriceQuote, PriceQuoteValue, PriceQuery,} from '@agoric/zoe/tools/types.js'; + */ + /** * * @param {import('@agoric/vat-data').Baggage} baggage - * @returns {ERef>} + * @returns {ERef>} */ export const provideQuoteMint = baggage => { const issuerBaggage = provideDurableMapStore( baggage, 'quoteMintIssuerBaggage', ); + /** @type {IssuerKit<'set', PriceDescription>} */ + // @ts-expect-error cast const issuerKit = prepareIssuerKit( issuerBaggage, 'quote', diff --git a/packages/zoe/src/contractSupport/priceAuthorityTransform.js b/packages/zoe/src/contractSupport/priceAuthorityTransform.js index 2744c599876..fbfd509c707 100644 --- a/packages/zoe/src/contractSupport/priceAuthorityTransform.js +++ b/packages/zoe/src/contractSupport/priceAuthorityTransform.js @@ -6,16 +6,16 @@ import { makeNotifier } from '@agoric/notifier'; /** * @import {EOnly} from '@endo/eventual-send'; - * @import {MutableQuote, PriceAuthority, PriceQuote, PriceQuoteValue, PriceQuery,} from '@agoric/zoe/tools/types.js'; + * @import {MutableQuote, PriceAuthority, PriceQuote, PriceDescription,} from '@agoric/zoe/tools/types.js'; */ /** * @param {Brand<'set'>} quoteBrand * @param {Amount<'nat'>} amountIn * @param {Amount<'nat'>} amountOut - * @param {ERef} timer - * @param {import('@agoric/time').Timestamp} timestamp - * @param {ERef>} quoteMint + * @param {import('@agoric/time').TimerService} timer + * @param {import('@agoric/time').TimestampRecord} timestamp + * @param {ERef>} quoteMint * @returns {Promise} */ export const mintQuote = async ( @@ -39,7 +39,7 @@ export const mintQuote = async ( /** * @param {object} opts - * @param {ERef>} opts.quoteMint + * @param {ERef>} opts.quoteMint * @param {ERef} opts.sourcePriceAuthority * @param {Brand<'nat'>} opts.sourceBrandIn * @param {Brand<'nat'>} opts.sourceBrandOut diff --git a/packages/zoe/src/contractSupport/ratio.js b/packages/zoe/src/contractSupport/ratio.js index c4659aa968b..7635ce7d7b8 100644 --- a/packages/zoe/src/contractSupport/ratio.js +++ b/packages/zoe/src/contractSupport/ratio.js @@ -70,7 +70,6 @@ export const makeRatio = ( denominator > 0n || Fail`No infinite ratios! Denominator was 0 ${q(denominatorBrand)}`; - // @ts-expect-error cast to return type because make() ensures return harden({ numerator: AmountMath.make(numeratorBrand, numerator), denominator: AmountMath.make(denominatorBrand, denominator), @@ -98,6 +97,7 @@ export const makeRatioFromAmounts = (numeratorAmount, denominatorAmount) => { * @param {Amount<'nat'>} amount * @param {Ratio} ratio * @param {*} divideOp + * @returns {Amount<'nat'>} */ const multiplyHelper = (amount, ratio, divideOp) => { AmountMath.coerce(amount.brand, amount); @@ -107,12 +107,14 @@ const multiplyHelper = (amount, ratio, divideOp) => { ratio.denominator.brand, )}`; - return AmountMath.make( - ratio.numerator.brand, - divideOp( - multiply(amount.value, ratio.numerator.value), - ratio.denominator.value, - ), + return /** @type {Amount<'nat'>} */ ( + AmountMath.make( + ratio.numerator.brand, + divideOp( + multiply(amount.value, ratio.numerator.value), + ratio.denominator.value, + ), + ) ); }; @@ -135,6 +137,7 @@ export const multiplyBy = (amount, ratio) => { * @param {Amount<'nat'>} amount * @param {Ratio} ratio * @param {*} divideOp + * @returns {Amount<'nat'>} */ const divideHelper = (amount, ratio, divideOp) => { AmountMath.coerce(amount.brand, amount); @@ -144,12 +147,14 @@ const divideHelper = (amount, ratio, divideOp) => { ratio.numerator.brand, )}`; - return AmountMath.make( - ratio.denominator.brand, - divideOp( - multiply(amount.value, ratio.denominator.value), - ratio.numerator.value, - ), + return /** @type {Amount<'nat'>} */ ( + AmountMath.make( + ratio.denominator.brand, + divideOp( + multiply(amount.value, ratio.denominator.value), + ratio.numerator.value, + ), + ) ); }; diff --git a/packages/zoe/src/contractSupport/recorder.js b/packages/zoe/src/contractSupport/recorder.js index 6e81830902b..7c9e63f7536 100644 --- a/packages/zoe/src/contractSupport/recorder.js +++ b/packages/zoe/src/contractSupport/recorder.js @@ -94,7 +94,7 @@ export const prepareRecorder = (baggage, marshaller) => { /** * Marshalls before writing to storage or publisher to help ensure the two streams match. * - * @param {unknown} value + * @param {any} value * @returns {Promise} */ async write(value) { @@ -111,7 +111,7 @@ export const prepareRecorder = (baggage, marshaller) => { /** * Like `write` but prevents future writes and terminates the publisher. * - * @param {unknown} value + * @param {any} value * @returns {Promise} */ async writeFinal(value) { @@ -267,7 +267,7 @@ export const prepareMockRecorderKitMakers = () => { * whole thing to `any`. * * @template T - * @typedef {{ validatedType?: T }} TypedMatcher + * @typedef {import('@endo/patterns').Matcher & { validatedType?: T }} TypedMatcher */ /** diff --git a/packages/zoe/src/contracts/autoswap.js b/packages/zoe/src/contracts/autoswap.js index 1b9f58f40a3..40939bbf65d 100644 --- a/packages/zoe/src/contracts/autoswap.js +++ b/packages/zoe/src/contracts/autoswap.js @@ -274,8 +274,10 @@ const start = async zcf => { }); // TODO (hibbert) should we burn tokens? - const userAllocation = removeLiqSeat.getCurrentAllocation(); - /** @type {Amount<'nat'>} */ + + const userAllocation = /** @type {{Liquidity: Amount<'nat'>}} */ ( + removeLiqSeat.getCurrentAllocation() + ); const liquidityIn = userAllocation.Liquidity; assert(!AmountMath.isEmpty(liquidityIn), 'Pool is empty'); const liquidityValueIn = liquidityIn.value; diff --git a/packages/zoe/src/contracts/callSpread/pricedCallSpread.js b/packages/zoe/src/contracts/callSpread/pricedCallSpread.js index 67cc94c23a6..451170bb31d 100644 --- a/packages/zoe/src/contracts/callSpread/pricedCallSpread.js +++ b/packages/zoe/src/contracts/callSpread/pricedCallSpread.js @@ -104,6 +104,7 @@ const start = zcf => { const invitationIssuer = zcf.getInvitationIssuer(); const payment = harden({ Option: option }); const Option = await E(invitationIssuer).getAmountOf(option); + /** @type {any} */ const spreadAmount = harden({ Option, }); diff --git a/packages/zoe/src/contracts/loan/borrow.js b/packages/zoe/src/contracts/loan/borrow.js index 5a07165fd01..af720c00e9d 100644 --- a/packages/zoe/src/contracts/loan/borrow.js +++ b/packages/zoe/src/contracts/loan/borrow.js @@ -39,7 +39,9 @@ export const makeBorrowInvitation = (zcf, config) => { const collateralGiven = borrowerSeat.getAmountAllocated( 'Collateral', - borrowerSeat.getProposal().give.Collateral.brand, + /** @type {Brand<'nat'>} */ ( + borrowerSeat.getProposal().give.Collateral.brand + ), ); const loanWanted = borrowerSeat.getProposal().want.Loan; const loanBrand = zcf.getTerms().brands.Loan; diff --git a/packages/zoe/src/contracts/priceAggregator.js b/packages/zoe/src/contracts/priceAggregator.js index 97bcff66f04..a1be89dc22c 100644 --- a/packages/zoe/src/contracts/priceAggregator.js +++ b/packages/zoe/src/contracts/priceAggregator.js @@ -60,7 +60,7 @@ const priceDescriptionFromQuote = quote => quote.quoteAmount.value[0]; * }>} zcf * @param {{ * marshaller: Marshaller, - * quoteMint?: ERef>, + * quoteMint?: ERef>, * storageNode: ERef, * }} privateArgs */ @@ -78,12 +78,11 @@ const start = async (zcf, privateArgs) => { const { marshaller, storageNode } = privateArgs; assertAllDefined({ marshaller, storageNode }); + /** @type {ERef>} */ const quoteMint = privateArgs.quoteMint || // makeIssuerKit fails upgrade, this contract is for demo only makeIssuerKit('quote', AssetKind.SET).mint; - /** @type {IssuerRecord<'set'>} */ - // xxx saveIssuer not generic const quoteIssuerRecord = await zcf.saveIssuer( E(quoteMint).getIssuer(), 'Quote', @@ -101,8 +100,6 @@ const start = async (zcf, privateArgs) => { * @param {PriceQuoteValue} quote */ const authenticateQuote = async quote => { - /** @type {Amount<'set'>} */ - // xxx type should be inferred from brand and value const quoteAmount = AmountMath.make(quoteKit.brand, harden(quote)); const quotePayment = await E(quoteKit.mint).mintPayment(quoteAmount); return harden({ quoteAmount, quotePayment }); diff --git a/packages/zoe/src/internal-types.js b/packages/zoe/src/internal-types.js index 7de031ab808..b84970e0ffb 100644 --- a/packages/zoe/src/internal-types.js +++ b/packages/zoe/src/internal-types.js @@ -53,13 +53,16 @@ */ /** - * @typedef {object} ZoeSeatAdmin + * @typedef ZoeSeatAdminMethods * @property {(allocation: Allocation) => void} replaceAllocation * @property {ZoeSeatAdminExit} exit * @property {import('@agoric/swingset-vat').ShutdownWithFailure} fail called with the reason * for calling fail on this seat, where reason is normally an instanceof Error. * @property {() => Subscriber} getExitSubscriber */ +/** + * @typedef {import('@endo/marshal').RemotableObject & ZoeSeatAdminMethods} ZoeSeatAdmin + */ /** * @callback {(brand: Brand) => AssetKind} GetAssetKind @@ -67,7 +70,7 @@ /** * @typedef {object} HandleOfferResult - * @property {Promise} offerResultPromise + * @property {Promise} offerResultPromise * @property {ExitObj} exitObj */ @@ -122,9 +125,9 @@ /** * @typedef {object} ZoeInstanceAdmin * @property {ZoeInstanceAdminMakeInvitation} makeInvitation - * @property {(issuerP: ERef, + * @property {(issuerP: ERef, * keyword: Keyword - * ) => Promise} saveIssuer + * ) => Promise ? IssuerRecord : never>} saveIssuer * @property {MakeZoeMint} makeZoeMint * @property {RegisterFeeMint} registerFeeMint * @property {MakeNoEscrowSeat} makeNoEscrowSeat diff --git a/packages/zoe/src/types-ambient.js b/packages/zoe/src/types-ambient.js index 0e4b4207ad4..dd640c50611 100644 --- a/packages/zoe/src/types-ambient.js +++ b/packages/zoe/src/types-ambient.js @@ -4,10 +4,7 @@ /** * @template {string} H - the name of the handle - * @typedef {H & import("@endo/marshal").Remotable} Handle A type constructor for an opaque type - * identified by the H string. This uses an intersection type - * ('MyHandle' & {}) to tag the handle's type even though the actual - * value is just an empty object. + * @typedef {import("@endo/marshal").RemotableObject} Handle Alias for RemotableObject */ /** @@ -35,9 +32,10 @@ /** * @template {AssetKind} [K=AssetKind] + * @template {import("@endo/patterns").Key} [M=import("@endo/patterns").Key] member kind, for Amounts that have member values * @typedef {object} IssuerRecord * @property {Brand} brand - * @property {Issuer} issuer + * @property {Issuer} issuer * @property {K} assetKind * @property {DisplayInfo} [displayInfo] * diff --git a/packages/zoe/src/zoeService/escrowStorage.js b/packages/zoe/src/zoeService/escrowStorage.js index 357ca9b880f..6c20944d02b 100644 --- a/packages/zoe/src/zoeService/escrowStorage.js +++ b/packages/zoe/src/zoeService/escrowStorage.js @@ -16,7 +16,7 @@ import { cleanKeywords } from '../cleanProposal.js'; * @param {import('@agoric/vat-data').Baggage} baggage */ export const provideEscrowStorage = baggage => { - /** @type {WeakMapStore>} */ + /** @type {WeakMapStore} */ const brandToPurse = provideDurableWeakMapStore(baggage, 'brandToPurse'); /** @type {CreatePurse} */ diff --git a/packages/zoe/src/zoeService/makeInvitation.js b/packages/zoe/src/zoeService/makeInvitation.js index 320de457143..5a755ed0d7a 100644 --- a/packages/zoe/src/zoeService/makeInvitation.js +++ b/packages/zoe/src/zoeService/makeInvitation.js @@ -28,6 +28,9 @@ export const prepareInvitationKit = (baggage, shutdownZoeVat = undefined) => { // Upgrade this legacy state by simply deleting it. invitationKitBaggage.delete(ZOE_INVITATION_KIT); } + + /** @type {IssuerKit<'set', InvitationDetails>} */ + // @ts-expect-error cast const invitationKit = prepareIssuerKit( invitationKitBaggage, 'Zoe Invitation', diff --git a/packages/zoe/src/zoeService/originalZoeSeat.js b/packages/zoe/src/zoeService/originalZoeSeat.js index 97e4660851d..68a2ed2d92f 100644 --- a/packages/zoe/src/zoeService/originalZoeSeat.js +++ b/packages/zoe/src/zoeService/originalZoeSeat.js @@ -135,7 +135,7 @@ export const declareOldZoeSeatAdminKind = (baggage, makeDurablePublishKit) => { currentAllocation: initialAllocation, proposal, exitObj, - offerResult: undefined, + offerResult: /** @type {any} */ (undefined), offerResultStored: offerResultIsUndefined, instanceAdminHelper, withdrawFacet, @@ -217,7 +217,7 @@ export const declareOldZoeSeatAdminKind = (baggage, makeDurablePublishKit) => { } const pKit = ephemeralOfferResultStore.get(facets.userSeat); - E.when( + void E.when( offerResultPromise, offerResult => { // Resolve the ephemeral promise for offerResult @@ -240,7 +240,8 @@ export const declareOldZoeSeatAdminKind = (baggage, makeDurablePublishKit) => { ephemeralOfferResultStore.delete(facets.userSeat); } catch (err) { console.warn( - `non-durable offer result will be lost upon zoe vat termination: ${offerResult}`, + 'non-durable offer result will be lost upon zoe vat termination:', + offerResult, ); } }, diff --git a/packages/zoe/src/zoeService/startInstance.js b/packages/zoe/src/zoeService/startInstance.js index ea70986549d..d18869da130 100644 --- a/packages/zoe/src/zoeService/startInstance.js +++ b/packages/zoe/src/zoeService/startInstance.js @@ -274,9 +274,13 @@ export const makeStartInstance = ( }, ); + /** + * @type {import('./utils.js').StartInstance} + */ const startInstance = async ( installationP, uncleanIssuerKeywordRecord = harden({}), + // @ts-expect-error FIXME may not match the expected terms of SF customTerms = harden({}), privateArgs = undefined, instanceLabel = '', @@ -330,6 +334,7 @@ export const makeStartInstance = ( void watchForAdminNodeDone(adminNode, instanceAdmin); /** @type {ZoeInstanceAdmin} */ + // @ts-expect-error XXX saveIssuer const zoeInstanceAdminForZcf = makeZoeInstanceAdmin( zoeInstanceStorageManager, instanceAdmin, @@ -355,6 +360,7 @@ export const makeStartInstance = ( // creatorInvitation can be undefined, but if it is defined, // let's make sure it is an invitation. + // @ts-expect-error cast return E.when( Promise.all([ creatorInvitationP, @@ -383,6 +389,5 @@ export const makeStartInstance = ( }, ); }; - // @ts-expect-error cast return harden(startInstance); }; diff --git a/packages/zoe/src/zoeService/types-ambient.js b/packages/zoe/src/zoeService/types-ambient.js index 17d9f7a31e1..24322cf7099 100644 --- a/packages/zoe/src/zoeService/types-ambient.js +++ b/packages/zoe/src/zoeService/types-ambient.js @@ -49,7 +49,7 @@ /** * @callback GetInvitationIssuer - * @returns {Promise>} + * @returns {Promise>} */ /** @@ -232,7 +232,7 @@ */ /** - * @typedef {Record>} AmountKeywordRecord + * @typedef {Record} AmountKeywordRecord * * The keys are keywords, and the values are amounts. For example: * { Asset: AmountMath.make(assetBrand, 5n), Price: diff --git a/packages/zoe/src/zoeService/utils.d.ts b/packages/zoe/src/zoeService/utils.d.ts index 6a31f5973a0..f94b6762d98 100644 --- a/packages/zoe/src/zoeService/utils.d.ts +++ b/packages/zoe/src/zoeService/utils.d.ts @@ -1,8 +1,9 @@ -import type { Callable } from '@agoric/internal/src/utils.js'; +import type { Issuer } from '@agoric/ertp/exported.js'; import type { Tagged } from '@agoric/internal/src/tagged.js'; -import type { VatUpgradeResults } from '@agoric/swingset-vat'; +import type { Callable } from '@agoric/internal/src/utils.js'; import type { Baggage } from '@agoric/swingset-liveslots'; -import type { Issuer } from '@agoric/ertp/exported.js'; +import type { VatUpgradeResults } from '@agoric/swingset-vat'; +import type { RemotableObject } from '@endo/marshal'; // XXX https://github.com/Agoric/agoric-sdk/issues/4565 type SourceBundle = Record; @@ -14,19 +15,18 @@ type ContractFacet = { /** * Installation of a contract, typed by its start function. */ -export type Installation = Tagged< - { - getBundle: () => SourceBundle; - getBundleLabel: () => string; - }, - 'StartFunction', - SF ->; -export type Instance = Tagged< - Handle<'Instance'>, - 'StartFunction', - SF ->; +export type Installation = + RemotableObject & + Tagged< + { + getBundle: () => SourceBundle; + getBundleLabel: () => string; + }, + 'StartFunction', + SF + >; +export type Instance = + RemotableObject & Tagged, 'StartFunction', SF>; export type InstallationStart = I extends Installation ? SF : never; @@ -37,7 +37,7 @@ export type ContractStartFunction = ( baggage?: Baggage, ) => ERef<{ creatorFacet?: {}; publicFacet?: {} }>; -export type AdminFacet = { +export type AdminFacet = RemotableObject & { // Completion, which is currently any getVatShutdownPromise: () => Promise; upgradeContract: Parameters[1] extends undefined diff --git a/packages/zoe/src/zoeService/zoeSeat.js b/packages/zoe/src/zoeService/zoeSeat.js index 688dcbb6a52..31abb4aa8c8 100644 --- a/packages/zoe/src/zoeService/zoeSeat.js +++ b/packages/zoe/src/zoeService/zoeSeat.js @@ -109,7 +109,7 @@ export const makeZoeSeatAdminFactory = baggage => { return { currentAllocation: initialAllocation, proposal, - offerResult: undefined, + offerResult: /** @type {any} */ (undefined), offerResultStored: offerResultIsUndefined, instanceAdminHelper, withdrawFacet, @@ -312,7 +312,8 @@ export const makeZoeSeatAdminFactory = baggage => { ephemeralOfferResultStore.delete(facets.zoeSeatAdmin); } catch (err) { console.warn( - `non-durable offer result will be lost upon zoe vat termination: ${offerResult}`, + 'non-durable offer result will be lost upon zoe vat termination:', + offerResult, ); } }, diff --git a/packages/zoe/src/zoeService/zoeStorageManager.js b/packages/zoe/src/zoeService/zoeStorageManager.js index e1f49abcea4..ae763e42adc 100644 --- a/packages/zoe/src/zoeService/zoeStorageManager.js +++ b/packages/zoe/src/zoeService/zoeStorageManager.js @@ -275,8 +275,9 @@ export const makeZoeStorageManager = ( ownKeys(customDetails).length >= 1 ? harden({ customDetails }) : harden({}); + /** @type {InvitationAmount} */ const invitationAmount = AmountMath.make( - invitationKit.brand, + /** @type {Brand<'set'>} */ (invitationKit.brand), harden([ { ...extraProperties, @@ -401,6 +402,7 @@ export const makeZoeStorageManager = ( contractBundleCap, contractLabel, ); + // @ts-expect-error checked cast return makeInstanceStorageManager(instanceRecord, adminNode, root) .instanceStorageManager; }; diff --git a/packages/zoe/test/types.test-d.ts b/packages/zoe/test/types.test-d.ts index e747384b9d8..f6f46eee091 100644 --- a/packages/zoe/test/types.test-d.ts +++ b/packages/zoe/test/types.test-d.ts @@ -5,8 +5,9 @@ * https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html */ import { E } from '@endo/eventual-send'; -import { expectNotType, expectType } from 'tsd'; +import { expectType } from 'tsd'; +import type { Key } from '@endo/patterns'; // 'prepare' is deprecated but still supported import type { prepare as scaledPriceAuthorityStart } from '../src/contracts/scaledPriceAuthority.js'; @@ -79,3 +80,8 @@ import type { prepare as scaledPriceAuthorityStart } from '../src/contracts/scal result.notInResult; expectType(result); } + +{ + const zcfSeat: ZCFSeat = null as any; + expectType(zcfSeat); +} diff --git a/packages/zoe/test/unitTests/contracts/test-oracle.js b/packages/zoe/test/unitTests/contracts/test-oracle.js index 10e02e4fd3b..d235b15166d 100644 --- a/packages/zoe/test/unitTests/contracts/test-oracle.js +++ b/packages/zoe/test/unitTests/contracts/test-oracle.js @@ -124,26 +124,15 @@ test('single oracle', /** @param {ExecutionContext} t */ async t => { t.truthy(await E(invitationIssuer).isLive(invitation3)); t.truthy(await E(invitationIssuer).isLive(invitation4)); - t.deepEqual( - (await E(invitationIssuer).getAmountOf(invitation1)).value[0].customDetails - .query, - query1, - ); - t.deepEqual( - (await E(invitationIssuer).getAmountOf(invitation2)).value[0].customDetails - .query, - query2, - ); - t.deepEqual( - (await E(invitationIssuer).getAmountOf(invitation3)).value[0].customDetails - .query, - query3, - ); - t.deepEqual( - (await E(invitationIssuer).getAmountOf(invitation4)).value[0].customDetails - .query, - query4, - ); + const getCustomDetailsQuery = async inv => { + const amt = await E(invitationIssuer).getAmountOf(inv); + return amt.value[0].customDetails?.query; + }; + + t.deepEqual(await getCustomDetailsQuery(invitation1), query1); + t.deepEqual(await getCustomDetailsQuery(invitation2), query2); + t.deepEqual(await getCustomDetailsQuery(invitation3), query3); + t.deepEqual(await getCustomDetailsQuery(invitation4), query4); const offer = E(zoe).offer(invitation1); diff --git a/packages/zoe/test/unitTests/contracts/test-priceAggregator.js b/packages/zoe/test/unitTests/contracts/test-priceAggregator.js index d1ddc92455b..1dd656d8230 100644 --- a/packages/zoe/test/unitTests/contracts/test-priceAggregator.js +++ b/packages/zoe/test/unitTests/contracts/test-priceAggregator.js @@ -53,7 +53,7 @@ import { * }>} zcf * @param {{ * marshaller: Marshaller, - * quoteMint?: ERef>, + * quoteMint?: ERef>, * storageNode: StorageNode, * }} privateArgs */ @@ -81,7 +81,7 @@ const makePublicationChecker = async (t, aggregatorPublicFacet, timerBrand) => { )[Symbol.asyncIterator](); return { - /** @param {{timestamp: bigint, amountOut: any}} spec */ + /** @param {{timestamp: import('@agoric/time').Timestamp, amountOut: any}} spec */ async nextMatches({ timestamp, amountOut }) { const expectedTimestamp = TimeMath.coerceTimestampRecord( timestamp, @@ -202,8 +202,10 @@ test('median aggregator', async t => { } = await E(zoe).getTerms(aggregator.instance); const timerBrand = oracleTimer.getTimerBrand(); const toTS = ts => TimeMath.coerceTimestampRecord(ts, timerBrand); - /** @type {Issuer<'set'>} */ - const quoteIssuer = rawQuoteIssuer; + + const quoteIssuer = /** @type {Issuer<'set', PriceDescription>} */ ( + rawQuoteIssuer + ); const price1000 = await makeFakePriceOracle(1000n); const price1300 = await makeFakePriceOracle(1300n); @@ -363,8 +365,10 @@ test('median aggregator - push only', async t => { } = await E(zoe).getTerms(aggregator.instance); const toTS = ts => TimeMath.coerceTimestampRecord(ts, oracleTimer.getTimerBrand()); - /** @type {Issuer<'set'>} */ - const quoteIssuer = rawQuoteIssuer; + + const quoteIssuer = /** @type {Issuer<'set', PriceDescription>} */ ( + rawQuoteIssuer + ); const pricePush = await makeFakePriceOracle(); const pa = E(aggregator.publicFacet).getPriceAuthority(); @@ -599,8 +603,9 @@ test('quoteAtTime', async t => { } = await E(zoe).getTerms(aggregator.instance); const toTS = ts => TimeMath.coerceTimestampRecord(ts, oracleTimer.getTimerBrand()); - /** @type {Issuer<'set'>} */ - const quoteIssuer = rawQuoteIssuer; + const quoteIssuer = /** @type {Issuer<'set', PriceDescription>} */ ( + rawQuoteIssuer + ); const price1000 = await makeFakePriceOracle(1000n); const price1300 = await makeFakePriceOracle(1300n); @@ -713,8 +718,9 @@ test('quoteWhen', async t => { } = await E(zoe).getTerms(aggregator.instance); const toTS = ts => TimeMath.coerceTimestampRecord(ts, oracleTimer.getTimerBrand()); - /** @type {Issuer<'set'>} */ - const quoteIssuer = rawQuoteIssuer; + const quoteIssuer = /** @type {Issuer<'set', PriceDescription>} */ ( + rawQuoteIssuer + ); const price1000 = await makeFakePriceOracle(1000n); const price1300 = await makeFakePriceOracle(1300n); @@ -823,8 +829,9 @@ test('mutableQuoteWhen no replacement', async t => { brandOut, } = await E(zoe).getTerms(aggregator.instance); const timerBrand = await E(oracleTimer).getTimerBrand(); - /** @type {Issuer<'set'>} */ - const quoteIssuer = rawQuoteIssuer; + const quoteIssuer = /** @type {Issuer<'set', PriceDescription>} */ ( + rawQuoteIssuer + ); const price1000 = await makeFakePriceOracle(1000n); const price1300 = await makeFakePriceOracle(1300n); @@ -941,8 +948,9 @@ test('mutableQuoteWhen with update', async t => { } = await E(zoe).getTerms(aggregator.instance); const toTS = ts => TimeMath.coerceTimestampRecord(ts, oracleTimer.getTimerBrand()); - /** @type {Issuer<'set'>} */ - const quoteIssuer = rawQuoteIssuer; + const quoteIssuer = /** @type {Issuer<'set', PriceDescription>} */ ( + rawQuoteIssuer + ); const price1200 = await makeFakePriceOracle(1200n); const pa = E(aggregator.publicFacet).getPriceAuthority(); diff --git a/packages/zoe/test/unitTests/contracts/test-sellTickets.js b/packages/zoe/test/unitTests/contracts/test-sellTickets.js index 32fe86deb9b..8ddb9d84894 100644 --- a/packages/zoe/test/unitTests/contracts/test-sellTickets.js +++ b/packages/zoe/test/unitTests/contracts/test-sellTickets.js @@ -146,6 +146,7 @@ test(`mint and sell opera tickets`, async t => { brand: moolaBrand, } = makeIssuerKit('moola'); + /** @param {bigint} value */ const moola = value => AmountMath.make(moolaBrand, value); const { admin: fakeVatAdmin, vatAdminState } = makeFakeVatAdmin(); @@ -442,7 +443,7 @@ test(`mint and sell opera tickets`, async t => { const bobPurse = await E(moolaIssuer).makeEmptyPurse(); await E(bobPurse).deposit(moola100Payment); - /** @type {Amount} */ + /** @type {Amount<'set', {number: number}>} */ const availableTickets = await E( ticketSalesPublicFacet, ).getAvailableItems(); diff --git a/packages/zoe/test/unitTests/setupBasicMints.js b/packages/zoe/test/unitTests/setupBasicMints.js index d00d3fe42e7..0ca43e22b0e 100644 --- a/packages/zoe/test/unitTests/setupBasicMints.js +++ b/packages/zoe/test/unitTests/setupBasicMints.js @@ -22,7 +22,7 @@ export const setup = () => { const { admin: fakeVatAdmin, vatAdminState } = makeFakeVatAdmin(); const zoe = makeZoeForTest(fakeVatAdmin); - /** @type {(brand: Brand) => (value: any) => Amount} */ + /** @type {(brand: Brand<'nat'>) => (value: bigint) => Amount<'nat'>} */ const makeSimpleMake = brand => value => AmountMath.make(brand, value); const result = { diff --git a/packages/zoe/tools/fakePriceAuthority.js b/packages/zoe/tools/fakePriceAuthority.js index 7c93d869ce8..3abdbca3ccb 100644 --- a/packages/zoe/tools/fakePriceAuthority.js +++ b/packages/zoe/tools/fakePriceAuthority.js @@ -28,7 +28,7 @@ const timestampLTE = (a, b) => TimeMath.compareAbs(a, b) <= 0; * @property {Brand<'nat'>} actualBrandOut * @property {Array} [priceList] * @property {Array<[number, number]>} [tradeList] - * @property {ERef} timer + * @property {import('@agoric/time').TimerService} timer * @property {import('@agoric/time').RelativeTime} [quoteInterval] * @property {ERef>} [quoteMint] * @property {Amount<'nat'>} [unitAmountIn] @@ -117,16 +117,19 @@ export async function makeFakePriceAuthority(options) { natSafeMath.multiply(amountIn.value, tradeValueOut), tradeValueIn, ); + /** @type {Amount<'set', PriceDescription>} */ const quoteAmount = AmountMath.make( quoteBrand, - harden([ - { - amountIn, - amountOut: AmountMath.make(actualBrandOut, valueOut), - timer, - timestamp: quoteTime, - }, - ]), + /** @type {[PriceDescription]} */ ( + harden([ + { + amountIn, + amountOut: AmountMath.make(actualBrandOut, valueOut), + timer, + timestamp: quoteTime, + }, + ]) + ), ); const quote = harden({ quotePayment: E(quoteMint).mintPayment(quoteAmount), diff --git a/packages/zoe/tools/manualTimer.js b/packages/zoe/tools/manualTimer.js index 44c9f3a639b..8573bfe7442 100644 --- a/packages/zoe/tools/manualTimer.js +++ b/packages/zoe/tools/manualTimer.js @@ -3,7 +3,11 @@ import { bindAllMethods } from '@agoric/internal'; import { buildManualTimer as build } from '@agoric/swingset-vat/tools/manual-timer.js'; import { TimeMath } from '@agoric/time'; -/** @import {TimerService} from '@agoric/time' */ +/** + * @import {TimerServiceI} from '@agoric/time'; + * @import {RemotableObject} from '@endo/pass-style'; + * @import {RemotableBrand} from '@endo/eventual-send'; + */ const { Fail } = assert; @@ -28,9 +32,7 @@ const nolog = (..._args) => {}; * @property {(nTimes: number, msg?: string) => Promise} tickN */ -/** - * @typedef {TimerService & ManualTimerAdmin} ManualTimer - */ +/** @typedef {TimerServiceI & RemotableObject<'TimerService'> & RemotableBrand & ManualTimerAdmin} ManualTimer */ /** * A fake TimerService, for unit tests that do not use a real diff --git a/packages/zoe/tools/types.js b/packages/zoe/tools/types.js index 13ee37f5de5..527b2d79676 100644 --- a/packages/zoe/tools/types.js +++ b/packages/zoe/tools/types.js @@ -3,9 +3,9 @@ export {}; /** * @typedef {object} PriceQuote - * @property {Amount<'set'>} quoteAmount + * @property {Amount<'set', PriceDescription>} quoteAmount * Amount whose value is a PriceQuoteValue - * @property {ERef>} quotePayment + * @property {ERef>} quotePayment * The `quoteAmount` wrapped as a payment */ @@ -22,7 +22,7 @@ export {}; * The amount supplied to a trade * @property {Amount<'nat'>} amountOut * The quoted result of trading `amountIn` - * @property {import('@agoric/time').TimerService} timer + * @property {import('@endo/pass-style').RemotableObject & import('@agoric/time').TimerService} timer * The service that gave the `timestamp` * @property {import('@agoric/time').TimestampRecord} timestamp * A timestamp according to `timer` for the quote @@ -64,7 +64,7 @@ export {}; * An object that mints PriceQuotes and handles * triggers and notifiers for changes in the price * - * @property {(brandIn: Brand, brandOut: Brand) => ERef>} getQuoteIssuer + * @property {(brandIn: Brand, brandOut: Brand) => ERef>} getQuoteIssuer * Get the ERTP issuer of PriceQuotes for a given brandIn/brandOut pair * * @property {(brandIn: Brand, diff --git a/packages/zone/src/durable.js b/packages/zone/src/durable.js index 75f632e9e00..34bcb69cd51 100644 --- a/packages/zone/src/durable.js +++ b/packages/zone/src/durable.js @@ -12,6 +12,7 @@ import { provideDurableSetStore, provideDurableWeakMapStore, provideDurableWeakSetStore, + watchPromise, } from '@agoric/vat-data'; import { agoricVatDataKeys as keys, makeOnceKit } from '@agoric/base-zone'; @@ -95,6 +96,7 @@ export const makeDurableZone = (baggage, baseLabel = 'durableZone') => { /** @type {import('.').Zone['subZone']} */ const subZone = (label, options = {}) => { + /** @type {import('@agoric/swingset-liveslots').Baggage} */ const subBaggage = subZoneStore(label, options); return makeDurableZone(subBaggage, `${baseLabel}.${label}`); }; @@ -106,6 +108,7 @@ export const makeDurableZone = (baggage, baseLabel = 'durableZone') => { subZone, makeOnce, + watchPromise, detached: attachedStores.detached, isStorable: attachedStores.isStorable, diff --git a/packages/zone/src/virtual.js b/packages/zone/src/virtual.js index 89a0a78a37c..5cba65cc268 100644 --- a/packages/zone/src/virtual.js +++ b/packages/zone/src/virtual.js @@ -11,7 +11,11 @@ import { makeScalarBigWeakSetStore, } from '@agoric/vat-data'; -import { agoricVatDataKeys as keys, makeOnceKit } from '@agoric/base-zone'; +import { + agoricVatDataKeys as keys, + makeOnceKit, + watchPromise, +} from '@agoric/base-zone'; const emptyRecord = harden({}); const initEmpty = harden(() => emptyRecord); @@ -79,6 +83,7 @@ export const makeVirtualZone = (baseLabel = 'virtualZone') => { subZone: wrapProvider(makeSubZone), makeOnce, + watchPromise, detached: detachedVirtualStores.detached, isStorable: detachedVirtualStores.isStorable, diff --git a/patches/@endo+exo+1.4.0.patch b/patches/@endo+exo+1.4.0.patch deleted file mode 100644 index aad2781fa3b..00000000000 --- a/patches/@endo+exo+1.4.0.patch +++ /dev/null @@ -1,10 +0,0 @@ -diff --git a/node_modules/@endo/exo/index.d.ts b/node_modules/@endo/exo/index.d.ts -index 3bc696d..55df34e 100644 ---- a/node_modules/@endo/exo/index.d.ts -+++ b/node_modules/@endo/exo/index.d.ts -@@ -1,3 +1,4 @@ - export * from "./src/exo-makers.js"; - export { GET_INTERFACE_GUARD } from "./src/get-interface.js"; -+export * from "./src/types.js"; - //# sourceMappingURL=index.d.ts.map -\ No newline at end of file diff --git a/scripts/replace-packages.sh b/scripts/replace-packages.sh index dc934a93cec..7d6817a649f 100755 --- a/scripts/replace-packages.sh +++ b/scripts/replace-packages.sh @@ -13,7 +13,9 @@ DSTDIR=${2-$PWD/node_modules} # Install and build the source directory. pushd "$SRCDIR" yarn install -yarn build +npm run build +# Endo requires this +npx lerna run build:types || true npm query .workspace | jq -r '.[].location' | while read -r dir; do # Skip private packages. test "$(jq .private < "$dir/package.json")" != true || continue @@ -23,7 +25,7 @@ npm query .workspace | jq -r '.[].location' | while read -r dir; do name=$(jq -r .name < package.json) stem=$(echo "$name" | sed -e 's!^@!!; s!/!-!g;') rm -f "${stem}"-*.tgz - yarn pack + npm pack tar -xvf "${stem}"-*.tgz # Replace the destination package. diff --git a/yarn.lock b/yarn.lock index a06fdbccfad..003c84e0dc5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8732,10 +8732,10 @@ minimatch@5.1.0: dependencies: brace-expansion "^2.0.1" -"minimatch@6 || 7 || 8 || 9", minimatch@^9.0.1, minimatch@^9.0.3: - version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== +"minimatch@6 || 7 || 8 || 9", minimatch@^9.0.1, minimatch@^9.0.3, minimatch@^9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== dependencies: brace-expansion "^2.0.1" @@ -8753,13 +8753,6 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.4: - version "9.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" - integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== - dependencies: - brace-expansion "^2.0.1" - minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -11366,12 +11359,7 @@ triple-beam@^1.3.0: resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== -ts-api-utils@^1.0.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.2.1.tgz#f716c7e027494629485b21c0df6180f4d08f5e8b" - integrity sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA== - -ts-api-utils@^1.3.0: +ts-api-utils@^1.0.1, ts-api-utils@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==