Skip to content

Commit

Permalink
feat(types): ContractMeta (#9493)
Browse files Browse the repository at this point in the history
_incidental_

## Description

In adding a term to a contract I forgot to update its
`customTermsShape`. The type checker should detect that.

This makes it do so.

### Security Considerations
n/a
<!-- Does this change introduce new assumptions or dependencies that, if
violated, could introduce security vulnerabilities? How does this PR
change the boundaries between mutually-suspicious components? What new
authorities are introduced by this change, perhaps by new API calls?
-->

### Scaling Considerations
n/a
<!-- Does this change require or encourage significant increase in
consumption of CPU cycles, RAM, on-chain storage, message exchanges, or
other scarce resources? If so, can that be prevented or mitigated? -->

### Documentation Considerations
n/a
<!-- Give our docs folks some hints about what needs to be described to
downstream users.

Backwards compatibility: what happens to existing data or deployments
when this code is shipped? Do we need to instruct users to do something
to upgrade their saved data? If there is no upgrade path possible, how
bad will that be for users?

-->

### Testing Considerations
I tested some failures but didn't add a unit test. Not opposed.
<!-- Every PR should of course come with tests of its own functionality.
What additional tests are still needed beyond those unit tests? How does
this affect CI, other test automation, or the testnet?
-->

### Upgrade Considerations

<!-- What aspects of this PR are relevant to upgrading live production
systems, and how should they be addressed? -->
n/a
  • Loading branch information
mergify[bot] authored Jun 12, 2024
2 parents 0282e58 + c843758 commit d492653
Show file tree
Hide file tree
Showing 13 changed files with 61 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AmountMath } from '@agoric/ertp';
import { makeDurableZone } from '@agoric/zone/durable.js';

/** @type {ContractMeta} */
/** @type {ContractMeta<typeof start>} */
export const meta = {
upgradability: 'canUpgrade',
};
Expand Down
2 changes: 1 addition & 1 deletion packages/boot/test/bootstrapTests/zcfProbe.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const ZcfProbeI = M.interface('ZCF Probe', {
makeFaucetInvitation: M.call().returns(M.promise()),
});

// /** @type {ContractMeta} */
// /** @type {ContractMeta<typeof start>} */
// export const meta = { upgradability: 'canUpgrade' };
// harden(meta);

Expand Down
2 changes: 1 addition & 1 deletion packages/governance/src/committee.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const { ceilDivide } = natSafeMath;
* }} CommitteeElectorateCreatorFacet
*/

/** @type {ContractMeta} */
/** @type {ContractMeta<typeof start>} */
export const meta = {
privateArgsShape: {
storageNode: StorageNodeShape,
Expand Down
2 changes: 1 addition & 1 deletion packages/governance/src/contractGovernor.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const { Fail } = assert;

const trace = makeTracer('CGov', false);

/** @type {ContractMeta} */
/** @type {ContractMeta<typeof start>} */
export const meta = {
upgradability: 'canUpgrade',
};
Expand Down
2 changes: 1 addition & 1 deletion packages/inter-protocol/src/econCommitteeCharter.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const ParamChangesOfferArgsShape = M.splitRecord(
},
);

/** @type {ContractMeta} */
/** @type {ContractMeta<typeof start>} */
export const meta = {
customTermsShape: {
binaryVoteCounterInstallation: InstallationShape,
Expand Down
2 changes: 1 addition & 1 deletion packages/inter-protocol/src/feeDistributor.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { KeywordShape } from '@agoric/zoe/src/typeGuards.js';

const KeywordSharesShape = M.recordOf(KeywordShape, M.nat());

/** @type {ContractMeta} */
/** @type {ContractMeta<typeof start>} */
export const meta = {
customTermsShape: {
keywordShares: KeywordSharesShape,
Expand Down
2 changes: 1 addition & 1 deletion packages/inter-protocol/src/reserve/assetReserve.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { prepareAssetReserveKit } from './assetReserveKit.js';

const trace = makeTracer('AR', true);

/** @type {ContractMeta} */
/** @type {ContractMeta<typeof start>} */
export const meta = {
upgradability: 'canUpgrade',
};
Expand Down
1 change: 1 addition & 0 deletions packages/orchestration/src/examples/stakeIca.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const trace = makeTracer('StakeAtom');
* @import {ICQConnection, OrchestrationService} from '../types.js';
*/

/** @type {ContractMeta<typeof start>} */
export const meta = harden({
customTermsShape: {
chainId: M.string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { prepareLocalChainAccountKit } from '../exos/local-chain-account-kit.js'
* @import {NameHub} from '@agoric/vats';
*/

/** @type {ContractMeta} */
/** @type {ContractMeta<typeof start>} */
export const meta = {
privateArgsShape: {
agoricNames: M.remotable('agoricNames'),
Expand Down
2 changes: 1 addition & 1 deletion packages/vats/src/mintHolder.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function provideIssuerKit(zcf, baggage) {
return prepareIssuerKit(baggage, keyword, assetKind, displayInfo);
}

/** @type {ContractMeta} */
/** @type {ContractMeta<typeof start>} */
export const meta = {
upgradability: 'canUpgrade',
};
Expand Down
17 changes: 14 additions & 3 deletions packages/zoe/src/contractFacet/types-ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,20 @@ type OfferHandler<OR extends unknown = unknown, OA = never> =
| {
handle: HandleOffer<OR, OA>;
};
type ContractMeta = {
customTermsShape?: import('@endo/pass-style').CopyRecord<any> | undefined;
privateArgsShape?: import('@endo/pass-style').CopyRecord<any> | undefined;
type ContractMeta<
SF extends // import inline to maintain ambient mode
import('../zoeService/utils').ContractStartFunction = import('../zoeService/utils').ContractStartFunction,
> = {
customTermsShape?: Record<
Parameters<SF>[0] extends ZCF<infer CT> ? keyof CT : never,
Pattern
>;
privateArgsShape?: { [K in keyof Parameters<SF>[1]]: Pattern };
/**
* - `none` means that the contract is not upgradable.
* - `canUpgrade` means this code can perform an upgrade
* - `canBeUpgraded` means that the contract stores kinds durably such that the next version can upgrade
*/
upgradability?: 'none' | 'canBeUpgraded' | 'canUpgrade' | undefined;
};
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const { details: X } = assert;

const sellSeatExpiredMsg = 'The covered call option is expired.';

/** @type {ContractMeta} */
/** @type {ContractMeta<typeof start>} */
export const meta = {
upgradability: 'canUpgrade',
};
Expand Down
37 changes: 36 additions & 1 deletion packages/zoe/test/types.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { E, RemoteFunctions } from '@endo/eventual-send';
import { expectNotType, expectType } from 'tsd';

import type { Key } from '@endo/patterns';
import { M, type Key } from '@endo/patterns';
// 'prepare' is deprecated but still supported
import type { prepare as scaledPriceAuthorityStart } from '../src/contracts/scaledPriceAuthority.js';
import type { Instance } from '../src/zoeService/utils.js';
Expand Down Expand Up @@ -104,3 +104,38 @@ const mock = null as any;
// @ts-expect-error
pf2.notInPublicFacet;
}

{
const start = async (
zcf: ZCF<{ anchorBrand: Brand<'nat'> }>,
privateArgs: {
storageNode: StorageNode;
marshaller: Marshaller;
feeMintAccess?: FeeMintAccess;
},
) => ({});

const meta: ContractMeta<typeof start> = {
// XXX not detected
extrakey: 'bad',
privateArgsShape: {
// @ts-expect-error extra key
extraKey: 'bad',
marshaller: mock,
storageNode: mock,
},
// @ts-expect-error invalid upgradability value
upgradability: 'invalid',
};

const metaWithSplitRecord: ContractMeta<typeof start> = {
// XXX not detected
extrakey: 'bad',
// @ts-expect-error Matcher not assignable
privateArgsShape: M.splitRecord({
extraKey: 'bad',
marshaller: mock,
storageNode: mock,
}),
};
}

0 comments on commit d492653

Please sign in to comment.