-
Notifications
You must be signed in to change notification settings - Fork 1
/
contractStarter.js
139 lines (125 loc) · 3.94 KB
/
contractStarter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/**
* @file contract to start other contracts (PROTOTYPE)
*
* An experiment in delegating the right to start new contracts
* from the full set of stakers to something smaller.
*
* WARNING: anyone can start anything for free.
*
* Options:
* - charge a fee to start a contract
* - charge a fee to install a bundle
* - use a governed API (in the sense of @agoric/governance)
* for install, start
* - use a governed API for install
* - use a governed API for access to bootstrap powers
*
* Issues:
* - adminFacet is NOT SAVED. UPGRADE IS IMPOSSIBLE
* - smartWallet provides no effective way to provide privateArgs
*/
// @ts-check
import { E, Far } from '@endo/far';
import { M, mustMatch } from '@endo/patterns';
import {
InstallationShape,
IssuerRecordShape,
} from '@agoric/zoe/src/typeGuards.js';
import { depositToSeat } from '@agoric/zoe/src/contractSupport/zoeHelpers.js';
/** @template SF @typedef {import('@agoric/zoe/src/zoeService/utils').StartParams<SF>} StartParams<SF> */
const { Fail } = assert;
// /** @type {ContractMeta} */
// const meta = {};
/**
* @see {ZoeService.startInstance}
*/
export const StartOptionsShape = M.and(
M.or(
M.splitRecord({ bundleID: M.string() }),
M.splitRecord({ installation: InstallationShape }),
),
M.partial({
issuerKeywordRecord: IssuerRecordShape,
customTerms: M.any(),
privateArgs: M.any(),
instanceLabel: M.string(),
}),
);
// TODO: generate types from shapes (IOU issue #)
/**
* @template SF
* @typedef {(
* { bundleID: string } | { installation: Installation<SF> }
* ) & Partial<{
* issuerKeywordRecord: Record<string, Issuer>,
* customTerms: StartParams<SF>['terms'],
* privateArgs: StartParams<SF>['privateArgs'],
* instanceLabel: string,
* }>} StartOptions
*/
const noHandler = () => Fail`no handler`;
const NoProposalShape = M.not(M.any());
/**
* @param {ZCF} zcf
* @param {unknown} _privateArgs
* @param {unknown} _baggage
*/
export const start = (zcf, _privateArgs, _baggage) => {
const zoe = zcf.getZoeService();
const invitationIssuerP = E(zoe).getInvitationIssuer();
// NOTE: opts could be moved to offerArgs to
// save one layer of closure, but
// this way makes the types more discoverable via publicFacet
/**
* Make an invitation to to start a contract.
* The payouts include an invitation whose details
* include the resulting contract instance (and installation).
* Since the smartWallet publishes the balance
* of a user's invitation purse, this will
* make the instance and installation visible in vstorage.
*
* @template {import('@agoric/zoe/src/zoeService/utils').ContractStartFunction} SF
* @param {StartOptions<SF>} opts
*/
const makeStartInvitation = async opts => {
mustMatch(opts, StartOptionsShape);
/** @param {ZCFSeat} seat */
const handleStart = async seat => {
const installation = await ('installation' in opts
? opts.installation
: E(zoe).installBundleID(opts.bundleID));
const { issuerKeywordRecord, customTerms, privateArgs, instanceLabel } =
opts;
/** @type {StartedInstanceKit<SF>} */
const it = await E(zoe).startInstance(
installation,
issuerKeywordRecord,
customTerms,
privateArgs,
instanceLabel,
);
// WARNING: adminFacet is dropped
const { instance, creatorFacet } = it;
const handlesInDetails = zcf.makeInvitation(
noHandler,
'started',
{ instance, installation },
NoProposalShape,
);
const amt = await E(invitationIssuerP).getAmountOf(handlesInDetails);
await depositToSeat(
zcf,
seat,
{ Started: amt },
{ Started: handlesInDetails },
);
seat.exit();
return harden({ invitationMakers: creatorFacet });
};
return zcf.makeInvitation(handleStart, 'start');
};
const publicFacet = Far('PublicFacet', {
makeStartInvitation,
});
return { publicFacet };
};