@agoric/zoe
Version:
Zoe: the Smart Contract Framework for Offer Enforcement
119 lines (110 loc) • 3.92 kB
JavaScript
import { q, Fail } from '@endo/errors';
import { prepareExoClass, M } from '@agoric/vat-data';
import { assertKeywordName } from './cleanProposal.js';
import {
BrandKeywordRecordShape,
InstallationShape,
InstanceRecordShape,
IssuerKeywordRecordShape,
IssuerRecordShape,
KeywordShape,
TermsShape,
} from './typeGuards.js';
/**
* @import {Baggage} from '@agoric/vat-data';
* @import {InstanceRecord} from './zoeService/utils.js';
*/
const { ownKeys } = Reflect;
/**
* The InstanceRecord stores the installation, customTerms, issuers,
* and brands for a particular Zoe contract instance. The installation
* and customTerms are never changed, but new issuers (and their
* matching brands) may be added by the contract code. Thus, an
* InstanceRecord may be outdated at any particular point. This class
* manages the creation and updating of an InstanceRecord and provides
* functions for getting the latest data.
*/
/**
* @param {Baggage} baggage
* @returns {(ir: InstanceRecord) => InstanceState}
*/
export const makeInstanceRecordStorage = baggage => {
const assertInstantiated = instanceRecord => {
instanceRecord !== 'undefined' ||
Fail`instanceRecord has not been instantiated`;
};
const InstanceRecordI = M.interface('InstanceRecord', {
addIssuer: M.call(KeywordShape, IssuerRecordShape).returns(),
getInstanceRecord: M.call().returns(InstanceRecordShape),
getTerms: M.call().returns(M.splitRecord(TermsShape)),
getInstallation: M.call().returns(InstallationShape),
getIssuers: M.call().returns(IssuerKeywordRecordShape),
getBrands: M.call().returns(BrandKeywordRecordShape),
assertUniqueKeyword: M.call(KeywordShape).returns(),
});
const makeInstanceRecord = prepareExoClass(
baggage,
'InstanceRecord',
InstanceRecordI,
/** @type {(ir: InstanceRecord) => {instanceRecord: InstanceRecord}} */
ir => harden({ instanceRecord: ir }),
{
/** @type {(keyword: Keyword, issuerRecord: ZoeIssuerRecord) => void} */
addIssuer(keyword, issuerRecord) {
const { state } = this;
!ownKeys(issuerRecord).includes(keyword) ||
Fail`conflicting definition of ${q(keyword)}`;
assertInstantiated(state.instanceRecord);
const instanceRecord = state.instanceRecord;
const nextInstanceRecord = harden({
...instanceRecord,
terms: {
...instanceRecord.terms,
issuers: {
...instanceRecord.terms.issuers,
[keyword]: issuerRecord.issuer,
},
brands: {
...instanceRecord.terms.brands,
[keyword]: issuerRecord.brand,
},
},
});
state.instanceRecord = nextInstanceRecord;
},
getInstanceRecord() {
const { state } = this;
assertInstantiated(state.instanceRecord);
return state.instanceRecord;
},
getTerms() {
const { state } = this;
assertInstantiated(state.instanceRecord);
return state.instanceRecord.terms;
},
getInstallation() {
const { state } = this;
assertInstantiated(state.instanceRecord);
return state.instanceRecord.installation;
},
getIssuers() {
const { state } = this;
assertInstantiated(state.instanceRecord);
return state.instanceRecord.terms.issuers;
},
getBrands() {
const { state } = this;
assertInstantiated(state.instanceRecord);
return state.instanceRecord.terms.brands;
},
assertUniqueKeyword(keyword) {
const { state } = this;
assertInstantiated(state.instanceRecord);
assertKeywordName(keyword);
!ownKeys(state.instanceRecord.terms.issuers).includes(keyword) ||
Fail`keyword ${q(keyword)} must be unique`;
},
},
);
return makeInstanceRecord;
};