@agoric/deploy-script-support 0.9.7-pismo-dev-0d5327f.0 → 0.10.1-dev-bf4b59f.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/exported.js +0 -1
- package/package.json +21 -20
- package/src/assertOfferResult.js +7 -5
- package/src/cachedBundleSpec.js +32 -0
- package/src/code-gen.js +1 -4
- package/src/coreProposalBehavior.js +47 -30
- package/src/depositInvitation.js +4 -3
- package/src/endo-pieces-contract.js +4 -2
- package/src/externalTypes.js +28 -48
- package/src/extract-proposal.js +31 -30
- package/src/getBundlerMaker.js +2 -1
- package/src/helpers.js +120 -52
- package/src/install.js +52 -11
- package/src/installInPieces.js +4 -1
- package/src/offer.js +22 -7
- package/src/saveIssuer.js +8 -3
- package/src/startInstance.js +2 -1
- package/src/writeCoreProposal.js +34 -32
- package/src/createBundles.js +0 -79
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,30 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.10.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/deploy-script-support@0.9.4...@agoric/deploy-script-support@0.10.0) (2023-05-19)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **core-proposals:** use bundle hash for label ([2eec093](https://github.com/Agoric/agoric-sdk/commit/2eec0939bd87bfcc48634ab75e2ba830cdb321e3))
|
|
12
|
+
* **deploy-script-support:** Publish bundles to chain if possible ([e8209da](https://github.com/Agoric/agoric-sdk/commit/e8209daec69fc6fd60f5d865cf29271eb106a995))
|
|
13
|
+
* **deploy-script-support:** reenable for `agoric run init-core.js` without `ag-solo` ([2b2bc96](https://github.com/Agoric/agoric-sdk/commit/2b2bc96780b00d9c964dba6e6c5de36acd4a83c6))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* **deploy-script-support:** avoid pulling in notifiers ([#7522](https://github.com/Agoric/agoric-sdk/issues/7522)) ([c73675d](https://github.com/Agoric/agoric-sdk/commit/c73675dad025b6600f0eafe9f8e768086e50b626))
|
|
19
|
+
* **deploy-script-support:** update permits for `vatAdminSvc` ([73fef25](https://github.com/Agoric/agoric-sdk/commit/73fef256ab9abda1bda7e0619e8eee08c19f8883))
|
|
20
|
+
* avoid using top-level `require` ([57ca2db](https://github.com/Agoric/agoric-sdk/commit/57ca2dbfbadb373f97d43b2fb4e90302c9149976))
|
|
21
|
+
* change manifestInstallRef to manifestBundleRef ([4b87694](https://github.com/Agoric/agoric-sdk/commit/4b8769494eec1ce6bb5beda295389e8b982a9f37))
|
|
22
|
+
* remove unused overridded restoreRef, fix default version ([7f1cd48](https://github.com/Agoric/agoric-sdk/commit/7f1cd488e2aa7f89473b2187016f7f0dcbc989e8))
|
|
23
|
+
* rename makeEnactCoreProposalsFromBundleName to ..BundleRef ([7403f06](https://github.com/Agoric/agoric-sdk/commit/7403f06f58f0f50ecd154ad076a0a82317f3018b))
|
|
24
|
+
* replace unsafe then with E.when ([#6684](https://github.com/Agoric/agoric-sdk/issues/6684)) ([d7a749e](https://github.com/Agoric/agoric-sdk/commit/d7a749eec4ddec9ba39bbc65434f03ec113cae7c))
|
|
25
|
+
* replace zoe.install with zoe.installBundleID ([8a91b1b](https://github.com/Agoric/agoric-sdk/commit/8a91b1b06bf1a62c08156e595cf46f5194f73337)), closes [#6826](https://github.com/Agoric/agoric-sdk/issues/6826)
|
|
26
|
+
* **deploy-script-support:** Use versioned bundleSource ([41af48e](https://github.com/Agoric/agoric-sdk/commit/41af48e0d44e0615a53d5e3fe9f019895a58f96d))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
6
30
|
### [0.9.6](https://github.com/Agoric/agoric-sdk/compare/@agoric/deploy-script-support@0.9.5...@agoric/deploy-script-support@0.9.6) (2023-02-17)
|
|
7
31
|
|
|
8
32
|
**Note:** Version bump only for package @agoric/deploy-script-support
|
package/exported.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/deploy-script-support",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1-dev-bf4b59f.0+bf4b59f",
|
|
4
4
|
"description": "Helpers and other support for writing deploy scripts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/helpers.js",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"test:xs": "exit 0",
|
|
14
14
|
"lint-fix": "yarn lint:eslint --fix",
|
|
15
15
|
"lint:eslint": "eslint .",
|
|
16
|
-
"lint:types": "tsc
|
|
16
|
+
"lint:types": "tsc -p jsconfig.json",
|
|
17
17
|
"lint": "run-s --continue-on-error lint:*"
|
|
18
18
|
},
|
|
19
19
|
"repository": {
|
|
@@ -34,25 +34,26 @@
|
|
|
34
34
|
},
|
|
35
35
|
"homepage": "https://github.com/Agoric/agoric-sdk#readme",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@agoric/assert": "0.
|
|
38
|
-
"@agoric/ertp": "0.
|
|
39
|
-
"@agoric/import-manager": "0.3.
|
|
40
|
-
"@agoric/
|
|
41
|
-
"@agoric/notifier": "0.
|
|
42
|
-
"@agoric/store": "0.
|
|
43
|
-
"@agoric/
|
|
44
|
-
"@
|
|
45
|
-
"@endo/
|
|
46
|
-
"@endo/
|
|
47
|
-
"@endo/
|
|
48
|
-
"@endo/
|
|
49
|
-
"@endo/promise-kit": "^0.2.
|
|
50
|
-
"@endo/zip": "^0.2.
|
|
37
|
+
"@agoric/assert": "0.6.1-dev-bf4b59f.0+bf4b59f",
|
|
38
|
+
"@agoric/ertp": "0.16.1-dev-bf4b59f.0+bf4b59f",
|
|
39
|
+
"@agoric/import-manager": "0.3.10-dev-bf4b59f.0+bf4b59f",
|
|
40
|
+
"@agoric/internal": "0.3.1-dev-bf4b59f.0+bf4b59f",
|
|
41
|
+
"@agoric/notifier": "0.6.1-dev-bf4b59f.0+bf4b59f",
|
|
42
|
+
"@agoric/store": "0.9.1-dev-bf4b59f.0+bf4b59f",
|
|
43
|
+
"@agoric/zoe": "0.26.1-dev-bf4b59f.0+bf4b59f",
|
|
44
|
+
"@endo/base64": "^0.2.31",
|
|
45
|
+
"@endo/bundle-source": "^2.5.1",
|
|
46
|
+
"@endo/far": "^0.2.18",
|
|
47
|
+
"@endo/marshal": "^0.8.5",
|
|
48
|
+
"@endo/nat": "^4.1.27",
|
|
49
|
+
"@endo/promise-kit": "^0.2.56",
|
|
50
|
+
"@endo/zip": "^0.2.31"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@agoric/
|
|
54
|
-
"
|
|
55
|
-
"
|
|
53
|
+
"@agoric/vats": "0.14.1-dev-bf4b59f.0+bf4b59f",
|
|
54
|
+
"@endo/init": "^0.5.56",
|
|
55
|
+
"ava": "^5.2.0",
|
|
56
|
+
"import-meta-resolve": "^2.2.1"
|
|
56
57
|
},
|
|
57
58
|
"files": [
|
|
58
59
|
"src",
|
|
@@ -67,5 +68,5 @@
|
|
|
67
68
|
"publishConfig": {
|
|
68
69
|
"access": "public"
|
|
69
70
|
},
|
|
70
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "bf4b59f2128aca73d786429c6ef4a7c9cdfb6700"
|
|
71
72
|
}
|
package/src/assertOfferResult.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
import {
|
|
2
|
+
import { Fail } from '@agoric/assert';
|
|
3
3
|
import { E } from '@endo/far';
|
|
4
4
|
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* @param {ERef<UserSeat>} seat
|
|
7
|
+
* @param {string} expectedOfferResult
|
|
8
|
+
* @returns {Promise<void>}
|
|
9
|
+
*/
|
|
6
10
|
export const assertOfferResult = async (seat, expectedOfferResult) => {
|
|
7
11
|
const actualOfferResult = await E(seat).getOfferResult();
|
|
8
12
|
actualOfferResult === expectedOfferResult ||
|
|
9
|
-
|
|
10
|
-
X`offerResult (${actualOfferResult}) did not equal expected: ${expectedOfferResult}`,
|
|
11
|
-
);
|
|
13
|
+
Fail`offerResult (${actualOfferResult}) did not equal expected: ${expectedOfferResult}`;
|
|
12
14
|
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const { Fail } = assert;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {string} cacheDir
|
|
5
|
+
* @param {{ now: typeof Date.now, fs: import('fs').promises, pathResolve: typeof import('path').resolve }} param1
|
|
6
|
+
*/
|
|
7
|
+
export const makeCacheAndGetBundleSpec =
|
|
8
|
+
(cacheDir, { now, fs, pathResolve }) =>
|
|
9
|
+
async bundleP => {
|
|
10
|
+
const bundle = await bundleP;
|
|
11
|
+
const { endoZipBase64Sha512: hash } = bundle;
|
|
12
|
+
|
|
13
|
+
typeof hash === 'string' || Fail`bundle hash ${hash} must be a string`;
|
|
14
|
+
const bundleID = `b1-${hash}`;
|
|
15
|
+
const cacheFile = pathResolve(cacheDir, `${bundleID}.json`);
|
|
16
|
+
|
|
17
|
+
await fs.mkdir(cacheDir, { recursive: true });
|
|
18
|
+
try {
|
|
19
|
+
await fs.stat(cacheFile);
|
|
20
|
+
} catch (e) {
|
|
21
|
+
if (e.code !== 'ENOENT') {
|
|
22
|
+
throw e;
|
|
23
|
+
}
|
|
24
|
+
// FIXME: We could take a hard dependency on `tmp` here, but is it worth it?
|
|
25
|
+
const tmpFile = `${cacheFile}.${now()}`;
|
|
26
|
+
await fs.writeFile(tmpFile, JSON.stringify(bundle, null, 2), {
|
|
27
|
+
flag: 'wx',
|
|
28
|
+
});
|
|
29
|
+
await fs.rename(tmpFile, cacheFile);
|
|
30
|
+
}
|
|
31
|
+
return harden({ bundleID, fileName: cacheFile });
|
|
32
|
+
};
|
package/src/code-gen.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
import { makeMarshal } from '@endo/marshal';
|
|
3
|
-
import { decodeToJustin } from '@endo/marshal/src/marshal-justin.js';
|
|
4
|
-
|
|
5
|
-
export { deeplyFulfilled } from '@endo/marshal';
|
|
2
|
+
import { makeMarshal, decodeToJustin } from '@endo/marshal';
|
|
6
3
|
|
|
7
4
|
const { keys, values, fromEntries } = Object;
|
|
8
5
|
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
const t = 'makeCoreProposalBehavior';
|
|
2
3
|
|
|
4
|
+
/**
|
|
5
|
+
* TODO import these from @agoric/vats when the types are better managed
|
|
6
|
+
*
|
|
7
|
+
* @typedef {*} ChainBootstrapSpace
|
|
8
|
+
* @typedef {*} BootstrapPowers
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// These permits apply to `allPowers` in `behavior` below.
|
|
3
12
|
export const permits = {
|
|
4
|
-
consume: {
|
|
5
|
-
|
|
13
|
+
consume: { agoricNamesAdmin: t, vatAdminSvc: t, zoe: t },
|
|
14
|
+
evaluateBundleCap: t,
|
|
6
15
|
installation: { produce: t },
|
|
7
16
|
modules: { utils: { runModuleBehaviors: t } },
|
|
8
17
|
};
|
|
@@ -15,7 +24,7 @@ export const permits = {
|
|
|
15
24
|
* definitions.
|
|
16
25
|
*
|
|
17
26
|
* @param {object} opts
|
|
18
|
-
* @param {string} opts.
|
|
27
|
+
* @param {{ bundleName: string } | { bundleID: string }} opts.manifestBundleRef
|
|
19
28
|
* @param {[string, ...unknown[]]} opts.getManifestCall
|
|
20
29
|
* @param {Record<string, Record<string, unknown>>} [opts.overrideManifest]
|
|
21
30
|
* @param {typeof import('@endo/far').E} opts.E
|
|
@@ -24,7 +33,7 @@ export const permits = {
|
|
|
24
33
|
* @returns {(vatPowers: unknown) => Promise<unknown>}
|
|
25
34
|
*/
|
|
26
35
|
export const makeCoreProposalBehavior = ({
|
|
27
|
-
|
|
36
|
+
manifestBundleRef,
|
|
28
37
|
getManifestCall,
|
|
29
38
|
overrideManifest,
|
|
30
39
|
E,
|
|
@@ -47,10 +56,13 @@ export const makeCoreProposalBehavior = ({
|
|
|
47
56
|
return fromEntries(ents);
|
|
48
57
|
};
|
|
49
58
|
|
|
59
|
+
/** @param {ChainBootstrapSpace & BootstrapPowers & { evaluateBundleCap: any }} allPowers */
|
|
50
60
|
const behavior = async allPowers => {
|
|
61
|
+
// NOTE: If updating any of these names extracted from `allPowers`, you must
|
|
62
|
+
// change `permits` above to reflect their accessibility.
|
|
51
63
|
const {
|
|
52
|
-
consume: {
|
|
53
|
-
|
|
64
|
+
consume: { vatAdminSvc, zoe, agoricNamesAdmin },
|
|
65
|
+
evaluateBundleCap,
|
|
54
66
|
installation: { produce: produceInstallations },
|
|
55
67
|
modules: {
|
|
56
68
|
utils: { runModuleBehaviors },
|
|
@@ -58,25 +70,44 @@ export const makeCoreProposalBehavior = ({
|
|
|
58
70
|
} = allPowers;
|
|
59
71
|
const [exportedGetManifest, ...manifestArgs] = getManifestCall;
|
|
60
72
|
|
|
61
|
-
const
|
|
73
|
+
const defaultRestoreRef = async ref => {
|
|
74
|
+
// extract-proposal.js creates these records, and bundleName is
|
|
75
|
+
// the name under which the bundle was installed into
|
|
76
|
+
// config.bundles
|
|
77
|
+
const p = ref.bundleName
|
|
78
|
+
? E(vatAdminSvc).getBundleIDByName(ref.bundleName)
|
|
79
|
+
: ref.bundleID;
|
|
80
|
+
const bundleID = await p;
|
|
81
|
+
const label = bundleID.slice(0, 8);
|
|
82
|
+
return E(zoe).installBundleID(bundleID, label);
|
|
83
|
+
};
|
|
84
|
+
const restoreRef = overrideRestoreRef || defaultRestoreRef;
|
|
62
85
|
|
|
63
86
|
// Get the on-chain installation containing the manifest and behaviors.
|
|
64
|
-
console.info('
|
|
65
|
-
|
|
87
|
+
console.info('evaluateBundleCap', {
|
|
88
|
+
manifestBundleRef,
|
|
66
89
|
exportedGetManifest,
|
|
90
|
+
vatAdminSvc,
|
|
67
91
|
});
|
|
68
|
-
|
|
69
|
-
|
|
92
|
+
let bcapP;
|
|
93
|
+
if ('bundleName' in manifestBundleRef) {
|
|
94
|
+
bcapP = E(vatAdminSvc).getNamedBundleCap(manifestBundleRef.bundleName);
|
|
95
|
+
} else {
|
|
96
|
+
bcapP = E(vatAdminSvc).getBundleCap(manifestBundleRef.bundleID);
|
|
97
|
+
}
|
|
98
|
+
const bundleCap = await bcapP;
|
|
99
|
+
|
|
100
|
+
const manifestNS = await evaluateBundleCap(bundleCap);
|
|
70
101
|
|
|
71
102
|
console.error('execute', {
|
|
72
103
|
exportedGetManifest,
|
|
73
|
-
behaviors: Object.keys(
|
|
104
|
+
behaviors: Object.keys(manifestNS),
|
|
74
105
|
});
|
|
75
106
|
const {
|
|
76
107
|
manifest,
|
|
77
108
|
options: rawOptions,
|
|
78
109
|
installations: rawInstallations,
|
|
79
|
-
} = await
|
|
110
|
+
} = await manifestNS[exportedGetManifest](
|
|
80
111
|
harden({ restoreRef }),
|
|
81
112
|
...manifestArgs,
|
|
82
113
|
);
|
|
@@ -98,7 +129,7 @@ export const makeCoreProposalBehavior = ({
|
|
|
98
129
|
// Evaluate the manifest for our behaviors.
|
|
99
130
|
return runModuleBehaviors({
|
|
100
131
|
allPowers,
|
|
101
|
-
behaviors,
|
|
132
|
+
behaviors: manifestNS,
|
|
102
133
|
manifest: overrideManifest || manifest,
|
|
103
134
|
makeConfig: (name, _permit) => {
|
|
104
135
|
log('coreProposal:', name);
|
|
@@ -111,30 +142,16 @@ export const makeCoreProposalBehavior = ({
|
|
|
111
142
|
return behavior;
|
|
112
143
|
};
|
|
113
144
|
|
|
114
|
-
export const
|
|
145
|
+
export const makeEnactCoreProposalsFromBundleRef =
|
|
115
146
|
({ makeCoreProposalArgs, E }) =>
|
|
116
147
|
async allPowers => {
|
|
117
|
-
const {
|
|
118
|
-
vatPowers: { D },
|
|
119
|
-
devices: { vatAdmin },
|
|
120
|
-
consume: { zoe },
|
|
121
|
-
} = allPowers;
|
|
122
|
-
const restoreRef = async ref => {
|
|
123
|
-
const { bundleID } = ref;
|
|
124
|
-
const bundleCap = D(vatAdmin).getNamedBundleCap(bundleID);
|
|
125
|
-
const bundle = D(bundleCap).getBundle();
|
|
126
|
-
const install = await E(zoe).install(bundle);
|
|
127
|
-
return install;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
148
|
await Promise.all(
|
|
131
149
|
makeCoreProposalArgs.map(async ({ ref, call, overrideManifest }) => {
|
|
132
150
|
const subBehavior = makeCoreProposalBehavior({
|
|
133
|
-
|
|
151
|
+
manifestBundleRef: ref,
|
|
134
152
|
getManifestCall: call,
|
|
135
153
|
overrideManifest,
|
|
136
154
|
E,
|
|
137
|
-
restoreRef,
|
|
138
155
|
});
|
|
139
156
|
return subBehavior(allPowers);
|
|
140
157
|
}),
|
package/src/depositInvitation.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
|
|
3
2
|
import { E } from '@endo/far';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* @param {ERef<Purse>} zoeInvitationPurse
|
|
7
|
-
* @returns {DepositInvitation}
|
|
8
6
|
*/
|
|
9
7
|
export const makeDepositInvitation = zoeInvitationPurse => {
|
|
10
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* @param {ERef<Invitation>} invitationP
|
|
10
|
+
* @returns {Promise<InvitationDetails>}
|
|
11
|
+
*/
|
|
11
12
|
const depositInvitation = async invitationP => {
|
|
12
13
|
const invitation = await invitationP;
|
|
13
14
|
// Deposit returns the amount deposited
|
|
@@ -3,7 +3,7 @@ import { E, Far } from '@endo/far';
|
|
|
3
3
|
import { encodeBase64, decodeBase64 } from '@endo/base64';
|
|
4
4
|
import { ZipWriter } from '@endo/zip';
|
|
5
5
|
|
|
6
|
-
const {
|
|
6
|
+
const { Fail, quote: q } = assert;
|
|
7
7
|
|
|
8
8
|
export const start = () => {
|
|
9
9
|
/** @type { Map<string, [string, Uint8Array]>} */
|
|
@@ -45,7 +45,9 @@ export const start = () => {
|
|
|
45
45
|
*/
|
|
46
46
|
addByRef: (name, hash) => {
|
|
47
47
|
const entry = hashToEntry.get(hash);
|
|
48
|
-
|
|
48
|
+
if (!entry) {
|
|
49
|
+
throw Fail`hash not found: ${q(hash)}`;
|
|
50
|
+
}
|
|
49
51
|
const [_n, content] = entry;
|
|
50
52
|
nameToContent.set(name, [hash, content]);
|
|
51
53
|
},
|
package/src/externalTypes.js
CHANGED
|
@@ -1,66 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* @param {string} resolvedPath
|
|
4
|
-
* @param {Petname} contractPetname
|
|
5
|
-
* @returns {{ installation: Installation, id: string}}
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @typedef {object} StartInstanceResultWithDetailsNoInvitation
|
|
10
|
-
* @property {any} creatorFacet
|
|
11
|
-
* @property {any} publicFacet
|
|
12
|
-
* @property {Instance} instance
|
|
13
|
-
* @property {InvitationDetails} creatorInvitationDetails
|
|
14
|
-
* @property {AdminFacet} adminFacet
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @typedef {object} OfferHelperConfig
|
|
19
|
-
* @property {ERef<Invitation>=} invitation
|
|
20
|
-
* @property {Partial<InvitationDetails>=} partialInvitationDetails
|
|
21
|
-
* @property {Proposal} proposal
|
|
22
|
-
* @property {Record<Keyword, Petname>} paymentsWithPursePetnames
|
|
23
|
-
* @property {Record<Keyword, Petname>} payoutPursePetnames
|
|
24
|
-
*/
|
|
1
|
+
// @ts-check
|
|
2
|
+
export {};
|
|
25
3
|
|
|
4
|
+
// TODO move this type somewhere better
|
|
26
5
|
/**
|
|
27
|
-
* @
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* InvitationDetails}}
|
|
6
|
+
* @typedef {string | string[]} Petname A petname can either be a plain string
|
|
7
|
+
* or a path for which the first element is a petname for the origin, and the
|
|
8
|
+
* rest of the elements are a snapshot of the names that were first given by that
|
|
9
|
+
* origin. We are migrating away from using plain strings, for consistency.
|
|
32
10
|
*/
|
|
33
11
|
|
|
34
12
|
/**
|
|
35
|
-
* @
|
|
36
|
-
* @
|
|
37
|
-
* @
|
|
13
|
+
* @typedef ProposalResult
|
|
14
|
+
* @property {string} sourceSpec
|
|
15
|
+
* @property {[exportedGetManifest: string, ...manifestArgs: any[]]} getManifestCall
|
|
38
16
|
*/
|
|
39
17
|
|
|
40
18
|
/**
|
|
41
|
-
* @
|
|
42
|
-
* @
|
|
43
|
-
* @returns {InvitationDetails}
|
|
19
|
+
* @typedef BundleHandle
|
|
20
|
+
* @property {string} [bundleName]
|
|
44
21
|
*/
|
|
45
22
|
|
|
46
23
|
/**
|
|
47
|
-
* @callback
|
|
48
|
-
* @param {ERef<
|
|
49
|
-
* @
|
|
50
|
-
* @param {Petname} pursePetname
|
|
51
|
-
* @returns {Promise<Petname>}
|
|
24
|
+
* @callback PublishBundleRef
|
|
25
|
+
* @param {ERef<BundleHandle>} bundle
|
|
26
|
+
* @returns {Promise<BundleHandle>}
|
|
52
27
|
*/
|
|
53
28
|
|
|
54
29
|
/**
|
|
55
|
-
* @callback
|
|
56
|
-
* @param {
|
|
57
|
-
* @param {string}
|
|
58
|
-
* @
|
|
30
|
+
* @callback InstallBundle
|
|
31
|
+
* @param {string} srcSpec
|
|
32
|
+
* @param {string} bundlePath
|
|
33
|
+
* @param {any} [opts]
|
|
34
|
+
* @returns {BundleHandle}
|
|
59
35
|
*/
|
|
60
36
|
|
|
61
37
|
/**
|
|
62
|
-
* @
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
38
|
+
* @callback ProposalBuilder
|
|
39
|
+
* @param {{
|
|
40
|
+
* publishRef: PublishBundleRef,
|
|
41
|
+
* install: InstallBundle,
|
|
42
|
+
* wrapInstall?: <T>(f: T) => T }
|
|
43
|
+
* } powers
|
|
44
|
+
* @param {...any} args
|
|
45
|
+
* @returns {Promise<ProposalResult>}
|
|
66
46
|
*/
|
package/src/extract-proposal.js
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
+
import { deeplyFulfilledObject } from '@agoric/internal';
|
|
2
3
|
import fs from 'fs';
|
|
3
4
|
import { createRequire } from 'module';
|
|
4
5
|
import path from 'path';
|
|
5
6
|
|
|
6
|
-
import {
|
|
7
|
+
import { defangAndTrim, stringify } from './code-gen.js';
|
|
7
8
|
import {
|
|
8
9
|
makeCoreProposalBehavior,
|
|
9
|
-
|
|
10
|
+
makeEnactCoreProposalsFromBundleRef,
|
|
10
11
|
} from './coreProposalBehavior.js';
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {string | { module: string, entrypoint: string, args?: Array<unknown> }} ConfigProposal
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const { details: X, Fail } = assert;
|
|
13
18
|
|
|
14
|
-
const
|
|
19
|
+
const req = createRequire(import.meta.url);
|
|
15
20
|
|
|
16
21
|
/**
|
|
17
22
|
* @param {(ModuleSpecifier | FilePath)[]} paths
|
|
@@ -22,7 +27,7 @@ const pathResolve = (...paths) => {
|
|
|
22
27
|
const fileName = paths.pop();
|
|
23
28
|
assert(fileName, '>=1 paths required');
|
|
24
29
|
try {
|
|
25
|
-
return
|
|
30
|
+
return req.resolve(fileName, {
|
|
26
31
|
paths,
|
|
27
32
|
});
|
|
28
33
|
} catch (e) {
|
|
@@ -41,16 +46,16 @@ const pathResolve = (...paths) => {
|
|
|
41
46
|
* but for sim-chain and such, they can be declared statically in
|
|
42
47
|
* the chain configuration, in which case they are run at bootstrap.
|
|
43
48
|
*
|
|
44
|
-
* @param {
|
|
49
|
+
* @param {ConfigProposal[]} coreProposals - governance
|
|
45
50
|
* proposals to run at chain bootstrap for scenarios such as sim-chain.
|
|
46
51
|
* @param {FilePath} [dirname]
|
|
47
|
-
* @param {typeof
|
|
52
|
+
* @param {typeof makeEnactCoreProposalsFromBundleRef} [makeEnactCoreProposals]
|
|
48
53
|
* @param {(i: number) => number} [getSequenceForProposal]
|
|
49
54
|
*/
|
|
50
55
|
export const extractCoreProposalBundles = async (
|
|
51
56
|
coreProposals,
|
|
52
57
|
dirname = '.',
|
|
53
|
-
makeEnactCoreProposals =
|
|
58
|
+
makeEnactCoreProposals = makeEnactCoreProposalsFromBundleRef,
|
|
54
59
|
getSequenceForProposal,
|
|
55
60
|
) => {
|
|
56
61
|
if (!getSequenceForProposal) {
|
|
@@ -63,7 +68,7 @@ export const extractCoreProposalBundles = async (
|
|
|
63
68
|
.stat(dirname)
|
|
64
69
|
.then(stbuf => (stbuf.isDirectory() ? dirname : path.dirname(dirname)));
|
|
65
70
|
|
|
66
|
-
/** @type {Map<{
|
|
71
|
+
/** @type {Map<{ bundleName?: string }, { source: string, bundle?: string }>} */
|
|
67
72
|
const bundleHandleToAbsolutePaths = new Map();
|
|
68
73
|
|
|
69
74
|
const bundleToSource = new Map();
|
|
@@ -85,23 +90,18 @@ export const extractCoreProposalBundles = async (
|
|
|
85
90
|
({ module, entrypoint, args = [] } = coreProposal);
|
|
86
91
|
}
|
|
87
92
|
|
|
88
|
-
|
|
89
|
-
module
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
)
|
|
93
|
-
assert.typeof(
|
|
94
|
-
entrypoint,
|
|
95
|
-
'string',
|
|
96
|
-
X`coreProposal entrypoint ${entrypoint} must be string`,
|
|
97
|
-
);
|
|
98
|
-
assert(Array.isArray(args), X`coreProposal args ${args} must be array`);
|
|
93
|
+
typeof module === 'string' ||
|
|
94
|
+
Fail`coreProposal module ${module} must be string`;
|
|
95
|
+
typeof entrypoint === 'string' ||
|
|
96
|
+
Fail`coreProposal entrypoint ${entrypoint} must be string`;
|
|
97
|
+
Array.isArray(args) || Fail`coreProposal args ${args} must be array`;
|
|
99
98
|
|
|
100
99
|
const thisProposalBundleHandles = new Set();
|
|
101
100
|
assert(getSequenceForProposal);
|
|
102
101
|
const thisProposalSequence = getSequenceForProposal(i);
|
|
103
102
|
const initPath = pathResolve(dirname, module);
|
|
104
103
|
const initDir = path.dirname(initPath);
|
|
104
|
+
/** @type {Record<string, import('./externalTypes.js').ProposalBuilder>} */
|
|
105
105
|
const ns = await import(initPath);
|
|
106
106
|
const install = (srcSpec, bundlePath) => {
|
|
107
107
|
const absoluteSrc = pathResolve(initDir, srcSpec);
|
|
@@ -121,16 +121,17 @@ export const extractCoreProposalBundles = async (
|
|
|
121
121
|
bundleToSource.set(absoluteBundle, absoluteSrc);
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
-
// Don't harden the bundleHandle since we need to set the
|
|
124
|
+
// Don't harden the bundleHandle since we need to set the bundleName on
|
|
125
125
|
// its unique identity later.
|
|
126
126
|
thisProposalBundleHandles.add(bundleHandle);
|
|
127
127
|
bundleHandleToAbsolutePaths.set(bundleHandle, harden(absolutePaths));
|
|
128
128
|
return bundleHandle;
|
|
129
129
|
};
|
|
130
|
+
/** @type {import('./externalTypes.js').PublishBundleRef} */
|
|
130
131
|
const publishRef = async handleP => {
|
|
131
132
|
const handle = await handleP;
|
|
132
133
|
bundleHandleToAbsolutePaths.has(handle) ||
|
|
133
|
-
|
|
134
|
+
Fail`${handle} not in installed bundles`;
|
|
134
135
|
return handle;
|
|
135
136
|
};
|
|
136
137
|
const proposal = await ns[entrypoint]({ publishRef, install }, ...args);
|
|
@@ -148,21 +149,21 @@ export const extractCoreProposalBundles = async (
|
|
|
148
149
|
return 0;
|
|
149
150
|
})
|
|
150
151
|
.map(([handle, absolutePaths], j) => {
|
|
151
|
-
// Transform the bundle handle identity into a
|
|
152
|
-
handle.
|
|
152
|
+
// Transform the bundle handle identity into a bundleName reference.
|
|
153
|
+
handle.bundleName = `coreProposal${thisProposalSequence}_${j}`;
|
|
153
154
|
harden(handle);
|
|
154
155
|
|
|
155
156
|
/** @type {[string, { sourceSpec: string }]} */
|
|
156
157
|
const specEntry = [
|
|
157
|
-
handle.
|
|
158
|
+
handle.bundleName,
|
|
158
159
|
{ sourceSpec: absolutePaths.source },
|
|
159
160
|
];
|
|
160
161
|
return specEntry;
|
|
161
162
|
});
|
|
162
163
|
|
|
163
|
-
// Now that we've assigned all the
|
|
164
|
-
// can extract the behavior bundle.
|
|
165
|
-
const { sourceSpec, getManifestCall } = await
|
|
164
|
+
// Now that we've assigned all the bundleNames and hardened the
|
|
165
|
+
// handles, we can extract the behavior bundle.
|
|
166
|
+
const { sourceSpec, getManifestCall } = await deeplyFulfilledObject(
|
|
166
167
|
harden(proposal),
|
|
167
168
|
);
|
|
168
169
|
|
|
@@ -174,7 +175,7 @@ export const extractCoreProposalBundles = async (
|
|
|
174
175
|
](harden({ restoreRef: () => null }), ...manifestArgs);
|
|
175
176
|
|
|
176
177
|
const behaviorBundleHandle = harden({
|
|
177
|
-
|
|
178
|
+
bundleName: `coreProposal${thisProposalSequence}_behaviors`,
|
|
178
179
|
});
|
|
179
180
|
const behaviorAbsolutePaths = harden({
|
|
180
181
|
source: behaviorSource,
|
|
@@ -185,7 +186,7 @@ export const extractCoreProposalBundles = async (
|
|
|
185
186
|
);
|
|
186
187
|
|
|
187
188
|
bundleSpecEntries.unshift([
|
|
188
|
-
behaviorBundleHandle.
|
|
189
|
+
behaviorBundleHandle.bundleName,
|
|
189
190
|
{ sourceSpec: behaviorAbsolutePaths.source },
|
|
190
191
|
]);
|
|
191
192
|
|
package/src/getBundlerMaker.js
CHANGED
|
@@ -14,11 +14,12 @@ import { E } from '@endo/far';
|
|
|
14
14
|
import url from 'url';
|
|
15
15
|
|
|
16
16
|
export const makeGetBundlerMaker =
|
|
17
|
-
(
|
|
17
|
+
(homeP, { lookup, bundleSource }) =>
|
|
18
18
|
async ({
|
|
19
19
|
BUNDLER_MAKER_LOOKUP = JSON.stringify(['scratch', 'bundlerMaker']),
|
|
20
20
|
log = console.log,
|
|
21
21
|
} = {}) => {
|
|
22
|
+
const { board: optionalBoard, zoe, scratch } = await homeP;
|
|
22
23
|
const lookupOrCreate = async () => {
|
|
23
24
|
// Locate the bundler maker if any already exists at the given path.
|
|
24
25
|
let bundlerMaker = await lookup(JSON.parse(BUNDLER_MAKER_LOOKUP));
|
package/src/helpers.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import '@agoric/zoe/exported.js';
|
|
3
3
|
import { E } from '@endo/far';
|
|
4
|
+
import bundleSource from '@endo/bundle-source';
|
|
5
|
+
|
|
6
|
+
import fs from 'fs/promises';
|
|
7
|
+
import os from 'os';
|
|
4
8
|
|
|
5
9
|
import { makeInstall } from './install.js';
|
|
6
10
|
import { makeOfferAndFindInvitationAmount } from './offer.js';
|
|
7
11
|
import { makeStartInstance } from './startInstance.js';
|
|
12
|
+
import { makeCacheAndGetBundleSpec } from './cachedBundleSpec.js';
|
|
8
13
|
import { makeDepositInvitation } from './depositInvitation.js';
|
|
9
14
|
import { makeSaveIssuer } from './saveIssuer.js';
|
|
10
15
|
import { makeGetBundlerMaker } from './getBundlerMaker.js';
|
|
@@ -12,68 +17,131 @@ import { assertOfferResult } from './assertOfferResult.js';
|
|
|
12
17
|
import { installInPieces } from './installInPieces.js';
|
|
13
18
|
import { makeWriteCoreProposal } from './writeCoreProposal.js';
|
|
14
19
|
|
|
15
|
-
export * from '
|
|
20
|
+
export * from '@agoric/internal/src/node/createBundles.js';
|
|
16
21
|
|
|
17
22
|
// These are also hard-coded in lib-wallet.js.
|
|
18
23
|
// TODO: Add methods to the wallet to access these without hard-coding
|
|
19
24
|
// on this end.
|
|
20
25
|
const ZOE_INVITE_PURSE_PETNAME = 'Default Zoe invite purse';
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
zoeInvitationPurse,
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
const { offer, findInvitationAmount } = makeOfferAndFindInvitationAmount(
|
|
48
|
-
walletAdmin,
|
|
49
|
-
zoe,
|
|
50
|
-
zoeInvitationPurse,
|
|
27
|
+
/**
|
|
28
|
+
* @template {Record<PropertyKey, any>} T
|
|
29
|
+
*
|
|
30
|
+
* Lazily populate the returned object's properties from the properties of a
|
|
31
|
+
* source object. Each `sourceObject` property value is sampled at most once.
|
|
32
|
+
*
|
|
33
|
+
* @param {T} sourceObject
|
|
34
|
+
* @returns {T}
|
|
35
|
+
*/
|
|
36
|
+
const makeLazyObject = sourceObject => {
|
|
37
|
+
const lazyObject = new Proxy(
|
|
38
|
+
{},
|
|
39
|
+
{
|
|
40
|
+
get(t, key) {
|
|
41
|
+
if (!(key in t)) {
|
|
42
|
+
if (key in sourceObject) {
|
|
43
|
+
t[key] = sourceObject[key];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return t[key];
|
|
47
|
+
},
|
|
48
|
+
},
|
|
51
49
|
);
|
|
50
|
+
return /** @type {T} */ (lazyObject);
|
|
51
|
+
};
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
export const makeHelpers = async (homePromise, endowments) => {
|
|
54
|
+
// Endowments provided via `agoric run` or `agoric deploy`.
|
|
55
|
+
const {
|
|
56
|
+
now,
|
|
57
|
+
lookup,
|
|
58
|
+
publishBundle,
|
|
59
|
+
pathResolve,
|
|
60
|
+
cacheDir = pathResolve(os.homedir(), '.agoric/cache'),
|
|
61
|
+
} = endowments;
|
|
62
|
+
|
|
63
|
+
// Internal-to-this-function lazy dependencies.
|
|
64
|
+
const deps = makeLazyObject({
|
|
65
|
+
get cacheAndGetBundleSpec() {
|
|
66
|
+
return makeCacheAndGetBundleSpec(cacheDir, {
|
|
67
|
+
now,
|
|
68
|
+
fs,
|
|
69
|
+
pathResolve,
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
get home() {
|
|
73
|
+
return E.get(homePromise);
|
|
74
|
+
},
|
|
75
|
+
get installationManager() {
|
|
76
|
+
return E(deps.walletAdmin).getInstallationManager();
|
|
77
|
+
},
|
|
78
|
+
get instanceManager() {
|
|
79
|
+
return E(deps.walletAdmin).getInstanceManager();
|
|
80
|
+
},
|
|
81
|
+
get issuerManager() {
|
|
82
|
+
return E(deps.walletAdmin).getIssuerManager();
|
|
83
|
+
},
|
|
84
|
+
get offerAndFind() {
|
|
85
|
+
return makeOfferAndFindInvitationAmount(
|
|
86
|
+
deps.walletAdmin,
|
|
87
|
+
deps.home.zoe,
|
|
88
|
+
deps.zoeInvitationPurse,
|
|
89
|
+
);
|
|
90
|
+
},
|
|
91
|
+
get walletAdmin() {
|
|
92
|
+
return E(deps.home.wallet).getAdminFacet();
|
|
93
|
+
},
|
|
94
|
+
get zoeInvitationPurse() {
|
|
95
|
+
// TODO: Rather than using one purse with a hard-coded petname, find
|
|
96
|
+
// a better solution.
|
|
97
|
+
return E(deps.walletAdmin).getPurse(ZOE_INVITE_PURSE_PETNAME);
|
|
98
|
+
},
|
|
99
|
+
});
|
|
61
100
|
|
|
62
|
-
|
|
101
|
+
// The memo returned to our callers.
|
|
102
|
+
const helpers = makeLazyObject({
|
|
103
|
+
assertOfferResult,
|
|
104
|
+
get depositInvitation() {
|
|
105
|
+
return makeDepositInvitation(deps.zoeInvitationPurse);
|
|
106
|
+
},
|
|
107
|
+
get findInvitationAmount() {
|
|
108
|
+
return deps.offerAndFind.findInvitationAmount;
|
|
109
|
+
},
|
|
110
|
+
get install() {
|
|
111
|
+
return makeInstall(
|
|
112
|
+
bundleSource,
|
|
113
|
+
deps.home.zoe,
|
|
114
|
+
deps.installationManager,
|
|
115
|
+
deps.home.board,
|
|
116
|
+
publishBundle,
|
|
117
|
+
pathResolve,
|
|
118
|
+
);
|
|
119
|
+
},
|
|
63
120
|
installInPieces,
|
|
64
|
-
|
|
121
|
+
get offer() {
|
|
122
|
+
return deps.offerAndFind.offer;
|
|
123
|
+
},
|
|
124
|
+
get saveIssuer() {
|
|
125
|
+
return makeSaveIssuer(deps.walletAdmin, deps.issuerManager);
|
|
126
|
+
},
|
|
127
|
+
get startInstance() {
|
|
128
|
+
return makeStartInstance(
|
|
129
|
+
deps.issuerManager,
|
|
130
|
+
deps.instanceManager,
|
|
131
|
+
deps.home.zoe,
|
|
132
|
+
deps.zoeInvitationPurse,
|
|
133
|
+
);
|
|
134
|
+
},
|
|
135
|
+
get getBundlerMaker() {
|
|
136
|
+
return makeGetBundlerMaker(homePromise, { bundleSource, lookup });
|
|
137
|
+
},
|
|
138
|
+
get writeCoreProposal() {
|
|
139
|
+
return makeWriteCoreProposal(homePromise, endowments, {
|
|
140
|
+
getBundleSpec: deps.cacheAndGetBundleSpec,
|
|
141
|
+
getBundlerMaker: helpers.getBundlerMaker,
|
|
142
|
+
});
|
|
143
|
+
},
|
|
65
144
|
});
|
|
66
145
|
|
|
67
|
-
return
|
|
68
|
-
install,
|
|
69
|
-
startInstance,
|
|
70
|
-
offer,
|
|
71
|
-
findInvitationAmount,
|
|
72
|
-
installInPieces,
|
|
73
|
-
getBundlerMaker,
|
|
74
|
-
saveIssuer,
|
|
75
|
-
depositInvitation,
|
|
76
|
-
assertOfferResult,
|
|
77
|
-
writeCoreProposal,
|
|
78
|
-
};
|
|
146
|
+
return helpers;
|
|
79
147
|
};
|
package/src/install.js
CHANGED
|
@@ -1,31 +1,72 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
|
|
3
2
|
import './externalTypes.js';
|
|
4
3
|
|
|
5
4
|
import { E } from '@endo/far';
|
|
6
5
|
|
|
6
|
+
/** @typedef {import('@agoric/deploy-script-support/src/externalTypes').Petname} Petname */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @callback BundleSource
|
|
10
|
+
* @param {string} startFilename - the filepath to start the bundling from
|
|
11
|
+
* @param {ModuleFormat | BundleOptions} [moduleFormat]
|
|
12
|
+
* @param {object} [powers]
|
|
13
|
+
* @param {ReadFn} [powers.read]
|
|
14
|
+
* @param {CanonicalFn} [powers.canonical]
|
|
15
|
+
*/
|
|
16
|
+
|
|
7
17
|
// XXX board is Board but specifying that leads to type errors with imports which aren't worth fixing right now
|
|
8
18
|
/**
|
|
9
19
|
* @param {BundleSource} bundleSource
|
|
10
20
|
* @param {ERef<ZoeService>} zoe
|
|
11
21
|
* @param {ERef<import('./startInstance.js').InstallationManager>} installationManager
|
|
12
22
|
* @param {ERef<any>} board
|
|
13
|
-
* @
|
|
23
|
+
* @param {(bundle: any) => any} [publishBundle]
|
|
24
|
+
* @param {(path: string) => string} [pathResolve]
|
|
14
25
|
*/
|
|
15
|
-
export const makeInstall = (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
26
|
+
export const makeInstall = (
|
|
27
|
+
bundleSource,
|
|
28
|
+
zoe,
|
|
29
|
+
installationManager,
|
|
30
|
+
board,
|
|
31
|
+
publishBundle,
|
|
32
|
+
pathResolve,
|
|
33
|
+
) => {
|
|
34
|
+
/**
|
|
35
|
+
* @param {string} contractPath
|
|
36
|
+
* @param {Petname} contractPetname
|
|
37
|
+
* @returns {Promise<{ installation: Installation, id: string}>}
|
|
38
|
+
*/
|
|
39
|
+
const install = async (contractPath, contractPetname) => {
|
|
40
|
+
const resolvedPath = pathResolve ? pathResolve(contractPath) : contractPath;
|
|
19
41
|
|
|
20
42
|
const bundle = await bundleSource(resolvedPath);
|
|
21
|
-
|
|
22
|
-
|
|
43
|
+
console.log(`- Publishing Contract Name: ${contractPetname}`);
|
|
44
|
+
const hashedBundle = await (publishBundle ? publishBundle(bundle) : bundle);
|
|
45
|
+
console.log(`- Installing Contract Name: ${contractPetname}`);
|
|
46
|
+
const installation = await E(zoe).install(hashedBundle);
|
|
47
|
+
console.log(
|
|
48
|
+
`- Adding contract to installation manager: ${contractPetname}`,
|
|
49
|
+
);
|
|
23
50
|
await E(installationManager).add(contractPetname, installation);
|
|
24
51
|
|
|
25
|
-
|
|
26
|
-
|
|
52
|
+
// Let's share this installation with other people, so that
|
|
53
|
+
// they can run our contract code by making a contract
|
|
54
|
+
// instance (see the api deploy script in this repo to see an
|
|
55
|
+
// example of how to use the installation to make a new contract
|
|
56
|
+
// instance.)
|
|
57
|
+
// To share the installation, we're going to put it in the
|
|
58
|
+
// board. The board is a shared, on-chain object that maps
|
|
59
|
+
// strings to objects.
|
|
27
60
|
const id = await E(board).getId(installation);
|
|
28
|
-
|
|
61
|
+
|
|
62
|
+
console.log('- SUCCESS! contract code installed on Zoe');
|
|
63
|
+
console.log(`-- Contract Name: ${contractPetname}`);
|
|
64
|
+
console.log(`-- Installation Board Id: ${id}`);
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
installation,
|
|
68
|
+
id,
|
|
69
|
+
};
|
|
29
70
|
};
|
|
30
71
|
return install;
|
|
31
72
|
};
|
package/src/installInPieces.js
CHANGED
|
@@ -12,9 +12,12 @@ const computeSha512 = bytes => {
|
|
|
12
12
|
|
|
13
13
|
export const installInPieces = async (
|
|
14
14
|
bundle,
|
|
15
|
-
|
|
15
|
+
bundlerOrGetter,
|
|
16
16
|
{ maxBytesInFlight = 800_000, log = console.log, persist = false } = {},
|
|
17
17
|
) => {
|
|
18
|
+
const bundler =
|
|
19
|
+
typeof bundlerOrGetter === 'function' ? bundlerOrGetter() : bundlerOrGetter;
|
|
20
|
+
|
|
18
21
|
// It would be nice to detect evaluation errors early like this:
|
|
19
22
|
// await importBundle(bundle, { endowments });
|
|
20
23
|
// but importBundle only works inside SwingSet; checking here
|
package/src/offer.js
CHANGED
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
|
|
3
2
|
import { E } from '@endo/far';
|
|
4
3
|
import { assert } from '@agoric/assert';
|
|
5
|
-
|
|
4
|
+
// Avoid pulling in too many dependencies like notifiers
|
|
5
|
+
import { AmountMath } from '@agoric/ertp/src/amountMath.js';
|
|
6
|
+
|
|
7
|
+
/** @typedef {import('@agoric/deploy-script-support/src/externalTypes').Petname} Petname */
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {object} OfferHelperConfig
|
|
11
|
+
* @property {ERef<Invitation>} [invitation]
|
|
12
|
+
* @property {Partial<InvitationDetails>} [partialInvitationDetails]
|
|
13
|
+
* @property {Proposal} proposal
|
|
14
|
+
* @property {Record<Keyword, Petname>} paymentsWithPursePetnames
|
|
15
|
+
* @property {Record<Keyword, Petname>} payoutPursePetnames
|
|
16
|
+
*/
|
|
6
17
|
|
|
7
18
|
/**
|
|
8
19
|
* @param {ERef<any>} walletAdmin - an internal type of the
|
|
9
20
|
* wallet, not defined here
|
|
10
21
|
* @param {ERef<ZoeService>} zoe
|
|
11
22
|
* @param {ERef<Purse>} zoeInvitationPurse
|
|
12
|
-
* @returns {{ offer: OfferHelper, findInvitationAmount: FindInvitationAmount }}
|
|
13
23
|
*/
|
|
14
24
|
export const makeOfferAndFindInvitationAmount = (
|
|
15
25
|
walletAdmin,
|
|
16
26
|
zoe,
|
|
17
27
|
zoeInvitationPurse,
|
|
18
28
|
) => {
|
|
19
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* @param {Record<string, any>} invitationDetailsCriteria
|
|
31
|
+
* @returns {Promise<Amount>} invitationAmount
|
|
32
|
+
*/
|
|
20
33
|
const findInvitationAmount = async invitationDetailsCriteria => {
|
|
21
34
|
const invitationAmount = await E(zoeInvitationPurse).getCurrentAmount();
|
|
22
35
|
|
|
@@ -79,16 +92,18 @@ export const makeOfferAndFindInvitationAmount = (
|
|
|
79
92
|
const allDepositedP = Promise.all(
|
|
80
93
|
Object.entries(paymentsP).map(([keyword, paymentP]) => {
|
|
81
94
|
const depositInPurse = makeDepositInPurse(keyword);
|
|
82
|
-
return
|
|
95
|
+
return E.when(paymentP, depositInPurse);
|
|
83
96
|
}),
|
|
84
97
|
);
|
|
85
98
|
return allDepositedP;
|
|
86
99
|
};
|
|
87
100
|
const paymentsPP = E(seat).getPayouts();
|
|
88
|
-
return
|
|
101
|
+
return E.when(paymentsPP, handlePayments);
|
|
89
102
|
};
|
|
90
103
|
|
|
91
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* @param {OfferHelperConfig} config
|
|
106
|
+
*/
|
|
92
107
|
const offer = async config => {
|
|
93
108
|
const {
|
|
94
109
|
invitation,
|
package/src/saveIssuer.js
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
|
|
3
2
|
import { E } from '@endo/far';
|
|
4
3
|
|
|
4
|
+
/** @typedef {import('@agoric/deploy-script-support/src/externalTypes').Petname} Petname */
|
|
5
|
+
|
|
5
6
|
/**
|
|
6
7
|
* @param {ERef<any>} walletAdmin - an internal type of the
|
|
7
8
|
* wallet, not defined here
|
|
8
9
|
* @param {ERef<import('./startInstance').IssuerManager>} issuerManager
|
|
9
|
-
* @returns {SaveIssuerHelper}
|
|
10
10
|
*/
|
|
11
11
|
export const makeSaveIssuer = (walletAdmin, issuerManager) => {
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* @param {ERef<Issuer>} issuerP
|
|
14
|
+
* @param {Petname} brandPetname
|
|
15
|
+
* @param {Petname} pursePetname
|
|
16
|
+
* @returns {Promise<Petname>}
|
|
17
|
+
*/
|
|
13
18
|
const saveIssuer = async (issuerP, brandPetname, pursePetname) => {
|
|
14
19
|
console.log(`-- Installing issuer for: ${brandPetname}`);
|
|
15
20
|
|
package/src/startInstance.js
CHANGED
package/src/writeCoreProposal.js
CHANGED
|
@@ -1,34 +1,29 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import { E } from '@endo/far';
|
|
4
|
+
import { deeplyFulfilled } from '@endo/marshal';
|
|
4
5
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
defangAndTrim,
|
|
8
|
-
mergePermits,
|
|
9
|
-
stringify,
|
|
10
|
-
} from './code-gen.js';
|
|
6
|
+
import { createBundles } from '@agoric/internal/src/node/createBundles.js';
|
|
7
|
+
import { defangAndTrim, mergePermits, stringify } from './code-gen.js';
|
|
11
8
|
import { makeCoreProposalBehavior, permits } from './coreProposalBehavior.js';
|
|
12
|
-
import { createBundles } from './createBundles.js';
|
|
13
9
|
|
|
14
10
|
export const makeWriteCoreProposal = (
|
|
15
11
|
homeP,
|
|
16
12
|
endowments,
|
|
17
13
|
{
|
|
18
14
|
getBundlerMaker,
|
|
19
|
-
|
|
15
|
+
getBundleSpec,
|
|
20
16
|
log = console.log,
|
|
21
17
|
writeFile = fs.promises.writeFile,
|
|
22
18
|
},
|
|
23
19
|
) => {
|
|
24
|
-
const { board, zoe } = E.get(homeP);
|
|
25
20
|
const { bundleSource, pathResolve } = endowments;
|
|
26
21
|
|
|
27
22
|
let bundlerCache;
|
|
28
23
|
const getBundler = () => {
|
|
29
24
|
if (!bundlerCache) {
|
|
30
25
|
bundlerCache = E(getBundlerMaker()).makeBundler({
|
|
31
|
-
zoe,
|
|
26
|
+
zoe: E.get(homeP).zoe,
|
|
32
27
|
});
|
|
33
28
|
}
|
|
34
29
|
return bundlerCache;
|
|
@@ -57,33 +52,37 @@ export const makeWriteCoreProposal = (
|
|
|
57
52
|
|
|
58
53
|
let mutex = Promise.resolve();
|
|
59
54
|
const writeCoreProposal = async (filePrefix, proposalBuilder) => {
|
|
55
|
+
const getBundle = async (entrypoint, bundlePath) => {
|
|
56
|
+
if (!bundlePath) {
|
|
57
|
+
return bundleSource(pathResolve(entrypoint));
|
|
58
|
+
}
|
|
59
|
+
const bundleCache = pathResolve(bundlePath);
|
|
60
|
+
await createBundles([[pathResolve(entrypoint), bundleCache]]);
|
|
61
|
+
const ns = await import(bundleCache);
|
|
62
|
+
return ns.default;
|
|
63
|
+
};
|
|
64
|
+
|
|
60
65
|
// Install an entrypoint.
|
|
61
66
|
const install = async (entrypoint, bundlePath, opts) => {
|
|
62
|
-
const
|
|
63
|
-
let bundle;
|
|
64
|
-
if (bundlePath) {
|
|
65
|
-
const bundleCache = pathResolve(bundlePath);
|
|
66
|
-
await createBundles([[pathResolve(entrypoint), bundleCache]]);
|
|
67
|
-
const ns = await import(bundleCache);
|
|
68
|
-
bundle = ns.default;
|
|
69
|
-
} else {
|
|
70
|
-
bundle = await bundleSource(pathResolve(entrypoint));
|
|
71
|
-
}
|
|
67
|
+
const bundle = getBundle(entrypoint, bundlePath);
|
|
72
68
|
|
|
73
69
|
// Serialise the installations.
|
|
74
|
-
mutex =
|
|
75
|
-
console.log('installing', { filePrefix, entrypoint, bundlePath });
|
|
76
|
-
|
|
77
|
-
return installInPieces(bundle, bundler, opts);
|
|
70
|
+
mutex = E.when(mutex, () => {
|
|
71
|
+
// console.log('installing', { filePrefix, entrypoint, bundlePath });
|
|
72
|
+
return getBundleSpec(bundle, getBundler, opts);
|
|
78
73
|
});
|
|
79
74
|
return mutex;
|
|
80
75
|
};
|
|
81
76
|
|
|
82
77
|
// Await a reference then publish to the board.
|
|
78
|
+
const cmds = [];
|
|
83
79
|
const publishRef = async refP => {
|
|
84
|
-
const ref = await refP;
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
const { fileName, ...ref } = await refP;
|
|
81
|
+
if (fileName) {
|
|
82
|
+
cmds.push(`agd tx swingset install-bundle @${fileName}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return harden(ref);
|
|
87
86
|
};
|
|
88
87
|
|
|
89
88
|
// Create the proposal structure.
|
|
@@ -91,25 +90,26 @@ export const makeWriteCoreProposal = (
|
|
|
91
90
|
harden(proposalBuilder({ publishRef, install })),
|
|
92
91
|
);
|
|
93
92
|
const { sourceSpec, getManifestCall } = proposal;
|
|
94
|
-
console.log('created', { filePrefix, sourceSpec, getManifestCall });
|
|
93
|
+
// console.log('created', { filePrefix, sourceSpec, getManifestCall });
|
|
95
94
|
|
|
96
95
|
// Extract the top-level permit.
|
|
97
96
|
const { permits: proposalPermit, manifest: overrideManifest } =
|
|
98
97
|
await mergeProposalPermit(proposal, permits);
|
|
99
98
|
|
|
100
99
|
// Get an install
|
|
101
|
-
const
|
|
102
|
-
|
|
100
|
+
const manifestBundleRef = await publishRef(install(sourceSpec));
|
|
101
|
+
|
|
102
|
+
// console.log('writing', { filePrefix, manifestBundleRef, sourceSpec });
|
|
103
103
|
const code = `\
|
|
104
104
|
// This is generated by writeCoreProposal; please edit!
|
|
105
105
|
/* eslint-disable */
|
|
106
106
|
|
|
107
|
-
const
|
|
107
|
+
const manifestBundleRef = ${stringify(manifestBundleRef)};
|
|
108
108
|
const getManifestCall = harden(${stringify(getManifestCall, true)});
|
|
109
109
|
const overrideManifest = ${stringify(overrideManifest, true)};
|
|
110
110
|
|
|
111
111
|
// Make the behavior the completion value.
|
|
112
|
-
(${makeCoreProposalBehavior})({
|
|
112
|
+
(${makeCoreProposalBehavior})({ manifestBundleRef, getManifestCall, overrideManifest, E });
|
|
113
113
|
`;
|
|
114
114
|
|
|
115
115
|
const trimmed = defangAndTrim(code);
|
|
@@ -130,6 +130,8 @@ You can now run a governance submission command like:
|
|
|
130
130
|
agd tx gov submit-proposal swingset-core-eval ${proposalPermitJsonFile} ${proposalJsFile} \\
|
|
131
131
|
--title="Enable <something>" --description="Evaluate ${proposalJsFile}" --deposit=1000000ubld \\
|
|
132
132
|
--gas=auto --gas-adjustment=1.2
|
|
133
|
+
Remember to install bundles before submitting the proposal:
|
|
134
|
+
${cmds.join('\n ')}
|
|
133
135
|
`);
|
|
134
136
|
};
|
|
135
137
|
|
package/src/createBundles.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import { spawnSync } from 'child_process';
|
|
3
|
-
import { createRequire } from 'module';
|
|
4
|
-
|
|
5
|
-
const BUNDLE_SOURCE_PROGRAM = 'bundle-source';
|
|
6
|
-
const require = createRequire(import.meta.url);
|
|
7
|
-
|
|
8
|
-
export const createBundlesFromAbsolute = async sourceBundles => {
|
|
9
|
-
const prog = require.resolve(`.bin/${BUNDLE_SOURCE_PROGRAM}`);
|
|
10
|
-
|
|
11
|
-
const cacheToArgs = new Map();
|
|
12
|
-
for (const [srcPath, bundlePath] of sourceBundles) {
|
|
13
|
-
const cache = path.dirname(bundlePath);
|
|
14
|
-
const base = path.basename(bundlePath);
|
|
15
|
-
|
|
16
|
-
const match = base.match(/^bundle-(.*)\.js$/);
|
|
17
|
-
assert(match, `${bundlePath} is not 'DIR/bundle-NAME.js'`);
|
|
18
|
-
const bundle = match[1];
|
|
19
|
-
|
|
20
|
-
const args = cacheToArgs.get(cache) || ['--to', cache];
|
|
21
|
-
args.push(srcPath, bundle);
|
|
22
|
-
cacheToArgs.set(cache, args);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
for (const args of cacheToArgs.values()) {
|
|
26
|
-
console.log(BUNDLE_SOURCE_PROGRAM, ...args);
|
|
27
|
-
const { status } = spawnSync(prog, args, { stdio: 'inherit' });
|
|
28
|
-
assert.equal(
|
|
29
|
-
status,
|
|
30
|
-
0,
|
|
31
|
-
`${BUNDLE_SOURCE_PROGRAM} failed with status ${status}`,
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const createBundles = async (sourceBundles, dirname = '.') => {
|
|
37
|
-
const absBundleSources = sourceBundles.map(([srcPath, bundlePath]) => [
|
|
38
|
-
require.resolve(srcPath, { paths: [dirname] }),
|
|
39
|
-
path.resolve(dirname, bundlePath),
|
|
40
|
-
]);
|
|
41
|
-
return createBundlesFromAbsolute(absBundleSources);
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export const extractProposalBundles = async (
|
|
45
|
-
dirProposalBuilder,
|
|
46
|
-
dirname = '.',
|
|
47
|
-
) => {
|
|
48
|
-
const toBundle = new Map();
|
|
49
|
-
|
|
50
|
-
await Promise.all(
|
|
51
|
-
dirProposalBuilder.map(async ([dir, proposalBuilder]) => {
|
|
52
|
-
const home = path.resolve(dirname, dir);
|
|
53
|
-
const publishRef = x => x;
|
|
54
|
-
const install = async (src, bundleName) => {
|
|
55
|
-
if (bundleName) {
|
|
56
|
-
const bundlePath = path.resolve(home, bundleName);
|
|
57
|
-
const srcPath = require.resolve(src, { paths: [home] });
|
|
58
|
-
if (toBundle.has(bundlePath)) {
|
|
59
|
-
const oldSrc = toBundle.get(bundlePath);
|
|
60
|
-
assert.equal(
|
|
61
|
-
oldSrc,
|
|
62
|
-
srcPath,
|
|
63
|
-
`${bundlePath} already installed as ${oldSrc}, also given ${srcPath}`,
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
toBundle.set(bundlePath, srcPath);
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
return proposalBuilder({ publishRef, install });
|
|
70
|
-
}),
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
return createBundlesFromAbsolute(
|
|
74
|
-
[...toBundle.entries()].map(([bundlePath, srcPath]) => [
|
|
75
|
-
srcPath,
|
|
76
|
-
bundlePath,
|
|
77
|
-
]),
|
|
78
|
-
);
|
|
79
|
-
};
|