UNPKG

@agoric/zoe

Version:

Zoe: the Smart Contract Framework for Offer Enforcement

250 lines (240 loc) • 8.26 kB
import type { AdditionalDisplayInfo, Amount, AnyAmount, AssetKind, Brand, DisplayInfo, Issuer, Payment, } from '@agoric/ertp'; import type { Subscriber } from '@agoric/notifier'; import type { ERef } from '@endo/far'; import type { Passable } from '@endo/pass-style'; import type { Key, Pattern } from '@endo/patterns'; import type { AmountKeywordRecord, ExitRule, FeeMintAccess, Instance, InvitationDetails, Keyword, ProposalRecord, StandardTerms, UserSeat, ZoeService, } from '../types-index.js'; import type { ContractStartFunction } from '../zoeService/utils.js'; /** * Any passable non-thenable. Often an explanatory string. */ export type Completion = Passable; export type ZCFMakeEmptySeatKit = (exit?: ExitRule | undefined) => ZcfSeatKit; export type InvitationAmount = Amount<'set', InvitationDetails>; export type ZoeIssuerRecord< K extends AssetKind = AssetKind, M extends Key = Key, > = { brand: Brand<K>; issuer: Issuer<K, M>; assetKind: K; displayInfo?: DisplayInfo<K>; }; export type Allocation = Record<Keyword, AnyAmount>; /** * Zoe Contract Facet * * The Zoe interface specific to a contract instance. The Zoe Contract * Facet is an API object used by running contract instances to access * the Zoe state for that instance. The Zoe Contract Facet is accessed * synchronously from within the contract, and usually is referred to * in code as zcf. */ export type ZCF<CT = Record<string, unknown>> = { /** * - atomically reallocate amounts among seats. */ atomicRearrange: (transfers: TransferPart[]) => void; /** * - check * whether a keyword is valid and unique and could be added in * `saveIssuer` */ assertUniqueKeyword: (keyword: Keyword) => void; /** * Informs Zoe about an issuer and returns a promise for acknowledging * when the issuer is added and ready. * * @returns the AmountMath and brand synchronously accessible after * saving */ saveIssuer: <I extends Issuer>( issuerP: ERef<I>, keyword: Keyword, ) => Promise< I extends Issuer<infer K, infer M> ? ZoeIssuerRecord<K, M> : never >; /** * Make a credible Zoe invitation for a particular smart contract * indicated by the `instance` in the details of the invitation. Zoe * also puts the `installation` and a unique `handle` in the details * of the invitation. The contract must provide a `description` for * the invitation and should include whatever information is necessary * for a potential buyer of the invitation to know what they are * getting in the `customDetails`. `customDetails` will be * placed in the details of the invitation. */ makeInvitation: <R, A = undefined>( offerHandler: OfferHandler<ERef<R>, A>, description: string, customDetails?: object, proposalShape?: Pattern, ) => Promise<Invitation<R, A>>; shutdown: (completion: Completion) => void; shutdownWithFailure: import('@agoric/swingset-vat').ShutdownWithFailure; getZoeService: () => ERef<ZoeService>; getInvitationIssuer: () => Issuer<'set'>; getTerms: () => StandardTerms & CT; getBrandForIssuer: <K extends AssetKind>(issuer: Issuer<K>) => Brand<K>; getIssuerForBrand: <K_1 extends AssetKind>(brand: Brand<K_1>) => Issuer<K_1>; getAssetKind: (brand: Brand) => AssetKind; makeZCFMint: <K_2 extends AssetKind = 'nat'>( keyword: Keyword, assetKind?: K_2 | undefined, displayInfo?: AdditionalDisplayInfo, options?: import('@agoric/ertp').IssuerOptionsRecord, ) => Promise<ZCFMint<K_2>>; registerFeeMint: ZCFRegisterFeeMint; makeEmptySeatKit: ZCFMakeEmptySeatKit; setTestJig: SetTestJig; stopAcceptingOffers: () => Promise<void>; setOfferFilter: (strings: Array<string>) => Promise<void>; getOfferFilter: () => Promise<Array<string>>; getInstance: () => Instance; }; export type TransferPart = [ fromSeat?: ZCFSeat, toSeat?: ZCFSeat, fromAmounts?: AmountKeywordRecord, toAmounts?: AmountKeywordRecord, ]; export type ZCFRegisterFeeMint = ( keyword: Keyword, allegedFeeMintAccess: FeeMintAccess, ) => Promise<ZCFMint<'nat'>>; /** * Provide a jig object for testing purposes only. * * The contract code provides a callback whose return result will * be made available to the test that started this contract. The * supplied callback will only be called in a testing context, * never in production; i.e., it is only called if `testJigSetter` * was supplied. * * If no `testFn` is supplied, then an empty jig will be used. * An additional `zcf` property set to the current ContractFacet * will be appended to the returned jig object (overriding any * provided by the `testFn`). */ export type SetTestJig = (testFn?: () => Record<string, unknown>) => void; export type ZCFMint<K extends AssetKind = AssetKind> = { getIssuerRecord: () => ZoeIssuerRecord<K>; /** * All the amounts in gains must be of this ZCFMint's brand. * The gains' keywords are in the namespace of that seat. * Add the gains to that seat's allocation. * The resulting state must be offer safe. (Currently, increasing assets can * never violate offer safety anyway.) * * Mint that amount of assets into the pooled purse. * If a seat is provided, it is returned. Otherwise a new seat is * returned. */ mintGains: (gains: AmountKeywordRecord, zcfSeat?: ZCFSeat) => ZCFSeat; /** * All the amounts in losses must be of this ZCFMint's brand. * The losses' keywords are in the namespace of that seat. * Subtract losses from that seat's allocation. * The resulting state must be offer safe. * * Burn that amount of assets from the pooled purse. */ burnLosses: (losses: AmountKeywordRecord, zcfSeat: ZCFSeat) => void; }; /** * fail called with the reason for this failure, where reason is * normally an instanceof Error. */ export type ZCFSeatFail = (reason: unknown) => Error; export type ZCFSeat = import('@endo/pass-style').RemotableObject & { exit: (completion?: Completion) => void; fail: ZCFSeatFail; getSubscriber: () => Promise<Subscriber<Allocation>>; hasExited: () => boolean; getProposal: () => ProposalRecord; /** * @param brand used for filling in an empty amount if the `keyword` * is not present in the allocation */ getAmountAllocated: <B extends Brand<any>>( keyword: Keyword, brand?: B, ) => B extends Brand<infer K> ? Amount<K> : Amount; getCurrentAllocation: () => Allocation; isOfferSafe: (newAllocation: Allocation) => boolean; }; export type ZcfSeatKit = { zcfSeat: ZCFSeat; userSeat: Promise<UserSeat>; }; export type HandleOffer<OR, OA> = (seat: ZCFSeat, offerArgs: OA) => OR; export type OfferHandler<OR = unknown, OA = never> = | HandleOffer<OR, OA> | { handle: HandleOffer<OR, OA>; }; export type ContractMeta< SF extends // import inline to maintain ambient mode ContractStartFunction = 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; }; /** * API for a contract start function. * * CAVEAT: assumes synchronous */ export type ContractStartFn<PF = any, CF = any, CT = any, PA = any> = ( zcf: ZCF<CT>, privateArgs: PA, baggage: import('@agoric/vat-data').Baggage, ) => ContractStartFnResult<PF, CF>; export type ContractStartFnResult<PF, CF> = { publicFacet?: PF; creatorFacet?: CF; creatorInvitation?: Promise<Invitation<any, any>> | undefined; }; /** * @deprecated use the parameterized version */ export type AdminFacet = import('../zoeService/utils.js').AdminFacet<any>; declare const OfferReturn: unique symbol; declare const OfferArgs: unique symbol; export type Invitation<R = unknown, A = undefined> = Payment< 'set', InvitationDetails > & { // because TS is structural, without this the generic is ignored [OfferReturn]?: R; [OfferArgs]?: A; };