From 24b53f291de76624743137383eefdfb510614e34 Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Wed, 6 Mar 2024 20:18:07 -0800 Subject: [PATCH 01/12] refactor: start replacing Far with makeExo --- .../basicFunctionality/bootstrap.js | 26 +- .../basicFunctionality/vat-alice.js | 116 +- .../bootstrap-ertp-service-upgrade.js | 146 +-- .../ertpService/vat-ertp-service.js | 10 +- .../swingsetTests/splitPayments/bootstrap.js | 26 +- .../swingsetTests/splitPayments/vat-alice.js | 67 +- .../test/unitTests/mathHelpers/mockBrand.js | 22 +- .../mathHelpers/test-natMathHelpers.js | 144 ++- .../mathHelpers/test-setMathHelpers.js | 48 +- .../test/unitTests/test-inputValidation.js | 20 +- .../demo/encouragementBot/bootstrap.js | 36 +- .../SwingSet/demo/encouragementBot/vat-bot.js | 18 +- .../demo/encouragementBot/vat-user.js | 24 +- .../demo/encouragementBotComms/bootstrap.js | 98 +- .../demo/encouragementBotComms/vat-bot.js | 18 +- .../demo/encouragementBotComms/vat-user.js | 24 +- packages/SwingSet/docs/devices.md | 2 +- packages/SwingSet/docs/static-vats.md | 2 +- packages/SwingSet/docs/timer.md | 4 +- .../src/controller/initializeKernel.js | 12 +- .../src/devices/bridge/device-bridge.js | 40 +- .../src/devices/command/device-command.js | 42 +- .../SwingSet/src/devices/lib/deviceTools.js | 26 +- .../src/devices/loopbox/device-loopbox.js | 74 +- .../src/devices/mailbox/device-mailbox.js | 64 +- .../src/devices/plugin/device-plugin.js | 26 +- .../src/devices/timer/device-timer.js | 82 +- packages/SwingSet/src/vats/plugin-manager.js | 290 +++-- packages/SwingSet/src/vats/timer/vat-timer.js | 12 +- .../src/vats/vat-admin/vat-vat-admin.js | 28 +- packages/SwingSet/src/vats/vattp/vat-vattp.js | 12 +- .../test/basedir-circular/bootstrap.js | 16 +- .../SwingSet/test/basedir-circular/vat-bob.js | 30 +- .../test/basedir-controller-2/bootstrap.js | 18 +- .../test/basedir-controller-3/bootstrap.js | 14 +- .../test/basedir-controller-3/vat-left.js | 14 +- .../test/basedir-controller-3/vat-right.js | 14 +- .../bootstrap-comms.js | 110 +- .../bootstrap-local.js | 26 +- .../test/basedir-message-patterns/vat-a.js | 36 +- .../test/basedir-message-patterns/vat-b.js | 48 +- .../test/basedir-message-patterns/vat-c.js | 20 +- .../test/basedir-promises-2/bootstrap.js | 60 +- .../test/basedir-promises-2/vat-left.js | 14 +- .../test/basedir-promises-3/bootstrap.js | 30 +- .../test/basedir-promises-3/vat-right.js | 38 +- .../test/basedir-promises/bootstrap.js | 158 +-- .../test/basedir-promises/vat-left.js | 88 +- .../test/basedir-promises/vat-right.js | 14 +- .../test/basedir-transcript/bootstrap.js | 32 +- .../test/basedir-transcript/vat-left.js | 20 +- .../test/basedir-transcript/vat-right.js | 14 +- .../test/bootstrap-syscall-failure.js | 78 +- .../test/bundling/bootstrap-bundles.js | 126 +- packages/SwingSet/test/bundling/vat-disk.js | 12 +- .../SwingSet/test/bundling/vat-install.js | 12 +- packages/SwingSet/test/bundling/vat-named.js | 12 +- .../bootstrap-change-parameters.js | 46 +- .../test/change-parameters/vat-carol.js | 10 +- .../SwingSet/test/definition/vat-liveslots.js | 26 +- .../SwingSet/test/definition/vat-setup.js | 26 +- .../SwingSet/test/device-bridge-bootstrap.js | 38 +- .../device-hooks/bootstrap-device-hook.js | 128 +- .../bootstrap-device-mailbox.js | 110 +- .../SwingSet/test/device-plugin/bootstrap.js | 48 +- .../SwingSet/test/device-plugin/pingpong.js | 26 +- .../SwingSet/test/device-plugin/vat-bridge.js | 46 +- packages/SwingSet/test/devices/bootstrap-2.js | 182 +-- packages/SwingSet/test/devices/bootstrap-3.js | 28 +- packages/SwingSet/test/devices/bootstrap-5.js | 26 +- packages/SwingSet/test/devices/bootstrap-6.js | 36 +- .../SwingSet/test/devices/bootstrap-raw.js | 130 +- packages/SwingSet/test/devices/device-0.js | 6 +- packages/SwingSet/test/devices/device-1.js | 16 +- packages/SwingSet/test/devices/device-2.js | 98 +- packages/SwingSet/test/devices/device-3.js | 20 +- packages/SwingSet/test/devices/device-5.js | 12 +- packages/SwingSet/test/devices/device-6.js | 12 +- packages/SwingSet/test/devices/vat-left.js | 30 +- .../test/files-vattp/bootstrap-test-vattp.js | 64 +- .../SwingSet/test/gc-dead-vat/bootstrap.js | 94 +- .../SwingSet/test/gc-dead-vat/vat-doomed.js | 42 +- .../test/gc-device-transfer/bootstrap-gc.js | 30 +- .../test/gc-device-transfer/device-gc.js | 20 +- .../test/gc-device-transfer/vat-left-gc.js | 12 +- .../test/gc-device-transfer/vat-right-gc.js | 22 +- packages/SwingSet/test/gc/bootstrap.js | 42 +- packages/SwingSet/test/gc/vat-fake-zoe.js | 18 +- packages/SwingSet/test/gc/vat-target.js | 20 +- packages/SwingSet/test/message-patterns.js | 128 +- .../test/metering/metered-dynamic-vat.js | 28 +- .../test/metering/vat-load-dynamic.js | 132 +- .../bootstrap-promise-watcher.js | 106 +- .../test/promise-watcher/vat-upton.js | 96 +- .../test/reap-all/bootstrap-reap-all.js | 32 +- packages/SwingSet/test/reap-all/vat-dumbo.js | 12 +- .../test/run-policy/vat-policy-left.js | 30 +- .../test/run-policy/vat-policy-right.js | 44 +- packages/SwingSet/test/test-marshal.js | 24 +- packages/SwingSet/test/test-timer-device.js | 56 +- packages/SwingSet/test/test-vat-timer.js | 280 +++-- .../SwingSet/test/timer-device/bootstrap.js | 75 +- .../SwingSet/test/timer/bootstrap-timer.js | 116 +- .../transcript/vat-bootstrap-transcript.js | 30 +- .../upgrade/bootstrap-scripted-upgrade.js | 482 ++++---- .../test/upgrade/bootstrap-upgrade-replay.js | 56 +- packages/SwingSet/test/upgrade/vat-ulrik-1.js | 92 +- packages/SwingSet/test/upgrade/vat-ulrik-2.js | 58 +- .../SwingSet/test/upgrade/vat-upton-replay.js | 30 +- .../SwingSet/test/vat-activityhash-comms.js | 36 +- packages/SwingSet/test/vat-admin/bootstrap.js | 140 ++- .../SwingSet/test/vat-admin/new-vat-13.js | 50 +- .../SwingSet/test/vat-admin/new-vat-44.js | 12 +- .../test/vat-admin/new-vat-refcount.js | 10 +- .../test/vat-admin/replay-bootstrap.js | 60 +- .../SwingSet/test/vat-admin/replay-dynamic.js | 22 +- .../terminate/bootstrap-badVatKey.js | 20 +- .../terminate/bootstrap-die-cleanly.js | 34 +- .../terminate/bootstrap-die-with-presence.js | 44 +- .../terminate/bootstrap-no-zombies.js | 36 +- .../terminate/bootstrap-speak-to-dead.js | 100 +- .../bootstrap-terminate-with-presence.js | 62 +- .../terminate/bootstrap-terminate.js | 360 +++--- .../vat-admin/terminate/vat-dude-terminate.js | 82 +- .../terminate/vat-medium-terminate.js | 20 +- .../terminate/vat-weatherwax-terminate.js | 34 +- .../test/vat-admin/vat-export-held.js | 15 +- .../test/vat-durable-promise-watcher.js | 32 +- packages/SwingSet/test/vat-envtest.js | 22 +- packages/SwingSet/test/vat-exomessages.js | 30 +- packages/SwingSet/test/vat-exporter.js | 18 +- .../bootstrap-vat-timer-upgrade.js | 160 +-- .../SwingSet/test/vat-warehouse/bootstrap.js | 12 +- .../vat-warehouse/vat-preload-bootstrap.js | 48 +- .../test/vat-warehouse/vat-preload-extra.js | 10 +- .../SwingSet/test/vat-warehouse/vat-target.js | 10 +- .../vat-warehouse/vat-warehouse-reload.js | 14 +- packages/SwingSet/test/vat-xsnap-hang.js | 14 +- .../bootstrap-collection-slots.js | 38 +- .../collection-slots/vat-collection-slots.js | 32 +- .../bootstrap-delete-stored-vo.js | 32 +- .../delete-stored-vo/vat-delete-stored-vo.js | 38 +- .../double-retire-import/bootstrap-dri.js | 36 +- .../double-retire-import/vat-dri.js | 18 +- .../test/virtualObjects/vat-orphan-bob.js | 64 +- .../virtualObjects/vat-orphan-bootstrap.js | 24 +- .../virtualObjects/vat-representatives.js | 74 +- .../test/virtualObjects/vat-vom-gc-bob.js | 72 +- .../virtualObjects/vat-vom-gc-bootstrap.js | 42 +- .../vat-weakcollections-alice.js | 82 +- .../vat-weakcollections-bootstrap.js | 56 +- .../bootstrap-vdata-promises.js | 96 +- .../vdata-promises/vat-vdata-promises.js | 326 ++--- .../test/vo-test-harness/vat-dvo-test-test.js | 32 +- .../SwingSet/test/workers/bootstrap-node.js | 12 +- packages/SwingSet/test/workers/bootstrap.js | 56 +- packages/SwingSet/test/workers/device-add.js | 12 +- packages/SwingSet/test/workers/vat-target.js | 14 +- .../xsnap-snapshots/bootstrap-snapshots.js | 16 +- .../test/xsnap-stable-bundles/vat-stable.js | 32 +- .../bootstrap-zcf-ish-upgrade.js | 64 +- .../test/zcf-ish-upgrade/pseudo-zcf.js | 6 +- packages/SwingSet/tools/bootstrap-dvo-test.js | 56 +- packages/SwingSet/tools/bootstrap-relay.js | 155 +-- packages/SwingSet/tools/manual-timer.js | 14 +- packages/agoric-cli/src/follow.js | 22 +- .../agoric-cli/tools/resm-plugin/package.json | 4 +- .../tools/resm-plugin/src/plugin.js | 29 +- packages/base-zone/src/heap.js | 54 +- .../bootstrapTests/test-vaults-upgrade.ts | 6 +- packages/boot/test/upgrading/bootstrap.js | 2 +- packages/boot/test/upgrading/device-bridge.js | 42 +- packages/boot/test/upgrading/vat-mint.js | 10 +- packages/boot/test/upgrading/vat-vow.js | 44 +- packages/cache/src/cache.js | 12 +- packages/cache/src/store.js | 112 +- packages/cache/test/test-storage.js | 18 +- packages/casting/src/change-follower.js | 94 +- packages/casting/src/defaults.js | 24 +- packages/casting/src/follower-cosmjs.js | 24 +- packages/casting/src/follower.js | 64 +- packages/casting/src/iterable.js | 90 +- packages/casting/src/leader.js | 106 +- .../src/endo-pieces-contract.js | 114 +- packages/governance/src/closingRule.js | 10 +- .../src/contractGovernance/governApi.js | 12 +- .../src/contractGovernance/governFilter.js | 12 +- .../src/contractGovernance/governParam.js | 12 +- .../src/contractGovernance/paramManager.js | 54 +- packages/governance/src/contractHelper.js | 78 +- packages/governance/src/electorateTools.js | 2 +- packages/governance/src/quorumCounter.js | 6 +- .../committeeBinary/bootstrap.js | 6 +- .../committeeBinary/vat-voter.js | 122 +- .../contractGovernor/bootstrap.js | 46 +- .../contractGovernor/vat-voter.js | 168 +-- .../test/unitTests/test-binaryballotCount.js | 6 +- .../test/unitTests/test-buildParamManager.js | 20 +- .../test/unitTests/test-typedParamManager.js | 20 +- .../tools/puppetContractGovernor.js | 36 +- .../inter-protocol/src/auction/auctioneer.js | 132 +- .../inter-protocol/src/auction/scheduler.js | 70 +- packages/inter-protocol/src/auction/util.js | 2 +- packages/inter-protocol/src/feeDistributor.js | 242 ++-- .../src/price/fluxAggregatorKit.js | 32 +- .../src/proposals/addAssetToVault.js | 6 +- .../inter-protocol/src/provisionPoolKit.js | 46 +- .../src/vaultFactory/prioritizedVaults.js | 30 +- .../src/vaultFactory/vaultDirector.js | 176 +-- packages/inter-protocol/test/auction/tools.js | 36 +- .../test/price/test-fluxAggregatorKit.js | 6 +- packages/inter-protocol/test/psm/setupPsm.js | 12 +- .../test/psm/test-governedPsm.js | 6 +- packages/inter-protocol/test/psm/test-psm.js | 34 +- .../test/smartWallet/boot-psm.js | 80 +- .../test/smartWallet/boot-test-utils.js | 68 +- ...ootstrap-fluxAggregator-service-upgrade.js | 350 +++--- .../psmUpgrade/bootstrap-psm-upgrade.js | 431 +++---- .../reserve/bootstrap-assetReserve-upgrade.js | 335 +++--- .../test/test-feeDistributor.js | 22 +- .../test/test-interest-labeled.js | 14 +- .../inter-protocol/test/test-provisionPool.js | 62 +- .../test/vaultFactory/faucet.js | 6 +- .../test/vaultFactory/interestSupport.js | 34 +- .../vaultFactory/vault-contract-wrapper.js | 140 ++- packages/internal/src/marshal.js | 2 +- packages/internal/src/priority-senders.js | 84 +- packages/internal/src/scratch.js | 80 +- packages/internal/src/storage-test-utils.js | 51 +- packages/internal/test/test-callback.js | 78 +- .../internal/test/test-storage-test-utils.js | 18 +- packages/internal/test/test-utils.js | 6 +- packages/notifier/src/notifier.js | 174 +-- packages/notifier/src/publish-kit.js | 84 +- packages/notifier/src/stored-notifier.js | 26 +- packages/notifier/src/storesub.js | 74 +- packages/notifier/src/subscribe.js | 192 +-- packages/notifier/src/subscriber.js | 43 +- packages/notifier/src/topic.js | 26 +- .../test/vat-integration/vat-pubsub.js | 26 +- packages/notifier/tools/testSupports.js | 28 +- packages/pegasus/src/courier.js | 6 +- packages/pegasus/src/ics20.js | 16 +- packages/pegasus/src/pegasus.js | 690 +++++------ .../pegasus/src/proposals/core-proposal.js | 18 +- packages/pegasus/test/test-peg.js | 126 +- packages/smart-wallet/src/marshal-contexts.js | 12 +- .../smart-wallet/test/gameAssetContract.js | 12 +- packages/smart-wallet/test/supports.js | 58 +- ...bootstrap-walletFactory-service-upgrade.js | 309 ++--- packages/smart-wallet/test/test-addAsset.js | 50 +- .../test/test-marshal-contexts.js | 47 +- packages/solo/src/captp.js | 146 +-- packages/solo/src/vat-http.js | 260 ++-- packages/solo/src/vat-spawner.js | 12 +- packages/solo/src/vat-uploads.js | 6 +- packages/solo/test/test-home.js | 32 +- packages/spawner/README.md | 4 +- packages/spawner/src/contractHost.js | 35 +- packages/spawner/src/vat-spawned.js | 30 +- .../swingsetTests/contractHost/bootstrap.js | 46 +- .../swingsetTests/contractHost/trivial.js | 44 +- .../swingsetTests/contractHost/vat-spawner.js | 12 +- packages/store/src/stores/scalarMapStore.js | 2 +- packages/store/src/stores/scalarSetStore.js | 2 +- .../store/src/stores/scalarWeakMapStore.js | 2 +- .../store/src/stores/scalarWeakSetStore.js | 2 +- packages/store/src/stores/store-utils.js | 57 +- packages/store/test/perf-patterns.js | 12 +- packages/store/test/test-AtomicProvider.js | 2 +- packages/store/test/test-store.js | 16 +- packages/swingset-liveslots/docs/liveslots.md | 4 +- .../src/virtualObjectManager.js | 12 +- .../swingset-liveslots/test/gc-helpers.js | 152 +-- .../swingset-liveslots/test/test-baggage.js | 14 +- .../test/test-collection-schema-refcount.js | 12 +- .../test/test-collection-upgrade.js | 12 +- .../test/test-dropped-collection-weakrefs.js | 6 +- .../test/test-durabilityChecks.js | 12 +- .../test/test-gc-sensitivity.js | 102 +- .../test/test-handled-promises.js | 40 +- .../test/test-initial-vrefs.js | 20 +- .../test/test-liveslots-mock-gc.js | 54 +- .../test/test-liveslots-real-gc.js | 158 ++- .../swingset-liveslots/test/test-liveslots.js | 570 +++++---- .../test/test-vpid-liveslots.js | 298 ++--- .../test/virtual-objects/test-kind-changes.js | 22 +- .../test/virtual-objects/test-state-shape.js | 50 +- .../virtual-objects/test-virtualObjectGC.js | 184 +-- .../test/virtual-objects/test-vo-real-gc.js | 24 +- .../tools/vo-test-harness.js | 54 +- .../demo/encouragementBot/bootstrap.js | 36 +- .../demo/encouragementBot/vat-bot.js | 14 +- .../demo/encouragementBot/vat-user.js | 24 +- .../demo/encouragementBotComms/bootstrap.js | 106 +- .../demo/encouragementBotComms/vat-bot.js | 14 +- .../demo/encouragementBotComms/vat-user.js | 24 +- .../demo/exchangeBenchmark/bootstrap.js | 138 ++- .../demo/exchangeBenchmark/exchanger.js | 24 +- .../demo/justReply/bootstrap.js | 24 +- .../demo/justReply/vat-alice.js | 24 +- .../swingset-runner/demo/justReply/vat-bob.js | 14 +- .../demo/megaPong/bootstrap.js | 34 +- .../demo/megaPong/vat-alice.js | 78 +- .../swingset-runner/demo/megaPong/vat-bob.js | 64 +- .../demo/meterExhaustion/bootstrap.js | 52 +- .../demo/meterExhaustion/vat-boomer.js | 14 +- .../demo/pingPongBenchmark/bootstrap.js | 38 +- .../demo/pingPongBenchmark/vat-alice.js | 52 +- .../demo/pingPongBenchmark/vat-bob.js | 38 +- .../demo/promiseChainBenchmark/bootstrap.js | 22 +- .../demo/promiseChainBenchmark/vat-bob.js | 34 +- .../demo/resolveCase1/bootstrap.js | 38 +- .../demo/resolveCase1/vat-bob.js | 24 +- .../demo/resolveCase2/bootstrap.js | 36 +- .../demo/resolveCase2/vat-bob.js | 24 +- .../demo/resolveCase3/bootstrap.js | 32 +- .../demo/resolveCase3/vat-bob.js | 24 +- .../demo/resolveChain/bootstrap.js | 20 +- .../demo/resolveChain/vat-bob.js | 34 +- .../demo/resolveCircular/bootstrap.js | 16 +- .../demo/resolveCircular/vat-bob.js | 30 +- .../demo/resolveCircular2/bootstrap.js | 18 +- .../demo/resolveCircular2/vat-bob.js | 36 +- .../demo/resolveCircular3/bootstrap.js | 18 +- .../demo/resolveCircular3/vat-alice.js | 12 +- .../demo/resolveCircular3/vat-bob.js | 30 +- .../resolveCircularMultiCrank/bootstrap.js | 18 +- .../demo/resolveCircularMultiCrank/vat-bob.js | 34 +- .../demo/resolveCrosswise/bootstrap.js | 18 +- .../demo/resolveCrosswise/vat-body.js | 20 +- .../demo/resolveDelayedPipeline/bootstrap.js | 48 +- .../demo/resolveDelayedPipeline/vat-bob.js | 28 +- .../demo/resolveInArrayCase1/bootstrap.js | 38 +- .../demo/resolveInArrayCase1/vat-bob.js | 26 +- .../demo/resolveIndirect/bootstrap.js | 16 +- .../demo/resolveIndirect/vat-bob.js | 26 +- .../demo/resolveMutualCircular/bootstrap.js | 18 +- .../demo/resolveMutualCircular/vat-bob.js | 24 +- .../demo/resolvePassResult/bootstrap.js | 42 +- .../demo/resolvePassResult/vat-bob.js | 32 +- .../resolvePassResultPromise/bootstrap.js | 42 +- .../demo/resolvePassResultPromise/vat-bob.js | 40 +- .../demo/resolvePipelined/bootstrap.js | 42 +- .../demo/resolvePipelined/vat-bob.js | 28 +- .../resolvePromiseComplicated/bootstrap.js | 42 +- .../demo/resolvePromiseComplicated/vat-bob.js | 48 +- .../resolvePromiseComplicated/vat-carol.js | 42 +- .../demo/resolveSimpleCircular/bootstrap.js | 14 +- .../demo/resolveSimpleCircular/vat-bob.js | 20 +- .../demo/resolveSimpleCircular2/bootstrap.js | 16 +- .../demo/resolveSimpleCircular2/vat-bob.js | 26 +- .../resolveWithEmbeddedPromise/bootstrap.js | 62 +- .../resolveWithEmbeddedPromise/vat-bob.js | 52 +- .../demo/simplePromisePass/bootstrap.js | 18 +- .../demo/simplePromisePass/vat-alice.js | 38 +- .../demo/simplePromisePass/vat-bob.js | 24 +- .../demo/swapBenchmark/bootstrap.js | 64 +- .../demo/swapBenchmark/exchanger.js | 24 +- .../demo/terminateVat/bootstrap.js | 124 +- .../demo/terminateVat/vat-dude.js | 42 +- .../demo/vatFailure/bootstrap.js | 92 +- .../demo/vatResolveTest/bootstrap.js | 84 +- .../demo/vatResolveTest/vat-bob.js | 66 +- .../demo/vatResolveTestSimple/bootstrap.js | 36 +- .../demo/vatResolveTestSimple/vat-bob.js | 48 +- .../demo/vatStore1/bootstrap.js | 16 +- .../swingset-runner/demo/vatStore1/vat-bob.js | 102 +- .../demo/vatStore2/bootstrap.js | 100 +- .../demo/vatStore2/thingHolder.js | 46 +- .../demo/vatStore3/bootstrap.js | 42 +- .../swingset-runner/demo/vatStore3/vat-bob.js | 70 +- .../demo/vaultPerfTest/vat-benchmark.js | 156 +-- .../demo/virtualObjectGC/bootstrap.js | 386 +++--- .../demo/virtualObjectGC/vat-bob.js | 68 +- .../demo/workerDeathTest/bootstrap.js | 18 +- .../demo/workerDeathTest/vat-busy.js | 30 +- .../demo/workerDeathTest/vat-idle.js | 10 +- .../demo/zoeTests/bootstrap.js | 104 +- .../demo/zoeTests/vat-alice.js | 100 +- .../swingset-runner/demo/zoeTests/vat-bob.js | 1016 ++++++++-------- .../demo/zoeTests/vat-carol.js | 104 +- .../swingset-runner/demo/zoeTests/vat-dave.js | 311 ++--- .../src/vat-benchmarkBootstrap.js | 45 +- packages/swingset-runner/src/vat-launcher.js | 66 +- packages/vat-data/test/test-vow.js | 10 +- packages/vats/src/centralSupply.js | 14 +- packages/vats/src/core/chain-behaviors.js | 270 +++-- packages/vats/src/core/client-behaviors.js | 62 +- packages/vats/src/core/demoIssuers.js | 24 +- packages/vats/src/core/lib-boot.js | 96 +- packages/vats/src/core/sim-behaviors.js | 6 +- packages/vats/src/core/startWalletFactory.js | 20 +- packages/vats/src/core/utils.js | 12 +- packages/vats/src/lib-board.js | 2 +- packages/vats/src/priceAuthorityRegistry.js | 19 +- packages/vats/src/repl.js | 44 +- packages/vats/src/vat-agoricNames.js | 34 +- packages/vats/src/vat-bank.js | 100 +- packages/vats/src/vat-board.js | 14 +- packages/vats/src/vat-bridge.js | 12 +- packages/vats/src/vat-ibc.js | 12 +- packages/vats/src/vat-localchain.js | 24 +- packages/vats/src/vat-mints.js | 138 +-- packages/vats/src/vat-network.js | 28 +- packages/vats/src/vat-priceAuthority.js | 6 +- packages/vats/src/vat-provisioning.js | 50 +- packages/vats/src/vat-zoe.js | 60 +- packages/vats/test/test-board-utils.js | 27 +- packages/vats/test/test-clientBundle.js | 38 +- packages/vats/test/test-lib-board.js | 24 +- packages/vats/test/test-name-hub.js | 6 +- packages/vats/tools/bank-utils.js | 14 +- packages/vats/tools/boot-test-utils.js | 79 +- packages/wallet/api/src/actions.js | 222 ++-- packages/wallet/api/src/lib-wallet.js | 492 ++++---- packages/wallet/api/src/wallet.js | 806 +++++++------ .../api/test/continuingInvitationExample.js | 10 +- .../wallet/api/test/test-lib-dehydrate.js | 18 +- packages/wallet/api/test/test-middleware.js | 10 +- packages/zoe/src/contractFacet/vatRoot.js | 42 +- .../zoe/src/contractSupport/priceAuthority.js | 273 +++-- .../contractSupport/priceAuthorityInitial.js | 28 +- .../priceAuthorityTransform.js | 186 +-- packages/zoe/src/contracts/auction/index.js | 32 +- packages/zoe/src/contracts/automaticRefund.js | 12 +- packages/zoe/src/contracts/autoswap.js | 28 +- packages/zoe/src/contracts/barterExchange.js | 11 +- .../contracts/callSpread/pricedCallSpread.js | 6 +- packages/zoe/src/contracts/loan/borrow.js | 26 +- packages/zoe/src/contracts/loan/updateDebt.js | 80 +- packages/zoe/src/contracts/mintAndSellNFT.js | 12 +- packages/zoe/src/contracts/mintPayments.js | 32 +- packages/zoe/src/contracts/oracle.js | 128 +- packages/zoe/src/contracts/otcDesk.js | 50 +- packages/zoe/src/contracts/priceAggregator.js | 420 ++++--- packages/zoe/src/contracts/sellItems.js | 30 +- packages/zoe/src/contracts/simpleExchange.js | 12 +- packages/zoe/test/privateArgsUsageContract.js | 10 +- packages/zoe/test/runMintContract.js | 18 +- .../brokenContracts/bootstrap.js | 57 +- .../brokenContracts/crashingAutoRefund.js | 32 +- .../brokenContracts/vat-alice.js | 70 +- .../test/swingsetTests/makeKind/bootstrap.js | 46 +- .../test/swingsetTests/makeKind/vat-alice.js | 26 +- .../test/swingsetTests/offerArgs/bootstrap.js | 46 +- .../test/swingsetTests/offerArgs/vat-alice.js | 48 +- .../swingsetTests/privateArgs/bootstrap.js | 46 +- .../swingsetTests/privateArgs/vat-alice.js | 50 +- .../test/swingsetTests/runMint/bootstrap.js | 50 +- .../test/swingsetTests/runMint/vat-alice.js | 96 +- .../bootstrap-coveredCall-service-upgrade.js | 259 ++-- .../upgradeCoveredCall/vat-ertp-service.js | 18 +- .../zoe/test/swingsetTests/zoe/bootstrap.js | 66 +- .../zoe/test/swingsetTests/zoe/vat-alice.js | 100 +- .../zoe/test/swingsetTests/zoe/vat-bob.js | 1063 +++++++++-------- .../zoe/test/swingsetTests/zoe/vat-carol.js | 110 +- .../zoe/test/swingsetTests/zoe/vat-dave.js | 321 ++--- packages/zoe/test/unitTests/bounty.js | 22 +- .../contractSupport/test-zoeHelpers.js | 74 +- .../test/unitTests/contracts/escrowToVote.js | 94 +- .../unitTests/contracts/test-atomicSwap.js | 254 ++-- .../test/unitTests/contracts/test-auction.js | 396 +++--- .../unitTests/contracts/test-coveredCall.js | 152 +-- .../test/unitTests/contracts/test-oracle.js | 40 +- .../test/unitTests/contracts/test-otcDesk.js | 2 +- .../contracts/test-priceAggregator.js | 54 +- .../contracts/throwInOfferHandler.js | 12 +- .../test/unitTests/contracts/useObjExample.js | 70 +- .../test/unitTests/test-instanceStorage.js | 12 +- .../zoe/test/unitTests/test-manualTimer.js | 82 +- .../test/unitTests/test-zoe-startInstance.js | 28 +- .../unitTests/zcf/registerFeeMintContract.js | 16 +- packages/zoe/test/unitTests/zcf/test-zcf.js | 28 +- .../test/unitTests/zcf/zcfTesterContract.js | 10 +- .../test/unitTests/zoe/test-burnInvitation.js | 42 +- .../zoe/test-instanceAdminStorage.js | 72 +- packages/zoe/tools/fakePriceAuthority.js | 194 +-- packages/zoe/tools/fakeVatAdmin.js | 140 ++- packages/zoe/tools/manualPriceAuthority.js | 26 +- packages/zoe/tools/manualTimer.js | 16 +- packages/zoe/tools/scriptedOracle.js | 32 +- packages/zoe/tools/scriptedPriceAuthority.js | 18 +- packages/zone/README.md | 2 +- packages/zone/src/durable.js | 56 +- packages/zone/src/virtual.js | 50 +- 486 files changed, 17849 insertions(+), 14161 deletions(-) diff --git a/packages/ERTP/test/swingsetTests/basicFunctionality/bootstrap.js b/packages/ERTP/test/swingsetTests/basicFunctionality/bootstrap.js index 1e70311929d..ce1e3e84d78 100644 --- a/packages/ERTP/test/swingsetTests/basicFunctionality/bootstrap.js +++ b/packages/ERTP/test/swingsetTests/basicFunctionality/bootstrap.js @@ -15,18 +15,22 @@ export function buildRootObject(vatPowers, vatParameters) { return E(aliceP).testBasicFunctionality(); } - const obj0 = Far('root', { - async bootstrap(vats) { - switch (arg0) { - case 'basicFunctionality': { - const aliceMaker = await E(vats.alice).makeAliceMaker(); - return testBasicFunctionality(aliceMaker); + const obj0 = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + switch (arg0) { + case 'basicFunctionality': { + const aliceMaker = await E(vats.alice).makeAliceMaker(); + return testBasicFunctionality(aliceMaker); + } + default: { + assert.fail(X`unrecognized argument value ${arg0}`); + } } - default: { - assert.fail(X`unrecognized argument value ${arg0}`); - } - } + }, }, - }); + ); return obj0; } diff --git a/packages/ERTP/test/swingsetTests/basicFunctionality/vat-alice.js b/packages/ERTP/test/swingsetTests/basicFunctionality/vat-alice.js index e95bf9a9b89..de7bc416e78 100644 --- a/packages/ERTP/test/swingsetTests/basicFunctionality/vat-alice.js +++ b/packages/ERTP/test/swingsetTests/basicFunctionality/vat-alice.js @@ -8,69 +8,85 @@ import { } from '../../../src/legacy-payment-helpers.js'; function makeAliceMaker(log) { - return Far('aliceMaker', { - make(issuer, brand, oldPaymentP) { - const alice = Far('alice', { - async testBasicFunctionality() { - // isLive - const alive = await E(issuer).isLive(oldPaymentP); - log('isLive: ', alive); + return makeExo( + 'aliceMaker', + M.interface('aliceMaker', {}, { defaultGuards: 'passable' }), + { + make(issuer, brand, oldPaymentP) { + const alice = makeExo( + 'alice', + M.interface('alice', {}, { defaultGuards: 'passable' }), + { + async testBasicFunctionality() { + // isLive + const alive = await E(issuer).isLive(oldPaymentP); + log('isLive: ', alive); - // getAmountOf - const amount = await E(issuer).getAmountOf(oldPaymentP); - log('getAmountOf: ', amount); + // getAmountOf + const amount = await E(issuer).getAmountOf(oldPaymentP); + log('getAmountOf: ', amount); - // Make Purse + // Make Purse - const purse = E(issuer).makeEmptyPurse(); + const purse = E(issuer).makeEmptyPurse(); - // Deposit Payment + // Deposit Payment - const payment = await oldPaymentP; - await E(purse).deposit(payment); + const payment = await oldPaymentP; + await E(purse).deposit(payment); - // Withdraw Payment - const newPayment = E(purse).withdraw(amount); - const newAmount = await E(issuer).getAmountOf(newPayment); - log('newPayment amount: ', newAmount); + // Withdraw Payment + const newPayment = E(purse).withdraw(amount); + const newAmount = await E(issuer).getAmountOf(newPayment); + log('newPayment amount: ', newAmount); - // splitMany - const moola200 = AmountMath.make(brand, 200n); - const [paymentToBurn, paymentToClaim, ...payments] = await splitMany( - E(issuer).makeEmptyPurse(), - newPayment, - harden([moola200, moola200, moola200, moola200, moola200]), - ); + // splitMany + const moola200 = AmountMath.make(brand, 200n); + const [paymentToBurn, paymentToClaim, ...payments] = + await splitMany( + E(issuer).makeEmptyPurse(), + newPayment, + harden([moola200, moola200, moola200, moola200, moola200]), + ); - // burn - const burnedAmount = await E(issuer).burn(paymentToBurn); - log('burned amount: ', burnedAmount); + // burn + const burnedAmount = await E(issuer).burn(paymentToBurn); + log('burned amount: ', burnedAmount); - // claim - const claimedPayment = await claim( - E(issuer).makeEmptyPurse(), - paymentToClaim, - ); - const claimedPaymentAmount = - await E(issuer).getAmountOf(claimedPayment); - log('claimedPayment amount: ', claimedPaymentAmount); + // claim + const claimedPayment = await claim( + E(issuer).makeEmptyPurse(), + paymentToClaim, + ); + const claimedPaymentAmount = + await E(issuer).getAmountOf(claimedPayment); + log('claimedPayment amount: ', claimedPaymentAmount); - // combine - const combinedPayment = combine(E(issuer).makeEmptyPurse(), payments); - const combinedPaymentAmount = - await E(issuer).getAmountOf(combinedPayment); - log('combinedPayment amount: ', combinedPaymentAmount); - }, - }); - return alice; + // combine + const combinedPayment = combine( + E(issuer).makeEmptyPurse(), + payments, + ); + const combinedPaymentAmount = + await E(issuer).getAmountOf(combinedPayment); + log('combinedPayment amount: ', combinedPaymentAmount); + }, + }, + ); + return alice; + }, }, - }); + ); } export function buildRootObject(vatPowers) { - return Far('root', { - makeAliceMaker() { - return harden(makeAliceMaker(vatPowers.testLog)); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + makeAliceMaker() { + return harden(makeAliceMaker(vatPowers.testLog)); + }, }, - }); + ); } diff --git a/packages/ERTP/test/swingsetTests/ertpService/bootstrap-ertp-service-upgrade.js b/packages/ERTP/test/swingsetTests/ertpService/bootstrap-ertp-service-upgrade.js index d5d14f0e01e..230ca3c6c29 100644 --- a/packages/ERTP/test/swingsetTests/ertpService/bootstrap-ertp-service-upgrade.js +++ b/packages/ERTP/test/swingsetTests/ertpService/bootstrap-ertp-service-upgrade.js @@ -19,84 +19,92 @@ export const buildRootObject = () => { let purseB2; let paymentForBP; - return Far('root', { - bootstrap: async (vats, devices) => { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap: async (vats, devices) => { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + }, - buildV1: async () => { - // build the contract vat from ZCF and the contract bundlecap - const bcap = await E(vatAdmin).getNamedBundleCap('ertpService'); - const res = await E(vatAdmin).createVat(bcap); - ertpRoot = res.root; - ertpAdmin = res.adminNode; - const ertpService = await E(ertpRoot).getErtpService(); + buildV1: async () => { + // build the contract vat from ZCF and the contract bundlecap + const bcap = await E(vatAdmin).getNamedBundleCap('ertpService'); + const res = await E(vatAdmin).createVat(bcap); + ertpRoot = res.root; + ertpAdmin = res.adminNode; + const ertpService = await E(ertpRoot).getErtpService(); - issuerKitA = await E(ertpService).makeIssuerKit('A'); - issuerKitB = await E(ertpService).makeIssuerKit('B'); + issuerKitA = await E(ertpService).makeIssuerKit('A'); + issuerKitB = await E(ertpService).makeIssuerKit('B'); - // make purses with non-zero balances - purseA1 = E(issuerKitA.issuer).makeEmptyPurse(); - purseA2 = E(issuerKitA.issuer).makeEmptyPurse(); - purseB1 = E(issuerKitB.issuer).makeEmptyPurse(); - purseB2 = E(issuerKitB.issuer).makeEmptyPurse(); - await Promise.all([ - mintInto(issuerKitA, purseA1, 20n), - mintInto(issuerKitA, purseA2, 40n), - mintInto(issuerKitB, purseB1, 12n), - mintInto(issuerKitB, purseB2, 16n), - ]); + // make purses with non-zero balances + purseA1 = E(issuerKitA.issuer).makeEmptyPurse(); + purseA2 = E(issuerKitA.issuer).makeEmptyPurse(); + purseB1 = E(issuerKitB.issuer).makeEmptyPurse(); + purseB2 = E(issuerKitB.issuer).makeEmptyPurse(); + await Promise.all([ + mintInto(issuerKitA, purseA1, 20n), + mintInto(issuerKitA, purseA2, 40n), + mintInto(issuerKitB, purseB1, 12n), + mintInto(issuerKitB, purseB2, 16n), + ]); - // hold onto a payment here. - paymentForBP = E(issuerKitB.mint).mintPayment( - AmountMath.make(issuerKitB.brand, 100n), - ); + // hold onto a payment here. + paymentForBP = E(issuerKitB.mint).mintPayment( + AmountMath.make(issuerKitB.brand, 100n), + ); - const purseA2Amount = await E(purseA2).getCurrentAmount(); - assert( - AmountMath.isEqual( - purseA2Amount, - AmountMath.make(issuerKitA.brand, 40n), - ), - ); - return true; - }, + const purseA2Amount = await E(purseA2).getCurrentAmount(); + assert( + AmountMath.isEqual( + purseA2Amount, + AmountMath.make(issuerKitA.brand, 40n), + ), + ); + return true; + }, - upgradeV2: async () => { - const bcap = await E(vatAdmin).getNamedBundleCap('ertpService'); - await E(ertpAdmin).upgrade(bcap); + upgradeV2: async () => { + const bcap = await E(vatAdmin).getNamedBundleCap('ertpService'); + await E(ertpAdmin).upgrade(bcap); - // exercise purses - const purseA2Balance = await E(purseA2).getCurrentAmount(); - assert( - AmountMath.isEqual( - purseA2Balance, - AmountMath.make(issuerKitA.brand, 40n), - ), - ); - const paymentA0 = await E(purseA2).withdraw( - AmountMath.make(issuerKitA.brand, 5n), - ); - const payment0Amount = await E(issuerKitA.issuer).getAmountOf(paymentA0); - assert( - AmountMath.isEqual( - payment0Amount, + // exercise purses + const purseA2Balance = await E(purseA2).getCurrentAmount(); + assert( + AmountMath.isEqual( + purseA2Balance, + AmountMath.make(issuerKitA.brand, 40n), + ), + ); + const paymentA0 = await E(purseA2).withdraw( AmountMath.make(issuerKitA.brand, 5n), - ), - ); + ); + const payment0Amount = await E(issuerKitA.issuer).getAmountOf( + paymentA0, + ); + assert( + AmountMath.isEqual( + payment0Amount, + AmountMath.make(issuerKitA.brand, 5n), + ), + ); - const paymentForB = await paymentForBP; - // deposit a payment from earlier - await E(purseB1).deposit(paymentForB); - const purseB1NewAmount = await E(purseB1).getCurrentAmount(); - assert( - AmountMath.isEqual( - purseB1NewAmount, - AmountMath.make(issuerKitB.brand, 112n), - ), - ); + const paymentForB = await paymentForBP; + // deposit a payment from earlier + await E(purseB1).deposit(paymentForB); + const purseB1NewAmount = await E(purseB1).getCurrentAmount(); + assert( + AmountMath.isEqual( + purseB1NewAmount, + AmountMath.make(issuerKitB.brand, 112n), + ), + ); - return true; + return true; + }, }, - }); + ); }; diff --git a/packages/ERTP/test/swingsetTests/ertpService/vat-ertp-service.js b/packages/ERTP/test/swingsetTests/ertpService/vat-ertp-service.js index f675ea609d3..b94b0dce953 100644 --- a/packages/ERTP/test/swingsetTests/ertpService/vat-ertp-service.js +++ b/packages/ERTP/test/swingsetTests/ertpService/vat-ertp-service.js @@ -45,7 +45,11 @@ harden(prepareErtpService); export const buildRootObject = async (vatPowers, _vatParams, baggage) => { const ertpService = prepareErtpService(baggage, vatPowers.exitVatWithFailure); - return Far('root', { - getErtpService: () => ertpService, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + getErtpService: () => ertpService, + }, + ); }; diff --git a/packages/ERTP/test/swingsetTests/splitPayments/bootstrap.js b/packages/ERTP/test/swingsetTests/splitPayments/bootstrap.js index 9a37b9b82a6..50ada51685f 100644 --- a/packages/ERTP/test/swingsetTests/splitPayments/bootstrap.js +++ b/packages/ERTP/test/swingsetTests/splitPayments/bootstrap.js @@ -15,18 +15,22 @@ export function buildRootObject(vatPowers, vatParameters) { return E(aliceP).testSplitPayments(); } - const obj0 = Far('root', { - async bootstrap(vats) { - switch (arg0) { - case 'splitPayments': { - const aliceMaker = await E(vats.alice).makeAliceMaker(); - return testSplitPayments(aliceMaker); + const obj0 = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + switch (arg0) { + case 'splitPayments': { + const aliceMaker = await E(vats.alice).makeAliceMaker(); + return testSplitPayments(aliceMaker); + } + default: { + assert.fail(X`unrecognized argument value ${arg0}`); + } } - default: { - assert.fail(X`unrecognized argument value ${arg0}`); - } - } + }, }, - }); + ); return obj0; } diff --git a/packages/ERTP/test/swingsetTests/splitPayments/vat-alice.js b/packages/ERTP/test/swingsetTests/splitPayments/vat-alice.js index c61edee397a..31f7551b398 100644 --- a/packages/ERTP/test/swingsetTests/splitPayments/vat-alice.js +++ b/packages/ERTP/test/swingsetTests/splitPayments/vat-alice.js @@ -4,35 +4,50 @@ import { AmountMath } from '../../../src/index.js'; import { split } from '../../../src/legacy-payment-helpers.js'; function makeAliceMaker(log) { - return Far('aliceMaker', { - make(issuer, brand, oldPaymentP) { - const alice = Far('alice', { - async testSplitPayments() { - log('oldPayment balance:', await E(issuer).getAmountOf(oldPaymentP)); - const splitPayments = await split( - E(issuer).makeEmptyPurse(), - oldPaymentP, - AmountMath.make(brand, 10n), - ); - log( - 'splitPayment[0] balance: ', - await E(issuer).getAmountOf(splitPayments[0]), - ); - log( - 'splitPayment[1] balance: ', - await E(issuer).getAmountOf(splitPayments[1]), - ); - }, - }); - return alice; + return makeExo( + 'aliceMaker', + M.interface('aliceMaker', {}, { defaultGuards: 'passable' }), + { + make(issuer, brand, oldPaymentP) { + const alice = makeExo( + 'alice', + M.interface('alice', {}, { defaultGuards: 'passable' }), + { + async testSplitPayments() { + log( + 'oldPayment balance:', + await E(issuer).getAmountOf(oldPaymentP), + ); + const splitPayments = await split( + E(issuer).makeEmptyPurse(), + oldPaymentP, + AmountMath.make(brand, 10n), + ); + log( + 'splitPayment[0] balance: ', + await E(issuer).getAmountOf(splitPayments[0]), + ); + log( + 'splitPayment[1] balance: ', + await E(issuer).getAmountOf(splitPayments[1]), + ); + }, + }, + ); + return alice; + }, }, - }); + ); } export function buildRootObject(vatPowers) { - return Far('root', { - makeAliceMaker() { - return makeAliceMaker(vatPowers.testLog); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + makeAliceMaker() { + return makeAliceMaker(vatPowers.testLog); + }, }, - }); + ); } diff --git a/packages/ERTP/test/unitTests/mathHelpers/mockBrand.js b/packages/ERTP/test/unitTests/mathHelpers/mockBrand.js index 3b0dd05597f..3daebd24386 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/mockBrand.js +++ b/packages/ERTP/test/unitTests/mathHelpers/mockBrand.js @@ -2,12 +2,16 @@ import { Far } from '@endo/marshal'; import { AssetKind } from '../../../src/index.js'; /** @type {Brand} */ -export const mockBrand = Far('brand', { - // eslint-disable-next-line no-unused-vars - isMyIssuer: async allegedIssuer => false, - getAllegedName: () => 'mock', - getAmountShape: () => {}, - getDisplayInfo: () => ({ - assetKind: AssetKind.NAT, - }), -}); +export const mockBrand = makeExo( + 'brand', + M.interface('brand', {}, { defaultGuards: 'passable' }), + { + // eslint-disable-next-line no-unused-vars + isMyIssuer: async allegedIssuer => false, + getAllegedName: () => 'mock', + getAmountShape: () => {}, + getDisplayInfo: () => ({ + assetKind: AssetKind.NAT, + }), + }, +); diff --git a/packages/ERTP/test/unitTests/mathHelpers/test-natMathHelpers.js b/packages/ERTP/test/unitTests/mathHelpers/test-natMathHelpers.js index d43164ce474..9b62d089e23 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/test-natMathHelpers.js +++ b/packages/ERTP/test/unitTests/mathHelpers/test-natMathHelpers.js @@ -61,12 +61,16 @@ test('natMathHelpers coerce', t => { m.coerce( mockBrand, harden({ - brand: Far('otherBrand', { - getAllegedName: () => 'somename', - isMyIssuer: async () => false, - getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), - getAmountShape: () => M.any(), - }), + brand: makeExo( + 'otherBrand', + M.interface('otherBrand', {}, { defaultGuards: 'passable' }), + { + getAllegedName: () => 'somename', + isMyIssuer: async () => false, + getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), + getAmountShape: () => M.any(), + }, + ), value: 4n, }), ), @@ -189,12 +193,16 @@ test('natMathHelpers isGTE mixed brands', t => { () => m.isGTE( m.make( - Far('otherBrand', { - getAllegedName: () => 'somename', - isMyIssuer: async () => false, - getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), - getAmountShape: () => M.any(), - }), + makeExo( + 'otherBrand', + M.interface('otherBrand', {}, { defaultGuards: 'passable' }), + { + getAllegedName: () => 'somename', + isMyIssuer: async () => false, + getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), + getAmountShape: () => M.any(), + }, + ), 5n, ), m.make(mockBrand, 3n), @@ -211,12 +219,16 @@ test(`natMathHelpers isGTE - brands don't match objective brand`, t => { m.isGTE( m.make(mockBrand, 5n), m.make(mockBrand, 3n), - Far('otherBrand', { - getAllegedName: () => 'somename', - isMyIssuer: async () => false, - getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), - getAmountShape: () => M.any(), - }), + makeExo( + 'otherBrand', + M.interface('otherBrand', {}, { defaultGuards: 'passable' }), + { + getAllegedName: () => 'somename', + isMyIssuer: async () => false, + getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), + getAmountShape: () => M.any(), + }, + ), ), { message: /amount's brand .* did not match expected brand .*/, @@ -240,12 +252,16 @@ test('natMathHelpers isEqual mixed brands', t => { () => m.isEqual( m.make( - Far('otherBrand', { - getAllegedName: () => 'somename', - isMyIssuer: async () => false, - getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), - getAmountShape: () => M.any(), - }), + makeExo( + 'otherBrand', + M.interface('otherBrand', {}, { defaultGuards: 'passable' }), + { + getAllegedName: () => 'somename', + isMyIssuer: async () => false, + getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), + getAmountShape: () => M.any(), + }, + ), 4n, ), m.make(mockBrand, 4n), @@ -262,12 +278,16 @@ test(`natMathHelpers isEqual - brands don't match objective brand`, t => { m.isEqual( m.make(mockBrand, 4n), m.make(mockBrand, 4n), - Far('otherBrand', { - getAllegedName: () => 'somename', - isMyIssuer: async () => false, - getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), - getAmountShape: () => M.any(), - }), + makeExo( + 'otherBrand', + M.interface('otherBrand', {}, { defaultGuards: 'passable' }), + { + getAllegedName: () => 'somename', + isMyIssuer: async () => false, + getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), + getAmountShape: () => M.any(), + }, + ), ), { message: /amount's brand .* did not match expected brand .*/, @@ -288,12 +308,16 @@ test('natMathHelpers add mixed brands', t => { () => m.add( m.make( - Far('otherBrand', { - getAllegedName: () => 'somename', - isMyIssuer: async () => false, - getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), - getAmountShape: () => M.any(), - }), + makeExo( + 'otherBrand', + M.interface('otherBrand', {}, { defaultGuards: 'passable' }), + { + getAllegedName: () => 'somename', + isMyIssuer: async () => false, + getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), + getAmountShape: () => M.any(), + }, + ), 5n, ), m.make(mockBrand, 9n), @@ -310,12 +334,16 @@ test(`natMathHelpers add - brands don't match objective brand`, t => { m.add( m.make(mockBrand, 5n), m.make(mockBrand, 9n), - Far('otherBrand', { - getAllegedName: () => 'somename', - isMyIssuer: async () => false, - getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), - getAmountShape: () => M.any(), - }), + makeExo( + 'otherBrand', + M.interface('otherBrand', {}, { defaultGuards: 'passable' }), + { + getAllegedName: () => 'somename', + isMyIssuer: async () => false, + getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), + getAmountShape: () => M.any(), + }, + ), ), { message: /amount's brand .* did not match expected brand .*/, @@ -336,12 +364,16 @@ test('natMathHelpers subtract mixed brands', t => { () => m.subtract( m.make( - Far('otherBrand', { - getAllegedName: () => 'somename', - isMyIssuer: async () => false, - getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), - getAmountShape: () => M.any(), - }), + makeExo( + 'otherBrand', + M.interface('otherBrand', {}, { defaultGuards: 'passable' }), + { + getAllegedName: () => 'somename', + isMyIssuer: async () => false, + getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), + getAmountShape: () => M.any(), + }, + ), 6n, ), m.make(mockBrand, 1n), @@ -358,12 +390,16 @@ test(`natMathHelpers subtract brands don't match brand`, t => { m.subtract( m.make(mockBrand, 6n), m.make(mockBrand, 1n), - Far('otherBrand', { - getAllegedName: () => 'somename', - isMyIssuer: async () => false, - getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), - getAmountShape: () => M.any(), - }), + makeExo( + 'otherBrand', + M.interface('otherBrand', {}, { defaultGuards: 'passable' }), + { + getAllegedName: () => 'somename', + isMyIssuer: async () => false, + getDisplayInfo: () => ({ assetKind: AssetKind.NAT }), + getAmountShape: () => M.any(), + }, + ), ), { message: /amount's brand .* did not match expected brand .*/, diff --git a/packages/ERTP/test/unitTests/mathHelpers/test-setMathHelpers.js b/packages/ERTP/test/unitTests/mathHelpers/test-setMathHelpers.js index 716df4ea092..053b68143ca 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/test-setMathHelpers.js +++ b/packages/ERTP/test/unitTests/mathHelpers/test-setMathHelpers.js @@ -398,9 +398,21 @@ const runSetMathHelpersTests = (t, [a, b, c], a2) => { }; test('setMathHelpers with handles', t => { - const a = Far('iface a', {}); - const b = Far('iface b', {}); - const c = Far('iface c', {}); + const a = makeExo( + 'iface a', + M.interface('iface a', {}, { defaultGuards: 'passable' }), + {}, + ); + const b = makeExo( + 'iface b', + M.interface('iface b', {}, { defaultGuards: 'passable' }), + {}, + ); + const c = makeExo( + 'iface c', + M.interface('iface c', {}, { defaultGuards: 'passable' }), + {}, + ); runSetMathHelpersTests(t, [a, b, c]); }); @@ -417,18 +429,38 @@ test('setMathHelpers with basic objects', t => { test('setMathHelpers with complex objects', t => { const a = { - handle: Far('handle', {}), - instanceHandle: Far('ihandle', {}), + handle: makeExo( + 'handle', + M.interface('handle', {}, { defaultGuards: 'passable' }), + {}, + ), + instanceHandle: makeExo( + 'ihandle', + M.interface('ihandle', {}, { defaultGuards: 'passable' }), + {}, + ), name: 'a', }; const b = { - handle: Far('handle', {}), + handle: makeExo( + 'handle', + M.interface('handle', {}, { defaultGuards: 'passable' }), + {}, + ), instanceHandle: a.instanceHandle, name: 'b', }; const c = { - handle: Far('handle', {}), - instanceHandle: Far('ihandle', {}), + handle: makeExo( + 'handle', + M.interface('handle', {}, { defaultGuards: 'passable' }), + {}, + ), + instanceHandle: makeExo( + 'ihandle', + M.interface('ihandle', {}, { defaultGuards: 'passable' }), + {}, + ), name: 'c', }; diff --git a/packages/ERTP/test/unitTests/test-inputValidation.js b/packages/ERTP/test/unitTests/test-inputValidation.js index e6c503e658e..3058f5bb76f 100644 --- a/packages/ERTP/test/unitTests/test-inputValidation.js +++ b/packages/ERTP/test/unitTests/test-inputValidation.js @@ -143,7 +143,13 @@ test('brand.isMyIssuer bad issuer', async t => { /In "isMyIssuer" method of \(myTokens brand\): arg 0: .*"not an issuer" - Must be a remotable/, }); const fakeIssuer = /** @type {Issuer} */ ( - /** @type {unknown} */ (Far('myTokens issuer', {})) + /** @type {unknown} */ ( + makeExo( + 'myTokens issuer', + M.interface('myTokens issuer', {}, { defaultGuards: 'passable' }), + {}, + ) + ) ); const result = await brand.isMyIssuer(fakeIssuer); t.false(result); @@ -186,10 +192,14 @@ test('issuer.combine bad payments array', async t => { message: 'srcPaymentsPs is not iterable', }); - const notAnArray2 = Far('notAnArray2', { - length: () => 2, - split: () => {}, - }); + const notAnArray2 = makeExo( + 'notAnArray2', + M.interface('notAnArray2', {}, { defaultGuards: 'passable' }), + { + length: () => 2, + split: () => {}, + }, + ); // @ts-expect-error Intentional wrong type for testing await t.throwsAsync(() => combine(E(issuer).makeEmptyPurse(), notAnArray2), { message: 'srcPaymentsPs is not iterable', diff --git a/packages/SwingSet/demo/encouragementBot/bootstrap.js b/packages/SwingSet/demo/encouragementBot/bootstrap.js index 4418a521ee4..509a3a5e2d7 100644 --- a/packages/SwingSet/demo/encouragementBot/bootstrap.js +++ b/packages/SwingSet/demo/encouragementBot/bootstrap.js @@ -4,21 +4,25 @@ console.log(`=> loading bootstrap.js`); export function buildRootObject(vatPowers) { const log = vatPowers.testLog; - return Far('root', { - bootstrap(vats) { - console.log('=> bootstrap() called'); - E(vats.user) - .talkToBot(vats.bot, 'encouragementBot') - .then( - r => - log( - `=> the promise given by the call to user.talkToBot resolved to '${r}'`, - ), - err => - log( - `=> the promise given by the call to user.talkToBot was rejected '${err}''`, - ), - ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + console.log('=> bootstrap() called'); + E(vats.user) + .talkToBot(vats.bot, 'encouragementBot') + .then( + r => + log( + `=> the promise given by the call to user.talkToBot resolved to '${r}'`, + ), + err => + log( + `=> the promise given by the call to user.talkToBot was rejected '${err}''`, + ), + ); + }, }, - }); + ); } diff --git a/packages/SwingSet/demo/encouragementBot/vat-bot.js b/packages/SwingSet/demo/encouragementBot/vat-bot.js index 69a3d619e6f..0bf868c3ae4 100644 --- a/packages/SwingSet/demo/encouragementBot/vat-bot.js +++ b/packages/SwingSet/demo/encouragementBot/vat-bot.js @@ -1,12 +1,16 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { - return Far('root', { - encourageMe(name) { - vatPowers.testLog( - `=> encouragementBot.encourageMe got the name: ${name}`, - ); - return `${name}, you are awesome, keep it up!`; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + encourageMe(name) { + vatPowers.testLog( + `=> encouragementBot.encourageMe got the name: ${name}`, + ); + return `${name}, you are awesome, keep it up!`; + }, }, - }); + ); } diff --git a/packages/SwingSet/demo/encouragementBot/vat-user.js b/packages/SwingSet/demo/encouragementBot/vat-user.js index acde1c8473e..1f0fcff8935 100644 --- a/packages/SwingSet/demo/encouragementBot/vat-user.js +++ b/packages/SwingSet/demo/encouragementBot/vat-user.js @@ -2,15 +2,19 @@ import { Far, E } from '@endo/far'; export function buildRootObject(vatPowers) { const log = vatPowers.testLog; - return Far('root', { - talkToBot(bot, botName) { - log(`=> user.talkToBot is called with ${botName}`); - E(bot) - .encourageMe('user') - .then(myEncouragement => - log(`=> user receives the encouragement: ${myEncouragement}`), - ); - return 'Thanks for the setup. I sure hope I get some encouragement...'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + talkToBot(bot, botName) { + log(`=> user.talkToBot is called with ${botName}`); + E(bot) + .encourageMe('user') + .then(myEncouragement => + log(`=> user receives the encouragement: ${myEncouragement}`), + ); + return 'Thanks for the setup. I sure hope I get some encouragement...'; + }, }, - }); + ); } diff --git a/packages/SwingSet/demo/encouragementBotComms/bootstrap.js b/packages/SwingSet/demo/encouragementBotComms/bootstrap.js index 3242b58d9e4..512df55fcc5 100644 --- a/packages/SwingSet/demo/encouragementBotComms/bootstrap.js +++ b/packages/SwingSet/demo/encouragementBotComms/bootstrap.js @@ -4,55 +4,63 @@ console.log(`=> loading bootstrap.js`); export function buildRootObject(vatPowers) { const { D, testLog: log } = vatPowers; - return Far('root', { - async bootstrap(vats, devices) { - console.log('=> bootstrap() called'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + console.log('=> bootstrap() called'); - const BOT = 'bot'; - const USER = 'user'; - const BOT_CLIST_INDEX = 0; + const BOT = 'bot'; + const USER = 'user'; + const BOT_CLIST_INDEX = 0; - D(devices.loopbox).registerInboundHandler(USER, vats.uservattp); - const usersender = D(devices.loopbox).getSender(USER); - await E(vats.uservattp).registerMailboxDevice(usersender); - const { transmitter: txToBotForUser, setReceiver: setRxFromBotForUser } = - await E(vats.uservattp).addRemote(BOT); - await E(vats.usercomms).addRemote( - BOT, - txToBotForUser, - setRxFromBotForUser, - ); - - D(devices.loopbox).registerInboundHandler(BOT, vats.botvattp); - const botsender = D(devices.loopbox).getSender(BOT); - await E(vats.botvattp).registerMailboxDevice(botsender); - const { transmitter: txToUserForBot, setReceiver: setRxFromUserForBot } = - await E(vats.botvattp).addRemote(USER); - await E(vats.botcomms).addRemote( - USER, - txToUserForBot, - setRxFromUserForBot, - ); + D(devices.loopbox).registerInboundHandler(USER, vats.uservattp); + const usersender = D(devices.loopbox).getSender(USER); + await E(vats.uservattp).registerMailboxDevice(usersender); + const { + transmitter: txToBotForUser, + setReceiver: setRxFromBotForUser, + } = await E(vats.uservattp).addRemote(BOT); + await E(vats.usercomms).addRemote( + BOT, + txToBotForUser, + setRxFromBotForUser, + ); - await E(vats.botcomms).addEgress( - USER, - BOT_CLIST_INDEX, // this would normally be autogenerated - vats.bot, - ); + D(devices.loopbox).registerInboundHandler(BOT, vats.botvattp); + const botsender = D(devices.loopbox).getSender(BOT); + await E(vats.botvattp).registerMailboxDevice(botsender); + const { + transmitter: txToUserForBot, + setReceiver: setRxFromUserForBot, + } = await E(vats.botvattp).addRemote(USER); + await E(vats.botcomms).addRemote( + USER, + txToUserForBot, + setRxFromUserForBot, + ); - const pPBot = E(vats.usercomms).addIngress(BOT, BOT_CLIST_INDEX); - E(vats.user) - .talkToBot(pPBot, 'bot') - .then( - r => - log( - `=> the promise given by the call to user.talkToBot resolved to '${r}'`, - ), - err => - log( - `=> the promise given by the call to user.talkToBot was rejected '${err}''`, - ), + await E(vats.botcomms).addEgress( + USER, + BOT_CLIST_INDEX, // this would normally be autogenerated + vats.bot, ); + + const pPBot = E(vats.usercomms).addIngress(BOT, BOT_CLIST_INDEX); + E(vats.user) + .talkToBot(pPBot, 'bot') + .then( + r => + log( + `=> the promise given by the call to user.talkToBot resolved to '${r}'`, + ), + err => + log( + `=> the promise given by the call to user.talkToBot was rejected '${err}''`, + ), + ); + }, }, - }); + ); } diff --git a/packages/SwingSet/demo/encouragementBotComms/vat-bot.js b/packages/SwingSet/demo/encouragementBotComms/vat-bot.js index 69a3d619e6f..0bf868c3ae4 100644 --- a/packages/SwingSet/demo/encouragementBotComms/vat-bot.js +++ b/packages/SwingSet/demo/encouragementBotComms/vat-bot.js @@ -1,12 +1,16 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { - return Far('root', { - encourageMe(name) { - vatPowers.testLog( - `=> encouragementBot.encourageMe got the name: ${name}`, - ); - return `${name}, you are awesome, keep it up!`; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + encourageMe(name) { + vatPowers.testLog( + `=> encouragementBot.encourageMe got the name: ${name}`, + ); + return `${name}, you are awesome, keep it up!`; + }, }, - }); + ); } diff --git a/packages/SwingSet/demo/encouragementBotComms/vat-user.js b/packages/SwingSet/demo/encouragementBotComms/vat-user.js index 343ff6b630c..1f6bdec0fdc 100644 --- a/packages/SwingSet/demo/encouragementBotComms/vat-user.js +++ b/packages/SwingSet/demo/encouragementBotComms/vat-user.js @@ -2,15 +2,19 @@ import { Far, E } from '@endo/far'; export function buildRootObject(vatPowers) { const log = vatPowers.testLog; - return Far('root', { - talkToBot(pbot, botName) { - log(`=> user.talkToBot is called with ${botName}`); - E(pbot) - .encourageMe('user') - .then(myEncouragement => - log(`=> user receives the encouragement: ${myEncouragement}`), - ); - return 'Thanks for the setup. I sure hope I get some encouragement...'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + talkToBot(pbot, botName) { + log(`=> user.talkToBot is called with ${botName}`); + E(pbot) + .encourageMe('user') + .then(myEncouragement => + log(`=> user receives the encouragement: ${myEncouragement}`), + ); + return 'Thanks for the setup. I sure hope I get some encouragement...'; + }, }, - }); + ); } diff --git a/packages/SwingSet/docs/devices.md b/packages/SwingSet/docs/devices.md index 5657ba92161..6511308a96a 100644 --- a/packages/SwingSet/docs/devices.md +++ b/packages/SwingSet/docs/devices.md @@ -237,7 +237,7 @@ This will push a delivery onto the kernel run-queue. ```js // vat does - const callbackObj = Far('cb', { + const callbackObj = makeExo('cb', M.interface('cb', {}, { defaultGuards: 'passable' }), { hello(arg) { console.log('they called me!', arg); }, diff --git a/packages/SwingSet/docs/static-vats.md b/packages/SwingSet/docs/static-vats.md index d13a0ed6e5c..7840b418919 100644 --- a/packages/SwingSet/docs/static-vats.md +++ b/packages/SwingSet/docs/static-vats.md @@ -21,7 +21,7 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { let counter = 0; - return Far('root', { + return makeExo('root', M.interface('root', {}, { defaultGuards: 'passable' }), { increment() { counter += 1; }, diff --git a/packages/SwingSet/docs/timer.md b/packages/SwingSet/docs/timer.md index a3b323f20b9..60ecbc295c1 100644 --- a/packages/SwingSet/docs/timer.md +++ b/packages/SwingSet/docs/timer.md @@ -82,7 +82,7 @@ The `timerService` object can be distributed to other vats as necessary. await p1; // same, but cancellable - const cancelToken = Far('cancel', {}); // any pass-by-reference object + const cancelToken = makeExo('cancel', M.interface('cancel', {}, { defaultGuards: 'passable' }), {}); // any pass-by-reference object // the cancel token is always optional const p2 = E(timerService).delay(toRT(30n), cancelToken); // E(timerService).cancel(cancelToken) will cancel that @@ -93,7 +93,7 @@ The `timerService` object can be distributed to other vats as necessary. await p3; // fires Tue, 19 Jan 2038 03:14:08 GMT // callback-based API functions need a handler object - const handler = Far('handler', { + const handler = makeExo('handler', M.interface('handler', {}, { defaultGuards: 'passable' }), { // t is a TimestampRecord wake(t) { console.log(`woken up, scheduled for ${fromTS(t)}`); }, }); diff --git a/packages/SwingSet/src/controller/initializeKernel.js b/packages/SwingSet/src/controller/initializeKernel.js index dbf4a74cf10..7df1bf65740 100644 --- a/packages/SwingSet/src/controller/initializeKernel.js +++ b/packages/SwingSet/src/controller/initializeKernel.js @@ -172,7 +172,11 @@ export async function initializeKernel(config, kernelStorage, options = {}) { // non-empty object as vatObj0s, since an empty object would be // serialized as pass-by-presence. It wouldn't make much sense for the // bootstrap object to call itself, though. - const vref = Far('root', {}); + const vref = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + {}, + ); vatObj0s[name] = vref; const vatKeeper = kernelKeeper.provideVatKeeper(vatID); const kernelSlot = vatKeeper.mapVatSlotToKernelSlot(vatSlot); @@ -183,7 +187,11 @@ export async function initializeKernel(config, kernelStorage, options = {}) { const drefs = new Map(); const deviceObj0s = {}; for (const [name, deviceID] of kernelKeeper.getDevices()) { - const dref = Far('device', {}); + const dref = makeExo( + 'device', + M.interface('device', {}, { defaultGuards: 'passable' }), + {}, + ); deviceObj0s[name] = dref; const devSlot = makeVatSlot('device', true, 0); const devKeeper = kernelKeeper.allocateDeviceKeeperIfNeeded(deviceID); diff --git a/packages/SwingSet/src/devices/bridge/device-bridge.js b/packages/SwingSet/src/devices/bridge/device-bridge.js index 463bf3097e0..bc56d198588 100644 --- a/packages/SwingSet/src/devices/bridge/device-bridge.js +++ b/packages/SwingSet/src/devices/bridge/device-bridge.js @@ -41,23 +41,27 @@ export function buildRootDeviceNode(tools) { } registerInboundCallback(inboundCallback); - return Far('root', { - registerInboundHandler(handler) { - if (inboundHandler) { - throw Error('inboundHandler already registered'); - } - inboundHandler = handler; - setDeviceState(harden({ inboundHandler })); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + registerInboundHandler(handler) { + if (inboundHandler) { + throw Error('inboundHandler already registered'); + } + inboundHandler = handler; + setDeviceState(harden({ inboundHandler })); + }, + unregisterInboundHandler() { + inboundHandler = undefined; + setDeviceState(harden({ inboundHandler })); + }, + callOutbound(...args) { + // invoke our endowment of the same name, with a sync return value + const retval = callOutbound(...args); + // we can return anything JSON-serializable, plus 'undefined' + return harden(sanitize(retval)); + }, }, - unregisterInboundHandler() { - inboundHandler = undefined; - setDeviceState(harden({ inboundHandler })); - }, - callOutbound(...args) { - // invoke our endowment of the same name, with a sync return value - const retval = callOutbound(...args); - // we can return anything JSON-serializable, plus 'undefined' - return harden(sanitize(retval)); - }, - }); + ); } diff --git a/packages/SwingSet/src/devices/command/device-command.js b/packages/SwingSet/src/devices/command/device-command.js index 98af2ea490c..5c6b80c9528 100644 --- a/packages/SwingSet/src/devices/command/device-command.js +++ b/packages/SwingSet/src/devices/command/device-command.js @@ -22,26 +22,30 @@ export function buildRootDeviceNode(tools) { } }); - return Far('root', { - registerInboundHandler(handler) { - inboundHandler = handler; - setDeviceState(harden({ inboundHandler })); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + registerInboundHandler(handler) { + inboundHandler = handler; + setDeviceState(harden({ inboundHandler })); + }, - sendResponse(count, isReject, obj) { - try { - deliverResponse(count, isReject, JSON.stringify(obj)); - } catch (e) { - console.error(`error during sendResponse:`, e); - } - }, + sendResponse(count, isReject, obj) { + try { + deliverResponse(count, isReject, JSON.stringify(obj)); + } catch (e) { + console.error(`error during sendResponse:`, e); + } + }, - sendBroadcast(obj) { - try { - sendBroadcast(JSON.stringify(obj)); - } catch (e) { - console.error(`error during sendBroadcast:`, e); - } + sendBroadcast(obj) { + try { + sendBroadcast(JSON.stringify(obj)); + } catch (e) { + console.error(`error during sendBroadcast:`, e); + } + }, }, - }); + ); } diff --git a/packages/SwingSet/src/devices/lib/deviceTools.js b/packages/SwingSet/src/devices/lib/deviceTools.js index b8ff25f4c42..17a6f41f677 100644 --- a/packages/SwingSet/src/devices/lib/deviceTools.js +++ b/packages/SwingSet/src/devices/lib/deviceTools.js @@ -20,15 +20,19 @@ export function buildSerializationTools(syscall, deviceName) { const { type, allocatedByVat } = parseVatSlot(slot); assert.equal(type, 'object'); assert.equal(allocatedByVat, false); - const p = Far('presence', { - send(method, args) { - assert.typeof(method, 'string'); - assert(Array.isArray(args), args); - // eslint-disable-next-line no-use-before-define - const capdata = serialize([method, args]); - syscall.sendOnly(slot, capdata); + const p = makeExo( + 'presence', + M.interface('presence', {}, { defaultGuards: 'passable' }), + { + send(method, args) { + assert.typeof(method, 'string'); + assert(Array.isArray(args), args); + // eslint-disable-next-line no-use-before-define + const capdata = serialize([method, args]); + syscall.sendOnly(slot, capdata); + }, }, - }); + ); presences.set(p, slot); return p; } @@ -40,7 +44,11 @@ export function buildSerializationTools(syscall, deviceName) { const { type, allocatedByVat } = parseVatSlot(slot); assert.equal(type, 'device'); assert.equal(allocatedByVat, true); - const dn = Far('device node', {}); + const dn = makeExo( + 'device node', + M.interface('device node', {}, { defaultGuards: 'passable' }), + {}, + ); myDeviceNodes.set(dn, slot); return dn; } diff --git a/packages/SwingSet/src/devices/loopbox/device-loopbox.js b/packages/SwingSet/src/devices/loopbox/device-loopbox.js index cb9bb6f1fdc..1b893bc960e 100644 --- a/packages/SwingSet/src/devices/loopbox/device-loopbox.js +++ b/packages/SwingSet/src/devices/loopbox/device-loopbox.js @@ -7,28 +7,32 @@ export function buildRootDeviceNode(tools) { const { registerPassOneMessage, deliverMode } = endowments; function makeSender(sender) { - return Far('sender', { - add(peer, msgnum, body) { - const oldDS = getDeviceState(); - oldDS.inboundHandlers[peer] || Fail`unregistered peer '${peer}'`; - const h = oldDS.inboundHandlers[peer]; - const newDS = { ...oldDS }; - if (deliverMode === 'immediate') { - SO(h).deliverInboundMessages( - sender, - harden([[oldDS.counts[sender], body]]), - ); - } else { - newDS.queuedMessages = Array.from(newDS.queuedMessages); - newDS.queuedMessages.push([h, sender, oldDS.counts[sender], body]); - } - newDS.counts = { ...newDS.counts }; - newDS.counts[sender] += 1; - setDeviceState(harden(newDS)); + return makeExo( + 'sender', + M.interface('sender', {}, { defaultGuards: 'passable' }), + { + add(peer, msgnum, body) { + const oldDS = getDeviceState(); + oldDS.inboundHandlers[peer] || Fail`unregistered peer '${peer}'`; + const h = oldDS.inboundHandlers[peer]; + const newDS = { ...oldDS }; + if (deliverMode === 'immediate') { + SO(h).deliverInboundMessages( + sender, + harden([[oldDS.counts[sender], body]]), + ); + } else { + newDS.queuedMessages = Array.from(newDS.queuedMessages); + newDS.queuedMessages.push([h, sender, oldDS.counts[sender], body]); + } + newDS.counts = { ...newDS.counts }; + newDS.counts[sender] += 1; + setDeviceState(harden(newDS)); + }, + remove(_peer, _msgnum) {}, + ackInbound(_peer, _msgnum) {}, }, - remove(_peer, _msgnum) {}, - ackInbound(_peer, _msgnum) {}, - }); + ); } let deviceState = getDeviceState(); @@ -86,18 +90,22 @@ export function buildRootDeviceNode(tools) { } registerPassOneMessage(loopboxPassOneMessage); - return Far('root', { - registerInboundHandler(name, handler) { - const oldDS = getDeviceState(); - !oldDS.inboundHandlers[name] || Fail`already registered`; - const newDS = { ...oldDS }; - newDS.inboundHandlers = { ...newDS.inboundHandlers }; - newDS.inboundHandlers[name] = handler; - setDeviceState(harden(newDS)); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + registerInboundHandler(name, handler) { + const oldDS = getDeviceState(); + !oldDS.inboundHandlers[name] || Fail`already registered`; + const newDS = { ...oldDS }; + newDS.inboundHandlers = { ...newDS.inboundHandlers }; + newDS.inboundHandlers[name] = handler; + setDeviceState(harden(newDS)); + }, - getSender(sender) { - return senderMap.get(sender); + getSender(sender) { + return senderMap.get(sender); + }, }, - }); + ); } diff --git a/packages/SwingSet/src/devices/mailbox/device-mailbox.js b/packages/SwingSet/src/devices/mailbox/device-mailbox.js index 256e0c2e1e6..9bafd302c45 100644 --- a/packages/SwingSet/src/devices/mailbox/device-mailbox.js +++ b/packages/SwingSet/src/devices/mailbox/device-mailbox.js @@ -54,39 +54,43 @@ export function buildRootDeviceNode(tools) { }; // the Root Device Node. - return Far('root', { - registerInboundHandler(handler) { - !inboundHandler || Fail`already registered`; - inboundHandler = handler; - setDeviceState(harden({ inboundHandler })); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + registerInboundHandler(handler) { + !inboundHandler || Fail`already registered`; + inboundHandler = handler; + setDeviceState(harden({ inboundHandler })); + }, - unregisterInboundHander() { - inboundHandler = undefined; - }, + unregisterInboundHander() { + inboundHandler = undefined; + }, - add(peer, msgnum, body) { - try { - endowments.add(`${peer}`, Nat(msgnum), `${body}`); - } catch (e) { - Fail`error in add: ${e}`; - } - }, + add(peer, msgnum, body) { + try { + endowments.add(`${peer}`, Nat(msgnum), `${body}`); + } catch (e) { + Fail`error in add: ${e}`; + } + }, - remove(peer, msgnum) { - try { - endowments.remove(`${peer}`, Nat(msgnum)); - } catch (e) { - Fail`error in remove: ${e}`; - } - }, + remove(peer, msgnum) { + try { + endowments.remove(`${peer}`, Nat(msgnum)); + } catch (e) { + Fail`error in remove: ${e}`; + } + }, - ackInbound(peer, msgnum) { - try { - endowments.setAcknum(`${peer}`, Nat(msgnum)); - } catch (e) { - Fail`error in ackInbound: ${e}`; - } + ackInbound(peer, msgnum) { + try { + endowments.setAcknum(`${peer}`, Nat(msgnum)); + } catch (e) { + Fail`error in ackInbound: ${e}`; + } + }, }, - }); + ); } diff --git a/packages/SwingSet/src/devices/plugin/device-plugin.js b/packages/SwingSet/src/devices/plugin/device-plugin.js index 41927ffe8fa..99b94dc8adb 100644 --- a/packages/SwingSet/src/devices/plugin/device-plugin.js +++ b/packages/SwingSet/src/devices/plugin/device-plugin.js @@ -140,16 +140,20 @@ export function buildRootDeviceNode(tools) { } }); - return Far('root', { - getPluginDir() { - return endowments.getPluginDir(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + getPluginDir() { + return endowments.getPluginDir(); + }, + connect, + send, + registerReceiver(receiver) { + !registeredReceiver || Fail`registered receiver already set`; + registeredReceiver = receiver; + saveState(); + }, }, - connect, - send, - registerReceiver(receiver) { - !registeredReceiver || Fail`registered receiver already set`; - registeredReceiver = receiver; - saveState(); - }, - }); + ); } diff --git a/packages/SwingSet/src/devices/timer/device-timer.js b/packages/SwingSet/src/devices/timer/device-timer.js index 25818d17bc5..65965be9317 100644 --- a/packages/SwingSet/src/devices/timer/device-timer.js +++ b/packages/SwingSet/src/devices/timer/device-timer.js @@ -269,47 +269,51 @@ export function buildRootDeviceNode(tools) { // guarantee that the handler will be called at the precise desired time, // but the repeated calls won't accumulate timing drift, so the trigger // point will be reached at consistent intervals. - return Far('root', { - setWakeup(baseTime, handler) { - baseTime = Nat(baseTime); - deadlines.add(baseTime, handler); - saveState(); - return baseTime; - }, - removeWakeup(handler) { - const times = deadlines.remove(handler); - saveState(); - return harden(times); - }, - getLastPolled, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + setWakeup(baseTime, handler) { + baseTime = Nat(baseTime); + deadlines.add(baseTime, handler); + saveState(); + return baseTime; + }, + removeWakeup(handler) { + const times = deadlines.remove(handler); + saveState(); + return harden(times); + }, + getLastPolled, - // We can't persist device objects at this point - // (https://github.com/Agoric/SwingSet/issues/175), so we represent the - // identity of Repeaters using unique indexes. The indexes are exposed - // directly to the wrapper vat, and we rely on the wrapper vat to manage - // the authority they represent as capabilities. - makeRepeater(startTime, interval) { - const index = nextRepeater; - repeaters.push({ - startTime: Nat(startTime), - interval: Nat(interval), - }); - nextRepeater += 1; - saveState(); - return index; + // We can't persist device objects at this point + // (https://github.com/Agoric/SwingSet/issues/175), so we represent the + // identity of Repeaters using unique indexes. The indexes are exposed + // directly to the wrapper vat, and we rely on the wrapper vat to manage + // the authority they represent as capabilities. + makeRepeater(startTime, interval) { + const index = nextRepeater; + repeaters.push({ + startTime: Nat(startTime), + interval: Nat(interval), + }); + nextRepeater += 1; + saveState(); + return index; + }, + deleteRepeater(index) { + repeaters[index] = undefined; + saveState(); + return index; + }, + schedule(index, handler) { + const nextTime = nextScheduleTime(index, repeaters, lastPolled); + deadlines.add(nextTime, handler, index); + saveState(); + return nextTime; + }, }, - deleteRepeater(index) { - repeaters[index] = undefined; - saveState(); - return index; - }, - schedule(index, handler) { - const nextTime = nextScheduleTime(index, repeaters, lastPolled); - deadlines.add(nextTime, handler, index); - saveState(); - return nextTime; - }, - }); + ); } // exported for testing. Only buildRootDeviceNode is intended for production diff --git a/packages/SwingSet/src/vats/plugin-manager.js b/packages/SwingSet/src/vats/plugin-manager.js index 93f98941bbd..8106a2d1927 100644 --- a/packages/SwingSet/src/vats/plugin-manager.js +++ b/packages/SwingSet/src/vats/plugin-manager.js @@ -13,10 +13,18 @@ import '@agoric/store/exported.js'; */ /** @type {{ onReset: (firstTime: Promise) => void}} */ -const DEFAULT_RESETTER = Far('resetter', { onReset: _ => {} }); +const DEFAULT_RESETTER = makeExo( + 'resetter', + M.interface('resetter', {}, { defaultGuards: 'passable' }), + { onReset: _ => {} }, +); /** @type {{ walk: (pluginRootP: any) => any }} */ -const DEFAULT_WALKER = Far('walker', { walk: pluginRootP => pluginRootP }); +const DEFAULT_WALKER = makeExo( + 'walker', + M.interface('walker', {}, { defaultGuards: 'passable' }), + { walk: pluginRootP => pluginRootP }, +); /** * @template T @@ -75,146 +83,164 @@ export function makePluginManager(pluginDevice, { D, ...vatPowers }) { // Dispatch object to the right index. D(pluginDevice).registerReceiver( - Far('receiver', { - dispatch(index, obj) { - const conn = modConnection.get(index); - conn.dispatch(obj); - }, - reset(index, epoch) { - const conn = modConnection.get(index); - conn.reset(epoch); + makeExo( + 'receiver', + M.interface('receiver', {}, { defaultGuards: 'passable' }), + { + dispatch(index, obj) { + const conn = modConnection.get(index); + conn.dispatch(obj); + }, + reset(index, epoch) { + const conn = modConnection.get(index); + conn.reset(epoch); + }, }, - }), + ), ); - return Far('plugin-manager', { - getPluginDir() { - return D(pluginDevice).getPluginDir(); - }, - /** - * Load a module, and call resetter.onReset(pluginRootP) every time - * it is instantiated. - * - * @type {LoadPlugin} - */ - load(specifier, opts = undefined, resetter = DEFAULT_RESETTER) { - // This is the internal state: a promise kit that doesn't - // resolve until we are connected. It is replaced by - // a new promise kit when we abort the prior module connection. - let pluginRootPK = makePromiseKit(); - let nextEpoch = 0; - - let currentEpoch; - let currentDispatch = _ => {}; - let currentReset = _ => {}; - - // Connect to the module. - const index = D(pluginDevice).connect(specifier); - if (typeof index !== 'number') { - // An error string. - throw Error(index); - } - - // Register our stable callbacks for this connect index. - modConnection.init( - index, - Far('connection', { - dispatch(obj) { - if (obj.epoch !== currentEpoch) { - return false; - } - return currentDispatch(obj); - }, - reset(epoch) { - return currentReset(epoch); - }, - }), - ); - - const connect = () => { - // Create a CapTP channel. - const myEpoch = nextEpoch; - nextEpoch += 1; - console.debug( - `Connecting to ${specifier}.${index} with epoch ${myEpoch}`, - ); - const { getBootstrap, dispatch } = makeCapTP( - specifier, - obj => { - // console.warn('sending', index, obj); - D(pluginDevice).send(index, obj); - }, - undefined, - { ...vatPowers, epoch: myEpoch }, + return makeExo( + 'plugin-manager', + M.interface('plugin-manager', {}, { defaultGuards: 'passable' }), + { + getPluginDir() { + return D(pluginDevice).getPluginDir(); + }, + /** + * Load a module, and call resetter.onReset(pluginRootP) every time + * it is instantiated. + * + * @type {LoadPlugin} + */ + load(specifier, opts = undefined, resetter = DEFAULT_RESETTER) { + // This is the internal state: a promise kit that doesn't + // resolve until we are connected. It is replaced by + // a new promise kit when we abort the prior module connection. + let pluginRootPK = makePromiseKit(); + let nextEpoch = 0; + + let currentEpoch; + let currentDispatch = _ => {}; + let currentReset = _ => {}; + + // Connect to the module. + const index = D(pluginDevice).connect(specifier); + if (typeof index !== 'number') { + // An error string. + throw Error(index); + } + + // Register our stable callbacks for this connect index. + modConnection.init( + index, + makeExo( + 'connection', + M.interface('connection', {}, { defaultGuards: 'passable' }), + { + dispatch(obj) { + if (obj.epoch !== currentEpoch) { + return false; + } + return currentDispatch(obj); + }, + reset(epoch) { + return currentReset(epoch); + }, + }, + ), ); - currentReset = _epoch => { - pluginRootPK = makePromiseKit(); - - // Tell our clients we are resetting. - void E(resetter).onReset(pluginRootPK.promise.then(_ => true)); - - // Attempt to restart the protocol using the same device connection. - connect(); - }; - - currentDispatch = obj => { - // console.warn('receiving', index, obj); - dispatch(obj); + const connect = () => { + // Create a CapTP channel. + const myEpoch = nextEpoch; + nextEpoch += 1; + console.debug( + `Connecting to ${specifier}.${index} with epoch ${myEpoch}`, + ); + const { getBootstrap, dispatch } = makeCapTP( + specifier, + obj => { + // console.warn('sending', index, obj); + D(pluginDevice).send(index, obj); + }, + undefined, + { ...vatPowers, epoch: myEpoch }, + ); + + currentReset = _epoch => { + pluginRootPK = makePromiseKit(); + + // Tell our clients we are resetting. + void E(resetter).onReset(pluginRootPK.promise.then(_ => true)); + + // Attempt to restart the protocol using the same device connection. + connect(); + }; + + currentDispatch = obj => { + // console.warn('receiving', index, obj); + dispatch(obj); + }; + + currentEpoch = myEpoch; + + // Publish our started plugin. + pluginRootPK.resolve(E(getBootstrap()).start(opts)); }; - currentEpoch = myEpoch; - - // Publish our started plugin. - pluginRootPK.resolve(E(getBootstrap()).start(opts)); - }; - - const actions = Far('actions', { - /** - * Create a stable identity that just forwards to the current - * implementation. - * - * @type {MakeStableForwarder} - */ - makeStableForwarder(walker = DEFAULT_WALKER) { - let pr; - // eslint-disable-next-line no-new - void new HandledPromise((_resolve, _reject, resolveWithPresence) => { - // Use Remotable rather than Far to make a remote from a presence - pr = Remotable( - 'Alleged: stableForwarder', - undefined, - resolveWithPresence({ - applyMethod(_p, name, args) { - // console.warn('applying method epoch', currentEpoch); - const targetP = E(walker).walk(pluginRootPK.promise); - return HandledPromise.applyMethod(targetP, name, args); + const actions = makeExo( + 'actions', + M.interface('actions', {}, { defaultGuards: 'passable' }), + { + /** + * Create a stable identity that just forwards to the current + * implementation. + * + * @type {MakeStableForwarder} + */ + makeStableForwarder(walker = DEFAULT_WALKER) { + let pr; + // eslint-disable-next-line no-new + void new HandledPromise( + (_resolve, _reject, resolveWithPresence) => { + // Use Remotable rather than Far to make a remote from a presence + pr = Remotable( + 'Alleged: stableForwarder', + undefined, + resolveWithPresence({ + applyMethod(_p, name, args) { + // console.warn('applying method epoch', currentEpoch); + const targetP = E(walker).walk(pluginRootPK.promise); + return HandledPromise.applyMethod(targetP, name, args); + }, + get(_p, name) { + // console.warn('applying get epoch', currentEpoch); + const targetP = E(walker).walk(pluginRootPK.promise); + return HandledPromise.get(targetP, name); + }, + }), + ); }, - get(_p, name) { - // console.warn('applying get epoch', currentEpoch); - const targetP = E(walker).walk(pluginRootPK.promise); - return HandledPromise.get(targetP, name); - }, - }), - ); - }); - return pr; - }, - }); + ); + return pr; + }, + }, + ); - // Declare the first reset. - void E(resetter).onReset(Promise.resolve(false)); + // Declare the first reset. + void E(resetter).onReset(Promise.resolve(false)); - // Start the first connection. - connect(); + // Start the first connection. + connect(); - // Give up our plugin root object for the caller to use. - return harden({ - // This is the public state, a promise that never resolves, - // but pipelines messages to the pluginRootPK.promise. - pluginRoot: actions.makeStableForwarder(), - actions, - }); + // Give up our plugin root object for the caller to use. + return harden({ + // This is the public state, a promise that never resolves, + // but pipelines messages to the pluginRootPK.promise. + pluginRoot: actions.makeStableForwarder(), + actions, + }); + }, }, - }); + ); } diff --git a/packages/SwingSet/src/vats/timer/vat-timer.js b/packages/SwingSet/src/vats/timer/vat-timer.js index eee357a3896..ff03a9e90bb 100644 --- a/packages/SwingSet/src/vats/timer/vat-timer.js +++ b/packages/SwingSet/src/vats/timer/vat-timer.js @@ -474,7 +474,11 @@ export const buildRootObject = (vatPowers, _vatParameters, baggage) => { const { resolve, reject, promise } = makePromiseKit(); // these 'controls' are never shared off-vat, but we wrap them as // Far to appease WeakMapStore's value requirements - const controls = Far('controls', { resolve, reject }); + const controls = makeExo( + 'controls', + M.interface('controls', {}, { defaultGuards: 'passable' }), + { resolve, reject }, + ); wakeupPromises.init(event, controls); event.scheduleYourself(); return promise; // disconnects upon upgrade @@ -957,7 +961,11 @@ export const buildRootObject = (vatPowers, _vatParameters, baggage) => { return timerService; }; - return Far('root', { createTimerService }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { createTimerService }, + ); }; export const debugTools = harden({ diff --git a/packages/SwingSet/src/vats/vat-admin/vat-vat-admin.js b/packages/SwingSet/src/vats/vat-admin/vat-vat-admin.js index 4cc363dc572..d1734f8aa48 100644 --- a/packages/SwingSet/src/vats/vat-admin/vat-vat-admin.js +++ b/packages/SwingSet/src/vats/vat-admin/vat-vat-admin.js @@ -584,16 +584,20 @@ export function buildRootObject(vatPowers, _vatParameters, baggage) { } } - return Far('root', { - createVatAdminService, - getCriticalVatKey, - bundleInstalled, - newVatCallback, - vatUpgradeCallback, - vatTerminated, - meterCrossedThreshold, - pauseService, - resumeService, - upgradeStaticVat, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + createVatAdminService, + getCriticalVatKey, + bundleInstalled, + newVatCallback, + vatUpgradeCallback, + vatTerminated, + meterCrossedThreshold, + pauseService, + resumeService, + upgradeStaticVat, + }, + ); } diff --git a/packages/SwingSet/src/vats/vattp/vat-vattp.js b/packages/SwingSet/src/vats/vattp/vat-vattp.js index f85d4dca222..5c8c27c2199 100644 --- a/packages/SwingSet/src/vats/vattp/vat-vattp.js +++ b/packages/SwingSet/src/vats/vattp/vat-vattp.js @@ -282,8 +282,12 @@ export function buildRootObject(vatPowers, _vatParams, baggage) { }; // Expose the service - return Far('vat-tp handler', { - ...serviceMailboxFunctions, - ...serviceNetworkFunctions, - }); + return makeExo( + 'vat-tp handler', + M.interface('vat-tp handler', {}, { defaultGuards: 'passable' }), + { + ...serviceMailboxFunctions, + ...serviceNetworkFunctions, + }, + ); } diff --git a/packages/SwingSet/test/basedir-circular/bootstrap.js b/packages/SwingSet/test/basedir-circular/bootstrap.js index 059f96e7bd8..c7b467797db 100644 --- a/packages/SwingSet/test/basedir-circular/bootstrap.js +++ b/packages/SwingSet/test/basedir-circular/bootstrap.js @@ -1,11 +1,15 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - const pa = E(vats.bob).genPromise1(); - const pb = E(vats.bob).genPromise2(); - E(vats.bob).usePromises([pa], [pb]); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const pa = E(vats.bob).genPromise1(); + const pb = E(vats.bob).genPromise2(); + E(vats.bob).usePromises([pa], [pb]); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-circular/vat-bob.js b/packages/SwingSet/test/basedir-circular/vat-bob.js index a7c4315e109..4e6bcb3e914 100644 --- a/packages/SwingSet/test/basedir-circular/vat-bob.js +++ b/packages/SwingSet/test/basedir-circular/vat-bob.js @@ -13,18 +13,22 @@ export function buildRootObject() { let r1; let p2; let r2; - return Far('root', { - genPromise1() { - void ([p1, r1] = makePR()); - return p1; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + genPromise1() { + void ([p1, r1] = makePR()); + return p1; + }, + genPromise2() { + void ([p2, r2] = makePR()); + return p2; + }, + usePromises(pa, pb) { + r1(pb); + r2(pa); + }, }, - genPromise2() { - void ([p2, r2] = makePR()); - return p2; - }, - usePromises(pa, pb) { - r1(pb); - r2(pa); - }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-controller-2/bootstrap.js b/packages/SwingSet/test/basedir-controller-2/bootstrap.js index e540a489f8e..dca8bb36d45 100644 --- a/packages/SwingSet/test/basedir-controller-2/bootstrap.js +++ b/packages/SwingSet/test/basedir-controller-2/bootstrap.js @@ -2,12 +2,16 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { vatPowers.testLog(`buildRootObject called`); - return Far('root', { - bootstrap: () => { - vatPowers.testLog(`bootstrap called`); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap: () => { + vatPowers.testLog(`bootstrap called`); + }, + doMore: () => { + vatPowers.testLog(`more stuff`); + }, }, - doMore: () => { - vatPowers.testLog(`more stuff`); - }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-controller-3/bootstrap.js b/packages/SwingSet/test/basedir-controller-3/bootstrap.js index 8ac3242fc66..8ce8c70d555 100644 --- a/packages/SwingSet/test/basedir-controller-3/bootstrap.js +++ b/packages/SwingSet/test/basedir-controller-3/bootstrap.js @@ -1,10 +1,14 @@ import { Far, E } from '@endo/far'; export function buildRootObject(vatPowers) { - return Far('root', { - bootstrap(vats) { - vatPowers.testLog(`bootstrap.obj0.bootstrap()`); - E(vats.left).foo(1, vats.right); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + vatPowers.testLog(`bootstrap.obj0.bootstrap()`); + E(vats.left).foo(1, vats.right); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-controller-3/vat-left.js b/packages/SwingSet/test/basedir-controller-3/vat-left.js index 0ca7f0b49a0..aba021687e8 100644 --- a/packages/SwingSet/test/basedir-controller-3/vat-left.js +++ b/packages/SwingSet/test/basedir-controller-3/vat-left.js @@ -1,10 +1,14 @@ import { Far, E } from '@endo/far'; export function buildRootObject(vatPowers) { - return Far('root', { - foo(arg1, right) { - vatPowers.testLog(`left.foo ${arg1}`); - E(right).bar(2, right); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + foo(arg1, right) { + vatPowers.testLog(`left.foo ${arg1}`); + E(right).bar(2, right); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-controller-3/vat-right.js b/packages/SwingSet/test/basedir-controller-3/vat-right.js index e382ed7d964..04d50f62f5f 100644 --- a/packages/SwingSet/test/basedir-controller-3/vat-right.js +++ b/packages/SwingSet/test/basedir-controller-3/vat-right.js @@ -1,11 +1,15 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { - const obj0 = Far('root', { - bar(arg2, self) { - vatPowers.testLog(`right.obj0.bar ${arg2} ${self === obj0}`); - return 3; + const obj0 = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bar(arg2, self) { + vatPowers.testLog(`right.obj0.bar ${arg2} ${self === obj0}`); + return 3; + }, }, - }); + ); return obj0; } diff --git a/packages/SwingSet/test/basedir-message-patterns/bootstrap-comms.js b/packages/SwingSet/test/basedir-message-patterns/bootstrap-comms.js index a25b45f9df0..1bc74f384a4 100644 --- a/packages/SwingSet/test/basedir-message-patterns/bootstrap-comms.js +++ b/packages/SwingSet/test/basedir-message-patterns/bootstrap-comms.js @@ -7,67 +7,75 @@ const C = 'C'; export function buildRootObject(vatPowers, vatParameters) { const { D } = vatPowers; - return Far('root', { - async bootstrap(vats, devices) { - const { loopbox } = devices; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const { loopbox } = devices; - // machine A can send and receive through the loopbox - const { vattpA, commsA } = vats; - D(loopbox).registerInboundHandler(A, vattpA); - await E(vattpA).registerMailboxDevice(D(loopbox).getSender(A)); + // machine A can send and receive through the loopbox + const { vattpA, commsA } = vats; + D(loopbox).registerInboundHandler(A, vattpA); + await E(vattpA).registerMailboxDevice(D(loopbox).getSender(A)); - // machine B can send and receive through the loopbox - const { vattpB, commsB } = vats; - D(loopbox).registerInboundHandler(B, vattpB); - await E(vattpB).registerMailboxDevice(D(loopbox).getSender(B)); + // machine B can send and receive through the loopbox + const { vattpB, commsB } = vats; + D(loopbox).registerInboundHandler(B, vattpB); + await E(vattpB).registerMailboxDevice(D(loopbox).getSender(B)); - // machine C can send and receive through the loopbox - const { vattpC, commsC } = vats; - D(loopbox).registerInboundHandler(C, vattpC); - await E(vattpC).registerMailboxDevice(D(loopbox).getSender(C)); + // machine C can send and receive through the loopbox + const { vattpC, commsC } = vats; + D(loopbox).registerInboundHandler(C, vattpC); + await E(vattpC).registerMailboxDevice(D(loopbox).getSender(C)); - // A knows about B - const AtoB = await E(vattpA).addRemote(B); - await E(commsA).addRemote(B, AtoB.transmitter, AtoB.setReceiver); - // B knows about A - const BtoA = await E(vattpB).addRemote(A); - await E(commsB).addRemote(A, BtoA.transmitter, BtoA.setReceiver); + // A knows about B + const AtoB = await E(vattpA).addRemote(B); + await E(commsA).addRemote(B, AtoB.transmitter, AtoB.setReceiver); + // B knows about A + const BtoA = await E(vattpB).addRemote(A); + await E(commsB).addRemote(A, BtoA.transmitter, BtoA.setReceiver); - // A knows about C - const AtoC = await E(vattpA).addRemote(C); - await E(commsA).addRemote(C, AtoC.transmitter, AtoC.setReceiver); - // C knows about A - const CtoA = await E(vattpC).addRemote(A); - await E(commsC).addRemote(A, CtoA.transmitter, CtoA.setReceiver); + // A knows about C + const AtoC = await E(vattpA).addRemote(C); + await E(commsA).addRemote(C, AtoC.transmitter, AtoC.setReceiver); + // C knows about A + const CtoA = await E(vattpC).addRemote(A); + await E(commsC).addRemote(A, CtoA.transmitter, CtoA.setReceiver); - // initialize B, to get the object that we'll export to A - const { bob, bert } = await E(vats.b).init(); + // initialize B, to get the object that we'll export to A + const { bob, bert } = await E(vats.b).init(); - // export B's objects to A - const BOB_INDEX = 12; - const BERT_INDEX = 13; - await E(commsB).addEgress(A, BOB_INDEX, bob); - const aBob = await E(commsA).addIngress(B, BOB_INDEX, 'Alleged: bob'); - await E(commsB).addEgress(A, BERT_INDEX, bert); - const aBert = await E(commsA).addIngress(B, BERT_INDEX, 'Alleged: bert'); + // export B's objects to A + const BOB_INDEX = 12; + const BERT_INDEX = 13; + await E(commsB).addEgress(A, BOB_INDEX, bob); + const aBob = await E(commsA).addIngress(B, BOB_INDEX, 'Alleged: bob'); + await E(commsB).addEgress(A, BERT_INDEX, bert); + const aBert = await E(commsA).addIngress( + B, + BERT_INDEX, + 'Alleged: bert', + ); - // initialize C, to get the object that we'll export to A - const { carol } = await E(vats.c).init(); + // initialize C, to get the object that we'll export to A + const { carol } = await E(vats.c).init(); - // export C's objects to A - const CAROL_INDEX = 25; - await E(commsC).addEgress(A, CAROL_INDEX, carol); - const aCarol = await E(commsA).addIngress( - C, - CAROL_INDEX, - 'Alleged: carol', - ); + // export C's objects to A + const CAROL_INDEX = 25; + await E(commsC).addEgress(A, CAROL_INDEX, carol); + const aCarol = await E(commsA).addIngress( + C, + CAROL_INDEX, + 'Alleged: carol', + ); - // initialize A, and give it objects from B and C - await E(vats.a).init(aBob, aBert, aCarol); + // initialize A, and give it objects from B and C + await E(vats.a).init(aBob, aBert, aCarol); - const which = vatParameters.argv[0]; - await E(vats.a).run(which); + const which = vatParameters.argv[0]; + await E(vats.a).run(which); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-message-patterns/bootstrap-local.js b/packages/SwingSet/test/basedir-message-patterns/bootstrap-local.js index 10fb7adbe42..1b76ad146db 100644 --- a/packages/SwingSet/test/basedir-message-patterns/bootstrap-local.js +++ b/packages/SwingSet/test/basedir-message-patterns/bootstrap-local.js @@ -1,18 +1,22 @@ import { Far, E } from '@endo/far'; export function buildRootObject(_vatPowers, vatParameters) { - return Far('root', { - async bootstrap(vats, _devices) { - // initialize B, to get the object that we'll export to A - const { bob, bert } = await E(vats.b).init(); - // initialize C, to get the object that we'll export to A - const { carol } = await E(vats.c).init(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, _devices) { + // initialize B, to get the object that we'll export to A + const { bob, bert } = await E(vats.b).init(); + // initialize C, to get the object that we'll export to A + const { carol } = await E(vats.c).init(); - // initialize A, and give it objects from B and C - await E(vats.a).init(bob, bert, carol); + // initialize A, and give it objects from B and C + await E(vats.a).init(bob, bert, carol); - const which = vatParameters.argv[0]; - await E(vats.a).run(which); + const which = vatParameters.argv[0]; + await E(vats.a).run(which); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-message-patterns/vat-a.js b/packages/SwingSet/test/basedir-message-patterns/vat-a.js index 0f288eb24a3..c20e57db04f 100644 --- a/packages/SwingSet/test/basedir-message-patterns/vat-a.js +++ b/packages/SwingSet/test/basedir-message-patterns/vat-a.js @@ -2,23 +2,31 @@ import { Far } from '@endo/far'; import { buildPatterns } from '../message-patterns.js'; export function buildRootObject(vatPowers) { - const amy = Far('amy', {}); + const amy = makeExo( + 'amy', + M.interface('amy', {}, { defaultGuards: 'passable' }), + {}, + ); let alice; - const root = Far('root', { - init(bob, bert, carol) { - const { setA, setB, setC, objA } = buildPatterns(vatPowers.testLog); - alice = objA; - const a = harden({ alice, amy }); - setA(a); - setB(harden({ bob, bert })); - setC(harden({ carol })); - return a; - }, + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + init(bob, bert, carol) { + const { setA, setB, setC, objA } = buildPatterns(vatPowers.testLog); + alice = objA; + const a = harden({ alice, amy }); + setA(a); + setB(harden({ bob, bert })); + setC(harden({ carol })); + return a; + }, - async run(which) { - await alice[which](); + async run(which) { + await alice[which](); + }, }, - }); + ); return root; } diff --git a/packages/SwingSet/test/basedir-message-patterns/vat-b.js b/packages/SwingSet/test/basedir-message-patterns/vat-b.js index a30b50f8f1e..9d744bec98c 100644 --- a/packages/SwingSet/test/basedir-message-patterns/vat-b.js +++ b/packages/SwingSet/test/basedir-message-patterns/vat-b.js @@ -2,27 +2,39 @@ import { Far } from '@endo/far'; import { buildPatterns } from '../message-patterns.js'; export function buildRootObject(vatPowers) { - const bert = Far('bert', { - toString: () => 'obj-bert', - log_bert: msg => { - vatPowers.testLog(msg); + const bert = makeExo( + 'bert', + M.interface('bert', {}, { defaultGuards: 'passable' }), + { + toString: () => 'obj-bert', + log_bert: msg => { + vatPowers.testLog(msg); + }, }, - }); - const bill = Far('bill', { - toString: () => 'obj-bill', - log_bill(msg) { - vatPowers.testLog(msg); + ); + const bill = makeExo( + 'bill', + M.interface('bill', {}, { defaultGuards: 'passable' }), + { + toString: () => 'obj-bill', + log_bill(msg) { + vatPowers.testLog(msg); + }, }, - }); + ); - const root = Far('root', { - init() { - const { setB, objB } = buildPatterns(vatPowers.testLog); - const bob = objB; - const b = harden({ bob, bert, bill }); - setB(b); - return harden({ bob, bert }); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + init() { + const { setB, objB } = buildPatterns(vatPowers.testLog); + const bob = objB; + const b = harden({ bob, bert, bill }); + setB(b); + return harden({ bob, bert }); + }, }, - }); + ); return root; } diff --git a/packages/SwingSet/test/basedir-message-patterns/vat-c.js b/packages/SwingSet/test/basedir-message-patterns/vat-c.js index f9f00f9b9cd..97cce5d0d9d 100644 --- a/packages/SwingSet/test/basedir-message-patterns/vat-c.js +++ b/packages/SwingSet/test/basedir-message-patterns/vat-c.js @@ -2,14 +2,18 @@ import { Far } from '@endo/far'; import { buildPatterns } from '../message-patterns.js'; export function buildRootObject(vatPowers) { - const root = Far('root', { - init() { - const { setC, objC } = buildPatterns(vatPowers.testLog); - const carol = objC; - const c = harden({ carol }); - setC(c); - return harden({ carol }); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + init() { + const { setC, objC } = buildPatterns(vatPowers.testLog); + const carol = objC; + const c = harden({ carol }); + setC(c); + return harden({ carol }); + }, }, - }); + ); return root; } diff --git a/packages/SwingSet/test/basedir-promises-2/bootstrap.js b/packages/SwingSet/test/basedir-promises-2/bootstrap.js index a67d406a3ff..b64afba67ba 100644 --- a/packages/SwingSet/test/basedir-promises-2/bootstrap.js +++ b/packages/SwingSet/test/basedir-promises-2/bootstrap.js @@ -4,33 +4,37 @@ import { Fail } from '@agoric/assert'; export function buildRootObject(vatPowers, vatParameters) { const log = vatPowers.testLog; - return Far('root', { - bootstrap(vats) { - const { argv } = vatParameters; - const mode = argv[0]; - if (mode === 'harden-promise-1') { - const { promise: p1 } = makePromiseKit(); - void harden(p1); - const allP = []; - // in bug #95, this first call returns a (correctly) frozen Promise, - // but for the wrong reasons - const p2 = E(vats.left).checkHarden(p1); - log(`p2 frozen ${Object.isFrozen(p2)}`); - allP.push(p2); - // but this one does not: - const p3 = E(p2).checkHarden(p1); - log(`p3 frozen ${Object.isFrozen(p3)}`); - allP.push(p3); - // TODO: this one doesn't get frozen, but we wish it did - // const p4 = vats.left!checkHarden(p1); - // log(`p4 frozen ${Object.isFrozen(p4)}`); - // allP.push(p4); - return Promise.all(allP).then(_ => { - log(`b.harden-promise-1.finish`); - }); - } else { - throw Fail`unknown mode ${mode}`; - } + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const { argv } = vatParameters; + const mode = argv[0]; + if (mode === 'harden-promise-1') { + const { promise: p1 } = makePromiseKit(); + void harden(p1); + const allP = []; + // in bug #95, this first call returns a (correctly) frozen Promise, + // but for the wrong reasons + const p2 = E(vats.left).checkHarden(p1); + log(`p2 frozen ${Object.isFrozen(p2)}`); + allP.push(p2); + // but this one does not: + const p3 = E(p2).checkHarden(p1); + log(`p3 frozen ${Object.isFrozen(p3)}`); + allP.push(p3); + // TODO: this one doesn't get frozen, but we wish it did + // const p4 = vats.left!checkHarden(p1); + // log(`p4 frozen ${Object.isFrozen(p4)}`); + // allP.push(p4); + return Promise.all(allP).then(_ => { + log(`b.harden-promise-1.finish`); + }); + } else { + throw Fail`unknown mode ${mode}`; + } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-promises-2/vat-left.js b/packages/SwingSet/test/basedir-promises-2/vat-left.js index 8873f98b241..8cd2246c638 100644 --- a/packages/SwingSet/test/basedir-promises-2/vat-left.js +++ b/packages/SwingSet/test/basedir-promises-2/vat-left.js @@ -1,11 +1,15 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { - const obj0 = Far('root', { - checkHarden(o1) { - vatPowers.testLog(`o1 frozen ${Object.isFrozen(o1)}`); - return obj0; + const obj0 = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + checkHarden(o1) { + vatPowers.testLog(`o1 frozen ${Object.isFrozen(o1)}`); + return obj0; + }, }, - }); + ); return obj0; } diff --git a/packages/SwingSet/test/basedir-promises-3/bootstrap.js b/packages/SwingSet/test/basedir-promises-3/bootstrap.js index a77789bb7c2..0a810420b12 100644 --- a/packages/SwingSet/test/basedir-promises-3/bootstrap.js +++ b/packages/SwingSet/test/basedir-promises-3/bootstrap.js @@ -4,18 +4,22 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { const pk1 = makePromiseKit(); const pin = []; - return Far('root', { - bootstrap(vats) { - pin.push(vats.right); // pin so test can send 'three' to it later - const p2 = E(vats.right).one(); // p2 is kp41 - E(p2).four(pk1.promise); - // that puts an unresolved promise in the arguments of the promise - // queue for p2 + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + pin.push(vats.right); // pin so test can send 'three' to it later + const p2 = E(vats.right).one(); // p2 is kp41 + E(p2).four(pk1.promise); + // that puts an unresolved promise in the arguments of the promise + // queue for p2 + }, + two() { + pk1.resolve(3); + // The promise is resolved and retired from our clist, the only + // remaining reference is from the p2 promise queue + }, }, - two() { - pk1.resolve(3); - // The promise is resolved and retired from our clist, the only - // remaining reference is from the p2 promise queue - }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-promises-3/vat-right.js b/packages/SwingSet/test/basedir-promises-3/vat-right.js index 94e16c02877..0b84bf8db54 100644 --- a/packages/SwingSet/test/basedir-promises-3/vat-right.js +++ b/packages/SwingSet/test/basedir-promises-3/vat-right.js @@ -4,22 +4,30 @@ import { makePromiseKit } from '@endo/promise-kit'; export function buildRootObject() { const pk3 = makePromiseKit(); const pk4 = makePromiseKit(); - const t2 = Far('t2', { - four(arg) { - // arg should be a Promise that promptly resolves to 4 - const argP = Promise.resolve(arg); - const wasP = argP === arg; - return argP.then(newArg => pk4.resolve([wasP, newArg])); + const t2 = makeExo( + 't2', + M.interface('t2', {}, { defaultGuards: 'passable' }), + { + four(arg) { + // arg should be a Promise that promptly resolves to 4 + const argP = Promise.resolve(arg); + const wasP = argP === arg; + return argP.then(newArg => pk4.resolve([wasP, newArg])); + }, }, - }); + ); - return Far('root', { - one() { - return pk3.promise; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + one() { + return pk3.promise; + }, + three() { + pk3.resolve(t2); + return pk4.promise; + }, }, - three() { - pk3.resolve(t2); - return pk4.promise; - }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-promises/bootstrap.js b/packages/SwingSet/test/basedir-promises/bootstrap.js index a5ef76fc22e..a622cf62d77 100644 --- a/packages/SwingSet/test/basedir-promises/bootstrap.js +++ b/packages/SwingSet/test/basedir-promises/bootstrap.js @@ -5,77 +5,93 @@ import { Fail } from '@agoric/assert'; export function buildRootObject(vatPowers, vatParameters) { const log = vatPowers.testLog; - return Far('root', { - bootstrap(vats) { - const mode = vatParameters.argv[0]; - if (mode === 'flush') { - void Promise.resolve('then1').then(log); - void Promise.resolve('then2').then(log); - } else if (mode === 'e-then') { - E(vats.left) - .callRight(1, vats.right) - .then( - r => log(`b.resolved ${r}`), - err => log(`b.rejected ${err}`), + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const mode = vatParameters.argv[0]; + if (mode === 'flush') { + void Promise.resolve('then1').then(log); + void Promise.resolve('then2').then(log); + } else if (mode === 'e-then') { + E(vats.left) + .callRight(1, vats.right) + .then( + r => log(`b.resolved ${r}`), + err => log(`b.rejected ${err}`), + ); + } else if (mode === 'chain1') { + const p1 = E(vats.left).call2(1); + const p2 = E(p1).call3(2); + p2.then(x => log(`b.resolved ${x}`)); + log(`b.call2`); + } else if (mode === 'chain2') { + const p1 = E(Promise.resolve(vats.left)).call2(1); + const p2 = E(p1).call3(2); + p2.then(x => log(`b.resolved ${x}`)); + log(`b.call2`); + } else if (mode === 'local1') { + const t1 = makeExo( + 't1', + M.interface('t1', {}, { defaultGuards: 'passable' }), + { + foo(arg) { + log(`local.foo ${arg}`); + return 2; + }, + }, ); - } else if (mode === 'chain1') { - const p1 = E(vats.left).call2(1); - const p2 = E(p1).call3(2); - p2.then(x => log(`b.resolved ${x}`)); - log(`b.call2`); - } else if (mode === 'chain2') { - const p1 = E(Promise.resolve(vats.left)).call2(1); - const p2 = E(p1).call3(2); - p2.then(x => log(`b.resolved ${x}`)); - log(`b.call2`); - } else if (mode === 'local1') { - const t1 = Far('t1', { - foo(arg) { - log(`local.foo ${arg}`); - return 2; - }, - }); - const p1 = E(t1).foo(1); - void p1.then(x => log(`b.resolved ${x}`)); - log(`b.local1.finish`); - } else if (mode === 'local2') { - const t1 = Far('t1', { - foo(arg) { - log(`local.foo ${arg}`); - return 3; - }, - }); - const p1 = E(vats.left).returnArg(t1); - const p2 = E(p1).foo(2); - p2.then(x => log(`b.resolved ${x}`)); - log(`b.local2.finish`); - } else if (mode === 'send-promise1') { - const t1 = Far('t1', { - foo(arg) { - log(`local.foo ${arg}`); - return 3; - }, - }); - const { promise: p1, resolve: r1 } = makePromiseKit(); - const p2 = E(vats.left).takePromise(p1); - p2.then(x => log(`b.resolved ${x}`)); - r1(t1); - log(`b.send-promise1.finish`); - } else if (mode === 'send-promise2') { - // the promise we send actually resolves to their side, not ours. In - // the future this should short-circuit us. - const p1 = E(vats.left).returnMyObject(); - const p2 = E(vats.left).takePromise(p1); - p2.then(x => log(`b.resolved ${x}`)); - log(`b.send-promise2.finish`); - } else if (mode === 'call-promise1') { - const p1 = E(vats.left).returnMyObject(); - const p2 = E(p1).foo(); - p2.then(x => log(`b.resolved ${x}`)); - log(`b.call-promise1.finish`); - } else { - Fail`unknown mode ${mode}`; - } + const p1 = E(t1).foo(1); + void p1.then(x => log(`b.resolved ${x}`)); + log(`b.local1.finish`); + } else if (mode === 'local2') { + const t1 = makeExo( + 't1', + M.interface('t1', {}, { defaultGuards: 'passable' }), + { + foo(arg) { + log(`local.foo ${arg}`); + return 3; + }, + }, + ); + const p1 = E(vats.left).returnArg(t1); + const p2 = E(p1).foo(2); + p2.then(x => log(`b.resolved ${x}`)); + log(`b.local2.finish`); + } else if (mode === 'send-promise1') { + const t1 = makeExo( + 't1', + M.interface('t1', {}, { defaultGuards: 'passable' }), + { + foo(arg) { + log(`local.foo ${arg}`); + return 3; + }, + }, + ); + const { promise: p1, resolve: r1 } = makePromiseKit(); + const p2 = E(vats.left).takePromise(p1); + p2.then(x => log(`b.resolved ${x}`)); + r1(t1); + log(`b.send-promise1.finish`); + } else if (mode === 'send-promise2') { + // the promise we send actually resolves to their side, not ours. In + // the future this should short-circuit us. + const p1 = E(vats.left).returnMyObject(); + const p2 = E(vats.left).takePromise(p1); + p2.then(x => log(`b.resolved ${x}`)); + log(`b.send-promise2.finish`); + } else if (mode === 'call-promise1') { + const p1 = E(vats.left).returnMyObject(); + const p2 = E(p1).foo(); + p2.then(x => log(`b.resolved ${x}`)); + log(`b.call-promise1.finish`); + } else { + Fail`unknown mode ${mode}`; + } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-promises/vat-left.js b/packages/SwingSet/test/basedir-promises/vat-left.js index 916f97e9429..f5b656942ee 100644 --- a/packages/SwingSet/test/basedir-promises/vat-left.js +++ b/packages/SwingSet/test/basedir-promises/vat-left.js @@ -2,47 +2,59 @@ import { Far, E } from '@endo/far'; export function buildRootObject(vatPowers) { const log = vatPowers.testLog; - const obj0 = Far('root', { - callRight(arg1, right) { - log(`left.callRight ${arg1}`); - E(right) - .bar(2) - .then(a => log(`left.then ${a}`)); - return 3; - }, - call2(arg) { - log(`left.call2 ${arg}`); - return Far('iface', { - call3(x) { - log(`left.call3 ${x}`); - return 3; - }, - }); - }, + const obj0 = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + callRight(arg1, right) { + log(`left.callRight ${arg1}`); + E(right) + .bar(2) + .then(a => log(`left.then ${a}`)); + return 3; + }, + call2(arg) { + log(`left.call2 ${arg}`); + return makeExo( + 'iface', + M.interface('iface', {}, { defaultGuards: 'passable' }), + { + call3(x) { + log(`left.call3 ${x}`); + return 3; + }, + }, + ); + }, - returnArg(arg) { - log(`left.returnArg`); - return arg; - }, + returnArg(arg) { + log(`left.returnArg`); + return arg; + }, - returnMyObject() { - return Far('iface', { - foo(x) { - log(`left.myobject.call ${x}`); - }, - }); - }, + returnMyObject() { + return makeExo( + 'iface', + M.interface('iface', {}, { defaultGuards: 'passable' }), + { + foo(x) { + log(`left.myobject.call ${x}`); + }, + }, + ); + }, - takePromise(p1) { - log(`left.takePromise`); - return harden( - p1.then(t1 => { - log(`left.takePromise.then`); - E(t1).foo(1); - return 4; - }), - ); + takePromise(p1) { + log(`left.takePromise`); + return harden( + p1.then(t1 => { + log(`left.takePromise.then`); + E(t1).foo(1); + return 4; + }), + ); + }, }, - }); + ); return obj0; } diff --git a/packages/SwingSet/test/basedir-promises/vat-right.js b/packages/SwingSet/test/basedir-promises/vat-right.js index 9580a404b86..2d909a3343e 100644 --- a/packages/SwingSet/test/basedir-promises/vat-right.js +++ b/packages/SwingSet/test/basedir-promises/vat-right.js @@ -1,10 +1,14 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { - return Far('root', { - bar(arg2) { - vatPowers.testLog(`right ${arg2}`); - return 4; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bar(arg2) { + vatPowers.testLog(`right ${arg2}`); + return 4; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-transcript/bootstrap.js b/packages/SwingSet/test/basedir-transcript/bootstrap.js index 917f5abe142..5f280b77df3 100644 --- a/packages/SwingSet/test/basedir-transcript/bootstrap.js +++ b/packages/SwingSet/test/basedir-transcript/bootstrap.js @@ -2,19 +2,23 @@ import { Far, E } from '@endo/far'; import { Fail } from '@agoric/assert'; export function buildRootObject(vatPowers, vatParameters) { - return Far('root', { - bootstrap(vats) { - const mode = vatParameters.argv[0]; - if (mode === 'one') { - E(vats.left) - .callRight(1, vats.right) - .then( - r => vatPowers.testLog(`b.resolved ${r}`), - err => vatPowers.testLog(`b.rejected ${err}`), - ); - } else { - Fail`unknown mode ${mode}`; - } + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const mode = vatParameters.argv[0]; + if (mode === 'one') { + E(vats.left) + .callRight(1, vats.right) + .then( + r => vatPowers.testLog(`b.resolved ${r}`), + err => vatPowers.testLog(`b.rejected ${err}`), + ); + } else { + Fail`unknown mode ${mode}`; + } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/basedir-transcript/vat-left.js b/packages/SwingSet/test/basedir-transcript/vat-left.js index 2d2ad679f62..e97e9cb640a 100644 --- a/packages/SwingSet/test/basedir-transcript/vat-left.js +++ b/packages/SwingSet/test/basedir-transcript/vat-left.js @@ -2,14 +2,18 @@ import { Far, E } from '@endo/far'; export function buildRootObject(vatPowers) { const log = vatPowers.testLog; - const obj0 = Far('root', { - callRight(arg1, right) { - log(`left.callRight ${arg1}`); - E(right) - .bar(2) - .then(a => log(`left.then ${a}`)); - return 3; + const obj0 = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + callRight(arg1, right) { + log(`left.callRight ${arg1}`); + E(right) + .bar(2) + .then(a => log(`left.then ${a}`)); + return 3; + }, }, - }); + ); return obj0; } diff --git a/packages/SwingSet/test/basedir-transcript/vat-right.js b/packages/SwingSet/test/basedir-transcript/vat-right.js index 9580a404b86..2d909a3343e 100644 --- a/packages/SwingSet/test/basedir-transcript/vat-right.js +++ b/packages/SwingSet/test/basedir-transcript/vat-right.js @@ -1,10 +1,14 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { - return Far('root', { - bar(arg2) { - vatPowers.testLog(`right ${arg2}`); - return 4; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bar(arg2) { + vatPowers.testLog(`right ${arg2}`); + return 4; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/bootstrap-syscall-failure.js b/packages/SwingSet/test/bootstrap-syscall-failure.js index 7b5e3780046..a976e5dd349 100644 --- a/packages/SwingSet/test/bootstrap-syscall-failure.js +++ b/packages/SwingSet/test/bootstrap-syscall-failure.js @@ -3,43 +3,51 @@ import { Far, E } from '@endo/far'; export function buildRootObject(vatPowers, vatParameters) { const { testLog } = vatPowers; - const ourThing = Far('ourThing', { - pretendToBeAThing(from) { - testLog(`pretendToBeAThing invoked from ${from}`); + const ourThing = makeExo( + 'ourThing', + M.interface('ourThing', {}, { defaultGuards: 'passable' }), + { + pretendToBeAThing(from) { + testLog(`pretendToBeAThing invoked from ${from}`); + }, }, - }); - const self = Far('root', { - async bootstrap(vats, devices) { - testLog('bootstrap'); - let badvat; - if (vatParameters.beDynamic) { - const vatMaker = E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, + ); + const self = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + testLog('bootstrap'); + let badvat; + if (vatParameters.beDynamic) { + const vatMaker = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + const vat = await E(vatMaker).createVatByName('badvat', { + enableSetup: true, + }); + badvat = vat.root; + } else { + badvat = vats.badvatStatic; + } + const p1 = E(badvat).begood(ourThing); + p1.then( + () => testLog('p1 resolve (bad!)'), + e => testLog(`p1 reject ${e}`), ); - const vat = await E(vatMaker).createVatByName('badvat', { - enableSetup: true, - }); - badvat = vat.root; - } else { - badvat = vats.badvatStatic; - } - const p1 = E(badvat).begood(ourThing); - p1.then( - () => testLog('p1 resolve (bad!)'), - e => testLog(`p1 reject ${e}`), - ); - const p2 = E(badvat).bebad(ourThing); - p2.then( - () => testLog('p2 resolve (bad!)'), - e => testLog(`p2 reject ${e}`), - ); - const p3 = E(badvat).begoodagain(ourThing); - p3.then( - () => testLog('p3 resolve (bad!)'), - e => testLog(`p3 reject ${e}`), - ); - testLog('bootstrap done'); + const p2 = E(badvat).bebad(ourThing); + p2.then( + () => testLog('p2 resolve (bad!)'), + e => testLog(`p2 reject ${e}`), + ); + const p3 = E(badvat).begoodagain(ourThing); + p3.then( + () => testLog('p3 resolve (bad!)'), + e => testLog(`p3 reject ${e}`), + ); + testLog('bootstrap done'); + }, }, - }); + ); return self; } diff --git a/packages/SwingSet/test/bundling/bootstrap-bundles.js b/packages/SwingSet/test/bundling/bootstrap-bundles.js index 93e20095c07..7780b8c891f 100644 --- a/packages/SwingSet/test/bundling/bootstrap-bundles.js +++ b/packages/SwingSet/test/bundling/bootstrap-bundles.js @@ -25,75 +25,81 @@ export function buildRootObject(vatPowers) { return [out[0], ok]; } - return Far('root', { - async bootstrap(v0, devices) { - vats = v0; - // we exercise a little bit of vatAdmin, but this test is mostly about - // bundles - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - }, - - async checkConfiguredVats() { - const hello = await E(vats.named).hi(); - return [hello]; - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(v0, devices) { + vats = v0; + // we exercise a little bit of vatAdmin, but this test is mostly about + // bundles + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + }, - async vatFromNamedBundleCap(name, method) { - const bcap = await E(vatAdmin).getNamedBundleCap(name); - const { root } = await E(vatAdmin).createVat(bcap); - const hello = await E(root)[method](); - return [hello]; - }, + async checkConfiguredVats() { + const hello = await E(vats.named).hi(); + return [hello]; + }, - // TODO: this will go away when we remove va~.createVatByName - async vatByName(name, method) { - const { root } = await E(vatAdmin).createVatByName(name); - const hello = await E(root)[method](); - return [hello]; - }, + async vatFromNamedBundleCap(name, method) { + const bcap = await E(vatAdmin).getNamedBundleCap(name); + const { root } = await E(vatAdmin).createVat(bcap); + const hello = await E(root)[method](); + return [hello]; + }, - async idByName(name) { - const id = await E(vatAdmin).getBundleIDByName(name); - return id; - }, + // TODO: this will go away when we remove va~.createVatByName + async vatByName(name, method) { + const { root } = await E(vatAdmin).createVatByName(name); + const hello = await E(root)[method](); + return [hello]; + }, - async vatFromID(id, method) { - const bcap = await E(vatAdmin).getBundleCap(id); - const { root } = await E(vatAdmin).createVat(bcap); - const hello = await E(root)[method](); - return [hello]; - }, + async idByName(name) { + const id = await E(vatAdmin).getBundleIDByName(name); + return id; + }, - waitForBundleCap(id) { - // bad bundleIDs should throw, missing bundleIDs should wait (hang) - return E(vatAdmin).waitForBundleCap(id); - }, + async vatFromID(id, method) { + const bcap = await E(vatAdmin).getBundleCap(id); + const { root } = await E(vatAdmin).createVat(bcap); + const hello = await E(root)[method](); + return [hello]; + }, - getBundleCap(id) { - // bad bundleIDs should throw, missing bundleIDs should throw - return E(vatAdmin).getBundleCap(id); - }, + waitForBundleCap(id) { + // bad bundleIDs should throw, missing bundleIDs should wait (hang) + return E(vatAdmin).waitForBundleCap(id); + }, - async getBundle(id) { - const bcap = await E(vatAdmin).getBundleCap(id); - return D(bcap).getBundle(); - }, + getBundleCap(id) { + // bad bundleIDs should throw, missing bundleIDs should throw + return E(vatAdmin).getBundleCap(id); + }, - async checkImportByID(id) { - async function getCap() { + async getBundle(id) { const bcap = await E(vatAdmin).getBundleCap(id); - assert.equal(D(bcap).getBundleID(), id); - return bcap; - } - return checkImport(getCap); - }, + return D(bcap).getBundle(); + }, - async checkImportByName(name) { - async function getCap() { - const bcap = await E(vatAdmin).getNamedBundleCap(name); - return bcap; - } - return checkImport(getCap); + async checkImportByID(id) { + async function getCap() { + const bcap = await E(vatAdmin).getBundleCap(id); + assert.equal(D(bcap).getBundleID(), id); + return bcap; + } + return checkImport(getCap); + }, + + async checkImportByName(name) { + async function getCap() { + const bcap = await E(vatAdmin).getNamedBundleCap(name); + return bcap; + } + return checkImport(getCap); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/bundling/vat-disk.js b/packages/SwingSet/test/bundling/vat-disk.js index 9d2e819250c..b27753c6510 100644 --- a/packages/SwingSet/test/bundling/vat-disk.js +++ b/packages/SwingSet/test/bundling/vat-disk.js @@ -1,9 +1,13 @@ import { Far } from '@endo/far'; export function buildRootObject() { - return Far('root', { - disk() { - return 'otech'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + disk() { + return 'otech'; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/bundling/vat-install.js b/packages/SwingSet/test/bundling/vat-install.js index e0b80123b74..0b9c554eb65 100644 --- a/packages/SwingSet/test/bundling/vat-install.js +++ b/packages/SwingSet/test/bundling/vat-install.js @@ -1,9 +1,13 @@ import { Far } from '@endo/far'; export function buildRootObject() { - return Far('root', { - runtime() { - return 'installed'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + runtime() { + return 'installed'; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/bundling/vat-named.js b/packages/SwingSet/test/bundling/vat-named.js index ab51e9a338f..49c0929a317 100644 --- a/packages/SwingSet/test/bundling/vat-named.js +++ b/packages/SwingSet/test/bundling/vat-named.js @@ -1,9 +1,13 @@ import { Far } from '@endo/far'; export function buildRootObject() { - return Far('root', { - hi() { - return 'hello'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + hi() { + return 'hello'; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/change-parameters/bootstrap-change-parameters.js b/packages/SwingSet/test/change-parameters/bootstrap-change-parameters.js index 908a11fab70..a06f6c606c8 100644 --- a/packages/SwingSet/test/change-parameters/bootstrap-change-parameters.js +++ b/packages/SwingSet/test/change-parameters/bootstrap-change-parameters.js @@ -5,27 +5,33 @@ export function buildRootObject() { let carolRoot; let carolAdmin; - return Far('root', { - async bootstrap(vats, devices) { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + }, - async prepare() { - // build Carol, the vat being changed - const bcap = await E(vatAdmin).getNamedBundleCap('carol'); - const res = await E(vatAdmin).createVat(bcap); - carolRoot = res.root; - carolAdmin = res.adminNode; - await E(carolRoot).doSomething(); - }, + async prepare() { + // build Carol, the vat being changed + const bcap = await E(vatAdmin).getNamedBundleCap('carol'); + const res = await E(vatAdmin).createVat(bcap); + carolRoot = res.root; + carolAdmin = res.adminNode; + await E(carolRoot).doSomething(); + }, - async change(options) { - try { - await E(carolAdmin).changeOptions(options); - return 'ok'; - } catch (e) { - return e.message; - } + async change(options) { + try { + await E(carolAdmin).changeOptions(options); + return 'ok'; + } catch (e) { + return e.message; + } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/change-parameters/vat-carol.js b/packages/SwingSet/test/change-parameters/vat-carol.js index ed24310d72e..2c1f159c785 100644 --- a/packages/SwingSet/test/change-parameters/vat-carol.js +++ b/packages/SwingSet/test/change-parameters/vat-carol.js @@ -1,7 +1,11 @@ import { Far } from '@endo/far'; export function buildRootObject() { - return Far('root', { - doSomething() {}, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + doSomething() {}, + }, + ); } diff --git a/packages/SwingSet/test/definition/vat-liveslots.js b/packages/SwingSet/test/definition/vat-liveslots.js index 1ec70553a95..4a41a073de4 100644 --- a/packages/SwingSet/test/definition/vat-liveslots.js +++ b/packages/SwingSet/test/definition/vat-liveslots.js @@ -2,16 +2,20 @@ import { Far, getInterfaceOf } from '@endo/far'; export function buildRootObject() { let counter = 0; - return Far('root', { - increment() { - counter += 1; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + increment() { + counter += 1; + }, + read() { + return counter; + }, + remotable() { + const r = Far('iface1'); + return getInterfaceOf(r); + }, }, - read() { - return counter; - }, - remotable() { - const r = Far('iface1'); - return getInterfaceOf(r); - }, - }); + ); } diff --git a/packages/SwingSet/test/definition/vat-setup.js b/packages/SwingSet/test/definition/vat-setup.js index 1ec70553a95..4a41a073de4 100644 --- a/packages/SwingSet/test/definition/vat-setup.js +++ b/packages/SwingSet/test/definition/vat-setup.js @@ -2,16 +2,20 @@ import { Far, getInterfaceOf } from '@endo/far'; export function buildRootObject() { let counter = 0; - return Far('root', { - increment() { - counter += 1; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + increment() { + counter += 1; + }, + read() { + return counter; + }, + remotable() { + const r = Far('iface1'); + return getInterfaceOf(r); + }, }, - read() { - return counter; - }, - remotable() { - const r = Far('iface1'); - return getInterfaceOf(r); - }, - }); + ); } diff --git a/packages/SwingSet/test/device-bridge-bootstrap.js b/packages/SwingSet/test/device-bridge-bootstrap.js index 14fe8246bd5..80a8ff2a78e 100644 --- a/packages/SwingSet/test/device-bridge-bootstrap.js +++ b/packages/SwingSet/test/device-bridge-bootstrap.js @@ -2,22 +2,30 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers, vatParameters) { const { D, testLog } = vatPowers; - const handler = Far('handler', { - inbound(...args) { - testLog('inbound'); - testLog(JSON.stringify(args)); + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { + inbound(...args) { + testLog('inbound'); + testLog(JSON.stringify(args)); + }, }, - }); + ); - return Far('root', { - async bootstrap(vats, devices) { - const { argv } = vatParameters; - harden(argv); - D(devices.bridge).registerInboundHandler(handler); - const retval = D(devices.bridge).callOutbound(argv[0], argv[1]); - testLog('outbound retval'); - testLog(JSON.stringify(retval)); - testLog(retval === undefined); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const { argv } = vatParameters; + harden(argv); + D(devices.bridge).registerInboundHandler(handler); + const retval = D(devices.bridge).callOutbound(argv[0], argv[1]); + testLog('outbound retval'); + testLog(JSON.stringify(retval)); + testLog(retval === undefined); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/device-hooks/bootstrap-device-hook.js b/packages/SwingSet/test/device-hooks/bootstrap-device-hook.js index 2ee3f1b1915..c736c059a8b 100644 --- a/packages/SwingSet/test/device-hooks/bootstrap-device-hook.js +++ b/packages/SwingSet/test/device-hooks/bootstrap-device-hook.js @@ -2,70 +2,82 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { const { D } = vatPowers; - const o1 = Far('obj', {}); - const o2 = Far('obj', {}); + const o1 = makeExo( + 'obj', + M.interface('obj', {}, { defaultGuards: 'passable' }), + {}, + ); + const o2 = makeExo( + 'obj', + M.interface('obj', {}, { defaultGuards: 'passable' }), + {}, + ); let hookdev; let devnode; - const root = Far('root', { - async bootstrap(_vats, devices) { - hookdev = devices.hookdev; - }, + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(_vats, devices) { + hookdev = devices.hookdev; + }, - async doCapdata(hookinput) { - return D(hookdev).returnCapdata(hookinput); - }, - async doActual(hookinput) { - return D(hookdev).returnActual(hookinput); - }, + async doCapdata(hookinput) { + return D(hookdev).returnCapdata(hookinput); + }, + async doActual(hookinput) { + return D(hookdev).returnActual(hookinput); + }, - async returnObjects() { - return [root, o1, o2]; - }, + async returnObjects() { + return [root, o1, o2]; + }, - async doObjects() { - return D(hookdev).returnCapdata(root, o1, o2); - }, - async actualObjects() { - return D(hookdev).returnActual(root, o1, o2); - }, - async checkObjects1(data) { - const rroot = D(hookdev).returnActual(data); - return { match: rroot === root, rroot }; - }, - async checkObjects2(data) { - const r2 = D(hookdev).returnActual(data); - return { match: r2 === o2, r2 }; - }, - async checkObjects3(data) { - const rextra2 = D(hookdev).returnActual(data); - return { rextra2 }; - }, - async checkDevNodeIn(data) { - devnode = D(hookdev).returnDevnode(data); - D(hookdev).returnActual(devnode); - return devnode; - }, - async checkDevNodeOut(data) { - const d2 = D(hookdev).returnActual(data); - return { match: d2 === devnode, d2 }; - }, - async throwError(data) { - try { - const ret = D(hookdev).throwError(data); // will throw - return { worked: true, ret }; - } catch (err) { - return { worked: false, err }; - } - }, - async missingHook(data) { - try { - const ret = D(hookdev).missingHook(data); // will throw - return { worked: true, ret }; - } catch (err) { - return { worked: false, err }; - } + async doObjects() { + return D(hookdev).returnCapdata(root, o1, o2); + }, + async actualObjects() { + return D(hookdev).returnActual(root, o1, o2); + }, + async checkObjects1(data) { + const rroot = D(hookdev).returnActual(data); + return { match: rroot === root, rroot }; + }, + async checkObjects2(data) { + const r2 = D(hookdev).returnActual(data); + return { match: r2 === o2, r2 }; + }, + async checkObjects3(data) { + const rextra2 = D(hookdev).returnActual(data); + return { rextra2 }; + }, + async checkDevNodeIn(data) { + devnode = D(hookdev).returnDevnode(data); + D(hookdev).returnActual(devnode); + return devnode; + }, + async checkDevNodeOut(data) { + const d2 = D(hookdev).returnActual(data); + return { match: d2 === devnode, d2 }; + }, + async throwError(data) { + try { + const ret = D(hookdev).throwError(data); // will throw + return { worked: true, ret }; + } catch (err) { + return { worked: false, err }; + } + }, + async missingHook(data) { + try { + const ret = D(hookdev).missingHook(data); // will throw + return { worked: true, ret }; + } catch (err) { + return { worked: false, err }; + } + }, }, - }); + ); return root; } diff --git a/packages/SwingSet/test/device-mailbox/bootstrap-device-mailbox.js b/packages/SwingSet/test/device-mailbox/bootstrap-device-mailbox.js index 2739b4266d6..a8661b6a68a 100644 --- a/packages/SwingSet/test/device-mailbox/bootstrap-device-mailbox.js +++ b/packages/SwingSet/test/device-mailbox/bootstrap-device-mailbox.js @@ -4,54 +4,66 @@ import { Fail } from '@agoric/assert'; export function buildRootObject(vatPowers, vatParameters) { const { D, testLog: log } = vatPowers; let numReceived = 0; - return Far('root', { - async bootstrap(vats, devices) { - const { argv } = vatParameters; - if (argv[0] === 'mailbox1') { - D(devices.mailbox).add('peer1', 1, 'data1'); - D(devices.mailbox).add('peer1', 2, 'data2'); - D(devices.mailbox).add('peer1', 3, 'data3'); - D(devices.mailbox).ackInbound('peer1', 12); - D(devices.mailbox).ackInbound('peer1', 13); - D(devices.mailbox).add('peer2', 4, 'data4'); - D(devices.mailbox).add('peer3', 5, 'data5'); - D(devices.mailbox).remove('peer1', 1); - D(devices.mailbox).remove('peer2', 4, 'data4'); - // should leave peer1: [data2,data3], peer2: [], peer3: [data5] - } else if (argv[0] === 'mailbox2') { - const handler = Far('mailbox', { - deliverInboundMessages(peer, messages) { - log(`dm-${peer}`); - for (const m of messages) { - log(`m-${m[0]}-${m[1]}`); - } - }, - deliverInboundAck(peer, ack) { - log(`da-${peer}-${ack}`); - }, - }); - D(devices.mailbox).registerInboundHandler(handler); - } else if (argv[0] === 'mailbox-determinism') { - D(devices.mailbox).registerInboundHandler(vats.vattp); - await E(vats.vattp).registerMailboxDevice(devices.mailbox); - const name = 'peer1'; - const { setReceiver } = await E(vats.vattp).addRemote(name); - const receiver = Far('receiver', { - receive(body) { - numReceived += 1; - log(`comms receive ${body}`); - }, - }); - await E(setReceiver).setReceiver(receiver); - } else { - Fail`unknown argv mode '${argv[0]}'`; - } + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const { argv } = vatParameters; + if (argv[0] === 'mailbox1') { + D(devices.mailbox).add('peer1', 1, 'data1'); + D(devices.mailbox).add('peer1', 2, 'data2'); + D(devices.mailbox).add('peer1', 3, 'data3'); + D(devices.mailbox).ackInbound('peer1', 12); + D(devices.mailbox).ackInbound('peer1', 13); + D(devices.mailbox).add('peer2', 4, 'data4'); + D(devices.mailbox).add('peer3', 5, 'data5'); + D(devices.mailbox).remove('peer1', 1); + D(devices.mailbox).remove('peer2', 4, 'data4'); + // should leave peer1: [data2,data3], peer2: [], peer3: [data5] + } else if (argv[0] === 'mailbox2') { + const handler = makeExo( + 'mailbox', + M.interface('mailbox', {}, { defaultGuards: 'passable' }), + { + deliverInboundMessages(peer, messages) { + log(`dm-${peer}`); + for (const m of messages) { + log(`m-${m[0]}-${m[1]}`); + } + }, + deliverInboundAck(peer, ack) { + log(`da-${peer}-${ack}`); + }, + }, + ); + D(devices.mailbox).registerInboundHandler(handler); + } else if (argv[0] === 'mailbox-determinism') { + D(devices.mailbox).registerInboundHandler(vats.vattp); + await E(vats.vattp).registerMailboxDevice(devices.mailbox); + const name = 'peer1'; + const { setReceiver } = await E(vats.vattp).addRemote(name); + const receiver = makeExo( + 'receiver', + M.interface('receiver', {}, { defaultGuards: 'passable' }), + { + receive(body) { + numReceived += 1; + log(`comms receive ${body}`); + }, + }, + ); + await E(setReceiver).setReceiver(receiver); + } else { + Fail`unknown argv mode '${argv[0]}'`; + } + }, + ping() { + return true; + }, + getNumReceived() { + return numReceived; + }, }, - ping() { - return true; - }, - getNumReceived() { - return numReceived; - }, - }); + ); } diff --git a/packages/SwingSet/test/device-plugin/bootstrap.js b/packages/SwingSet/test/device-plugin/bootstrap.js index 20bc3c1f4eb..559a8e08668 100644 --- a/packages/SwingSet/test/device-plugin/bootstrap.js +++ b/packages/SwingSet/test/device-plugin/bootstrap.js @@ -5,28 +5,32 @@ import { makePluginManager } from '../../src/vats/plugin-manager.js'; export function buildRootObject(vatPowers, vatParameters) { const { D } = vatPowers; const log = vatPowers.testLog; - return Far('root', { - async bootstrap(vats, devices) { - try { - const { argv } = vatParameters; - if (argv[0] === 'plugin') { - log(`starting plugin test`); - const pluginManager = makePluginManager(devices.plugin, vatPowers); - const { pluginRoot: pingPongP } = await E(pluginManager).load( - 'pingpong', - { - prefix: 'Whoopie ', - }, - ); - D(devices.bridge).registerInboundHandler(vats.bridge); - await E(vats.bridge).init(pingPongP, devices.bridge); - } else { - Fail`unknown argv mode '${argv[0]}'`; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + try { + const { argv } = vatParameters; + if (argv[0] === 'plugin') { + log(`starting plugin test`); + const pluginManager = makePluginManager(devices.plugin, vatPowers); + const { pluginRoot: pingPongP } = await E(pluginManager).load( + 'pingpong', + { + prefix: 'Whoopie ', + }, + ); + D(devices.bridge).registerInboundHandler(vats.bridge); + await E(vats.bridge).init(pingPongP, devices.bridge); + } else { + Fail`unknown argv mode '${argv[0]}'`; + } + } catch (e) { + console.error('have error', e); + throw e; } - } catch (e) { - console.error('have error', e); - throw e; - } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/device-plugin/pingpong.js b/packages/SwingSet/test/device-plugin/pingpong.js index a42a820814a..49289d67344 100644 --- a/packages/SwingSet/test/device-plugin/pingpong.js +++ b/packages/SwingSet/test/device-plugin/pingpong.js @@ -1,14 +1,22 @@ import { Far } from '@endo/far'; export function bootPlugin() { - return Far('iface', { - start(opts) { - const { prefix } = opts; - return Far('iface2', { - ping(msg) { - return `${prefix}${msg}`; - }, - }); + return makeExo( + 'iface', + M.interface('iface', {}, { defaultGuards: 'passable' }), + { + start(opts) { + const { prefix } = opts; + return makeExo( + 'iface2', + M.interface('iface2', {}, { defaultGuards: 'passable' }), + { + ping(msg) { + return `${prefix}${msg}`; + }, + }, + ); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/device-plugin/vat-bridge.js b/packages/SwingSet/test/device-plugin/vat-bridge.js index 1c1c0e36f4f..6a5a06138e6 100644 --- a/packages/SwingSet/test/device-plugin/vat-bridge.js +++ b/packages/SwingSet/test/device-plugin/vat-bridge.js @@ -4,28 +4,32 @@ import { Fail } from '@agoric/assert'; export function buildRootObject(vatPowers, _vatParameters) { const log = vatPowers.testLog; let pingPongP; - return Far('root', { - init(pingPong) { - log(`installing pingPongP`); - pingPongP = pingPong; - }, - async inbound(msg) { - try { - switch (msg) { - case 'pingpong': { - log(`starting pingpong test`); - const pong = await E(pingPongP).ping('Agoric!'); - log(`pingpong reply = ${pong}`); - break; - } - default: { - Fail`unknown bridge input ${msg}`; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + init(pingPong) { + log(`installing pingPongP`); + pingPongP = pingPong; + }, + async inbound(msg) { + try { + switch (msg) { + case 'pingpong': { + log(`starting pingpong test`); + const pong = await E(pingPongP).ping('Agoric!'); + log(`pingpong reply = ${pong}`); + break; + } + default: { + Fail`unknown bridge input ${msg}`; + } } + } catch (e) { + console.error('failed with', e); + log(`failed: ${e}`); } - } catch (e) { - console.error('failed with', e); - log(`failed: ${e}`); - } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/devices/bootstrap-2.js b/packages/SwingSet/test/devices/bootstrap-2.js index 719361d1d5d..91805290b4a 100644 --- a/packages/SwingSet/test/devices/bootstrap-2.js +++ b/packages/SwingSet/test/devices/bootstrap-2.js @@ -4,88 +4,104 @@ export function buildRootObject(vatPowers) { const { D, testLog: log } = vatPowers; let devices; let vats; - return Far('root', { - async bootstrap(v, devs) { - vats = v; - devices = devs; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(v, devs) { + vats = v; + devices = devs; + }, + async do1() { + log(`calling d2.method1`); + const ret = D(devices.d2).method1('hello'); + log(ret); + }, + async do2() { + log(`calling d2.method2`); + const [d2, d3] = D(devices.d2).method2(); // [d2,d3] + const ret2 = D(d3).method3(d2); + log(ret2.key); + }, + async do3() { + log(`calling d2.method3`); + // devices can't yet do sendOnly on pass-by-presence objects, but + // they should still be able to accept and return them + const o = makeExo( + 'iface', + M.interface('iface', {}, { defaultGuards: 'passable' }), + {}, + ); + const ret = D(devices.d2).method3(o); + log(`ret ${ret === o}`); + }, + async do4() { + log(`calling d2.method4`); + // now exercise sendOnly on pass-by-presence objects + const o = makeExo( + 'o', + M.interface('o', {}, { defaultGuards: 'passable' }), + { + foo(obj) { + log(`d2.m4 foo`); + D(obj).bar('hello'); + log(`d2.m4 did bar`); + }, + }, + ); + const ret = D(devices.d2).method4(o); + log(`ret ${ret}`); + }, + async do5() { + log(`calling v2.method5`); + const p = E(vats.left).left5(devices.d2); + log(`called`); + const ret = await p; + log(`ret ${ret}`); + }, + async doState1() { + log(`calling setState`); + D(devices.d2).setState('state2'); + log(`called`); + }, + async doState2() { + log(`calling getState`); + const s = D(devices.d2).getState(); + log(`got ${s}`); + }, + async doCommand1() { + D(devices.command).sendBroadcast({ hello: 'everybody' }); + }, + async doCommand2() { + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { + inbound(count, body) { + log(`handle-${count}-${body.piece}`); + D(devices.command).sendResponse(count, body.doReject, { + response: 'body', + }); + }, + }, + ); + D(devices.command).registerInboundHandler(handler); + }, + async doPromise1() { + const p = Promise.resolve(); + log('sending Promise'); + try { + // this will be rejected by liveslots before the device is involved + D(devices.d0).send({ p }); + // shouldn't get here + log('oops: survived sending Promise'); + } catch (e) { + log('good: callNow failed'); + } + }, + ping() { + return true; + }, }, - async do1() { - log(`calling d2.method1`); - const ret = D(devices.d2).method1('hello'); - log(ret); - }, - async do2() { - log(`calling d2.method2`); - const [d2, d3] = D(devices.d2).method2(); // [d2,d3] - const ret2 = D(d3).method3(d2); - log(ret2.key); - }, - async do3() { - log(`calling d2.method3`); - // devices can't yet do sendOnly on pass-by-presence objects, but - // they should still be able to accept and return them - const o = Far('iface', {}); - const ret = D(devices.d2).method3(o); - log(`ret ${ret === o}`); - }, - async do4() { - log(`calling d2.method4`); - // now exercise sendOnly on pass-by-presence objects - const o = Far('o', { - foo(obj) { - log(`d2.m4 foo`); - D(obj).bar('hello'); - log(`d2.m4 did bar`); - }, - }); - const ret = D(devices.d2).method4(o); - log(`ret ${ret}`); - }, - async do5() { - log(`calling v2.method5`); - const p = E(vats.left).left5(devices.d2); - log(`called`); - const ret = await p; - log(`ret ${ret}`); - }, - async doState1() { - log(`calling setState`); - D(devices.d2).setState('state2'); - log(`called`); - }, - async doState2() { - log(`calling getState`); - const s = D(devices.d2).getState(); - log(`got ${s}`); - }, - async doCommand1() { - D(devices.command).sendBroadcast({ hello: 'everybody' }); - }, - async doCommand2() { - const handler = Far('handler', { - inbound(count, body) { - log(`handle-${count}-${body.piece}`); - D(devices.command).sendResponse(count, body.doReject, { - response: 'body', - }); - }, - }); - D(devices.command).registerInboundHandler(handler); - }, - async doPromise1() { - const p = Promise.resolve(); - log('sending Promise'); - try { - // this will be rejected by liveslots before the device is involved - D(devices.d0).send({ p }); - // shouldn't get here - log('oops: survived sending Promise'); - } catch (e) { - log('good: callNow failed'); - } - }, - ping() { - return true; - }, - }); + ); } diff --git a/packages/SwingSet/test/devices/bootstrap-3.js b/packages/SwingSet/test/devices/bootstrap-3.js index 3bff1e5cd71..c7282e2eafc 100644 --- a/packages/SwingSet/test/devices/bootstrap-3.js +++ b/packages/SwingSet/test/devices/bootstrap-3.js @@ -3,17 +3,21 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers, vatParameters) { const { D, testLog: log } = vatPowers; - return Far('root', { - async bootstrap(vats, devices) { - if (vatParameters.argv[0] === 'write+read') { - log(`w+r`); - D(devices.d3).setState(harden({ s: 'new' })); - log(`called`); - const s = D(devices.d3).getState(); - log(`got ${JSON.stringify(s)}`); - } else { - Fail`unknown argv mode '${vatParameters.argv[0]}'`; - } + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + if (vatParameters.argv[0] === 'write+read') { + log(`w+r`); + D(devices.d3).setState(harden({ s: 'new' })); + log(`called`); + const s = D(devices.d3).getState(); + log(`got ${JSON.stringify(s)}`); + } else { + Fail`unknown argv mode '${vatParameters.argv[0]}'`; + } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/devices/bootstrap-5.js b/packages/SwingSet/test/devices/bootstrap-5.js index bf975423c3a..13e1fb76aa7 100644 --- a/packages/SwingSet/test/devices/bootstrap-5.js +++ b/packages/SwingSet/test/devices/bootstrap-5.js @@ -2,16 +2,20 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers, _vatParameters) { const { D } = vatPowers; - return Far('root', { - async bootstrap(vats, devices) { - let got; - try { - D(devices.d5).pleaseThrow('with message'); - got = 'oops, did not throw'; - } catch (e) { - got = e; - } - return harden(['got', got]); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + let got; + try { + D(devices.d5).pleaseThrow('with message'); + got = 'oops, did not throw'; + } catch (e) { + got = e; + } + return harden(['got', got]); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/devices/bootstrap-6.js b/packages/SwingSet/test/devices/bootstrap-6.js index 9514291cdbc..b426b304fd8 100644 --- a/packages/SwingSet/test/devices/bootstrap-6.js +++ b/packages/SwingSet/test/devices/bootstrap-6.js @@ -2,21 +2,25 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers, _vatParameters) { const { D } = vatPowers; - return Far('root', { - async bootstrap(vats, devices) { - let got; - try { - // ideally, device nodes can round-trip through unrelated devices - const second = D(devices.d6first).pleaseReturn(devices.d6second); - got = second === devices.d6second; - } catch (e) { - // but deviceSlots.js cannot handle foreign device nodes yet, so we - // expect a catchable device error. If/when deviceSlots is enhanced - // to handle this, or if the target is raw device, this can start to - // work. - got = e; - } - return harden(['got', got]); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + let got; + try { + // ideally, device nodes can round-trip through unrelated devices + const second = D(devices.d6first).pleaseReturn(devices.d6second); + got = second === devices.d6second; + } catch (e) { + // but deviceSlots.js cannot handle foreign device nodes yet, so we + // expect a catchable device error. If/when deviceSlots is enhanced + // to handle this, or if the target is raw device, this can start to + // work. + got = e; + } + return harden(['got', got]); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/devices/bootstrap-raw.js b/packages/SwingSet/test/devices/bootstrap-raw.js index 7772d4727e7..2d8b8096530 100644 --- a/packages/SwingSet/test/devices/bootstrap-raw.js +++ b/packages/SwingSet/test/devices/bootstrap-raw.js @@ -5,72 +5,80 @@ import { makePromiseKit } from '@endo/promise-kit'; export function buildRootObject(vatPowers, _vatParameters) { const { D } = vatPowers; let devices; - return Far('root', { - bootstrap(vats, d0) { - devices = d0; - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats, d0) { + devices = d0; + }, - step1() { - return D(devices.dr).one(harden({ toPush: 'pushed', x: 4 })); - }, + step1() { + return D(devices.dr).one(harden({ toPush: 'pushed', x: 4 })); + }, - async step2() { - const pk1 = makePromiseKit(); - const pk2 = makePromiseKit(); - const got = []; - // give the device an object to return and do sendOnly - const target = Far('target', { - ping1(hello, p1) { - got.push(hello); // should be 'hi ping1' - got.push(p1 === target); - pk1.resolve(); - }, - ping2(hello, p2) { - got.push(hello); // should be 'hi ping2' - got.push(p2 === target); - pk2.resolve(); - }, - }); - const ret = D(devices.dr).two(target); // ['got', target] - got.push(ret[0]); - got.push(ret[1] === target); - await pk1.promise; - await pk2.promise; - return got; // ['got', true, 'hi ping1', true, 'hi ping2', true] - }, + async step2() { + const pk1 = makePromiseKit(); + const pk2 = makePromiseKit(); + const got = []; + // give the device an object to return and do sendOnly + const target = makeExo( + 'target', + M.interface('target', {}, { defaultGuards: 'passable' }), + { + ping1(hello, p1) { + got.push(hello); // should be 'hi ping1' + got.push(p1 === target); + pk1.resolve(); + }, + ping2(hello, p2) { + got.push(hello); // should be 'hi ping2' + got.push(p2 === target); + pk2.resolve(); + }, + }, + ); + const ret = D(devices.dr).two(target); // ['got', target] + got.push(ret[0]); + got.push(ret[1] === target); + await pk1.promise; + await pk2.promise; + return got; // ['got', true, 'hi ping1', true, 'hi ping2', true] + }, - step3() { - const { dn1, dn2 } = D(devices.dr).three(); // returns new device nodes - const ret1 = D(dn1).threeplus(21, dn1, dn2); // ['dn1', 21, true, true] - const ret2 = D(dn2).threeplus(22, dn1, dn2); // ['dn2', 22, true, true] - return [ret1, ret2]; - }, + step3() { + const { dn1, dn2 } = D(devices.dr).three(); // returns new device nodes + const ret1 = D(dn1).threeplus(21, dn1, dn2); // ['dn1', 21, true, true] + const ret2 = D(dn2).threeplus(22, dn1, dn2); // ['dn2', 22, true, true] + return [ret1, ret2]; + }, - step4() { - const got1 = D(devices.dr).fourGet(); - D(devices.dr).fourSet('value1'); - const got2 = D(devices.dr).fourGet(); - D(devices.dr).fourDelete(); - const got3 = D(devices.dr).fourGet(); - return [got1, got2, got3]; - }, + step4() { + const got1 = D(devices.dr).fourGet(); + D(devices.dr).fourSet('value1'); + const got2 = D(devices.dr).fourGet(); + D(devices.dr).fourDelete(); + const got3 = D(devices.dr).fourGet(); + return [got1, got2, got3]; + }, - step5() { - try { - D(devices.dr).fiveThrow(); - return false; - } catch (e) { - return e; - } - }, + step5() { + try { + D(devices.dr).fiveThrow(); + return false; + } catch (e) { + return e; + } + }, - step6() { - try { - D(devices.dr).sixError(); - return false; - } catch (e) { - return e; - } + step6() { + try { + D(devices.dr).sixError(); + return false; + } catch (e) { + return e; + } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/devices/device-0.js b/packages/SwingSet/test/devices/device-0.js index 4b2bc4e29d9..185c8ebc2e2 100644 --- a/packages/SwingSet/test/devices/device-0.js +++ b/packages/SwingSet/test/devices/device-0.js @@ -1,5 +1,9 @@ import { Far } from '@endo/far'; export function buildRootDeviceNode() { - return Far('root', {}); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + {}, + ); } diff --git a/packages/SwingSet/test/devices/device-1.js b/packages/SwingSet/test/devices/device-1.js index fa7a812a661..626342c5e9d 100644 --- a/packages/SwingSet/test/devices/device-1.js +++ b/packages/SwingSet/test/devices/device-1.js @@ -1,11 +1,15 @@ import { Far } from '@endo/far'; export function buildRootDeviceNode({ testLog, endowments }) { - return Far('root', { - set(arg1, arg2) { - testLog(`invoke ${arg1} ${arg2}`); - endowments.shared.push('pushed'); - return harden({ ret: 3 }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + set(arg1, arg2) { + testLog(`invoke ${arg1} ${arg2}`); + endowments.shared.push('pushed'); + return harden({ ret: 3 }); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/devices/device-2.js b/packages/SwingSet/test/devices/device-2.js index 9e2c4970673..f0b7a31d4c3 100644 --- a/packages/SwingSet/test/devices/device-2.js +++ b/packages/SwingSet/test/devices/device-2.js @@ -6,46 +6,62 @@ export function buildRootDeviceNode({ getDeviceState, setDeviceState, }) { - return Far('root', { - method1(arg) { - log(`method1 ${arg}`); - return 'done'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + method1(arg) { + log(`method1 ${arg}`); + return 'done'; + }, + method2() { + const d2 = makeExo( + 'empty', + M.interface('empty', {}, { defaultGuards: 'passable' }), + {}, + ); + const d3 = makeExo( + 'd3', + M.interface('d3', {}, { defaultGuards: 'passable' }), + { + method3(arg) { + log(`method3 ${arg === d2}`); + return harden({ key: 'value' }); + }, + }, + ); + log(`method2`); + return harden([d2, d3]); + }, + method3(o) { + log(`method3`); + return o; + }, + method4(o) { + log(`method4`); + const obj = makeExo( + 'obj', + M.interface('obj', {}, { defaultGuards: 'passable' }), + { + bar(arg) { + log(`method4.bar ${arg}`); + }, + }, + ); + SO(o).foo(obj); + return 'method4 done'; + }, + method5(arg) { + log(`method5 ${arg}`); + return 'ok'; + }, + setState(arg) { + setDeviceState(`deviceState-${arg}`); + return 'ok'; + }, + getState() { + return getDeviceState(); + }, }, - method2() { - const d2 = Far('empty', {}); - const d3 = Far('d3', { - method3(arg) { - log(`method3 ${arg === d2}`); - return harden({ key: 'value' }); - }, - }); - log(`method2`); - return harden([d2, d3]); - }, - method3(o) { - log(`method3`); - return o; - }, - method4(o) { - log(`method4`); - const obj = Far('obj', { - bar(arg) { - log(`method4.bar ${arg}`); - }, - }); - SO(o).foo(obj); - return 'method4 done'; - }, - method5(arg) { - log(`method5 ${arg}`); - return 'ok'; - }, - setState(arg) { - setDeviceState(`deviceState-${arg}`); - return 'ok'; - }, - getState() { - return getDeviceState(); - }, - }); + ); } diff --git a/packages/SwingSet/test/devices/device-3.js b/packages/SwingSet/test/devices/device-3.js index bdc82c5a03b..1808825522d 100644 --- a/packages/SwingSet/test/devices/device-3.js +++ b/packages/SwingSet/test/devices/device-3.js @@ -7,13 +7,17 @@ export function buildRootDeviceNode({ }) { testLog(typeof getDeviceState()); - return Far('root', { - setState(arg) { - setDeviceState(arg); - return 'ok'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + setState(arg) { + setDeviceState(arg); + return 'ok'; + }, + getState() { + return harden(getDeviceState()); + }, }, - getState() { - return harden(getDeviceState()); - }, - }); + ); } diff --git a/packages/SwingSet/test/devices/device-5.js b/packages/SwingSet/test/devices/device-5.js index 48ceebaff22..a38cb8a47d2 100644 --- a/packages/SwingSet/test/devices/device-5.js +++ b/packages/SwingSet/test/devices/device-5.js @@ -1,9 +1,13 @@ import { Far } from '@endo/far'; export function buildRootDeviceNode() { - return Far('root', { - pleaseThrow(msg) { - throw Error(`intentional: ${msg}`); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + pleaseThrow(msg) { + throw Error(`intentional: ${msg}`); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/devices/device-6.js b/packages/SwingSet/test/devices/device-6.js index 7269d65c04d..488a8b2c8a9 100644 --- a/packages/SwingSet/test/devices/device-6.js +++ b/packages/SwingSet/test/devices/device-6.js @@ -1,9 +1,13 @@ import { Far } from '@endo/far'; export function buildRootDeviceNode() { - return Far('root', { - pleaseReturn(obj) { - return obj; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + pleaseReturn(obj) { + return obj; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/devices/vat-left.js b/packages/SwingSet/test/devices/vat-left.js index 4e1d821a1a1..feded6ad5c5 100644 --- a/packages/SwingSet/test/devices/vat-left.js +++ b/packages/SwingSet/test/devices/vat-left.js @@ -2,18 +2,22 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { const { D, testLog: log } = vatPowers; - return Far('root', { - left5(d2) { - log(`left5`); - const ret = D(d2).method5('hello'); - log(`left5 did d2.method5, got ${ret}`); - return 'done'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + left5(d2) { + log(`left5`); + const ret = D(d2).method5('hello'); + log(`left5 did d2.method5, got ${ret}`); + return 'done'; + }, + leftSharedTable(st) { + log(`leftSharedTable`); + log(`has key1= ${D(st).has('key1')}`); + log(`got key1= ${D(st).get('key1')}`); + log(`has key2= ${D(st).has('key2')}`); + }, }, - leftSharedTable(st) { - log(`leftSharedTable`); - log(`has key1= ${D(st).has('key1')}`); - log(`got key1= ${D(st).get('key1')}`); - log(`has key2= ${D(st).has('key2')}`); - }, - }); + ); } diff --git a/packages/SwingSet/test/files-vattp/bootstrap-test-vattp.js b/packages/SwingSet/test/files-vattp/bootstrap-test-vattp.js index 097d7da86b9..268ea6e54e9 100644 --- a/packages/SwingSet/test/files-vattp/bootstrap-test-vattp.js +++ b/packages/SwingSet/test/files-vattp/bootstrap-test-vattp.js @@ -3,37 +3,45 @@ import { Fail } from '@agoric/assert'; export function buildRootObject(vatPowers, vatParameters) { const { D, testLog: log } = vatPowers; - const receiver = Far('receiver', { - receive(body) { - log(`ch.receive ${body}`); + const receiver = makeExo( + 'receiver', + M.interface('receiver', {}, { defaultGuards: 'passable' }), + { + receive(body) { + log(`ch.receive ${body}`); + }, }, - }); + ); let transmitter; - return Far('root', { - async bootstrap(vats, devices) { - // to exercise vat-vattp upgrade, we need the vatAdminService to - // be configured, even though we don't use it ourselves - await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - const { argv } = vatParameters; - D(devices.mailbox).registerInboundHandler(vats.vattp); - await E(vats.vattp).registerMailboxDevice(devices.mailbox); - const name = 'remote1'; - const res = await E(vats.vattp).addRemote(name); - transmitter = res.transmitter; - // replace the E(vats.comms).addRemote() we'd normally do - await E(res.setReceiver).setReceiver(receiver); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + // to exercise vat-vattp upgrade, we need the vatAdminService to + // be configured, even though we don't use it ourselves + await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); + const { argv } = vatParameters; + D(devices.mailbox).registerInboundHandler(vats.vattp); + await E(vats.vattp).registerMailboxDevice(devices.mailbox); + const name = 'remote1'; + const res = await E(vats.vattp).addRemote(name); + transmitter = res.transmitter; + // replace the E(vats.comms).addRemote() we'd normally do + await E(res.setReceiver).setReceiver(receiver); - if (argv[0] === '1') { - log('not sending anything'); - } else if (argv[0] === '2') { - E(transmitter).transmit('out1'); - } else { - Fail`unknown argv mode '${argv[0]}'`; - } + if (argv[0] === '1') { + log('not sending anything'); + } else if (argv[0] === '2') { + E(transmitter).transmit('out1'); + } else { + Fail`unknown argv mode '${argv[0]}'`; + } + }, + transmit(msg) { + E(transmitter).transmit(msg); + }, }, - transmit(msg) { - E(transmitter).transmit(msg); - }, - }); + ); } diff --git a/packages/SwingSet/test/gc-dead-vat/bootstrap.js b/packages/SwingSet/test/gc-dead-vat/bootstrap.js index 50668b2902b..5f2717a1b7e 100644 --- a/packages/SwingSet/test/gc-dead-vat/bootstrap.js +++ b/packages/SwingSet/test/gc-dead-vat/bootstrap.js @@ -2,7 +2,11 @@ import { Far, E } from '@endo/far'; import { makePromiseKit } from '@endo/promise-kit'; async function sendExport(doomedRoot) { - const exportToDoomed = Far('exportToDoomed', {}); + const exportToDoomed = makeExo( + 'exportToDoomed', + M.interface('exportToDoomed', {}, { defaultGuards: 'passable' }), + {}, + ); await E(doomedRoot).accept(exportToDoomed); } @@ -11,44 +15,54 @@ export function buildRootObject() { let doomedRoot; const pin = []; const pk1 = makePromiseKit(); - return Far('root', { - async bootstrap(vats, devices) { - const vatMaker = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - vat = await E(vatMaker).createVatByName('doomed'); - doomedRoot = vat.root; - await sendExport(doomedRoot); - const doomedExport1Presence = await E(doomedRoot).getDoomedExport1(); - pin.push(doomedExport1Presence); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatMaker = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + vat = await E(vatMaker).createVatByName('doomed'); + doomedRoot = vat.root; + await sendExport(doomedRoot); + const doomedExport1Presence = await E(doomedRoot).getDoomedExport1(); + pin.push(doomedExport1Presence); + }, + async stash() { + // Give vat-doomed a target that doesn't resolve one() right away. + // vat-doomed will send doomedExport2 to the result of target~.one(), + // which means doomedExport2 will be held in the kernel's promise-queue + // entry until we resolve pk1.promise + const target = makeExo( + 'target', + M.interface('target', {}, { defaultGuards: 'passable' }), + { + one() { + return pk1.promise; + }, + }, + ); + await E(doomedRoot).stashDoomedExport2(target); + }, + async startTerminate() { + await E(vat.root).terminate(); + await E(vat.done); + }, + callOrphan() { + // the object is gone, so hello() ought to reject + const p = E(pin[0]).hello(); + return p.then( + _res => { + throw Error('what??'); + }, + _err => 'good', + ); + }, + async drop() { + pin.splice(0); + pk1.reject(0); + }, }, - async stash() { - // Give vat-doomed a target that doesn't resolve one() right away. - // vat-doomed will send doomedExport2 to the result of target~.one(), - // which means doomedExport2 will be held in the kernel's promise-queue - // entry until we resolve pk1.promise - const target = Far('target', { - one() { - return pk1.promise; - }, - }); - await E(doomedRoot).stashDoomedExport2(target); - }, - async startTerminate() { - await E(vat.root).terminate(); - await E(vat.done); - }, - callOrphan() { - // the object is gone, so hello() ought to reject - const p = E(pin[0]).hello(); - return p.then( - _res => { - throw Error('what??'); - }, - _err => 'good', - ); - }, - async drop() { - pin.splice(0); - pk1.reject(0); - }, - }); + ); } diff --git a/packages/SwingSet/test/gc-dead-vat/vat-doomed.js b/packages/SwingSet/test/gc-dead-vat/vat-doomed.js index f3ad636b7c0..a0fe2a8578a 100644 --- a/packages/SwingSet/test/gc-dead-vat/vat-doomed.js +++ b/packages/SwingSet/test/gc-dead-vat/vat-doomed.js @@ -2,20 +2,32 @@ import { Far, E } from '@endo/far'; export function buildRootObject(vatPowers) { const pin = []; - const doomedExport1 = Far('doomedExport1', {}); - const doomedExport2 = Far('doomedExport2', {}); - return Far('root', { - accept(exportToDoomedPresence) { - pin.push(exportToDoomedPresence); + const doomedExport1 = makeExo( + 'doomedExport1', + M.interface('doomedExport1', {}, { defaultGuards: 'passable' }), + {}, + ); + const doomedExport2 = makeExo( + 'doomedExport2', + M.interface('doomedExport2', {}, { defaultGuards: 'passable' }), + {}, + ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + accept(exportToDoomedPresence) { + pin.push(exportToDoomedPresence); + }, + getDoomedExport1() { + return doomedExport1; + }, + stashDoomedExport2(target) { + E(E(target).one()).neverCalled(doomedExport2); + }, + terminate() { + vatPowers.exitVat('completion'); + }, }, - getDoomedExport1() { - return doomedExport1; - }, - stashDoomedExport2(target) { - E(E(target).one()).neverCalled(doomedExport2); - }, - terminate() { - vatPowers.exitVat('completion'); - }, - }); + ); } diff --git a/packages/SwingSet/test/gc-device-transfer/bootstrap-gc.js b/packages/SwingSet/test/gc-device-transfer/bootstrap-gc.js index cafb0741d35..2f6848b9cf0 100644 --- a/packages/SwingSet/test/gc-device-transfer/bootstrap-gc.js +++ b/packages/SwingSet/test/gc-device-transfer/bootstrap-gc.js @@ -1,9 +1,13 @@ import { Far, E } from '@endo/far'; async function sendAmy(D, dev, testLog, left) { - const amy = Far('amy', { - hello: testLog, - }); + const amy = makeExo( + 'amy', + M.interface('amy', {}, { defaultGuards: 'passable' }), + { + hello: testLog, + }, + ); D(dev).set(amy); await E(left).forget(amy); } @@ -11,13 +15,17 @@ async function sendAmy(D, dev, testLog, left) { export function buildRootObject(vatPowers) { const { D, testLog } = vatPowers; const pin = []; - return Far('root', { - async bootstrap(vats, devices) { - pin.push(vats); // don't drop vat-right, our test needs it later - // export amy to the device, and send to vat-left, then forget her - void sendAmy(D, devices.stash_device, testLog, vats.left); - // tell the vat to retrieve amy from the device - await E(vats.right).acceptDevice(devices.stash_device); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + pin.push(vats); // don't drop vat-right, our test needs it later + // export amy to the device, and send to vat-left, then forget her + void sendAmy(D, devices.stash_device, testLog, vats.left); + // tell the vat to retrieve amy from the device + await E(vats.right).acceptDevice(devices.stash_device); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/gc-device-transfer/device-gc.js b/packages/SwingSet/test/gc-device-transfer/device-gc.js index fb17a3ea855..4d91280519e 100644 --- a/packages/SwingSet/test/gc-device-transfer/device-gc.js +++ b/packages/SwingSet/test/gc-device-transfer/device-gc.js @@ -2,13 +2,17 @@ import { Far } from '@endo/far'; export function buildRootDeviceNode({ setDeviceState }) { let stash; - return Far('root', { - set(arg) { - setDeviceState(arg); - stash = arg; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + set(arg) { + setDeviceState(arg); + stash = arg; + }, + get() { + return stash; + }, }, - get() { - return stash; - }, - }); + ); } diff --git a/packages/SwingSet/test/gc-device-transfer/vat-left-gc.js b/packages/SwingSet/test/gc-device-transfer/vat-left-gc.js index 2b1b215dd36..e39778e6108 100644 --- a/packages/SwingSet/test/gc-device-transfer/vat-left-gc.js +++ b/packages/SwingSet/test/gc-device-transfer/vat-left-gc.js @@ -1,9 +1,13 @@ import { Far } from '@endo/far'; export function buildRootObject() { - return Far('left', { - async forget(_amy) { - // just drop the argument + return makeExo( + 'left', + M.interface('left', {}, { defaultGuards: 'passable' }), + { + async forget(_amy) { + // just drop the argument + }, }, - }); + ); } diff --git a/packages/SwingSet/test/gc-device-transfer/vat-right-gc.js b/packages/SwingSet/test/gc-device-transfer/vat-right-gc.js index 9deb4b96ce2..7c702fa93bc 100644 --- a/packages/SwingSet/test/gc-device-transfer/vat-right-gc.js +++ b/packages/SwingSet/test/gc-device-transfer/vat-right-gc.js @@ -3,14 +3,18 @@ import { Far, E } from '@endo/far'; export function buildRootObject(vatPowers) { const { D, testLog } = vatPowers; let stashDevice; - return Far('right', { - async acceptDevice(dev) { - stashDevice = dev; + return makeExo( + 'right', + M.interface('right', {}, { defaultGuards: 'passable' }), + { + async acceptDevice(dev) { + stashDevice = dev; + }, + async getAmy() { + const amy = D(stashDevice).get(); + testLog('vat-right got amy'); + await E(amy).hello('hi amy from vat-right'); + }, }, - async getAmy() { - const amy = D(stashDevice).get(); - testLog('vat-right got amy'); - await E(amy).hello('hi amy from vat-right'); - }, - }); + ); } diff --git a/packages/SwingSet/test/gc/bootstrap.js b/packages/SwingSet/test/gc/bootstrap.js index 3c08bb01b4e..c1e7098f225 100644 --- a/packages/SwingSet/test/gc/bootstrap.js +++ b/packages/SwingSet/test/gc/bootstrap.js @@ -2,26 +2,34 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { - let A = Far('A', { hello() {} }); - let B = Far('B', { hello() {} }); + let A = makeExo('A', M.interface('A', {}, { defaultGuards: 'passable' }), { + hello() {}, + }); + let B = makeExo('B', M.interface('B', {}, { defaultGuards: 'passable' }), { + hello() {}, + }); let target; let zoe; - return Far('root', { - async bootstrap(vats) { - target = vats.target; - zoe = vats.zoe; - }, - async one() { - await E(target).two(A, B); - }, - drop() { - A = null; - B = null; - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + target = vats.target; + zoe = vats.zoe; + }, + async one() { + await E(target).two(A, B); + }, + drop() { + A = null; + B = null; + }, - async makeInvitation0() { - await E(target).makeInvitationTarget(zoe); + async makeInvitation0() { + await E(target).makeInvitationTarget(zoe); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/gc/vat-fake-zoe.js b/packages/SwingSet/test/gc/vat-fake-zoe.js index 2f9a69f3027..566f859d23d 100644 --- a/packages/SwingSet/test/gc/vat-fake-zoe.js +++ b/packages/SwingSet/test/gc/vat-fake-zoe.js @@ -1,10 +1,18 @@ import { Far } from '@endo/far'; export function buildRootObject() { - const C = Far('Zoe Invitation payment', { hello() {} }); - return Far('root', { - async makeInvitationZoe() { - return C; + const C = makeExo( + 'Zoe Invitation payment', + M.interface('Zoe Invitation payment', {}, { defaultGuards: 'passable' }), + { hello() {} }, + ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async makeInvitationZoe() { + return C; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/gc/vat-target.js b/packages/SwingSet/test/gc/vat-target.js index dd4c1d5d0a6..28558040c42 100644 --- a/packages/SwingSet/test/gc/vat-target.js +++ b/packages/SwingSet/test/gc/vat-target.js @@ -1,14 +1,18 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { - return Far('root', { - async two(A, B) { - // A=ko26 B=ko27 - await E(A).hello(B); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async two(A, B) { + // A=ko26 B=ko27 + await E(A).hello(B); + }, - makeInvitationTarget(zoe) { - return E(zoe).makeInvitationZoe(); + makeInvitationTarget(zoe) { + return E(zoe).makeInvitationZoe(); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/message-patterns.js b/packages/SwingSet/test/message-patterns.js index b393c236a5d..646979fda88 100644 --- a/packages/SwingSet/test/message-patterns.js +++ b/packages/SwingSet/test/message-patterns.js @@ -516,12 +516,16 @@ export function buildPatterns(log) { p2.then(() => log('p2 resolved')); }; objB.b66_flush = () => 0; - const target = Far('target', { - msg2: () => { - log('two'); - return 'res'; + const target = makeExo( + 'target', + M.interface('target', {}, { defaultGuards: 'passable' }), + { + msg2: () => { + log('two'); + return 'res'; + }, }, - }); + ); objB.b66_resolve = () => { pk.resolve(target); }; @@ -541,17 +545,25 @@ export function buildPatterns(log) { }; objB.b70_pipe1 = async () => { log(`pipe1`); - const pipe2 = Far('pipe2', { - pipe2() { - log(`pipe2`); - const pipe3 = Far('pipe3', { - pipe3() { - log(`pipe3`); - }, - }); - return pipe3; + const pipe2 = makeExo( + 'pipe2', + M.interface('pipe2', {}, { defaultGuards: 'passable' }), + { + pipe2() { + log(`pipe2`); + const pipe3 = makeExo( + 'pipe3', + M.interface('pipe3', {}, { defaultGuards: 'passable' }), + { + pipe3() { + log(`pipe3`); + }, + }, + ); + return pipe3; + }, }, - }); + ); return pipe2; }; } @@ -585,23 +597,35 @@ export function buildPatterns(log) { const p1 = makePromiseKit(); objB.b71_getpx = async () => p1.promise; objB.b71_resolvex = async () => { - const x = Far('x', { - pipe1() { - log(`pipe1`); - const pipe2 = Far('pipe2', { - pipe2() { - log(`pipe2`); - const pipe3 = Far('pipe3', { - pipe3() { - log(`pipe3`); + const x = makeExo( + 'x', + M.interface('x', {}, { defaultGuards: 'passable' }), + { + pipe1() { + log(`pipe1`); + const pipe2 = makeExo( + 'pipe2', + M.interface('pipe2', {}, { defaultGuards: 'passable' }), + { + pipe2() { + log(`pipe2`); + const pipe3 = makeExo( + 'pipe3', + M.interface('pipe3', {}, { defaultGuards: 'passable' }), + { + pipe3() { + log(`pipe3`); + }, + }, + ); + return pipe3; }, - }); - return pipe3; - }, - }); - return pipe2; + }, + ); + return pipe2; + }, }, - }); + ); p1.resolve(x); }; } @@ -636,23 +660,35 @@ export function buildPatterns(log) { objB.b72_wait = async () => 0; objB.b72_getpx = async () => p1.promise; objB.b72_resolvex = async () => { - const x = Far('x', { - pipe1() { - log(`pipe1`); - const pipe2 = Far('pipe2', { - pipe2() { - log(`pipe2`); - const pipe3 = Far('pipe3', { - pipe3() { - log(`pipe3`); + const x = makeExo( + 'x', + M.interface('x', {}, { defaultGuards: 'passable' }), + { + pipe1() { + log(`pipe1`); + const pipe2 = makeExo( + 'pipe2', + M.interface('pipe2', {}, { defaultGuards: 'passable' }), + { + pipe2() { + log(`pipe2`); + const pipe3 = makeExo( + 'pipe3', + M.interface('pipe3', {}, { defaultGuards: 'passable' }), + { + pipe3() { + log(`pipe3`); + }, + }, + ); + return pipe3; }, - }); - return pipe3; - }, - }); - return pipe2; + }, + ); + return pipe2; + }, }, - }); + ); p1.resolve(x); }; } @@ -681,7 +717,7 @@ export function buildPatterns(log) { ignore(p2); }; objB.b73_one = () => - Far('one', { + makeExo('one', M.interface('one', {}, { defaultGuards: 'passable' }), { two: () => log('two'), }); } diff --git a/packages/SwingSet/test/metering/metered-dynamic-vat.js b/packages/SwingSet/test/metering/metered-dynamic-vat.js index 11f5bb5aaae..0059f3cb571 100644 --- a/packages/SwingSet/test/metering/metered-dynamic-vat.js +++ b/packages/SwingSet/test/metering/metered-dynamic-vat.js @@ -3,19 +3,23 @@ import { Far } from '@endo/far'; import { meterMe } from './metered-code.js'; export function buildRootObject(_dynamicVatPowers) { - return Far('root', { - never() { - return makePromiseKit().promise; - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + never() { + return makePromiseKit().promise; + }, - async run() { - meterMe([], 'no'); - return 42; - }, + async run() { + meterMe([], 'no'); + return 42; + }, - async explode(how) { - meterMe([], how); - return -1; + async explode(how) { + meterMe([], how); + return -1; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/metering/vat-load-dynamic.js b/packages/SwingSet/test/metering/vat-load-dynamic.js index cec0c2648f3..6bbe19f7070 100644 --- a/packages/SwingSet/test/metering/vat-load-dynamic.js +++ b/packages/SwingSet/test/metering/vat-load-dynamic.js @@ -6,80 +6,86 @@ export function buildRootObject(vatPowers) { let control; const notifierToUpdateCount = new WeakMap(); - return Far('root', { - async bootstrap(vats, devices) { - service = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + service = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + }, - createMeter(remaining, notifyThreshold) { - return E(service).createMeter(remaining, notifyThreshold); - }, + createMeter(remaining, notifyThreshold) { + return E(service).createMeter(remaining, notifyThreshold); + }, - createUnlimitedMeter() { - return E(service).createUnlimitedMeter(); - }, + createUnlimitedMeter() { + return E(service).createUnlimitedMeter(); + }, - addMeterRemaining(meter, remaining) { - return E(meter).addRemaining(remaining); - }, + addMeterRemaining(meter, remaining) { + return E(meter).addRemaining(remaining); + }, - setMeterThreshold(meter, threshold) { - return E(meter).setThreshold(threshold); - }, + setMeterThreshold(meter, threshold) { + return E(meter).setThreshold(threshold); + }, - getMeter(meter) { - return E(meter).get(); - }, + getMeter(meter) { + return E(meter).get(); + }, - async whenMeterNotifiesNext(meter) { - const notifier = await E(meter).getNotifier(); - const update = await E(notifier).getUpdateSince( - notifierToUpdateCount.get(notifier), - ); - notifierToUpdateCount.set(notifier, update.updateCount); - return update; - }, + async whenMeterNotifiesNext(meter) { + const notifier = await E(meter).getNotifier(); + const update = await E(notifier).getUpdateSince( + notifierToUpdateCount.get(notifier), + ); + notifierToUpdateCount.set(notifier, update.updateCount); + return update; + }, - async createVat(name, dynamicOptions) { - const bundlecap = await E(service).getNamedBundleCap(name); - control = await E(service).createVat(bundlecap, dynamicOptions); - const done = E(control.adminNode).done(); - done.catch(() => 'hush'); - // the caller checks this later, but doesn't wait for it - return ['created', done]; - }, + async createVat(name, dynamicOptions) { + const bundlecap = await E(service).getNamedBundleCap(name); + control = await E(service).createVat(bundlecap, dynamicOptions); + const done = E(control.adminNode).done(); + done.catch(() => 'hush'); + // the caller checks this later, but doesn't wait for it + return ['created', done]; + }, - getNever() { - // grab a Promise which won't resolve until the vat dies - const neverP = E(control.root).never(); - neverP.catch(() => 'hush'); - return [neverP]; - }, + getNever() { + // grab a Promise which won't resolve until the vat dies + const neverP = E(control.root).never(); + neverP.catch(() => 'hush'); + return [neverP]; + }, - run() { - return E(control.root).run(); - }, + run() { + return E(control.root).run(); + }, - explode(how) { - return E(control.root).explode(how); - }, + explode(how) { + return E(control.root).explode(how); + }, - async bundleRun() { - try { - await E(control.root).meterThem('no'); - log('did run'); - } catch (err) { - log(`run exploded: ${err}`); - } - }, + async bundleRun() { + try { + await E(control.root).meterThem('no'); + log('did run'); + } catch (err) { + log(`run exploded: ${err}`); + } + }, - async bundleExplode(how) { - try { - await E(control.root).meterThem(how); - log('failed to explode'); - } catch (err) { - log(`did explode: ${err}`); - } + async bundleExplode(how) { + try { + await E(control.root).meterThem(how); + log('failed to explode'); + } catch (err) { + log(`did explode: ${err}`); + } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/promise-watcher/bootstrap-promise-watcher.js b/packages/SwingSet/test/promise-watcher/bootstrap-promise-watcher.js index 8eaee9241cd..34b12b21c93 100644 --- a/packages/SwingSet/test/promise-watcher/bootstrap-promise-watcher.js +++ b/packages/SwingSet/test/promise-watcher/bootstrap-promise-watcher.js @@ -11,62 +11,68 @@ export function buildRootObject() { const pk4 = makePromiseKit(); const resolveAfterUpgrade = []; - const self = Far('root', { - async bootstrap(vats, devices) { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - }, + const self = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + }, - async buildV1() { - // build Upton, the upgrading vat - const bcap = await E(vatAdmin).getNamedBundleCap('upton'); - const vatParameters = { version: 'v1' }; - const options = { vatParameters }; - const res = await E(vatAdmin).createVat(bcap, options); - uptonRoot = res.root; - uptonAdmin = res.adminNode; - await E(uptonRoot).haveSomePromises( - self, - pk1.promise, - pk2.promise, - pk3.promise, - pk4.promise, - ); - pk1.resolve('val1'); - pk2.reject('err2'); - }, + async buildV1() { + // build Upton, the upgrading vat + const bcap = await E(vatAdmin).getNamedBundleCap('upton'); + const vatParameters = { version: 'v1' }; + const options = { vatParameters }; + const res = await E(vatAdmin).createVat(bcap, options); + uptonRoot = res.root; + uptonAdmin = res.adminNode; + await E(uptonRoot).haveSomePromises( + self, + pk1.promise, + pk2.promise, + pk3.promise, + pk4.promise, + ); + pk1.resolve('val1'); + pk2.reject('err2'); + }, - replyToThis(withSuccess, beforeUpgrade) { - if (beforeUpgrade) { - if (withSuccess) { - return 'rvalbefore'; + replyToThis(withSuccess, beforeUpgrade) { + if (beforeUpgrade) { + if (withSuccess) { + return 'rvalbefore'; + } else { + // eslint-disable-next-line no-throw-literal + throw 'rerrbefore'; + } } else { - // eslint-disable-next-line no-throw-literal - throw 'rerrbefore'; + const rp = makePromiseKit(); + resolveAfterUpgrade.push({ rp, withSuccess }); + return rp.promise; } - } else { - const rp = makePromiseKit(); - resolveAfterUpgrade.push({ rp, withSuccess }); - return rp.promise; - } - }, + }, - async upgradeV2() { - const bcap = await E(vatAdmin).getNamedBundleCap('upton'); - const vatParameters = { version: 'v2' }; - await E(uptonAdmin).upgrade(bcap, { - vatParameters, - upgradeMessage: 'test upgrade', - }); - pk3.resolve('val3'); - pk4.reject('err4'); - for (const { rp, withSuccess } of resolveAfterUpgrade) { - if (withSuccess) { - rp.resolve('rvalafter'); - } else { - rp.reject('rerrafter'); + async upgradeV2() { + const bcap = await E(vatAdmin).getNamedBundleCap('upton'); + const vatParameters = { version: 'v2' }; + await E(uptonAdmin).upgrade(bcap, { + vatParameters, + upgradeMessage: 'test upgrade', + }); + pk3.resolve('val3'); + pk4.reject('err4'); + for (const { rp, withSuccess } of resolveAfterUpgrade) { + if (withSuccess) { + rp.resolve('rvalafter'); + } else { + rp.reject('rerrafter'); + } } - } + }, }, - }); + ); return self; } diff --git a/packages/SwingSet/test/promise-watcher/vat-upton.js b/packages/SwingSet/test/promise-watcher/vat-upton.js index 2f3d894dd05..3755f6f1a84 100644 --- a/packages/SwingSet/test/promise-watcher/vat-upton.js +++ b/packages/SwingSet/test/promise-watcher/vat-upton.js @@ -49,51 +49,55 @@ export function buildRootObject(vatPowers, vatParameters, baggage) { }, }); - return Far('root', { - haveSomePromises(other, p1, p2, p3, p4) { - const dk = makeDK(); - const lpk1 = makePromiseKit(); - const lpk2 = makePromiseKit(); - const lpk3 = makePromiseKit(); - const lpk4 = makePromiseKit(); - const rp1 = E(other).replyToThis(true, true); - const rp2 = E(other).replyToThis(false, true); - const rp3 = E(other).replyToThis(true, false); - const rp4 = E(other).replyToThis(false, false); - watchPromise(p1, pw, 'p1-pw'); - watchPromise(p2, pw, 'p2-pw', 'a'); - watchPromise(p3, pw, 'p3-pw', 'b', 'c'); - watchPromise(p4, pw, 'p4-pw', 'd', 'e', 'f'); - watchPromise(p1, dk.full, 'p1-dk.full'); - watchPromise(p1, dk.res, 'p1-dk.res'); - watchPromise(p1, dk.rej, 'p1-dk.rej'); - watchPromise(p2, dk.full, 'p2-dk.full'); - watchPromise(p2, dk.res, 'p2-dk.res'); - watchPromise(p2, dk.rej, 'p2-dk.rej'); - watchPromise(p3, dk.full, 'p3-dk.full'); - watchPromise(p3, dk.res, 'p3-dk.res'); - watchPromise(p3, dk.rej, 'p3-dk.rej'); - watchPromise(p4, dk.full, 'p4-dk.full'); - watchPromise(p4, dk.res, 'p4-dk.res'); - watchPromise(p4, dk.rej, 'p4-dk.rej'); - watchPromise(lpk1.promise, pw, 'lp1-pw'); - watchPromise(lpk2.promise, pw, 'lp2-pw'); - watchPromise(lpk3.promise, pw, 'lp3-pw'); - watchPromise(lpk4.promise, pw, 'lp4-pw'); - watchPromise(lpk1.promise, dk.full, 'lp1-dk'); - watchPromise(lpk2.promise, dk.full, 'lp2-dk'); - watchPromise(lpk3.promise, dk.full, 'lp3-dk'); - watchPromise(lpk4.promise, dk.full, 'lp4-dk'); - watchPromise(rp1, pw, 'rp1-pw'); - watchPromise(rp2, pw, 'rp2-pw'); - watchPromise(rp3, pw, 'rp3-pw'); - watchPromise(rp4, pw, 'rp4-pw'); - watchPromise(rp1, dk.full, 'rp1-dk'); - watchPromise(rp2, dk.full, 'rp2-dk'); - watchPromise(rp3, dk.full, 'rp3-dk'); - watchPromise(rp4, dk.full, 'rp4-dk'); - lpk1.resolve('lval1'); - lpk2.reject('lerr2'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + haveSomePromises(other, p1, p2, p3, p4) { + const dk = makeDK(); + const lpk1 = makePromiseKit(); + const lpk2 = makePromiseKit(); + const lpk3 = makePromiseKit(); + const lpk4 = makePromiseKit(); + const rp1 = E(other).replyToThis(true, true); + const rp2 = E(other).replyToThis(false, true); + const rp3 = E(other).replyToThis(true, false); + const rp4 = E(other).replyToThis(false, false); + watchPromise(p1, pw, 'p1-pw'); + watchPromise(p2, pw, 'p2-pw', 'a'); + watchPromise(p3, pw, 'p3-pw', 'b', 'c'); + watchPromise(p4, pw, 'p4-pw', 'd', 'e', 'f'); + watchPromise(p1, dk.full, 'p1-dk.full'); + watchPromise(p1, dk.res, 'p1-dk.res'); + watchPromise(p1, dk.rej, 'p1-dk.rej'); + watchPromise(p2, dk.full, 'p2-dk.full'); + watchPromise(p2, dk.res, 'p2-dk.res'); + watchPromise(p2, dk.rej, 'p2-dk.rej'); + watchPromise(p3, dk.full, 'p3-dk.full'); + watchPromise(p3, dk.res, 'p3-dk.res'); + watchPromise(p3, dk.rej, 'p3-dk.rej'); + watchPromise(p4, dk.full, 'p4-dk.full'); + watchPromise(p4, dk.res, 'p4-dk.res'); + watchPromise(p4, dk.rej, 'p4-dk.rej'); + watchPromise(lpk1.promise, pw, 'lp1-pw'); + watchPromise(lpk2.promise, pw, 'lp2-pw'); + watchPromise(lpk3.promise, pw, 'lp3-pw'); + watchPromise(lpk4.promise, pw, 'lp4-pw'); + watchPromise(lpk1.promise, dk.full, 'lp1-dk'); + watchPromise(lpk2.promise, dk.full, 'lp2-dk'); + watchPromise(lpk3.promise, dk.full, 'lp3-dk'); + watchPromise(lpk4.promise, dk.full, 'lp4-dk'); + watchPromise(rp1, pw, 'rp1-pw'); + watchPromise(rp2, pw, 'rp2-pw'); + watchPromise(rp3, pw, 'rp3-pw'); + watchPromise(rp4, pw, 'rp4-pw'); + watchPromise(rp1, dk.full, 'rp1-dk'); + watchPromise(rp2, dk.full, 'rp2-dk'); + watchPromise(rp3, dk.full, 'rp3-dk'); + watchPromise(rp4, dk.full, 'rp4-dk'); + lpk1.resolve('lval1'); + lpk2.reject('lerr2'); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/reap-all/bootstrap-reap-all.js b/packages/SwingSet/test/reap-all/bootstrap-reap-all.js index 615e7c46f45..4f4ea379cd1 100644 --- a/packages/SwingSet/test/reap-all/bootstrap-reap-all.js +++ b/packages/SwingSet/test/reap-all/bootstrap-reap-all.js @@ -5,19 +5,25 @@ export function buildRootObject() { let bcap; const roots = []; - return Far('root', { - async bootstrap(vats, devices) { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - bcap = await E(vatAdmin).getNamedBundleCap('dumbo'); - console.log('end of bootstrap, vatAdmin', vatAdmin); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + bcap = await E(vatAdmin).getNamedBundleCap('dumbo'); + console.log('end of bootstrap, vatAdmin', vatAdmin); + }, - async createDynamicVats() { - for (let i = 0; i < 3; i += 1) { - const res = await E(vatAdmin).createVat(bcap); - roots.push(res.root); - } - return roots; + async createDynamicVats() { + for (let i = 0; i < 3; i += 1) { + const res = await E(vatAdmin).createVat(bcap); + roots.push(res.root); + } + return roots; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/reap-all/vat-dumbo.js b/packages/SwingSet/test/reap-all/vat-dumbo.js index 3770cd3dde1..aba3653be11 100644 --- a/packages/SwingSet/test/reap-all/vat-dumbo.js +++ b/packages/SwingSet/test/reap-all/vat-dumbo.js @@ -1,9 +1,13 @@ import { Far } from '@endo/far'; export function buildRootObject() { - return Far('root', { - doSomething(msg) { - console.log(`doSomething: ${msg}`); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + doSomething(msg) { + console.log(`doSomething: ${msg}`); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/run-policy/vat-policy-left.js b/packages/SwingSet/test/run-policy/vat-policy-left.js index 7eea4d1ed85..8d3ea1108b4 100644 --- a/packages/SwingSet/test/run-policy/vat-policy-left.js +++ b/packages/SwingSet/test/run-policy/vat-policy-left.js @@ -12,20 +12,24 @@ export function buildRootObject() { oldPK.resolve([nextPK.promise]); } - const left = Far('left', { - doMessage(right, seqnum) { - E(right).doMessage(left, seqnum); - }, + const left = makeExo( + 'left', + M.interface('left', {}, { defaultGuards: 'passable' }), + { + doMessage(right, seqnum) { + E(right).doMessage(left, seqnum); + }, - startPromise(right) { - nextPK = makePromiseKit(); - E(right) - .startPromise([nextPK.promise]) - .then(args => { - doPromise(args); - }) - .catch(err => console.log(`left startPromise err`, err)); + startPromise(right) { + nextPK = makePromiseKit(); + E(right) + .startPromise([nextPK.promise]) + .then(args => { + doPromise(args); + }) + .catch(err => console.log(`left startPromise err`, err)); + }, }, - }); + ); return left; } diff --git a/packages/SwingSet/test/run-policy/vat-policy-right.js b/packages/SwingSet/test/run-policy/vat-policy-right.js index 9630c4bb4bf..6da7bbd8a66 100644 --- a/packages/SwingSet/test/run-policy/vat-policy-right.js +++ b/packages/SwingSet/test/run-policy/vat-policy-right.js @@ -34,28 +34,32 @@ export function buildRootObject(_vatPowers, _vatParameters, baggage) { oldPK.resolve([nextPKR.promise]); } - const right = Far('right', { - doMessage(left, seqnum) { - increment(); - if (seqnum !== 'disabled') { - // if enbled, do extra work once every 5 cranks, to exercise the - // limited-computron policy - seqnum += 1; - baggage.set('seqnum', seqnum); - if (seqnum % 5 === 0) { - consumeCPU(); + const right = makeExo( + 'right', + M.interface('right', {}, { defaultGuards: 'passable' }), + { + doMessage(left, seqnum) { + increment(); + if (seqnum !== 'disabled') { + // if enbled, do extra work once every 5 cranks, to exercise the + // limited-computron policy + seqnum += 1; + baggage.set('seqnum', seqnum); + if (seqnum % 5 === 0) { + consumeCPU(); + } } - } - E(left).doMessage(right, seqnum); - }, + E(left).doMessage(right, seqnum); + }, - startPromise(args) { - nextPKR = makePromiseKit(); - args[0] - .then(doPromise) - .catch(err => console.log(`right startPromise err`, err)); - return harden([nextPKR.promise]); + startPromise(args) { + nextPKR = makePromiseKit(); + args[0] + .then(doPromise) + .catch(err => console.log(`right startPromise err`, err)); + return harden([nextPKR.promise]); + }, }, - }); + ); return right; } diff --git a/packages/SwingSet/test/test-marshal.js b/packages/SwingSet/test/test-marshal.js index 6e1a8d673ca..68bb5a34b7f 100644 --- a/packages/SwingSet/test/test-marshal.js +++ b/packages/SwingSet/test/test-marshal.js @@ -27,12 +27,20 @@ test('serialize exports', t => { }; const { m } = makeMarshaller(syscall, gcTools); const ser = m.serialize; - const o1 = Far('o1', {}); - const o2 = Far('o2', { - meth1() { - return 4; + const o1 = makeExo( + 'o1', + M.interface('o1', {}, { defaultGuards: 'passable' }), + {}, + ); + const o2 = makeExo( + 'o2', + M.interface('o2', {}, { defaultGuards: 'passable' }), + { + meth1() { + return 4; + }, }, - }); + ); t.deepEqual(ser(o1), { body: '#"$0.Alleged: o1"', slots: ['o+1'], @@ -78,7 +86,11 @@ test('deserialize exports', t => { vatstoreGet: () => undefined, }; const { m, unmeteredUnserialize } = makeUnmeteredMarshaller(syscall); - const o1 = Far('o1', {}); + const o1 = makeExo( + 'o1', + M.interface('o1', {}, { defaultGuards: 'passable' }), + {}, + ); m.serialize(o1); // allocates slot=1 const a = unmeteredUnserialize({ body: '#"$0"', diff --git a/packages/SwingSet/test/test-timer-device.js b/packages/SwingSet/test/test-timer-device.js index b4ae7a07011..823119320ff 100644 --- a/packages/SwingSet/test/test-timer-device.js +++ b/packages/SwingSet/test/test-timer-device.js @@ -45,40 +45,52 @@ test('multiMap remove key', t => { }); function fakeSO(o) { - return Far('fake SO', { - wake(arg = null) { - o.wake(arg); + return makeExo( + 'fake SO', + M.interface('fake SO', {}, { defaultGuards: 'passable' }), + { + wake(arg = null) { + o.wake(arg); + }, }, - }); + ); } function makeHandler() { let calls = 0; const args = []; - return Far('wake handler', { - getCalls() { - return calls; - }, - getArgs() { - return args; - }, - wake(arg) { - args.push(arg); - calls += 1; + return makeExo( + 'wake handler', + M.interface('wake handler', {}, { defaultGuards: 'passable' }), + { + getCalls() { + return calls; + }, + getArgs() { + return args; + }, + wake(arg) { + args.push(arg); + calls += 1; + }, }, - }); + ); } function makeFakeTimer(initialVal) { let fakeTime = initialVal; - return Far('fake timer', { - getLastPolled() { - return fakeTime; - }, - setTime(t) { - fakeTime = t; + return makeExo( + 'fake timer', + M.interface('fake timer', {}, { defaultGuards: 'passable' }), + { + getLastPolled() { + return fakeTime; + }, + setTime(t) { + fakeTime = t; + }, }, - }); + ); } test('Timer schedule single event', t => { diff --git a/packages/SwingSet/test/test-vat-timer.js b/packages/SwingSet/test/test-vat-timer.js index ef1a5b305ad..27cf846e163 100644 --- a/packages/SwingSet/test/test-vat-timer.js +++ b/packages/SwingSet/test/test-vat-timer.js @@ -67,9 +67,21 @@ test('cancels', t => { const removeCancel = (cancelToken, event) => debugTools.removeCancel(cancels, cancelToken, event); - const cancel1 = Far('cancel token', {}); - const cancel2 = Far('cancel token', {}); - const cancel3 = Far('cancel token', {}); + const cancel1 = makeExo( + 'cancel token', + M.interface('cancel token', {}, { defaultGuards: 'passable' }), + {}, + ); + const cancel2 = makeExo( + 'cancel token', + M.interface('cancel token', {}, { defaultGuards: 'passable' }), + {}, + ); + const cancel3 = makeExo( + 'cancel token', + M.interface('cancel token', {}, { defaultGuards: 'passable' }), + {}, + ); addCancel(cancel1, 'e10'); addCancel(cancel2, 'e20'); addCancel(cancel3, 'e30'); @@ -174,17 +186,21 @@ const setup = async (t, allowRefire = false) => { const fired = {}; const makeHandler = which => - Far('handler', { - wake(time) { - // handlers/promises get the most recent timestamp - if (!allowRefire) { - // some tests re-use the handler, but the rest should not - // observe handler.wake() called more than once - t.is(fired[which], undefined, 'wake() called multiple times'); - } - fired[which] = time; + makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { + wake(time) { + // handlers/promises get the most recent timestamp + if (!allowRefire) { + // some tests re-use the handler, but the rest should not + // observe handler.wake() called more than once + t.is(fired[which], undefined, 'wake() called multiple times'); + } + fired[which] = time; + }, }, - }); + ); const thenFire = (p, which) => { p.then( @@ -233,12 +249,20 @@ test('brand', async t => { t.false(brand.isMyClock(brand)); t.false(brand.isMyClock(ts)); - const handler = Far('handler', { wake: _time => 0 }); + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { wake: _time => 0 }, + ); const right = ts.getTimerBrand(); - const wrong = Far('wrong', { - isMyTimerService: () => false, - isMyClock: () => false, - }); + const wrong = makeExo( + 'wrong', + M.interface('wrong', {}, { defaultGuards: 'passable' }), + { + isMyTimerService: () => false, + isMyClock: () => false, + }, + ); t.not(right, wrong); const when = TimeMath.coerceTimestampRecord(1000n, wrong); @@ -313,7 +337,11 @@ test('setWakeup', async t => { t.not(state.currentHandler, undefined); // an earlier setWakeup brings the alarm forward - const cancel20 = Far('cancel token', {}); + const cancel20 = makeExo( + 'cancel token', + M.interface('cancel token', {}, { defaultGuards: 'passable' }), + {}, + ); ts.setWakeup(toTS(20n), makeHandler(20), cancel20); t.is(state.currentWakeup, 20n); @@ -326,7 +354,11 @@ test('setWakeup', async t => { ts.setWakeup(toTS(50n), makeHandler(50)); ts.setWakeup(toTS(50n), makeHandler('50x')); // cancel tokens can be shared - const cancel6x = Far('cancel token', {}); + const cancel6x = makeExo( + 'cancel token', + M.interface('cancel token', {}, { defaultGuards: 'passable' }), + {}, + ); ts.setWakeup(toTS(60n), makeHandler(60n), cancel6x); ts.setWakeup(toTS(60n), makeHandler('60x')); ts.setWakeup(toTS(61n), makeHandler(61n), cancel6x); @@ -377,8 +409,16 @@ test('wakeAt', async t => { // p = ts.wakeAt(absolute, cancelToken=undefined) const { ts, state, fired, thenFire, toTS } = await setup(t); - const cancel10 = Far('cancel token', {}); - const cancel20 = Far('cancel token', {}); + const cancel10 = makeExo( + 'cancel token', + M.interface('cancel token', {}, { defaultGuards: 'passable' }), + {}, + ); + const cancel20 = makeExo( + 'cancel token', + M.interface('cancel token', {}, { defaultGuards: 'passable' }), + {}, + ); thenFire(ts.wakeAt(toTS(10n), cancel10), '10'); thenFire(ts.wakeAt(toTS(10n)), '10x'); thenFire(ts.wakeAt(toTS(20n), cancel20), '20'); @@ -420,8 +460,16 @@ test('delay', async t => { state.now = 100n; - const cancel10 = Far('cancel token', {}); - const cancel20 = Far('cancel token', {}); + const cancel10 = makeExo( + 'cancel token', + M.interface('cancel token', {}, { defaultGuards: 'passable' }), + {}, + ); + const cancel20 = makeExo( + 'cancel token', + M.interface('cancel token', {}, { defaultGuards: 'passable' }), + {}, + ); thenFire(ts.delay(toRT(10n), cancel10), '10'); // =110 thenFire(ts.delay(toRT(10n)), '10x'); // =110 thenFire(ts.delay(toRT(20n), cancel20), '20'); // =120 @@ -525,12 +573,16 @@ test('makeRepeater', async t => { let pk = makePromiseKit(); let slowState = 'uncalled'; - const slowHandler = Far('slow', { - wake(time) { - slowState = time; - return pk.promise; + const slowHandler = makeExo( + 'slow', + M.interface('slow', {}, { defaultGuards: 'passable' }), + { + wake(time) { + slowState = time; + return pk.promise; + }, }, - }); + ); // we can .schedule a new handler if the repeater is not active r1.schedule(slowHandler); await waitUntilQuiescent(); @@ -554,11 +606,15 @@ test('makeRepeater', async t => { r1.disable(); // if the handler rejects, the repeater is cancelled - const brokenHandler = Far('broken', { - wake(_time) { - throw Error('deliberate handler error'); + const brokenHandler = makeExo( + 'broken', + M.interface('broken', {}, { defaultGuards: 'passable' }), + { + wake(_time) { + throw Error('deliberate handler error'); + }, }, - }); + ); r1.schedule(brokenHandler); await waitUntilQuiescent(); t.is(state.currentWakeup, 105n); @@ -637,7 +693,11 @@ test('repeatAfter', async t => { state.now = 3n; // fire at T=25,35,45,.. - const cancel1 = Far('cancel', {}); + const cancel1 = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); ts.repeatAfter(toRT(22n), toRT(10n), makeHandler(1), cancel1); t.is(state.currentWakeup, 25n); @@ -691,14 +751,22 @@ test('repeatAfter', async t => { let pk = makePromiseKit(); let slowState = 'uncalled'; - const slowHandler = Far('slow', { - wake(time) { - slowState = time; - return pk.promise; + const slowHandler = makeExo( + 'slow', + M.interface('slow', {}, { defaultGuards: 'passable' }), + { + wake(time) { + slowState = time; + return pk.promise; + }, }, - }); + ); - const cancel2 = Far('cancel', {}); + const cancel2 = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); ts.repeatAfter(toRT(5n), toRT(10n), slowHandler, cancel2); await waitUntilQuiescent(); t.is(state.currentWakeup, 75n); @@ -722,11 +790,15 @@ test('repeatAfter', async t => { await waitUntilQuiescent(); // if the handler rejects, the repeater is cancelled - const brokenHandler = Far('broken', { - wake(_time) { - throw Error('expected error'); + const brokenHandler = makeExo( + 'broken', + M.interface('broken', {}, { defaultGuards: 'passable' }), + { + wake(_time) { + throw Error('expected error'); + }, }, - }); + ); // we can re-use cancel tokens too ts.repeatAfter(toRT(5n), toRT(10n), brokenHandler, cancel1); await waitUntilQuiescent(); @@ -744,7 +816,11 @@ test('repeatAfter', async t => { // we can cancel while the handler is running pk = makePromiseKit(); slowState = 'uncalled'; - const cancel3 = Far('cancel', {}); + const cancel3 = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); ts.repeatAfter(toRT(5n), toRT(10n), slowHandler, cancel3); await waitUntilQuiescent(); t.is(state.currentWakeup, 115n); @@ -767,7 +843,11 @@ test('repeatAfter from now', async t => { state.now = 3n; // delay=0 fires right away - const cancel1 = Far('cancel1', {}); + const cancel1 = makeExo( + 'cancel1', + M.interface('cancel1', {}, { defaultGuards: 'passable' }), + {}, + ); ts.repeatAfter(toRT(0n), toRT(10n), makeHandler(3), cancel1); t.is(state.currentWakeup, undefined); await waitUntilQuiescent(); @@ -779,15 +859,23 @@ test('repeatAfter from now', async t => { t.is(state.currentWakeup, undefined); // unscheduled // delay=0 can be cancelled during slow handler - const cancel2 = Far('cancel2', {}); + const cancel2 = makeExo( + 'cancel2', + M.interface('cancel2', {}, { defaultGuards: 'passable' }), + {}, + ); const pk2 = makePromiseKit(); let slowState2 = 'uncalled'; - const slowHandler2 = Far('slow', { - wake(time) { - slowState2 = time; - return pk2.promise; + const slowHandler2 = makeExo( + 'slow', + M.interface('slow', {}, { defaultGuards: 'passable' }), + { + wake(time) { + slowState2 = time; + return pk2.promise; + }, }, - }); + ); ts.repeatAfter(toRT(0n), toRT(10n), slowHandler2, cancel2); // 3,13,.. await waitUntilQuiescent(); t.deepEqual(slowState2, toTS(3n)); @@ -798,15 +886,23 @@ test('repeatAfter from now', async t => { t.is(state.currentWakeup, undefined); // not rescheduled // cancellation during slow handler which rejects (thus cancels again) - const cancel3 = Far('cancel3', {}); + const cancel3 = makeExo( + 'cancel3', + M.interface('cancel3', {}, { defaultGuards: 'passable' }), + {}, + ); const pk3 = makePromiseKit(); let slowState3 = 'uncalled'; - const slowHandler3 = Far('slow', { - wake(time) { - slowState3 = time; - return pk3.promise; + const slowHandler3 = makeExo( + 'slow', + M.interface('slow', {}, { defaultGuards: 'passable' }), + { + wake(time) { + slowState3 = time; + return pk3.promise; + }, }, - }); + ); ts.repeatAfter(toRT(0n), toRT(10n), slowHandler3, cancel3); // 3,13,.. await waitUntilQuiescent(); t.deepEqual(slowState3, toTS(3n)); @@ -823,14 +919,22 @@ test('repeatAfter shared cancel token', async t => { state.now = 0n; - const throwingHandler = Far('handler', { - wake(time) { - fired.thrower = time; - throw Error('boom'); + const throwingHandler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { + wake(time) { + fired.thrower = time; + throw Error('boom'); + }, }, - }); + ); - const cancel1 = Far('cancel', {}); + const cancel1 = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); // first repeater fires at T=5,15,25,35 ts.repeatAfter(toRT(5n), toRT(10n), makeHandler(1), cancel1); // second repeater fires at T=10,20,30,40 @@ -869,7 +973,11 @@ test('notifier in future', async t => { state.now = 100n; // fire at T=125,135,145,.. - const cancel1 = Far('cancel', {}); + const cancel1 = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); const n = ts.makeNotifier(toRT(25n), toRT(10n), cancel1); t.is(state.currentWakeup, undefined); // not active yet @@ -976,7 +1084,11 @@ test('cancel notifier', async t => { state.now = 0n; // cancel n1 while inactive, before it ever fires - const cancel1 = Far('cancel', {}); + const cancel1 = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); const n1 = ts.makeNotifier(toRT(5n - state.now), toRT(10n), cancel1); // T=5,15, t.is(state.currentWakeup, undefined); // not active yet const p1a = n1.getUpdateSince(undefined); @@ -990,7 +1102,11 @@ test('cancel notifier', async t => { t.deepEqual(await p1c, { value: toTS(1n), updateCount: undefined }); // cancel n2 while active, but before it ever fires - const cancel2 = Far('cancel', {}); + const cancel2 = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); const n2 = ts.makeNotifier(toRT(5n - state.now), toRT(10n), cancel2); // T=5,15, t.is(state.currentWakeup, undefined); // not active yet const p2a = n2.getUpdateSince(undefined); @@ -1008,7 +1124,11 @@ test('cancel notifier', async t => { t.deepEqual(await p2d, { value: toTS(3n), updateCount: undefined }); // cancel n3 while idle, immediately after first firing - const cancel3 = Far('cancel', {}); + const cancel3 = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); const n3 = ts.makeNotifier(toRT(5n - state.now), toRT(10n), cancel3); // T=5,15, const p3a = n3.getUpdateSince(undefined); t.is(state.currentWakeup, 5n); // primed @@ -1027,7 +1147,11 @@ test('cancel notifier', async t => { // cancel n4 while idle, slightly after first firing - const cancel4 = Far('cancel', {}); + const cancel4 = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); const n4 = ts.makeNotifier(toRT(10n - state.now), toRT(10n), cancel4); // T=10,20, const p4a = n4.getUpdateSince(undefined); t.is(state.currentWakeup, 10n); // primed @@ -1048,7 +1172,11 @@ test('cancel notifier', async t => { t.deepEqual(await p4d, { value: toTS(11n), updateCount: undefined }); // cancel n5 while active, after first firing - const cancel5 = Far('cancel', {}); + const cancel5 = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); const n5 = ts.makeNotifier(toRT(20n - state.now), toRT(10n), cancel5); // fire at T=20,30, const p5a = n5.getUpdateSince(undefined); t.is(state.currentWakeup, 20n); // primed @@ -1212,7 +1340,11 @@ test('cancel active iterator', async t => { state.now = 100n; // fire at T=125,135,145,.. - const cancel1 = Far('cancel', {}); + const cancel1 = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); const n = ts.makeNotifier(toRT(25n), toRT(10n), cancel1); // Cancellation halts the iterator, and the "return value" is the @@ -1246,7 +1378,11 @@ test('cancel idle iterator', async t => { state.now = 100n; // fire at T=125,135,145,.. - const cancel1 = Far('cancel', {}); + const cancel1 = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); const n = ts.makeNotifier(toRT(25), toRT(10), cancel1); ts.cancel(cancel1); // before first event diff --git a/packages/SwingSet/test/timer-device/bootstrap.js b/packages/SwingSet/test/timer-device/bootstrap.js index 14bee765765..e8af0aa808e 100644 --- a/packages/SwingSet/test/timer-device/bootstrap.js +++ b/packages/SwingSet/test/timer-device/bootstrap.js @@ -5,34 +5,51 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers, vatParameters) { const { D } = vatPowers; const log = vatPowers.testLog; - return Far('root', { - async bootstrap(vats, devices) { - const { argv } = vatParameters; - if (argv[0] === 'timer') { - log(`starting wake test`); - const handler = Far('handler', { - wake() { - log(`handler.wake()`); - }, - }); - D(devices.timer).setWakeup(3n, handler); - } else if (argv[0] === 'repeater') { - log(`starting repeater test`); - let handlerCalled = 0; - const handler = Far('handler', { - wake(h) { - handlerCalled += 1; - log( - `handler.wake(${h || 'handler'}) called ${handlerCalled} times.`, - ); - }, - }); - const rptr = D(devices.timer).makeRepeater(Nat(argv[1]), Nat(argv[2])); - const nextTime = D(devices.timer).schedule(rptr, handler); - log(`next scheduled time: ${nextTime}`); - } else { - Fail`unknown argv mode '${argv[0]}'`; - } + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const { argv } = vatParameters; + if (argv[0] === 'timer') { + log(`starting wake test`); + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { + wake() { + log(`handler.wake()`); + }, + }, + ); + D(devices.timer).setWakeup(3n, handler); + } else if (argv[0] === 'repeater') { + log(`starting repeater test`); + let handlerCalled = 0; + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { + wake(h) { + handlerCalled += 1; + log( + `handler.wake(${ + h || 'handler' + }) called ${handlerCalled} times.`, + ); + }, + }, + ); + const rptr = D(devices.timer).makeRepeater( + Nat(argv[1]), + Nat(argv[2]), + ); + const nextTime = D(devices.timer).schedule(rptr, handler); + log(`next scheduled time: ${nextTime}`); + } else { + Fail`unknown argv mode '${argv[0]}'`; + } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/timer/bootstrap-timer.js b/packages/SwingSet/test/timer/bootstrap-timer.js index e16b78eeff4..f44ae5f3d03 100644 --- a/packages/SwingSet/test/timer/bootstrap-timer.js +++ b/packages/SwingSet/test/timer/bootstrap-timer.js @@ -9,65 +9,77 @@ export function buildRootObject() { const toRT = abs => TimeMath.coerceRelativeTimeRecord(abs, timerBrand); const fromTS = timestamp => TimeMath.absValue(timestamp); const events = []; - const handler = Far('handler', { - wake(time) { - events.push(fromTS(time)); + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { + wake(time) { + events.push(fromTS(time)); + }, }, - }); - const cancelToken = Far('cancel', {}); + ); + const cancelToken = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); let repeater; - return Far('root', { - async bootstrap(vats, devices) { - ts = await E(vats.timer).createTimerService(devices.timer); - timerBrand = await E(ts).getTimerBrand(); - }, - async installWakeup(baseTime) { - const t = await E(ts).setWakeup(toTS(baseTime), handler, cancelToken); - return fromTS(t); - }, - async getEvents() { - // we need 'events' to remain mutable, but return values are - // hardened, so clone the array first - const ret = Array.from(events); - events.length = 0; - return ret; - }, - async cancel() { - return E(ts).cancel(cancelToken); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + ts = await E(vats.timer).createTimerService(devices.timer); + timerBrand = await E(ts).getTimerBrand(); + }, + async installWakeup(baseTime) { + const t = await E(ts).setWakeup(toTS(baseTime), handler, cancelToken); + return fromTS(t); + }, + async getEvents() { + // we need 'events' to remain mutable, but return values are + // hardened, so clone the array first + const ret = Array.from(events); + events.length = 0; + return ret; + }, + async cancel() { + return E(ts).cancel(cancelToken); + }, - async banana(baseTime) { - try { - console.log(`intentional 'bad setWakeup() handler' error follows`); - await E(ts).setWakeup(toTS(baseTime), 'banana'); - } catch (e) { - return e.message; - } - throw Error('banana too slippery'); - }, + async banana(baseTime) { + try { + console.log(`intentional 'bad setWakeup() handler' error follows`); + await E(ts).setWakeup(toTS(baseTime), 'banana'); + } catch (e) { + return e.message; + } + throw Error('banana too slippery'); + }, - async goodRepeater(delay, interval) { - repeater = await E(ts).makeRepeater(toRT(delay), toRT(interval)); - await E(repeater).schedule(handler); - }, + async goodRepeater(delay, interval) { + repeater = await E(ts).makeRepeater(toRT(delay), toRT(interval)); + await E(repeater).schedule(handler); + }, - async stopRepeater() { - await E(repeater).disable(); - }, + async stopRepeater() { + await E(repeater).disable(); + }, - async repeaterBadSchedule(delay, interval) { - repeater = await E(ts).makeRepeater(toRT(delay), toRT(interval)); - try { - await E(repeater).schedule('norb'); // missing arguments #4282 - return 'should have failed'; - } catch (e) { - return e.message; - } - }, + async repeaterBadSchedule(delay, interval) { + repeater = await E(ts).makeRepeater(toRT(delay), toRT(interval)); + try { + await E(repeater).schedule('norb'); // missing arguments #4282 + return 'should have failed'; + } catch (e) { + return e.message; + } + }, - async badCancel() { - await E(ts).cancel('bogus'); + async badCancel() { + await E(ts).cancel('bogus'); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/transcript/vat-bootstrap-transcript.js b/packages/SwingSet/test/transcript/vat-bootstrap-transcript.js index e1b4bc735aa..7b9a9b2c77e 100644 --- a/packages/SwingSet/test/transcript/vat-bootstrap-transcript.js +++ b/packages/SwingSet/test/transcript/vat-bootstrap-transcript.js @@ -3,18 +3,22 @@ import { E, Far } from '@endo/far'; export const buildRootObject = harden(() => { let vas; let counter = 0; - return Far('root', { - bootstrap: async (vats, devices) => { - vas = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap: async (vats, devices) => { + vas = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); + }, + create: async () => { + const { root } = await E(vas).createVatByName('bundle'); + return root; + }, + nothing: () => {}, + count: () => { + counter += 1; + return counter; + }, }, - create: async () => { - const { root } = await E(vas).createVatByName('bundle'); - return root; - }, - nothing: () => {}, - count: () => { - counter += 1; - return counter; - }, - }); + ); }); diff --git a/packages/SwingSet/test/upgrade/bootstrap-scripted-upgrade.js b/packages/SwingSet/test/upgrade/bootstrap-scripted-upgrade.js index b5762a77ad1..93553d9fbc2 100644 --- a/packages/SwingSet/test/upgrade/bootstrap-scripted-upgrade.js +++ b/packages/SwingSet/test/upgrade/bootstrap-scripted-upgrade.js @@ -25,245 +25,271 @@ export const buildRootObject = () => { let vatAdmin; let ulrikRoot; let ulrikAdmin; - const marker = Far('marker', {}); + const marker = makeExo( + 'marker', + M.interface('marker', {}, { defaultGuards: 'passable' }), + {}, + ); // for debugging, this array starts with a dummy element so // the vref of each contained object in an importing vat // (o-NN where NN starts at 1) is aligned with its index /** @type {[string, ...object]} */ const importSensors = ['skip0']; for (let i = 1; i <= NUM_SENSORS; i += 1) { - importSensors.push(Far(`import-${i}`, {})); + importSensors.push(makeExo(`import-${i}`, M.interface(`import-${i}`, {}, { defaultGuards: 'passable' }), {})); } const { promise, resolve } = makePromiseKit(); let dur; let retain; - return Far('root', { - bootstrap: async (vats, devices) => { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - }, - - getMarker: () => marker, - - getImportSensors: () => importSensors, - - buildV1: async () => { - // build Ulrik, the upgrading vat - const bcap = await E(vatAdmin).getNamedBundleCap('ulrik1'); - const vatParameters = { youAre: 'v1', marker }; - const options = { vatParameters }; - const res = await E(vatAdmin).createVat(bcap, options); - ulrikRoot = res.root; - ulrikAdmin = res.adminNode; - const version = await E(ulrikRoot).getVersion(); - const parameters = await E(ulrikRoot).getParameters(); - await E(ulrikRoot).acceptPresence(marker); - const m2 = await E(ulrikRoot).getPresence(); - assert.equal(m2, marker); - const data = await E(ulrikRoot).getData(); - - retain = await E(ulrikRoot).getExports(importSensors); - - dur = await E(ulrikRoot).getDurandal({ d1: 'd1' }); - const d1arg = await E(dur).get(); - // poor man's deepEqual - // (each enumerable own property as a [key, value] pair) - assert.equal(JSON.stringify(Object.entries(d1arg)), '[["d1","d1"]]'); - - // give version 1 a promise that won't be resolved until after upgrade - await E(ulrikRoot).acceptPromise(promise); - - // get promises that never resolve (and will be rejected at upgrade) - const [p1] = await E(ulrikRoot).getEternalPromiseInArray(); - p1.catch(() => 'hush'); - const p2 = E(ulrikRoot).getEternalPromise(); - p2.catch(() => 'hush'); - - return { version, data, p1, p2, retain, ...parameters }; - }, - - upgradeV2: async () => { - const bcap = await E(vatAdmin).getNamedBundleCap('ulrik2'); - const vatParameters = { youAre: 'v2', marker }; - const upgradeMessage = 'test upgrade'; - const upgradeResult = await E(ulrikAdmin).upgrade(bcap, { - vatParameters, - upgradeMessage, - }); - const version = await E(ulrikRoot).getVersion(); - const parameters = await E(ulrikRoot).getParameters(); - const m2 = await E(ulrikRoot).getPresence(); - assert.equal(m2, marker); - const data = await E(ulrikRoot).getData(); - - // marshal splats a bunch of log messages when it serializes - // 'remoerr' at the end of this function, warn the human - console.log(`note: expect one 'vat terminated' error logged below`); - let remoerr; // = Error('foo'); - await E(retain.rem1) - .get() - .catch(err => (remoerr = err)); - - const d1arg = await E(dur).get(); - assert.equal(d1arg.d1, 'd1'); // durable object still works - assert.equal(d1arg.new, 'new'); // in the new way - - // the durables we retained should still be viable - const doget = obj => - E(obj) + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap: async (vats, devices) => { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + }, + + getMarker: () => marker, + + getImportSensors: () => importSensors, + + buildV1: async () => { + // build Ulrik, the upgrading vat + const bcap = await E(vatAdmin).getNamedBundleCap('ulrik1'); + const vatParameters = { youAre: 'v1', marker }; + const options = { vatParameters }; + const res = await E(vatAdmin).createVat(bcap, options); + ulrikRoot = res.root; + ulrikAdmin = res.adminNode; + const version = await E(ulrikRoot).getVersion(); + const parameters = await E(ulrikRoot).getParameters(); + await E(ulrikRoot).acceptPresence(marker); + const m2 = await E(ulrikRoot).getPresence(); + assert.equal(m2, marker); + const data = await E(ulrikRoot).getData(); + + retain = await E(ulrikRoot).getExports(importSensors); + + dur = await E(ulrikRoot).getDurandal({ d1: 'd1' }); + const d1arg = await E(dur).get(); + // poor man's deepEqual + // (each enumerable own property as a [key, value] pair) + assert.equal(JSON.stringify(Object.entries(d1arg)), '[["d1","d1"]]'); + + // give version 1 a promise that won't be resolved until after upgrade + await E(ulrikRoot).acceptPromise(promise); + + // get promises that never resolve (and will be rejected at upgrade) + const [p1] = await E(ulrikRoot).getEternalPromiseInArray(); + p1.catch(() => 'hush'); + const p2 = E(ulrikRoot).getEternalPromise(); + p2.catch(() => 'hush'); + + return { version, data, p1, p2, retain, ...parameters }; + }, + + upgradeV2: async () => { + const bcap = await E(vatAdmin).getNamedBundleCap('ulrik2'); + const vatParameters = { youAre: 'v2', marker }; + const upgradeMessage = 'test upgrade'; + const upgradeResult = await E(ulrikAdmin).upgrade(bcap, { + vatParameters, + upgradeMessage, + }); + const version = await E(ulrikRoot).getVersion(); + const parameters = await E(ulrikRoot).getParameters(); + const m2 = await E(ulrikRoot).getPresence(); + assert.equal(m2, marker); + const data = await E(ulrikRoot).getData(); + + // marshal splats a bunch of log messages when it serializes + // 'remoerr' at the end of this function, warn the human + console.log(`note: expect one 'vat terminated' error logged below`); + let remoerr; // = Error('foo'); + await E(retain.rem1) .get() - .then(res => res.name); - assert.equal(await doget(retain.dur1), 'd1', 'retain.dur1 broken'); - - const dc4entries = await E(ulrikRoot).getEntries(retain.dc4); - assert.equal(dc4entries.length, 2); - const dur28 = await E(retain.dc4).get(importSensors[28]); - const imp28 = await E(dur28).getImport(); - assert.equal(imp28, importSensors[28], 'retain.dc4 broken'); - - // the durables retained by the vat in baggage should still be viable - const baggageImps = await E(ulrikRoot).checkBaggage( - importSensors[32], - importSensors[36], - ); - const { imp33, imp35, imp37, imp38 } = baggageImps; - assert.equal(imp33, importSensors[33]); - assert.equal(imp35, importSensors[35]); - assert.equal(imp37, importSensors[37]); - assert.equal(imp38, importSensors[38]); - - // all Remotable and merely-virtual objects are gone - await insistMissing(retain.vir2); - await insistMissing(retain.vir5); - await insistMissing(retain.vir7); - await insistMissing(retain.vc1, true); - await insistMissing(retain.vc3, true); - await insistMissing(retain.rem1); - await insistMissing(retain.rem2); - await insistMissing(retain.rem3); - - resolve(`message for your predecessor, don't freak out`); - - const newDur = await E(ulrikRoot).getNewDurandal(); - - return { version, data, remoerr, newDur, upgradeResult, ...parameters }; - }, - - buildV1WithLostKind: async () => { - const bcap = await E(vatAdmin).getNamedBundleCap('ulrik1'); - const events = []; - const handler = Far('handler', { ping: msg => events.push(msg) }); - const vatParameters = { youAre: 'v1', marker }; - const options = { vatParameters }; - const res = await E(vatAdmin).createVat(bcap, options); - ulrikRoot = res.root; - ulrikAdmin = res.adminNode; - await E(ulrikRoot).makeLostKind(); - await E(ulrikRoot).pingback(handler); // pushes 'ping 1' on events - return events; - }, - - upgradeV2Simple: async mode => { - const bcap = await E(vatAdmin).getNamedBundleCap('ulrik2'); - const vatParameters = { youAre: 'v2', marker, mode }; - await E(ulrikAdmin).upgrade(bcap, { vatParameters }); - return []; - }, - - upgradeV2WhichLosesKind: async () => { - const bcap = await E(vatAdmin).getNamedBundleCap('ulrik2'); - const events = []; - const handler = Far('handler', { ping: msg => events.push(msg) }); - await E(ulrikRoot).pingback(handler); // pushes 'ping 2' on events - const vatParameters = { youAre: 'v2', marker, handler }; - // vp.handler causes v2 to handler~.ping(), but that gets unwound - const p = E(ulrikAdmin).upgrade(bcap, { vatParameters }); // throws - await p.catch(e => events.push(e)); // pushes upgrade Error on events - await E(ulrikRoot).pingback(handler); // v1 pushes 'ping 3' on events - return events; - }, - - buildV1WithPing: async () => { - const bcap = await E(vatAdmin).getNamedBundleCap('ulrik1'); - const events = []; - const handler = Far('handler', { ping: msg => events.push(msg) }); - const vatParameters = { youAre: 'v1', handler }; - const options = { vatParameters }; - const res = await E(vatAdmin).createVat(bcap, options); - ulrikRoot = res.root; - ulrikAdmin = res.adminNode; - await E(ulrikRoot).pingback(handler); // goes to v1 - return events; + .catch(err => (remoerr = err)); + + const d1arg = await E(dur).get(); + assert.equal(d1arg.d1, 'd1'); // durable object still works + assert.equal(d1arg.new, 'new'); // in the new way + + // the durables we retained should still be viable + const doget = obj => + E(obj) + .get() + .then(res => res.name); + assert.equal(await doget(retain.dur1), 'd1', 'retain.dur1 broken'); + + const dc4entries = await E(ulrikRoot).getEntries(retain.dc4); + assert.equal(dc4entries.length, 2); + const dur28 = await E(retain.dc4).get(importSensors[28]); + const imp28 = await E(dur28).getImport(); + assert.equal(imp28, importSensors[28], 'retain.dc4 broken'); + + // the durables retained by the vat in baggage should still be viable + const baggageImps = await E(ulrikRoot).checkBaggage( + importSensors[32], + importSensors[36], + ); + const { imp33, imp35, imp37, imp38 } = baggageImps; + assert.equal(imp33, importSensors[33]); + assert.equal(imp35, importSensors[35]); + assert.equal(imp37, importSensors[37]); + assert.equal(imp38, importSensors[38]); + + // all Remotable and merely-virtual objects are gone + await insistMissing(retain.vir2); + await insistMissing(retain.vir5); + await insistMissing(retain.vir7); + await insistMissing(retain.vc1, true); + await insistMissing(retain.vc3, true); + await insistMissing(retain.rem1); + await insistMissing(retain.rem2); + await insistMissing(retain.rem3); + + resolve(`message for your predecessor, don't freak out`); + + const newDur = await E(ulrikRoot).getNewDurandal(); + + return { version, data, remoerr, newDur, upgradeResult, ...parameters }; + }, + + buildV1WithLostKind: async () => { + const bcap = await E(vatAdmin).getNamedBundleCap('ulrik1'); + const events = []; + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { ping: msg => events.push(msg) }, + ); + const vatParameters = { youAre: 'v1', marker }; + const options = { vatParameters }; + const res = await E(vatAdmin).createVat(bcap, options); + ulrikRoot = res.root; + ulrikAdmin = res.adminNode; + await E(ulrikRoot).makeLostKind(); + await E(ulrikRoot).pingback(handler); // pushes 'ping 1' on events + return events; + }, + + upgradeV2Simple: async mode => { + const bcap = await E(vatAdmin).getNamedBundleCap('ulrik2'); + const vatParameters = { youAre: 'v2', marker, mode }; + await E(ulrikAdmin).upgrade(bcap, { vatParameters }); + return []; + }, + + upgradeV2WhichLosesKind: async () => { + const bcap = await E(vatAdmin).getNamedBundleCap('ulrik2'); + const events = []; + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { ping: msg => events.push(msg) }, + ); + await E(ulrikRoot).pingback(handler); // pushes 'ping 2' on events + const vatParameters = { youAre: 'v2', marker, handler }; + // vp.handler causes v2 to handler~.ping(), but that gets unwound + const p = E(ulrikAdmin).upgrade(bcap, { vatParameters }); // throws + await p.catch(e => events.push(e)); // pushes upgrade Error on events + await E(ulrikRoot).pingback(handler); // v1 pushes 'ping 3' on events + return events; + }, + + buildV1WithPing: async () => { + const bcap = await E(vatAdmin).getNamedBundleCap('ulrik1'); + const events = []; + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { ping: msg => events.push(msg) }, + ); + const vatParameters = { youAre: 'v1', handler }; + const options = { vatParameters }; + const res = await E(vatAdmin).createVat(bcap, options); + ulrikRoot = res.root; + ulrikAdmin = res.adminNode; + await E(ulrikRoot).pingback(handler); // goes to v1 + return events; + }, + + buildV1KindModeTest: async v1mode => { + const bcap = await E(vatAdmin).getNamedBundleCap('ulrik1'); + const vatParameters = { youAre: 'v1', marker }; + const options = { vatParameters }; + const res = await E(vatAdmin).createVat(bcap, options); + ulrikRoot = res.root; + ulrikAdmin = res.adminNode; + retain = await E(ulrikRoot).getExports(importSensors); + ulrikRoot = res.root; + ulrikAdmin = res.adminNode; + if (v1mode === 'single') { + await E(ulrikRoot).makeSingleKind(); + } else { + await E(ulrikRoot).makeMultiKind(); + } + return []; + }, + + upgradeV2KindModeTest: async v2mode => { + const bcap = await E(vatAdmin).getNamedBundleCap('ulrik2'); + const vatParameters = { youAre: 'v2', marker, v2mode }; + await E(ulrikAdmin).upgrade(bcap, { vatParameters }); + return []; + }, + + upgradeV2WhichExplodes: async () => { + const bcap = await E(vatAdmin).getNamedBundleCap('ulrik2'); + const events = []; + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { ping: msg => events.push(msg) }, + ); + const explode = 'kaboom'; + const vatParameters = { youAre: 'v2', marker, handler, explode }; + // vp.handler causes v2 to handler~.ping(), but that gets unwound + const p = E(ulrikAdmin).upgrade(bcap, { vatParameters }); // throws + await p.catch(e => { + events.push(e); + events.push(e instanceof Error); + events.push(/vat-upgrade failure/.test(e.message)); + }); + await E(ulrikRoot).pingback(handler); // goes to post-rewind v1 + return events; + }, + + doUpgradeWithBadOption: async () => { + const bcap1 = await E(vatAdmin).getNamedBundleCap('ulrik1'); + const options1 = { vatParameters: { youAre: 'v1', marker } }; + const res = await E(vatAdmin).createVat(bcap1, options1); + ulrikAdmin = res.adminNode; + + const bcap2 = await E(vatAdmin).getNamedBundleCap('ulrik2'); + const options2 = { + vatParameters: { youAre: 'v2', marker }, + bad: 'unknown option', + }; + await E(ulrikAdmin).upgrade(bcap2, options2); // throws + }, + + doUpgradeWithoutVatParameters: async () => { + const bcap1 = await E(vatAdmin).getNamedBundleCap('ulrik1'); + const res = await E(vatAdmin).createVat(bcap1); + ulrikAdmin = res.adminNode; + const root = res.root; + const paramA = await E(root).getParameters(); + + const bcap2 = await E(vatAdmin).getNamedBundleCap('ulrik2'); + await E(ulrikAdmin).upgrade(bcap2); // no options + const paramB = await E(root).getParameters(); + + return [paramA, paramB]; + }, }, - - buildV1KindModeTest: async v1mode => { - const bcap = await E(vatAdmin).getNamedBundleCap('ulrik1'); - const vatParameters = { youAre: 'v1', marker }; - const options = { vatParameters }; - const res = await E(vatAdmin).createVat(bcap, options); - ulrikRoot = res.root; - ulrikAdmin = res.adminNode; - retain = await E(ulrikRoot).getExports(importSensors); - ulrikRoot = res.root; - ulrikAdmin = res.adminNode; - if (v1mode === 'single') { - await E(ulrikRoot).makeSingleKind(); - } else { - await E(ulrikRoot).makeMultiKind(); - } - return []; - }, - - upgradeV2KindModeTest: async v2mode => { - const bcap = await E(vatAdmin).getNamedBundleCap('ulrik2'); - const vatParameters = { youAre: 'v2', marker, v2mode }; - await E(ulrikAdmin).upgrade(bcap, { vatParameters }); - return []; - }, - - upgradeV2WhichExplodes: async () => { - const bcap = await E(vatAdmin).getNamedBundleCap('ulrik2'); - const events = []; - const handler = Far('handler', { ping: msg => events.push(msg) }); - const explode = 'kaboom'; - const vatParameters = { youAre: 'v2', marker, handler, explode }; - // vp.handler causes v2 to handler~.ping(), but that gets unwound - const p = E(ulrikAdmin).upgrade(bcap, { vatParameters }); // throws - await p.catch(e => { - events.push(e); - events.push(e instanceof Error); - events.push(/vat-upgrade failure/.test(e.message)); - }); - await E(ulrikRoot).pingback(handler); // goes to post-rewind v1 - return events; - }, - - doUpgradeWithBadOption: async () => { - const bcap1 = await E(vatAdmin).getNamedBundleCap('ulrik1'); - const options1 = { vatParameters: { youAre: 'v1', marker } }; - const res = await E(vatAdmin).createVat(bcap1, options1); - ulrikAdmin = res.adminNode; - - const bcap2 = await E(vatAdmin).getNamedBundleCap('ulrik2'); - const options2 = { - vatParameters: { youAre: 'v2', marker }, - bad: 'unknown option', - }; - await E(ulrikAdmin).upgrade(bcap2, options2); // throws - }, - - doUpgradeWithoutVatParameters: async () => { - const bcap1 = await E(vatAdmin).getNamedBundleCap('ulrik1'); - const res = await E(vatAdmin).createVat(bcap1); - ulrikAdmin = res.adminNode; - const root = res.root; - const paramA = await E(root).getParameters(); - - const bcap2 = await E(vatAdmin).getNamedBundleCap('ulrik2'); - await E(ulrikAdmin).upgrade(bcap2); // no options - const paramB = await E(root).getParameters(); - - return [paramA, paramB]; - }, - }); + ); }; diff --git a/packages/SwingSet/test/upgrade/bootstrap-upgrade-replay.js b/packages/SwingSet/test/upgrade/bootstrap-upgrade-replay.js index 607e9c9e584..e1742720406 100644 --- a/packages/SwingSet/test/upgrade/bootstrap-upgrade-replay.js +++ b/packages/SwingSet/test/upgrade/bootstrap-upgrade-replay.js @@ -5,33 +5,39 @@ export function buildRootObject() { let uptonRoot; let uptonAdmin; - return Far('root', { - async bootstrap(vats, devices) { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + }, - async buildV1() { - // build Upton, the upgrading vat - const bcap = await E(vatAdmin).getNamedBundleCap('upton'); - const vatParameters = { version: 'v1' }; - const options = { vatParameters }; - const res = await E(vatAdmin).createVat(bcap, options); - uptonRoot = res.root; - uptonAdmin = res.adminNode; - return E(uptonRoot).phase1(); - }, + async buildV1() { + // build Upton, the upgrading vat + const bcap = await E(vatAdmin).getNamedBundleCap('upton'); + const vatParameters = { version: 'v1' }; + const options = { vatParameters }; + const res = await E(vatAdmin).createVat(bcap, options); + uptonRoot = res.root; + uptonAdmin = res.adminNode; + return E(uptonRoot).phase1(); + }, - async upgradeV2() { - // upgrade Upton to version 2 - const bcap = await E(vatAdmin).getNamedBundleCap('upton'); - const vatParameters = { version: 'v2' }; - await E(uptonAdmin).upgrade(bcap, { vatParameters }); - return E(uptonRoot).phase2(); - }, + async upgradeV2() { + // upgrade Upton to version 2 + const bcap = await E(vatAdmin).getNamedBundleCap('upton'); + const vatParameters = { version: 'v2' }; + await E(uptonAdmin).upgrade(bcap, { vatParameters }); + return E(uptonRoot).phase2(); + }, - async checkReplay() { - // ask Upton to do something after a restart - return E(uptonRoot).checkReplay(); + async checkReplay() { + // ask Upton to do something after a restart + return E(uptonRoot).checkReplay(); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/upgrade/vat-ulrik-1.js b/packages/SwingSet/test/upgrade/vat-ulrik-1.js index 89c08c286df..2d787788fd9 100644 --- a/packages/SwingSet/test/upgrade/vat-ulrik-1.js +++ b/packages/SwingSet/test/upgrade/vat-ulrik-1.js @@ -144,49 +144,53 @@ export const buildRootObject = (_vatPowers, vatParameters, baggage) => { E(vatParameters.handler).ping('hello from v1'); } - return Far('root', { - getVersion: () => 'v1', - getParameters: () => vatParameters, - - acceptPresence: pres => { - baggage.init('presence', pres); - }, - getPresence: () => baggage.get('presence'), - getData: () => baggage.get('data'), - getDurandal: arg => makeDur('durandal', 0, arg), - getExports: imports => buildExports(baggage, imports), - - acceptPromise: p => { - // upgrade will reject the promises that we decide, but should - // not touch the ones we don't decide, so we hold onto this - // until upgrade, to probe for bugs in that process - heldPromise = p; - heldPromise.catch(() => 'hush'); - }, - getEternalPromiseInArray: () => [p1], - getEternalPromise: () => p2, - - makeLostKind: () => { - makeKindHandle('unhandled'); - }, - - makeSingleKind: () => { - const kh = makeKindHandle('kind'); - baggage.init('kh', kh); - defineDurableKind(kh, initEmpty, {}); - }, - - makeMultiKind: () => { - const kh = makeKindHandle('kind'); - baggage.init('kh', kh); - defineDurableKindMulti(kh, initEmpty, { - foo: {}, - bar: {}, - }); - }, - pingback: handler => { - counter += 1; - return E(handler).ping(`ping ${counter}`); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + getVersion: () => 'v1', + getParameters: () => vatParameters, + + acceptPresence: pres => { + baggage.init('presence', pres); + }, + getPresence: () => baggage.get('presence'), + getData: () => baggage.get('data'), + getDurandal: arg => makeDur('durandal', 0, arg), + getExports: imports => buildExports(baggage, imports), + + acceptPromise: p => { + // upgrade will reject the promises that we decide, but should + // not touch the ones we don't decide, so we hold onto this + // until upgrade, to probe for bugs in that process + heldPromise = p; + heldPromise.catch(() => 'hush'); + }, + getEternalPromiseInArray: () => [p1], + getEternalPromise: () => p2, + + makeLostKind: () => { + makeKindHandle('unhandled'); + }, + + makeSingleKind: () => { + const kh = makeKindHandle('kind'); + baggage.init('kh', kh); + defineDurableKind(kh, initEmpty, {}); + }, + + makeMultiKind: () => { + const kh = makeKindHandle('kind'); + baggage.init('kh', kh); + defineDurableKindMulti(kh, initEmpty, { + foo: {}, + bar: {}, + }); + }, + pingback: handler => { + counter += 1; + return E(handler).ping(`ping ${counter}`); + }, }, - }); + ); }; diff --git a/packages/SwingSet/test/upgrade/vat-ulrik-2.js b/packages/SwingSet/test/upgrade/vat-ulrik-2.js index 0d80ed3b490..c3550998a47 100644 --- a/packages/SwingSet/test/upgrade/vat-ulrik-2.js +++ b/packages/SwingSet/test/upgrade/vat-ulrik-2.js @@ -61,35 +61,39 @@ export const buildRootObject = (_vatPowers, vatParameters, baggage) => { } } - const root = Far('root', { - getVersion: () => 'v2', - getParameters: () => vatParameters, - getPresence: () => baggage.get('presence'), - getData: () => baggage.get('data'), - getEntries: collection => Array.from(collection.entries()), - checkBaggage: (imp32, imp36) => { - // console.log(`baggage:`, Array.from(baggage.keys())); - const dc5 = baggage.get('dc5'); - const dc6 = baggage.get('dc6'); - const imp33 = dc5.get(imp32).getImport(); - let dur34; - for (const key of dc6.keys()) { - if (key !== imp36) { - dur34 = key; + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + getVersion: () => 'v2', + getParameters: () => vatParameters, + getPresence: () => baggage.get('presence'), + getData: () => baggage.get('data'), + getEntries: collection => Array.from(collection.entries()), + checkBaggage: (imp32, imp36) => { + // console.log(`baggage:`, Array.from(baggage.keys())); + const dc5 = baggage.get('dc5'); + const dc6 = baggage.get('dc6'); + const imp33 = dc5.get(imp32).getImport(); + let dur34; + for (const key of dc6.keys()) { + if (key !== imp36) { + dur34 = key; + } } - } - const imp35 = dc6.get(dur34).getImport(); - assert.equal(imp36, dc6.get(imp36).getImport()); - const imp37 = baggage.get('dur37').getImport(); - const imp38 = baggage.get('imp38'); - return { imp33, imp35, imp37, imp38 }; + const imp35 = dc6.get(dur34).getImport(); + assert.equal(imp36, dc6.get(imp36).getImport()); + const imp37 = baggage.get('dur37').getImport(); + const imp38 = baggage.get('imp38'); + return { imp33, imp35, imp37, imp38 }; + }, + pingback: handler => { + counter += 1; + return E(handler).ping(`ping ${counter}`); + }, + getNewDurandal: () => newDur, }, - pingback: handler => { - counter += 1; - return E(handler).ping(`ping ${counter}`); - }, - getNewDurandal: () => newDur, - }); + ); // buildRootObject() is allowed to return a Promise, as long as it fulfills // promptly (we added this in #5246 to allow ZCF to use the async // importBundle() during contract upgrade). We return a pre-fulfilled Promise diff --git a/packages/SwingSet/test/upgrade/vat-upton-replay.js b/packages/SwingSet/test/upgrade/vat-upton-replay.js index 90c72abb998..8211c07ed5f 100644 --- a/packages/SwingSet/test/upgrade/vat-upton-replay.js +++ b/packages/SwingSet/test/upgrade/vat-upton-replay.js @@ -3,20 +3,24 @@ import { Far } from '@endo/far'; export function buildRootObject() { let counter = 0; - return Far('root', { - phase1() { - counter += 1; - return counter; - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + phase1() { + counter += 1; + return counter; + }, - phase2() { - counter += 20; - return counter; - }, + phase2() { + counter += 20; + return counter; + }, - checkReplay() { - counter += 300; - return counter; + checkReplay() { + counter += 300; + return counter; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/vat-activityhash-comms.js b/packages/SwingSet/test/vat-activityhash-comms.js index d7455679cfa..d3179bdf149 100644 --- a/packages/SwingSet/test/vat-activityhash-comms.js +++ b/packages/SwingSet/test/vat-activityhash-comms.js @@ -4,20 +4,32 @@ export function buildRootObject() { let comms; async function addNewRemote(name) { - const transmitter = Far('tx', {}); - const setReceiver = Far('sr', { - setReceiver() {}, - }); + const transmitter = makeExo( + 'tx', + M.interface('tx', {}, { defaultGuards: 'passable' }), + {}, + ); + const setReceiver = makeExo( + 'sr', + M.interface('sr', {}, { defaultGuards: 'passable' }), + { + setReceiver() {}, + }, + ); await E(comms).addRemote(name, transmitter, setReceiver); } - return Far('root', { - async bootstrap(vats) { - comms = vats.comms; - await addNewRemote('remote1'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + comms = vats.comms; + await addNewRemote('remote1'); + }, + async addRemote(name) { + await addNewRemote(name); + }, }, - async addRemote(name) { - await addNewRemote(name); - }, - }); + ); } diff --git a/packages/SwingSet/test/vat-admin/bootstrap.js b/packages/SwingSet/test/vat-admin/bootstrap.js index 5b1bcaa15ee..e47cd039730 100644 --- a/packages/SwingSet/test/vat-admin/bootstrap.js +++ b/packages/SwingSet/test/vat-admin/bootstrap.js @@ -4,81 +4,95 @@ export function buildRootObject() { let admin; let held; - const adder = Far('adder', { add1: x => x + 1 }); + const adder = makeExo( + 'adder', + M.interface('adder', {}, { defaultGuards: 'passable' }), + { add1: x => x + 1 }, + ); const options = { name: 'newvat', vatParameters: { adder } }; - return Far('root', { - async bootstrap(vats, devices) { - admin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - held = await E(vats['export-held']).createHeld(); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + admin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); + held = await E(vats['export-held']).createHeld(); + }, - async byBundle(bundle) { - const { root } = await E(admin).createVat(bundle, options); - const n = await E(root).getANumber(); - return n; - }, + async byBundle(bundle) { + const { root } = await E(admin).createVat(bundle, options); + const n = await E(root).getANumber(); + return n; + }, - async byName(bundleName) { - const { root } = await E(admin).createVatByName(bundleName, options); - const n = await E(root).getANumber(); - return n; - }, + async byName(bundleName) { + const { root } = await E(admin).createVatByName(bundleName, options); + const n = await E(root).getANumber(); + return n; + }, - async byNamedBundleCap(name) { - const bcap = await E(admin).getNamedBundleCap(name); - const { root } = await E(admin).createVat(bcap, options); - const n = await E(root).getANumber(); - return n; - }, + async byNamedBundleCap(name) { + const bcap = await E(admin).getNamedBundleCap(name); + const { root } = await E(admin).createVat(bcap, options); + const n = await E(root).getANumber(); + return n; + }, - async byID(id) { - const bcap = await E(admin).getBundleCap(id); - const { root } = await E(admin).createVat(bcap, options); - const n = await E(root).getANumber(); - return n; - }, + async byID(id) { + const bcap = await E(admin).getBundleCap(id); + const { root } = await E(admin).createVat(bcap, options); + const n = await E(root).getANumber(); + return n; + }, - async counters(bundleName) { - const { root } = await E(admin).createVatByName(bundleName, options); - const c = E(root).createRcvr(1); - const log = []; - log.push(await E(c).increment(3)); - log.push(await E(c).increment(5)); - log.push(await E(c).ticker()); - log.push(await E(c).add2(6)); - return log; - }, + async counters(bundleName) { + const { root } = await E(admin).createVatByName(bundleName, options); + const c = E(root).createRcvr(1); + const log = []; + log.push(await E(c).increment(3)); + log.push(await E(c).increment(5)); + log.push(await E(c).ticker()); + log.push(await E(c).add2(6)); + return log; + }, - async brokenVat(bundleName) { - return E(admin).createVatByName(bundleName); // should reject - }, + async brokenVat(bundleName) { + return E(admin).createVatByName(bundleName); // should reject + }, - async nonBundleCap() { - return E(admin).createVat(Far('non-bundlecap', {})); // should reject - }, + async nonBundleCap() { + return E(admin).createVat( + makeExo( + 'non-bundlecap', + M.interface('non-bundlecap', {}, { defaultGuards: 'passable' }), + {}, + ), + ); // should reject + }, - async vatName(name) { - const opts = { name, vatParameters: {} }; - await E(admin).createVatByName('new13', opts); - return 'ok'; - }, + async vatName(name) { + const opts = { name, vatParameters: {} }; + await E(admin).createVatByName('new13', opts); + return 'ok'; + }, - async badOptions() { - const opts = { bogus: 'nope' }; - return E(admin).createVatByName('new13', opts); // should reject - }, + async badOptions() { + const opts = { bogus: 'nope' }; + return E(admin).createVatByName('new13', opts); // should reject + }, - getHeld() { - return held; - }, + getHeld() { + return held; + }, - refcount(id) { - // bootstrap retains 'held' the whole time, contributing one refcount - return E(admin) - .getBundleCap(id) - .then(bcap => E(admin).createVat(bcap, { vatParameters: { held } })) - .then(() => 0); + refcount(id) { + // bootstrap retains 'held' the whole time, contributing one refcount + return E(admin) + .getBundleCap(id) + .then(bcap => E(admin).createVat(bcap, { vatParameters: { held } })) + .then(() => 0); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/vat-admin/new-vat-13.js b/packages/SwingSet/test/vat-admin/new-vat-13.js index 6d32acce6fe..42071a79ce4 100644 --- a/packages/SwingSet/test/vat-admin/new-vat-13.js +++ b/packages/SwingSet/test/vat-admin/new-vat-13.js @@ -5,31 +5,39 @@ export function buildRootObject(_vatPowers, vatParameters) { function rcvrMaker(seed) { let count = 0; let sum = seed; - return Far('rcvr', { - increment(val) { - sum += val; - count += 1; - return sum; + return makeExo( + 'rcvr', + M.interface('rcvr', {}, { defaultGuards: 'passable' }), + { + increment(val) { + sum += val; + count += 1; + return sum; + }, + add2(val) { + return E(adder).add1(val + 1); + }, + ticker() { + return count; + }, }, - add2(val) { - return E(adder).add1(val + 1); + ); + } + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + getANumber() { + return 13; }, - ticker() { - return count; + sendMsg(obj, arg) { + return E(obj).message(arg); + }, + createRcvr(init) { + return rcvrMaker(init); }, - }); - } - const root = Far('root', { - getANumber() { - return 13; - }, - sendMsg(obj, arg) { - return E(obj).message(arg); - }, - createRcvr(init) { - return rcvrMaker(init); }, - }); + ); // exercise async return return Promise.resolve(root); } diff --git a/packages/SwingSet/test/vat-admin/new-vat-44.js b/packages/SwingSet/test/vat-admin/new-vat-44.js index f8e718b458f..c480a5239ca 100644 --- a/packages/SwingSet/test/vat-admin/new-vat-44.js +++ b/packages/SwingSet/test/vat-admin/new-vat-44.js @@ -2,9 +2,13 @@ import { Far, E } from '@endo/far'; export function buildRootObject(_vatPowers, vatParameters) { const { adder } = vatParameters; - return Far('root', { - getANumber() { - return E(adder).add1(43); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + getANumber() { + return E(adder).add1(43); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/vat-admin/new-vat-refcount.js b/packages/SwingSet/test/vat-admin/new-vat-refcount.js index af86ea718a4..ac95bfe2b2e 100644 --- a/packages/SwingSet/test/vat-admin/new-vat-refcount.js +++ b/packages/SwingSet/test/vat-admin/new-vat-refcount.js @@ -2,7 +2,11 @@ import { Far } from '@endo/far'; export function buildRootObject(_vatPowers, vatParameters) { const { held } = vatParameters; - return Far('root', { - foo: () => held, // hold until root goes away - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + foo: () => held, // hold until root goes away + }, + ); } diff --git a/packages/SwingSet/test/vat-admin/replay-bootstrap.js b/packages/SwingSet/test/vat-admin/replay-bootstrap.js index 74eb82e3b13..eb17aa03776 100644 --- a/packages/SwingSet/test/vat-admin/replay-bootstrap.js +++ b/packages/SwingSet/test/vat-admin/replay-bootstrap.js @@ -6,36 +6,42 @@ export function buildRootObject() { let root; let vats; - return Far('root', { - async bootstrap(vats0, devices) { - vats = vats0; - gotVatAdminSvc(E(vats.vatAdmin).createVatAdminService(devices.vatAdmin)); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats0, devices) { + vats = vats0; + gotVatAdminSvc( + E(vats.vatAdmin).createVatAdminService(devices.vatAdmin), + ); + }, - async createVat() { - // cause vat-vattp to record a device error in its transcript, - // to exercise the fix for #5511 - E(vatAdminSvc) - .getNamedBundleCap('missing') - .catch(_err => 0); - const bcap = await E(vatAdminSvc).getNamedBundleCap('dynamic'); - const vc = await E(vatAdminSvc).createVat(bcap); - root = vc.root; - const count = await E(root).first(); - return count === 1 ? 'created' : `wrong counter ${count}`; - }, + async createVat() { + // cause vat-vattp to record a device error in its transcript, + // to exercise the fix for #5511 + E(vatAdminSvc) + .getNamedBundleCap('missing') + .catch(_err => 0); + const bcap = await E(vatAdminSvc).getNamedBundleCap('dynamic'); + const vc = await E(vatAdminSvc).createVat(bcap); + root = vc.root; + const count = await E(root).first(); + return count === 1 ? 'created' : `wrong counter ${count}`; + }, - // if the dynamic vat was not reloaded into the next-generation swingset, - // root~.second() will fail (there won't be a vat in ephemeral.vats when - // the message comes to the top of the run queue, and our result promise - // will never resolve) + // if the dynamic vat was not reloaded into the next-generation swingset, + // root~.second() will fail (there won't be a vat in ephemeral.vats when + // the message comes to the top of the run queue, and our result promise + // will never resolve) - // if the vat exists but its transcript was not replayed, the +=1 will - // not have happened, and root~.second() will return 20, not 21 + // if the vat exists but its transcript was not replayed, the +=1 will + // not have happened, and root~.second() will return 20, not 21 - async check() { - const count = await E(root).second(); - return count === 21 ? 'ok' : `wrong counter ${count}`; + async check() { + const count = await E(root).second(); + return count === 21 ? 'ok' : `wrong counter ${count}`; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/vat-admin/replay-dynamic.js b/packages/SwingSet/test/vat-admin/replay-dynamic.js index d9cfd8156fe..720e924b188 100644 --- a/packages/SwingSet/test/vat-admin/replay-dynamic.js +++ b/packages/SwingSet/test/vat-admin/replay-dynamic.js @@ -2,14 +2,18 @@ import { Far } from '@endo/far'; export function buildRootObject() { let counter = 0; - return Far('root', { - first() { - counter += 1; - return counter; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + first() { + counter += 1; + return counter; + }, + second() { + counter += 20; + return counter; + }, }, - second() { - counter += 20; - return counter; - }, - }); + ); } diff --git a/packages/SwingSet/test/vat-admin/terminate/bootstrap-badVatKey.js b/packages/SwingSet/test/vat-admin/terminate/bootstrap-badVatKey.js index 728d6f3cbb8..18f47f7153d 100644 --- a/packages/SwingSet/test/vat-admin/terminate/bootstrap-badVatKey.js +++ b/packages/SwingSet/test/vat-admin/terminate/bootstrap-badVatKey.js @@ -1,12 +1,18 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { - return Far('root', { - async bootstrap(vats, devices) { - const vatMaker = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - await E(vatMaker).createVatByName('dude', { - critical: true, // this is bogus and should fail - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatMaker = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + await E(vatMaker).createVatByName('dude', { + critical: true, // this is bogus and should fail + }); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/vat-admin/terminate/bootstrap-die-cleanly.js b/packages/SwingSet/test/vat-admin/terminate/bootstrap-die-cleanly.js index 8b67c11b9a1..dc6d83a8a27 100644 --- a/packages/SwingSet/test/vat-admin/terminate/bootstrap-die-cleanly.js +++ b/packages/SwingSet/test/vat-admin/terminate/bootstrap-die-cleanly.js @@ -3,21 +3,27 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { let dude; - const self = Far('root', { - async bootstrap(vats, devices) { - const vatMaker = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); + const self = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatMaker = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); - // create a dynamic vat, send it a message and let it respond, to make - // sure everything is working - dude = await E(vatMaker).createVatByName('dude'); - await E(dude.root).foo(1); - return 'bootstrap done'; + // create a dynamic vat, send it a message and let it respond, to make + // sure everything is working + dude = await E(vatMaker).createVatByName('dude'); + await E(dude.root).foo(1); + return 'bootstrap done'; + }, + async phase2() { + // terminate as a second phase, so we can capture the kernel state in between + E(dude.adminNode).terminateWithFailure('phase 2'); + await E(dude.adminNode).done(); + }, }, - async phase2() { - // terminate as a second phase, so we can capture the kernel state in between - E(dude.adminNode).terminateWithFailure('phase 2'); - await E(dude.adminNode).done(); - }, - }); + ); return self; } diff --git a/packages/SwingSet/test/vat-admin/terminate/bootstrap-die-with-presence.js b/packages/SwingSet/test/vat-admin/terminate/bootstrap-die-with-presence.js index 5428150a2a8..6e8707643f6 100644 --- a/packages/SwingSet/test/vat-admin/terminate/bootstrap-die-with-presence.js +++ b/packages/SwingSet/test/vat-admin/terminate/bootstrap-die-with-presence.js @@ -3,26 +3,32 @@ import { Far, E } from '@endo/far'; export function buildRootObject(vatPowers) { const { testLog } = vatPowers; - const self = Far('root', { - async bootstrap(vats, devices) { - testLog('preparing dynamic vat'); - const vatMaker = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - const dude = await E(vatMaker).createVatByName('dude'); - E(dude.root).dieReturningAPresence(self); - const doneP = E(dude.adminNode).done(); - try { - const doneResult = await doneP; - testLog(`done message: ${doneResult.message}`); - await E(doneResult.emissary).talkBack('from beyond?'); - } catch (e) { - testLog(`done exception ${e} (this should not happen)`); - } - testLog('done'); - }, + const self = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + testLog('preparing dynamic vat'); + const vatMaker = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + const dude = await E(vatMaker).createVatByName('dude'); + E(dude.root).dieReturningAPresence(self); + const doneP = E(dude.adminNode).done(); + try { + const doneResult = await doneP; + testLog(`done message: ${doneResult.message}`); + await E(doneResult.emissary).talkBack('from beyond?'); + } catch (e) { + testLog(`done exception ${e} (this should not happen)`); + } + testLog('done'); + }, - talkBack(arg) { - testLog(`talkback ${arg}`); + talkBack(arg) { + testLog(`talkback ${arg}`); + }, }, - }); + ); return self; } diff --git a/packages/SwingSet/test/vat-admin/terminate/bootstrap-no-zombies.js b/packages/SwingSet/test/vat-admin/terminate/bootstrap-no-zombies.js index 3ecdd90937d..a9bb61f87c9 100644 --- a/packages/SwingSet/test/vat-admin/terminate/bootstrap-no-zombies.js +++ b/packages/SwingSet/test/vat-admin/terminate/bootstrap-no-zombies.js @@ -1,22 +1,28 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { - const self = Far('root', { - async bootstrap(vats, devices) { - const vatMaker = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); + const self = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatMaker = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); - // create a dynamic vat, send it a message and let it respond, to make - // sure everything is working - const weatherwax = await E(vatMaker).createVatByName('weatherwax'); - await E(weatherwax.root).live(); - E(weatherwax.adminNode).terminateWithFailure('no zombies?'); - try { - await E(weatherwax.adminNode).done(); - } catch (e) { - // ignored - } - return 'bootstrap done'; + // create a dynamic vat, send it a message and let it respond, to make + // sure everything is working + const weatherwax = await E(vatMaker).createVatByName('weatherwax'); + await E(weatherwax.root).live(); + E(weatherwax.adminNode).terminateWithFailure('no zombies?'); + try { + await E(weatherwax.adminNode).done(); + } catch (e) { + // ignored + } + return 'bootstrap done'; + }, }, - }); + ); return self; } diff --git a/packages/SwingSet/test/vat-admin/terminate/bootstrap-speak-to-dead.js b/packages/SwingSet/test/vat-admin/terminate/bootstrap-speak-to-dead.js index ee255796b80..3f708c81889 100644 --- a/packages/SwingSet/test/vat-admin/terminate/bootstrap-speak-to-dead.js +++ b/packages/SwingSet/test/vat-admin/terminate/bootstrap-speak-to-dead.js @@ -7,53 +7,59 @@ export function buildRootObject(vatPowers) { let weatherwaxRoot; let rAfterG; - const self = Far('root', { - async bootstrap(vats, devices) { - const vatMaker = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - mediumRoot = vats.medium; - - // create a dynamic vat, then kill it, then try to send it a message - - const weatherwax = await E(vatMaker).createVatByName('weatherwax'); - weatherwaxRoot = weatherwax.root; - - const { promise: pBefore, resolve: rBefore } = makePromiseKit(); - const { promise: pAfter, resolve: rAfter } = makePromiseKit(); - rAfterG = rAfter; - const [p1, p2] = await E(weatherwaxRoot).rememberThese(pBefore, pAfter); - p1.then( - v => testLog(`b: p1b = ${v}`), - e => testLog(`b: p1b fails ${e}`), - ); - p2.then( - v => testLog(`b: p2b = ${v}`), - e => testLog(`b: p2b fails ${e}`), - ); - rBefore('before'); - - try { - await E(mediumRoot).speak(weatherwaxRoot, '1'); - } catch (e) { - testLog(`b: speak failed: ${e}`); - } - - E(weatherwax.adminNode).terminateWithFailure(Error('arbitrary reason')); - try { - await E(weatherwax.adminNode).done(); - } catch (e) { - testLog(`done: ${e}`); - } - - return 'bootstrap done'; - }, - async speakAgain() { - rAfterG('after'); - try { - await E(mediumRoot).speak(weatherwaxRoot, '2'); - } catch (e) { - testLog(`b: respeak failed: ${e}`); - } + const self = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatMaker = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + mediumRoot = vats.medium; + + // create a dynamic vat, then kill it, then try to send it a message + + const weatherwax = await E(vatMaker).createVatByName('weatherwax'); + weatherwaxRoot = weatherwax.root; + + const { promise: pBefore, resolve: rBefore } = makePromiseKit(); + const { promise: pAfter, resolve: rAfter } = makePromiseKit(); + rAfterG = rAfter; + const [p1, p2] = await E(weatherwaxRoot).rememberThese(pBefore, pAfter); + p1.then( + v => testLog(`b: p1b = ${v}`), + e => testLog(`b: p1b fails ${e}`), + ); + p2.then( + v => testLog(`b: p2b = ${v}`), + e => testLog(`b: p2b fails ${e}`), + ); + rBefore('before'); + + try { + await E(mediumRoot).speak(weatherwaxRoot, '1'); + } catch (e) { + testLog(`b: speak failed: ${e}`); + } + + E(weatherwax.adminNode).terminateWithFailure(Error('arbitrary reason')); + try { + await E(weatherwax.adminNode).done(); + } catch (e) { + testLog(`done: ${e}`); + } + + return 'bootstrap done'; + }, + async speakAgain() { + rAfterG('after'); + try { + await E(mediumRoot).speak(weatherwaxRoot, '2'); + } catch (e) { + testLog(`b: respeak failed: ${e}`); + } + }, }, - }); + ); return self; } diff --git a/packages/SwingSet/test/vat-admin/terminate/bootstrap-terminate-with-presence.js b/packages/SwingSet/test/vat-admin/terminate/bootstrap-terminate-with-presence.js index 07a538bac65..54cb4b2487c 100644 --- a/packages/SwingSet/test/vat-admin/terminate/bootstrap-terminate-with-presence.js +++ b/packages/SwingSet/test/vat-admin/terminate/bootstrap-terminate-with-presence.js @@ -2,36 +2,46 @@ import { Far, E } from '@endo/far'; export function buildRootObject(vatPowers) { const { testLog } = vatPowers; - const marker = Far('marker', {}); + const marker = makeExo( + 'marker', + M.interface('marker', {}, { defaultGuards: 'passable' }), + {}, + ); - const self = Far('root', { - async bootstrap(vats, devices) { - const vatMaker = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); + const self = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatMaker = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); - const dude = await E(vatMaker).createVatByName('dude'); - const count1 = await E(dude.root).foo(1); - testLog(`vat ready ${count1}`); + const dude = await E(vatMaker).createVatByName('dude'); + const count1 = await E(dude.root).foo(1); + testLog(`vat ready ${count1}`); - const doneP = E(dude.adminNode).done(); - doneP.then( - answer => testLog(`doneP.then ${answer}`), - err => testLog(`doneP.catch ${err.why} ${err.marker === marker}`), - ); - const foreverP = E(dude.root).never(); - foreverP.then( - answer => testLog(`foreverP.then ${answer}`), - err => testLog(`foreverP.catch ${err}`), - ); + const doneP = E(dude.adminNode).done(); + doneP.then( + answer => testLog(`doneP.then ${answer}`), + err => testLog(`doneP.catch ${err.why} ${err.marker === marker}`), + ); + const foreverP = E(dude.root).never(); + foreverP.then( + answer => testLog(`foreverP.then ${answer}`), + err => testLog(`foreverP.catch ${err}`), + ); - const why = 'because'; - const reason = harden({ why, marker }); - const termP = E(dude.adminNode).terminateWithFailure(reason); - termP.then( - answer => testLog(`termP.then ${answer}`), - err => testLog(`termP.err ${err}`), - ); - return 'bootstrap done'; + const why = 'because'; + const reason = harden({ why, marker }); + const termP = E(dude.adminNode).terminateWithFailure(reason); + termP.then( + answer => testLog(`termP.then ${answer}`), + err => testLog(`termP.err ${err}`), + ); + return 'bootstrap done'; + }, }, - }); + ); return self; } diff --git a/packages/SwingSet/test/vat-admin/terminate/bootstrap-terminate.js b/packages/SwingSet/test/vat-admin/terminate/bootstrap-terminate.js index 851d811ff88..8a48c192c6b 100644 --- a/packages/SwingSet/test/vat-admin/terminate/bootstrap-terminate.js +++ b/packages/SwingSet/test/vat-admin/terminate/bootstrap-terminate.js @@ -8,190 +8,194 @@ export function buildRootObject(vatPowers) { let root; let adminNode; - const self = Far('root', { - bootstrap(vats, devices) { - vatAdminService = E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, - ); - staticVats = vats; - }, + const self = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats, devices) { + vatAdminService = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + staticVats = vats; + }, + + async setupCriticalVatKey() { + criticalVatKey = await E(staticVats.vatAdmin).getCriticalVatKey(); + }, + + async setupTestVat(critical, dynamic) { + // create a dynamic vat, send it a message and let it respond, to make + // sure everything is working + if (dynamic) { + const dude = await E(vatAdminService).createVatByName('dude', { + critical: critical ? criticalVatKey : false, + }); + root = dude.root; + adminNode = dude.adminNode; + } else if (critical) { + root = staticVats.staticCritical; + } else { + root = staticVats.staticNonCritical; + } + const count1 = await E(root).foo(1); + // pushes 'FOO 1' to testLog + testLog(`count1 ${count1}`); // 'count1 FOO SAYS 1' + }, + + async performTest(mode) { + // get a promise that will never be resolved, at least not until the + // vat dies + const foreverP = E(root).never(); + foreverP.then( + answer => testLog(`foreverP.then ${answer}`), + err => testLog(`foreverP.catch ${err}`), + ); - async setupCriticalVatKey() { - criticalVatKey = await E(staticVats.vatAdmin).getCriticalVatKey(); - }, + // and pipeline a message to it, which won't ever be delivered because + // we haven't configured the vat to enable pipelining. This message + // will sit in the kernel promise-table queue until the target + // resolves. When the vat is killed, this ought to be rejected too. + const afterForeverP = E(foreverP).something(); + afterForeverP.then( + answer => testLog(`afterForeverP.then ${answer}`), + err => testLog(`afterForeverP.catch ${err}`), + ); - async setupTestVat(critical, dynamic) { - // create a dynamic vat, send it a message and let it respond, to make - // sure everything is working - if (dynamic) { - const dude = await E(vatAdminService).createVatByName('dude', { - critical: critical ? criticalVatKey : false, - }); - root = dude.root; - adminNode = dude.adminNode; - } else if (critical) { - root = staticVats.staticCritical; - } else { - root = staticVats.staticNonCritical; - } - const count1 = await E(root).foo(1); - // pushes 'FOO 1' to testLog - testLog(`count1 ${count1}`); // 'count1 FOO SAYS 1' - }, + // make it send an outgoing query, both to make sure that works, and + // also to make sure never() has been delivered before the vat is + // killed + const query2 = await E(root).elsewhere(self, 2); + // pushes 'QUERY 2', 'GOT QUERY 2', 'ANSWER 2' to testLog + testLog(`query2 ${query2}`); // 'query2 2' + + // now we queue up a batch of four messages: - async performTest(mode) { - // get a promise that will never be resolved, at least not until the - // vat dies - const foreverP = E(root).never(); - foreverP.then( - answer => testLog(`foreverP.then ${answer}`), - err => testLog(`foreverP.catch ${err}`), - ); - - // and pipeline a message to it, which won't ever be delivered because - // we haven't configured the vat to enable pipelining. This message - // will sit in the kernel promise-table queue until the target - // resolves. When the vat is killed, this ought to be rejected too. - const afterForeverP = E(foreverP).something(); - afterForeverP.then( - answer => testLog(`afterForeverP.then ${answer}`), - err => testLog(`afterForeverP.catch ${err}`), - ); - - // make it send an outgoing query, both to make sure that works, and - // also to make sure never() has been delivered before the vat is - // killed - const query2 = await E(root).elsewhere(self, 2); - // pushes 'QUERY 2', 'GOT QUERY 2', 'ANSWER 2' to testLog - testLog(`query2 ${query2}`); // 'query2 2' - - // now we queue up a batch of four messages: - - // the first will trigger another outgoing query .. - const query3P = E(root).elsewhere(self, 3); - query3P.then( - answer => testLog(`query3P.then ${answer}`), - err => testLog(`query3P.catch ${err}`), - ); - // .. but it will be killed .. - switch (mode) { - case 'kill': - E(adminNode).terminateWithFailure(mode); - break; - case 'happy': - E(root).dieHappy(mode); - break; - case 'exceptionallyHappy': - E(root).dieHappy(Error(mode)); - break; - case 'happyTalkFirst': - E(root).dieHappyButTalkToMeFirst(self, mode); - break; - case 'sad': - E(root).dieSad(mode); - break; - case 'exceptionallySad': - E(root).dieSad(Error(mode)); - break; - case 'sadTalkFirst': - E(root).dieSadButTalkToMeFirst(self, Error(mode)); - break; - case 'dieReturningAPresence': - E(root).dieReturningAPresence(self, Error(mode)); - break; - default: - console.log('something terrible has happened'); - break; - } - // .. before the third message can be delivered - const foo4P = E(root).foo(4); - foo4P.then( - answer => testLog(`foo4P.then ${answer}`), - err => testLog(`foo4P.catch ${err}`), - ); - // then we try to kill the vat again, which should fail - if (mode === 'kill') { - const termP = E(adminNode).terminateWithFailure('because we said so'); - termP.then( - val => testLog(`termP.then ${val}`), - err => testLog(`termP.catch ${err}`), + // the first will trigger another outgoing query .. + const query3P = E(root).elsewhere(self, 3); + query3P.then( + answer => testLog(`query3P.then ${answer}`), + err => testLog(`query3P.catch ${err}`), + ); + // .. but it will be killed .. + switch (mode) { + case 'kill': + E(adminNode).terminateWithFailure(mode); + break; + case 'happy': + E(root).dieHappy(mode); + break; + case 'exceptionallyHappy': + E(root).dieHappy(Error(mode)); + break; + case 'happyTalkFirst': + E(root).dieHappyButTalkToMeFirst(self, mode); + break; + case 'sad': + E(root).dieSad(mode); + break; + case 'exceptionallySad': + E(root).dieSad(Error(mode)); + break; + case 'sadTalkFirst': + E(root).dieSadButTalkToMeFirst(self, Error(mode)); + break; + case 'dieReturningAPresence': + E(root).dieReturningAPresence(self, Error(mode)); + break; + default: + console.log('something terrible has happened'); + break; + } + // .. before the third message can be delivered + const foo4P = E(root).foo(4); + foo4P.then( + answer => testLog(`foo4P.then ${answer}`), + err => testLog(`foo4P.catch ${err}`), ); - } - - // the run-queue should now look like: - // [dude.elsewhere(3), adminNode.terminate, dude.foo(4), adminNode.terminate] - - // finally we wait for the kernel to tell us that the vat is dead - const doneP = adminNode ? E(adminNode).done() : null; - - // first, dude.elsewhere(self, 3) is delivered, which pushes - // 'QUERY 3' to testLog, and sends query(). The run-queue should now look like: - // [adminNode.terminate, dude.foo(4), adminNode.terminate, self.query(3)] - - // then terminate() is delivered, and the vat is killed. The kernel pushes a - // message to vatAdmin to let the done() promise resolve. The kernel also - // looks for the unresolved promises decided by the late vat, and rejects them, - // which pushes notify events on the queue - // run-queue is: - // [dude.foo(4), adminNode.terminate, self.query(3), vatAdmin.fireDone, - // self.notify(foreverP), self.notify(afterForeverP)] - - // now dude.foo(4) comes up for delivery, and deliverToVat notices the - // target is dead, so the kernel rejects the result, pushing another - // notify - // run-queue is: - // [adminNode.terminate, self.query(3), vatAdmin.fireDone, - // self.notify(foreverP), self.notify(afterForeverP), self.notify(foo4P)] - - // now the duplicate terminate() comes up, and vatAdminVat should ignore it - // run-queue is: - // [self.query(3), vatAdmin.fireDone, self.notify(foreverP), - // self.notify(afterForeverP), self.notify(foo4P)] - - // now the self.query(3) gets delivered, which pushes 'GOT QUERY 3' onto testLog, and - // resolves the result promise. The dead vat is the only subscriber, so the kernel - // pushes a notify event to vat-dude for it (which will never be delivered) - // run-queue is: - // [vatAdmin.fireDone, self.notify(foreverP), self.notify(afterForeverP), - // self.notify(foo4P), dude.notify(answerP)] - - // now vatAdmin gets fireDone, which resolves the 'done' promise we've been awaiting for, - // which pushes a notify - // run-queue is: - // [self.notify(foreverP), self.notify(afterForeverP), self.notify(foo4P), - // dude.notify(answerP), self.notify(doneP)] - - // We receive the rejection of foreverP, pushing 'foreverP.catch (err)' to testLog - // We receive the rejection of afterForeverP, pushing 'afterForeverP.catch (err)' to testLog - // run-queue is: - // [self.notify(foo4P), dude.notify(answerP), self.notify(doneP)] - - // we receive the rejection of foo4P, pushing 'foo4P.catch (err)' to - // testLog. The run-queue is: - // [dude.notify(answerP), self.notify(doneP)] - - // the dude.notify(answerP) comes to the top of the run-queue, and the - // kernel ignores it because the dude is dead. The run-queue is: - // [self.notify(doneP)] - - // We finally hear about doneP resolving, allowing the bootstrap to - // proceed to the end of the test. We push the 'done' message to testLog - if (doneP) { - try { - const v = await doneP; - testLog(`done result ${v} (Error=${v instanceof Error})`); - } catch (e) { - testLog(`done exception ${e} (Error=${e instanceof Error})`); + // then we try to kill the vat again, which should fail + if (mode === 'kill') { + const termP = E(adminNode).terminateWithFailure('because we said so'); + termP.then( + val => testLog(`termP.then ${val}`), + err => testLog(`termP.catch ${err}`), + ); } - } - testLog('done'); - return 'test done'; - }, - query(arg) { - testLog(`GOT QUERY ${arg}`); - return arg; + // the run-queue should now look like: + // [dude.elsewhere(3), adminNode.terminate, dude.foo(4), adminNode.terminate] + + // finally we wait for the kernel to tell us that the vat is dead + const doneP = adminNode ? E(adminNode).done() : null; + + // first, dude.elsewhere(self, 3) is delivered, which pushes + // 'QUERY 3' to testLog, and sends query(). The run-queue should now look like: + // [adminNode.terminate, dude.foo(4), adminNode.terminate, self.query(3)] + + // then terminate() is delivered, and the vat is killed. The kernel pushes a + // message to vatAdmin to let the done() promise resolve. The kernel also + // looks for the unresolved promises decided by the late vat, and rejects them, + // which pushes notify events on the queue + // run-queue is: + // [dude.foo(4), adminNode.terminate, self.query(3), vatAdmin.fireDone, + // self.notify(foreverP), self.notify(afterForeverP)] + + // now dude.foo(4) comes up for delivery, and deliverToVat notices the + // target is dead, so the kernel rejects the result, pushing another + // notify + // run-queue is: + // [adminNode.terminate, self.query(3), vatAdmin.fireDone, + // self.notify(foreverP), self.notify(afterForeverP), self.notify(foo4P)] + + // now the duplicate terminate() comes up, and vatAdminVat should ignore it + // run-queue is: + // [self.query(3), vatAdmin.fireDone, self.notify(foreverP), + // self.notify(afterForeverP), self.notify(foo4P)] + + // now the self.query(3) gets delivered, which pushes 'GOT QUERY 3' onto testLog, and + // resolves the result promise. The dead vat is the only subscriber, so the kernel + // pushes a notify event to vat-dude for it (which will never be delivered) + // run-queue is: + // [vatAdmin.fireDone, self.notify(foreverP), self.notify(afterForeverP), + // self.notify(foo4P), dude.notify(answerP)] + + // now vatAdmin gets fireDone, which resolves the 'done' promise we've been awaiting for, + // which pushes a notify + // run-queue is: + // [self.notify(foreverP), self.notify(afterForeverP), self.notify(foo4P), + // dude.notify(answerP), self.notify(doneP)] + + // We receive the rejection of foreverP, pushing 'foreverP.catch (err)' to testLog + // We receive the rejection of afterForeverP, pushing 'afterForeverP.catch (err)' to testLog + // run-queue is: + // [self.notify(foo4P), dude.notify(answerP), self.notify(doneP)] + + // we receive the rejection of foo4P, pushing 'foo4P.catch (err)' to + // testLog. The run-queue is: + // [dude.notify(answerP), self.notify(doneP)] + + // the dude.notify(answerP) comes to the top of the run-queue, and the + // kernel ignores it because the dude is dead. The run-queue is: + // [self.notify(doneP)] + + // We finally hear about doneP resolving, allowing the bootstrap to + // proceed to the end of the test. We push the 'done' message to testLog + if (doneP) { + try { + const v = await doneP; + testLog(`done result ${v} (Error=${v instanceof Error})`); + } catch (e) { + testLog(`done exception ${e} (Error=${e instanceof Error})`); + } + } + testLog('done'); + + return 'test done'; + }, + query(arg) { + testLog(`GOT QUERY ${arg}`); + return arg; + }, }, - }); + ); return self; } diff --git a/packages/SwingSet/test/vat-admin/terminate/vat-dude-terminate.js b/packages/SwingSet/test/vat-admin/terminate/vat-dude-terminate.js index 42da13a3cfb..064766df4af 100644 --- a/packages/SwingSet/test/vat-admin/terminate/vat-dude-terminate.js +++ b/packages/SwingSet/test/vat-admin/terminate/vat-dude-terminate.js @@ -6,43 +6,47 @@ export function buildRootObject(vatPowers) { // to be cut off const { testLog } = vatPowers; - return Far('root', { - foo(arg) { - testLog(`FOO ${arg}`); - return `FOO SAYS ${arg}`; - }, - - never() { - return makePromiseKit().promise; // never fires - }, - - dieHappy(completion) { - vatPowers.exitVat(completion); - }, - - dieSad(reason) { - vatPowers.exitVatWithFailure(reason); - }, - - dieHappyButTalkToMeFirst(other, completion) { - vatPowers.exitVat(completion); - E(other).query('not dead quite yet'); - }, - - dieSadButTalkToMeFirst(other, reason) { - vatPowers.exitVatWithFailure(reason); - E(other).query('not dead quite yet (but soon)'); - }, - - dieReturningAPresence(other) { - vatPowers.exitVat({ message: 'your ad here', emissary: other }); - }, - - async elsewhere(other, arg) { - testLog(`QUERY ${arg}`); - const answer = await E(other).query(arg); - testLog(`ANSWER ${answer}`); - return answer; - }, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + foo(arg) { + testLog(`FOO ${arg}`); + return `FOO SAYS ${arg}`; + }, + + never() { + return makePromiseKit().promise; // never fires + }, + + dieHappy(completion) { + vatPowers.exitVat(completion); + }, + + dieSad(reason) { + vatPowers.exitVatWithFailure(reason); + }, + + dieHappyButTalkToMeFirst(other, completion) { + vatPowers.exitVat(completion); + E(other).query('not dead quite yet'); + }, + + dieSadButTalkToMeFirst(other, reason) { + vatPowers.exitVatWithFailure(reason); + E(other).query('not dead quite yet (but soon)'); + }, + + dieReturningAPresence(other) { + vatPowers.exitVat({ message: 'your ad here', emissary: other }); + }, + + async elsewhere(other, arg) { + testLog(`QUERY ${arg}`); + const answer = await E(other).query(arg); + testLog(`ANSWER ${answer}`); + return answer; + }, + }, + ); } diff --git a/packages/SwingSet/test/vat-admin/terminate/vat-medium-terminate.js b/packages/SwingSet/test/vat-admin/terminate/vat-medium-terminate.js index 5f48dd4bc63..e00d485d489 100644 --- a/packages/SwingSet/test/vat-admin/terminate/vat-medium-terminate.js +++ b/packages/SwingSet/test/vat-admin/terminate/vat-medium-terminate.js @@ -3,13 +3,17 @@ import { Far, E } from '@endo/far'; export function buildRootObject(vatPowers) { const { testLog } = vatPowers; - return Far('root', { - async speak(target, tag) { - try { - await E(target).live(); - } catch (e) { - testLog(`m: live ${tag} failed: ${e}`); - } + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async speak(target, tag) { + try { + await E(target).live(); + } catch (e) { + testLog(`m: live ${tag} failed: ${e}`); + } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/vat-admin/terminate/vat-weatherwax-terminate.js b/packages/SwingSet/test/vat-admin/terminate/vat-weatherwax-terminate.js index 1dbcf3b1c52..3d49eef9790 100644 --- a/packages/SwingSet/test/vat-admin/terminate/vat-weatherwax-terminate.js +++ b/packages/SwingSet/test/vat-admin/terminate/vat-weatherwax-terminate.js @@ -7,20 +7,24 @@ export function buildRootObject(vatPowers) { const { testLog } = vatPowers; let resolvers; - return Far('root', { - live() { - testLog(`w: I ate'nt dead`); - if (resolvers && resolvers.length) { - resolvers.shift()('I so resolve'); - } + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + live() { + testLog(`w: I ate'nt dead`); + if (resolvers && resolvers.length) { + resolvers.shift()('I so resolve'); + } + }, + rememberThese(p1, p2) { + p1.then(v => testLog(`w: p1 = ${v}`)); + p2.then(v => testLog(`w: p2 = ${v}`)); + const { promise: pBefore, resolve: rBefore } = makePromiseKit(); + const { promise: pAfter, resolve: rAfter } = makePromiseKit(); + resolvers = [rBefore, rAfter]; + return [pBefore, pAfter]; + }, }, - rememberThese(p1, p2) { - p1.then(v => testLog(`w: p1 = ${v}`)); - p2.then(v => testLog(`w: p2 = ${v}`)); - const { promise: pBefore, resolve: rBefore } = makePromiseKit(); - const { promise: pAfter, resolve: rAfter } = makePromiseKit(); - resolvers = [rBefore, rAfter]; - return [pBefore, pAfter]; - }, - }); + ); } diff --git a/packages/SwingSet/test/vat-admin/vat-export-held.js b/packages/SwingSet/test/vat-admin/vat-export-held.js index 5b9f033e93c..b159f067b59 100644 --- a/packages/SwingSet/test/vat-admin/vat-export-held.js +++ b/packages/SwingSet/test/vat-admin/vat-export-held.js @@ -1,7 +1,16 @@ import { Far } from '@endo/far'; export function buildRootObject() { - return Far('root', { - createHeld: () => Far('held', {}), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + createHeld: () => + makeExo( + 'held', + M.interface('held', {}, { defaultGuards: 'passable' }), + {}, + ), + }, + ); } diff --git a/packages/SwingSet/test/vat-durable-promise-watcher.js b/packages/SwingSet/test/vat-durable-promise-watcher.js index ef4287b2699..e6182381675 100644 --- a/packages/SwingSet/test/vat-durable-promise-watcher.js +++ b/packages/SwingSet/test/vat-durable-promise-watcher.js @@ -23,19 +23,23 @@ export function buildRootObject(_vatPowers, vatParameters, baggage) { }, }); - return Far('root', { - watchLocalPromise: (name, fulfillment, rejection) => { - const { promise, resolve, reject } = makePromiseKit(); - if (fulfillment !== undefined) { - resolve(fulfillment); - } else if (rejection !== undefined) { - reject(rejection); - } - watchPromise(promise, watcher, name); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + watchLocalPromise: (name, fulfillment, rejection) => { + const { promise, resolve, reject } = makePromiseKit(); + if (fulfillment !== undefined) { + resolve(fulfillment); + } else if (rejection !== undefined) { + reject(rejection); + } + watchPromise(promise, watcher, name); + }, + getSettlements: () => { + const settlementsCopyMap = settlements.snapshot(); + return Object.fromEntries(getCopyMapEntries(settlementsCopyMap)); + }, }, - getSettlements: () => { - const settlementsCopyMap = settlements.snapshot(); - return Object.fromEntries(getCopyMapEntries(settlementsCopyMap)); - }, - }); + ); } diff --git a/packages/SwingSet/test/vat-envtest.js b/packages/SwingSet/test/vat-envtest.js index e66efd4f9c0..5427c7d828e 100644 --- a/packages/SwingSet/test/vat-envtest.js +++ b/packages/SwingSet/test/vat-envtest.js @@ -5,14 +5,18 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { const log = vatPowers.testLog; - return Far('root', { - bootstrap(_vats) { - log(`control sample: ${typeof notThere}`); - log(`harden: ${typeof harden}`); - log(`VatData: ${typeof VatData}`); - for (const prop of Object.keys(VatData)) { - log(`VatData.${prop}: ${typeof VatData[prop]}`); - } + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(_vats) { + log(`control sample: ${typeof notThere}`); + log(`harden: ${typeof harden}`); + log(`VatData: ${typeof VatData}`); + for (const prop of Object.keys(VatData)) { + log(`VatData.${prop}: ${typeof VatData[prop]}`); + } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/vat-exomessages.js b/packages/SwingSet/test/vat-exomessages.js index 60481bbd7e9..a0d1566e855 100644 --- a/packages/SwingSet/test/vat-exomessages.js +++ b/packages/SwingSet/test/vat-exomessages.js @@ -1,11 +1,15 @@ import { Far } from '@endo/far'; export function buildRootObject(_vatPowers, vatParameters) { - const other = Far('other', { - something(arg) { - return arg; + const other = makeExo( + 'other', + M.interface('other', {}, { defaultGuards: 'passable' }), + { + something(arg) { + return arg; + }, }, - }); + ); function behave(mode) { if (mode === 'data') { @@ -18,12 +22,16 @@ export function buildRootObject(_vatPowers, vatParameters) { return undefined; } - return Far('root', { - bootstrap(_vats) { - return behave(vatParameters.argv[0]); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(_vats) { + return behave(vatParameters.argv[0]); + }, + extra(mode) { + return behave(mode); + }, }, - extra(mode) { - return behave(mode); - }, - }); + ); } diff --git a/packages/SwingSet/test/vat-exporter.js b/packages/SwingSet/test/vat-exporter.js index fe9cabb227e..8d2dbda5110 100644 --- a/packages/SwingSet/test/vat-exporter.js +++ b/packages/SwingSet/test/vat-exporter.js @@ -49,11 +49,15 @@ export const buildRootObject = (_vatPowers, vatParameters, baggage) => { makeDurableCounter(), ); - return Far('root', { - getVersion: () => version, - getParameters: () => vatParameters, - getEphemeralCounter: () => ephemeralCounter, - getVirtualCounter: () => virtualCounter, - getDurableCounter: () => durableCounter, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + getVersion: () => version, + getParameters: () => vatParameters, + getEphemeralCounter: () => ephemeralCounter, + getVirtualCounter: () => virtualCounter, + getDurableCounter: () => durableCounter, + }, + ); }; diff --git a/packages/SwingSet/test/vat-timer-upgrade/bootstrap-vat-timer-upgrade.js b/packages/SwingSet/test/vat-timer-upgrade/bootstrap-vat-timer-upgrade.js index 0c913887a14..bc9c450c88e 100644 --- a/packages/SwingSet/test/vat-timer-upgrade/bootstrap-vat-timer-upgrade.js +++ b/packages/SwingSet/test/vat-timer-upgrade/bootstrap-vat-timer-upgrade.js @@ -10,13 +10,17 @@ export function buildRootObject() { const fromTS = timestamp => TimeMath.absValue(timestamp); const events = []; function makeHandler(name) { - return Far(`handler-${name}`, { + return makeExo(`handler-${name}`, M.interface(`handler-${name}`, {}, { defaultGuards: 'passable' }), { wake(time) { events.push(`${name}-${fromTS(time)}`); }, }); } - const cancelToken = Far('cancel', {}); + const cancelToken = makeExo( + 'cancel', + M.interface('cancel', {}, { defaultGuards: 'passable' }), + {}, + ); let clock; let brand; const notifiers = {}; @@ -24,92 +28,96 @@ export function buildRootObject() { let updateCount; let repeaterControl; - return Far('root', { - async bootstrap(vats, devices) { - ts = await E(vats.timer).createTimerService(devices.timer); - timerBrand = await E(ts).getTimerBrand(); - // to exercise vat-vattp upgrade, we need the vatAdminService to - // be configured, even though we don't use it ourselves - await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + ts = await E(vats.timer).createTimerService(devices.timer); + timerBrand = await E(ts).getTimerBrand(); + // to exercise vat-vattp upgrade, we need the vatAdminService to + // be configured, even though we don't use it ourselves + await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); + }, - async installWakeup(baseTime) { - const handler = makeHandler('wake'); - const t = await E(ts).setWakeup(toTS(baseTime), handler, cancelToken); - return fromTS(t); - }, + async installWakeup(baseTime) { + const handler = makeHandler('wake'); + const t = await E(ts).setWakeup(toTS(baseTime), handler, cancelToken); + return fromTS(t); + }, - async installRepeater(delay, interval) { - repeaterControl = await E(ts).makeRepeater(toRT(delay), toRT(interval)); - return E(repeaterControl).schedule(makeHandler('repeat')); - }, + async installRepeater(delay, interval) { + repeaterControl = await E(ts).makeRepeater(toRT(delay), toRT(interval)); + return E(repeaterControl).schedule(makeHandler('repeat')); + }, - async installRepeatAfter(delay, interval) { - return E(ts).repeatAfter( - toRT(delay), - toRT(interval), - makeHandler('repeatAfter'), - cancelToken, - ); - }, + async installRepeatAfter(delay, interval) { + return E(ts).repeatAfter( + toRT(delay), + toRT(interval), + makeHandler('repeatAfter'), + cancelToken, + ); + }, - async installNotifier(name, delay, interval) { - notifiers[name] = await E(ts).makeNotifier( - toRT(delay), - toRT(interval), - cancelToken, - ); - iterators[name] = await E(notifiers[name])[Symbol.asyncIterator](); - }, + async installNotifier(name, delay, interval) { + notifiers[name] = await E(ts).makeNotifier( + toRT(delay), + toRT(interval), + cancelToken, + ); + iterators[name] = await E(notifiers[name])[Symbol.asyncIterator](); + }, - async getClock() { - clock = await E(ts).getClock(); - }, + async getClock() { + clock = await E(ts).getClock(); + }, - async getBrand() { - brand = await E(ts).getTimerBrand(); - }, + async getBrand() { + brand = await E(ts).getTimerBrand(); + }, - async checkClock() { - const clock2 = await E(ts).getClock(); - return clock2 === clock; - }, + async checkClock() { + const clock2 = await E(ts).getClock(); + return clock2 === clock; + }, - async checkBrand() { - const brand2 = await E(ts).getTimerBrand(); - return brand2 === brand; - }, + async checkBrand() { + const brand2 = await E(ts).getTimerBrand(); + return brand2 === brand; + }, - async readClock() { - const t = await E(clock).getCurrentTimestamp(); - return fromTS(t); - }, + async readClock() { + const t = await E(clock).getCurrentTimestamp(); + return fromTS(t); + }, - async readNotifier(name) { - return E(notifiers[name]) - .getUpdateSince(updateCount) - .then(update => { - updateCount = update.updateCount; - return { ...update, value: fromTS(update.value) }; - }); - }, + async readNotifier(name) { + return E(notifiers[name]) + .getUpdateSince(updateCount) + .then(update => { + updateCount = update.updateCount; + return { ...update, value: fromTS(update.value) }; + }); + }, - async readIterator(name) { - const result = await E(iterators[name]).next(); - return { ...result, value: fromTS(result.value) }; - }, + async readIterator(name) { + const result = await E(iterators[name]).next(); + return { ...result, value: fromTS(result.value) }; + }, - async getEvents() { - // we need 'events' to remain mutable, but return values are - // hardened, so clone the array first - const ret = Array.from(events); - events.length = 0; - return ret; - }, + async getEvents() { + // we need 'events' to remain mutable, but return values are + // hardened, so clone the array first + const ret = Array.from(events); + events.length = 0; + return ret; + }, - async cancel() { - await E(repeaterControl).disable(); - await E(ts).cancel(cancelToken); + async cancel() { + await E(repeaterControl).disable(); + await E(ts).cancel(cancelToken); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/vat-warehouse/bootstrap.js b/packages/SwingSet/test/vat-warehouse/bootstrap.js index bbf567ead24..dd843e3368b 100644 --- a/packages/SwingSet/test/vat-warehouse/bootstrap.js +++ b/packages/SwingSet/test/vat-warehouse/bootstrap.js @@ -3,9 +3,13 @@ import { Far } from '@endo/far'; export function buildRootObject() { // eslint-disable-next-line no-unused-vars let vatStrongRef; - return Far('root', { - bootstrap(vats, _devices) { - vatStrongRef = vats; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats, _devices) { + vatStrongRef = vats; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/vat-warehouse/vat-preload-bootstrap.js b/packages/SwingSet/test/vat-warehouse/vat-preload-bootstrap.js index f4c0d81c83c..1da183fe22d 100644 --- a/packages/SwingSet/test/vat-warehouse/vat-preload-bootstrap.js +++ b/packages/SwingSet/test/vat-warehouse/vat-preload-bootstrap.js @@ -11,30 +11,34 @@ export function buildRootObject() { return root; } - return Far('root', { - async bootstrap(vats, devices) { - vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, - ); - bcap = await E(vatAdminSvc).getNamedBundleCap('extra'); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + bcap = await E(vatAdminSvc).getNamedBundleCap('extra'); + }, - async launchCanary() { - const canary = await start('canary'); - extras.set('canary', canary); - }, + async launchCanary() { + const canary = await start('canary'); + extras.set('canary', canary); + }, - async launchExtra() { - for (let count = 0; count < 10; count += 1) { - const name = `extra-${count}`; - const root = await start(name); - extras.set(name, root); - } - }, + async launchExtra() { + for (let count = 0; count < 10; count += 1) { + const name = `extra-${count}`; + const root = await start(name); + extras.set(name, root); + } + }, - ping(which) { - console.log(`ping ${which}`); - return E(extras.get(which)).ping(); + ping(which) { + console.log(`ping ${which}`); + return E(extras.get(which)).ping(); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/vat-warehouse/vat-preload-extra.js b/packages/SwingSet/test/vat-warehouse/vat-preload-extra.js index 26b02c92e17..0f50dd51f31 100644 --- a/packages/SwingSet/test/vat-warehouse/vat-preload-extra.js +++ b/packages/SwingSet/test/vat-warehouse/vat-preload-extra.js @@ -2,7 +2,11 @@ import { Far } from '@endo/far'; export function buildRootObject(_vatPowers, _vatParameters) { // console.log(`extra: ${vatParameters.name}`); - return Far('root', { - ping() {}, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + ping() {}, + }, + ); } diff --git a/packages/SwingSet/test/vat-warehouse/vat-target.js b/packages/SwingSet/test/vat-warehouse/vat-target.js index 847a25b7848..09436adffe8 100644 --- a/packages/SwingSet/test/vat-warehouse/vat-target.js +++ b/packages/SwingSet/test/vat-warehouse/vat-target.js @@ -7,9 +7,13 @@ export function buildRootObject(_vatPowers, _vatParameters) { return harden([...contents]); } - const target = Far('root', { - append, - }); + const target = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + append, + }, + ); return target; } diff --git a/packages/SwingSet/test/vat-warehouse/vat-warehouse-reload.js b/packages/SwingSet/test/vat-warehouse/vat-warehouse-reload.js index 8fb7eece545..65fb62ac7c0 100644 --- a/packages/SwingSet/test/vat-warehouse/vat-warehouse-reload.js +++ b/packages/SwingSet/test/vat-warehouse/vat-warehouse-reload.js @@ -3,10 +3,14 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { const { testLog: log } = vatPowers; let count = 0; - return Far('root', { - count() { - log(`count = ${count}`); - count += 1; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + count() { + log(`count = ${count}`); + count += 1; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/vat-xsnap-hang.js b/packages/SwingSet/test/vat-xsnap-hang.js index 91fd0dc03e0..4a2d48f5b20 100644 --- a/packages/SwingSet/test/vat-xsnap-hang.js +++ b/packages/SwingSet/test/vat-xsnap-hang.js @@ -1,10 +1,14 @@ import { Far } from '@endo/far'; export function buildRootObject() { - return Far('root', { - hang() { - // eslint-disable-next-line no-empty - for (;;) {} + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + hang() { + // eslint-disable-next-line no-empty + for (;;) {} + }, }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/collection-slots/bootstrap-collection-slots.js b/packages/SwingSet/test/virtualObjects/collection-slots/bootstrap-collection-slots.js index 47650caf0c6..dcc5cc42dfc 100644 --- a/packages/SwingSet/test/virtualObjects/collection-slots/bootstrap-collection-slots.js +++ b/packages/SwingSet/test/virtualObjects/collection-slots/bootstrap-collection-slots.js @@ -2,29 +2,33 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { // build the import sensor - const imp1 = Far(`import-1`, {}); + const imp1 = makeExo(`import-1`, M.interface(`import-1`, {}, { defaultGuards: 'passable' }), {}); let targetvat; - return Far('root', { - async bootstrap(vats) { - targetvat = vats.target; - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + targetvat = vats.target; + }, - async getImportSensors() { - return [imp1]; - }, + async getImportSensors() { + return [imp1]; + }, - async step1() { - await E(targetvat).build(imp1); - }, + async step1() { + await E(targetvat).build(imp1); + }, - async step2() { - await E(targetvat).delete(); - }, + async step2() { + await E(targetvat).delete(); + }, - async step3() { - await E(targetvat).flush(); + async step3() { + await E(targetvat).flush(); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/collection-slots/vat-collection-slots.js b/packages/SwingSet/test/virtualObjects/collection-slots/vat-collection-slots.js index 65a48ade333..21e7f334896 100644 --- a/packages/SwingSet/test/virtualObjects/collection-slots/vat-collection-slots.js +++ b/packages/SwingSet/test/virtualObjects/collection-slots/vat-collection-slots.js @@ -5,7 +5,11 @@ import { Far } from '@endo/far'; const { makeScalarBigMapStore } = VatData; function makeRemotable(imp1) { - return Far('rem1', { get: () => imp1 }); + return makeExo( + 'rem1', + M.interface('rem1', {}, { defaultGuards: 'passable' }), + { get: () => imp1 }, + ); } // vc1 -> vc2 -> rem1 -> imp1 @@ -13,16 +17,20 @@ function makeRemotable(imp1) { export function buildRootObject() { const vc1 = makeScalarBigMapStore('vc1'); - return Far('root', { - build(imp1) { - const vc2 = makeScalarBigMapStore('vc2'); - const rem1 = makeRemotable(imp1); - vc2.init('key', rem1); - vc1.init('vc2', vc2); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build(imp1) { + const vc2 = makeScalarBigMapStore('vc2'); + const rem1 = makeRemotable(imp1); + vc2.init('key', rem1); + vc1.init('vc2', vc2); + }, + delete() { + vc1.delete('vc2'); + }, + flush() {}, }, - delete() { - vc1.delete('vc2'); - }, - flush() {}, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/delete-stored-vo/bootstrap-delete-stored-vo.js b/packages/SwingSet/test/virtualObjects/delete-stored-vo/bootstrap-delete-stored-vo.js index 9a0cb9a7ae8..356e3bc8233 100644 --- a/packages/SwingSet/test/virtualObjects/delete-stored-vo/bootstrap-delete-stored-vo.js +++ b/packages/SwingSet/test/virtualObjects/delete-stored-vo/bootstrap-delete-stored-vo.js @@ -2,25 +2,29 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { // build the import sensor - const imp1 = Far(`import-1`, {}); + const imp1 = makeExo(`import-1`, M.interface(`import-1`, {}, { defaultGuards: 'passable' }), {}); let targetvat; - return Far('root', { - async bootstrap(vats) { - targetvat = vats.target; - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + targetvat = vats.target; + }, - async getImportSensors() { - return [imp1]; - }, + async getImportSensors() { + return [imp1]; + }, - async step1() { - await E(targetvat).build(imp1); - }, + async step1() { + await E(targetvat).build(imp1); + }, - async step2() { - await E(targetvat).delete(); + async step2() { + await E(targetvat).delete(); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/delete-stored-vo/vat-delete-stored-vo.js b/packages/SwingSet/test/virtualObjects/delete-stored-vo/vat-delete-stored-vo.js index 6b4a5086c11..e96f3126aae 100644 --- a/packages/SwingSet/test/virtualObjects/delete-stored-vo/vat-delete-stored-vo.js +++ b/packages/SwingSet/test/virtualObjects/delete-stored-vo/vat-delete-stored-vo.js @@ -12,7 +12,11 @@ const makeVir = defineKind('virtual', initialize, {}); const makeDummy = defineKind('dummy', initialize, {}); function makeRemotable(imp1) { - return Far('rem1', { get: () => imp1 }); + return makeExo( + 'rem1', + M.interface('rem1', {}, { defaultGuards: 'passable' }), + { get: () => imp1 }, + ); } // vc1 -> vo1 -> [rem1, imp1] @@ -20,19 +24,23 @@ function makeRemotable(imp1) { export function buildRootObject() { const vc1 = makeScalarBigMapStore('vc1'); - return Far('root', { - build(imp1) { - const rem1 = makeRemotable(imp1); - const vo1 = makeVir(harden([rem1, imp1])); - vc1.init('vo1', vo1); - // kick vo1 out of the virtual-object cache's leftover slot - makeDummy(); - makeDummy(); - makeDummy(); - makeDummy(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build(imp1) { + const rem1 = makeRemotable(imp1); + const vo1 = makeVir(harden([rem1, imp1])); + vc1.init('vo1', vo1); + // kick vo1 out of the virtual-object cache's leftover slot + makeDummy(); + makeDummy(); + makeDummy(); + makeDummy(); + }, + delete() { + vc1.delete('vo1'); + }, }, - delete() { - vc1.delete('vo1'); - }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/double-retire-import/bootstrap-dri.js b/packages/SwingSet/test/virtualObjects/double-retire-import/bootstrap-dri.js index 496e4dd9bb2..fa6f948ad4a 100644 --- a/packages/SwingSet/test/virtualObjects/double-retire-import/bootstrap-dri.js +++ b/packages/SwingSet/test/virtualObjects/double-retire-import/bootstrap-dri.js @@ -3,22 +3,28 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { let vatAdmin; let root; - const sensor0 = Far(`sensor-0`, {}); - const sensor1 = Far(`sensor-1`, {}); + const sensor0 = makeExo(`sensor-0`, M.interface(`sensor-0`, {}, { defaultGuards: 'passable' }), {}); + const sensor1 = makeExo(`sensor-1`, M.interface(`sensor-1`, {}, { defaultGuards: 'passable' }), {}); - return Far('root', { - async bootstrap(vats, devices) { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + }, - async build() { - // build the target vat - const bcap = await E(vatAdmin).getNamedBundleCap('dri'); - const res = await E(vatAdmin).createVat(bcap); - root = res.root; - await E(root).buildVir(sensor0, sensor1); - await E(root).ping(); - return 'ok'; + async build() { + // build the target vat + const bcap = await E(vatAdmin).getNamedBundleCap('dri'); + const res = await E(vatAdmin).createVat(bcap); + root = res.root; + await E(root).buildVir(sensor0, sensor1); + await E(root).ping(); + return 'ok'; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/double-retire-import/vat-dri.js b/packages/SwingSet/test/virtualObjects/double-retire-import/vat-dri.js index a3087a213c8..95b293e6a20 100644 --- a/packages/SwingSet/test/virtualObjects/double-retire-import/vat-dri.js +++ b/packages/SwingSet/test/virtualObjects/double-retire-import/vat-dri.js @@ -58,12 +58,16 @@ function buildVirtuals(sensor0, sensor1) { } export function buildRootObject() { - return Far('root', { - ping() { - return 0; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + ping() { + return 0; + }, + buildVir(sensor0, sensor1) { + return buildVirtuals(sensor0, sensor1); + }, }, - buildVir(sensor0, sensor1) { - return buildVirtuals(sensor0, sensor1); - }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/vat-orphan-bob.js b/packages/SwingSet/test/virtualObjects/vat-orphan-bob.js index c943755bcec..67e9b4a6d32 100644 --- a/packages/SwingSet/test/virtualObjects/vat-orphan-bob.js +++ b/packages/SwingSet/test/virtualObjects/vat-orphan-bob.js @@ -74,37 +74,41 @@ export function buildRootObject() { reset(); - return Far('root', { - reset, - retain(kind, what, how) { - const thing = makeThing(); - const { regularFacet, emptyFacet } = makeMultiThing(); - const things = { thing, regularFacet, emptyFacet }; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + reset, + retain(kind, what, how) { + const thing = makeThing(); + const { regularFacet, emptyFacet } = makeMultiThing(); + const things = { thing, regularFacet, emptyFacet }; - const hold = extract(things, kind, what); - switch (how) { - case 'retain': - strongRetainer = hold; - break; - case 'weakset': - weakRetainer.add(hold); - break; - default: - throw Error(`unknown how ${how}`); - } - return things; - }, + const hold = extract(things, kind, what); + switch (how) { + case 'retain': + strongRetainer = hold; + break; + case 'weakset': + weakRetainer.add(hold); + break; + default: + throw Error(`unknown how ${how}`); + } + return things; + }, - compare(things, kind, what, how) { - const sample = extract(things, kind, what); - switch (how) { - case 'retain': - return strongRetainer === sample; - case 'weakset': - return weakRetainer.has(sample); - default: - throw Error(`unknown how ${how}`); - } + compare(things, kind, what, how) { + const sample = extract(things, kind, what); + switch (how) { + case 'retain': + return strongRetainer === sample; + case 'weakset': + return weakRetainer.has(sample); + default: + throw Error(`unknown how ${how}`); + } + }, }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/vat-orphan-bootstrap.js b/packages/SwingSet/test/virtualObjects/vat-orphan-bootstrap.js index c76d8d06860..423d0794c79 100644 --- a/packages/SwingSet/test/virtualObjects/vat-orphan-bootstrap.js +++ b/packages/SwingSet/test/virtualObjects/vat-orphan-bootstrap.js @@ -2,15 +2,19 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { let bob; - return Far('root', { - async bootstrap(vats) { - bob = vats.bob; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + bob = vats.bob; + }, + async run(kind, what, how) { + await E(bob).reset(); + const things = await E(bob).retain(kind, what, how); + const compare = await E(bob).compare(things, kind, what, how); + return compare; + }, }, - async run(kind, what, how) { - await E(bob).reset(); - const things = await E(bob).retain(kind, what, how); - const compare = await E(bob).compare(things, kind, what, how); - return compare; - }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/vat-representatives.js b/packages/SwingSet/test/virtualObjects/vat-representatives.js index be307428199..5af07fd30e1 100644 --- a/packages/SwingSet/test/virtualObjects/vat-representatives.js +++ b/packages/SwingSet/test/virtualObjects/vat-representatives.js @@ -17,39 +17,43 @@ const makeThing = defineKind( export function buildRootObject() { let heldThing; - return Far('root', { - makeThing(name, hold) { - const thing = makeThing(name); - if (hold) { - heldThing = thing; - } - return thing; - }, - readThing(what) { - return what.getName(); - }, - readHeldThing() { - if (heldThing) { - return heldThing.getName(); - } else { - throw Error('no held thing'); - } - }, - writeThing(what, newName) { - what.rename(newName); - }, - writeHeldThing(newName) { - if (heldThing) { - heldThing.rename(newName); - } else { - throw Error('no held thing'); - } - }, - holdThing(what) { - heldThing = what; - }, - forgetHeldThing() { - heldThing = null; - }, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + makeThing(name, hold) { + const thing = makeThing(name); + if (hold) { + heldThing = thing; + } + return thing; + }, + readThing(what) { + return what.getName(); + }, + readHeldThing() { + if (heldThing) { + return heldThing.getName(); + } else { + throw Error('no held thing'); + } + }, + writeThing(what, newName) { + what.rename(newName); + }, + writeHeldThing(newName) { + if (heldThing) { + heldThing.rename(newName); + } else { + throw Error('no held thing'); + } + }, + holdThing(what) { + heldThing = what; + }, + forgetHeldThing() { + heldThing = null; + }, + }, + ); } diff --git a/packages/SwingSet/test/virtualObjects/vat-vom-gc-bob.js b/packages/SwingSet/test/virtualObjects/vat-vom-gc-bob.js index f75ff9faa88..964baaa27c6 100644 --- a/packages/SwingSet/test/virtualObjects/vat-vom-gc-bob.js +++ b/packages/SwingSet/test/virtualObjects/vat-vom-gc-bob.js @@ -9,41 +9,45 @@ export function buildRootObject() { }); let nextThingNumber = 0; - return Far('root', { - prepare() { - things.push(null); - for (let i = 1; i <= 9; i += 1) { - things.push(makeThing(`thing #${i}`)); - } - }, - getThing(forWhom) { - let thing; - do { - thing = things[nextThingNumber]; - nextThingNumber += 1; - } while (!thing); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + prepare() { + things.push(null); + for (let i = 1; i <= 9; i += 1) { + things.push(makeThing(`thing #${i}`)); + } + }, + getThing(forWhom) { + let thing; + do { + thing = things[nextThingNumber]; + nextThingNumber += 1; + } while (!thing); - if (nextThingNumber === 3) { - thing.getLabel(); - things[4].getLabel(); - things[4] = null; // arbitrarily drop one before sending it, but don't drop the one we're sending - } else { - thing.getLabel(); - things[nextThingNumber - 1] = null; // drop the one we're sending - } - E(forWhom).deliverThing(thing); - thing = null; - }, - finish() { - while (nextThingNumber < 8) { - const deadThing = things[nextThingNumber]; - if (deadThing) { - deadThing.getLabel(); - things[nextThingNumber] = null; + if (nextThingNumber === 3) { + thing.getLabel(); + things[4].getLabel(); + things[4] = null; // arbitrarily drop one before sending it, but don't drop the one we're sending + } else { + thing.getLabel(); + things[nextThingNumber - 1] = null; // drop the one we're sending } - nextThingNumber += 1; - } - console.log(`Bob finishing`); + E(forWhom).deliverThing(thing); + thing = null; + }, + finish() { + while (nextThingNumber < 8) { + const deadThing = things[nextThingNumber]; + if (deadThing) { + deadThing.getLabel(); + things[nextThingNumber] = null; + } + nextThingNumber += 1; + } + console.log(`Bob finishing`); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/vat-vom-gc-bootstrap.js b/packages/SwingSet/test/virtualObjects/vat-vom-gc-bootstrap.js index 935fab077cd..7398185ac66 100644 --- a/packages/SwingSet/test/virtualObjects/vat-vom-gc-bootstrap.js +++ b/packages/SwingSet/test/virtualObjects/vat-vom-gc-bootstrap.js @@ -7,24 +7,28 @@ export function buildRootObject() { let bob; let me; let goCount = 3; - return Far('root', { - async bootstrap(vats) { - me = vats.bootstrap; - bob = vats.bob; - E(bob).prepare(); - await E(me).go(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + me = vats.bootstrap; + bob = vats.bob; + E(bob).prepare(); + await E(me).go(); + }, + go() { + if (goCount > 0) { + E(bob).getThing(me); + } else { + E(bob).finish(); + } + goCount -= 1; + }, + deliverThing(thing) { + other = thing; + E(me).go(); + }, }, - go() { - if (goCount > 0) { - E(bob).getThing(me); - } else { - E(bob).finish(); - } - goCount -= 1; - }, - deliverThing(thing) { - other = thing; - E(me).go(); - }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/vat-weakcollections-alice.js b/packages/SwingSet/test/virtualObjects/vat-weakcollections-alice.js index 0dd2ca39333..5b21a5946be 100644 --- a/packages/SwingSet/test/virtualObjects/vat-weakcollections-alice.js +++ b/packages/SwingSet/test/virtualObjects/vat-weakcollections-alice.js @@ -17,43 +17,55 @@ export function buildRootObject() { let forgetableExportVirtualObject; let forgetableExportPromise; - return Far('root', { - prepareWeakMap(theirStuff) { - memorableExportRemotable = Far('remember-exp', {}); - memorableExportVirtualObject = makeHolder('remember-exp-vo'); - memorableExportPromise = new Promise((_res, _rej) => {}); - forgetableExportRemotable = Far('forget-exp', {}); - forgetableExportVirtualObject = makeHolder('forget-exp-vo'); - forgetableExportPromise = new Promise((_res, _rej) => {}); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + prepareWeakMap(theirStuff) { + memorableExportRemotable = makeExo( + 'remember-exp', + M.interface('remember-exp', {}, { defaultGuards: 'passable' }), + {}, + ); + memorableExportVirtualObject = makeHolder('remember-exp-vo'); + memorableExportPromise = new Promise((_res, _rej) => {}); + forgetableExportRemotable = makeExo( + 'forget-exp', + M.interface('forget-exp', {}, { defaultGuards: 'passable' }), + {}, + ); + forgetableExportVirtualObject = makeHolder('forget-exp-vo'); + forgetableExportPromise = new Promise((_res, _rej) => {}); - const result = [ - memorableExportRemotable, - memorableExportVirtualObject, - memorableExportPromise, - forgetableExportRemotable, - forgetableExportVirtualObject, - forgetableExportPromise, - ]; + const result = [ + memorableExportRemotable, + memorableExportVirtualObject, + memorableExportPromise, + forgetableExportRemotable, + forgetableExportVirtualObject, + forgetableExportPromise, + ]; - let i = 0; - for (const item of theirStuff) { - testWeakMap.set(item, `imported item #${i}`); - i += 1; - } - testWeakMap.set(memorableExportRemotable, 'mer'); - testWeakMap.set(memorableExportVirtualObject, 'mevo'); - testWeakMap.set(memorableExportPromise, 'mep'); - testWeakMap.set(forgetableExportRemotable, 'fer'); - testWeakMap.set(forgetableExportVirtualObject, 'fevo'); - testWeakMap.set(forgetableExportPromise, 'fep'); - forgetableExportRemotable = null; - forgetableExportVirtualObject = null; - forgetableExportPromise = null; + let i = 0; + for (const item of theirStuff) { + testWeakMap.set(item, `imported item #${i}`); + i += 1; + } + testWeakMap.set(memorableExportRemotable, 'mer'); + testWeakMap.set(memorableExportVirtualObject, 'mevo'); + testWeakMap.set(memorableExportPromise, 'mep'); + testWeakMap.set(forgetableExportRemotable, 'fer'); + testWeakMap.set(forgetableExportVirtualObject, 'fevo'); + testWeakMap.set(forgetableExportPromise, 'fep'); + forgetableExportRemotable = null; + forgetableExportVirtualObject = null; + forgetableExportPromise = null; - return result; + return result; + }, + probeWeakMap(probe) { + return testWeakMap.get(probe); + }, }, - probeWeakMap(probe) { - return testWeakMap.get(probe); - }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/vat-weakcollections-bootstrap.js b/packages/SwingSet/test/virtualObjects/vat-weakcollections-bootstrap.js index 2542a23fa32..e562f920904 100644 --- a/packages/SwingSet/test/virtualObjects/vat-weakcollections-bootstrap.js +++ b/packages/SwingSet/test/virtualObjects/vat-weakcollections-bootstrap.js @@ -7,34 +7,42 @@ export function buildRootObject(vatPowers) { const p = new Promise(resolve => { r = resolve; }); - const obj = Far('object', { - toString() { - return 'sample-object'; + const obj = makeExo( + 'object', + M.interface('object', {}, { defaultGuards: 'passable' }), + { + toString() { + return 'sample-object'; + }, }, - }); + ); const ourStuff = [obj, p]; let theirStuff; - return Far('root', { - async bootstrap(vats) { - alice = vats.alice; - theirStuff = await E(alice).prepareWeakMap(ourStuff); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + alice = vats.alice; + theirStuff = await E(alice).prepareWeakMap(ourStuff); - return 'bootstrap done'; - }, - betweenProbes() { - r('resolved'); + return 'bootstrap done'; + }, + betweenProbes() { + r('resolved'); + }, + async runProbes() { + for (const item of ourStuff) { + const what = await E(alice).probeWeakMap(item); + testLog(`probe of ${item} returns ${what}`); + } + for (const item of theirStuff) { + const what = await E(alice).probeWeakMap(item); + testLog(`probe of ${item} returns ${what}`); + } + return 'probes done'; + }, }, - async runProbes() { - for (const item of ourStuff) { - const what = await E(alice).probeWeakMap(item); - testLog(`probe of ${item} returns ${what}`); - } - for (const item of theirStuff) { - const what = await E(alice).probeWeakMap(item); - testLog(`probe of ${item} returns ${what}`); - } - return 'probes done'; - }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/vdata-promises/bootstrap-vdata-promises.js b/packages/SwingSet/test/virtualObjects/vdata-promises/bootstrap-vdata-promises.js index 2e351b5f27b..766c98cc253 100644 --- a/packages/SwingSet/test/virtualObjects/vdata-promises/bootstrap-vdata-promises.js +++ b/packages/SwingSet/test/virtualObjects/vdata-promises/bootstrap-vdata-promises.js @@ -10,54 +10,62 @@ export function buildRootObject() { const [p1, p2, p3] = [pk1.promise, pk2.promise, pk3.promise]; const subscriberStash = []; - const subscriber = Far('subscriber', { - subscribe(name, p) { - const entryP = p.then(res => [name, res]); - subscriberStash.push(entryP); + const subscriber = makeExo( + 'subscriber', + M.interface('subscriber', {}, { defaultGuards: 'passable' }), + { + subscribe(name, p) { + const entryP = p.then(res => [name, res]); + subscriberStash.push(entryP); + }, }, - }); + ); - return Far('root', { - async bootstrap(vats) { - targetvat = vats.target; - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + targetvat = vats.target; + }, - // exercised imported promises - doImportTest1() { - E(targetvat).importPromiseStep1(p1, p2, p3); - return [p1, p2, p3]; - }, - doImportTest2() { - pk1.resolve(1); - pk2.resolve(2); - pk3.resolve(3); - }, - doImportTest3() { - return E(targetvat).importPromiseStep2(); - }, + // exercised imported promises + doImportTest1() { + E(targetvat).importPromiseStep1(p1, p2, p3); + return [p1, p2, p3]; + }, + doImportTest2() { + pk1.resolve(1); + pk2.resolve(2); + pk3.resolve(3); + }, + doImportTest3() { + return E(targetvat).importPromiseStep2(); + }, - doResultTest1() { - const p4 = E(targetvat).returnPromise4(); - const p5 = E(targetvat).returnPromise5(); - const p6 = E(targetvat).returnPromise6(); - E(targetvat).resultPromiseStep1(p4, p5, p6); - return harden([p4, p5, p6]); - }, - doResultTest2() { - E(targetvat).resultPromiseStep2(); - }, - doResultTest3() { - return E(targetvat).resultPromiseStep3(); - }, + doResultTest1() { + const p4 = E(targetvat).returnPromise4(); + const p5 = E(targetvat).returnPromise5(); + const p6 = E(targetvat).returnPromise6(); + E(targetvat).resultPromiseStep1(p4, p5, p6); + return harden([p4, p5, p6]); + }, + doResultTest2() { + E(targetvat).resultPromiseStep2(); + }, + doResultTest3() { + return E(targetvat).resultPromiseStep3(); + }, - async doStoreTest1() { - const data = await E(targetvat).storePromiseStep1(subscriber); - const subscriberEntries = await Promise.all(subscriberStash); - const resolutions = {}; - for (const [name, res] of subscriberEntries) { - resolutions[name] = res; - } - return { data, resolutions }; + async doStoreTest1() { + const data = await E(targetvat).storePromiseStep1(subscriber); + const subscriberEntries = await Promise.all(subscriberStash); + const resolutions = {}; + for (const [name, res] of subscriberEntries) { + resolutions[name] = res; + } + return { data, resolutions }; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/virtualObjects/vdata-promises/vat-vdata-promises.js b/packages/SwingSet/test/virtualObjects/vdata-promises/vat-vdata-promises.js index e1610f263a8..259f65dd969 100644 --- a/packages/SwingSet/test/virtualObjects/vdata-promises/vat-vdata-promises.js +++ b/packages/SwingSet/test/virtualObjects/vdata-promises/vat-vdata-promises.js @@ -26,166 +26,170 @@ export function buildRootObject() { const importStash = []; const resultStash = []; - return Far('root', { - importPromiseStep1(p1, p2, p3) { - // imported p1 is resolved without ever being put into vdata - importStash.push(p1); - - // imported p2 is added to vdata, fetched from vdata, deleted - // from vdata, then resolved - vc.init('p2', p2); - const p2a = vc.get('p2'); - vc.delete('p2'); - importStash.push(p2); - importStash.push(p2a); - - // imported p3 is added to vdata, resolved, fetched from vdata, - // then deleted from vdata - vc.init('p3', p3); - importStash.push(p3); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + importPromiseStep1(p1, p2, p3) { + // imported p1 is resolved without ever being put into vdata + importStash.push(p1); + + // imported p2 is added to vdata, fetched from vdata, deleted + // from vdata, then resolved + vc.init('p2', p2); + const p2a = vc.get('p2'); + vc.delete('p2'); + importStash.push(p2); + importStash.push(p2a); + + // imported p3 is added to vdata, resolved, fetched from vdata, + // then deleted from vdata + vc.init('p3', p3); + importStash.push(p3); + }, + + // p1/p2/p3 are resolved before importPromiseStep2 is called + + importPromiseStep2() { + const p3a = vc.get('p3'); + importStash.push(p3a); + vc.delete('p3'); + + return Promise.all(importStash); + }, + + // these three methods return p4/p5/p6 (note these are not the + // same as pk4.promise/etc, but pk4.resolve() will cause p4 to be + // resolved) + returnPromise4() { + return pk4.promise; + }, + returnPromise5() { + return pk5.promise; + }, + returnPromise6() { + return pk6.promise; + }, + + resultPromiseStep1(p4, p5, p6) { + // result p4 is resolved without ever being put into vdata + resultStash.push(p4); + // result p5 is added to vdata, fetched from vdata, deleted + // from vdata, then resolved + vc.init('p5', p5); + const p5a = vc.get('p5'); + vc.delete('p5'); + resultStash.push(p5); + resultStash.push(p5a); + + // result p6 is added to vdata, resolved, fetched from vdata, + // then deleted from vdata + vc.init('p6', p6); + resultStash.push(p6); + }, + + resultPromiseStep2() { + pk4.resolve(4); + pk5.resolve(5); + pk6.resolve(6); + }, + + resultPromiseStep3() { + const p6a = vc.get('p6'); + resultStash.push(p6a); + vc.delete('p6'); + + return Promise.all(resultStash); + }, + + async storePromiseStep1(subscriber) { + const ret = {}; + + // p7: basic retrieval: store, fetch, delete, resolve + ret.p7 = pk7.promise; + vc.init('p7', pk7.promise); + ret.p7a = vc.get('p7'); + vc.delete('p7'); + pk7.resolve(7); + + // p8: unexported resolution doesn't unregister, can delete + // after resolution: store, resolve, (pause), fetch, delete + ret.p8 = pk8.promise; + vc.init('p8', pk8.promise); + pk8.resolve(8); + await pk8.promise; + ret.p8a = vc.get('p8'); // unexported resolution doesn't unregister + vc.delete('p8'); + + // p9: can export while stored+unresolved: store, export, + // resolve, (notify), (pause), fetch, delete + ret.p9 = pk9.promise; + vc.init('p9', pk9.promise); + E(subscriber).subscribe('p9', pk9.promise); + await Promise.resolve(); // serialize before resolution + pk9.resolve(9); + await pk9.promise; + ret.p9a = vc.get('p9'); // exported resolution doesn't unregister + vc.delete('p9'); + + // p10: can export while stored+resolved: store, resolve, + // (pause), export, fetch, delete + ret.p10 = pk10.promise; + vc.init('p10', pk10.promise); + pk10.resolve(10); + await pk10.promise; + E(subscriber).subscribe('p10', pk10.promise); + await Promise.resolve(); // allow serialize+send + ret.p10a = vc.get('p10'); + vc.delete('p10'); + + // p11: delete while unresolved: store, export, delete, resolve, + // (notify) + ret.p11 = pk11.promise; + vc.init('p11', pk11.promise); + E(subscriber).subscribe('p11', pk11.promise); + await Promise.resolve(); // allow serialize+send + vc.delete('p11'); + pk11.resolve(11); + + // p12: delete+re-store while unresolved: store, export, delete, + // store, resolve, (notify), delete + ret.p12 = pk12.promise; + vc.init('p12', pk12.promise); + E(subscriber).subscribe('p12', pk12.promise); + await Promise.resolve(); // allow serialize+send + vc.delete('p12'); + vc.init('p12', pk12.promise); + pk12.resolve(12); + await pk12.promise; + vc.delete('p12'); + + // p13: basic export: export, resolve, (notify) + ret.p13 = pk13.promise; + E(subscriber).subscribe('p13', pk13.promise); + pk13.resolve(13); + await pk13.promise; + + // p14: export first: export, store, resolve, (notify), fetch, + // delete + ret.p14 = pk14.promise; + E(subscriber).subscribe('p14', pk14.promise); + await Promise.resolve(); // allow serialize+send + vc.init('p14', pk14.promise); + pk14.resolve(14); + await pk14.promise; + ret.p14a = vc.get('p14'); + vc.delete('p14'); + + const is = { + p7is: ret.p7 === ret.p7a, + p8is: ret.p8 === ret.p8a, + p9is: ret.p9 === ret.p9a, + p10is: ret.p10 === ret.p10a, + p14is: ret.p14 === ret.p14a, + }; + return { is, ret }; + }, }, - - // p1/p2/p3 are resolved before importPromiseStep2 is called - - importPromiseStep2() { - const p3a = vc.get('p3'); - importStash.push(p3a); - vc.delete('p3'); - - return Promise.all(importStash); - }, - - // these three methods return p4/p5/p6 (note these are not the - // same as pk4.promise/etc, but pk4.resolve() will cause p4 to be - // resolved) - returnPromise4() { - return pk4.promise; - }, - returnPromise5() { - return pk5.promise; - }, - returnPromise6() { - return pk6.promise; - }, - - resultPromiseStep1(p4, p5, p6) { - // result p4 is resolved without ever being put into vdata - resultStash.push(p4); - // result p5 is added to vdata, fetched from vdata, deleted - // from vdata, then resolved - vc.init('p5', p5); - const p5a = vc.get('p5'); - vc.delete('p5'); - resultStash.push(p5); - resultStash.push(p5a); - - // result p6 is added to vdata, resolved, fetched from vdata, - // then deleted from vdata - vc.init('p6', p6); - resultStash.push(p6); - }, - - resultPromiseStep2() { - pk4.resolve(4); - pk5.resolve(5); - pk6.resolve(6); - }, - - resultPromiseStep3() { - const p6a = vc.get('p6'); - resultStash.push(p6a); - vc.delete('p6'); - - return Promise.all(resultStash); - }, - - async storePromiseStep1(subscriber) { - const ret = {}; - - // p7: basic retrieval: store, fetch, delete, resolve - ret.p7 = pk7.promise; - vc.init('p7', pk7.promise); - ret.p7a = vc.get('p7'); - vc.delete('p7'); - pk7.resolve(7); - - // p8: unexported resolution doesn't unregister, can delete - // after resolution: store, resolve, (pause), fetch, delete - ret.p8 = pk8.promise; - vc.init('p8', pk8.promise); - pk8.resolve(8); - await pk8.promise; - ret.p8a = vc.get('p8'); // unexported resolution doesn't unregister - vc.delete('p8'); - - // p9: can export while stored+unresolved: store, export, - // resolve, (notify), (pause), fetch, delete - ret.p9 = pk9.promise; - vc.init('p9', pk9.promise); - E(subscriber).subscribe('p9', pk9.promise); - await Promise.resolve(); // serialize before resolution - pk9.resolve(9); - await pk9.promise; - ret.p9a = vc.get('p9'); // exported resolution doesn't unregister - vc.delete('p9'); - - // p10: can export while stored+resolved: store, resolve, - // (pause), export, fetch, delete - ret.p10 = pk10.promise; - vc.init('p10', pk10.promise); - pk10.resolve(10); - await pk10.promise; - E(subscriber).subscribe('p10', pk10.promise); - await Promise.resolve(); // allow serialize+send - ret.p10a = vc.get('p10'); - vc.delete('p10'); - - // p11: delete while unresolved: store, export, delete, resolve, - // (notify) - ret.p11 = pk11.promise; - vc.init('p11', pk11.promise); - E(subscriber).subscribe('p11', pk11.promise); - await Promise.resolve(); // allow serialize+send - vc.delete('p11'); - pk11.resolve(11); - - // p12: delete+re-store while unresolved: store, export, delete, - // store, resolve, (notify), delete - ret.p12 = pk12.promise; - vc.init('p12', pk12.promise); - E(subscriber).subscribe('p12', pk12.promise); - await Promise.resolve(); // allow serialize+send - vc.delete('p12'); - vc.init('p12', pk12.promise); - pk12.resolve(12); - await pk12.promise; - vc.delete('p12'); - - // p13: basic export: export, resolve, (notify) - ret.p13 = pk13.promise; - E(subscriber).subscribe('p13', pk13.promise); - pk13.resolve(13); - await pk13.promise; - - // p14: export first: export, store, resolve, (notify), fetch, - // delete - ret.p14 = pk14.promise; - E(subscriber).subscribe('p14', pk14.promise); - await Promise.resolve(); // allow serialize+send - vc.init('p14', pk14.promise); - pk14.resolve(14); - await pk14.promise; - ret.p14a = vc.get('p14'); - vc.delete('p14'); - - const is = { - p7is: ret.p7 === ret.p7a, - p8is: ret.p8 === ret.p8a, - p9is: ret.p9 === ret.p9a, - p10is: ret.p10 === ret.p10a, - p14is: ret.p14 === ret.p14a, - }; - return { is, ret }; - }, - }); + ); } diff --git a/packages/SwingSet/test/vo-test-harness/vat-dvo-test-test.js b/packages/SwingSet/test/vo-test-harness/vat-dvo-test-test.js index 350ac4639ed..cd2a2f90241 100644 --- a/packages/SwingSet/test/vo-test-harness/vat-dvo-test-test.js +++ b/packages/SwingSet/test/vo-test-harness/vat-dvo-test-test.js @@ -19,19 +19,23 @@ export function buildRootObject(_vatPowers, vatParameters, baggage) { makeThing('test thing'), ); - return Far('root', { - runTests(testDriver, phase) { - other = testDriver; - log(`start test`); - log(phase); - if (vatParameters.mode === phase) { - log(`fail during "${phase}"`); - } else { - log(testThing.getTag()); - } - log(vatParameters); - log(`end test`); - testComplete(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + runTests(testDriver, phase) { + other = testDriver; + log(`start test`); + log(phase); + if (vatParameters.mode === phase) { + log(`fail during "${phase}"`); + } else { + log(testThing.getTag()); + } + log(vatParameters); + log(`end test`); + testComplete(); + }, }, - }); + ); } diff --git a/packages/SwingSet/test/workers/bootstrap-node.js b/packages/SwingSet/test/workers/bootstrap-node.js index 444da86332a..6cb254ef64d 100644 --- a/packages/SwingSet/test/workers/bootstrap-node.js +++ b/packages/SwingSet/test/workers/bootstrap-node.js @@ -1,9 +1,13 @@ import { Far } from '@endo/far'; export function buildRootObject() { - return Far('root', { - bootstrap() { - return 'ok'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap() { + return 'ok'; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/workers/bootstrap.js b/packages/SwingSet/test/workers/bootstrap.js index bcbad1a1478..f6f7751d868 100644 --- a/packages/SwingSet/test/workers/bootstrap.js +++ b/packages/SwingSet/test/workers/bootstrap.js @@ -2,17 +2,25 @@ import { makePromiseKit } from '@endo/promise-kit'; import { Far, E } from '@endo/far'; export function buildRootObject() { - const callbackObj = Far('callback', { - callback(_arg1, _arg2) { - // console.log(`callback`, arg1, arg2); - return ['data', callbackObj]; // four, resolves pF + const callbackObj = makeExo( + 'callback', + M.interface('callback', {}, { defaultGuards: 'passable' }), + { + callback(_arg1, _arg2) { + // console.log(`callback`, arg1, arg2); + return ['data', callbackObj]; // four, resolves pF + }, }, - }); + ); const precD = makePromiseKit(); const precE = makePromiseKit(); - const dropMe = Far('dropMe', {}); + const dropMe = makeExo( + 'dropMe', + M.interface('dropMe', {}, { defaultGuards: 'passable' }), + {}, + ); function checkResB(resB) { if (resB === callbackObj) { @@ -57,21 +65,25 @@ export function buildRootObject() { ]); } - return Far('root', { - bootstrap(vats, devices) { - const pA = E(vats.target).zero( - callbackObj, - precD.promise, - precE.promise, - devices.add, - dropMe, - ); - const rp3 = E(vats.target).one(); - precD.resolve(callbackObj); // two - precE.reject(Error('four')); // three - const done = Promise.all([pA.then(checkA), rp3]); - // expect: [['B good', 'C good', 'F good', 'three good', 'exit good', 'exitWF good'], 'rp3 good'] - return done; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats, devices) { + const pA = E(vats.target).zero( + callbackObj, + precD.promise, + precE.promise, + devices.add, + dropMe, + ); + const rp3 = E(vats.target).one(); + precD.resolve(callbackObj); // two + precE.reject(Error('four')); // three + const done = Promise.all([pA.then(checkA), rp3]); + // expect: [['B good', 'C good', 'F good', 'three good', 'exit good', 'exitWF good'], 'rp3 good'] + return done; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/workers/device-add.js b/packages/SwingSet/test/workers/device-add.js index 77e38e0502e..83e8c6cc9c7 100644 --- a/packages/SwingSet/test/workers/device-add.js +++ b/packages/SwingSet/test/workers/device-add.js @@ -1,9 +1,13 @@ import { Far } from '@endo/far'; export function buildRootDeviceNode() { - return Far('root', { - add(x, y) { - return x + y; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + add(x, y) { + return x + y; + }, }, - }); + ); } diff --git a/packages/SwingSet/test/workers/vat-target.js b/packages/SwingSet/test/workers/vat-target.js index 9a24a0d4f5d..961eee5f7a5 100644 --- a/packages/SwingSet/test/workers/vat-target.js +++ b/packages/SwingSet/test/workers/vat-target.js @@ -73,11 +73,15 @@ export function buildRootObject(vatPowers, vatParameters) { return harden([...contents]); } - const target = Far('root', { - zero, - one, - append, - }); + const target = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + zero, + one, + append, + }, + ); return target; } diff --git a/packages/SwingSet/test/xsnap-snapshots/bootstrap-snapshots.js b/packages/SwingSet/test/xsnap-snapshots/bootstrap-snapshots.js index 774b271d578..557528a436f 100644 --- a/packages/SwingSet/test/xsnap-snapshots/bootstrap-snapshots.js +++ b/packages/SwingSet/test/xsnap-snapshots/bootstrap-snapshots.js @@ -2,11 +2,15 @@ import { Far } from '@endo/far'; export const buildRootObject = () => { let count = 0; - return Far('root', { - bootstrap: () => 0, - increment: () => { - count += 1; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap: () => 0, + increment: () => { + count += 1; + }, + read: () => count, }, - read: () => count, - }); + ); }; diff --git a/packages/SwingSet/test/xsnap-stable-bundles/vat-stable.js b/packages/SwingSet/test/xsnap-stable-bundles/vat-stable.js index 4fd7f30fa5f..2a5b08f06ad 100644 --- a/packages/SwingSet/test/xsnap-stable-bundles/vat-stable.js +++ b/packages/SwingSet/test/xsnap-stable-bundles/vat-stable.js @@ -3,19 +3,23 @@ import { E, Far } from '@endo/far'; export const buildRootObject = harden(() => { let vas; let control; - return Far('root', { - bootstrap: async (vats, devices) => { - vas = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap: async (vats, devices) => { + vas = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); + }, + ping: () => 0, + create: async () => { + const bcap = await E(vas).getNamedBundleCap('bootstrap'); + const options = { managerType: 'xs-worker' }; + control = await E(vas).createVat(bcap, options); + }, + upgrade: async () => { + const bcap = await E(vas).getNamedBundleCap('bootstrap'); + await E(control.adminNode).upgrade(bcap); + }, }, - ping: () => 0, - create: async () => { - const bcap = await E(vas).getNamedBundleCap('bootstrap'); - const options = { managerType: 'xs-worker' }; - control = await E(vas).createVat(bcap, options); - }, - upgrade: async () => { - const bcap = await E(vas).getNamedBundleCap('bootstrap'); - await E(control.adminNode).upgrade(bcap); - }, - }); + ); }); diff --git a/packages/SwingSet/test/zcf-ish-upgrade/bootstrap-zcf-ish-upgrade.js b/packages/SwingSet/test/zcf-ish-upgrade/bootstrap-zcf-ish-upgrade.js index b39f8999a53..b0821fd4cb3 100644 --- a/packages/SwingSet/test/zcf-ish-upgrade/bootstrap-zcf-ish-upgrade.js +++ b/packages/SwingSet/test/zcf-ish-upgrade/bootstrap-zcf-ish-upgrade.js @@ -5,36 +5,46 @@ export const buildRootObject = () => { let zcfRoot; let zcfAdmin; - return Far('root', { - bootstrap: async (vats, devices) => { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap: async (vats, devices) => { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + }, - buildV1: async () => { - // build the contract vat from ZCF and the contract bundlecap - const zcfbcap = await E(vatAdmin).getNamedBundleCap('zcf'); - const v1bcap = await E(vatAdmin).getNamedBundleCap('contractV1'); - const vatParameters = { contractBundleCap: v1bcap }; - const options = { vatParameters }; - const res = await E(vatAdmin).createVat(zcfbcap, options); - zcfRoot = res.root; - zcfAdmin = res.adminNode; + buildV1: async () => { + // build the contract vat from ZCF and the contract bundlecap + const zcfbcap = await E(vatAdmin).getNamedBundleCap('zcf'); + const v1bcap = await E(vatAdmin).getNamedBundleCap('contractV1'); + const vatParameters = { contractBundleCap: v1bcap }; + const options = { vatParameters }; + const res = await E(vatAdmin).createVat(zcfbcap, options); + zcfRoot = res.root; + zcfAdmin = res.adminNode; - // zygote clone would happen here + // zygote clone would happen here - const zoeThing = Far('zoeThing', {}); - // eslint-disable-next-line no-unused-vars - const { publicFacet, privateFacet } = await E(zcfRoot).start(zoeThing); - return true; - }, + const zoeThing = makeExo( + 'zoeThing', + M.interface('zoeThing', {}, { defaultGuards: 'passable' }), + {}, + ); + // eslint-disable-next-line no-unused-vars + const { publicFacet, privateFacet } = await E(zcfRoot).start(zoeThing); + return true; + }, - upgradeV2: async () => { - const zcfbcap = await E(vatAdmin).getNamedBundleCap('zcf'); - const v2bcap = await E(vatAdmin).getNamedBundleCap('contractV2'); - const vatParameters = { contractBundleCap: v2bcap }; - const options = { vatParameters }; - await E(zcfAdmin).upgrade(zcfbcap, options); - return true; + upgradeV2: async () => { + const zcfbcap = await E(vatAdmin).getNamedBundleCap('zcf'); + const v2bcap = await E(vatAdmin).getNamedBundleCap('contractV2'); + const vatParameters = { contractBundleCap: v2bcap }; + const options = { vatParameters }; + await E(zcfAdmin).upgrade(zcfbcap, options); + return true; + }, }, - }); + ); }; diff --git a/packages/SwingSet/test/zcf-ish-upgrade/pseudo-zcf.js b/packages/SwingSet/test/zcf-ish-upgrade/pseudo-zcf.js index b2aac733211..42d0ad1aa12 100644 --- a/packages/SwingSet/test/zcf-ish-upgrade/pseudo-zcf.js +++ b/packages/SwingSet/test/zcf-ish-upgrade/pseudo-zcf.js @@ -80,6 +80,10 @@ export const buildRootObject = async (vatPowers, vatParameters, baggage) => { // however we do not call makeInstanceKit() again } - const zcfRoot = Far('zcfRoot', { start }); + const zcfRoot = makeExo( + 'zcfRoot', + M.interface('zcfRoot', {}, { defaultGuards: 'passable' }), + { start }, + ); return zcfRoot; }; diff --git a/packages/SwingSet/tools/bootstrap-dvo-test.js b/packages/SwingSet/tools/bootstrap-dvo-test.js index 337e4d95abe..7b900adc510 100644 --- a/packages/SwingSet/tools/bootstrap-dvo-test.js +++ b/packages/SwingSet/tools/bootstrap-dvo-test.js @@ -17,35 +17,41 @@ export function buildRootObject() { return testLog; } - const self = Far('root', { - async bootstrap(vats, devices) { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - }, + const self = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + }, - log(message) { - testLog.push(message); - }, + log(message) { + testLog.push(message); + }, - testComplete() { - doneP.resolve(true); - }, + testComplete() { + doneP.resolve(true); + }, - async buildV1(vatParameters) { - const bcap = await E(vatAdmin).getNamedBundleCap('testVat'); - const options = { vatParameters }; - const res = await E(vatAdmin).createVat(bcap, options); - testVatRoot = res.root; - testVatAdmin = res.adminNode; - await runTests('before'); - return testLog; - }, + async buildV1(vatParameters) { + const bcap = await E(vatAdmin).getNamedBundleCap('testVat'); + const options = { vatParameters }; + const res = await E(vatAdmin).createVat(bcap, options); + testVatRoot = res.root; + testVatAdmin = res.adminNode; + await runTests('before'); + return testLog; + }, - async upgradeV2(vatParameters) { - const bcap = await E(vatAdmin).getNamedBundleCap('testVat'); - await E(testVatAdmin).upgrade(bcap, { vatParameters }); - await runTests('after'); - return testLog; + async upgradeV2(vatParameters) { + const bcap = await E(vatAdmin).getNamedBundleCap('testVat'); + await E(testVatAdmin).upgrade(bcap, { vatParameters }); + await runTests('after'); + return testLog; + }, }, - }); + ); return self; } diff --git a/packages/SwingSet/tools/bootstrap-relay.js b/packages/SwingSet/tools/bootstrap-relay.js index f054f567ae5..f9c2d191ad3 100644 --- a/packages/SwingSet/tools/bootstrap-relay.js +++ b/packages/SwingSet/tools/bootstrap-relay.js @@ -12,90 +12,97 @@ export const buildRootObject = () => { const devicesByName = new Map(); const callLogsByRemotable = new Map(); - return Far('root', { - bootstrap: async (vats, devices) => { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - for (const [name, root] of Object.entries(vats)) { - if (name !== 'vatAdmin') { - vatData.set(name, { root }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap: async (vats, devices) => { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + for (const [name, root] of Object.entries(vats)) { + if (name !== 'vatAdmin') { + vatData.set(name, { root }); + } } - } - for (const [name, device] of Object.entries(devices)) { - devicesByName.set(name, device); - } - }, + for (const [name, device] of Object.entries(devices)) { + devicesByName.set(name, device); + } + }, - getDevice: async deviceName => devicesByName.get(deviceName), + getDevice: async deviceName => devicesByName.get(deviceName), - getVatAdmin: async () => vatAdmin, + getVatAdmin: async () => vatAdmin, - getTimer: async () => timer, + getTimer: async () => timer, - getVatRoot: async vatName => { - const vat = vatData.get(vatName) || Fail`unknown vat name: ${q(vatName)}`; - const { root } = vat; - return root; - }, + getVatRoot: async vatName => { + const vat = + vatData.get(vatName) || Fail`unknown vat name: ${q(vatName)}`; + const { root } = vat; + return root; + }, - createVat: async ({ name, bundleCapName, vatParameters = {} }) => { - const bcap = await E(vatAdmin).getNamedBundleCap(bundleCapName); - const options = { vatParameters }; - const { adminNode, root } = await E(vatAdmin).createVat(bcap, options); - vatData.set(name, { adminNode, root }); - return root; - }, + createVat: async ({ name, bundleCapName, vatParameters = {} }) => { + const bcap = await E(vatAdmin).getNamedBundleCap(bundleCapName); + const options = { vatParameters }; + const { adminNode, root } = await E(vatAdmin).createVat(bcap, options); + vatData.set(name, { adminNode, root }); + return root; + }, - upgradeVat: async ({ name, bundleCapName, vatParameters = {} }) => { - const vat = vatData.get(name) || Fail`unknown vat name: ${q(name)}`; - const bcap = await E(vatAdmin).getNamedBundleCap(bundleCapName); - const options = { vatParameters }; - const incarnationNumber = await E(vat.adminNode).upgrade(bcap, options); - vat.incarnationNumber = incarnationNumber; - return incarnationNumber; - }, + upgradeVat: async ({ name, bundleCapName, vatParameters = {} }) => { + const vat = vatData.get(name) || Fail`unknown vat name: ${q(name)}`; + const bcap = await E(vatAdmin).getNamedBundleCap(bundleCapName); + const options = { vatParameters }; + const incarnationNumber = await E(vat.adminNode).upgrade(bcap, options); + vat.incarnationNumber = incarnationNumber; + return incarnationNumber; + }, - /** - * Derives a remotable from an object by mapping each object property into a method that returns the value. - * - * @param {string} label - * @param {Record} returnValues - */ - makeRemotable: (label, returnValues) => { - const callLogs = []; - const makeGetterFunction = (value, name) => { - const getValue = (...args) => { - callLogs.push([name, ...args]); - return value; + /** + * Derives a remotable from an object by mapping each object property into a method that returns the value. + * + * @param {string} label + * @param {Record} returnValues + */ + makeRemotable: (label, returnValues) => { + const callLogs = []; + const makeGetterFunction = (value, name) => { + const getValue = (...args) => { + callLogs.push([name, ...args]); + return value; + }; + return getValue; }; - return getValue; - }; - // `objectMap` hardens its result, but... - const methods = objectMap(returnValues, makeGetterFunction); - // ... `Far` requires its methods argument not to be hardened. - const remotable = Far(label, { ...methods }); - callLogsByRemotable.set(remotable, callLogs); - return remotable; - }, + // `objectMap` hardens its result, but... + const methods = objectMap(returnValues, makeGetterFunction); + // ... `Far` requires its methods argument not to be hardened. + const remotable = Far(label, { ...methods }); + callLogsByRemotable.set(remotable, callLogs); + return remotable; + }, - /** - * Returns a copy of a remotable's logs. - * - * @param {object} remotable - */ - getLogForRemotable: remotable => { - const logs = - callLogsByRemotable.get(remotable) || - Fail`logs not found for ${q(remotable)}`; - // Return a copy so that the original remains mutable. - return harden([...logs]); - }, + /** + * Returns a copy of a remotable's logs. + * + * @param {object} remotable + */ + getLogForRemotable: remotable => { + const logs = + callLogsByRemotable.get(remotable) || + Fail`logs not found for ${q(remotable)}`; + // Return a copy so that the original remains mutable. + return harden([...logs]); + }, - awaitVatObject: async (presence, path = []) => { - let value = await presence; - for (const key of path) { - value = await value[key]; - } - return value; + awaitVatObject: async (presence, path = []) => { + let value = await presence; + for (const key of path) { + value = await value[key]; + } + return value; + }, }, - }); + ); }; diff --git a/packages/SwingSet/tools/manual-timer.js b/packages/SwingSet/tools/manual-timer.js index 9d7ab7924fb..8c1c0f522ca 100644 --- a/packages/SwingSet/tools/manual-timer.js +++ b/packages/SwingSet/tools/manual-timer.js @@ -118,9 +118,13 @@ export const buildManualTimer = (options = {}) => { return advanceTo(TimeMath.addAbsRel(state.now, rel), msg); }; - return Far('ManualTimer', { - ...bindAllMethods(timerService), - advanceTo, - advanceBy, - }); + return makeExo( + 'ManualTimer', + M.interface('ManualTimer', {}, { defaultGuards: 'passable' }), + { + ...bindAllMethods(timerService), + advanceTo, + advanceBy, + }, + ); }; diff --git a/packages/agoric-cli/src/follow.js b/packages/agoric-cli/src/follow.js index 745afc5830f..31f7e4dbe8d 100644 --- a/packages/agoric-cli/src/follow.js +++ b/packages/agoric-cli/src/follow.js @@ -114,16 +114,20 @@ export default async function followerMain(progname, rawArgs, powers, opts) { } if (proof !== 'none') { - followerOptions.crasher = Far('follower crasher', { - crash: (...args) => { - console.error(...args); - console.warn(`You are running with '--proof=${proof}'`); - console.warn( - `If you trust your RPC nodes, you can turn off proofs with '--proof=none'`, - ); - process.exit(1); + followerOptions.crasher = makeExo( + 'follower crasher', + M.interface('follower crasher', {}, { defaultGuards: 'passable' }), + { + crash: (...args) => { + console.error(...args); + console.warn(`You are running with '--proof=${proof}'`); + console.warn( + `If you trust your RPC nodes, you can turn off proofs with '--proof=none'`, + ); + process.exit(1); + }, }, - }); + ); } const leaderOptions = makeLeaderOptions({ diff --git a/packages/agoric-cli/tools/resm-plugin/package.json b/packages/agoric-cli/tools/resm-plugin/package.json index 367b50b8dd1..1e6de39941d 100644 --- a/packages/agoric-cli/tools/resm-plugin/package.json +++ b/packages/agoric-cli/tools/resm-plugin/package.json @@ -4,7 +4,9 @@ "type": "commonjs", "dependencies": { "@endo/eventual-send": "^0.17.2", - "@endo/marshal": "^0.8.5" + "@endo/exo": "^1.2.1", + "@endo/marshal": "^0.8.5", + "@endo/patterns": "^1.2.0" }, "typeCoverage": { "atLeast": 0 diff --git a/packages/agoric-cli/tools/resm-plugin/src/plugin.js b/packages/agoric-cli/tools/resm-plugin/src/plugin.js index 83bb1e2662d..59ae85590c5 100644 --- a/packages/agoric-cli/tools/resm-plugin/src/plugin.js +++ b/packages/agoric-cli/tools/resm-plugin/src/plugin.js @@ -1,17 +1,26 @@ // @jessie-check -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { start } from './output.js'; export const bootPlugin = () => { - return Far('plugin', { - start(_opts) { - console.log(start); - return Far('plugin start', { - async ping() { - return 'pong'; - }, - }); + return makeExo( + 'plugin', + M.interface('plugin', {}, { defaultGuards: 'passable' }), + { + start(_opts) { + console.log(start); + return makeExo( + 'plugin start', + M.interface('plugin start', {}, { defaultGuards: 'passable' }), + { + async ping() { + return 'pong'; + }, + }, + ); + }, }, - }); + ); }; diff --git a/packages/base-zone/src/heap.js b/packages/base-zone/src/heap.js index 839cd2abaf1..5abc789ebb1 100644 --- a/packages/base-zone/src/heap.js +++ b/packages/base-zone/src/heap.js @@ -17,15 +17,19 @@ import { isPassable } from './is-passable.js'; /** * @type {import('./types.js').Stores} */ -const detachedHeapStores = Far('heapStores', { - detached: () => detachedHeapStores, - isStorable: isPassable, +const detachedHeapStores = makeExo( + 'heapStores', + M.interface('heapStores', {}, { defaultGuards: 'passable' }), + { + detached: () => detachedHeapStores, + isStorable: isPassable, - setStore: makeScalarSetStore, - mapStore: makeScalarMapStore, - weakMapStore: makeScalarWeakMapStore, - weakSetStore: makeScalarWeakSetStore, -}); + setStore: makeScalarSetStore, + mapStore: makeScalarMapStore, + weakMapStore: makeScalarWeakMapStore, + weakSetStore: makeScalarWeakSetStore, + }, +); /** * Create a heap (in-memory) zone that uses the default exo and store implementations. @@ -43,20 +47,24 @@ export const makeHeapZone = (baseLabel = 'heapZone') => { const makeSubZone = (label, _options) => makeHeapZone(`${baseLabel}.${label}`); - return Far('heapZone', { - exo: wrapProvider(makeExo, keys.exo), - exoClass: wrapProvider(defineExoClass, keys.exoClass), - exoClassKit: wrapProvider(defineExoClassKit, keys.exoClassKit), - subZone: wrapProvider(makeSubZone), - - makeOnce, - detached: detachedHeapStores.detached, - isStorable: detachedHeapStores.isStorable, - - mapStore: wrapProvider(detachedHeapStores.mapStore), - setStore: wrapProvider(detachedHeapStores.setStore), - weakMapStore: wrapProvider(detachedHeapStores.weakMapStore), - weakSetStore: wrapProvider(detachedHeapStores.weakSetStore), - }); + return makeExo( + 'heapZone', + M.interface('heapZone', {}, { defaultGuards: 'passable' }), + { + exo: wrapProvider(makeExo, keys.exo), + exoClass: wrapProvider(defineExoClass, keys.exoClass), + exoClassKit: wrapProvider(defineExoClassKit, keys.exoClassKit), + subZone: wrapProvider(makeSubZone), + + makeOnce, + detached: detachedHeapStores.detached, + isStorable: detachedHeapStores.isStorable, + + mapStore: wrapProvider(detachedHeapStores.mapStore), + setStore: wrapProvider(detachedHeapStores.setStore), + weakMapStore: wrapProvider(detachedHeapStores.weakMapStore), + weakSetStore: wrapProvider(detachedHeapStores.weakSetStore), + }, + ); }; harden(makeHeapZone); diff --git a/packages/boot/test/bootstrapTests/test-vaults-upgrade.ts b/packages/boot/test/bootstrapTests/test-vaults-upgrade.ts index d88523ad44a..e9f6a4e00a5 100644 --- a/packages/boot/test/bootstrapTests/test-vaults-upgrade.ts +++ b/packages/boot/test/bootstrapTests/test-vaults-upgrade.ts @@ -207,7 +207,11 @@ test.serial('audit bootstrap exports', async t => { // Map oid to iface by poring over transcript syscalls const toIface = new Map(); - const anObj = Far('obj', {}); + const anObj = makeExo( + 'obj', + M.interface('obj', {}, { defaultGuards: 'passable' }), + {}, + ); const aPromise = harden(new Promise(() => {})); const saveBootstrapIface = (slot, iface) => { if (slot.startsWith('p')) return aPromise; diff --git a/packages/boot/test/upgrading/bootstrap.js b/packages/boot/test/upgrading/bootstrap.js index c009b02ddea..55deda2492b 100644 --- a/packages/boot/test/upgrading/bootstrap.js +++ b/packages/boot/test/upgrading/bootstrap.js @@ -13,7 +13,7 @@ export const buildRootObject = () => { const bootKit = makePromiseKit(); const v1Kit = makePromiseKit(); - return Far('B', { + return makeExo('B', M.interface('B', {}, { defaultGuards: 'passable' }), { bootstrap: async (vats, devices) => { const vatAdmin = await E(vats.vatAdmin).createVatAdminService( devices.vatAdmin, diff --git a/packages/boot/test/upgrading/device-bridge.js b/packages/boot/test/upgrading/device-bridge.js index 74011615f19..88bd20e2930 100644 --- a/packages/boot/test/upgrading/device-bridge.js +++ b/packages/boot/test/upgrading/device-bridge.js @@ -5,24 +5,28 @@ export const buildRootDeviceNode = tools => { const { endowments: { t, bridgeBackends }, } = tools; - return Far('fakeBridgeDevice', { - callOutbound(dstID, obj) { - t.assert(inboundHandler, 'callOutbound before registerInboundHandler'); - if (dstID in bridgeBackends) { - return bridgeBackends[dstID](obj); - } - t.fail(`bridge unknown dstID ${dstID}`); + return makeExo( + 'fakeBridgeDevice', + M.interface('fakeBridgeDevice', {}, { defaultGuards: 'passable' }), + { + callOutbound(dstID, obj) { + t.assert(inboundHandler, 'callOutbound before registerInboundHandler'); + if (dstID in bridgeBackends) { + return bridgeBackends[dstID](obj); + } + t.fail(`bridge unknown dstID ${dstID}`); + }, + registerInboundHandler(handler) { + t.assert(!inboundHandler, `already registered ${inboundHandler}`); + inboundHandler = handler; + }, + unregisterInboundHandler() { + t.assert( + inboundHandler, + 'unregisterInboundHandler before registerInboundHandler', + ); + inboundHandler = undefined; + }, }, - registerInboundHandler(handler) { - t.assert(!inboundHandler, `already registered ${inboundHandler}`); - inboundHandler = handler; - }, - unregisterInboundHandler() { - t.assert( - inboundHandler, - 'unregisterInboundHandler before registerInboundHandler', - ); - inboundHandler = undefined; - }, - }); + ); }; diff --git a/packages/boot/test/upgrading/vat-mint.js b/packages/boot/test/upgrading/vat-mint.js index 0a76eca73f4..8a3770e9015 100644 --- a/packages/boot/test/upgrading/vat-mint.js +++ b/packages/boot/test/upgrading/vat-mint.js @@ -2,7 +2,11 @@ import { makeIssuerKit } from '@agoric/ertp'; import { Far } from '@endo/far'; export const buildRootObject = () => { - return Far('MintRoot', { - makeIssuerKit, - }); + return makeExo( + 'MintRoot', + M.interface('MintRoot', {}, { defaultGuards: 'passable' }), + { + makeIssuerKit, + }, + ); }; diff --git a/packages/boot/test/upgrading/vat-vow.js b/packages/boot/test/upgrading/vat-vow.js index 647f1606b72..a001a68c91b 100644 --- a/packages/boot/test/upgrading/vat-vow.js +++ b/packages/boot/test/upgrading/vat-vow.js @@ -20,28 +20,32 @@ export const buildRootObject = (_vatPowers, _args, baggage) => { }, }); - return Far('VowRoot', { - getWatcherResults() { - return harden(Object.fromEntries(nameToResult.entries())); - }, - /** @param {Record} localPromises */ - async makeLocalPromiseWatchers(localPromises) { - for (const [name, settlement] of Object.entries(localPromises)) { - nameToResult.init(name, harden({ status: 'unsettled' })); - let p; - if (!settlement.length) { - // Never settle. - p = new Promise(() => {}); - } else { - const [settlementValue, isRejection] = settlement; - if (isRejection) { - p = Promise.reject(settlementValue); + return makeExo( + 'VowRoot', + M.interface('VowRoot', {}, { defaultGuards: 'passable' }), + { + getWatcherResults() { + return harden(Object.fromEntries(nameToResult.entries())); + }, + /** @param {Record} localPromises */ + async makeLocalPromiseWatchers(localPromises) { + for (const [name, settlement] of Object.entries(localPromises)) { + nameToResult.init(name, harden({ status: 'unsettled' })); + let p; + if (!settlement.length) { + // Never settle. + p = new Promise(() => {}); } else { - p = Promise.resolve(settlementValue); + const [settlementValue, isRejection] = settlement; + if (isRejection) { + p = Promise.reject(settlementValue); + } else { + p = Promise.resolve(settlementValue); + } } + watch(p, makeWatcher(name)); } - watch(p, makeWatcher(name)); - } + }, }, - }); + ); }; diff --git a/packages/cache/src/cache.js b/packages/cache/src/cache.js index 1788745a74f..08539457eba 100644 --- a/packages/cache/src/cache.js +++ b/packages/cache/src/cache.js @@ -32,11 +32,15 @@ export const makeCache = (coordinator = makeScalarStoreCoordinator()) => { return E(coordinator).setCacheValue(key, update, guardPattern); } - const updater = Far('cache updater', { - update: oldValue => { - return update(oldValue); + const updater = makeExo( + 'cache updater', + M.interface('cache updater', {}, { defaultGuards: 'passable' }), + { + update: oldValue => { + return update(oldValue); + }, }, - }); + ); return E(coordinator).updateCacheValue(key, updater, guardPattern); }; diff --git a/packages/cache/src/store.js b/packages/cache/src/store.js index 01670024e8f..37ce13ece4d 100644 --- a/packages/cache/src/store.js +++ b/packages/cache/src/store.js @@ -137,32 +137,36 @@ export const makeScalarStoreCoordinator = ( const defaultStateStore = withGroundState(stateStore); /** @type {import('./types.js').Coordinator} */ - const coord = Far('store cache coordinator', { - getRecentValue: async key => { - const keyStr = await serializePassable(key); - return defaultStateStore.get(keyStr).value; + const coord = makeExo( + 'store cache coordinator', + M.interface('store cache coordinator', {}, { defaultGuards: 'passable' }), + { + getRecentValue: async key => { + const keyStr = await serializePassable(key); + return defaultStateStore.get(keyStr).value; + }, + setCacheValue: async (key, newValue, guardPattern) => { + const keyStr = await serializePassable(key); + return applyCacheTransaction( + keyStr, + () => newValue, + guardPattern, + sanitize, + defaultStateStore, + ); + }, + updateCacheValue: async (key, updater, guardPattern) => { + const keyStr = await serializePassable(key); + return applyCacheTransaction( + keyStr, + oldValue => E(updater).update(oldValue), + guardPattern, + sanitize, + defaultStateStore, + ); + }, }, - setCacheValue: async (key, newValue, guardPattern) => { - const keyStr = await serializePassable(key); - return applyCacheTransaction( - keyStr, - () => newValue, - guardPattern, - sanitize, - defaultStateStore, - ); - }, - updateCacheValue: async (key, updater, guardPattern) => { - const keyStr = await serializePassable(key); - return applyCacheTransaction( - keyStr, - oldValue => E(updater).update(oldValue), - guardPattern, - sanitize, - defaultStateStore, - ); - }, - }); + ); return coord; }; @@ -217,33 +221,37 @@ export const makeChainStorageCoordinator = (storageNode, marshaller) => { ); /** @type {import('./types.js').Coordinator} */ - const coord = Far('store cache coordinator', { - getRecentValue: async key => { - const keyStr = await serializePassable(key); - return defaultStateStore.get(keyStr).value; + const coord = makeExo( + 'store cache coordinator', + M.interface('store cache coordinator', {}, { defaultGuards: 'passable' }), + { + getRecentValue: async key => { + const keyStr = await serializePassable(key); + return defaultStateStore.get(keyStr).value; + }, + setCacheValue: async (key, newValue, guardPattern) => { + const keyStr = await serializePassable(key); + const storedValue = await applyCacheTransaction( + keyStr, + () => newValue, + guardPattern, + sanitize, + defaultStateStore, + ); + return updateStorageNode(storedValue); + }, + updateCacheValue: async (key, updater, guardPattern) => { + const keyStr = await serializePassable(key); + const storedValue = await applyCacheTransaction( + keyStr, + oldValue => E(updater).update(oldValue), + guardPattern, + sanitize, + defaultStateStore, + ); + return updateStorageNode(storedValue); + }, }, - setCacheValue: async (key, newValue, guardPattern) => { - const keyStr = await serializePassable(key); - const storedValue = await applyCacheTransaction( - keyStr, - () => newValue, - guardPattern, - sanitize, - defaultStateStore, - ); - return updateStorageNode(storedValue); - }, - updateCacheValue: async (key, updater, guardPattern) => { - const keyStr = await serializePassable(key); - const storedValue = await applyCacheTransaction( - keyStr, - oldValue => E(updater).update(oldValue), - guardPattern, - sanitize, - defaultStateStore, - ); - return updateStorageNode(storedValue); - }, - }); + ); return coord; }; diff --git a/packages/cache/test/test-storage.js b/packages/cache/test/test-storage.js index af41dabf3ae..15d751b6929 100644 --- a/packages/cache/test/test-storage.js +++ b/packages/cache/test/test-storage.js @@ -92,7 +92,11 @@ test('makeChainStorageCoordinator with non-remote values', async t => { test('makeChainStorageCoordinator with remote values', async t => { const { cache, storageNodeState } = setup(); - const farThing = Far('farThing', { getAllegedName: () => 'dollaz' }); + const farThing = makeExo( + 'farThing', + M.interface('farThing', {}, { defaultGuards: 'passable' }), + { getAllegedName: () => 'dollaz' }, + ); t.is(await cache('brand', farThing), farThing); t.deepEqual(Object.keys(storageNodeState), ['cache']); @@ -144,11 +148,15 @@ test('makeChainStorageCoordinator with remote updater', async t => { const { cache, storageNodeState } = setup(); let counter = 0; - const counterObj = Far('counterObj', { - increment: () => { - return (counter += 1); + const counterObj = makeExo( + 'counterObj', + M.interface('counterObj', {}, { defaultGuards: 'passable' }), + { + increment: () => { + return (counter += 1); + }, }, - }); + ); // Initial t.is(await cache('counter', counterObj.increment), 1); diff --git a/packages/casting/src/change-follower.js b/packages/casting/src/change-follower.js index e5d8cf38ef0..53ef22e5ad3 100644 --- a/packages/casting/src/change-follower.js +++ b/packages/casting/src/change-follower.js @@ -10,44 +10,64 @@ import { DEFAULT_KEEP_POLLING } from './defaults.js'; export const makePollingChangeFollower = async leader => { const { keepPolling = DEFAULT_KEEP_POLLING } = await E(leader).getOptions(); - const iterable = Far('polling change follower iterable', { - [Symbol.asyncIterator]: () => { - /** @type {Promise | undefined} */ - let nextPollPromise; - return Far('polling change follower iterator', { - next: async () => { - if (!nextPollPromise) { - nextPollPromise = keepPolling('polling change follower').then( - cont => { - if (cont) { - return E(leader) - .jitter('polling change follower') - .then(() => cont); - } - return cont; - }, - ); - } - const keepGoing = await nextPollPromise; - nextPollPromise = undefined; - const change = harden({ - // Make no warrant as to the values. - values: [], - }); - return harden({ - value: change, - done: !keepGoing, - }); - }, - }); + const iterable = makeExo( + 'polling change follower iterable', + M.interface( + 'polling change follower iterable', + {}, + { defaultGuards: 'passable' }, + ), + { + [Symbol.asyncIterator]: () => { + /** @type {Promise | undefined} */ + let nextPollPromise; + return makeExo( + 'polling change follower iterator', + M.interface( + 'polling change follower iterator', + {}, + { defaultGuards: 'passable' }, + ), + { + next: async () => { + if (!nextPollPromise) { + nextPollPromise = keepPolling('polling change follower').then( + cont => { + if (cont) { + return E(leader) + .jitter('polling change follower') + .then(() => cont); + } + return cont; + }, + ); + } + const keepGoing = await nextPollPromise; + nextPollPromise = undefined; + const change = harden({ + // Make no warrant as to the values. + values: [], + }); + return harden({ + value: change, + done: !keepGoing, + }); + }, + }, + ); + }, }, - }); + ); - return Far('polling change follower', { - getLatestIterable: async () => iterable, - getEachIterable: async () => iterable, - getReverseIterable: async () => { - throw Error('not implemented for polling change follower'); + return makeExo( + 'polling change follower', + M.interface('polling change follower', {}, { defaultGuards: 'passable' }), + { + getLatestIterable: async () => iterable, + getEachIterable: async () => iterable, + getReverseIterable: async () => { + throw Error('not implemented for polling change follower'); + }, }, - }); + ); }; diff --git a/packages/casting/src/defaults.js b/packages/casting/src/defaults.js index 321e9eec29a..e101adbb91e 100644 --- a/packages/casting/src/defaults.js +++ b/packages/casting/src/defaults.js @@ -109,17 +109,21 @@ export const MAKE_DEFAULT_UNSERIALIZER = () => { if (typeof iface === 'string' && iface.startsWith(ifaceAllegedPrefix)) { iface = iface.slice(ifaceAllegedPrefix.length); } - const obj = Far(`${ifaceInaccessiblePrefix}${iface}`, {}); + const obj = makeExo(`${ifaceInaccessiblePrefix}${iface}`, M.interface(`${ifaceInaccessiblePrefix}${iface}`, {}, { defaultGuards: 'passable' }), {}); seen.set(slot, obj); return obj; }; - return Far('marshal unserializer', { - fromCapData: makeMarshal(undefined, slotToVal, { - serializeBodyFormat: 'smallcaps', - }).fromCapData, - /** @deprecated use fromCapData */ - unserialize: makeMarshal(undefined, slotToVal, { - serializeBodyFormat: 'smallcaps', - }).fromCapData, - }); + return makeExo( + 'marshal unserializer', + M.interface('marshal unserializer', {}, { defaultGuards: 'passable' }), + { + fromCapData: makeMarshal(undefined, slotToVal, { + serializeBodyFormat: 'smallcaps', + }).fromCapData, + /** @deprecated use fromCapData */ + unserialize: makeMarshal(undefined, slotToVal, { + serializeBodyFormat: 'smallcaps', + }).fromCapData, + }, + ); }; diff --git a/packages/casting/src/follower-cosmjs.js b/packages/casting/src/follower-cosmjs.js index 5792b6c8ede..30417e26738 100644 --- a/packages/casting/src/follower-cosmjs.js +++ b/packages/casting/src/follower-cosmjs.js @@ -592,15 +592,19 @@ export const makeCosmjsFollower = ( harden(getReverseIterableAtHeight); /** @type {ValueFollower} */ - return Far('chain follower', { - async getLatestIterable() { - return getLatestIterable(); + return makeExo( + 'chain follower', + M.interface('chain follower', {}, { defaultGuards: 'passable' }), + { + async getLatestIterable() { + return getLatestIterable(); + }, + async getEachIterable({ height = undefined } = {}) { + return getEachIterableAtHeight(height); + }, + async getReverseIterable({ height = undefined } = {}) { + return getReverseIterableAtHeight(height); + }, }, - async getEachIterable({ height = undefined } = {}) { - return getEachIterableAtHeight(height); - }, - async getReverseIterable({ height = undefined } = {}) { - return getReverseIterableAtHeight(height); - }, - }); + ); }; diff --git a/packages/casting/src/follower.js b/packages/casting/src/follower.js index bc49801acab..8d954ae4b7b 100644 --- a/packages/casting/src/follower.js +++ b/packages/casting/src/follower.js @@ -17,37 +17,45 @@ const makeSubscriptionFollower = spec => { const transform = value => harden({ value, blockHeight: NaN, currentBlockHeight: NaN }); /** @type {import('./types.js').Follower>} */ - const follower = Far('subscription/notifier follower', { - getLatestIterable: async () => { - const { notifier, subscription } = await spec; - let ai; - if (notifier) { - ai = subscribeLatest(notifier); - } else { - assert(subscription); - ai = subscribeEach(subscription); - } - return mapAsyncIterable(ai, transform); - }, + const follower = makeExo( + 'subscription/notifier follower', + M.interface( + 'subscription/notifier follower', + {}, + { defaultGuards: 'passable' }, + ), + { + getLatestIterable: async () => { + const { notifier, subscription } = await spec; + let ai; + if (notifier) { + ai = subscribeLatest(notifier); + } else { + assert(subscription); + ai = subscribeEach(subscription); + } + return mapAsyncIterable(ai, transform); + }, - getEachIterable: async () => { - const { notifier, subscription } = await spec; - let ai; - if (subscription) { - ai = subscribeEach(subscription); - } else { - assert(notifier); - ai = subscribeLatest(notifier); - } - return mapAsyncIterable(ai, transform); - }, + getEachIterable: async () => { + const { notifier, subscription } = await spec; + let ai; + if (subscription) { + ai = subscribeEach(subscription); + } else { + assert(notifier); + ai = subscribeLatest(notifier); + } + return mapAsyncIterable(ai, transform); + }, - getReverseIterable: async () => { - throw Error( - 'reverse iteration not implemented for subscription follower', - ); + getReverseIterable: async () => { + throw Error( + 'reverse iteration not implemented for subscription follower', + ); + }, }, - }); + ); return follower; }; diff --git a/packages/casting/src/iterable.js b/packages/casting/src/iterable.js index e97fa8e3fc6..2e33e1f5a22 100644 --- a/packages/casting/src/iterable.js +++ b/packages/casting/src/iterable.js @@ -27,16 +27,28 @@ export const mapAsyncIterable = (iterable, transform) => { */ export const iterateLatest = follower => // For now, just pass through the iterable. - Far('iterateLatest iterable', { - /** @returns {AsyncIterator} */ - [Symbol.asyncIterator]: () => { - const latestIterable = E(follower).getLatestIterable(); - const iterator = E(latestIterable)[Symbol.asyncIterator](); - return Far('iterateLatest iterator', { - next: () => E(iterator).next(), - }); + makeExo( + 'iterateLatest iterable', + M.interface('iterateLatest iterable', {}, { defaultGuards: 'passable' }), + { + /** @returns {AsyncIterator} */ + [Symbol.asyncIterator]: () => { + const latestIterable = E(follower).getLatestIterable(); + const iterator = E(latestIterable)[Symbol.asyncIterator](); + return makeExo( + 'iterateLatest iterator', + M.interface( + 'iterateLatest iterator', + {}, + { defaultGuards: 'passable' }, + ), + { + next: () => E(iterator).next(), + }, + ); + }, }, - }); + ); /** * TODO: Remove this function when we have an @endo/publish-kit that suppports pull topics @@ -47,16 +59,28 @@ export const iterateLatest = follower => */ export const iterateEach = (follower, options) => // For now, just pass through the iterable. - Far('iterateEach iterable', { - /** @returns {AsyncIterator} */ - [Symbol.asyncIterator]: () => { - const eachIterable = E(follower).getEachIterable(options); - const iterator = E(eachIterable)[Symbol.asyncIterator](); - return Far('iterateEach iterator', { - next: () => E(iterator).next(), - }); + makeExo( + 'iterateEach iterable', + M.interface('iterateEach iterable', {}, { defaultGuards: 'passable' }), + { + /** @returns {AsyncIterator} */ + [Symbol.asyncIterator]: () => { + const eachIterable = E(follower).getEachIterable(options); + const iterator = E(eachIterable)[Symbol.asyncIterator](); + return makeExo( + 'iterateEach iterator', + M.interface( + 'iterateEach iterator', + {}, + { defaultGuards: 'passable' }, + ), + { + next: () => E(iterator).next(), + }, + ); + }, }, - }); + ); /** * @template T @@ -65,13 +89,25 @@ export const iterateEach = (follower, options) => */ export const iterateReverse = (follower, options) => // For now, just pass through the iterable. - Far('iterateReverse iterable', { - /** @returns {AsyncIterator} */ - [Symbol.asyncIterator]: () => { - const eachIterable = E(follower).getReverseIterable(options); - const iterator = E(eachIterable)[Symbol.asyncIterator](); - return Far('iterateEach iterator', { - next: () => E(iterator).next(), - }); + makeExo( + 'iterateReverse iterable', + M.interface('iterateReverse iterable', {}, { defaultGuards: 'passable' }), + { + /** @returns {AsyncIterator} */ + [Symbol.asyncIterator]: () => { + const eachIterable = E(follower).getReverseIterable(options); + const iterator = E(eachIterable)[Symbol.asyncIterator](); + return makeExo( + 'iterateEach iterator', + M.interface( + 'iterateEach iterator', + {}, + { defaultGuards: 'passable' }, + ), + { + next: () => E(iterator).next(), + }, + ); + }, }, - }); + ); diff --git a/packages/casting/src/leader.js b/packages/casting/src/leader.js index 793551326ba..afdd3c6a8a3 100644 --- a/packages/casting/src/leader.js +++ b/packages/casting/src/leader.js @@ -22,63 +22,67 @@ export const makeRoundRobinLeader = (endpoints, leaderOptions = {}) => { let retrying; /** @type {import('./types.js').Leader} */ - const leader = Far('round robin leader', { - getOptions: () => leaderOptions, - jitter: async where => jitter && jitter(where), - retry: async (where, err, attempt) => { - if (retryCallback) { - return retryCallback(where, err, attempt); - } - throw err; - }, - // eslint-disable-next-line no-use-before-define - watchCasting: _castingSpecP => pollingChangeFollower, - /** - * @template T - * @param {string} where - * @param {(endpoint: string) => Promise} callback - */ - mapEndpoints: async (where, callback) => { - where = `${where} (round-robin endpoints)`; - /** @type {Promise} */ - const p = new Promise((resolve, reject) => { - let endpointIndex = lastRespondingEndpointIndex; + const leader = makeExo( + 'round robin leader', + M.interface('round robin leader', {}, { defaultGuards: 'passable' }), + { + getOptions: () => leaderOptions, + jitter: async where => jitter && jitter(where), + retry: async (where, err, attempt) => { + if (retryCallback) { + return retryCallback(where, err, attempt); + } + throw err; + }, + // eslint-disable-next-line no-use-before-define + watchCasting: _castingSpecP => pollingChangeFollower, + /** + * @template T + * @param {string} where + * @param {(endpoint: string) => Promise} callback + */ + mapEndpoints: async (where, callback) => { + where = `${where} (round-robin endpoints)`; + /** @type {Promise} */ + const p = new Promise((resolve, reject) => { + let endpointIndex = lastRespondingEndpointIndex; - const retry = err => { - if (!retrying) { - const attempt = thisAttempt; - retrying = E(leader) - .retry(where, err, attempt) - .then(() => { - endpointIndex = (endpointIndex + 1) % endpoints.length; - retrying = null; - }); - } + const retry = err => { + if (!retrying) { + const attempt = thisAttempt; + retrying = E(leader) + .retry(where, err, attempt) + .then(() => { + endpointIndex = (endpointIndex + 1) % endpoints.length; + retrying = null; + }); + } - retrying - .then(() => jitter && jitter(where)) - // eslint-disable-next-line no-use-before-define - .then(applyOne, reject); - thisAttempt += 1; - }; + retrying + .then(() => jitter && jitter(where)) + // eslint-disable-next-line no-use-before-define + .then(applyOne, reject); + thisAttempt += 1; + }; - const applyOne = () => { - Promise.resolve() - .then(() => callback(endpoints[endpointIndex])) - .then(res => { - resolve(harden([res])); - lastRespondingEndpointIndex = endpointIndex; - thisAttempt = 0; - }, retry); + const applyOne = () => { + Promise.resolve() + .then(() => callback(endpoints[endpointIndex])) + .then(res => { + resolve(harden([res])); + lastRespondingEndpointIndex = endpointIndex; + thisAttempt = 0; + }, retry); - // Don't return to prevent a promise chain. - }; + // Don't return to prevent a promise chain. + }; - applyOne(); - }); - return p; + applyOne(); + }); + return p; + }, }, - }); + ); const pollingChangeFollower = makePollingChangeFollower(leader); return leader; diff --git a/packages/deploy-script-support/src/endo-pieces-contract.js b/packages/deploy-script-support/src/endo-pieces-contract.js index 715000aa415..4d25c5fd3a0 100644 --- a/packages/deploy-script-support/src/endo-pieces-contract.js +++ b/packages/deploy-script-support/src/endo-pieces-contract.js @@ -25,62 +25,70 @@ export const start = () => { /** @type { Map} */ const nameToContent = new Map(); - return Far('Bundler', { - preFilter, - /** - * @param {string} name - * @param {string} encodedContent - * @param {string} hash - */ - add: (name, encodedContent, hash) => { - assert.typeof(name, 'string'); - assert.typeof(encodedContent, 'string'); - assert.typeof(hash, 'string'); - // TODO: verify hash - nameToContent.set(name, [ - hash, - new Uint8Array(decodeBase64(encodedContent)), - ]); - }, - /** - * @param {string} name - * @param {string} hash - */ - addByRef: (name, hash) => { - const entry = hashToEntry.get(hash); - if (!entry) { - throw Fail`hash not found: ${q(hash)}`; - } - const [_n, content] = entry; - nameToContent.set(name, [hash, content]); - }, - persist: () => { - for (const [name, [hash, content]] of nameToContent.entries()) { - hashToEntry.set(hash, [name, content]); - } - }, - /** @param {{ moduleFormat: string}} bundleShell */ - install: bundleShell => { - const writer = new ZipWriter(); - for (const [name, [_hash, content]] of nameToContent.entries()) { - writer.write(name, content); - } - const endoZipBase64 = encodeBase64(writer.snapshot()); - const bundle = { ...bundleShell, endoZipBase64 }; - return E(zoe) - .install(bundle) - .finally(() => nameToContent.clear()); + return makeExo( + 'Bundler', + M.interface('Bundler', {}, { defaultGuards: 'passable' }), + { + preFilter, + /** + * @param {string} name + * @param {string} encodedContent + * @param {string} hash + */ + add: (name, encodedContent, hash) => { + assert.typeof(name, 'string'); + assert.typeof(encodedContent, 'string'); + assert.typeof(hash, 'string'); + // TODO: verify hash + nameToContent.set(name, [ + hash, + new Uint8Array(decodeBase64(encodedContent)), + ]); + }, + /** + * @param {string} name + * @param {string} hash + */ + addByRef: (name, hash) => { + const entry = hashToEntry.get(hash); + if (!entry) { + throw Fail`hash not found: ${q(hash)}`; + } + const [_n, content] = entry; + nameToContent.set(name, [hash, content]); + }, + persist: () => { + for (const [name, [hash, content]] of nameToContent.entries()) { + hashToEntry.set(hash, [name, content]); + } + }, + /** @param {{ moduleFormat: string}} bundleShell */ + install: bundleShell => { + const writer = new ZipWriter(); + for (const [name, [_hash, content]] of nameToContent.entries()) { + writer.write(name, content); + } + const endoZipBase64 = encodeBase64(writer.snapshot()); + const bundle = { ...bundleShell, endoZipBase64 }; + return E(zoe) + .install(bundle) + .finally(() => nameToContent.clear()); + }, + clear: () => { + nameToContent.clear(); + }, }, - clear: () => { - nameToContent.clear(); - }, - }); + ); }; - const publicFacet = Far('endoCAS', { - makeBundler, - preFilter, - }); + const publicFacet = makeExo( + 'endoCAS', + M.interface('endoCAS', {}, { defaultGuards: 'passable' }), + { + makeBundler, + preFilter, + }, + ); return harden({ publicFacet }); }; diff --git a/packages/governance/src/closingRule.js b/packages/governance/src/closingRule.js index 7d7252a96bc..23caee278a2 100644 --- a/packages/governance/src/closingRule.js +++ b/packages/governance/src/closingRule.js @@ -10,8 +10,12 @@ export const scheduleClose = (closingRule, closeVoting) => { const { timer, deadline } = closingRule; void E(timer).setWakeup( deadline, - Far('close voting', { - wake: closeVoting, - }), + makeExo( + 'close voting', + M.interface('close voting', {}, { defaultGuards: 'passable' }), + { + wake: closeVoting, + }, + ), ); }; diff --git a/packages/governance/src/contractGovernance/governApi.js b/packages/governance/src/contractGovernance/governApi.js index 3dd00a37405..cf0676edb9e 100644 --- a/packages/governance/src/contractGovernance/governApi.js +++ b/packages/governance/src/contractGovernance/governApi.js @@ -116,10 +116,14 @@ const setupApiGovernance = ( }); }; - return Far('paramGovernor', { - voteOnApiInvocation, - createdQuestion: b => voteCounters.has(b), - }); + return makeExo( + 'paramGovernor', + M.interface('paramGovernor', {}, { defaultGuards: 'passable' }), + { + voteOnApiInvocation, + createdQuestion: b => voteCounters.has(b), + }, + ); }; harden(setupApiGovernance); diff --git a/packages/governance/src/contractGovernance/governFilter.js b/packages/governance/src/contractGovernance/governFilter.js index 9898434e8ce..3cc87164d0b 100644 --- a/packages/governance/src/contractGovernance/governFilter.js +++ b/packages/governance/src/contractGovernance/governFilter.js @@ -94,10 +94,14 @@ const setupFilterGovernance = (timer, getUpdatedPoserFacet, governedCF) => { }); }; - return Far('filterGovernor', { - voteOnFilter, - createdQuestion: b => voteCounters.has(b), - }); + return makeExo( + 'filterGovernor', + M.interface('filterGovernor', {}, { defaultGuards: 'passable' }), + { + voteOnFilter, + createdQuestion: b => voteCounters.has(b), + }, + ); }; harden(setupFilterGovernance); diff --git a/packages/governance/src/contractGovernance/governParam.js b/packages/governance/src/contractGovernance/governParam.js index 3b8623a5cda..093a28b0b1b 100644 --- a/packages/governance/src/contractGovernance/governParam.js +++ b/packages/governance/src/contractGovernance/governParam.js @@ -140,10 +140,14 @@ const setupParamGovernance = ( }; }; - return Far('paramGovernor', { - voteOnParamChanges, - createdQuestion: b => voteCounters.has(b), - }); + return makeExo( + 'paramGovernor', + M.interface('paramGovernor', {}, { defaultGuards: 'passable' }), + { + voteOnParamChanges, + createdQuestion: b => voteCounters.has(b), + }, + ); }; harden(setupParamGovernance); diff --git a/packages/governance/src/contractGovernance/paramManager.js b/packages/governance/src/contractGovernance/paramManager.js index e300f67bfc1..b629003394e 100644 --- a/packages/governance/src/contractGovernance/paramManager.js +++ b/packages/governance/src/contractGovernance/paramManager.js @@ -109,7 +109,7 @@ const makeParamManagerBuilder = (publisherKit, zoe) => { return proposed; }; - const publicMethods = Far(`Parameter ${name}`, { + const publicMethods = makeExo(`Parameter ${name}`, M.interface(`Parameter ${name}`, {}, { defaultGuards: 'passable' }), { getValue: () => current, assertType: assertion, makeDescription: () => ({ type, value: current }), @@ -281,7 +281,7 @@ const makeParamManagerBuilder = (publisherKit, zoe) => { const getVisibleValue = async allegedInvitation => E(E(zoe).getInvitationIssuer()).getAmountOf(allegedInvitation); - const publicMethods = Far(`Parameter ${name}`, { + const publicMethods = makeExo(`Parameter ${name}`, M.interface(`Parameter ${name}`, {}, { defaultGuards: 'passable' }), { getValue: () => currentAmount, getInternalValue: () => currentInvitation, assertType: assertInvitation, @@ -383,29 +383,33 @@ const makeParamManagerBuilder = (publisherKit, zoe) => { // CRUCIAL: Contracts that call buildParamManager should only export the // resulting paramManager to their creatorFacet, where it will be picked up by // contractGovernor. The getParams method can be shared widely. - return Far('param manager', { - getParams, - getSubscription: () => subscriber, - getAmount: name => getTypedParam(ParamTypes.AMOUNT, name), - getBrand: name => getTypedParam(ParamTypes.BRAND, name), - getInstance: name => getTypedParam(ParamTypes.INSTANCE, name), - getInstallation: name => getTypedParam(ParamTypes.INSTALLATION, name), - getInvitationAmount: name => getTypedParam(ParamTypes.INVITATION, name), - getNat: name => getTypedParam(ParamTypes.NAT, name), - getRatio: name => getTypedParam(ParamTypes.RATIO, name), - getRecord: name => getTypedParam(ParamTypes.PASSABLE_RECORD, name), - getString: name => getTypedParam(ParamTypes.STRING, name), - getTimestamp: name => getTypedParam(ParamTypes.TIMESTAMP, name), - getRelativeTime: name => getTypedParam(ParamTypes.RELATIVE_TIME, name), - getUnknown: name => getTypedParam(ParamTypes.UNKNOWN, name), - getVisibleValue, - getInternalParamValue, - // Getters and setters for each param value - ...getters, - updateParams, - // Collection of all getters for passing to read-only contexts - readonly: () => harden(getters), - }); + return makeExo( + 'param manager', + M.interface('param manager', {}, { defaultGuards: 'passable' }), + { + getParams, + getSubscription: () => subscriber, + getAmount: name => getTypedParam(ParamTypes.AMOUNT, name), + getBrand: name => getTypedParam(ParamTypes.BRAND, name), + getInstance: name => getTypedParam(ParamTypes.INSTANCE, name), + getInstallation: name => getTypedParam(ParamTypes.INSTALLATION, name), + getInvitationAmount: name => getTypedParam(ParamTypes.INVITATION, name), + getNat: name => getTypedParam(ParamTypes.NAT, name), + getRatio: name => getTypedParam(ParamTypes.RATIO, name), + getRecord: name => getTypedParam(ParamTypes.PASSABLE_RECORD, name), + getString: name => getTypedParam(ParamTypes.STRING, name), + getTimestamp: name => getTypedParam(ParamTypes.TIMESTAMP, name), + getRelativeTime: name => getTypedParam(ParamTypes.RELATIVE_TIME, name), + getUnknown: name => getTypedParam(ParamTypes.UNKNOWN, name), + getVisibleValue, + getInternalParamValue, + // Getters and setters for each param value + ...getters, + updateParams, + // Collection of all getters for passing to read-only contexts + readonly: () => harden(getters), + }, + ); }; /** @type {ParamManagerBuilder} */ diff --git a/packages/governance/src/contractHelper.js b/packages/governance/src/contractHelper.js index 894f6f041d0..e7218449e44 100644 --- a/packages/governance/src/contractHelper.js +++ b/packages/governance/src/contractHelper.js @@ -89,11 +89,15 @@ const facetHelpers = (zcf, paramManager) => { * @returns {GovernedPublicFacet} */ const augmentPublicFacet = originalPublicFacet => { - return Far('publicFacet', { - ...originalPublicFacet, - ...commonPublicMethods, - ...typedAccessors, - }); + return makeExo( + 'publicFacet', + M.interface('publicFacet', {}, { defaultGuards: 'passable' }), + { + ...originalPublicFacet, + ...commonPublicMethods, + ...typedAccessors, + }, + ); }; /** @@ -103,11 +107,15 @@ const facetHelpers = (zcf, paramManager) => { * @template {{}} OPF */ const augmentVirtualPublicFacet = originalPublicFacet => { - return Far('publicFacet', { - ...originalPublicFacet, - ...commonPublicMethods, - ...objectMap(typedAccessors, ignoreContext), - }); + return makeExo( + 'publicFacet', + M.interface('publicFacet', {}, { defaultGuards: 'passable' }), + { + ...originalPublicFacet, + ...commonPublicMethods, + ...objectMap(typedAccessors, ignoreContext), + }, + ); }; /** @@ -117,21 +125,29 @@ const facetHelpers = (zcf, paramManager) => { * @returns {GovernedCreatorFacet} */ const makeFarGovernorFacet = (limitedCreatorFacet, governedApis = {}) => { - const governorFacet = Far('governorFacet', { - getParamMgrRetriever: () => - Far('paramRetriever', { get: () => paramManager }), - getInvitation: name => paramManager.getInternalParamValue(name), - getLimitedCreatorFacet: () => limitedCreatorFacet, - // The contract provides a facet with the APIs that can be invoked by - // governance - /** @type {() => GovernedApis} */ - getGovernedApis: () => Far('governedAPIs', governedApis), - // The facet returned by getGovernedApis is Far, so we can't see what - // methods it has. There's no clean way to have contracts specify the APIs - // without also separately providing their names. - getGovernedApiNames: () => Object.keys(governedApis), - setOfferFilter: strings => zcf.setOfferFilter(strings), - }); + const governorFacet = makeExo( + 'governorFacet', + M.interface('governorFacet', {}, { defaultGuards: 'passable' }), + { + getParamMgrRetriever: () => + makeExo( + 'paramRetriever', + M.interface('paramRetriever', {}, { defaultGuards: 'passable' }), + { get: () => paramManager }, + ), + getInvitation: name => paramManager.getInternalParamValue(name), + getLimitedCreatorFacet: () => limitedCreatorFacet, + // The contract provides a facet with the APIs that can be invoked by + // governance + /** @type {() => GovernedApis} */ + getGovernedApis: () => Far('governedAPIs', governedApis), + // The facet returned by getGovernedApis is Far, so we can't see what + // methods it has. There's no clean way to have contracts specify the APIs + // without also separately providing their names. + getGovernedApiNames: () => Object.keys(governedApis), + setOfferFilter: strings => zcf.setOfferFilter(strings), + }, + ); // exclusively for contractGovernor, which only reveals limitedCreatorFacet return governorFacet; @@ -159,7 +175,11 @@ const facetHelpers = (zcf, paramManager) => { /** @type {import('@agoric/swingset-liveslots').FunctionsPlusContext>} */ const governorFacet = harden({ getParamMgrRetriever: () => - Far('paramRetriever', { get: () => paramManager }), + makeExo( + 'paramRetriever', + M.interface('paramRetriever', {}, { defaultGuards: 'passable' }), + { get: () => paramManager }, + ), getInvitation: (_context, /** @type {string} */ name) => paramManager.getInternalParamValue(name), getLimitedCreatorFacet: ({ facets }) => facets.limitedCreatorFacet, @@ -198,7 +218,11 @@ const facetHelpers = (zcf, paramManager) => { M.interface('governorFacet', GovernorFacetShape), { getParamMgrRetriever: () => - Far('paramRetriever', { get: () => paramManager }), + makeExo( + 'paramRetriever', + M.interface('paramRetriever', {}, { defaultGuards: 'passable' }), + { get: () => paramManager }, + ), getInvitation: name => paramManager.getInternalParamValue(name), getLimitedCreatorFacet: () => limitedCreatorFacet, // The contract provides a facet with the APIs that can be invoked by diff --git a/packages/governance/src/electorateTools.js b/packages/governance/src/electorateTools.js index ecb8cd2424d..1ef9cb9aa2a 100644 --- a/packages/governance/src/electorateTools.js +++ b/packages/governance/src/electorateTools.js @@ -89,7 +89,7 @@ const getQuestion = (questionHandleP, questionStore) => const getPoserInvitation = (zcf, addQuestion) => { const questionPoserHandler = seat => { seat.exit(); - return Far(`questionPoser`, { addQuestion }); + return makeExo(`questionPoser`, M.interface(`questionPoser`, {}, { defaultGuards: 'passable' }), { addQuestion }); }; return zcf.makeInvitation( questionPoserHandler, diff --git a/packages/governance/src/quorumCounter.js b/packages/governance/src/quorumCounter.js index 762a70bcd83..be854d053b8 100644 --- a/packages/governance/src/quorumCounter.js +++ b/packages/governance/src/quorumCounter.js @@ -11,5 +11,9 @@ export const makeQuorumCounter = quorumThreshold => { return votes >= quorumThreshold; }; /** @type {QuorumCounter} */ - return Far('checker', { check }); + return makeExo( + 'checker', + M.interface('checker', {}, { defaultGuards: 'passable' }), + { check }, + ); }; diff --git a/packages/governance/test/swingsetTests/committeeBinary/bootstrap.js b/packages/governance/test/swingsetTests/committeeBinary/bootstrap.js index dd7d527cf40..b99d632e649 100644 --- a/packages/governance/test/swingsetTests/committeeBinary/bootstrap.js +++ b/packages/governance/test/swingsetTests/committeeBinary/bootstrap.js @@ -263,5 +263,9 @@ const makeBootstrap = (argv, cb, vatPowers) => async (vats, devices) => { export const buildRootObject = (vatPowers, vatParameters) => { const { argv, contractBundles: cb } = vatParameters; - return Far('root', { bootstrap: makeBootstrap(argv, cb, vatPowers) }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { bootstrap: makeBootstrap(argv, cb, vatPowers) }, + ); }; diff --git a/packages/governance/test/swingsetTests/committeeBinary/vat-voter.js b/packages/governance/test/swingsetTests/committeeBinary/vat-voter.js index 652a26156bf..b08c2944735 100644 --- a/packages/governance/test/swingsetTests/committeeBinary/vat-voter.js +++ b/packages/governance/test/swingsetTests/committeeBinary/vat-voter.js @@ -38,71 +38,83 @@ const verify = async (log, issue, electoratePublicFacet, instances) => { * @param {ZoeService} zoe */ const build = async (log, zoe) => { - return Far('voter', { - createVoter: async (name, invitation, choice) => { - /** @type {import('@agoric/zoe/src/zoeService/utils.js').Instance} */ - const electorateInstance = await E(zoe).getInstance(invitation); - const electoratePublicFacet = E(zoe).getPublicFacet(electorateInstance); - const seat = E(zoe).offer(invitation); - const { voter } = E.get(E(seat).getOfferResult()); - void E.when(E(seat).getPayouts(), async () => { - void E.when(E(seat).hasExited(), exited => { - log(`Seat ${name} ${exited ? 'has exited' : 'is open'}`); + return makeExo( + 'voter', + M.interface('voter', {}, { defaultGuards: 'passable' }), + { + createVoter: async (name, invitation, choice) => { + /** @type {import('@agoric/zoe/src/zoeService/utils.js').Instance} */ + const electorateInstance = await E(zoe).getInstance(invitation); + const electoratePublicFacet = E(zoe).getPublicFacet(electorateInstance); + const seat = E(zoe).offer(invitation); + const { voter } = E.get(E(seat).getOfferResult()); + void E.when(E(seat).getPayouts(), async () => { + void E.when(E(seat).hasExited(), exited => { + log(`Seat ${name} ${exited ? 'has exited' : 'is open'}`); + }); }); - }); - const votingObserver = Far('voting observer', { - updateState: details => { - log(`${name} voted for ${q(choice)}`); - return E(voter).castBallotFor(details.questionHandle, [choice]); - }, - }); - const subscriber = E(electoratePublicFacet).getQuestionSubscriber(); - void observeNotifier( - makeNotifierFromSubscriber(subscriber), - votingObserver, - ); + const votingObserver = makeExo( + 'voting observer', + M.interface('voting observer', {}, { defaultGuards: 'passable' }), + { + updateState: details => { + log(`${name} voted for ${q(choice)}`); + return E(voter).castBallotFor(details.questionHandle, [choice]); + }, + }, + ); + const subscriber = E(electoratePublicFacet).getQuestionSubscriber(); + void observeNotifier( + makeNotifierFromSubscriber(subscriber), + votingObserver, + ); - return Far(`Voter ${name}`, { - verifyBallot: (question, instances) => - verify(log, question, electoratePublicFacet, instances), - }); - }, - createMultiVoter: async (name, invitation, choices) => { - const electorateInstance = await E(zoe).getInstance(invitation); - /** @type {Promise} electoratePublicFacet */ - const electoratePublicFacet = E(zoe).getPublicFacet(electorateInstance); - const seat = E(zoe).offer(invitation); - const { voter } = E.get(E(seat).getOfferResult()); + return makeExo(`Voter ${name}`, M.interface(`Voter ${name}`, {}, { defaultGuards: 'passable' }), { + verifyBallot: (question, instances) => + verify(log, question, electoratePublicFacet, instances), + }); + }, + createMultiVoter: async (name, invitation, choices) => { + const electorateInstance = await E(zoe).getInstance(invitation); + /** @type {Promise} electoratePublicFacet */ + const electoratePublicFacet = E(zoe).getPublicFacet(electorateInstance); + const seat = E(zoe).offer(invitation); + const { voter } = E.get(E(seat).getOfferResult()); - const voteMap = new Map(); - for (const [issue, position] of choices) { - voteMap.set(issue.text, position); - } - const votingObserver = Far('voting observer', { - updateState: details => { - const choice = voteMap.get(details.issue.text); - log(`${name} voted on ${q(details.issue)} for ${q(choice)}`); - return E(voter).castBallotFor(details.questionHandle, [choice]); - }, - }); - const subscriber = E(electoratePublicFacet).getQuestionSubscriber(); - void observeNotifier( - makeNotifierFromSubscriber(subscriber), - votingObserver, - ); + const voteMap = new Map(); + for (const [issue, position] of choices) { + voteMap.set(issue.text, position); + } + const votingObserver = makeExo( + 'voting observer', + M.interface('voting observer', {}, { defaultGuards: 'passable' }), + { + updateState: details => { + const choice = voteMap.get(details.issue.text); + log(`${name} voted on ${q(details.issue)} for ${q(choice)}`); + return E(voter).castBallotFor(details.questionHandle, [choice]); + }, + }, + ); + const subscriber = E(electoratePublicFacet).getQuestionSubscriber(); + void observeNotifier( + makeNotifierFromSubscriber(subscriber), + votingObserver, + ); - return Far(`Voter ${name}`, { - verifyBallot: (question, instances) => - verify(log, question, electoratePublicFacet, instances), - }); + return makeExo(`Voter ${name}`, M.interface(`Voter ${name}`, {}, { defaultGuards: 'passable' }), { + verifyBallot: (question, instances) => + verify(log, question, electoratePublicFacet, instances), + }); + }, }, - }); + ); }; /** @type {import('@agoric/swingset-vat/src/kernel/vat-loader/types.js').BuildRootObjectForTestVat} */ export const buildRootObject = vatPowers => - Far('root', { + makeExo('root', M.interface('root', {}, { defaultGuards: 'passable' }), { /** @param {ZoeService} zoe */ build: zoe => build(vatPowers.testLog, zoe), }); diff --git a/packages/governance/test/swingsetTests/contractGovernor/bootstrap.js b/packages/governance/test/swingsetTests/contractGovernor/bootstrap.js index 4d7dae1ae9f..a87d27faccf 100644 --- a/packages/governance/test/swingsetTests/contractGovernor/bootstrap.js +++ b/packages/governance/test/swingsetTests/contractGovernor/bootstrap.js @@ -148,25 +148,29 @@ const watchParams = async (zoe, contractInstanceP, log) => { const subscription = await E(contractPublic).getSubscription(); /** @type {any} */ let prev = await E(contractPublic).getGovernedParams(); - const paramChangeObserver = Far('param observer', { - updateState: ({ current }) => { - const changed = []; - if ( - prev.Electorate.value.value[0].handle !== - current.Electorate.value.value[0].handle - ) { - changed.push('Electorate'); - } - if (prev.MalleableNumber.value !== current.MalleableNumber.value) { - changed.push('MalleableNumber'); - } - log(`params update: `, changed.join(',')); - log( - `current value of MalleableNumber is ${current.MalleableNumber.value}`, - ); - prev = current; + const paramChangeObserver = makeExo( + 'param observer', + M.interface('param observer', {}, { defaultGuards: 'passable' }), + { + updateState: ({ current }) => { + const changed = []; + if ( + prev.Electorate.value.value[0].handle !== + current.Electorate.value.value[0].handle + ) { + changed.push('Electorate'); + } + if (prev.MalleableNumber.value !== current.MalleableNumber.value) { + changed.push('MalleableNumber'); + } + log(`params update: `, changed.join(',')); + log( + `current value of MalleableNumber is ${current.MalleableNumber.value}`, + ); + prev = current; + }, }, - }); + ); void observeIteration(subscribeEach(subscription), paramChangeObserver); }; @@ -551,5 +555,9 @@ const makeBootstrap = (argv, cb, vatPowers) => async (vats, devices) => { export const buildRootObject = (vatPowers, vatParameters) => { const { argv, contractBundles: cb } = vatParameters; - return Far('root', { bootstrap: makeBootstrap(argv, cb, vatPowers) }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { bootstrap: makeBootstrap(argv, cb, vatPowers) }, + ); }; diff --git a/packages/governance/test/swingsetTests/contractGovernor/vat-voter.js b/packages/governance/test/swingsetTests/contractGovernor/vat-voter.js index a165f474cf8..207335605a4 100644 --- a/packages/governance/test/swingsetTests/contractGovernor/vat-voter.js +++ b/packages/governance/test/swingsetTests/contractGovernor/vat-voter.js @@ -13,96 +13,100 @@ import { MALLEABLE_NUMBER } from './governedContract.js'; const { quote: q } = assert; const build = async (log, zoe) => { - return Far('voter', { - createVoter: async (name, invitation) => { - const seat = E(zoe).offer(invitation); - const { voter } = E.get(E(seat).getOfferResult()); + return makeExo( + 'voter', + M.interface('voter', {}, { defaultGuards: 'passable' }), + { + createVoter: async (name, invitation) => { + const seat = E(zoe).offer(invitation); + const { voter } = E.get(E(seat).getOfferResult()); - return Far(`Voter ${name}`, { - castBallotFor: async (questionHandle, choice) => { - log(`Voter ${name} voted for ${q(choice)}`); - return E(voter).castBallotFor(questionHandle, [choice]); - }, - /** - * - * @param {Instance} counterInstance - * @param {Instance} governedInstance - * @param {Instance} electorateInstance - * @param {Instance} governorInstance - * @param {Record} installations - * @returns {Promise} - */ - validate: async ( - counterInstance, - governedInstance, - electorateInstance, - governorInstance, - installations, - ) => { - const validateQuestionFromCounterP = validateQuestionFromCounter( - zoe, - electorateInstance, + return makeExo(`Voter ${name}`, M.interface(`Voter ${name}`, {}, { defaultGuards: 'passable' }), { + castBallotFor: async (questionHandle, choice) => { + log(`Voter ${name} voted for ${q(choice)}`); + return E(voter).castBallotFor(questionHandle, [choice]); + }, + /** + * + * @param {Instance} counterInstance + * @param {Instance} governedInstance + * @param {Instance} electorateInstance + * @param {Instance} governorInstance + * @param {Record} installations + * @returns {Promise} + */ + validate: async ( counterInstance, - ); - - const contractGovernanceP = assertContractGovernance( - zoe, governedInstance, + electorateInstance, governorInstance, - installations.contractGovernor, - ); + installations, + ) => { + const validateQuestionFromCounterP = validateQuestionFromCounter( + zoe, + electorateInstance, + counterInstance, + ); - const [ - questionDetails, - electorateInstallation, - voteCounterInstallation, - governedInstallation, - governorInstallation, - validatedQuestion, - contractGovernance, - ] = await Promise.all([ - E(E(zoe).getPublicFacet(counterInstance)).getDetails(), - E(zoe).getInstallationForInstance(electorateInstance), - E(zoe).getInstallationForInstance(counterInstance), - E(zoe).getInstallationForInstance(governedInstance), - E(zoe).getInstallationForInstance(governorInstance), - validateQuestionFromCounterP, - contractGovernanceP, - ]); + const contractGovernanceP = assertContractGovernance( + zoe, + governedInstance, + governorInstance, + installations.contractGovernor, + ); - assertBallotConcernsParam( - harden({ - paramPath: { key: 'governedParams' }, - parameterName: MALLEABLE_NUMBER, - }), - questionDetails, - ); - assert(installations.binaryVoteCounter === voteCounterInstallation); - assert(installations.governedContract === governedInstallation); - assert(installations.contractGovernor === governorInstallation); - assert(installations.committee === electorateInstallation); - await assertContractElectorate( - zoe, - governorInstance, - electorateInstance, - ); + const [ + questionDetails, + electorateInstallation, + voteCounterInstallation, + governedInstallation, + governorInstallation, + validatedQuestion, + contractGovernance, + ] = await Promise.all([ + E(E(zoe).getPublicFacet(counterInstance)).getDetails(), + E(zoe).getInstallationForInstance(electorateInstance), + E(zoe).getInstallationForInstance(counterInstance), + E(zoe).getInstallationForInstance(governedInstance), + E(zoe).getInstallationForInstance(governorInstance), + validateQuestionFromCounterP, + contractGovernanceP, + ]); - await validateQuestionDetails( - zoe, - electorateInstance, - questionDetails, - ); - assert(validatedQuestion, 'governor failed to validate electorate'); - assert( - contractGovernance, - "governor and governed aren't tightly linked", - ); + assertBallotConcernsParam( + harden({ + paramPath: { key: 'governedParams' }, + parameterName: MALLEABLE_NUMBER, + }), + questionDetails, + ); + assert(installations.binaryVoteCounter === voteCounterInstallation); + assert(installations.governedContract === governedInstallation); + assert(installations.contractGovernor === governorInstallation); + assert(installations.committee === electorateInstallation); + await assertContractElectorate( + zoe, + governorInstance, + electorateInstance, + ); - log(`Voter ${name} validated all the things`); - }, - }); + await validateQuestionDetails( + zoe, + electorateInstance, + questionDetails, + ); + assert(validatedQuestion, 'governor failed to validate electorate'); + assert( + contractGovernance, + "governor and governed aren't tightly linked", + ); + + log(`Voter ${name} validated all the things`); + }, + }); + }, }, - }); + ); }; /** @@ -111,6 +115,6 @@ const build = async (log, zoe) => { /** @type {import('@agoric/swingset-vat/src/kernel/vat-loader/types.js').BuildRootObjectForTestVat} */ export const buildRootObject = vatPowers => - Far('root', { + makeExo('root', M.interface('root', {}, { defaultGuards: 'passable' }), { build: (...args) => build(vatPowers.testLog, ...args), }); diff --git a/packages/governance/test/unitTests/test-binaryballotCount.js b/packages/governance/test/unitTests/test-binaryballotCount.js index 7e8197e1721..5671c212d80 100644 --- a/packages/governance/test/unitTests/test-binaryballotCount.js +++ b/packages/governance/test/unitTests/test-binaryballotCount.js @@ -32,7 +32,11 @@ const PARAM_ISSUE = harden({ paramPath: { key: 'something' }, changes: { arbitrary: 37 }, }, - contract: Far('contract', {}), + contract: makeExo( + 'contract', + M.interface('contract', {}, { defaultGuards: 'passable' }), + {}, + ), }); const { positive, negative } = makeParamChangePositions({ Arbitrary: 37 }); const PARAM_CHANGE_ISSUE = harden({ diff --git a/packages/governance/test/unitTests/test-buildParamManager.js b/packages/governance/test/unitTests/test-buildParamManager.js index 3585026d361..e94cdfbbeb7 100644 --- a/packages/governance/test/unitTests/test-buildParamManager.js +++ b/packages/governance/test/unitTests/test-buildParamManager.js @@ -114,9 +114,13 @@ test('params one installation', async t => { // isInstallation() (#3344), we'll need to make a mockZoe. /** @type {Installation} */ // @ts-expect-error cast - const installationHandle = Far('fake Installation', { - getBundle: () => ({ obfuscated: 42 }), - }); + const installationHandle = makeExo( + 'fake Installation', + M.interface('fake Installation', {}, { defaultGuards: 'passable' }), + { + getBundle: () => ({ obfuscated: 42 }), + }, + ); const paramManager = makeParamManagerBuilder(makeStoredPublisherKit()) .addInstallation('PName', installationHandle) @@ -132,9 +136,13 @@ test('params one installation', async t => { ); /** @type {Installation} */ // @ts-expect-error cast - const handle2 = Far('another fake Installation', { - getBundle: () => ({ condensed: '() => {})' }), - }); + const handle2 = makeExo( + 'another fake Installation', + M.interface('another fake Installation', {}, { defaultGuards: 'passable' }), + { + getBundle: () => ({ condensed: '() => {})' }), + }, + ); await paramManager.updateParams({ PName: handle2 }); t.deepEqual(paramManager.getInstallation('PName'), handle2); diff --git a/packages/governance/test/unitTests/test-typedParamManager.js b/packages/governance/test/unitTests/test-typedParamManager.js index 505d826acfa..d8bef8b8677 100644 --- a/packages/governance/test/unitTests/test-typedParamManager.js +++ b/packages/governance/test/unitTests/test-typedParamManager.js @@ -145,9 +145,13 @@ test('params one installation', async t => { /** @type {Installation} */ // @ts-expect-error mock - const installationHandle = Far('fake Installation', { - getBundle: () => ({ obfuscated: 42 }), - }); + const installationHandle = makeExo( + 'fake Installation', + M.interface('fake Installation', {}, { defaultGuards: 'passable' }), + { + getBundle: () => ({ obfuscated: 42 }), + }, + ); const paramManager = await makeParamManager( makeStoredPublisherKit(), @@ -167,9 +171,13 @@ test('params one installation', async t => { ); /** @type {Installation} */ // @ts-expect-error mock - const handle2 = Far('another fake Installation', { - getBundle: () => ({ condensed: '() => {})' }), - }); + const handle2 = makeExo( + 'another fake Installation', + M.interface('another fake Installation', {}, { defaultGuards: 'passable' }), + { + getBundle: () => ({ condensed: '() => {})' }), + }, + ); await paramManager.updateParams({ PName: handle2 }); t.deepEqual(paramManager.getPName(), handle2); diff --git a/packages/governance/tools/puppetContractGovernor.js b/packages/governance/tools/puppetContractGovernor.js index 8e92a86cb89..9253e63e40c 100644 --- a/packages/governance/tools/puppetContractGovernor.js +++ b/packages/governance/tools/puppetContractGovernor.js @@ -86,20 +86,28 @@ export const start = async (zcf, privateArgs) => { .then(() => positive); }; - const creatorFacet = Far('governor creatorFacet', { - changeParams, - invokeAPI, - setFilters, - getCreatorFacet: () => limitedCreatorFacet, - getAdminFacet: () => adminFacet, - getInstance: () => governedInstance, - /** @returns {Awaited>['publicFacet']} */ - getPublicFacet: () => governedPF, - }); - - const publicFacet = Far('contract governor public', { - getGovernedContract: () => governedInstance, - }); + const creatorFacet = makeExo( + 'governor creatorFacet', + M.interface('governor creatorFacet', {}, { defaultGuards: 'passable' }), + { + changeParams, + invokeAPI, + setFilters, + getCreatorFacet: () => limitedCreatorFacet, + getAdminFacet: () => adminFacet, + getInstance: () => governedInstance, + /** @returns {Awaited>['publicFacet']} */ + getPublicFacet: () => governedPF, + }, + ); + + const publicFacet = makeExo( + 'contract governor public', + M.interface('contract governor public', {}, { defaultGuards: 'passable' }), + { + getGovernedContract: () => governedInstance, + }, + ); return { creatorFacet, publicFacet }; }; diff --git a/packages/inter-protocol/src/auction/auctioneer.js b/packages/inter-protocol/src/auction/auctioneer.js index c894964159f..af699dafc1a 100644 --- a/packages/inter-protocol/src/auction/auctioneer.js +++ b/packages/inter-protocol/src/auction/auctioneer.js @@ -546,44 +546,48 @@ export const start = async (zcf, privateArgs, baggage) => { } }; - const driver = Far('Auctioneer', { - reducePriceAndTrade: () => { - trace('reducePriceAndTrade'); + const driver = makeExo( + 'Auctioneer', + M.interface('Auctioneer', {}, { defaultGuards: 'passable' }), + { + reducePriceAndTrade: () => { + trace('reducePriceAndTrade'); - natSafeMath.isGTE(currentDiscountRateBP, params.getDiscountStep()) || - Fail`rates must fall ${currentDiscountRateBP}`; + natSafeMath.isGTE(currentDiscountRateBP, params.getDiscountStep()) || + Fail`rates must fall ${currentDiscountRateBP}`; - currentDiscountRateBP = natSafeMath.subtract( - currentDiscountRateBP, - params.getDiscountStep(), - ); + currentDiscountRateBP = natSafeMath.subtract( + currentDiscountRateBP, + params.getDiscountStep(), + ); - tradeEveryBook(); - }, - finalize: () => { - trace('finalize'); + tradeEveryBook(); + }, + finalize: () => { + trace('finalize'); - for (const book of books.values()) { - book.endAuction(); - } - distributeProceeds(); - }, - startRound() { - trace('startRound'); + for (const book of books.values()) { + book.endAuction(); + } + distributeProceeds(); + }, + startRound() { + trace('startRound'); - currentDiscountRateBP = params.getStartingRate(); - for (const book of books.values()) { - book.setStartingRate(makeBPRatio(currentDiscountRateBP, brands.Bid)); - } + currentDiscountRateBP = params.getStartingRate(); + for (const book of books.values()) { + book.setStartingRate(makeBPRatio(currentDiscountRateBP, brands.Bid)); + } - tradeEveryBook(); - }, - capturePrices() { - for (const book of books.values()) { - book.captureOraclePriceForRound(); - } + tradeEveryBook(); + }, + capturePrices() { + for (const book of books.values()) { + book.captureOraclePriceForRound(); + } + }, }, - }); + ); // eslint-disable-next-line no-use-before-define const isActive = () => scheduler.getAuctionState() === AuctionState.ACTIVE; @@ -688,38 +692,42 @@ export const start = async (zcf, privateArgs, baggage) => { ); const creatorFacet = makeFarGovernorFacet( - Far('Auctioneer creatorFacet', { - /** - * @param {Issuer} issuer - * @param {Keyword} kwd - */ - async addBrand(issuer, kwd) { - zcf.assertUniqueKeyword(kwd); - !baggage.has(kwd) || - Fail`cannot add brand with keyword ${kwd}. it's in use`; - const { brand } = await zcf.saveIssuer(issuer, kwd); - - const bookId = `book${bookCounter}`; - bookCounter += 1; - const bNode = await E(privateArgs.storageNode).makeChildNode(bookId); - - const newBook = await makeAuctionBook( - brands.Bid, - brand, - priceAuthority, - bNode, - ); - - // These three store.init() calls succeed or fail atomically - deposits.init(brand, harden([])); - books.init(brand, newBook); - brandToKeyword.init(brand, kwd); - }, - /** @returns {Promise} */ - getSchedule() { - return E(scheduler).getSchedule(); + makeExo( + 'Auctioneer creatorFacet', + M.interface('Auctioneer creatorFacet', {}, { defaultGuards: 'passable' }), + { + /** + * @param {Issuer} issuer + * @param {Keyword} kwd + */ + async addBrand(issuer, kwd) { + zcf.assertUniqueKeyword(kwd); + !baggage.has(kwd) || + Fail`cannot add brand with keyword ${kwd}. it's in use`; + const { brand } = await zcf.saveIssuer(issuer, kwd); + + const bookId = `book${bookCounter}`; + bookCounter += 1; + const bNode = await E(privateArgs.storageNode).makeChildNode(bookId); + + const newBook = await makeAuctionBook( + brands.Bid, + brand, + priceAuthority, + bNode, + ); + + // These three store.init() calls succeed or fail atomically + deposits.init(brand, harden([])); + books.init(brand, newBook); + brandToKeyword.init(brand, kwd); + }, + /** @returns {Promise} */ + getSchedule() { + return E(scheduler).getSchedule(); + }, }, - }), + ), ); return { publicFacet, creatorFacet }; diff --git a/packages/inter-protocol/src/auction/scheduler.js b/packages/inter-protocol/src/auction/scheduler.js index e78d8645a97..ef76aba2c64 100644 --- a/packages/inter-protocol/src/auction/scheduler.js +++ b/packages/inter-protocol/src/auction/scheduler.js @@ -220,17 +220,21 @@ export const makeScheduler = async ( void E(timer).repeatAfter( delayFromNow, liveSchedule.clockStep, - Far('PriceStepWaker', { - wake(time) { - try { - setTimeMonotonically(time); - trace('wake step', now); - clockTick(liveSchedule); - } catch (e) { - console.error(`⚠️ Auction threw ${e}. Caught in PriceStepWaker.`); - } + makeExo( + 'PriceStepWaker', + M.interface('PriceStepWaker', {}, { defaultGuards: 'passable' }), + { + wake(time) { + try { + setTimeMonotonically(time); + trace('wake step', now); + clockTick(liveSchedule); + } catch (e) { + console.error(`⚠️ Auction threw ${e}. Caught in PriceStepWaker.`); + } + }, }, - }), + ), stepCancelToken, ); }; @@ -240,18 +244,22 @@ export const makeScheduler = async ( trace(`nextRound`, start); void E(timer).setWakeup( start, - Far('SchedulerWaker', { - wake(time) { - try { - setTimeMonotonically(time); - auctionDriver.capturePrices(); - // eslint-disable-next-line no-use-before-define - return startAuction(); - } catch (e) { - console.error(`⚠️ Auction threw ${e}. Caught in SchedulerWaker.`); - } + makeExo( + 'SchedulerWaker', + M.interface('SchedulerWaker', {}, { defaultGuards: 'passable' }), + { + wake(time) { + try { + setTimeMonotonically(time); + auctionDriver.capturePrices(); + // eslint-disable-next-line no-use-before-define + return startAuction(); + } catch (e) { + console.error(`⚠️ Auction threw ${e}. Caught in SchedulerWaker.`); + } + }, }, - }), + ), ); void publishSchedule(); }; @@ -350,14 +358,18 @@ export const makeScheduler = async ( }), ); - return Far('scheduler', { - getSchedule: () => - harden({ - liveAuctionSchedule: liveSchedule, - nextAuctionSchedule: nextSchedule, - }), - getAuctionState: () => auctionState, - }); + return makeExo( + 'scheduler', + M.interface('scheduler', {}, { defaultGuards: 'passable' }), + { + getSchedule: () => + harden({ + liveAuctionSchedule: liveSchedule, + nextAuctionSchedule: nextSchedule, + }), + getAuctionState: () => auctionState, + }, + ); }; /** diff --git a/packages/inter-protocol/src/auction/util.js b/packages/inter-protocol/src/auction/util.js index 2a844c6ea82..5a3a0e3c682 100644 --- a/packages/inter-protocol/src/auction/util.js +++ b/packages/inter-protocol/src/auction/util.js @@ -51,5 +51,5 @@ export const priceFrom = quote => export const makeCancelTokenMaker = name => { let tokenCount = 1; - return () => Far(`cancelToken-${name}-${(tokenCount += 1)}`, {}); + return () => makeExo(`cancelToken-${name}-${(tokenCount += 1)}`, M.interface(`cancelToken-${name}-${(tokenCount += 1)}`, {}, { defaultGuards: 'passable' }), {}); }; diff --git a/packages/inter-protocol/src/feeDistributor.js b/packages/inter-protocol/src/feeDistributor.js index ddffa8bb322..b297befff3f 100644 --- a/packages/inter-protocol/src/feeDistributor.js +++ b/packages/inter-protocol/src/feeDistributor.js @@ -51,13 +51,17 @@ harden(meta); */ export const makeContractFeeCollector = (zoe, creatorFacet) => { /** @type {FeeCollector} */ - return Far('feeCollector', { - collectFees: () => { - const invitation = E(creatorFacet).makeCollectFeesInvitation(); - const collectFeesSeat = E(zoe).offer(invitation, undefined, undefined); - return E(collectFeesSeat).getPayout('Fee'); + return makeExo( + 'feeCollector', + M.interface('feeCollector', {}, { defaultGuards: 'passable' }), + { + collectFees: () => { + const invitation = E(creatorFacet).makeCollectFeesInvitation(); + const collectFeesSeat = E(zoe).offer(invitation, undefined, undefined); + return E(collectFeesSeat).getPayout('Fee'); + }, }, - }); + ); }; /** @@ -228,112 +232,136 @@ export const makeFeeDistributor = (feeIssuer, terms) => { ); }; - const publicFacet = Far('feeDistributor publicFacet', { - distributeFees, - getKeywordShares: () => keywordShares, - }); - - const creatorFacet = Far('feeDistributor creatorFacet', { - makeContractFeeCollector, - /** - * Start distributing fees from this collector. - * - * @param {string} debugName - * @param {ERef} collectorP - */ - startPeriodicCollection: async (debugName, collectorP) => { - const collector = await collectorP; - - /** @type {PeriodicFeeCollector} */ - const periodicCollector = Far('PeriodicFeeCollector', { - getDebugName: () => debugName, - getCollector: () => collector, - collectAndDistributeNow: async () => { - if (shareConfig.totalShares <= 0n) { - return; - } - const payment = await E(collector).collectFees(); - await distributeFees(payment); - }, - stop: () => { - collectors.delete(collector); - }, - }); - - // Run once immediately for this collector, to test that the registration - // will work. - await E(periodicCollector).collectAndDistributeNow(); - - collectors.add(collector); - return periodicCollector; + const publicFacet = makeExo( + 'feeDistributor publicFacet', + M.interface( + 'feeDistributor publicFacet', + {}, + { defaultGuards: 'passable' }, + ), + { + distributeFees, + getKeywordShares: () => keywordShares, }, + ); - /** @param {import('@endo/far').EOnly} depositFacet */ - makeDepositFacetDestination: depositFacet => { - return Far(`DepositFacetDestination`, { - pushPayment: async (payment, _issuer) => { - return E(depositFacet).receive(payment); - }, - }); - }, - /** - * Create a destination that generates invitations and makes Zoe offers. - * - * @param {ERef} zoe - * @param {string} keyword - * @param {unknown} target - * @param {PropertyKey} makeInvitationMethod - * @param {unknown[]} [args] - */ - makeOfferDestination: ( - zoe, - keyword, - target, - makeInvitationMethod, - args = [], - ) => { - return Far(`${String(makeInvitationMethod)} OfferDestination`, { - pushPayment: async (payment, issuer) => { - const paymentAmount = await E(issuer).getAmountOf(payment); - - // Give the payment to the contract via its invitation. - const invitation = E(target)[makeInvitationMethod](...args); - const result = E(zoe).offer( - invitation, - { - give: { - [keyword]: paymentAmount, - }, + const creatorFacet = makeExo( + 'feeDistributor creatorFacet', + M.interface( + 'feeDistributor creatorFacet', + {}, + { defaultGuards: 'passable' }, + ), + { + makeContractFeeCollector, + /** + * Start distributing fees from this collector. + * + * @param {string} debugName + * @param {ERef} collectorP + */ + startPeriodicCollection: async (debugName, collectorP) => { + const collector = await collectorP; + + /** @type {PeriodicFeeCollector} */ + const periodicCollector = makeExo( + 'PeriodicFeeCollector', + M.interface( + 'PeriodicFeeCollector', + {}, + { defaultGuards: 'passable' }, + ), + { + getDebugName: () => debugName, + getCollector: () => collector, + collectAndDistributeNow: async () => { + if (shareConfig.totalShares <= 0n) { + return; + } + const payment = await E(collector).collectFees(); + await distributeFees(payment); }, - { - [keyword]: payment, + stop: () => { + collectors.delete(collector); }, - ); - - // Assert that the offer completed. - await E(result).getOfferResult(); - - // We deliberately drop our payouts on the floor, since the ERTP purse - // recovery mechanism can get them back to the distributor contract. - return paymentAmount; - }, - }); - }, - - /** @param {Record>} newDestinations */ - setDestinations: async newDestinations => { - destinations = newDestinations; - shareConfig = makeShareConfig(destinations, keywordShares); - // Run once immediately for these destinations. - await schedulePayments(); - }, - - /** @param {Record} newShares */ - setKeywordShares: newShares => { - mustMatch(newShares, KeywordSharesShape); - keywordShares = newShares; + }, + ); + + // Run once immediately for this collector, to test that the registration + // will work. + await E(periodicCollector).collectAndDistributeNow(); + + collectors.add(collector); + return periodicCollector; + }, + + /** @param {import('@endo/far').EOnly} depositFacet */ + makeDepositFacetDestination: depositFacet => { + return makeExo(`DepositFacetDestination`, M.interface(`DepositFacetDestination`, {}, { defaultGuards: 'passable' }), { + pushPayment: async (payment, _issuer) => { + return E(depositFacet).receive(payment); + }, + }); + }, + /** + * Create a destination that generates invitations and makes Zoe offers. + * + * @param {ERef} zoe + * @param {string} keyword + * @param {unknown} target + * @param {PropertyKey} makeInvitationMethod + * @param {unknown[]} [args] + */ + makeOfferDestination: ( + zoe, + keyword, + target, + makeInvitationMethod, + args = [], + ) => { + return makeExo(`${String(makeInvitationMethod)} OfferDestination`, M.interface(`${String(makeInvitationMethod)} OfferDestination`, {}, { defaultGuards: 'passable' }), { + pushPayment: async (payment, issuer) => { + const paymentAmount = await E(issuer).getAmountOf(payment); + + // Give the payment to the contract via its invitation. + const invitation = E(target)[makeInvitationMethod](...args); + const result = E(zoe).offer( + invitation, + { + give: { + [keyword]: paymentAmount, + }, + }, + { + [keyword]: payment, + }, + ); + + // Assert that the offer completed. + await E(result).getOfferResult(); + + // We deliberately drop our payouts on the floor, since the ERTP purse + // recovery mechanism can get them back to the distributor contract. + return paymentAmount; + }, + }); + }, + + /** @param {Record>} newDestinations */ + setDestinations: async newDestinations => { + destinations = newDestinations; + shareConfig = makeShareConfig(destinations, keywordShares); + // Run once immediately for these destinations. + await schedulePayments(); + }, + + /** @param {Record} newShares */ + setKeywordShares: newShares => { + mustMatch(newShares, KeywordSharesShape); + keywordShares = newShares; + }, }, - }); + ); // Start processing collections. startDistributing(schedulePayments, timerService, collectionInterval); diff --git a/packages/inter-protocol/src/price/fluxAggregatorKit.js b/packages/inter-protocol/src/price/fluxAggregatorKit.js index 39601167799..be81fd52cc0 100644 --- a/packages/inter-protocol/src/price/fluxAggregatorKit.js +++ b/packages/inter-protocol/src/price/fluxAggregatorKit.js @@ -257,19 +257,27 @@ export const prepareFluxAggregatorKit = async ( const offerHandler = async seat => { seat.exit(); const { oracle } = await facets.creator.initOracle(oracleId); - const invitationMakers = Far('invitation makers', { - /** @param {import('./roundsManager.js').PriceRound} result */ - PushPrice(result) { - return zcf.makeInvitation( - /** @param {ZCFSeat} cSeat */ - async cSeat => { - cSeat.exit(); - await oracle.pushPrice(result); - }, - 'PushPrice', - ); + const invitationMakers = makeExo( + 'invitation makers', + M.interface( + 'invitation makers', + {}, + { defaultGuards: 'passable' }, + ), + { + /** @param {import('./roundsManager.js').PriceRound} result */ + PushPrice(result) { + return zcf.makeInvitation( + /** @param {ZCFSeat} cSeat */ + async cSeat => { + cSeat.exit(); + await oracle.pushPrice(result); + }, + 'PushPrice', + ); + }, }, - }); + ); return harden({ invitationMakers, diff --git a/packages/inter-protocol/src/proposals/addAssetToVault.js b/packages/inter-protocol/src/proposals/addAssetToVault.js index c448b76632b..69968afbffd 100644 --- a/packages/inter-protocol/src/proposals/addAssetToVault.js +++ b/packages/inter-protocol/src/proposals/addAssetToVault.js @@ -259,7 +259,11 @@ const whenQuiescent = async (schedules, timer, thunk) => { const { nextAuctionSchedule, liveAuctionSchedule } = schedules; const now = await E(timer).getCurrentTimestamp(); - const waker = Far('addAssetWaker', { wake: () => thunk() }); + const waker = makeExo( + 'addAssetWaker', + M.interface('addAssetWaker', {}, { defaultGuards: 'passable' }), + { wake: () => thunk() }, + ); if (liveAuctionSchedule) { const safeStart = TimeMath.subtractAbsRel( diff --git a/packages/inter-protocol/src/provisionPoolKit.js b/packages/inter-protocol/src/provisionPoolKit.js index d5626a522f0..30a4e8fbdae 100644 --- a/packages/inter-protocol/src/provisionPoolKit.js +++ b/packages/inter-protocol/src/provisionPoolKit.js @@ -64,30 +64,34 @@ export const makeBridgeProvisionTool = (sendInitialPayment, onProvisioned) => { namesByAddressAdmin, walletFactory, }) => - Far('provisioningHandler', { - fromBridge: async obj => { - obj.type === 'PLEASE_PROVISION' || - Fail`Unrecognized request ${obj.type}`; - console.info('PLEASE_PROVISION', obj); - const { address, powerFlags } = obj; - powerFlags.includes(PowerFlags.SMART_WALLET) || - Fail`missing SMART_WALLET in powerFlags`; + makeExo( + 'provisioningHandler', + M.interface('provisioningHandler', {}, { defaultGuards: 'passable' }), + { + fromBridge: async obj => { + obj.type === 'PLEASE_PROVISION' || + Fail`Unrecognized request ${obj.type}`; + console.info('PLEASE_PROVISION', obj); + const { address, powerFlags } = obj; + powerFlags.includes(PowerFlags.SMART_WALLET) || + Fail`missing SMART_WALLET in powerFlags`; - const bank = E(bankManager).getBankForAddress(address); - // only proceed if we can provide funds - await sendInitialPayment(bank); + const bank = E(bankManager).getBankForAddress(address); + // only proceed if we can provide funds + await sendInitialPayment(bank); - const [_, created] = await E(walletFactory).provideSmartWallet( - address, - bank, - namesByAddressAdmin, - ); - if (created) { - onProvisioned(); - } - console.info(created ? 'provisioned' : 're-provisioned', address); + const [_, created] = await E(walletFactory).provideSmartWallet( + address, + bank, + namesByAddressAdmin, + ); + if (created) { + onProvisioned(); + } + console.info(created ? 'provisioned' : 're-provisioned', address); + }, }, - }); + ); return makeBridgeHandler; }; diff --git a/packages/inter-protocol/src/vaultFactory/prioritizedVaults.js b/packages/inter-protocol/src/vaultFactory/prioritizedVaults.js index 9e56855ba91..379645580a4 100644 --- a/packages/inter-protocol/src/vaultFactory/prioritizedVaults.js +++ b/packages/inter-protocol/src/vaultFactory/prioritizedVaults.js @@ -135,17 +135,21 @@ export const makePrioritizedVaults = store => { return vaultsRemoved; }; - return Far('PrioritizedVaults', { - addVault, - entries: vaults.entries, - getCount: vaults.getSize, - hasVaultByAttributes, - highestRatio, - removeVault, - removeVaultByAttributes, - removeVaultsBelow, - - // visible for testing - countVaultsBelow: crKey => vaults.getSize(M.lte(crKey)), - }); + return makeExo( + 'PrioritizedVaults', + M.interface('PrioritizedVaults', {}, { defaultGuards: 'passable' }), + { + addVault, + entries: vaults.entries, + getCount: vaults.getSize, + hasVaultByAttributes, + highestRatio, + removeVault, + removeVaultByAttributes, + removeVaultsBelow, + + // visible for testing + countVaultsBelow: crKey => vaults.getSize(M.lte(crKey)), + }, + ); }; diff --git a/packages/inter-protocol/src/vaultFactory/vaultDirector.js b/packages/inter-protocol/src/vaultFactory/vaultDirector.js index 1d3d0aeac30..8244d689f9a 100644 --- a/packages/inter-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/inter-protocol/src/vaultFactory/vaultDirector.js @@ -164,70 +164,82 @@ const prepareVaultDirector = ( } }; - const factoryPowers = Far('vault factory powers', { - /** - * Get read-only params for this manager and its director. This grants all - * managers access to params from all managers. It's not POLA but it's a - * public authority and it reduces the number of distinct power objects to - * create. - * - * @param {Brand} brand - */ - getGovernedParams: brand => { - const vaultParamManager = vaultParamManagers.get(brand); - return Far('vault manager param manager', { - // merge director and manager params - ...directorParamManager.readonly(), - ...vaultParamManager.readonly(), - // redeclare these getters as to specify the kind of the Amount - getMinInitialDebt: /** @type {() => Amount<'nat'>} */ ( - directorParamManager.readonly().getMinInitialDebt - ), - getDebtLimit: /** @type {() => Amount<'nat'>} */ ( - vaultParamManager.readonly().getDebtLimit - ), - }); - }, + const factoryPowers = makeExo( + 'vault factory powers', + M.interface('vault factory powers', {}, { defaultGuards: 'passable' }), + { + /** + * Get read-only params for this manager and its director. This grants all + * managers access to params from all managers. It's not POLA but it's a + * public authority and it reduces the number of distinct power objects to + * create. + * + * @param {Brand} brand + */ + getGovernedParams: brand => { + const vaultParamManager = vaultParamManagers.get(brand); + return makeExo( + 'vault manager param manager', + M.interface( + 'vault manager param manager', + {}, + { defaultGuards: 'passable' }, + ), + { + // merge director and manager params + ...directorParamManager.readonly(), + ...vaultParamManager.readonly(), + // redeclare these getters as to specify the kind of the Amount + getMinInitialDebt: /** @type {() => Amount<'nat'>} */ ( + directorParamManager.readonly().getMinInitialDebt + ), + getDebtLimit: /** @type {() => Amount<'nat'>} */ ( + vaultParamManager.readonly().getDebtLimit + ), + }, + ); + }, - /** - * Let the manager add rewards to the rewardPoolSeat without exposing the - * rewardPoolSeat to them. - * - * @type {MintAndTransfer} - */ - mintAndTransfer: (mintReceiver, toMint, fee, nonMintTransfers) => { - const kept = AmountMath.subtract(toMint, fee); - debtMint.mintGains(harden({ Minted: toMint }), mintSeat); - /** @type {TransferPart[]} */ - const transfers = [ - ...nonMintTransfers, - [mintSeat, rewardPoolSeat, { Minted: fee }], - [mintSeat, mintReceiver, { Minted: kept }], - ]; - try { - atomicRearrange(zcf, harden(transfers)); - } catch (e) { - console.error('mintAndTransfer failed to rearrange', e); - // If the rearrange fails, burn the newly minted tokens. - // Assume this won't fail because it relies on the internal mint. - // (Failure would imply much larger problems.) - debtMint.burnLosses(harden({ Minted: toMint }), mintSeat); - throw e; - } - void writeMetrics(); - }, - getShortfallReporter: async () => { - await updateShortfallReporter(); - return shortfallReporter; - }, - /** - * @param {Amount<'nat'>} toBurn - * @param {ZCFSeat} seat - */ - burnDebt: (toBurn, seat) => { - debtMint.burnLosses(harden({ Minted: toBurn }), seat); + /** + * Let the manager add rewards to the rewardPoolSeat without exposing the + * rewardPoolSeat to them. + * + * @type {MintAndTransfer} + */ + mintAndTransfer: (mintReceiver, toMint, fee, nonMintTransfers) => { + const kept = AmountMath.subtract(toMint, fee); + debtMint.mintGains(harden({ Minted: toMint }), mintSeat); + /** @type {TransferPart[]} */ + const transfers = [ + ...nonMintTransfers, + [mintSeat, rewardPoolSeat, { Minted: fee }], + [mintSeat, mintReceiver, { Minted: kept }], + ]; + try { + atomicRearrange(zcf, harden(transfers)); + } catch (e) { + console.error('mintAndTransfer failed to rearrange', e); + // If the rearrange fails, burn the newly minted tokens. + // Assume this won't fail because it relies on the internal mint. + // (Failure would imply much larger problems.) + debtMint.burnLosses(harden({ Minted: toMint }), mintSeat); + throw e; + } + void writeMetrics(); + }, + getShortfallReporter: async () => { + await updateShortfallReporter(); + return shortfallReporter; + }, + /** + * @param {Amount<'nat'>} toBurn + * @param {ZCFSeat} seat + */ + burnDebt: (toBurn, seat) => { + debtMint.burnLosses(harden({ Minted: toBurn }), seat); + }, }, - }); + ); const makeVaultManagerKit = prepareVaultManagerKit(baggage, { makeERecorderKit, @@ -317,20 +329,28 @@ const prepareVaultDirector = ( { creator: { getParamMgrRetriever: () => - Far('paramManagerRetriever', { - /** @param {VaultFactoryParamPath} paramPath */ - get: ( - paramPath = { key: /** @type {const} */ 'governedParams' }, - ) => { - if (paramPath.key === 'governedParams') { - return directorParamManager; - } else if (paramPath.key.collateralBrand) { - return vaultParamManagers.get(paramPath.key.collateralBrand); - } else { - assert.fail('Unsupported paramPath'); - } + makeExo( + 'paramManagerRetriever', + M.interface( + 'paramManagerRetriever', + {}, + { defaultGuards: 'passable' }, + ), + { + /** @param {VaultFactoryParamPath} paramPath */ + get: ( + paramPath = { key: /** @type {const} */ 'governedParams' }, + ) => { + if (paramPath.key === 'governedParams') { + return directorParamManager; + } else if (paramPath.key.collateralBrand) { + return vaultParamManagers.get(paramPath.key.collateralBrand); + } else { + assert.fail('Unsupported paramPath'); + } + }, }, - }), + ), /** @param {string} name */ getInvitation(name) { return directorParamManager.getInternalParamValue(name); @@ -341,7 +361,11 @@ const prepareVaultDirector = ( /** @returns {ERef} */ getGovernedApis() { // @ts-expect-error cast - return Far('governedAPIs', {}); + return makeExo( + 'governedAPIs', + M.interface('governedAPIs', {}, { defaultGuards: 'passable' }), + {}, + ); }, getGovernedApiNames() { return harden([]); diff --git a/packages/inter-protocol/test/auction/tools.js b/packages/inter-protocol/test/auction/tools.js index 0c78bfe8c97..10a9d0d1c0b 100644 --- a/packages/inter-protocol/test/auction/tools.js +++ b/packages/inter-protocol/test/auction/tools.js @@ -60,23 +60,27 @@ export const makeFakeAuctioneer = () => { const state = { step: 0, final: false, capturedPrices: false }; const startRounds = []; - return Far('FakeAuctioneer', { - reducePriceAndTrade: () => { - state.step += 1; + return makeExo( + 'FakeAuctioneer', + M.interface('FakeAuctioneer', {}, { defaultGuards: 'passable' }), + { + reducePriceAndTrade: () => { + state.step += 1; + }, + finalize: () => { + state.final = true; + state.capturedPrices = false; + }, + getState: () => state, + startRound: () => { + startRounds.push(state.step); + state.step += 1; + state.final = false; + }, + getStartRounds: () => startRounds, + capturePrices: () => (state.capturedPrices = true), }, - finalize: () => { - state.final = true; - state.capturedPrices = false; - }, - getState: () => state, - startRound: () => { - startRounds.push(state.step); - state.step += 1; - state.final = false; - }, - getStartRounds: () => startRounds, - capturePrices: () => (state.capturedPrices = true), - }); + ); }; /** diff --git a/packages/inter-protocol/test/price/test-fluxAggregatorKit.js b/packages/inter-protocol/test/price/test-fluxAggregatorKit.js index 0fcb6a15122..9f406f86bda 100644 --- a/packages/inter-protocol/test/price/test-fluxAggregatorKit.js +++ b/packages/inter-protocol/test/price/test-fluxAggregatorKit.js @@ -40,7 +40,11 @@ const makeContext = async () => { const zcfTestKit = await setupZCFTest(undefined, terms); // ??? why do we need the Far here and not in VaultFactory tests? - const marshaller = Far('fake marshaller', { ...makeFakeMarshaller() }); + const marshaller = makeExo( + 'fake marshaller', + M.interface('fake marshaller', {}, { defaultGuards: 'passable' }), + { ...makeFakeMarshaller() }, + ); const mockStorageRoot = makeMockChainStorageRoot(); const storageNode = E(mockStorageRoot).makeChildNode('priceAggregator'); diff --git a/packages/inter-protocol/test/psm/setupPsm.js b/packages/inter-protocol/test/psm/setupPsm.js index 089ec7da275..8b52df3953a 100644 --- a/packages/inter-protocol/test/psm/setupPsm.js +++ b/packages/inter-protocol/test/psm/setupPsm.js @@ -100,11 +100,15 @@ export const setupPsm = async ( space.produce.provisionPoolStartResult.resolve({ // @ts-expect-error mock - creatorFacet: Far('dummy', { - initPSM: () => { - t.log('dummy provisionPool.initPSM'); + creatorFacet: makeExo( + 'dummy', + M.interface('dummy', {}, { defaultGuards: 'passable' }), + { + initPSM: () => { + t.log('dummy provisionPool.initPSM'); + }, }, - }), + ), }); await Promise.all([ diff --git a/packages/inter-protocol/test/psm/test-governedPsm.js b/packages/inter-protocol/test/psm/test-governedPsm.js index 3a10c7a345f..c75ff0ee18c 100644 --- a/packages/inter-protocol/test/psm/test-governedPsm.js +++ b/packages/inter-protocol/test/psm/test-governedPsm.js @@ -180,7 +180,11 @@ test('replace electorate of Economic Committee', async t => { harden({}), electorateTerms, { - marshaller: Far('fake marshaller', { ...makeFakeMarshaller() }), + marshaller: makeExo( + 'fake marshaller', + M.interface('fake marshaller', {}, { defaultGuards: 'passable' }), + { ...makeFakeMarshaller() }, + ), storageNode: makeFakeStorageKit('governedPsmTest').rootNode, }, ); diff --git a/packages/inter-protocol/test/psm/test-psm.js b/packages/inter-protocol/test/psm/test-psm.js index 38066486922..adb0bc141a9 100644 --- a/packages/inter-protocol/test/psm/test-psm.js +++ b/packages/inter-protocol/test/psm/test-psm.js @@ -733,20 +733,28 @@ test('extra give wantMintedInvitation', async t => { // XXX copied (with minor tweak) from packages/inter-protocol/test/test-gov-collateral.js const makeMockBankManager = t => { /** @type {BankManager} */ - const bankManager = Far('mock BankManager', { - __getInterfaceGuard__: () => undefined, - getAssetSubscription: () => assert.fail('not impl'), - getModuleAccountAddress: () => assert.fail('not impl'), - getRewardDistributorDepositFacet: () => - Far('depositFacet', { - receive: () => /** @type {any} */ (null), - }), - addAsset: async (denom, keyword, proposedName, kit) => { - t.log('addAsset', { denom, keyword, issuer: `${kit.issuer}` }); - t.truthy(kit.mint); + const bankManager = makeExo( + 'mock BankManager', + M.interface('mock BankManager', {}, { defaultGuards: 'passable' }), + { + __getInterfaceGuard__: () => undefined, + getAssetSubscription: () => assert.fail('not impl'), + getModuleAccountAddress: () => assert.fail('not impl'), + getRewardDistributorDepositFacet: () => + makeExo( + 'depositFacet', + M.interface('depositFacet', {}, { defaultGuards: 'passable' }), + { + receive: () => /** @type {any} */ (null), + }, + ), + addAsset: async (denom, keyword, proposedName, kit) => { + t.log('addAsset', { denom, keyword, issuer: `${kit.issuer}` }); + t.truthy(kit.mint); + }, + getBankForAddress: () => assert.fail('not impl'), }, - getBankForAddress: () => assert.fail('not impl'), - }); + ); return bankManager; }; diff --git a/packages/inter-protocol/test/smartWallet/boot-psm.js b/packages/inter-protocol/test/smartWallet/boot-psm.js index 5ffa6612550..3f8346458a9 100644 --- a/packages/inter-protocol/test/smartWallet/boot-psm.js +++ b/packages/inter-protocol/test/smartWallet/boot-psm.js @@ -310,42 +310,54 @@ export const buildRootObject = async (vatPowers, vatParameters) => { console.log('boot-psm fully resolved'); }; - return Far('bootstrap', { - bootstrap: (vats, devices) => { - const { D } = vatPowers; - D(devices.mailbox).registerInboundHandler( - Far('dummyInboundHandler', { deliverInboundMessages: () => {} }), - ); + return makeExo( + 'bootstrap', + M.interface('bootstrap', {}, { defaultGuards: 'passable' }), + { + bootstrap: (vats, devices) => { + const { D } = vatPowers; + D(devices.mailbox).registerInboundHandler( + makeExo( + 'dummyInboundHandler', + M.interface( + 'dummyInboundHandler', + {}, + { defaultGuards: 'passable' }, + ), + { deliverInboundMessages: () => {} }, + ), + ); - return runBootstrapParts(vats, devices).catch(e => { - console.error('BOOTSTRAP FAILED:', e); - throw e; - }); - }, - /** - * Allow kernel to provide things to CORE_EVAL. - * - * @param {string} name - * @param {unknown} resolution - */ - produceItem: (name, resolution) => { - assert.typeof(name, 'string'); - produce[name].resolve(resolution); - }, - // expose reset in case we need to do-over - resetItem: name => { - assert.typeof(name, 'string'); - produce[name].reset(); - }, - // expose consume mostly for testing - consumeItem: name => { - assert.typeof(name, 'string'); - return consume[name]; + return runBootstrapParts(vats, devices).catch(e => { + console.error('BOOTSTRAP FAILED:', e); + throw e; + }); + }, + /** + * Allow kernel to provide things to CORE_EVAL. + * + * @param {string} name + * @param {unknown} resolution + */ + produceItem: (name, resolution) => { + assert.typeof(name, 'string'); + produce[name].resolve(resolution); + }, + // expose reset in case we need to do-over + resetItem: name => { + assert.typeof(name, 'string'); + produce[name].reset(); + }, + // expose consume mostly for testing + consumeItem: name => { + assert.typeof(name, 'string'); + return consume[name]; + }, + /** @type {() => ChainBootstrapSpace} */ + // @ts-expect-error cast + getPromiseSpace: () => ({ consume, produce, ...spaces }), }, - /** @type {() => ChainBootstrapSpace} */ - // @ts-expect-error cast - getPromiseSpace: () => ({ consume, produce, ...spaces }), - }); + ); }; harden({ buildRootObject }); diff --git a/packages/inter-protocol/test/smartWallet/boot-test-utils.js b/packages/inter-protocol/test/smartWallet/boot-test-utils.js index 67b36f949a2..be77045406f 100644 --- a/packages/inter-protocol/test/smartWallet/boot-test-utils.js +++ b/packages/inter-protocol/test/smartWallet/boot-test-utils.js @@ -34,32 +34,48 @@ export const makeMock = log => }, vats: { vattp: /** @type {any} */ ( - Far('vattp', { - registerMailboxDevice: noop, - addRemote: () => harden({}), - }) + makeExo( + 'vattp', + M.interface('vattp', {}, { defaultGuards: 'passable' }), + { + registerMailboxDevice: noop, + addRemote: () => harden({}), + }, + ) + ), + comms: makeExo( + 'comms', + M.interface('comms', {}, { defaultGuards: 'passable' }), + { + addRemote: noop, + addEgress: noop, + addIngress: async () => + harden({ + getConfiguration: () => harden({ _: 'client configuration' }), + }), + }, ), - comms: Far('comms', { - addRemote: noop, - addEgress: noop, - addIngress: async () => - harden({ - getConfiguration: () => harden({ _: 'client configuration' }), - }), - }), http: { setPresences: noop, setCommandDevice: noop }, spawner: { buildSpawner: () => harden({ _: 'spawner' }), }, - timer: Far('TimerVat', { - createTimerService: async () => buildManualTimer(log), - }), + timer: makeExo( + 'TimerVat', + M.interface('TimerVat', {}, { defaultGuards: 'passable' }), + { + createTimerService: async () => buildManualTimer(log), + }, + ), uploads: { getUploads: () => harden({ _: 'uploads' }) }, - network: Far('network', { - registerProtocolHandler: noop, - bind: () => harden({ addListener: noop }), - }), + network: makeExo( + 'network', + M.interface('network', {}, { defaultGuards: 'passable' }), + { + registerProtocolHandler: noop, + bind: () => harden({ addListener: noop }), + }, + ), }, }); @@ -117,11 +133,15 @@ export const makePopulatedFakeVatAdmin = () => { return createVat(fakeNameToCap.get(name) || Fail`unknown vat ${name}`); }; - const vatAdminService = Far('vatAdminSvc', { - ...fakeVatAdmin, - createVat, - createVatByName, - }); + const vatAdminService = makeExo( + 'vatAdminSvc', + M.interface('vatAdminSvc', {}, { defaultGuards: 'passable' }), + { + ...fakeVatAdmin, + createVat, + createVatByName, + }, + ); const criticalVatKey = vatAdminState.getCriticalVatKey(); const getCriticalVatKey = () => criticalVatKey; const createVatAdminService = () => vatAdminService; diff --git a/packages/inter-protocol/test/swingsetTests/fluxAggregator/bootstrap-fluxAggregator-service-upgrade.js b/packages/inter-protocol/test/swingsetTests/fluxAggregator/bootstrap-fluxAggregator-service-upgrade.js index f7ee468d911..b6b0b1c527d 100644 --- a/packages/inter-protocol/test/swingsetTests/fluxAggregator/bootstrap-fluxAggregator-service-upgrade.js +++ b/packages/inter-protocol/test/swingsetTests/fluxAggregator/bootstrap-fluxAggregator-service-upgrade.js @@ -106,187 +106,197 @@ export const buildRootObject = async () => { namesByAddressAdmin, }; - return Far('root', { - bootstrap: async (vats, devices) => { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - const { zoeService } = await E(vats.zoe).buildZoe( - vatAdmin, - undefined, - 'zcf', - ); - zoePK.resolve(zoeService); - - const v1BundleId = await E(vatAdmin).getBundleIDByName(faV1BundleName); - v1BundleId || Fail`bundleId must not be empty`; - installations.fluxAggregatorV1 = await E(zoe).installBundleID(v1BundleId); - - installations.puppetContractGovernor = await E(zoe).installBundleID( - await E(vatAdmin).getBundleIDByName('puppetContractGovernor'), - ); - - installations.committee = await E(zoe).installBundleID( - await E(vatAdmin).getBundleIDByName('committee'), - ); - const ccStartResult = await E(zoe).startInstance( - installations.committee, - harden({}), - { - committeeName: 'Demos', - committeeSize: 1, - }, - { - storageNode: storageKit.rootNode.makeChildNode('thisCommittee'), - marshaller, - }, - ); - ccPK.resolve(ccStartResult.creatorFacet); - - const poserInvitationP = E(committeeCreator).getPoserInvitation(); - [initialPoserInvitation, poserInvitationAmount] = await Promise.all([ - poserInvitationP, - E(E(zoe).getInvitationIssuer()).getAmountOf(poserInvitationP), - ]); - }, - - buildV1: async () => { - trace(`BOOT buildV1 start`); - // build the contract vat from ZCF and the contract bundlecap - - // @ts-expect-error xxx - faTerms.governedParams[CONTRACT_ELECTORATE].value = poserInvitationAmount; - - const governorTerms = await deeplyFulfilledObject( - harden({ - timer, - governedContractInstallation: NonNullish( - installations.fluxAggregatorV1, - ), - governed: { - terms: faTerms, - label: 'fluxAggregatorV1', + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap: async (vats, devices) => { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + const { zoeService } = await E(vats.zoe).buildZoe( + vatAdmin, + undefined, + 'zcf', + ); + zoePK.resolve(zoeService); + + const v1BundleId = await E(vatAdmin).getBundleIDByName(faV1BundleName); + v1BundleId || Fail`bundleId must not be empty`; + installations.fluxAggregatorV1 = + await E(zoe).installBundleID(v1BundleId); + + installations.puppetContractGovernor = await E(zoe).installBundleID( + await E(vatAdmin).getBundleIDByName('puppetContractGovernor'), + ); + + installations.committee = await E(zoe).installBundleID( + await E(vatAdmin).getBundleIDByName('committee'), + ); + const ccStartResult = await E(zoe).startInstance( + installations.committee, + harden({}), + { + committeeName: 'Demos', + committeeSize: 1, }, - }), - ); - trace('got governorTerms', governorTerms); - - // Complete round-trip without upgrade - trace(`BOOT buildV1 startInstance`); - governorFacets = await E(zoe).startInstance( - NonNullish(installations.puppetContractGovernor), - undefined, - // @ts-expect-error - governorTerms, - { - governed: { - ...staticPrivateArgs, - initialPoserInvitation, + { + storageNode: storageKit.rootNode.makeChildNode('thisCommittee'), + marshaller, }, - }, - ); - trace('BOOT buildV1 started instance'); + ); + ccPK.resolve(ccStartResult.creatorFacet); + + const poserInvitationP = E(committeeCreator).getPoserInvitation(); + [initialPoserInvitation, poserInvitationAmount] = await Promise.all([ + poserInvitationP, + E(E(zoe).getInvitationIssuer()).getAmountOf(poserInvitationP), + ]); + }, - // @ts-expect-error XXX governance types https://github.com/Agoric/agoric-sdk/issues/7178 - faLimitedFacet = await E(governorFacets.creatorFacet).getCreatorFacet(); + buildV1: async () => { + trace(`BOOT buildV1 start`); + // build the contract vat from ZCF and the contract bundlecap + + // @ts-expect-error xxx + faTerms.governedParams[CONTRACT_ELECTORATE].value = + poserInvitationAmount; + + const governorTerms = await deeplyFulfilledObject( + harden({ + timer, + governedContractInstallation: NonNullish( + installations.fluxAggregatorV1, + ), + governed: { + terms: faTerms, + label: 'fluxAggregatorV1', + }, + }), + ); + trace('got governorTerms', governorTerms); + + // Complete round-trip without upgrade + trace(`BOOT buildV1 startInstance`); + governorFacets = await E(zoe).startInstance( + NonNullish(installations.puppetContractGovernor), + undefined, + // @ts-expect-error + governorTerms, + { + governed: { + ...staticPrivateArgs, + initialPoserInvitation, + }, + }, + ); + trace('BOOT buildV1 started instance'); - oracleA = await E(faLimitedFacet).initOracle('oracleA'); + // @ts-expect-error XXX governance types https://github.com/Agoric/agoric-sdk/issues/7178 + faLimitedFacet = await E(governorFacets.creatorFacet).getCreatorFacet(); - trace('BOOT buildV1 made oracleA'); + oracleA = await E(faLimitedFacet).initOracle('oracleA'); - return true; - }, + trace('BOOT buildV1 made oracleA'); - testFunctionality1: async () => { - const faPublicFacet = await E( - governorFacets.creatorFacet, - ).getPublicFacet(); - - const publicTopics = await E(faPublicFacet).getPublicTopics(); - assert.equal( - publicTopics.latestRound.description, - 'Notification of each round', - ); - assert.equal( - publicTopics.quotes.description, - 'Quotes from this price aggregator', - ); - - trace('testFunctionality pushing price'); - await timer.tickN(1); - const unitPrice = 123n; - await E(oracleA.oracle).pushPrice({ roundId: 1, unitPrice }); - quoteSubscriber1 = await publicTopics.quotes.subscriber; - - const quoteNotifier = makeNotifierFromSubscriber(quoteSubscriber1); - - trace('testFunctionality awaiting quoteNotifier1'); - lastQuote = await quoteNotifier.getUpdateSince(); - assert.equal(lastQuote.updateCount, 1n); - assert.equal(lastQuote.value.amountOut.value, unitPrice); - - // XXX t.throwsAsync sure would be nice - await E(governorFacets.creatorFacet) - .invokeAPI('removeOracles', [['oracleB']]) - .then(() => Error('this should have errored')) - .catch(reason => { - assert.equal( - reason.message, - 'key oracleB not found in collection oracles', - ); - }); - await timer.tickN(1); - }, + return true; + }, - nullUpgradeV1: async () => { - trace(`BOOT nullUpgradeV1 start`); + testFunctionality1: async () => { + const faPublicFacet = await E( + governorFacets.creatorFacet, + ).getPublicFacet(); + + const publicTopics = await E(faPublicFacet).getPublicTopics(); + assert.equal( + publicTopics.latestRound.description, + 'Notification of each round', + ); + assert.equal( + publicTopics.quotes.description, + 'Quotes from this price aggregator', + ); + + trace('testFunctionality pushing price'); + await timer.tickN(1); + const unitPrice = 123n; + await E(oracleA.oracle).pushPrice({ roundId: 1, unitPrice }); + quoteSubscriber1 = await publicTopics.quotes.subscriber; + + const quoteNotifier = makeNotifierFromSubscriber(quoteSubscriber1); + + trace('testFunctionality awaiting quoteNotifier1'); + lastQuote = await quoteNotifier.getUpdateSince(); + assert.equal(lastQuote.updateCount, 1n); + assert.equal(lastQuote.value.amountOut.value, unitPrice); + + // XXX t.throwsAsync sure would be nice + await E(governorFacets.creatorFacet) + .invokeAPI('removeOracles', [['oracleB']]) + .then(() => Error('this should have errored')) + .catch(reason => { + assert.equal( + reason.message, + 'key oracleB not found in collection oracles', + ); + }); + await timer.tickN(1); + }, - const bundleId = await E(vatAdmin).getBundleIDByName(faV1BundleName); + nullUpgradeV1: async () => { + trace(`BOOT nullUpgradeV1 start`); - trace(`BOOT nullUpgradeV1 upgradeContract`); - const faAdminFacet = await E(governorFacets.creatorFacet).getAdminFacet(); - const upgradeResult = await E(faAdminFacet).upgradeContract(bundleId, { - ...staticPrivateArgs, - initialPoserInvitation, - }); - assert.equal(upgradeResult.incarnationNumber, 1); - trace(`BOOT nullUpgradeV1 upgradeContract completed`); + const bundleId = await E(vatAdmin).getBundleIDByName(faV1BundleName); - await timer.tickN(1); - return true; - }, + trace(`BOOT nullUpgradeV1 upgradeContract`); + const faAdminFacet = await E( + governorFacets.creatorFacet, + ).getAdminFacet(); + const upgradeResult = await E(faAdminFacet).upgradeContract(bundleId, { + ...staticPrivateArgs, + initialPoserInvitation, + }); + assert.equal(upgradeResult.incarnationNumber, 1); + trace(`BOOT nullUpgradeV1 upgradeContract completed`); - testFunctionality2: async () => { - const faPublicFacet = await E( - governorFacets.creatorFacet, - ).getPublicFacet(); - - const publicTopics = await E(faPublicFacet).getPublicTopics(); - const quoteSubscriber2 = await publicTopics.quotes.subscriber; - assert( - quoteSubscriber2 === quoteSubscriber1, - 'same subscriber object after upgrade', - ); - - trace('testFunctionality2 pushing price'); - // advance time to allow new round - await timer.tickN(1); - const unitPrice = 234n; - await E(oracleA.oracle).pushPrice({ roundId: 2, unitPrice }); - await null; // xxx - - trace('testFunctionality awaiting quotes'); - const quoteNotifier = makeNotifierFromSubscriber( - publicTopics.quotes.subscriber, - ); - lastQuote = await quoteNotifier.getUpdateSince(lastQuote.updateCount); - assert.equal(lastQuote.updateCount, 2n); // incremented durable subscriber - - trace('testFunctionality awaiting quote again'); - lastQuote = await quoteNotifier.getUpdateSince(lastQuote.updateCount); - assert.equal(lastQuote.updateCount, 3n); - assert.equal(lastQuote.value.amountOut.value, unitPrice); - }, + await timer.tickN(1); + return true; + }, + + testFunctionality2: async () => { + const faPublicFacet = await E( + governorFacets.creatorFacet, + ).getPublicFacet(); + + const publicTopics = await E(faPublicFacet).getPublicTopics(); + const quoteSubscriber2 = await publicTopics.quotes.subscriber; + assert( + quoteSubscriber2 === quoteSubscriber1, + 'same subscriber object after upgrade', + ); + + trace('testFunctionality2 pushing price'); + // advance time to allow new round + await timer.tickN(1); + const unitPrice = 234n; + await E(oracleA.oracle).pushPrice({ roundId: 2, unitPrice }); + await null; // xxx + + trace('testFunctionality awaiting quotes'); + const quoteNotifier = makeNotifierFromSubscriber( + publicTopics.quotes.subscriber, + ); + lastQuote = await quoteNotifier.getUpdateSince(lastQuote.updateCount); + assert.equal(lastQuote.updateCount, 2n); // incremented durable subscriber + + trace('testFunctionality awaiting quote again'); + lastQuote = await quoteNotifier.getUpdateSince(lastQuote.updateCount); + assert.equal(lastQuote.updateCount, 3n); + assert.equal(lastQuote.value.amountOut.value, unitPrice); + }, - // this test doesn't upgrade to a new bundle because we have coverage elsewhere that - // a new bundle will replace the behavior of the prior bundle - }); + // this test doesn't upgrade to a new bundle because we have coverage elsewhere that + // a new bundle will replace the behavior of the prior bundle + }, + ); }; diff --git a/packages/inter-protocol/test/swingsetTests/psmUpgrade/bootstrap-psm-upgrade.js b/packages/inter-protocol/test/swingsetTests/psmUpgrade/bootstrap-psm-upgrade.js index 64982243d48..01c06d20a63 100644 --- a/packages/inter-protocol/test/swingsetTests/psmUpgrade/bootstrap-psm-upgrade.js +++ b/packages/inter-protocol/test/swingsetTests/psmUpgrade/bootstrap-psm-upgrade.js @@ -118,222 +118,233 @@ export const buildRootObject = async () => { return seat; }; - return Far('root', { - /** - * @param {{ - * vatAdmin: ReturnType< - * import('@agoric/swingset-vat/src/vats/vat-admin/vat-vat-admin.js')['buildRootObject'] - * >; - * zoe: ReturnType< - * import('@agoric/vats/src/vat-zoe.js')['buildRootObject'] - * >; - * }} vats - * @param {any} devices - */ - bootstrap: async (vats, devices) => { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - ({ feeMintAccess, zoeService } = await E(vats.zoe).buildZoe( - vatAdmin, - undefined, - 'zcf', - )); - - minted = { - brand: await E(E(zoeService).getFeeIssuer()).getBrand(), - make: n => AmountMath.make(minted.brand, n), - }; - psmTerms.anchorPerMinted = makeRatio(1n, anchor.brand, 1n, minted.brand); - psmTerms.governedParams.WantMintedFee = { - type: ParamTypes.RATIO, - value: makeRatio(1n, minted.brand, 1n), - }; - psmTerms.governedParams.GiveMintedFee = { - type: ParamTypes.RATIO, - value: makeRatio(1n, minted.brand, 1n), - }; - psmTerms.governedParams.MintLimit = { - type: ParamTypes.AMOUNT, - value: minted.make(scale6(1_000_000)), - }; - - const v1BundleId = await E(vatAdmin).getBundleIDByName(psmV1BundleName); - v1BundleId || Fail`bundleId must not be empty`; - installations.psmV1 = await E(zoeService).installBundleID(v1BundleId); - - installations.puppetContractGovernor = await E( - zoeService, - ).installBundleID( - await E(vatAdmin).getBundleIDByName('puppetContractGovernor'), - ); - - installations.committee = await E(zoeService).installBundleID( - await E(vatAdmin).getBundleIDByName('committee'), - ); - const ccStartResult = await E(zoeService).startInstance( - installations.committee, - harden({}), - { - committeeName: 'Demos', - committeeSize: 1, - }, - { - storageNode: storageKit.rootNode.makeChildNode('thisCommittee'), - marshaller, - }, - ); - ccPK.resolve(ccStartResult.creatorFacet); - - const poserInvitationP = E(committeeCreator).getPoserInvitation(); - [initialPoserInvitation, poserInvitationAmount] = await Promise.all([ - poserInvitationP, - E(E(zoeService).getInvitationIssuer()).getAmountOf(poserInvitationP), - ]); - // fill in missing value - psmTerms.governedParams[CONTRACT_ELECTORATE].value = - poserInvitationAmount; - }, - - buildV1: async () => { - trace(`BOOT buildV1 start`); - // build the contract vat from ZCF and the contract bundlecap - - const governorTerms = await deeplyFulfilledObject( - harden({ - timer, - governedContractInstallation: NonNullish(installations.psmV1), - governed: { - terms: psmTerms, - issuerKeywordRecord: { AUSD: anchor.issuer }, - label: 'psmV1', + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + /** + * @param {{ + * vatAdmin: ReturnType< + * import('@agoric/swingset-vat/src/vats/vat-admin/vat-vat-admin.js')['buildRootObject'] + * >; + * zoe: ReturnType< + * import('@agoric/vats/src/vat-zoe.js')['buildRootObject'] + * >; + * }} vats + * @param {any} devices + */ + bootstrap: async (vats, devices) => { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + ({ feeMintAccess, zoeService } = await E(vats.zoe).buildZoe( + vatAdmin, + undefined, + 'zcf', + )); + + minted = { + brand: await E(E(zoeService).getFeeIssuer()).getBrand(), + make: n => AmountMath.make(minted.brand, n), + }; + psmTerms.anchorPerMinted = makeRatio( + 1n, + anchor.brand, + 1n, + minted.brand, + ); + psmTerms.governedParams.WantMintedFee = { + type: ParamTypes.RATIO, + value: makeRatio(1n, minted.brand, 1n), + }; + psmTerms.governedParams.GiveMintedFee = { + type: ParamTypes.RATIO, + value: makeRatio(1n, minted.brand, 1n), + }; + psmTerms.governedParams.MintLimit = { + type: ParamTypes.AMOUNT, + value: minted.make(scale6(1_000_000)), + }; + + const v1BundleId = await E(vatAdmin).getBundleIDByName(psmV1BundleName); + v1BundleId || Fail`bundleId must not be empty`; + installations.psmV1 = await E(zoeService).installBundleID(v1BundleId); + + installations.puppetContractGovernor = await E( + zoeService, + ).installBundleID( + await E(vatAdmin).getBundleIDByName('puppetContractGovernor'), + ); + + installations.committee = await E(zoeService).installBundleID( + await E(vatAdmin).getBundleIDByName('committee'), + ); + const ccStartResult = await E(zoeService).startInstance( + installations.committee, + harden({}), + { + committeeName: 'Demos', + committeeSize: 1, }, - }), - ); - trace('got governorTerms', governorTerms); - - trace(`BOOT buildV1 startInstance`); - // @ts-expect-error - governorFacets = await E(zoeService).startInstance( - NonNullish(installations.puppetContractGovernor), - undefined, - governorTerms, - { - governed: { - ...staticPrivateArgs, - feeMintAccess, - initialPoserInvitation, + { + storageNode: storageKit.rootNode.makeChildNode('thisCommittee'), + marshaller, }, - }, - ); - trace('BOOT buildV1 started instance'); + ); + ccPK.resolve(ccStartResult.creatorFacet); + + const poserInvitationP = E(committeeCreator).getPoserInvitation(); + [initialPoserInvitation, poserInvitationAmount] = await Promise.all([ + poserInvitationP, + E(E(zoeService).getInvitationIssuer()).getAmountOf(poserInvitationP), + ]); + // fill in missing value + psmTerms.governedParams[CONTRACT_ELECTORATE].value = + poserInvitationAmount; + }, - psmPublicFacet = await E(governorFacets.creatorFacet).getPublicFacet(); + buildV1: async () => { + trace(`BOOT buildV1 start`); + // build the contract vat from ZCF and the contract bundlecap + + const governorTerms = await deeplyFulfilledObject( + harden({ + timer, + governedContractInstallation: NonNullish(installations.psmV1), + governed: { + terms: psmTerms, + issuerKeywordRecord: { AUSD: anchor.issuer }, + label: 'psmV1', + }, + }), + ); + trace('got governorTerms', governorTerms); + + trace(`BOOT buildV1 startInstance`); + // @ts-expect-error + governorFacets = await E(zoeService).startInstance( + NonNullish(installations.puppetContractGovernor), + undefined, + governorTerms, + { + governed: { + ...staticPrivateArgs, + feeMintAccess, + initialPoserInvitation, + }, + }, + ); + trace('BOOT buildV1 started instance'); - return true; - }, + psmPublicFacet = await E(governorFacets.creatorFacet).getPublicFacet(); - testFunctionality1: async () => { - trace('testFunctionality1'); - - metrics = await E(psmPublicFacet).getMetrics(); - - metricsRecord = await E(metrics).getUpdateSince(); - mustMatch( - metricsRecord.value, - harden({ - anchorPoolBalance: anchor.make(0n), - feePoolBalance: minted.make(0n), - mintedPoolBalance: minted.make(0n), - totalAnchorProvided: anchor.make(0n), - totalMintedProvided: minted.make(0n), - }), - ); - - const seat = swapAnchorForMintedSeat(firstGive); - const payouts = await E(seat).getPayouts(); - mustMatch(payouts, PaymentPKeywordRecordShape); - - metricsRecord = await E(metrics).getUpdateSince( - metricsRecord.updateCount, - ); - mustMatch( - metricsRecord.value, - harden({ - anchorPoolBalance: firstGive, - feePoolBalance: minted.make(firstGive.value), - mintedPoolBalance: minted.make(firstGive.value), - totalAnchorProvided: anchor.make(0n), - totalMintedProvided: minted.make(firstGive.value), - }), - ); - }, + return true; + }, - nullUpgradeV1: async () => { - trace(`BOOT nullUpgradeV1 start`); - - const bundleId = await E(vatAdmin).getBundleIDByName(psmV1BundleName); - - trace(`BOOT nullUpgradeV1 upgradeContract`); - const psmAdminFacet = await E( - governorFacets.creatorFacet, - ).getAdminFacet(); - const upgradeResult = await E(psmAdminFacet).upgradeContract(bundleId, { - ...staticPrivateArgs, - // @ts-expect-error mock - feeMintAccess: undefined, - initialPoserInvitation, - }); - // incremented from zero - assert.equal(upgradeResult.incarnationNumber, 1); - trace(`BOOT nullUpgradeV1 upgradeContract completed`); - - await timer.tickN(1); - return true; - }, + testFunctionality1: async () => { + trace('testFunctionality1'); + + metrics = await E(psmPublicFacet).getMetrics(); + + metricsRecord = await E(metrics).getUpdateSince(); + mustMatch( + metricsRecord.value, + harden({ + anchorPoolBalance: anchor.make(0n), + feePoolBalance: minted.make(0n), + mintedPoolBalance: minted.make(0n), + totalAnchorProvided: anchor.make(0n), + totalMintedProvided: minted.make(0n), + }), + ); + + const seat = swapAnchorForMintedSeat(firstGive); + const payouts = await E(seat).getPayouts(); + mustMatch(payouts, PaymentPKeywordRecordShape); + + metricsRecord = await E(metrics).getUpdateSince( + metricsRecord.updateCount, + ); + mustMatch( + metricsRecord.value, + harden({ + anchorPoolBalance: firstGive, + feePoolBalance: minted.make(firstGive.value), + mintedPoolBalance: minted.make(firstGive.value), + totalAnchorProvided: anchor.make(0n), + totalMintedProvided: minted.make(firstGive.value), + }), + ); + }, - testFunctionality2: async () => { - trace('testFunctionality2'); - - // contract publishes metrics in prepare() - // verify that they match what we ended with before restart - metricsRecord = await E(metrics).getUpdateSince( - metricsRecord.updateCount, - ); - mustMatch( - metricsRecord.value, - harden({ - anchorPoolBalance: firstGive, - feePoolBalance: minted.make(firstGive.value), - mintedPoolBalance: minted.make(firstGive.value), - totalAnchorProvided: anchor.make(0n), - totalMintedProvided: minted.make(firstGive.value), - }), - ); - - // verify we can still trade - const seat = swapAnchorForMintedSeat(secondGive); - const payouts = await E(seat).getPayouts(); - mustMatch(payouts, PaymentPKeywordRecordShape); - - // verify that the subscriber's index is maintained - metricsRecord = await E(metrics).getUpdateSince( - metricsRecord.updateCount, - ); - - // verify that the metrics still update (from the trade above) - const totalGive = AmountMath.add(firstGive, secondGive); - mustMatch( - metricsRecord.value, - harden({ - anchorPoolBalance: totalGive, - feePoolBalance: minted.make(totalGive.value), - mintedPoolBalance: minted.make(totalGive.value), - totalAnchorProvided: anchor.make(0n), - totalMintedProvided: minted.make(totalGive.value), - }), - ); - }, + nullUpgradeV1: async () => { + trace(`BOOT nullUpgradeV1 start`); + + const bundleId = await E(vatAdmin).getBundleIDByName(psmV1BundleName); + + trace(`BOOT nullUpgradeV1 upgradeContract`); + const psmAdminFacet = await E( + governorFacets.creatorFacet, + ).getAdminFacet(); + const upgradeResult = await E(psmAdminFacet).upgradeContract(bundleId, { + ...staticPrivateArgs, + // @ts-expect-error mock + feeMintAccess: undefined, + initialPoserInvitation, + }); + // incremented from zero + assert.equal(upgradeResult.incarnationNumber, 1); + trace(`BOOT nullUpgradeV1 upgradeContract completed`); + + await timer.tickN(1); + return true; + }, - // this test doesn't upgrade to a new bundle because we have coverage elsewhere that - // a new bundle will replace the behavior of the prior bundle - }); + testFunctionality2: async () => { + trace('testFunctionality2'); + + // contract publishes metrics in prepare() + // verify that they match what we ended with before restart + metricsRecord = await E(metrics).getUpdateSince( + metricsRecord.updateCount, + ); + mustMatch( + metricsRecord.value, + harden({ + anchorPoolBalance: firstGive, + feePoolBalance: minted.make(firstGive.value), + mintedPoolBalance: minted.make(firstGive.value), + totalAnchorProvided: anchor.make(0n), + totalMintedProvided: minted.make(firstGive.value), + }), + ); + + // verify we can still trade + const seat = swapAnchorForMintedSeat(secondGive); + const payouts = await E(seat).getPayouts(); + mustMatch(payouts, PaymentPKeywordRecordShape); + + // verify that the subscriber's index is maintained + metricsRecord = await E(metrics).getUpdateSince( + metricsRecord.updateCount, + ); + + // verify that the metrics still update (from the trade above) + const totalGive = AmountMath.add(firstGive, secondGive); + mustMatch( + metricsRecord.value, + harden({ + anchorPoolBalance: totalGive, + feePoolBalance: minted.make(totalGive.value), + mintedPoolBalance: minted.make(totalGive.value), + totalAnchorProvided: anchor.make(0n), + totalMintedProvided: minted.make(totalGive.value), + }), + ); + }, + + // this test doesn't upgrade to a new bundle because we have coverage elsewhere that + // a new bundle will replace the behavior of the prior bundle + }, + ); }; diff --git a/packages/inter-protocol/test/swingsetTests/reserve/bootstrap-assetReserve-upgrade.js b/packages/inter-protocol/test/swingsetTests/reserve/bootstrap-assetReserve-upgrade.js index c6f00c8655a..069633d1bd5 100644 --- a/packages/inter-protocol/test/swingsetTests/reserve/bootstrap-assetReserve-upgrade.js +++ b/packages/inter-protocol/test/swingsetTests/reserve/bootstrap-assetReserve-upgrade.js @@ -118,177 +118,186 @@ export const buildRootObject = async () => { return seat; }; - return Far('root', { - bootstrap: async (vats, devices) => { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - ({ feeMintAccess, zoeService } = await E(vats.zoe).buildZoe( - vatAdmin, - undefined, - 'zcf', - )); - - const v1BundleId = await E(vatAdmin).getBundleIDByName(arV1BundleName); - v1BundleId || Fail`bundleId must not be empty`; - installations.assetReserveV1 = - await E(zoeService).installBundleID(v1BundleId); - - installations.puppetContractGovernor = await E( - zoeService, - ).installBundleID( - await E(vatAdmin).getBundleIDByName('puppetContractGovernor'), - ); - - installations.committee = await E(zoeService).installBundleID( - await E(vatAdmin).getBundleIDByName('committee'), - ); - const ccStartResult = await E(zoeService).startInstance( - installations.committee, - harden({}), - { - committeeName: 'Demos', - committeeSize: 1, - }, - { - storageNode: storageKit.rootNode.makeChildNode('thisCommittee'), - marshaller, - }, - ); - ccPK.resolve(ccStartResult.creatorFacet); - - const poserInvitationP = E(committeeCreator).getPoserInvitation(); - [initialPoserInvitation, poserInvitationAmount] = await Promise.all([ - poserInvitationP, - E(E(zoeService).getInvitationIssuer()).getAmountOf(poserInvitationP), - ]); - }, - - buildV1: async () => { - trace(`BOOT buildV1 start`); - // build the contract vat from ZCF and the contract bundlecap - - arTerms.governedParams[CONTRACT_ELECTORATE].value = poserInvitationAmount; - - const governorTerms = await deeplyFulfilledObject( - harden({ - timer, - governedContractInstallation: NonNullish( - installations.assetReserveV1, - ), - governed: { - terms: arTerms, - label: 'assetReserveV1', + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap: async (vats, devices) => { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + ({ feeMintAccess, zoeService } = await E(vats.zoe).buildZoe( + vatAdmin, + undefined, + 'zcf', + )); + + const v1BundleId = await E(vatAdmin).getBundleIDByName(arV1BundleName); + v1BundleId || Fail`bundleId must not be empty`; + installations.assetReserveV1 = + await E(zoeService).installBundleID(v1BundleId); + + installations.puppetContractGovernor = await E( + zoeService, + ).installBundleID( + await E(vatAdmin).getBundleIDByName('puppetContractGovernor'), + ); + + installations.committee = await E(zoeService).installBundleID( + await E(vatAdmin).getBundleIDByName('committee'), + ); + const ccStartResult = await E(zoeService).startInstance( + installations.committee, + harden({}), + { + committeeName: 'Demos', + committeeSize: 1, }, - }), - ); - trace('got governorTerms', governorTerms); - - // Complete round-trip without upgrade - trace(`BOOT buildV1 startInstance`); - // @ts-expect-error - governorFacets = await E(zoeService).startInstance( - NonNullish(installations.puppetContractGovernor), - undefined, - governorTerms, - { - governed: { - ...staticPrivateArgs, - feeMintAccess, - initialPoserInvitation, + { + storageNode: storageKit.rootNode.makeChildNode('thisCommittee'), + marshaller, }, - }, - ); - trace('BOOT buildV1 started instance'); - - // @ts-expect-error XXX governance types https://github.com/Agoric/agoric-sdk/issues/7178 - arLimitedFacet = await E(governorFacets.creatorFacet).getCreatorFacet(); + ); + ccPK.resolve(ccStartResult.creatorFacet); + + const poserInvitationP = E(committeeCreator).getPoserInvitation(); + [initialPoserInvitation, poserInvitationAmount] = await Promise.all([ + poserInvitationP, + E(E(zoeService).getInvitationIssuer()).getAmountOf(poserInvitationP), + ]); + }, - return true; - }, + buildV1: async () => { + trace(`BOOT buildV1 start`); + // build the contract vat from ZCF and the contract bundlecap + + arTerms.governedParams[CONTRACT_ELECTORATE].value = + poserInvitationAmount; + + const governorTerms = await deeplyFulfilledObject( + harden({ + timer, + governedContractInstallation: NonNullish( + installations.assetReserveV1, + ), + governed: { + terms: arTerms, + label: 'assetReserveV1', + }, + }), + ); + trace('got governorTerms', governorTerms); + + // Complete round-trip without upgrade + trace(`BOOT buildV1 startInstance`); + // @ts-expect-error + governorFacets = await E(zoeService).startInstance( + NonNullish(installations.puppetContractGovernor), + undefined, + governorTerms, + { + governed: { + ...staticPrivateArgs, + feeMintAccess, + initialPoserInvitation, + }, + }, + ); + trace('BOOT buildV1 started instance'); - testFunctionality1: async () => { - const arPublicFacet = await E( - governorFacets.creatorFacet, - ).getPublicFacet(); - - const publicTopics = await E(arPublicFacet).getPublicTopics(); - assert.equal(publicTopics.metrics.description, 'Asset Reserve metrics'); - metrics = publicTopics.metrics.subscriber; - metricsRecord = await E(metrics).getUpdateSince(); - assert.equal(metricsRecord.updateCount, 1n); - assert.equal(metricsRecord.value.shortfallBalance.value, 0n); - assert.equal(metricsRecord.value.totalFeeBurned.value, 0n); - assert.equal(metricsRecord.value.totalFeeMinted.value, 0n); - - await E(arLimitedFacet).addIssuer(moola.issuer, 'Moola'); - - const amt = moola.make(100_000n); - const collateralSeat = addCollateral(amt); - - assert.equal( - await E(collateralSeat).getOfferResult(), - 'added Collateral to the Reserve', - ); - // new record - metricsRecord = await E(metrics).getUpdateSince( - metricsRecord.updateCount, - ); - // added collateral is recorded - assert.equal(metricsRecord.value.allocations.Moola.value, amt.value); - }, + // @ts-expect-error XXX governance types https://github.com/Agoric/agoric-sdk/issues/7178 + arLimitedFacet = await E(governorFacets.creatorFacet).getCreatorFacet(); - nullUpgradeV1: async () => { - trace(`BOOT nullUpgradeV1 start`); + return true; + }, - const bundleId = await E(vatAdmin).getBundleIDByName(arV1BundleName); + testFunctionality1: async () => { + const arPublicFacet = await E( + governorFacets.creatorFacet, + ).getPublicFacet(); + + const publicTopics = await E(arPublicFacet).getPublicTopics(); + assert.equal(publicTopics.metrics.description, 'Asset Reserve metrics'); + metrics = publicTopics.metrics.subscriber; + metricsRecord = await E(metrics).getUpdateSince(); + assert.equal(metricsRecord.updateCount, 1n); + assert.equal(metricsRecord.value.shortfallBalance.value, 0n); + assert.equal(metricsRecord.value.totalFeeBurned.value, 0n); + assert.equal(metricsRecord.value.totalFeeMinted.value, 0n); + + await E(arLimitedFacet).addIssuer(moola.issuer, 'Moola'); + + const amt = moola.make(100_000n); + const collateralSeat = addCollateral(amt); + + assert.equal( + await E(collateralSeat).getOfferResult(), + 'added Collateral to the Reserve', + ); + // new record + metricsRecord = await E(metrics).getUpdateSince( + metricsRecord.updateCount, + ); + // added collateral is recorded + assert.equal(metricsRecord.value.allocations.Moola.value, amt.value); + }, - trace(`BOOT nullUpgradeV1 upgradeContract`); - const arAdminFacet = await E(governorFacets.creatorFacet).getAdminFacet(); - const upgradeResult = await E(arAdminFacet).upgradeContract(bundleId, { - ...staticPrivateArgs, - // @ts-expect-error mock - feeMintAccess: undefined, - initialPoserInvitation, - }); - assert.equal(upgradeResult.incarnationNumber, 1); - trace(`BOOT nullUpgradeV1 upgradeContract completed`); + nullUpgradeV1: async () => { + trace(`BOOT nullUpgradeV1 start`); + + const bundleId = await E(vatAdmin).getBundleIDByName(arV1BundleName); + + trace(`BOOT nullUpgradeV1 upgradeContract`); + const arAdminFacet = await E( + governorFacets.creatorFacet, + ).getAdminFacet(); + const upgradeResult = await E(arAdminFacet).upgradeContract(bundleId, { + ...staticPrivateArgs, + // @ts-expect-error mock + feeMintAccess: undefined, + initialPoserInvitation, + }); + assert.equal(upgradeResult.incarnationNumber, 1); + trace(`BOOT nullUpgradeV1 upgradeContract completed`); + + await timer.tickN(1); + return true; + }, - await timer.tickN(1); - return true; - }, + testFunctionality2: async () => { + const arPublicFacet = await E( + governorFacets.creatorFacet, + ).getPublicFacet(); + + const publicTopics = await E(arPublicFacet).getPublicTopics(); + assert.equal(metrics, publicTopics.metrics.subscriber); + + metricsRecord = await E(metrics).getUpdateSince(); + + // same as last + assert.equal(metricsRecord.updateCount, 2n); + + // add more collateral + const amt = moola.make(20_000n); + const collateralSeat = addCollateral(amt); + + assert.equal( + await E(collateralSeat).getOfferResult(), + 'added Collateral to the Reserve', + ); + // new record + metricsRecord = await E(metrics).getUpdateSince( + metricsRecord.updateCount, + ); + // collateral continued up from last state + assert.equal( + metricsRecord.value.allocations.Moola.value, + 100_000n + amt.value, + ); + }, - testFunctionality2: async () => { - const arPublicFacet = await E( - governorFacets.creatorFacet, - ).getPublicFacet(); - - const publicTopics = await E(arPublicFacet).getPublicTopics(); - assert.equal(metrics, publicTopics.metrics.subscriber); - - metricsRecord = await E(metrics).getUpdateSince(); - - // same as last - assert.equal(metricsRecord.updateCount, 2n); - - // add more collateral - const amt = moola.make(20_000n); - const collateralSeat = addCollateral(amt); - - assert.equal( - await E(collateralSeat).getOfferResult(), - 'added Collateral to the Reserve', - ); - // new record - metricsRecord = await E(metrics).getUpdateSince( - metricsRecord.updateCount, - ); - // collateral continued up from last state - assert.equal( - metricsRecord.value.allocations.Moola.value, - 100_000n + amt.value, - ); + // this test doesn't upgrade to a new bundle because we have coverage elsewhere that + // a new bundle will replace the behavior of the prior bundle }, - - // this test doesn't upgrade to a new bundle because we have coverage elsewhere that - // a new bundle will replace the behavior of the prior bundle - }); + ); }; diff --git a/packages/inter-protocol/test/test-feeDistributor.js b/packages/inter-protocol/test/test-feeDistributor.js index b1d14509271..7286be073d5 100644 --- a/packages/inter-protocol/test/test-feeDistributor.js +++ b/packages/inter-protocol/test/test-feeDistributor.js @@ -30,12 +30,16 @@ const makeFakeFeeDepositFacetKit = feeIssuer => { const makeFakeFeeProducer = (makeEmptyPayment = () => {}) => { const feePayments = []; - return Far('feeCollector', { - collectFees: () => feePayments.shift() || makeEmptyPayment(), - - // tools for the fake: - pushFees: payment => feePayments.push(payment), - }); + return makeExo( + 'feeCollector', + M.interface('feeCollector', {}, { defaultGuards: 'passable' }), + { + collectFees: () => feePayments.shift() || makeEmptyPayment(), + + // tools for the fake: + pushFees: payment => feePayments.push(payment), + }, + ); }; /** * @param {any} t @@ -245,7 +249,11 @@ test('fee distribution, leftovers', async t => { }); test('feeDistributor custom terms shape catches non-Nat bigint', t => { - const timerService = Far('MockTimer', {}); + const timerService = makeExo( + 'MockTimer', + M.interface('MockTimer', {}, { defaultGuards: 'passable' }), + {}, + ); t.throws( () => mustMatch( diff --git a/packages/inter-protocol/test/test-interest-labeled.js b/packages/inter-protocol/test/test-interest-labeled.js index ac63dbac354..ba9dfc36b68 100644 --- a/packages/inter-protocol/test/test-interest-labeled.js +++ b/packages/inter-protocol/test/test-interest-labeled.js @@ -8,11 +8,15 @@ import { TimeMath } from '@agoric/time'; import { makeInterestCalculator, SECONDS_PER_YEAR } from '../src/interest.js'; -const timerBrand = Far('fake timer brand', { - isMyTimerService: () => true, - isMyClock: () => true, -}); -// const otherTimerBrand = Far('other fake timer brand', {}); +const timerBrand = makeExo( + 'fake timer brand', + M.interface('fake timer brand', {}, { defaultGuards: 'passable' }), + { + isMyTimerService: () => true, + isMyClock: () => true, + }, +); +// const otherTimerBrand = makeExo('other fake timer brand', M.interface('other fake timer brand', {}, { defaultGuards: 'passable' }), {}); const ONE_DAY = TimeMath.coerceRelativeTimeRecord(60n * 60n * 24n, timerBrand); const ONE_MONTH = TimeMath.multiplyRelNat(ONE_DAY, 30n); diff --git a/packages/inter-protocol/test/test-provisionPool.js b/packages/inter-protocol/test/test-provisionPool.js index ef53965c3fc..ccc8bf5579f 100644 --- a/packages/inter-protocol/test/test-provisionPool.js +++ b/packages/inter-protocol/test/test-provisionPool.js @@ -310,12 +310,24 @@ const makeWalletFactoryKitForAddresses = async addresses => { const wallets = new Map( addresses.map(addr => { const purse = /** @type {Purse} */ (purses.get(addr)); - const mockWallet = Far('mock wallet', { - getDepositFacet: () => - Far('mock depositFacet', { - receive: payment => E(purse).deposit(payment), - }), - }); + const mockWallet = makeExo( + 'mock wallet', + M.interface('mock wallet', {}, { defaultGuards: 'passable' }), + { + getDepositFacet: () => + makeExo( + 'mock depositFacet', + M.interface( + 'mock depositFacet', + {}, + { defaultGuards: 'passable' }, + ), + { + receive: payment => E(purse).deposit(payment), + }, + ), + }, + ); return [addr, mockWallet]; }), ); @@ -329,25 +341,29 @@ const makeWalletFactoryKitForAddresses = async addresses => { const done = new Set(); /** @type {import('@agoric/vats/src/core/startWalletFactory.js').WalletFactoryStartResult['creatorFacet']} */ - const walletFactory = Far('mock walletFactory', { - provideSmartWallet: async (addr, _b, nameAdmin) => { - const wallet = wallets.get(addr); - assert(wallet); - - let isNew = !done.has(addr); - if (isNew) { - const isRevive = - walletReviver && (await E(walletReviver).ackWallet(addr)); - if (isRevive) { - isNew = false; - } else { - await publishDepositFacet(addr, wallet, nameAdmin); + const walletFactory = makeExo( + 'mock walletFactory', + M.interface('mock walletFactory', {}, { defaultGuards: 'passable' }), + { + provideSmartWallet: async (addr, _b, nameAdmin) => { + const wallet = wallets.get(addr); + assert(wallet); + + let isNew = !done.has(addr); + if (isNew) { + const isRevive = + walletReviver && (await E(walletReviver).ackWallet(addr)); + if (isRevive) { + isNew = false; + } else { + await publishDepositFacet(addr, wallet, nameAdmin); + } + done.add(addr); } - done.add(addr); - } - return [wallet, isNew]; + return [wallet, isNew]; + }, }, - }); + ); return { fees, diff --git a/packages/inter-protocol/test/vaultFactory/faucet.js b/packages/inter-protocol/test/vaultFactory/faucet.js index 1edee2d1eaf..0ad3a813c1b 100644 --- a/packages/inter-protocol/test/vaultFactory/faucet.js +++ b/packages/inter-protocol/test/vaultFactory/faucet.js @@ -27,6 +27,10 @@ export async function start(zcf, { feeMintAccess }) { return zcf.makeInvitation(faucetHook, 'provide RUN'); } - const creatorFacet = Far('faucetInvitationMaker', { makeFaucetInvitation }); + const creatorFacet = makeExo( + 'faucetInvitationMaker', + M.interface('faucetInvitationMaker', {}, { defaultGuards: 'passable' }), + { makeFaucetInvitation }, + ); return harden({ creatorFacet }); } diff --git a/packages/inter-protocol/test/vaultFactory/interestSupport.js b/packages/inter-protocol/test/vaultFactory/interestSupport.js index 56640d403a7..6782acd2303 100644 --- a/packages/inter-protocol/test/vaultFactory/interestSupport.js +++ b/packages/inter-protocol/test/vaultFactory/interestSupport.js @@ -38,21 +38,25 @@ export const makeFakeVault = ( ); let collateral = initCollateral; const fakeSeat = {}; - const vault = Far('Vault', { - getCollateralAmount: () => collateral, - getNormalizedDebt: () => normalizedDebt, - getCurrentDebt: () => - floorMultiplyBy(normalizedDebt, manager.getCompoundedInterest()), - setDebt: newDebt => - (normalizedDebt = reverseInterest( - newDebt, - manager.getCompoundedInterest(), - )), - setCollateral: newCollateral => (collateral = newCollateral), - getIdInManager: () => vaultId, - liquidate: () => {}, - getVaultSeat: () => fakeSeat, - }); + const vault = makeExo( + 'Vault', + M.interface('Vault', {}, { defaultGuards: 'passable' }), + { + getCollateralAmount: () => collateral, + getNormalizedDebt: () => normalizedDebt, + getCurrentDebt: () => + floorMultiplyBy(normalizedDebt, manager.getCompoundedInterest()), + setDebt: newDebt => + (normalizedDebt = reverseInterest( + newDebt, + manager.getCompoundedInterest(), + )), + setCollateral: newCollateral => (collateral = newCollateral), + getIdInManager: () => vaultId, + liquidate: () => {}, + getVaultSeat: () => fakeSeat, + }, + ); // @ts-expect-error cast return vault; }; diff --git a/packages/inter-protocol/test/vaultFactory/vault-contract-wrapper.js b/packages/inter-protocol/test/vaultFactory/vault-contract-wrapper.js index e403f71029f..6633e04ec69 100644 --- a/packages/inter-protocol/test/vaultFactory/vault-contract-wrapper.js +++ b/packages/inter-protocol/test/vaultFactory/vault-contract-wrapper.js @@ -119,60 +119,64 @@ export async function start(zcf, privateArgs, baggage) { }; /** @type {Parameters[0]} */ - const managerMock = Far('vault manager mock', { - getGovernedParams() { - return { - getDebtLimit() { - throw Error('not implemented'); - }, - getLiquidationMargin() { - return LIQUIDATION_MARGIN; - }, - getLiquidationPenalty() { - throw Error('not implemented'); - }, - getMintFee() { - return makeRatio(500n, stableBrand, BASIS_POINTS); - }, - getInterestRate() { - return currentInterest; - }, - getChargingPeriod() { - return DAY; - }, - getLiquidationPadding() { - // XXX re-use - return LIQUIDATION_MARGIN; - }, - getMinInitialDebt() { - return AmountMath.makeEmpty(stableBrand); - }, - getRecordingPeriod() { - return DAY; - }, - }; + const managerMock = makeExo( + 'vault manager mock', + M.interface('vault manager mock', {}, { defaultGuards: 'passable' }), + { + getGovernedParams() { + return { + getDebtLimit() { + throw Error('not implemented'); + }, + getLiquidationMargin() { + return LIQUIDATION_MARGIN; + }, + getLiquidationPenalty() { + throw Error('not implemented'); + }, + getMintFee() { + return makeRatio(500n, stableBrand, BASIS_POINTS); + }, + getInterestRate() { + return currentInterest; + }, + getChargingPeriod() { + return DAY; + }, + getLiquidationPadding() { + // XXX re-use + return LIQUIDATION_MARGIN; + }, + getMinInitialDebt() { + return AmountMath.makeEmpty(stableBrand); + }, + getRecordingPeriod() { + return DAY; + }, + }; + }, + getCollateralBrand() { + return collateralBrand; + }, + getDebtBrand: () => stableBrand, + + getAssetSubscriber: () => assetSubscriber, + maxDebtFor, + mintAndTransfer, + burn, + getCollateralQuote() { + return Promise.reject(Error('Not implemented')); + }, + getCompoundedInterest: () => compoundedInterest, + scopeDescription: base => `VCW: ${base}`, + handleBalanceChange: () => { + console.warn('mock handleBalanceChange does nothing'); + }, + mintforVault: async amount => { + stableMint.mintGains({ Minted: amount }); + }, }, - getCollateralBrand() { - return collateralBrand; - }, - getDebtBrand: () => stableBrand, - - getAssetSubscriber: () => assetSubscriber, - maxDebtFor, - mintAndTransfer, - burn, - getCollateralQuote() { - return Promise.reject(Error('Not implemented')); - }, - getCompoundedInterest: () => compoundedInterest, - scopeDescription: base => `VCW: ${base}`, - handleBalanceChange: () => { - console.warn('mock handleBalanceChange does nothing'); - }, - mintforVault: async amount => { - stableMint.mintGains({ Minted: amount }); - }, - }); + ); const makeRecorderKit = prepareRecorderKit(baggage, marshaller); @@ -217,24 +221,32 @@ export async function start(zcf, privateArgs, baggage) { vault, stableMint, collateralKit, - actions: Far('vault actions', { - add() { - return vaultKit.invitationMakers.AdjustBalances(); + actions: makeExo( + 'vault actions', + M.interface('vault actions', {}, { defaultGuards: 'passable' }), + { + add() { + return vaultKit.invitationMakers.AdjustBalances(); + }, }, - }), + ), }; } console.log(`makeContract returning`); - const vaultAPI = Far('vaultAPI', { - makeAdjustBalancesInvitation() { - return vault.makeAdjustBalancesInvitation(); - }, - mintRun(amount) { - return paymentFromZCFMint(zcf, stableMint, amount); + const vaultAPI = makeExo( + 'vaultAPI', + M.interface('vaultAPI', {}, { defaultGuards: 'passable' }), + { + makeAdjustBalancesInvitation() { + return vault.makeAdjustBalancesInvitation(); + }, + mintRun(amount) { + return paymentFromZCFMint(zcf, stableMint, amount); + }, }, - }); + ); const testInvitation = zcf.makeInvitation(makeHook, 'foo'); return harden({ creatorInvitation: testInvitation, creatorFacet: vaultAPI }); diff --git a/packages/internal/src/marshal.js b/packages/internal/src/marshal.js index fadbfc5d535..0d8c40bdbc6 100644 --- a/packages/internal/src/marshal.js +++ b/packages/internal/src/marshal.js @@ -17,7 +17,7 @@ const { Fail } = assert; */ export const makeBoardRemote = ({ boardId, iface }) => { const nonalleged = iface ? iface.replace(/^Alleged: /, '') : ''; - return Far(`BoardRemote${nonalleged}`, { getBoardId: () => boardId }); + return makeExo(`BoardRemote${nonalleged}`, M.interface(`BoardRemote${nonalleged}`, {}, { defaultGuards: 'passable' }), { getBoardId: () => boardId }); }; /** diff --git a/packages/internal/src/priority-senders.js b/packages/internal/src/priority-senders.js index 28d5ef99938..79ebd265dda 100644 --- a/packages/internal/src/priority-senders.js +++ b/packages/internal/src/priority-senders.js @@ -53,51 +53,57 @@ export const makePrioritySendersManager = sendersNode => { return r; }; - return Far('prioritySenders manager', { - /** - * @param {string} rawNamespace - * @param {string} address - * @returns {Promise} - */ - add: async (rawNamespace, address) => { - const namespace = normalizeSenderNamespace(rawNamespace); + return makeExo( + 'prioritySenders manager', + M.interface('prioritySenders manager', {}, { defaultGuards: 'passable' }), + { + /** + * @param {string} rawNamespace + * @param {string} address + * @returns {Promise} + */ + add: async (rawNamespace, address) => { + const namespace = normalizeSenderNamespace(rawNamespace); - const record = await provideRecordForAddress(address); + const record = await provideRecordForAddress(address); - const [node, namespaces] = record; - if (namespaces.has(namespace)) { - throw Fail`namespace ${q(namespace)} already has address ${q(address)}`; - } - namespaces.add(namespace); + const [node, namespaces] = record; + if (namespaces.has(namespace)) { + throw Fail`namespace ${q(namespace)} already has address ${q( + address, + )}`; + } + namespaces.add(namespace); - return refreshVstorage(node, namespaces); - }, - /** - * @param {string} rawNamespace - * @param {string} address - * @returns {Promise} - */ - remove: (rawNamespace, address) => { - const namespace = normalizeSenderNamespace(rawNamespace); - const record = addressRecords.get(address); - if (!record) { - throw Fail`address not registered: ${q(address)}`; - } - const [node, namespaces] = record; - if (!namespaces.has(namespace)) { - throw Fail`namespace ${q(namespace)} does not have address ${q( - address, - )}`; - } + return refreshVstorage(node, namespaces); + }, + /** + * @param {string} rawNamespace + * @param {string} address + * @returns {Promise} + */ + remove: (rawNamespace, address) => { + const namespace = normalizeSenderNamespace(rawNamespace); + const record = addressRecords.get(address); + if (!record) { + throw Fail`address not registered: ${q(address)}`; + } + const [node, namespaces] = record; + if (!namespaces.has(namespace)) { + throw Fail`namespace ${q(namespace)} does not have address ${q( + address, + )}`; + } - namespaces.delete(namespace); - if (namespaces.size === 0) { - addressRecords.delete(address); - } + namespaces.delete(namespace); + if (namespaces.size === 0) { + addressRecords.delete(address); + } - return refreshVstorage(node, namespaces); + return refreshVstorage(node, namespaces); + }, }, - }); + ); }; harden(makePrioritySendersManager); diff --git a/packages/internal/src/scratch.js b/packages/internal/src/scratch.js index 4434d1592ea..b7c2171bc2c 100644 --- a/packages/internal/src/scratch.js +++ b/packages/internal/src/scratch.js @@ -8,45 +8,49 @@ export default function makeScratchPad() { return harden(keyList.sort()); }; - const scratch = Far('scratchPad', { - delete: async keyP => { - const key = await keyP; - map.delete(key); + const scratch = makeExo( + 'scratchPad', + M.interface('scratchPad', {}, { defaultGuards: 'passable' }), + { + delete: async keyP => { + const key = await keyP; + map.delete(key); + }, + get: async keyP => { + const key = await keyP; + return map.get(key); + }, + lookup: (...path) => { + if (path.length === 0) { + return scratch; + } + const [first, ...rest] = path; + const firstValue = E(scratch).get(first); + if (rest.length === 0) { + return firstValue; + } + return E(firstValue).lookup(...rest); + }, + // Initialize a key only if it doesn't already exist. Needed for atomicity + // between multiple invocations. + init: async (keyP, objP) => { + const [key, obj] = await Promise.all([keyP, objP]); + if (map.has(key)) { + throw Error(`Scratchpad already has key ${key}`); + } + map.set(key, obj); + return key; + }, + keys, + // Legacy alias for `keys`. + list: keys, + set: async (keyP, objP) => { + const [key, obj] = await Promise.all([keyP, objP]); + map.set(key, obj); + return key; + }, }, - get: async keyP => { - const key = await keyP; - return map.get(key); - }, - lookup: (...path) => { - if (path.length === 0) { - return scratch; - } - const [first, ...rest] = path; - const firstValue = E(scratch).get(first); - if (rest.length === 0) { - return firstValue; - } - return E(firstValue).lookup(...rest); - }, - // Initialize a key only if it doesn't already exist. Needed for atomicity - // between multiple invocations. - init: async (keyP, objP) => { - const [key, obj] = await Promise.all([keyP, objP]); - if (map.has(key)) { - throw Error(`Scratchpad already has key ${key}`); - } - map.set(key, obj); - return key; - }, - keys, - // Legacy alias for `keys`. - list: keys, - set: async (keyP, objP) => { - const [key, obj] = await Promise.all([keyP, objP]); - map.set(key, obj); - return key; - }, - }); + ); return scratch; } /** @typedef {ReturnType} ScratchPad */ diff --git a/packages/internal/src/storage-test-utils.js b/packages/internal/src/storage-test-utils.js index e843daa4dfb..cf1ae302aa2 100644 --- a/packages/internal/src/storage-test-utils.js +++ b/packages/internal/src/storage-test-utils.js @@ -58,7 +58,10 @@ export const defaultMarshaller = makeMarshal(undefined, slotToRemotable, { */ const makeSlotStringUnserialize = () => { /** @type { (slot: string, iface: string) => any } */ - const identitySlotToValFn = (slot, _) => Far('unk', { toJSON: () => slot }); + const identitySlotToValFn = (slot, _) => + makeExo('unk', M.interface('unk', {}, { defaultGuards: 'passable' }), { + toJSON: () => slot, + }); const { fromCapData } = makeMarshal(undefined, identitySlotToValFn); /** @type { (capData: any) => any } */ const unserialize = capData => @@ -205,27 +208,31 @@ harden(makeFakeStorageKit); export const makeMockChainStorageRoot = () => { const { rootNode, data } = makeFakeStorageKit('mockChainStorageRoot'); - return Far('mockChainStorage', { - ...bindAllMethods(rootNode), - /** - * Defaults to deserializing slot references into plain Remotable - * objects having the specified interface name (as from `Far(iface)`), - * but can accept a different marshaller for producing Remotables - * that e.g. embed the slot string in their iface name. - * - * @param {string} path - * @param {import('./lib-chainStorage.js').Marshaller} marshaller - * @param {number} [index] - * @returns {unknown} - */ - getBody: (path, marshaller = defaultMarshaller, index = -1) => { - data.size || Fail`no data in storage`; - /** @type {ReturnType['fromCapData']} */ - const fromCapData = (...args) => - Reflect.apply(marshaller.fromCapData, marshaller, args); - return unmarshalFromVstorage(data, path, fromCapData, index); + return makeExo( + 'mockChainStorage', + M.interface('mockChainStorage', {}, { defaultGuards: 'passable' }), + { + ...bindAllMethods(rootNode), + /** + * Defaults to deserializing slot references into plain Remotable + * objects having the specified interface name (as from `Far(iface)`), + * but can accept a different marshaller for producing Remotables + * that e.g. embed the slot string in their iface name. + * + * @param {string} path + * @param {import('./lib-chainStorage.js').Marshaller} marshaller + * @param {number} [index] + * @returns {unknown} + */ + getBody: (path, marshaller = defaultMarshaller, index = -1) => { + data.size || Fail`no data in storage`; + /** @type {ReturnType['fromCapData']} */ + const fromCapData = (...args) => + Reflect.apply(marshaller.fromCapData, marshaller, args); + return unmarshalFromVstorage(data, path, fromCapData, index); + }, + keys: () => [...data.keys()], }, - keys: () => [...data.keys()], - }); + ); }; /** @typedef {ReturnType} MockChainStorageRoot */ diff --git a/packages/internal/test/test-callback.js b/packages/internal/test/test-callback.js index ca23cec186c..8dc0852da05 100644 --- a/packages/internal/test/test-callback.js +++ b/packages/internal/test/test-callback.js @@ -121,29 +121,33 @@ test('near method callbacks', t => { test('far method callbacks', async t => { const m2 = Symbol.for('m2'); - const o = Far('MyObject', { - /** - * - * @param {number} a - * @param {number} b - * @param {string} c - * @returns {Promise} - */ - async m1(a, b, c) { - return `${a + b}${c}`; + const o = makeExo( + 'MyObject', + M.interface('MyObject', {}, { defaultGuards: 'passable' }), + { + /** + * + * @param {number} a + * @param {number} b + * @param {string} c + * @returns {Promise} + */ + async m1(a, b, c) { + return `${a + b}${c}`; + }, + + /** + * + * @param {number} a + * @param {number} b + * @param {string} c + * @returns {Promise} + */ + [m2]: async (a, b, c) => { + return `${a + b}${c}`; + }, }, - - /** - * - * @param {number} a - * @param {number} b - * @param {string} c - * @returns {Promise} - */ - [m2]: async (a, b, c) => { - return `${a + b}${c}`; - }, - }); + ); /** @type {import('../src/callback.js').Callback<(c: string) => Promise>} */ const cbp2 = cb.makeMethodCallback(Promise.resolve(o), 'm1', 9, 10); @@ -267,20 +271,24 @@ test('isCallback', t => { test('makeAttenuator', async t => { const zone = makeHeapZone(); const makeAttenuator = cb.prepareAttenuator(zone, ['m0', 'm1', 'm2', 'm4']); - const target = Far('original', { - m0() { - return 'return original.m0'; + const target = makeExo( + 'original', + M.interface('original', {}, { defaultGuards: 'passable' }), + { + m0() { + return 'return original.m0'; + }, + m1() { + return 'return original.m1'; + }, + m2() { + throw Error('unexpected original.m2'); + }, + m3() { + throw Error('unexpected original.m3'); + }, }, - m1() { - return 'return original.m1'; - }, - m2() { - throw Error('unexpected original.m2'); - }, - m3() { - throw Error('unexpected original.m3'); - }, - }); + ); // @ts-expect-error deliberate: omitted method t.throws(() => makeAttenuator({ target, overrides: { m3: null } }), { message: `"Attenuator" overrides["m3"] not allowed by methodNames`, diff --git a/packages/internal/test/test-storage-test-utils.js b/packages/internal/test/test-storage-test-utils.js index 5eab748c657..d47e1eb6533 100644 --- a/packages/internal/test/test-storage-test-utils.js +++ b/packages/internal/test/test-storage-test-utils.js @@ -272,10 +272,22 @@ const testUnmarshaller = test.macro((t, format) => { // create capdata with specific slots /** @typedef { { getBoardId: () => string } } SlottedRemotable */ const foo = Far('foo'); - const foo1 = Far('foo', { getBoardId: () => 'board1' }); - const foo2 = Far('foo', { getBoardId: () => 'board2' }); + const foo1 = makeExo( + 'foo', + M.interface('foo', {}, { defaultGuards: 'passable' }), + { getBoardId: () => 'board1' }, + ); + const foo2 = makeExo( + 'foo', + M.interface('foo', {}, { defaultGuards: 'passable' }), + { getBoardId: () => 'board2' }, + ); const bar = Far('bar'); - const bar1 = Far('bar', { getBoardId: () => 'board1' }); + const bar1 = makeExo( + 'bar', + M.interface('bar', {}, { defaultGuards: 'passable' }), + { getBoardId: () => 'board1' }, + ); const foo1CD = m.toCapData(harden({ o: foo1 })); const foo2CD = m.toCapData(harden({ o: foo2 })); const bar1CD = m.toCapData(harden({ o: bar1 })); diff --git a/packages/internal/test/test-utils.js b/packages/internal/test/test-utils.js index 5126686a6fb..d3a40837352 100644 --- a/packages/internal/test/test-utils.js +++ b/packages/internal/test/test-utils.js @@ -13,7 +13,11 @@ import { } from '../src/utils.js'; test('deeplyFulfilledObject', async t => { - const someFar = Far('somefar', { getAsync: () => Promise.resolve('async') }); + const someFar = makeExo( + 'somefar', + M.interface('somefar', {}, { defaultGuards: 'passable' }), + { getAsync: () => Promise.resolve('async') }, + ); const unfulfilled = harden({ obj1: { obj2a: { diff --git a/packages/notifier/src/notifier.js b/packages/notifier/src/notifier.js index 7dab8342038..512ac602d61 100644 --- a/packages/notifier/src/notifier.js +++ b/packages/notifier/src/notifier.js @@ -14,25 +14,29 @@ import { subscribeLatest } from './subscribe.js'; */ export const makeNotifier = sharableInternalsP => { /** @type {Notifier} */ - const notifier = Far('notifier', { - ...subscribeLatest(sharableInternalsP), - getUpdateSince: async updateCount => - E(sharableInternalsP).getUpdateSince(updateCount), - - /** - * Use this to distribute a Notifier efficiently over the network, - * by obtaining this from the Notifier to be replicated, and applying - * `makeNotifier` to it at the new site to get an equivalent local - * Notifier at that site. - */ - getSharableNotifierInternals: async () => sharableInternalsP, - /** - * @deprecated - * Used only by `makeCastingSpecFromRef`. Instead that function should use - * the `StoredFacet` API. - */ - getStoreKey: () => harden({ notifier }), - }); + const notifier = makeExo( + 'notifier', + M.interface('notifier', {}, { defaultGuards: 'passable' }), + { + ...subscribeLatest(sharableInternalsP), + getUpdateSince: async updateCount => + E(sharableInternalsP).getUpdateSince(updateCount), + + /** + * Use this to distribute a Notifier efficiently over the network, + * by obtaining this from the Notifier to be replicated, and applying + * `makeNotifier` to it at the new site to get an equivalent local + * Notifier at that site. + */ + getSharableNotifierInternals: async () => sharableInternalsP, + /** + * @deprecated + * Used only by `makeCastingSpecFromRef`. Instead that function should use + * the `StoredFacet` API. + */ + getStoreKey: () => harden({ notifier }), + }, + ); return notifier; }; @@ -51,10 +55,14 @@ export const makeNotifierFromSubscriber = subscriber => { }); /** @type {Notifier} */ - const notifier = Far('notifier', { - ...makeNotifier(baseNotifier), - ...baseNotifier, - }); + const notifier = makeExo( + 'notifier', + M.interface('notifier', {}, { defaultGuards: 'passable' }), + { + ...makeNotifier(baseNotifier), + ...baseNotifier, + }, + ); return notifier; }; harden(makeNotifierFromSubscriber); @@ -82,11 +90,15 @@ export const makeNotifierKit = (...initialStateArr) => { const notifier = makeNotifierFromSubscriber(subscriber); - const updater = Far('updater', { - updateState: state => publisher.publish(state), - finish: completion => publisher.finish(completion), - fail: reason => publisher.fail(reason), - }); + const updater = makeExo( + 'updater', + M.interface('updater', {}, { defaultGuards: 'passable' }), + { + updateState: state => publisher.publish(state), + finish: completion => publisher.finish(completion), + fail: reason => publisher.fail(reason), + }, + ); assert(initialStateArr.length <= 1, 'too many arguments'); if (initialStateArr.length === 1) { @@ -123,61 +135,69 @@ export const makeNotifierFromAsyncIterable = asyncIterableP => { /** * @type {LatestTopic} */ - const baseNotifier = Far('baseNotifier', { - getUpdateSince(updateCount = -1n) { - if (updateCount < currentUpdateCount) { - if (currentResponse) { + const baseNotifier = makeExo( + 'baseNotifier', + M.interface('baseNotifier', {}, { defaultGuards: 'passable' }), + { + getUpdateSince(updateCount = -1n) { + if (updateCount < currentUpdateCount) { + if (currentResponse) { + return Promise.resolve(currentResponse); + } + } else if (updateCount !== currentUpdateCount) { + throw Error( + 'getUpdateSince argument must be a previously-issued updateCount.', + ); + } + + // Return a final response if we have one, otherwise a promise for the next state. + if (final) { + assert(currentResponse !== undefined); return Promise.resolve(currentResponse); } - } else if (updateCount !== currentUpdateCount) { - throw Error( - 'getUpdateSince argument must be a previously-issued updateCount.', - ); - } - - // Return a final response if we have one, otherwise a promise for the next state. - if (final) { - assert(currentResponse !== undefined); - return Promise.resolve(currentResponse); - } - if (!optNextPromise) { - const nextIterResultP = E(iteratorP).next(); - optNextPromise = E.when( - nextIterResultP, - ({ done, value }) => { - assert(!final); - if (done) { + if (!optNextPromise) { + const nextIterResultP = E(iteratorP).next(); + optNextPromise = E.when( + nextIterResultP, + ({ done, value }) => { + assert(!final); + if (done) { + final = true; + } + currentUpdateCount += 1n; + currentResponse = harden({ + value, + updateCount: done ? undefined : currentUpdateCount, + }); + optNextPromise = undefined; + return currentResponse; + }, + _reason => { final = true; - } - currentUpdateCount += 1n; - currentResponse = harden({ - value, - updateCount: done ? undefined : currentUpdateCount, - }); - optNextPromise = undefined; - return currentResponse; - }, - _reason => { - final = true; - currentResponse = - /** @type {Promise>} */ - (nextIterResultP); - optNextPromise = undefined; - return currentResponse; - }, - ); - } - return optNextPromise; + currentResponse = + /** @type {Promise>} */ + (nextIterResultP); + optNextPromise = undefined; + return currentResponse; + }, + ); + } + return optNextPromise; + }, }, - }); + ); /** @type {Notifier} */ - const notifier = Far('notifier', { - // Don't leak the original asyncIterableP since it may be remote and we also - // want the same semantics for this exposed iterable and the baseNotifier. - ...makeNotifier(baseNotifier), - ...baseNotifier, - }); + const notifier = makeExo( + 'notifier', + M.interface('notifier', {}, { defaultGuards: 'passable' }), + { + // Don't leak the original asyncIterableP since it may be remote and we also + // want the same semantics for this exposed iterable and the baseNotifier. + ...makeNotifier(baseNotifier), + ...baseNotifier, + }, + ); return notifier; }; harden(makeNotifierFromAsyncIterable); diff --git a/packages/notifier/src/publish-kit.js b/packages/notifier/src/publish-kit.js index e3ab7496c68..52c46892bb0 100644 --- a/packages/notifier/src/publish-kit.js +++ b/packages/notifier/src/publish-kit.js @@ -152,49 +152,57 @@ export const makePublishKit = () => { * @template T * @type {Subscriber} */ - const subscriber = Far('Subscriber', { - subscribeAfter: (publishCount = -1n) => { - assert.typeof(publishCount, 'bigint'); - if (publishCount === currentPublishCount) { - return tailP; - } else if (publishCount < currentPublishCount) { - return currentP; - } else { - throw Error( - 'subscribeAfter argument must be a previously-issued publishCount.', + const subscriber = makeExo( + 'Subscriber', + M.interface('Subscriber', {}, { defaultGuards: 'passable' }), + { + subscribeAfter: (publishCount = -1n) => { + assert.typeof(publishCount, 'bigint'); + if (publishCount === currentPublishCount) { + return tailP; + } else if (publishCount < currentPublishCount) { + return currentP; + } else { + throw Error( + 'subscribeAfter argument must be a previously-issued publishCount.', + ); + } + }, + getUpdateSince: updateCount => { + if (updateCount === undefined) { + return subscriber.subscribeAfter().then(makeMemoizedUpdateRecord); + } + updateCount = BigInt(updateCount); + return ( + subscriber + // `subscribeAfter` may resolve with the update record numbered + // `updateCount + 1`, even if several updates are published in the + // same crank... + .subscribeAfter(updateCount) + // ... so we poll the latest published update, without waiting for any + // further ones. + .then(() => subscriber.getUpdateSince()) ); - } - }, - getUpdateSince: updateCount => { - if (updateCount === undefined) { - return subscriber.subscribeAfter().then(makeMemoizedUpdateRecord); - } - updateCount = BigInt(updateCount); - return ( - subscriber - // `subscribeAfter` may resolve with the update record numbered - // `updateCount + 1`, even if several updates are published in the - // same crank... - .subscribeAfter(updateCount) - // ... so we poll the latest published update, without waiting for any - // further ones. - .then(() => subscriber.getUpdateSince()) - ); + }, }, - }); + ); /** @type {Publisher} */ - const publisher = Far('Publisher', { - publish: value => { - advanceCurrent(false, value); - }, - finish: finalValue => { - advanceCurrent(true, finalValue); - }, - fail: reason => { - advanceCurrent(true, undefined, makeQuietRejection(reason)); + const publisher = makeExo( + 'Publisher', + M.interface('Publisher', {}, { defaultGuards: 'passable' }), + { + publish: value => { + advanceCurrent(false, value); + }, + finish: finalValue => { + advanceCurrent(true, finalValue); + }, + fail: reason => { + advanceCurrent(true, undefined, makeQuietRejection(reason)); + }, }, - }); + ); return harden({ publisher, subscriber }); }; harden(makePublishKit); diff --git a/packages/notifier/src/stored-notifier.js b/packages/notifier/src/stored-notifier.js index 24b639b89b1..82e770977ed 100644 --- a/packages/notifier/src/stored-notifier.js +++ b/packages/notifier/src/stored-notifier.js @@ -44,16 +44,24 @@ export const makeStoredNotifier = (notifier, storageNode, marshaller) => { }); /** @type {Unserializer} */ - const unserializer = Far('unserializer', { - fromCapData: data => E(marshaller).fromCapData(data), - unserialize: data => E(marshaller).fromCapData(data), - }); + const unserializer = makeExo( + 'unserializer', + M.interface('unserializer', {}, { defaultGuards: 'passable' }), + { + fromCapData: data => E(marshaller).fromCapData(data), + unserialize: data => E(marshaller).fromCapData(data), + }, + ); /** @type {StoredNotifier} */ - const storedNotifier = Far('StoredNotifier', { - getUpdateSince: updateCount => E(notifier).getUpdateSince(updateCount), - getPath: () => E(storageNode).getPath(), - getUnserializer: () => unserializer, - }); + const storedNotifier = makeExo( + 'StoredNotifier', + M.interface('StoredNotifier', {}, { defaultGuards: 'passable' }), + { + getUpdateSince: updateCount => E(notifier).getUpdateSince(updateCount), + getPath: () => E(storageNode).getPath(), + getUnserializer: () => unserializer, + }, + ); return storedNotifier; }; diff --git a/packages/notifier/src/storesub.js b/packages/notifier/src/storesub.js index 3389b2b6cb9..6238e2e4d26 100644 --- a/packages/notifier/src/storesub.js +++ b/packages/notifier/src/storesub.js @@ -57,19 +57,27 @@ export const makeStoredSubscriber = (subscriber, storageNode, marshaller) => { }); /** @type {Unserializer} */ - const unserializer = Far('unserializer', { - fromCapData: data => E(marshaller).fromCapData(data), - unserialize: data => E(marshaller).fromCapData(data), - }); + const unserializer = makeExo( + 'unserializer', + M.interface('unserializer', {}, { defaultGuards: 'passable' }), + { + fromCapData: data => E(marshaller).fromCapData(data), + unserialize: data => E(marshaller).fromCapData(data), + }, + ); /** @type {StoredSubscriber} */ - const storesub = Far('StoredSubscriber', { - subscribeAfter: publishCount => subscriber.subscribeAfter(publishCount), - getUpdateSince: updateCount => subscriber.getUpdateSince(updateCount), - getPath: () => E(storageNode).getPath(), - getStoreKey: () => E(storageNode).getStoreKey(), - getUnserializer: () => unserializer, - }); + const storesub = makeExo( + 'StoredSubscriber', + M.interface('StoredSubscriber', {}, { defaultGuards: 'passable' }), + { + subscribeAfter: publishCount => subscriber.subscribeAfter(publishCount), + getUpdateSince: updateCount => subscriber.getUpdateSince(updateCount), + getPath: () => E(storageNode).getPath(), + getStoreKey: () => E(storageNode).getStoreKey(), + getUnserializer: () => unserializer, + }, + ); return storesub; }; @@ -98,10 +106,14 @@ export const makeStoredSubscription = ( }), ) => { /** @type {Unserializer} */ - const unserializer = Far('unserializer', { - fromCapData: data => E(marshaller).fromCapData(data), - unserialize: data => E(marshaller).fromCapData(data), - }); + const unserializer = makeExo( + 'unserializer', + M.interface('unserializer', {}, { defaultGuards: 'passable' }), + { + fromCapData: data => E(marshaller).fromCapData(data), + unserialize: data => E(marshaller).fromCapData(data), + }, + ); // Abort the iteration on the next observation if the publisher ever fails. let publishFailed = false; @@ -140,21 +152,25 @@ export const makeStoredSubscription = ( } /** @type {StoredSubscription} */ - const storesub = Far('StoredSubscription', { - // @ts-expect-error getStoreKey type does not have `subscription` - getStoreKey: async () => { - if (!storageNode) { - return harden({ subscription }); - } - const storeKey = await E(storageNode).getStoreKey(); - return harden({ ...storeKey, subscription }); + const storesub = makeExo( + 'StoredSubscription', + M.interface('StoredSubscription', {}, { defaultGuards: 'passable' }), + { + // @ts-expect-error getStoreKey type does not have `subscription` + getStoreKey: async () => { + if (!storageNode) { + return harden({ subscription }); + } + const storeKey = await E(storageNode).getStoreKey(); + return harden({ ...storeKey, subscription }); + }, + getUnserializer: () => unserializer, + getSharableSubscriptionInternals: () => + subscription.getSharableSubscriptionInternals(), + [Symbol.asyncIterator]: () => subscription[Symbol.asyncIterator](), + subscribeAfter: publishCount => subscription.subscribeAfter(publishCount), }, - getUnserializer: () => unserializer, - getSharableSubscriptionInternals: () => - subscription.getSharableSubscriptionInternals(), - [Symbol.asyncIterator]: () => subscription[Symbol.asyncIterator](), - subscribeAfter: publishCount => subscription.subscribeAfter(publishCount), - }); + ); return storesub; }; harden(makeStoredSubscription); diff --git a/packages/notifier/src/subscribe.js b/packages/notifier/src/subscribe.js index e35fa153cfa..0bb0992a755 100644 --- a/packages/notifier/src/subscribe.js +++ b/packages/notifier/src/subscribe.js @@ -65,16 +65,28 @@ const reconnectAsNeeded = async (getter, seed = []) => { * @param {ERef>} itP */ export const subscribe = itP => - Far('AsyncIterable', { - [Symbol.asyncIterator]: () => { - const it = E(itP)[Symbol.asyncIterator](); - const self = Far('AsyncIterableIterator', { - [Symbol.asyncIterator]: () => self, - next: async () => E(it).next(), - }); - return self; + makeExo( + 'AsyncIterable', + M.interface('AsyncIterable', {}, { defaultGuards: 'passable' }), + { + [Symbol.asyncIterator]: () => { + const it = E(itP)[Symbol.asyncIterator](); + const self = makeExo( + 'AsyncIterableIterator', + M.interface( + 'AsyncIterableIterator', + {}, + { defaultGuards: 'passable' }, + ), + { + [Symbol.asyncIterator]: () => self, + next: async () => E(it).next(), + }, + ); + return self; + }, }, - }); + ); /** * Asyncronously iterates over the contents of a PublicationRecord chain as they @@ -90,42 +102,46 @@ export const subscribe = itP => const makeEachIterator = (topic, nextCellP) => { // To understand the implementation, start with // https://web.archive.org/web/20160404122250/http://wiki.ecmascript.org/doku.php?id=strawman:concurrency#infinite_queue - const self = Far('EachIterator', { - [Symbol.asyncIterator]: () => self, - next: () => { - const { - head: resultP, - publishCount: publishCountP, - tail: tailP, - } = E.get(nextCellP); + const self = makeExo( + 'EachIterator', + M.interface('EachIterator', {}, { defaultGuards: 'passable' }), + { + [Symbol.asyncIterator]: () => self, + next: () => { + const { + head: resultP, + publishCount: publishCountP, + tail: tailP, + } = E.get(nextCellP); - // If tailP is broken by upgrade, we will need to re-request it - // directly from `topic`. - const getSuccessor = async () => { - const publishCount = await publishCountP; - assert.typeof(publishCount, 'bigint'); - const successor = await E(topic).subscribeAfter(publishCount); - const newPublishCount = successor.publishCount; - if (newPublishCount !== publishCount + 1n) { - Fail`eachIterator broken by gap from publishCount ${publishCount} to ${newPublishCount}`; - } - return successor; - }; + // If tailP is broken by upgrade, we will need to re-request it + // directly from `topic`. + const getSuccessor = async () => { + const publishCount = await publishCountP; + assert.typeof(publishCount, 'bigint'); + const successor = await E(topic).subscribeAfter(publishCount); + const newPublishCount = successor.publishCount; + if (newPublishCount !== publishCount + 1n) { + Fail`eachIterator broken by gap from publishCount ${publishCount} to ${newPublishCount}`; + } + return successor; + }; - // Replace nextCellP on every call to next() so things work even - // with an eager consumer that doesn't wait for results to settle. - nextCellP = reconnectAsNeeded(getSuccessor, [tailP]); + // Replace nextCellP on every call to next() so things work even + // with an eager consumer that doesn't wait for results to settle. + nextCellP = reconnectAsNeeded(getSuccessor, [tailP]); - // Avoid unhandled rejection warnings here if the previous cell was rejected or - // there is no further request of this iterator. - // `tailP` is handled inside `reconnectAsNeeded` and `resultP` is the caller's - // concern, leaving only `publishCountP` and the new `nextCellP`. - void E.when(publishCountP, sink, sink); - void E.when(nextCellP, sink, sink); - return resultP; + // Avoid unhandled rejection warnings here if the previous cell was rejected or + // there is no further request of this iterator. + // `tailP` is handled inside `reconnectAsNeeded` and `resultP` is the caller's + // concern, leaving only `publishCountP` and the new `nextCellP`. + void E.when(publishCountP, sink, sink); + void E.when(nextCellP, sink, sink); + return resultP; + }, + fork: () => makeEachIterator(topic, nextCellP), }, - fork: () => makeEachIterator(topic, nextCellP), - }); + ); return self; }; @@ -146,12 +162,16 @@ const makeEachIterator = (topic, nextCellP) => { * @param {ERef>} topic */ export const subscribeEach = topic => { - const iterable = Far('EachIterable', { - [Symbol.asyncIterator]: () => { - const firstCellP = reconnectAsNeeded(() => E(topic).subscribeAfter()); - return makeEachIterator(topic, firstCellP); + const iterable = makeExo( + 'EachIterable', + M.interface('EachIterable', {}, { defaultGuards: 'passable' }), + { + [Symbol.asyncIterator]: () => { + const firstCellP = reconnectAsNeeded(() => E(topic).subscribeAfter()); + return makeEachIterator(topic, firstCellP); + }, }, - }); + ); return iterable; }; harden(subscribeEach); @@ -195,43 +215,47 @@ const cloneLatestIterator = (topic, localUpdateCount, terminalResult) => { return harden({ done: false, value }); }; - const self = Far('LatestIterator', { - fork: () => cloneLatestIterator(topic, localUpdateCount, terminalResult), - [Symbol.asyncIterator]: () => self, - next: async () => { - // In this adaptor, once `next()` is called and returns an unresolved - // promise, further `next()` calls will also return unresolved promises - // but each call will not trigger another `topic` request until the prior - // one has settled. - // - // This linear queueing behavior is only needed for code that uses the - // async iterator protocol explicitly. When this async iterator is - // consumed by a for/await/of loop, `next()` will only be called after the - // promise for the previous iteration result has fulfilled. If it fulfills - // with `done: true`, the for/await/of loop will never call `next()` - // again. - // - // See - // https://2ality.com/2016/10/asynchronous-iteration.html#queuing-next()-invocations - // for an explicit use that sends `next()` without waiting. + const self = makeExo( + 'LatestIterator', + M.interface('LatestIterator', {}, { defaultGuards: 'passable' }), + { + fork: () => cloneLatestIterator(topic, localUpdateCount, terminalResult), + [Symbol.asyncIterator]: () => self, + next: async () => { + // In this adaptor, once `next()` is called and returns an unresolved + // promise, further `next()` calls will also return unresolved promises + // but each call will not trigger another `topic` request until the prior + // one has settled. + // + // This linear queueing behavior is only needed for code that uses the + // async iterator protocol explicitly. When this async iterator is + // consumed by a for/await/of loop, `next()` will only be called after the + // promise for the previous iteration result has fulfilled. If it fulfills + // with `done: true`, the for/await/of loop will never call `next()` + // again. + // + // See + // https://2ality.com/2016/10/asynchronous-iteration.html#queuing-next()-invocations + // for an explicit use that sends `next()` without waiting. - if (terminalResult) { - // We've reached the end of the topic, just keep returning the last - // result. - return terminalResult; - } + if (terminalResult) { + // We've reached the end of the topic, just keep returning the last + // result. + return terminalResult; + } - // BEGIN CRITICAL SECTION - synchronously enqueue and reassign `mutex` - // - // Use `mutex` to ensure that we have no more than a single request in - // flight. - const nextResult = mutex.then(maybeRequestNextResult); - mutex = nextResult.then(sink, sink); - // END CRITICAL SECTION + // BEGIN CRITICAL SECTION - synchronously enqueue and reassign `mutex` + // + // Use `mutex` to ensure that we have no more than a single request in + // flight. + const nextResult = mutex.then(maybeRequestNextResult); + mutex = nextResult.then(sink, sink); + // END CRITICAL SECTION - return nextResult; + return nextResult; + }, }, - }); + ); return self; }; @@ -256,9 +280,13 @@ const makeLatestIterator = topic => cloneLatestIterator(topic); * @param {ERef>} topic */ export const subscribeLatest = topic => { - const iterable = Far('LatestIterable', { - [Symbol.asyncIterator]: () => makeLatestIterator(topic), - }); + const iterable = makeExo( + 'LatestIterable', + M.interface('LatestIterable', {}, { defaultGuards: 'passable' }), + { + [Symbol.asyncIterator]: () => makeLatestIterator(topic), + }, + ); return iterable; }; harden(subscribeLatest); diff --git a/packages/notifier/src/subscriber.js b/packages/notifier/src/subscriber.js index cafdad40877..63081416a9a 100644 --- a/packages/notifier/src/subscriber.js +++ b/packages/notifier/src/subscriber.js @@ -16,20 +16,25 @@ import './types-ambient.js'; * @returns {Subscription} */ const makeSubscription = topic => { - const subscription = Far('Subscription', { - ...subscribeEach(topic), - subscribeAfter: async publishCount => E(topic).subscribeAfter(publishCount), + const subscription = makeExo( + 'Subscription', + M.interface('Subscription', {}, { defaultGuards: 'passable' }), + { + ...subscribeEach(topic), + subscribeAfter: async publishCount => + E(topic).subscribeAfter(publishCount), - /** - * Use this to distribute a Subscription efficiently over the network, - * by obtaining this from the Subscription to be replicated, and applying - * `makeSubscription` to it at the new site to get an equivalent local - * Subscription at that site. - */ - getSharableSubscriptionInternals: async () => topic, + /** + * Use this to distribute a Subscription efficiently over the network, + * by obtaining this from the Subscription to be replicated, and applying + * `makeSubscription` to it at the new site to get an equivalent local + * Subscription at that site. + */ + getSharableSubscriptionInternals: async () => topic, - getStoreKey: () => harden({ subscription }), - }); + getStoreKey: () => harden({ subscription }), + }, + ); return subscription; }; harden(makeSubscription); @@ -63,11 +68,15 @@ const makeSubscriptionKit = () => { const subscription = makeSubscription(pinnedHistoryTopic); /** @type {IterationObserver} */ - const publication = Far('publication', { - updateState: nonFinalValue => publisher.publish(nonFinalValue), - finish: completion => publisher.finish(completion), - fail: reason => publisher.fail(reason), - }); + const publication = makeExo( + 'publication', + M.interface('publication', {}, { defaultGuards: 'passable' }), + { + updateState: nonFinalValue => publisher.publish(nonFinalValue), + finish: completion => publisher.finish(completion), + fail: reason => publisher.fail(reason), + }, + ); return harden({ publication, subscription }); }; diff --git a/packages/notifier/src/topic.js b/packages/notifier/src/topic.js index 0912dd6f195..ff76bf233fa 100644 --- a/packages/notifier/src/topic.js +++ b/packages/notifier/src/topic.js @@ -18,17 +18,21 @@ export const makePinnedHistoryTopic = topic => { // We need to take an immediate snapshot of the topic's current state. const pinnedPubList = topic.subscribeAfter(); - return Far('PinnedHistoryTopic', { - subscribeAfter: async (publishCount = -1n) => { - if (publishCount === -1n) { - return pinnedPubList; - } - return topic.subscribeAfter(publishCount); + return makeExo( + 'PinnedHistoryTopic', + M.interface('PinnedHistoryTopic', {}, { defaultGuards: 'passable' }), + { + subscribeAfter: async (publishCount = -1n) => { + if (publishCount === -1n) { + return pinnedPubList; + } + return topic.subscribeAfter(publishCount); + }, + getUpdateSince: async (updateCount = undefined) => { + // TODO: Build this out of EachTopic. + return topic.getUpdateSince(updateCount); + }, }, - getUpdateSince: async (updateCount = undefined) => { - // TODO: Build this out of EachTopic. - return topic.getUpdateSince(updateCount); - }, - }); + ); }; harden(makePinnedHistoryTopic); diff --git a/packages/notifier/test/vat-integration/vat-pubsub.js b/packages/notifier/test/vat-integration/vat-pubsub.js index ed19dc37a21..6cb1b62f934 100644 --- a/packages/notifier/test/vat-integration/vat-pubsub.js +++ b/packages/notifier/test/vat-integration/vat-pubsub.js @@ -19,15 +19,19 @@ export const buildRootObject = (_vatPowers, vatParameters, baggage) => { const { version } = vatParameters; - return Far('root', { - getVersion: () => version, - getParameters: () => vatParameters, - getSubscriber: () => subscriber, - subscribeEach: topic => subscribeEach(topic), - subscribeLatest: topic => subscribeLatest(topic), - makeDurablePublishKit: (...args) => makeDurablePublishKit(...args), - publish: value => publisher.publish(value), - finish: finalValue => publisher.finish(finalValue), - fail: reason => publisher.fail(reason), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + getVersion: () => version, + getParameters: () => vatParameters, + getSubscriber: () => subscriber, + subscribeEach: topic => subscribeEach(topic), + subscribeLatest: topic => subscribeLatest(topic), + makeDurablePublishKit: (...args) => makeDurablePublishKit(...args), + publish: value => publisher.publish(value), + finish: finalValue => publisher.finish(finalValue), + fail: reason => publisher.fail(reason), + }, + ); }; diff --git a/packages/notifier/tools/testSupports.js b/packages/notifier/tools/testSupports.js index f1eceb40db7..994a4211a7b 100644 --- a/packages/notifier/tools/testSupports.js +++ b/packages/notifier/tools/testSupports.js @@ -18,19 +18,23 @@ export const makeFakeStorage = (path, publication) => { dataPrefixBytes: '', }); /** @type {StorageNode & { countSetValueCalls: () => number}} */ - const storage = Far('StorageNode', { - getPath: () => path, - getStoreKey: async () => storeKey, - setValue: async value => { - setValueCalls += 1; - assert.typeof(value, 'string'); - if (publication) { - publication.updateState(value); - } + const storage = makeExo( + 'StorageNode', + M.interface('StorageNode', {}, { defaultGuards: 'passable' }), + { + getPath: () => path, + getStoreKey: async () => storeKey, + setValue: async value => { + setValueCalls += 1; + assert.typeof(value, 'string'); + if (publication) { + publication.updateState(value); + } + }, + makeChildNode: () => storage, + countSetValueCalls: () => setValueCalls, }, - makeChildNode: () => storage, - countSetValueCalls: () => setValueCalls, - }); + ); return storage; }; harden(makeFakeStorage); diff --git a/packages/pegasus/src/courier.js b/packages/pegasus/src/courier.js index a7c5cdb637b..7da4ce77c6a 100644 --- a/packages/pegasus/src/courier.js +++ b/packages/pegasus/src/courier.js @@ -130,5 +130,9 @@ export const makeCourierMaker = return E(transferProtocol).makeTransferPacketAck(true); }; - return Far('courier', { send, receive }); + return makeExo( + 'courier', + M.interface('courier', {}, { defaultGuards: 'passable' }), + { send, receive }, + ); }; diff --git a/packages/pegasus/src/ics20.js b/packages/pegasus/src/ics20.js index df96c2d8f4c..66d871c6a52 100644 --- a/packages/pegasus/src/ics20.js +++ b/packages/pegasus/src/ics20.js @@ -143,9 +143,13 @@ export const makeICS20TransferPacketAck = async (success, error) => { }; /** @type {TransferProtocol} */ -export const ICS20TransferProtocol = Far('ics20-1 transfer protocol', { - makeTransferPacket: makeICS20TransferPacket, - assertTransferPacketAck: assertICS20TransferPacketAck, - parseTransferPacket: parseICS20TransferPacket, - makeTransferPacketAck: makeICS20TransferPacketAck, -}); +export const ICS20TransferProtocol = makeExo( + 'ics20-1 transfer protocol', + M.interface('ics20-1 transfer protocol', {}, { defaultGuards: 'passable' }), + { + makeTransferPacket: makeICS20TransferPacket, + assertTransferPacketAck: assertICS20TransferPacketAck, + parseTransferPacket: parseICS20TransferPacket, + makeTransferPacketAck: makeICS20TransferPacketAck, + }, +); diff --git a/packages/pegasus/src/pegasus.js b/packages/pegasus/src/pegasus.js index bae6a05d963..93ec89295cc 100644 --- a/packages/pegasus/src/pegasus.js +++ b/packages/pegasus/src/pegasus.js @@ -82,7 +82,7 @@ export const makePegasus = ({ zcf, board, namesByAddress, when }) => { */ const makePeg = (state, desc) => { /** @type {Peg} */ - const peg = Far(`${desc.allegedName} peg`, { + const peg = makeExo(`${desc.allegedName} peg`, M.interface(`${desc.allegedName} peg`, {}, { defaultGuards: 'passable' }), { getAllegedName() { return desc.allegedName; }, @@ -121,377 +121,397 @@ export const makePegasus = ({ zcf, board, namesByAddress, when }) => { const pegs = new Set(); /** @type {PegasusConnectionActions} */ - const pegasusConnectionActions = Far('pegasusConnectionActions', { - async rejectTransfersWaitingForPegRemote(remoteDenom) { - checkAbort(); - const { receiveDenomToCourierPK } = localDenomState; - - const { receiveDenom } = await E( - denomTransformer, - ).getDenomsForRemotePeg( - remoteDenom, - localDenomState.localAddr, - localDenomState.remoteAddr, - ); - checkAbort(); - - const { reject, promise } = receiveDenomToCourierPK.get(receiveDenom); + const pegasusConnectionActions = makeExo( + 'pegasusConnectionActions', + M.interface( + 'pegasusConnectionActions', + {}, + { defaultGuards: 'passable' }, + ), + { + async rejectTransfersWaitingForPegRemote(remoteDenom) { + checkAbort(); + const { receiveDenomToCourierPK } = localDenomState; + + const { receiveDenom } = await E( + denomTransformer, + ).getDenomsForRemotePeg( + remoteDenom, + localDenomState.localAddr, + localDenomState.remoteAddr, + ); + checkAbort(); - // Only continue if the promise isn't already resolved. - const raceWinner = await Promise.race([promise, null]); - checkAbort(); - !raceWinner || Fail`${receiveDenom} is already resolved`; + const { reject, promise } = receiveDenomToCourierPK.get(receiveDenom); - // If rejected, the rejection is returned to our caller, so we have - // handled it correctly and that flow doesn't need to trigger an - // additional UnhandledRejectionWarning in our vat. - promise.catch(() => {}); - reject(assert.error(X`${receiveDenom} is temporarily unavailable`)); + // Only continue if the promise isn't already resolved. + const raceWinner = await Promise.race([promise, null]); + checkAbort(); + !raceWinner || Fail`${receiveDenom} is already resolved`; - // Allow new transfers to be initiated after this rejection. - receiveDenomToCourierPK.delete(receiveDenom); - }, - async pegRemote( - allegedName, - remoteDenom, - assetKind = undefined, - displayInfo = undefined, - ) { - checkAbort(); - const { receiveDenomToCourierPK } = localDenomState; - - // Create the issuer for the local erights corresponding to the remote values. - const localKeyword = createLocalIssuerKeyword(); - const zcfMint = await zcf.makeZCFMint( - localKeyword, - assetKind, - displayInfo, - ); - checkAbort(); - const { brand: localBrand } = zcfMint.getIssuerRecord(); + // If rejected, the rejection is returned to our caller, so we have + // handled it correctly and that flow doesn't need to trigger an + // additional UnhandledRejectionWarning in our vat. + promise.catch(() => {}); + reject(assert.error(X`${receiveDenom} is temporarily unavailable`)); - const { sendDenom, receiveDenom } = await E( - denomTransformer, - ).getDenomsForRemotePeg( + // Allow new transfers to be initiated after this rejection. + receiveDenomToCourierPK.delete(receiveDenom); + }, + async pegRemote( + allegedName, remoteDenom, - localDenomState.localAddr, - localDenomState.remoteAddr, - ); - checkAbort(); - - // Describe how to retain/redeem pegged shadow erights. - const courier = makeCourier({ - zcf, - localBrand, - board, - namesByAddress, - sendDenom, - retain: (zcfSeat, amounts) => - zcfMint.burnLosses(harden(amounts), zcfSeat), - redeem: (zcfSeat, amounts) => { - zcfMint.mintGains(harden(amounts), zcfSeat); - }, - transferProtocol, - when, - }); + assetKind = undefined, + displayInfo = undefined, + ) { + checkAbort(); + const { receiveDenomToCourierPK } = localDenomState; + + // Create the issuer for the local erights corresponding to the remote values. + const localKeyword = createLocalIssuerKeyword(); + const zcfMint = await zcf.makeZCFMint( + localKeyword, + assetKind, + displayInfo, + ); + checkAbort(); + const { brand: localBrand } = zcfMint.getIssuerRecord(); - const courierPK = getCourierPK(receiveDenom, receiveDenomToCourierPK); - courierPK.resolve(courier); + const { sendDenom, receiveDenom } = await E( + denomTransformer, + ).getDenomsForRemotePeg( + remoteDenom, + localDenomState.localAddr, + localDenomState.remoteAddr, + ); + checkAbort(); - checkAbort(); - const peg = makePeg(localDenomState, { - localBrand, - sendDenom, - receiveDenom, - allegedName, - }); - pegs.add(peg); - return peg; - }, + // Describe how to retain/redeem pegged shadow erights. + const courier = makeCourier({ + zcf, + localBrand, + board, + namesByAddress, + sendDenom, + retain: (zcfSeat, amounts) => + zcfMint.burnLosses(harden(amounts), zcfSeat), + redeem: (zcfSeat, amounts) => { + zcfMint.mintGains(harden(amounts), zcfSeat); + }, + transferProtocol, + when, + }); - async pegLocal(allegedName, localIssuer) { - checkAbort(); + const courierPK = getCourierPK(receiveDenom, receiveDenomToCourierPK); + courierPK.resolve(courier); - localDenomState.lastDenomNonce += 1n; - const remoteDenom = `pegasus${localDenomState.lastDenomNonce}`; + checkAbort(); + const peg = makePeg(localDenomState, { + localBrand, + sendDenom, + receiveDenom, + allegedName, + }); + pegs.add(peg); + return peg; + }, - // Create a seat in which to keep our escrowed ERTP assets of this denomination. - const { zcfSeat: poolSeat } = zcf.makeEmptySeatKit(); + async pegLocal(allegedName, localIssuer) { + checkAbort(); - // Ensure the issuer can be used in Zoe offers. - const localKeyword = createLocalIssuerKeyword(); - const { brand: localBrand } = await zcf.saveIssuer( - localIssuer, - localKeyword, - ); - checkAbort(); + localDenomState.lastDenomNonce += 1n; + const remoteDenom = `pegasus${localDenomState.lastDenomNonce}`; - const { sendDenom, receiveDenom } = await E( - denomTransformer, - ).getDenomsForLocalPeg( - remoteDenom, - localDenomState.localAddr, - localDenomState.remoteAddr, - ); - checkAbort(); + // Create a seat in which to keep our escrowed ERTP assets of this denomination. + const { zcfSeat: poolSeat } = zcf.makeEmptySeatKit(); - /** - * Transfer amount (of localBrand) from loser to winner seats. - * - * @param {Amount} amount amount to transfer - * @param {Keyword} loserKeyword the keyword to take from the loser - * @param {ZCFSeat} loser seat to transfer from - * @param {Keyword} winnerKeyword the keyword to give to the winner - * @param {ZCFSeat} winner seat to transfer to - */ - const transferAmountFrom = ( - amount, - loserKeyword, - loser, - winnerKeyword, - winner, - ) => { - // Transfer the amount to our backing seat. - atomicTransfer( - zcf, + // Ensure the issuer can be used in Zoe offers. + const localKeyword = createLocalIssuerKeyword(); + const { brand: localBrand } = await zcf.saveIssuer( + localIssuer, + localKeyword, + ); + checkAbort(); + + const { sendDenom, receiveDenom } = await E( + denomTransformer, + ).getDenomsForLocalPeg( + remoteDenom, + localDenomState.localAddr, + localDenomState.remoteAddr, + ); + checkAbort(); + + /** + * Transfer amount (of localBrand) from loser to winner seats. + * + * @param {Amount} amount amount to transfer + * @param {Keyword} loserKeyword the keyword to take from the loser + * @param {ZCFSeat} loser seat to transfer from + * @param {Keyword} winnerKeyword the keyword to give to the winner + * @param {ZCFSeat} winner seat to transfer to + */ + const transferAmountFrom = ( + amount, + loserKeyword, loser, + winnerKeyword, winner, - { [loserKeyword]: amount }, - { [winnerKeyword]: amount }, - ); - }; + ) => { + // Transfer the amount to our backing seat. + atomicTransfer( + zcf, + loser, + winner, + { [loserKeyword]: amount }, + { [winnerKeyword]: amount }, + ); + }; - // Describe how to retain/redeem real local erights. - const courier = makeCourier({ - zcf, - board, - namesByAddress, - sendDenom, - localBrand, - retain: (transferSeat, amounts) => - transferAmountFrom( - amounts.Transfer, - 'Transfer', - transferSeat, - 'Pool', - poolSeat, - ), - redeem: (transferSeat, amounts) => - transferAmountFrom( - amounts.Transfer, - 'Pool', - poolSeat, - 'Transfer', - transferSeat, - ), - transferProtocol, - when, - }); + // Describe how to retain/redeem real local erights. + const courier = makeCourier({ + zcf, + board, + namesByAddress, + sendDenom, + localBrand, + retain: (transferSeat, amounts) => + transferAmountFrom( + amounts.Transfer, + 'Transfer', + transferSeat, + 'Pool', + poolSeat, + ), + redeem: (transferSeat, amounts) => + transferAmountFrom( + amounts.Transfer, + 'Pool', + poolSeat, + 'Transfer', + transferSeat, + ), + transferProtocol, + when, + }); - const { receiveDenomToCourierPK } = localDenomState; + const { receiveDenomToCourierPK } = localDenomState; - const courierPK = getCourierPK(receiveDenom, receiveDenomToCourierPK); - courierPK.resolve(courier); + const courierPK = getCourierPK(receiveDenom, receiveDenomToCourierPK); + courierPK.resolve(courier); - const peg = makePeg(localDenomState, { - localBrand, - sendDenom, - receiveDenom, - allegedName, - }); - pegs.add(peg); - return peg; - }, - abort: reason => { - checkAbort(); - checkAbort = () => { - throw reason; - }; - for (const peg of pegs) { - pegToDenomState.delete(peg); - } + const peg = makePeg(localDenomState, { + localBrand, + sendDenom, + receiveDenom, + allegedName, + }); + pegs.add(peg); + return peg; + }, + abort: reason => { + checkAbort(); + checkAbort = () => { + throw reason; + }; + for (const peg of pegs) { + pegToDenomState.delete(peg); + } + }, }, - }); + ); return pegasusConnectionActions; }; - return Far('pegasus', { - /** - * Return a handler that can be used with the Network API. - * - * @param {ERef} [transferProtocol] - * @param {ERef} [denomTransformer] - * @returns {PegasusConnectionKit} - */ - makePegasusConnectionKit( - transferProtocol = DEFAULT_TRANSFER_PROTOCOL, - denomTransformer = DEFAULT_DENOM_TRANSFORMER, - ) { + return makeExo( + 'pegasus', + M.interface('pegasus', {}, { defaultGuards: 'passable' }), + { /** - * @type {LegacyWeakMap} - */ - // Legacy because the value contains a JS Set - const connectionToLocalDenomState = makeLegacyWeakMap('Connection'); - - /** - * @type {SubscriptionRecord} + * Return a handler that can be used with the Network API. + * + * @param {ERef} [transferProtocol] + * @param {ERef} [denomTransformer] + * @returns {PegasusConnectionKit} */ - const { - subscription: connectionSubscription, - publication: connectionPublication, - } = makeSubscriptionKit(); - - /** @type {ConnectionHandler} */ - const handler = { - async onOpen(c, localAddr, remoteAddr) { - // Register `c` with the table of Peg receivers. - const { - subscription: remoteDenomSubscription, - publication: receiveDenomPublication, - } = makeSubscriptionKit(); - const receiveDenomToCourierPK = makeLegacyMap('Denomination'); - - /** @type {LocalDenomState} */ - const localDenomState = { - localAddr, - remoteAddr, - receiveDenomToCourierPK, - lastDenomNonce: 0n, - receiveDenomPublication, - remoteDenomSubscription, - abort: reason => { - // eslint-disable-next-line no-use-before-define - actions.abort(reason); - }, - }; - - // The courier is the only thing that we use to send messages to `c`. - const makeCourier = makeCourierMaker(c); - const actions = makePegasusConnectionActions({ - localDenomState, - makeCourier, - transferProtocol, - denomTransformer, - }); - - connectionToLocalDenomState.init(c, localDenomState); - - /** @type {PegasusConnection} */ - const state = harden({ - localAddr, - remoteAddr, - actions, - remoteDenomSubscription, - }); - connectionPublication.updateState(state); - }, - async onReceive(c, packetBytes) { - const doReceive = async () => { - // Dispatch the packet to the appropriate Peg for this connection. - const parts = - await E(transferProtocol).parseTransferPacket(packetBytes); - - const { remoteDenom: receiveDenom } = parts; - assert.typeof(receiveDenom, 'string'); - - const { receiveDenomToCourierPK, receiveDenomPublication } = - connectionToLocalDenomState.get(c); - - if (!receiveDenomToCourierPK.has(receiveDenom)) { - // This is the first time we've heard of this denomination. - receiveDenomPublication.updateState(receiveDenom); - } + makePegasusConnectionKit( + transferProtocol = DEFAULT_TRANSFER_PROTOCOL, + denomTransformer = DEFAULT_DENOM_TRANSFORMER, + ) { + /** + * @type {LegacyWeakMap} + */ + // Legacy because the value contains a JS Set + const connectionToLocalDenomState = makeLegacyWeakMap('Connection'); - // Wait for the courier to be instantiated. - const courierPK = getCourierPK( - receiveDenom, + /** + * @type {SubscriptionRecord} + */ + const { + subscription: connectionSubscription, + publication: connectionPublication, + } = makeSubscriptionKit(); + + /** @type {ConnectionHandler} */ + const handler = { + async onOpen(c, localAddr, remoteAddr) { + // Register `c` with the table of Peg receivers. + const { + subscription: remoteDenomSubscription, + publication: receiveDenomPublication, + } = makeSubscriptionKit(); + const receiveDenomToCourierPK = makeLegacyMap('Denomination'); + + /** @type {LocalDenomState} */ + const localDenomState = { + localAddr, + remoteAddr, receiveDenomToCourierPK, + lastDenomNonce: 0n, + receiveDenomPublication, + remoteDenomSubscription, + abort: reason => { + // eslint-disable-next-line no-use-before-define + actions.abort(reason); + }, + }; + + // The courier is the only thing that we use to send messages to `c`. + const makeCourier = makeCourierMaker(c); + const actions = makePegasusConnectionActions({ + localDenomState, + makeCourier, + transferProtocol, + denomTransformer, + }); + + connectionToLocalDenomState.init(c, localDenomState); + + /** @type {PegasusConnection} */ + const state = harden({ + localAddr, + remoteAddr, + actions, + remoteDenomSubscription, + }); + connectionPublication.updateState(state); + }, + async onReceive(c, packetBytes) { + const doReceive = async () => { + // Dispatch the packet to the appropriate Peg for this connection. + const parts = + await E(transferProtocol).parseTransferPacket(packetBytes); + + const { remoteDenom: receiveDenom } = parts; + assert.typeof(receiveDenom, 'string'); + + const { receiveDenomToCourierPK, receiveDenomPublication } = + connectionToLocalDenomState.get(c); + + if (!receiveDenomToCourierPK.has(receiveDenom)) { + // This is the first time we've heard of this denomination. + receiveDenomPublication.updateState(receiveDenom); + } + + // Wait for the courier to be instantiated. + const courierPK = getCourierPK( + receiveDenom, + receiveDenomToCourierPK, + ); + const { receive } = await courierPK.promise; + return receive(parts); + }; + + return doReceive().catch(error => + E(transferProtocol).makeTransferPacketAck(false, error), ); - const { receive } = await courierPK.promise; - return receive(parts); - }; - - return doReceive().catch(error => - E(transferProtocol).makeTransferPacketAck(false, error), - ); - }, - async onClose(c) { - // Unregister `c`. Pending transfers will be rejected by the Network - // API. - const { - receiveDenomPublication, - receiveDenomToCourierPK, - localAddr, - remoteAddr, - abort, - } = connectionToLocalDenomState.get(c); - connectionToLocalDenomState.delete(c); - const err = assert.error(X`pegasusConnectionHandler closed`); - receiveDenomPublication.fail(err); - /** @type {PegasusConnection} */ - const state = harden({ - localAddr, - remoteAddr, - }); - connectionPublication.updateState(state); - for (const courierPK of receiveDenomToCourierPK.values()) { - try { - courierPK.reject(err); - } catch (e) { - // Already resolved/rejected, so ignore. + }, + async onClose(c) { + // Unregister `c`. Pending transfers will be rejected by the Network + // API. + const { + receiveDenomPublication, + receiveDenomToCourierPK, + localAddr, + remoteAddr, + abort, + } = connectionToLocalDenomState.get(c); + connectionToLocalDenomState.delete(c); + const err = assert.error(X`pegasusConnectionHandler closed`); + receiveDenomPublication.fail(err); + /** @type {PegasusConnection} */ + const state = harden({ + localAddr, + remoteAddr, + }); + connectionPublication.updateState(state); + for (const courierPK of receiveDenomToCourierPK.values()) { + try { + courierPK.reject(err); + } catch (e) { + // Already resolved/rejected, so ignore. + } } - } - abort(err); - }, - }; - - return harden({ - handler: Far('pegasusConnectionHandler', handler), - subscription: connectionSubscription, - }); - }, + abort(err); + }, + }; - getLocalIssuer(localBrand) { - return zcf.getIssuerForBrand(localBrand); - }, + return harden({ + handler: Far('pegasusConnectionHandler', handler), + subscription: connectionSubscription, + }); + }, - /** - * Create a Zoe invitation to transfer assets over network to a deposit address. - * - * @param {ERef} pegP the peg over which to transfer - * @param {DepositAddress} depositAddress the remote receiver's address - * @param {string} [memo] the memo to attach to ics transfer packet - * @param {SenderOptions} [opts] additional sender options - * @returns {Promise} to transfer, make an offer of { give: { Transfer: pegAmount } } to this invitation - */ - async makeInvitationToTransfer(pegP, depositAddress, memo = '', opts = {}) { - // Verify the peg. - const peg = await pegP; - const denomState = pegToDenomState.get(peg); - - // Get details from the peg. - const [receiveDenom, sendDenom] = await Promise.all([ - E(peg).getReceiveDenom(), - E(peg).getSendDenom(), - ]); - const { receiveDenomToCourierPK } = denomState; - - const courierPK = getCourierPK(receiveDenom, receiveDenomToCourierPK); - const { send } = await courierPK.promise; + getLocalIssuer(localBrand) { + return zcf.getIssuerForBrand(localBrand); + }, /** - * Attempt the transfer, returning a refund if failed. + * Create a Zoe invitation to transfer assets over network to a deposit address. * - * @type {OfferHandler} + * @param {ERef} pegP the peg over which to transfer + * @param {DepositAddress} depositAddress the remote receiver's address + * @param {string} [memo] the memo to attach to ics transfer packet + * @param {SenderOptions} [opts] additional sender options + * @returns {Promise} to transfer, make an offer of { give: { Transfer: pegAmount } } to this invitation */ - const offerHandler = zcfSeat => { - assertProposalShape(zcfSeat, TRANSFER_PROPOSAL_SHAPE); - send(zcfSeat, depositAddress, memo, opts); - }; + async makeInvitationToTransfer( + pegP, + depositAddress, + memo = '', + opts = {}, + ) { + // Verify the peg. + const peg = await pegP; + const denomState = pegToDenomState.get(peg); + + // Get details from the peg. + const [receiveDenom, sendDenom] = await Promise.all([ + E(peg).getReceiveDenom(), + E(peg).getSendDenom(), + ]); + const { receiveDenomToCourierPK } = denomState; - return zcf.makeInvitation(offerHandler, `pegasus ${sendDenom} transfer`); + const courierPK = getCourierPK(receiveDenom, receiveDenomToCourierPK); + const { send } = await courierPK.promise; + + /** + * Attempt the transfer, returning a refund if failed. + * + * @type {OfferHandler} + */ + const offerHandler = zcfSeat => { + assertProposalShape(zcfSeat, TRANSFER_PROPOSAL_SHAPE); + send(zcfSeat, depositAddress, memo, opts); + }; + + return zcf.makeInvitation( + offerHandler, + `pegasus ${sendDenom} transfer`, + ); + }, }, - }); + ); }; harden(makePegasus); diff --git a/packages/pegasus/src/proposals/core-proposal.js b/packages/pegasus/src/proposals/core-proposal.js index dd099e57f99..daa35d002fa 100644 --- a/packages/pegasus/src/proposals/core-proposal.js +++ b/packages/pegasus/src/proposals/core-proposal.js @@ -80,14 +80,18 @@ export const addPegasusTransferPort = async ( console.error('Error observing Pegasus connection kit:', err), ); return E(port).addListener( - Far('listener', { - async onAccept(_port, _localAddr, _remoteAddr, _listenHandler) { - return handler; + makeExo( + 'listener', + M.interface('listener', {}, { defaultGuards: 'passable' }), + { + async onAccept(_port, _localAddr, _remoteAddr, _listenHandler) { + return handler; + }, + async onListen(p, _listenHandler) { + console.debug(`Listening on Pegasus transfer port: ${p}`); + }, }, - async onListen(p, _listenHandler) { - console.debug(`Listening on Pegasus transfer port: ${p}`); - }, - }), + ), ); }; harden(addPegasusTransferPort); diff --git a/packages/pegasus/test/test-peg.js b/packages/pegasus/test/test-peg.js index 5517ec996eb..1c186fa502b 100644 --- a/packages/pegasus/test/test-peg.js +++ b/packages/pegasus/test/test-peg.js @@ -55,23 +55,31 @@ async function testRemotePeg(t) { */ const { promise: localDepositFacet, resolve: resolveLocalDepositFacet } = makePromiseKit(); - const fakeBoard = Far('fakeBoard', { - getValue(id) { - if (id === '0x1234') { - return localDepositFacet; - } - t.is(id, 'agoric1234567', 'tried bech32 first in board'); - throw Error(`unrecognized board id ${id}`); + const fakeBoard = makeExo( + 'fakeBoard', + M.interface('fakeBoard', {}, { defaultGuards: 'passable' }), + { + getValue(id) { + if (id === '0x1234') { + return localDepositFacet; + } + t.is(id, 'agoric1234567', 'tried bech32 first in board'); + throw Error(`unrecognized board id ${id}`); + }, }, - }); - const fakeNamesByAddress = Far('fakeNamesByAddress', { - lookup(...keys) { - t.is(keys[0], 'agoric1234567', 'unrecognized fakeNamesByAddress'); - t.is(keys[1], 'depositFacet', 'lookup not for the depositFacet'); - t.is(keys.length, 2); - return localDepositFacet; + ); + const fakeNamesByAddress = makeExo( + 'fakeNamesByAddress', + M.interface('fakeNamesByAddress', {}, { defaultGuards: 'passable' }), + { + lookup(...keys) { + t.is(keys[0], 'agoric1234567', 'unrecognized fakeNamesByAddress'); + t.is(keys[1], 'depositFacet', 'lookup not for the depositFacet'); + t.is(keys.length, 2); + return localDepositFacet; + }, }, - }); + ); const zoe = makeZoeForTest(); @@ -106,47 +114,55 @@ async function testRemotePeg(t) { let gaiaConnection; E(portP) .addListener( - Far('acceptor', { - async onAccept(_p, _localAddr, _remoteAddr) { - return Far('handler', { - async onOpen(c) { - gaiaConnection = c; - }, - async onReceive(_c, packetBytes) { - const { resolver, vow } = makeVowKit(); - const packet = JSON.parse(packetBytes); - if (packet.memo) { - t.deepEqual( - packet, - { - amount: '100000000000000000001', - denom: 'portdef/chanabc/uatom', - memo: 'I am a memo!', - receiver: 'markaccount', - sender: 'agoric1jmd7lwdyykrxm5h83nlhg74fctwnky04ufpqtc', - }, - 'expected transfer packet', - ); - resolver.resolve(JSON.stringify({ result: 'AQ==' })); - } else { - t.deepEqual( - packet, - { - amount: '100000000000000000001', - denom: 'portdef/chanabc/uatom', - memo: '', - receiver: 'markaccount', - sender: 'pegasus', - }, - 'expected transfer packet', - ); - resolver.resolve(JSON.stringify({ result: 'AQ==' })); - } - return vow; - }, - }); + makeExo( + 'acceptor', + M.interface('acceptor', {}, { defaultGuards: 'passable' }), + { + async onAccept(_p, _localAddr, _remoteAddr) { + return makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { + async onOpen(c) { + gaiaConnection = c; + }, + async onReceive(_c, packetBytes) { + const { resolver, vow } = makeVowKit(); + const packet = JSON.parse(packetBytes); + if (packet.memo) { + t.deepEqual( + packet, + { + amount: '100000000000000000001', + denom: 'portdef/chanabc/uatom', + memo: 'I am a memo!', + receiver: 'markaccount', + sender: 'agoric1jmd7lwdyykrxm5h83nlhg74fctwnky04ufpqtc', + }, + 'expected transfer packet', + ); + resolver.resolve(JSON.stringify({ result: 'AQ==' })); + } else { + t.deepEqual( + packet, + { + amount: '100000000000000000001', + denom: 'portdef/chanabc/uatom', + memo: '', + receiver: 'markaccount', + sender: 'pegasus', + }, + 'expected transfer packet', + ); + resolver.resolve(JSON.stringify({ result: 'AQ==' })); + } + return vow; + }, + }, + ); + }, }, - }), + ), ) .catch(e => t.fail(e)); diff --git a/packages/smart-wallet/src/marshal-contexts.js b/packages/smart-wallet/src/marshal-contexts.js index de5b3b94160..ec463dd72ac 100644 --- a/packages/smart-wallet/src/marshal-contexts.js +++ b/packages/smart-wallet/src/marshal-contexts.js @@ -350,8 +350,16 @@ export const makeImportContext = (makePresence = defaultMakePresence) => { } initSlotVal(boardObjects, id, val); }, - fromMyWallet: Far('wallet marshaller', { ...marshal.fromMyWallet }), - fromBoard: Far('board marshaller', { ...marshal.fromBoard }), + fromMyWallet: makeExo( + 'wallet marshaller', + M.interface('wallet marshaller', {}, { defaultGuards: 'passable' }), + { ...marshal.fromMyWallet }, + ), + fromBoard: makeExo( + 'board marshaller', + M.interface('board marshaller', {}, { defaultGuards: 'passable' }), + { ...marshal.fromBoard }, + ), }); }; /** @typedef {ReturnType} ImportContext */ diff --git a/packages/smart-wallet/test/gameAssetContract.js b/packages/smart-wallet/test/gameAssetContract.js index ef982ce9882..2a842efdb53 100644 --- a/packages/smart-wallet/test/gameAssetContract.js +++ b/packages/smart-wallet/test/gameAssetContract.js @@ -57,10 +57,14 @@ export const start = async zcf => { return 'welcome to the game'; }; - const publicFacet = Far('API', { - makeJoinInvitation: () => - zcf.makeInvitation(joinHook, 'join', undefined, joinShape), - }); + const publicFacet = makeExo( + 'API', + M.interface('API', {}, { defaultGuards: 'passable' }), + { + makeJoinInvitation: () => + zcf.makeInvitation(joinHook, 'join', undefined, joinShape), + }, + ); return harden({ publicFacet }); }; diff --git a/packages/smart-wallet/test/supports.js b/packages/smart-wallet/test/supports.js index 867dfa5860f..c43c38d8c7b 100644 --- a/packages/smart-wallet/test/supports.js +++ b/packages/smart-wallet/test/supports.js @@ -59,32 +59,40 @@ export const subscriptionKey = subscription => { /** @returns {import('@agoric/vats').BridgeManager} */ const makeFakeBridgeManager = () => - Far('fakeBridgeManager', { - register(bridgeId, handler) { - return Far('scopedBridgeManager', { - fromBridge(_obj) { - assert.fail(`expected fromBridge`); - }, - toBridge(obj) { - if (!handler) { - Fail`No handler for ${bridgeId}`; - } - // Rely on interface guard for validation. - // This should also be validated upstream but don't rely on it. - // @ts-expect-error handler possibly undefined - return E(handler).fromBridge(obj); - }, - initHandler(newHandler) { - !handler || Fail`Handler already set`; - handler = newHandler; - }, - setHandler(newHandler) { - !!handler || Fail`Handler not set`; - handler = newHandler; - }, - }); + makeExo( + 'fakeBridgeManager', + M.interface('fakeBridgeManager', {}, { defaultGuards: 'passable' }), + { + register(bridgeId, handler) { + return makeExo( + 'scopedBridgeManager', + M.interface('scopedBridgeManager', {}, { defaultGuards: 'passable' }), + { + fromBridge(_obj) { + assert.fail(`expected fromBridge`); + }, + toBridge(obj) { + if (!handler) { + Fail`No handler for ${bridgeId}`; + } + // Rely on interface guard for validation. + // This should also be validated upstream but don't rely on it. + // @ts-expect-error handler possibly undefined + return E(handler).fromBridge(obj); + }, + initHandler(newHandler) { + !handler || Fail`Handler already set`; + handler = newHandler; + }, + setHandler(newHandler) { + !!handler || Fail`Handler not set`; + handler = newHandler; + }, + }, + ); + }, }, - }); + ); /** * @param {*} log * @returns {Promise}>} diff --git a/packages/smart-wallet/test/swingsetTests/upgradeWalletFactory/bootstrap-walletFactory-service-upgrade.js b/packages/smart-wallet/test/swingsetTests/upgradeWalletFactory/bootstrap-walletFactory-service-upgrade.js index 127a465cdbe..46ba97eef47 100644 --- a/packages/smart-wallet/test/swingsetTests/upgradeWalletFactory/bootstrap-walletFactory-service-upgrade.js +++ b/packages/smart-wallet/test/swingsetTests/upgradeWalletFactory/bootstrap-walletFactory-service-upgrade.js @@ -53,155 +53,164 @@ export const buildRootObject = async () => { // omit walletBridgeManager }; - return Far('root', { - bootstrap: async (vats, devices) => { - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - const { zoeService } = await E(vats.zoe).buildZoe( - vatAdmin, - undefined, - 'zcf', - ); - zoePK.resolve(zoeService); - - const v1BundleId = await E(vatAdmin).getBundleIDByName(wfV1BundleName); - v1BundleId || Fail`bundleId must not be empty`; - installation = await E(zoe).installBundleID(v1BundleId); - - const autoRefundBundleId = - await E(vatAdmin).getBundleIDByName('automaticRefund'); - const autoRefundInstallation = - await E(zoe).installBundleID(autoRefundBundleId); - const { instance } = await E(zoe).startInstance(autoRefundInstallation, { - Moola: moolaKit.issuer, - }); - arPK.resolve(instance); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap: async (vats, devices) => { + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + const { zoeService } = await E(vats.zoe).buildZoe( + vatAdmin, + undefined, + 'zcf', + ); + zoePK.resolve(zoeService); + + const v1BundleId = await E(vatAdmin).getBundleIDByName(wfV1BundleName); + v1BundleId || Fail`bundleId must not be empty`; + installation = await E(zoe).installBundleID(v1BundleId); + + const autoRefundBundleId = + await E(vatAdmin).getBundleIDByName('automaticRefund'); + const autoRefundInstallation = + await E(zoe).installBundleID(autoRefundBundleId); + const { instance } = await E(zoe).startInstance( + autoRefundInstallation, + { + Moola: moolaKit.issuer, + }, + ); + arPK.resolve(instance); + }, + + buildV1: async () => { + trace(`BOOT buildV1 start`); + // build the contract vat from ZCF and the contract bundlecap + + // Complete round-trip without upgrade + trace(`BOOT buildV1 startInstance`); + const facets = await E(zoe).startInstance( + installation, + {}, + terms, + privateArgs, + ); + trace('BOOT buildV1 started instance'); + ({ adminFacet, creatorFacet } = facets); + const [newWallet, isNew] = await E(creatorFacet).provideSmartWallet( + walletAddr, + bank, + namesByAddressAdmin, + ); + isNew || Fail`wallet in buildV1 should be new`; + wallet = newWallet; + + const currentStoragePath = await E.get( + E.get(E(wallet).getPublicTopics()).current, + ).storagePath; + currentStoragePath === currentPath || Fail`bad storage path`; + + addAsset('umoola', 'moola', 'moola', moolaKit); + const depositFacet = E(wallet).getDepositFacet(); + const payment = moolaKit.mint.mintPayment( + AmountMath.make(moolaKit.brand, 100n), + ); + await E(depositFacet).receive(payment); + + return true; + }, + + testOfferV1: async () => { + // If this doesn't throw, the offer succeeded. + // I tried to also check vstorage but it doesn't always update in time. + await E(E(wallet).getOffersFacet()).executeOffer({ + id: 'firstOffer', + invitationSpec: { + source: 'contract', + instance: await automaticRefundInstance, + publicInvitationMaker: 'makeInvitation', + }, + proposal: { + give: { Moola: AmountMath.make(moolaKit.brand, 100n) }, + }, + }); + }, + + nullUpgradeV1: async () => { + trace(`BOOT nullUpgradeV1 start`); + + trace(`BOOT nullUpgradeV1 upgradeContract`); + const bundleId = await E(vatAdmin).getBundleIDByName(wfV1BundleName); + const upgradeResult = await E(adminFacet).upgradeContract( + bundleId, + privateArgs, + ); + assert.equal(upgradeResult.incarnationNumber, 1); + + const [wallet2, isNew] = await E(creatorFacet).provideSmartWallet( + walletAddr, + bank, + namesByAddressAdmin, + ); + !isNew || Fail`wallet in nullUpgradeV1 should not be new`; + wallet2 === wallet || Fail`must be same wallet obj`; + + const currentStoragePath = await E.get( + E.get(E(wallet).getPublicTopics()).current, + ).storagePath; + currentStoragePath === currentPath || Fail`bad storage path`; + + return true; + }, + + upgradeV2: async () => { + trace(`BOOT upgradeV2 start`); + const bundleId = await E(vatAdmin).getBundleIDByName(wfV2BundleName); + + const upgradeResult = await E(adminFacet).upgradeContract( + bundleId, + privateArgs, + ); + assert.equal(upgradeResult.incarnationNumber, 2); + trace(`BOOT upgradeV2 startInstance`); + + const [wallet2, isNew] = await E(creatorFacet).provideSmartWallet( + walletAddr, + bank, + namesByAddressAdmin, + ); + !isNew || Fail`wallet in nullUpgradeV1 should not be new`; + wallet2 === wallet || Fail`must be same wallet obj`; + + const currentStoragePath = await E.get( + E.get(E(wallet).getPublicTopics()).current, + ).storagePath; + currentStoragePath === currentPath || Fail`bad storage path`; + + // verify new method is present + const result = await E(creatorFacet).sayHelloUpgrade(); + result === 'hello, upgrade' || Fail`bad upgrade`; + + return true; + }, + + testOfferV2: async () => { + // If this doesn't throw, the offer succeeded. + // I tried to also check vstorage but it doesn't always update in time. + await E(E(wallet).getOffersFacet()).executeOffer({ + id: 'secondOffer', + invitationSpec: { + source: 'contract', + instance: await automaticRefundInstance, + publicInvitationMaker: 'makeInvitation', + }, + proposal: { + give: { Moola: AmountMath.make(moolaKit.brand, 100n) }, + }, + }); + }, }, - - buildV1: async () => { - trace(`BOOT buildV1 start`); - // build the contract vat from ZCF and the contract bundlecap - - // Complete round-trip without upgrade - trace(`BOOT buildV1 startInstance`); - const facets = await E(zoe).startInstance( - installation, - {}, - terms, - privateArgs, - ); - trace('BOOT buildV1 started instance'); - ({ adminFacet, creatorFacet } = facets); - const [newWallet, isNew] = await E(creatorFacet).provideSmartWallet( - walletAddr, - bank, - namesByAddressAdmin, - ); - isNew || Fail`wallet in buildV1 should be new`; - wallet = newWallet; - - const currentStoragePath = await E.get( - E.get(E(wallet).getPublicTopics()).current, - ).storagePath; - currentStoragePath === currentPath || Fail`bad storage path`; - - addAsset('umoola', 'moola', 'moola', moolaKit); - const depositFacet = E(wallet).getDepositFacet(); - const payment = moolaKit.mint.mintPayment( - AmountMath.make(moolaKit.brand, 100n), - ); - await E(depositFacet).receive(payment); - - return true; - }, - - testOfferV1: async () => { - // If this doesn't throw, the offer succeeded. - // I tried to also check vstorage but it doesn't always update in time. - await E(E(wallet).getOffersFacet()).executeOffer({ - id: 'firstOffer', - invitationSpec: { - source: 'contract', - instance: await automaticRefundInstance, - publicInvitationMaker: 'makeInvitation', - }, - proposal: { - give: { Moola: AmountMath.make(moolaKit.brand, 100n) }, - }, - }); - }, - - nullUpgradeV1: async () => { - trace(`BOOT nullUpgradeV1 start`); - - trace(`BOOT nullUpgradeV1 upgradeContract`); - const bundleId = await E(vatAdmin).getBundleIDByName(wfV1BundleName); - const upgradeResult = await E(adminFacet).upgradeContract( - bundleId, - privateArgs, - ); - assert.equal(upgradeResult.incarnationNumber, 1); - - const [wallet2, isNew] = await E(creatorFacet).provideSmartWallet( - walletAddr, - bank, - namesByAddressAdmin, - ); - !isNew || Fail`wallet in nullUpgradeV1 should not be new`; - wallet2 === wallet || Fail`must be same wallet obj`; - - const currentStoragePath = await E.get( - E.get(E(wallet).getPublicTopics()).current, - ).storagePath; - currentStoragePath === currentPath || Fail`bad storage path`; - - return true; - }, - - upgradeV2: async () => { - trace(`BOOT upgradeV2 start`); - const bundleId = await E(vatAdmin).getBundleIDByName(wfV2BundleName); - - const upgradeResult = await E(adminFacet).upgradeContract( - bundleId, - privateArgs, - ); - assert.equal(upgradeResult.incarnationNumber, 2); - trace(`BOOT upgradeV2 startInstance`); - - const [wallet2, isNew] = await E(creatorFacet).provideSmartWallet( - walletAddr, - bank, - namesByAddressAdmin, - ); - !isNew || Fail`wallet in nullUpgradeV1 should not be new`; - wallet2 === wallet || Fail`must be same wallet obj`; - - const currentStoragePath = await E.get( - E.get(E(wallet).getPublicTopics()).current, - ).storagePath; - currentStoragePath === currentPath || Fail`bad storage path`; - - // verify new method is present - const result = await E(creatorFacet).sayHelloUpgrade(); - result === 'hello, upgrade' || Fail`bad upgrade`; - - return true; - }, - - testOfferV2: async () => { - // If this doesn't throw, the offer succeeded. - // I tried to also check vstorage but it doesn't always update in time. - await E(E(wallet).getOffersFacet()).executeOffer({ - id: 'secondOffer', - invitationSpec: { - source: 'contract', - instance: await automaticRefundInstance, - publicInvitationMaker: 'makeInvitation', - }, - proposal: { - give: { Moola: AmountMath.make(moolaKit.brand, 100n) }, - }, - }); - }, - }); + ); }; diff --git a/packages/smart-wallet/test/test-addAsset.js b/packages/smart-wallet/test/test-addAsset.js index bf9e5de0b6d..2b1d7109903 100644 --- a/packages/smart-wallet/test/test-addAsset.js +++ b/packages/smart-wallet/test/test-addAsset.js @@ -182,22 +182,26 @@ const makeScenario = t => { }; const { entries } = Object; - const uiBridge = Far('UIBridge', { - /** @param {import('@endo/marshal').CapData} offerEncoding */ - proposeOffer: async offerEncoding => { - /** @type {import('../src/offers.js').OfferSpec} */ - const offer = ctx.fromBoard.fromCapData(offerEncoding); - const { give, want } = offer.proposal; - for await (const [kw, amt] of entries({ ...give, ...want })) { - // @ts-expect-error - const { displayInfo } = await auxInfo(amt.brand); - const kind = displayInfo?.assetKind === 'nat' ? 'fungible' : 'NFT'; - t.log('wallet:', kind, 'display for', kw, amt.brand); - } - t.log(addr, 'walletUI: approve offer:', offer.id); - await signAndBroadcast(harden({ method: 'executeOffer', offer })); + const uiBridge = makeExo( + 'UIBridge', + M.interface('UIBridge', {}, { defaultGuards: 'passable' }), + { + /** @param {import('@endo/marshal').CapData} offerEncoding */ + proposeOffer: async offerEncoding => { + /** @type {import('../src/offers.js').OfferSpec} */ + const offer = ctx.fromBoard.fromCapData(offerEncoding); + const { give, want } = offer.proposal; + for await (const [kw, amt] of entries({ ...give, ...want })) { + // @ts-expect-error + const { displayInfo } = await auxInfo(amt.brand); + const kind = displayInfo?.assetKind === 'nat' ? 'fungible' : 'NFT'; + t.log('wallet:', kind, 'display for', kw, amt.brand); + } + t.log(addr, 'walletUI: approve offer:', offer.id); + await signAndBroadcast(harden({ method: 'executeOffer', offer })); + }, }, - }); + ); bridgeKit.resolve(uiBridge); return walletUpdates; }; @@ -233,13 +237,17 @@ test.serial('trading in non-vbank asset: game real-estate NFTs', async t => { assert(namesNode); for (const kind of ['brand', 'instance']) { const kindNode = await E(namesNode).makeChildNode(kind); - const kindUpdater = Far('Updater', { - write: async x => { - // console.log('marshal for vstorage write', x); - const capData = await E(pubm).toCapData(x); - await E(kindNode).setValue(JSON.stringify(capData)); + const kindUpdater = makeExo( + 'Updater', + M.interface('Updater', {}, { defaultGuards: 'passable' }), + { + write: async x => { + // console.log('marshal for vstorage write', x); + const capData = await E(pubm).toCapData(x); + await E(kindNode).setValue(JSON.stringify(capData)); + }, }, - }); + ); await E(kindAdmin(kind)).onUpdate(kindUpdater); } t.log('bootstrap: share agoricNames updates via vstorage RPC'); diff --git a/packages/smart-wallet/test/test-marshal-contexts.js b/packages/smart-wallet/test/test-marshal-contexts.js index 596096da37f..a5182a2e78a 100644 --- a/packages/smart-wallet/test/test-marshal-contexts.js +++ b/packages/smart-wallet/test/test-marshal-contexts.js @@ -10,7 +10,11 @@ import { /** @param {import('@agoric/vats').Board} board */ const makeAMM = board => { - const atom = Far('ATOM brand', {}); + const atom = makeExo( + 'ATOM brand', + M.interface('ATOM brand', {}, { defaultGuards: 'passable' }), + {}, + ); const pub = board.getPublishingMarshaller(); return harden({ getMetrics: () => pub.toCapData(harden([atom])) }); }; @@ -22,7 +26,7 @@ const makeOnChainWallet = board => { return harden({ suggestIssuer: (name, boardId) => { brand = board.getValue(boardId); - const purse = Far(`${name} purse`, { + const purse = makeExo(`${name} purse`, M.interface(`${name} purse`, {}, { defaultGuards: 'passable' }), { getCurrentAmount: () => harden({ brand, value: 100 }), }); // only for private brands @@ -95,7 +99,14 @@ test('makeImportContext preserves identity across AMM and wallet', t => { ); t.throws( - () => context.fromMyWallet.toCapData(Far('widget', {})), + () => + context.fromMyWallet.toCapData( + makeExo( + 'widget', + M.interface('widget', {}, { defaultGuards: 'passable' }), + {}, + ), + ), { message: /unregistered/, }, @@ -104,8 +115,16 @@ test('makeImportContext preserves identity across AMM and wallet', t => { }); test('ensureBoardId allows re-registration; initBoardId does not', t => { - const brandM = Far('Moola brand', {}); - const brandS = Far('Semolean brand', {}); + const brandM = makeExo( + 'Moola brand', + M.interface('Moola brand', {}, { defaultGuards: 'passable' }), + {}, + ); + const brandS = makeExo( + 'Semolean brand', + M.interface('Semolean brand', {}, { defaultGuards: 'passable' }), + {}, + ); const context = makeExportContext(); context.initBoardId('board01', brandM); @@ -117,8 +136,16 @@ test('ensureBoardId allows re-registration; initBoardId does not', t => { }); test('makeExportContext.serialize handles unregistered identities', t => { - const brand = Far('Zoe invitation brand', {}); - const instance = Far('amm instance', {}); + const brand = makeExo( + 'Zoe invitation brand', + M.interface('Zoe invitation brand', {}, { defaultGuards: 'passable' }), + {}, + ); + const instance = makeExo( + 'amm instance', + M.interface('amm instance', {}, { defaultGuards: 'passable' }), + {}, + ); const invitationAmount = harden({ brand, value: [{ instance }] }); const context = makeExportContext(); @@ -140,7 +167,11 @@ test('makeExportContext.serialize handles unregistered identities', t => { t.deepEqual(context.fromCapData(actual), invitationAmount); const myPayment = /** @type {Payment} */ ( - Far('payment', { getAllegedBrand: () => assert.fail('no impl') }) + makeExo( + 'payment', + M.interface('payment', {}, { defaultGuards: 'passable' }), + { getAllegedBrand: () => assert.fail('no impl') }, + ) ); context.savePaymentActions(myPayment); const cap2 = context.toCapData(myPayment); diff --git a/packages/solo/src/captp.js b/packages/solo/src/captp.js index 2052d954553..957776c6c8a 100644 --- a/packages/solo/src/captp.js +++ b/packages/solo/src/captp.js @@ -12,80 +12,84 @@ export const getCapTPHandler = (send, getLocalBootstrap, fallback) => { } return E(fallback)[method](...args); }; - const handler = Far('capTpHandler', { - onOpen(obj, meta) { - const { channelHandle, origin = 'unknown' } = meta || {}; - lastEpoch += 1; - const epoch = lastEpoch; - console.debug(`Starting CapTP#${epoch}`, meta); - const sendObj = o => { - send(o, [channelHandle]); - }; - const { - dispatch, - abort, - getBootstrap: getRemoteBootstrap, - } = makeCapTP( - origin, - sendObj, - async o => getLocalBootstrap(getRemoteBootstrap(), meta, o), - { - // Disambiguate in case we receive messages from different - // connections. - epoch, - onReject(err) { - // Be quieter for sanity's sake. - console.log('CapTP', origin, 'exception:', err); + const handler = makeExo( + 'capTpHandler', + M.interface('capTpHandler', {}, { defaultGuards: 'passable' }), + { + onOpen(obj, meta) { + const { channelHandle, origin = 'unknown' } = meta || {}; + lastEpoch += 1; + const epoch = lastEpoch; + console.debug(`Starting CapTP#${epoch}`, meta); + const sendObj = o => { + send(o, [channelHandle]); + }; + const { + dispatch, + abort, + getBootstrap: getRemoteBootstrap, + } = makeCapTP( + origin, + sendObj, + async o => getLocalBootstrap(getRemoteBootstrap(), meta, o), + { + // Disambiguate in case we receive messages from different + // connections. + epoch, + onReject(err) { + // Be quieter for sanity's sake. + console.log('CapTP', origin, 'exception:', err); + }, }, - }, - ); - chans.set(channelHandle, { - dispatch, - abort, - }); - doFallback('onOpen', obj, meta).catch(e => { - console.error(`Error in fallback onOpen`, e); - }); - }, - onClose(obj, meta) { - console.debug(`Finishing CapTP`, meta); - const chan = chans.get(meta.channelHandle); - if (chan) { - const { abort } = chan; - abort(); - } - chans.delete(meta.channelHandle); - doFallback('onClose', obj, meta).catch(e => { - console.error(`Error in fallback onClose`, e); - }); - }, - onError(obj, meta) { - console.debug(`Error in CapTP`, meta, obj.error); - const chan = chans.get(meta.channelHandle); - if (chan) { - const { abort } = chan; - abort(obj.error); - } - doFallback('onError', obj, meta).catch(e => { - console.error(`Error in fallback onError`, e); - }); - }, - async onMessage(obj, meta) { - console.debug('processing inbound', obj); - const chan = chans.get(meta.channelHandle); - if (chan) { - const { dispatch } = chan; - if (dispatch(obj)) { - return true; + ); + chans.set(channelHandle, { + dispatch, + abort, + }); + doFallback('onOpen', obj, meta).catch(e => { + console.error(`Error in fallback onOpen`, e); + }); + }, + onClose(obj, meta) { + console.debug(`Finishing CapTP`, meta); + const chan = chans.get(meta.channelHandle); + if (chan) { + const { abort } = chan; + abort(); + } + chans.delete(meta.channelHandle); + doFallback('onClose', obj, meta).catch(e => { + console.error(`Error in fallback onClose`, e); + }); + }, + onError(obj, meta) { + console.debug(`Error in CapTP`, meta, obj.error); + const chan = chans.get(meta.channelHandle); + if (chan) { + const { abort } = chan; + abort(obj.error); + } + doFallback('onError', obj, meta).catch(e => { + console.error(`Error in fallback onError`, e); + }); + }, + async onMessage(obj, meta) { + console.debug('processing inbound', obj); + const chan = chans.get(meta.channelHandle); + if (chan) { + const { dispatch } = chan; + if (dispatch(obj)) { + return true; + } + } + const done = await doFallback('onMessage', obj, meta); + if (!done) { + console.error(`Could not find handler ${obj.type}`, obj, meta); } - } - const done = await doFallback('onMessage', obj, meta); - if (!done) { - console.error(`Could not find handler ${obj.type}`, obj, meta); - } - return done; + return done; + }, }, - }); + ); return harden(handler); }; diff --git a/packages/solo/src/vat-http.js b/packages/solo/src/vat-http.js index 70e638e6ff3..d65d242d35f 100644 --- a/packages/solo/src/vat-http.js +++ b/packages/solo/src/vat-http.js @@ -103,141 +103,151 @@ export function buildRootObject(vatPowers) { urlToHandler.set(url, commandHandler); } - return Far('root', { - setCommandDevice(d) { - commandDevice = d; - - const replHandler = getReplHandler(replObjects, send); - void registerURLHandler(replHandler, '/private/repl'); - - // Assign the captp handler. - const captpHandler = Far('captpHandler', { - getBootstrap(_otherSide, _meta) { - // Harden only our exported objects, and fetch them afresh each time. - const exported = { - loadingNotifier, - ...replObjects.home, - }; - if (replObjects.agoric) { - exported.agoric = { ...replObjects.agoric }; - } - if (replObjects.local) { - exported.local = { ...replObjects.local }; - } - return harden(exported); - }, - }); - void registerURLHandler(captpHandler, '/private/captp'); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + setCommandDevice(d) { + commandDevice = d; + + const replHandler = getReplHandler(replObjects, send); + void registerURLHandler(replHandler, '/private/repl'); + + // Assign the captp handler. + const captpHandler = makeExo( + 'captpHandler', + M.interface('captpHandler', {}, { defaultGuards: 'passable' }), + { + getBootstrap(_otherSide, _meta) { + // Harden only our exported objects, and fetch them afresh each time. + const exported = { + loadingNotifier, + ...replObjects.home, + }; + if (replObjects.agoric) { + exported.agoric = { ...replObjects.agoric }; + } + if (replObjects.local) { + exported.local = { ...replObjects.local }; + } + return harden(exported); + }, + }, + ); + void registerURLHandler(captpHandler, '/private/captp'); + }, - registerURLHandler, - registerAPIHandler: h => registerURLHandler(h, '/api'), - send, - doneLoading, + registerURLHandler, + registerAPIHandler: h => registerURLHandler(h, '/api'), + send, + doneLoading, + + setWallet(wallet) { + replObjects.local.wallet = wallet; + replObjects.home.wallet = wallet; + resolveCacheCooordinator( + E(E(wallet).getBridge()).getCacheCoordinator(), + ); + }, - setWallet(wallet) { - replObjects.local.wallet = wallet; - replObjects.home.wallet = wallet; - resolveCacheCooordinator(E(E(wallet).getBridge()).getCacheCoordinator()); - }, + /** + * @param {object} [privateObjects] + * @param {object} [decentralObjects] + * @param {object} [deprecatedObjects] + */ + setPresences( + privateObjects = undefined, + decentralObjects = undefined, + deprecatedObjects = undefined, + ) { + // We need to mutate the repl subobjects instead of replacing them. + if (privateObjects) { + Object.assign(replObjects.local, privateObjects); + doneLoading(['local']); + } - /** - * @param {object} [privateObjects] - * @param {object} [decentralObjects] - * @param {object} [deprecatedObjects] - */ - setPresences( - privateObjects = undefined, - decentralObjects = undefined, - deprecatedObjects = undefined, - ) { - // We need to mutate the repl subobjects instead of replacing them. - if (privateObjects) { - Object.assign(replObjects.local, privateObjects); - doneLoading(['local']); - } + if (decentralObjects) { + // Assign the complete decentralObjects to `agoric`. + Object.assign(replObjects.agoric, decentralObjects); + doneLoading(['agoric']); + + // Prune out the demo governance stuff from `home`; they're noisy. + const { + behaviors: _, + governanceActions: _2, + ...rest + } = decentralObjects; + decentralObjects = rest; + } - if (decentralObjects) { - // Assign the complete decentralObjects to `agoric`. - Object.assign(replObjects.agoric, decentralObjects); - doneLoading(['agoric']); + // TODO: Maybe remove sometime; home object is deprecated. + Object.assign( + replObjects.home, + decentralObjects, + privateObjects, + deprecatedObjects, + ); + }, - // Prune out the demo governance stuff from `home`; they're noisy. + // devices.command invokes our inbound() because we passed to + // registerInboundHandler() + async inbound(count, rawObj) { + // Launder the data, since the command device tends to pass device nodes + // when there are empty objects, which screw things up for us. + // Analysis is in https://github.com/Agoric/agoric-sdk/pull/1956 + const obj = JSON.parse(JSON.stringify(rawObj)); + console.debug( + `vat-http.inbound (from browser) ${count}`, + JSON.stringify(obj, undefined, 2), + ); + + const { type, meta: rawMeta = {} } = obj || {}; const { - behaviors: _, - governanceActions: _2, - ...rest - } = decentralObjects; - decentralObjects = rest; - } - - // TODO: Maybe remove sometime; home object is deprecated. - Object.assign( - replObjects.home, - decentralObjects, - privateObjects, - deprecatedObjects, - ); - }, - - // devices.command invokes our inbound() because we passed to - // registerInboundHandler() - async inbound(count, rawObj) { - // Launder the data, since the command device tends to pass device nodes - // when there are empty objects, which screw things up for us. - // Analysis is in https://github.com/Agoric/agoric-sdk/pull/1956 - const obj = JSON.parse(JSON.stringify(rawObj)); - console.debug( - `vat-http.inbound (from browser) ${count}`, - JSON.stringify(obj, undefined, 2), - ); - - const { type, meta: rawMeta = {} } = obj || {}; - const { - url = '/private/repl', - channelID: rawChannelID, - dispatcher = 'onMessage', - } = rawMeta; - - await null; - try { - let channelHandle = channelIdToHandle.get(rawChannelID); - if (dispatcher === 'onOpen') { - channelHandle = Far('channelHandle'); - channelIdToHandle.set(rawChannelID, channelHandle); - channelHandleToId.set(channelHandle, rawChannelID); - } else if (dispatcher === 'onClose') { - channelIdToHandle.delete(rawChannelID); - channelHandleToId.delete(channelHandle); - } - - delete obj.meta; + url = '/private/repl', + channelID: rawChannelID, + dispatcher = 'onMessage', + } = rawMeta; + + await null; + try { + let channelHandle = channelIdToHandle.get(rawChannelID); + if (dispatcher === 'onOpen') { + channelHandle = Far('channelHandle'); + channelIdToHandle.set(rawChannelID, channelHandle); + channelHandleToId.set(channelHandle, rawChannelID); + } else if (dispatcher === 'onClose') { + channelIdToHandle.delete(rawChannelID); + channelHandleToId.delete(channelHandle); + } - const meta = { - ...rawMeta, - channelHandle, - }; - delete meta.channelID; + delete obj.meta; - const urlHandler = urlToHandler.get(url); - if (urlHandler) { - const res = await E(urlHandler)[dispatcher](obj, meta); - if (res) { - sendResponse(count, false, res); - return; + const meta = { + ...rawMeta, + channelHandle, + }; + delete meta.channelID; + + const urlHandler = urlToHandler.get(url); + if (urlHandler) { + const res = await E(urlHandler)[dispatcher](obj, meta); + if (res) { + sendResponse(count, false, res); + return; + } } - } - if (dispatcher === 'onMessage') { - sendResponse(count, false, { type: 'doesNotUnderstand', obj }); - Fail`No handler for ${url} ${type}`; + if (dispatcher === 'onMessage') { + sendResponse(count, false, { type: 'doesNotUnderstand', obj }); + Fail`No handler for ${url} ${type}`; + } + sendResponse(count, false, true); + } catch (rej) { + console.debug(`Error ${dispatcher}:`, rej); + const jsonable = (rej && rej.message) || rej; + sendResponse(count, true, jsonable); } - sendResponse(count, false, true); - } catch (rej) { - console.debug(`Error ${dispatcher}:`, rej); - const jsonable = (rej && rej.message) || rej; - sendResponse(count, true, jsonable); - } + }, }, - }); + ); } diff --git a/packages/solo/src/vat-spawner.js b/packages/solo/src/vat-spawner.js index e7b0b9f8f1a..e42dc7066bf 100644 --- a/packages/solo/src/vat-spawner.js +++ b/packages/solo/src/vat-spawner.js @@ -3,11 +3,15 @@ import { Far } from '@endo/marshal'; import { makeSpawner } from '@agoric/spawner'; function buildRootObject() { - return Far('root', { - buildSpawner(vatAdminSvc) { - return makeSpawner(vatAdminSvc); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + buildSpawner(vatAdminSvc) { + return makeSpawner(vatAdminSvc); + }, }, - }); + ); } harden(buildRootObject); export { buildRootObject }; diff --git a/packages/solo/src/vat-uploads.js b/packages/solo/src/vat-uploads.js index ecfa8195c03..8c1909c9f9f 100644 --- a/packages/solo/src/vat-uploads.js +++ b/packages/solo/src/vat-uploads.js @@ -10,5 +10,9 @@ export function buildRootObject() { return uploads; } - return Far('root', { getUploads }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { getUploads }, + ); } diff --git a/packages/solo/test/test-home.js b/packages/solo/test/test-home.js index 9821f264c9b..97a0c863c78 100644 --- a/packages/solo/test/test-home.js +++ b/packages/solo/test/test-home.js @@ -62,7 +62,11 @@ test.serial('home.board', async t => { `using a non-verified id throws`, ); - const myValue = Far('myValue', {}); + const myValue = makeExo( + 'myValue', + M.interface('myValue', {}, { defaultGuards: 'passable' }), + {}, + ); const myId = await E(board).getId(myValue); t.is(typeof myId, 'string', `board key is string`); @@ -166,18 +170,22 @@ test.serial('home.localTimerService makeNotifier', async t => { function makeHandler() { let calls = 0; const args = []; - return Far('wake handler', { - getCalls() { - return calls; - }, - getArgs() { - return args; + return makeExo( + 'wake handler', + M.interface('wake handler', {}, { defaultGuards: 'passable' }), + { + getCalls() { + return calls; + }, + getArgs() { + return args; + }, + wake(arg) { + args.push(arg); + calls += 1; + }, }, - wake(arg) { - args.push(arg); - calls += 1; - }, - }); + ); } test.serial('home.localTimerService makeRepeater', async t => { diff --git a/packages/spawner/README.md b/packages/spawner/README.md index 6f99547076a..099abc75baf 100644 --- a/packages/spawner/README.md +++ b/packages/spawner/README.md @@ -34,7 +34,7 @@ in the new vat). Your `vat-spawner.js` should look like: import { Far } from '@endo/marshal'; import { makeSpawner } from '@agoric/spawner'; function buildRootObject() { - return Far('root', { + return makeExo('root', M.interface('root', {}, { defaultGuards: 'passable' }), { buildSpawner(vatAdminSvc) { return makeSpawner(vatAdminSvc); } @@ -47,7 +47,7 @@ export { buildRootObject }; And your bootstrap function needs something like this: ```js -return Far('root', { +return makeExo('root', M.interface('root', {}, { defaultGuards: 'passable' }), { async bootstrap(vats, devices) { const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( devices.vatAdmin, diff --git a/packages/spawner/src/contractHost.js b/packages/spawner/src/contractHost.js index 7971e4e728f..cfb6a995362 100644 --- a/packages/spawner/src/contractHost.js +++ b/packages/spawner/src/contractHost.js @@ -8,19 +8,30 @@ import { Far } from '@endo/marshal'; import spawnBundle from '../bundles/bundle-spawn.js'; function makeSpawner(vatAdminSvc) { - return Far('spawner', { - install(bundle, oldModuleFormat) { - assert(!oldModuleFormat, 'oldModuleFormat not supported'); - return Far('installer', { - async spawn(argsP) { - const meter = await E(vatAdminSvc).createUnlimitedMeter(); - const opts = { name: 'spawn', meter }; - const { root } = await E(vatAdminSvc).createVat(spawnBundle, opts); - return E(E(root).loadBundle(bundle)).start(argsP); - }, - }); + return makeExo( + 'spawner', + M.interface('spawner', {}, { defaultGuards: 'passable' }), + { + install(bundle, oldModuleFormat) { + assert(!oldModuleFormat, 'oldModuleFormat not supported'); + return makeExo( + 'installer', + M.interface('installer', {}, { defaultGuards: 'passable' }), + { + async spawn(argsP) { + const meter = await E(vatAdminSvc).createUnlimitedMeter(); + const opts = { name: 'spawn', meter }; + const { root } = await E(vatAdminSvc).createVat( + spawnBundle, + opts, + ); + return E(E(root).loadBundle(bundle)).start(argsP); + }, + }, + ); + }, }, - }); + ); } harden(makeSpawner); diff --git a/packages/spawner/src/vat-spawned.js b/packages/spawner/src/vat-spawned.js index fa33bfa3e47..bfd0727e35f 100644 --- a/packages/spawner/src/vat-spawned.js +++ b/packages/spawner/src/vat-spawned.js @@ -12,16 +12,24 @@ const endowments = { }; export function buildRootObject() { - return Far('root', { - async loadBundle(bundle) { - const ns = await importBundle(bundle, { endowments }); - const startFn = ns.default; - return Far('spawned bundle', { - async start(argsP) { - const args = await argsP; - return startFn(args); - }, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async loadBundle(bundle) { + const ns = await importBundle(bundle, { endowments }); + const startFn = ns.default; + return makeExo( + 'spawned bundle', + M.interface('spawned bundle', {}, { defaultGuards: 'passable' }), + { + async start(argsP) { + const args = await argsP; + return startFn(args); + }, + }, + ); + }, }, - }); + ); } diff --git a/packages/spawner/test/swingsetTests/contractHost/bootstrap.js b/packages/spawner/test/swingsetTests/contractHost/bootstrap.js index 573c1297125..f8f5b6ac1f7 100644 --- a/packages/spawner/test/swingsetTests/contractHost/bootstrap.js +++ b/packages/spawner/test/swingsetTests/contractHost/bootstrap.js @@ -61,27 +61,31 @@ export function buildRootObject(vatPowers, vatParameters) { log(`++ DONE`); } - return Far('root', { - async bootstrap(vats, devices) { - const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, - ); - const spawner = await E(vats.spawner).buildSpawner(vatAdminSvc); - const [mode, trivialBundle] = vatParameters.argv; - switch (mode) { - case 'trivial': { - return trivialContractTest(spawner, trivialBundle); - } - case 'exhaust': { - return exhaustedContractTest(spawner, trivialBundle); - } - case 'farFailure': { - return farFailureContractTest(spawner, trivialBundle); - } - default: { - throw Fail`unrecognized argument value ${mode}`; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + const spawner = await E(vats.spawner).buildSpawner(vatAdminSvc); + const [mode, trivialBundle] = vatParameters.argv; + switch (mode) { + case 'trivial': { + return trivialContractTest(spawner, trivialBundle); + } + case 'exhaust': { + return exhaustedContractTest(spawner, trivialBundle); + } + case 'farFailure': { + return farFailureContractTest(spawner, trivialBundle); + } + default: { + throw Fail`unrecognized argument value ${mode}`; + } } - } + }, }, - }); + ); } diff --git a/packages/spawner/test/swingsetTests/contractHost/trivial.js b/packages/spawner/test/swingsetTests/contractHost/trivial.js index 7d7b8af5085..b68e14b5e55 100644 --- a/packages/spawner/test/swingsetTests/contractHost/trivial.js +++ b/packages/spawner/test/swingsetTests/contractHost/trivial.js @@ -8,25 +8,29 @@ export default function start(terms) { // Do nothing. } } - return Far('trivial', { - getTerms() { - return `terms were: ${terms}`; + return makeExo( + 'trivial', + M.interface('trivial', {}, { defaultGuards: 'passable' }), + { + getTerms() { + return `terms were: ${terms}`; + }, + bar(x) { + return x + 1; + }, + loopForever() { + for (;;) { + // Do nothing. + } + }, + areYouOk() { + return 'yes'; + }, + failureToFar() { + return harden({ + failureReturn() {}, + }); + }, }, - bar(x) { - return x + 1; - }, - loopForever() { - for (;;) { - // Do nothing. - } - }, - areYouOk() { - return 'yes'; - }, - failureToFar() { - return harden({ - failureReturn() {}, - }); - }, - }); + ); } diff --git a/packages/spawner/test/swingsetTests/contractHost/vat-spawner.js b/packages/spawner/test/swingsetTests/contractHost/vat-spawner.js index 766dfe7cb9a..2303fef28a8 100644 --- a/packages/spawner/test/swingsetTests/contractHost/vat-spawner.js +++ b/packages/spawner/test/swingsetTests/contractHost/vat-spawner.js @@ -3,11 +3,15 @@ import { Far } from '@endo/marshal'; import { makeSpawner } from '../../../src/contractHost.js'; function buildRootObject() { - return Far('root', { - buildSpawner(vatAdminSvc) { - return makeSpawner(vatAdminSvc); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + buildSpawner(vatAdminSvc) { + return makeSpawner(vatAdminSvc); + }, }, - }); + ); } harden(buildRootObject); export { buildRootObject }; diff --git a/packages/store/src/stores/scalarMapStore.js b/packages/store/src/stores/scalarMapStore.js index 4440e2dc81c..f5c32319174 100644 --- a/packages/store/src/stores/scalarMapStore.js +++ b/packages/store/src/stores/scalarMapStore.js @@ -168,7 +168,7 @@ export const makeScalarMapStore = ( assertKVOkToSet(key, value); }; - return Far(`scalar MapStore of ${q(tag)}`, { + return makeExo(`scalar MapStore of ${q(tag)}`, M.interface(`scalar MapStore of ${q(tag)}`, {}, { defaultGuards: 'passable' }), { ...makeMapStoreMethods( jsmap, assertKVOkToAdd, diff --git a/packages/store/src/stores/scalarSetStore.js b/packages/store/src/stores/scalarSetStore.js index 11146e5f28c..b0194dea767 100644 --- a/packages/store/src/stores/scalarSetStore.js +++ b/packages/store/src/stores/scalarSetStore.js @@ -109,7 +109,7 @@ export const makeScalarSetStore = ( } }; - return Far(`scalar SetStore of ${q(tag)}`, { + return makeExo(`scalar SetStore of ${q(tag)}`, M.interface(`scalar SetStore of ${q(tag)}`, {}, { defaultGuards: 'passable' }), { ...makeSetStoreMethods(jsset, assertKeyOkToAdd, undefined, tag), }); }; diff --git a/packages/store/src/stores/scalarWeakMapStore.js b/packages/store/src/stores/scalarWeakMapStore.js index 1062ac554b8..b4f97d94c20 100644 --- a/packages/store/src/stores/scalarWeakMapStore.js +++ b/packages/store/src/stores/scalarWeakMapStore.js @@ -131,7 +131,7 @@ export const makeScalarWeakMapStore = ( assertKVOkToSet(key, value); }; - return Far(`scalar WeakMapStore of ${q(tag)}`, { + return makeExo(`scalar WeakMapStore of ${q(tag)}`, M.interface(`scalar WeakMapStore of ${q(tag)}`, {}, { defaultGuards: 'passable' }), { ...makeWeakMapStoreMethods( jsmap, assertKVOkToAdd, diff --git a/packages/store/src/stores/scalarWeakSetStore.js b/packages/store/src/stores/scalarWeakSetStore.js index 68bcdfd594e..7742894f3f5 100644 --- a/packages/store/src/stores/scalarWeakSetStore.js +++ b/packages/store/src/stores/scalarWeakSetStore.js @@ -98,7 +98,7 @@ export const makeScalarWeakSetStore = ( } }; - return Far(`scalar WeakSetStore of ${q(tag)}`, { + return makeExo(`scalar WeakSetStore of ${q(tag)}`, M.interface(`scalar WeakSetStore of ${q(tag)}`, {}, { defaultGuards: 'passable' }), { ...makeWeakSetStoreMethods(jsset, assertKeyOkToAdd, undefined, tag), }); }; diff --git a/packages/store/src/stores/store-utils.js b/packages/store/src/stores/store-utils.js index df5661005c4..034cbecee40 100644 --- a/packages/store/src/stores/store-utils.js +++ b/packages/store/src/stores/store-utils.js @@ -48,32 +48,41 @@ export const makeCurrentKeysKit = ( return sortedKeysMemo; }; - const iterableKeys = Far('Iterable of keys', { - [Symbol.iterator]: () => { - const generation = updateCount; - getSortedKeys(); - const len = sortedKeysMemo.length; - let i = 0; - return Far('Iterator of keys', { - next: () => { - generation === updateCount || Fail`Store ${q(keyName)} cursor stale`; - // If they're equal, then the sortedKeyMemo is the same one - // we started with. - for (;;) { - if (i < len) { - const value = sortedKeysMemo[i]; - i += 1; - if (checkHas(value)) { - return harden({ done: false, value }); + const iterableKeys = makeExo( + 'Iterable of keys', + M.interface('Iterable of keys', {}, { defaultGuards: 'passable' }), + { + [Symbol.iterator]: () => { + const generation = updateCount; + getSortedKeys(); + const len = sortedKeysMemo.length; + let i = 0; + return makeExo( + 'Iterator of keys', + M.interface('Iterator of keys', {}, { defaultGuards: 'passable' }), + { + next: () => { + generation === updateCount || + Fail`Store ${q(keyName)} cursor stale`; + // If they're equal, then the sortedKeyMemo is the same one + // we started with. + for (;;) { + if (i < len) { + const value = sortedKeysMemo[i]; + i += 1; + if (checkHas(value)) { + return harden({ done: false, value }); + } + } else { + return harden({ done: true, value: undefined }); + } } - } else { - return harden({ done: true, value: undefined }); - } - } - }, - }); + }, + }, + ); + }, }, - }); + ); return harden({ assertUpdateOnAdd, diff --git a/packages/store/test/perf-patterns.js b/packages/store/test/perf-patterns.js index c068c31e3b6..407b5725d8b 100644 --- a/packages/store/test/perf-patterns.js +++ b/packages/store/test/perf-patterns.js @@ -223,12 +223,20 @@ const measure = async (title, specimen, yesPattern, factor = 1) => { ); }; -const brand = Far('fungible brand', {}); +const brand = makeExo( + 'fungible brand', + M.interface('fungible brand', {}, { defaultGuards: 'passable' }), + {}, +); const amount1000 = harden({ brand, value: 1000n, }); -const payment1000 = Far('fungible payment', {}); +const payment1000 = makeExo( + 'fungible payment', + M.interface('fungible payment', {}, { defaultGuards: 'passable' }), + {}, +); const proposal = harden({ give: { In: amount1000 }, diff --git a/packages/store/test/test-AtomicProvider.js b/packages/store/test/test-AtomicProvider.js index d6a18bc12ed..85867bee450 100644 --- a/packages/store/test/test-AtomicProvider.js +++ b/packages/store/test/test-AtomicProvider.js @@ -77,7 +77,7 @@ test('far keys', async t => { let i = 0; const makeBrand = name => - Far(`brand ${name}`, { + makeExo(`brand ${name}`, M.interface(`brand ${name}`, {}, { defaultGuards: 'passable' }), { getAllegedName: () => `${name} ${(i += 1)}`, }); diff --git a/packages/store/test/test-store.js b/packages/store/test/test-store.js index b53f6196e31..8d563029def 100644 --- a/packages/store/test/test-store.js +++ b/packages/store/test/test-store.js @@ -91,10 +91,22 @@ test('store', t => { // makeScalarMapStore check(t, 'strong', count => count); // simple numeric keys check(t, 'strong', count => `${count}`); // simple strings - check(t, 'strong', () => Far('handle', {})); + check(t, 'strong', () => + makeExo( + 'handle', + M.interface('handle', {}, { defaultGuards: 'passable' }), + {}, + ), + ); // makeScalarWeakMapStore - check(t, 'weak', () => Far('handle', {})); + check(t, 'weak', () => + makeExo( + 'handle', + M.interface('handle', {}, { defaultGuards: 'passable' }), + {}, + ), + ); }); test('reject promise keys', t => { diff --git a/packages/swingset-liveslots/docs/liveslots.md b/packages/swingset-liveslots/docs/liveslots.md index 40a8c1bbade..28a6147c75b 100644 --- a/packages/swingset-liveslots/docs/liveslots.md +++ b/packages/swingset-liveslots/docs/liveslots.md @@ -17,7 +17,7 @@ import { Far } from '@endo/far'; export function buildRootObject(vatPowers) { let counter = 0; - return Far('root', { + return makeExo('root', M.interface('root', {}, { defaultGuards: 'passable' }), { increment() { counter += 1; }, @@ -38,7 +38,7 @@ The root object *must* be a hardened "ephemeral" object (e.g., created with `Far ```js foo(arg1) { - const obj2 = Far('obj2', { + const obj2 = makeExo('obj2', M.interface('obj2', {}, { defaultGuards: 'passable' }), { bar(arg2) { return 'barbar'; } }); return obj2; diff --git a/packages/swingset-liveslots/src/virtualObjectManager.js b/packages/swingset-liveslots/src/virtualObjectManager.js index 1b4728559a8..c382d92ff06 100644 --- a/packages/swingset-liveslots/src/virtualObjectManager.js +++ b/packages/swingset-liveslots/src/virtualObjectManager.js @@ -1090,7 +1090,11 @@ export const makeVirtualObjectManager = ( const nextInstanceID = loadNextInstanceID(kindID); kindIDToDescriptor.set(kindID, durableKindDescriptor); nextInstanceIDs.set(kindID, nextInstanceID); - const kindHandle = Far('kind', {}); + const kindHandle = makeExo( + 'kind', + M.interface('kind', {}, { defaultGuards: 'passable' }), + {}, + ); kindHandleToID.set(kindHandle, kindID); // KindHandles are held strongly for the remainder of the incarnation, so // their components do not provide GC sensors @@ -1171,7 +1175,11 @@ export const makeVirtualObjectManager = ( /** @type {import('@agoric/vat-data').DurableKindHandle} */ // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error -- https://github.com/Agoric/agoric-sdk/issues/4620 // @ts-ignore cast - const kindHandle = Far('kind', {}); + const kindHandle = makeExo( + 'kind', + M.interface('kind', {}, { defaultGuards: 'passable' }), + {}, + ); kindHandleToID.set(kindHandle, kindID); const kindIDvref = makeBaseRef(kindIDID, kindID, true); registerValue(kindIDvref, kindHandle, false); diff --git a/packages/swingset-liveslots/test/gc-helpers.js b/packages/swingset-liveslots/test/gc-helpers.js index 2cd32a78319..4fb11793c16 100644 --- a/packages/swingset-liveslots/test/gc-helpers.js +++ b/packages/swingset-liveslots/test/gc-helpers.js @@ -59,79 +59,87 @@ export function buildRootObject(vatPowers) { const mainHolder = makeHolder(null); - return Far('root', { - makeAndHold() { - heldStore = makeMapStore(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + makeAndHold() { + heldStore = makeMapStore(); + }, + makeAndHoldAndKey() { + aWeakMapStore = makeWeakMapStore(); + aWeakSetStore = makeWeakSetStore(); + heldStore = makeMapStore(); + aWeakMapStore.init(heldStore, 'arbitrary'); + aWeakSetStore.add(heldStore); + }, + makeAndHoldWeakly() { + aWeakMapStore = makeWeakMapStore(); + heldStore = makeMapStore(); + const indirValue = makeMapStore(); + aWeakMapStore.init(heldStore, indirValue); + }, + makeAndHoldRemotable() { + heldStore = makeExo( + 'thing', + M.interface('thing', {}, { defaultGuards: 'passable' }), + {}, + ); + }, + dropHeld() { + heldStore = null; + }, + storeHeld() { + mainHolder.set('foo', heldStore); + }, + dropStored() { + mainHolder.set('foo', null); + }, + fetchAndHold() { + heldStore = mainHolder.get('foo'); + }, + exportHeld() { + return heldStore; + }, + importAndHold(thing) { + heldStore = thing; + }, + importAndHoldAndKey(key) { + aWeakMapStore = makeWeakMapStore(); + aWeakSetStore = makeWeakSetStore(); + heldStore = key; + aWeakMapStore.init(key, 'arbitrary'); + aWeakSetStore.add(key); + }, + + prepareStore3() { + holders.push(makeHolder(heldStore)); + holders.push(makeHolder(heldStore)); + holders.push(makeHolder(heldStore)); + heldStore = null; + }, + finishClearHolders() { + for (let i = 0; i < holders.length; i += 1) { + holders[i].set('foo', null); + } + }, + finishDropHolders() { + for (let i = 0; i < holders.length; i += 1) { + holders[i] = null; + } + }, + prepareStoreLinked() { + let holder = makeHolder(heldStore); // Map7->Map6 + holder = makeHolder(holder); // Map8->Map7 + holder = makeHolder(holder); // Map9->Map8 + holders.push(holder); // RAM->Map9 + heldStore = null; // remove RAM->Map6 + }, + noOp() { + // used when an extra cycle is needed to pump GC + }, }, - makeAndHoldAndKey() { - aWeakMapStore = makeWeakMapStore(); - aWeakSetStore = makeWeakSetStore(); - heldStore = makeMapStore(); - aWeakMapStore.init(heldStore, 'arbitrary'); - aWeakSetStore.add(heldStore); - }, - makeAndHoldWeakly() { - aWeakMapStore = makeWeakMapStore(); - heldStore = makeMapStore(); - const indirValue = makeMapStore(); - aWeakMapStore.init(heldStore, indirValue); - }, - makeAndHoldRemotable() { - heldStore = Far('thing', {}); - }, - dropHeld() { - heldStore = null; - }, - storeHeld() { - mainHolder.set('foo', heldStore); - }, - dropStored() { - mainHolder.set('foo', null); - }, - fetchAndHold() { - heldStore = mainHolder.get('foo'); - }, - exportHeld() { - return heldStore; - }, - importAndHold(thing) { - heldStore = thing; - }, - importAndHoldAndKey(key) { - aWeakMapStore = makeWeakMapStore(); - aWeakSetStore = makeWeakSetStore(); - heldStore = key; - aWeakMapStore.init(key, 'arbitrary'); - aWeakSetStore.add(key); - }, - - prepareStore3() { - holders.push(makeHolder(heldStore)); - holders.push(makeHolder(heldStore)); - holders.push(makeHolder(heldStore)); - heldStore = null; - }, - finishClearHolders() { - for (let i = 0; i < holders.length; i += 1) { - holders[i].set('foo', null); - } - }, - finishDropHolders() { - for (let i = 0; i < holders.length; i += 1) { - holders[i] = null; - } - }, - prepareStoreLinked() { - let holder = makeHolder(heldStore); // Map7->Map6 - holder = makeHolder(holder); // Map8->Map7 - holder = makeHolder(holder); // Map9->Map8 - holders.push(holder); // RAM->Map9 - heldStore = null; // remove RAM->Map6 - }, - noOp() { - // used when an extra cycle is needed to pump GC - }, - }); + ); } export function deduceCollectionID(fakestore, ctype, offset) { diff --git a/packages/swingset-liveslots/test/test-baggage.js b/packages/swingset-liveslots/test/test-baggage.js index a1523b647a4..997555611fe 100644 --- a/packages/swingset-liveslots/test/test-baggage.js +++ b/packages/swingset-liveslots/test/test-baggage.js @@ -9,12 +9,16 @@ import { parseVatSlot } from '../src/parseVatSlots.js'; function buildRootObject(vatPowers, vatParameters, baggage) { baggage.has('outside'); baggage.init('outside', 'outer val'); - return Far('root', { - doSomething() { - baggage.get('outside'); - baggage.init('inside', 'inner val'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + doSomething() { + baggage.get('outside'); + baggage.init('inside', 'inner val'); + }, }, - }); + ); } test.serial('exercise baggage', async t => { diff --git a/packages/swingset-liveslots/test/test-collection-schema-refcount.js b/packages/swingset-liveslots/test/test-collection-schema-refcount.js index e563ecf5227..6bf40adc3f7 100644 --- a/packages/swingset-liveslots/test/test-collection-schema-refcount.js +++ b/packages/swingset-liveslots/test/test-collection-schema-refcount.js @@ -26,7 +26,11 @@ const shapetest = test.macro(async (t, collectionType, remotableType) => { const makeDurableThing = VatData.defineDurableKind(handle, initData, {}); switch (remotableType) { case 'ephemeral': - remotable = Far('thing', {}); + remotable = makeExo( + 'thing', + M.interface('thing', {}, { defaultGuards: 'passable' }), + {}, + ); break; case 'virtual': remotable = makeVirtualThing(); @@ -41,7 +45,11 @@ const shapetest = test.macro(async (t, collectionType, remotableType) => { const valueShape = remotable; const durable = collectionType === 'durable'; map = VatData.makeScalarBigMapStore('map', { valueShape, durable }); - return Far('root', {}); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + {}, + ); } const makeNS = () => ({ buildRootObject }); diff --git a/packages/swingset-liveslots/test/test-collection-upgrade.js b/packages/swingset-liveslots/test/test-collection-upgrade.js index ca329209659..45afca41a2b 100644 --- a/packages/swingset-liveslots/test/test-collection-upgrade.js +++ b/packages/swingset-liveslots/test/test-collection-upgrade.js @@ -39,7 +39,11 @@ test('durable collections survive upgrade', async t => { durable, }); baggage.init('set', set1); - return Far('root', {}); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + {}, + ); } const make1 = () => ({ buildRootObject: build1 }); @@ -102,7 +106,11 @@ test('durable collections survive upgrade', async t => { newThing2 = map2.get('thing2')[1]; t.is(newThing2.name(), 'thing2'); set2 = baggage.get('set'); - return Far('root', {}); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + {}, + ); } const make2 = () => ({ buildRootObject: build2 }); diff --git a/packages/swingset-liveslots/test/test-dropped-collection-weakrefs.js b/packages/swingset-liveslots/test/test-dropped-collection-weakrefs.js index 8c197fc79ea..eb7add831ae 100644 --- a/packages/swingset-liveslots/test/test-dropped-collection-weakrefs.js +++ b/packages/swingset-liveslots/test/test-dropped-collection-weakrefs.js @@ -32,7 +32,11 @@ test('droppedCollectionWeakRefs', async t => { // creating a WeakMap/Set should put it in droppedCollectionWeakRefs myVOAwareWeakMap = new WeakMap(); myVOAwareWeakSet = new WeakSet(); - return Far('root', {}); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + {}, + ); } const makeNS = () => ({ buildRootObject }); diff --git a/packages/swingset-liveslots/test/test-durabilityChecks.js b/packages/swingset-liveslots/test/test-durabilityChecks.js index a939a681213..5e373c482b3 100644 --- a/packages/swingset-liveslots/test/test-durabilityChecks.js +++ b/packages/swingset-liveslots/test/test-durabilityChecks.js @@ -33,11 +33,15 @@ async function runDurabilityCheckTest(t, relaxDurabilityRules) { const aString = 'zorch!'; const aVirtualObject = makeVirtualHolder(); const aDurableObject = makeDurableHolder(); - const aRemotableObject = Far('what', { - aMethod() { - return 'remote whatever'; + const aRemotableObject = makeExo( + 'what', + M.interface('what', {}, { defaultGuards: 'passable' }), + { + aMethod() { + return 'remote whatever'; + }, }, - }); + ); const aPassablePromise = harden(Promise.resolve(aString)); const aPassableError = harden(Error(aString)); const aNonScalarKey = harden([]); diff --git a/packages/swingset-liveslots/test/test-gc-sensitivity.js b/packages/swingset-liveslots/test/test-gc-sensitivity.js index 4952446c911..d36474e1057 100644 --- a/packages/swingset-liveslots/test/test-gc-sensitivity.js +++ b/packages/swingset-liveslots/test/test-gc-sensitivity.js @@ -17,21 +17,25 @@ test.failing('kind handle reanimation', async t => { VatData.defineDurableKind(kh0, () => ({}), {}); baggage.init('kh', kh0); - const root = Far('root', { - fetch1() { - // console.log(`--fetch1`); - baggage.get('kh'); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + fetch1() { + // console.log(`--fetch1`); + baggage.get('kh'); + }, + gc() { + // console.log(`--gc`); + gcTools.kill(kh0); + gcTools.flushAllFRs(); + }, + fetch2() { + // console.log(`--fetch2`); + baggage.get('kh'); + }, }, - gc() { - // console.log(`--gc`); - gcTools.kill(kh0); - gcTools.flushAllFRs(); - }, - fetch2() { - // console.log(`--fetch2`); - baggage.get('kh'); - }, - }); + ); return root; } @@ -84,24 +88,28 @@ test('representative reanimation', async t => { make(); r1.get(); - const root = Far('root', { - fetch1() { - // console.log(`--fetch1`); - baggage.get('k'); - }, - gc() { - // console.log(`--gc`); - gcTools.kill(r0); - gcTools.flushAllFRs(); - // knock r0.innerSelf out of the cache, leave only r1 - make(); - r1.get(); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + fetch1() { + // console.log(`--fetch1`); + baggage.get('k'); + }, + gc() { + // console.log(`--gc`); + gcTools.kill(r0); + gcTools.flushAllFRs(); + // knock r0.innerSelf out of the cache, leave only r1 + make(); + r1.get(); + }, + fetch2() { + // console.log(`--fetch2`); + baggage.get('k'); + }, }, - fetch2() { - // console.log(`--fetch2`); - baggage.get('k'); - }, - }); + ); return root; } @@ -155,21 +163,25 @@ test('collection reanimation', async t => { const c0 = VatData.makeScalarBigMapStore('c', { durable: true }); baggage.init('c', c0); - const root = Far('root', { - fetch1() { - // console.log(`--fetch1`); - baggage.get('c'); - }, - gc() { - // console.log(`--gc`); - gcTools.kill(c0); - gcTools.flushAllFRs(); - }, - fetch2() { - // console.log(`--fetch2`); - baggage.get('c'); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + fetch1() { + // console.log(`--fetch1`); + baggage.get('c'); + }, + gc() { + // console.log(`--gc`); + gcTools.kill(c0); + gcTools.flushAllFRs(); + }, + fetch2() { + // console.log(`--fetch2`); + baggage.get('c'); + }, }, - }); + ); return root; } diff --git a/packages/swingset-liveslots/test/test-handled-promises.js b/packages/swingset-liveslots/test/test-handled-promises.js index e13c0055cae..052a9633c80 100644 --- a/packages/swingset-liveslots/test/test-handled-promises.js +++ b/packages/swingset-liveslots/test/test-handled-promises.js @@ -105,25 +105,29 @@ const buildPromiseWatcherRootObject = (vatPowers, _vatParameters, baggage) => { const localPromises = new Map(); - return Far('root', { - exportPromise: () => [Promise.resolve()], - createLocalPromise: (name, fulfillment, rejection) => { - !localPromises.has(name) || Fail`local promise already exists: ${name}`; - const { promise, resolve, reject } = makePromiseKit(); - if (fulfillment !== undefined) { - resolve(fulfillment); - } else if (rejection !== undefined) { - reject(rejection); - } - localPromises.set(name, promise); - return `created local promise: ${name}`; - }, - watchLocalPromise: name => { - localPromises.has(name) || Fail`local promise not found: ${name}`; - watchPromise(localPromises.get(name), watcher, name); - return `watched local promise: ${name}`; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + exportPromise: () => [Promise.resolve()], + createLocalPromise: (name, fulfillment, rejection) => { + !localPromises.has(name) || Fail`local promise already exists: ${name}`; + const { promise, resolve, reject } = makePromiseKit(); + if (fulfillment !== undefined) { + resolve(fulfillment); + } else if (rejection !== undefined) { + reject(rejection); + } + localPromises.set(name, promise); + return `created local promise: ${name}`; + }, + watchLocalPromise: name => { + localPromises.has(name) || Fail`local promise not found: ${name}`; + watchPromise(localPromises.get(name), watcher, name); + return `watched local promise: ${name}`; + }, }, - }); + ); }; const kvStoreDataV1 = Object.entries({ baggageID: 'o+d6/1', diff --git a/packages/swingset-liveslots/test/test-initial-vrefs.js b/packages/swingset-liveslots/test/test-initial-vrefs.js index c53262d95ad..7c9a35c3ebf 100644 --- a/packages/swingset-liveslots/test/test-initial-vrefs.js +++ b/packages/swingset-liveslots/test/test-initial-vrefs.js @@ -39,14 +39,18 @@ function buildRootObject(vatPowers, vatParameters, baggage) { store1.init('self', store1); } - return Far('root', { - start, - getVinstance1: () => vinstance1, - getKH1: () => kh1, - getDinstance1: () => dinstance1, - getDinstance2: () => dinstance2, - getStore1: () => store1, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + start, + getVinstance1: () => vinstance1, + getKH1: () => kh1, + getDinstance1: () => dinstance1, + getDinstance2: () => dinstance2, + getStore1: () => store1, + }, + ); } test('initial vatstore contents', async t => { diff --git a/packages/swingset-liveslots/test/test-liveslots-mock-gc.js b/packages/swingset-liveslots/test/test-liveslots-mock-gc.js index d7cff5d0967..8f7c7532165 100644 --- a/packages/swingset-liveslots/test/test-liveslots-mock-gc.js +++ b/packages/swingset-liveslots/test/test-liveslots-mock-gc.js @@ -20,17 +20,21 @@ test('dropImports', async t => { const gcTools = makeMockGC(); function build(_vatPowers) { - const root = Far('root', { - hold(imp) { - imports.push(imp); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + hold(imp) { + imports.push(imp); + }, + free() { + gcTools.kill(imports.pop()); + }, + ignore(imp) { + gcTools.kill(imp); + }, }, - free() { - gcTools.kill(imports.pop()); - }, - ignore(imp) { - gcTools.kill(imp); - }, - }); + ); return root; } @@ -163,14 +167,22 @@ test('retention counters', async t => { const gcTools = makeMockGC(); function buildRootObject(_vatPowers) { - const root = Far('root', { - hold(imp) { - held = imp; - }, - exportRemotable() { - return Far('exported', {}); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + hold(imp) { + held = imp; + }, + exportRemotable() { + return makeExo( + 'exported', + M.interface('exported', {}, { defaultGuards: 'passable' }), + {}, + ); + }, }, - }); + ); return root; } @@ -351,7 +363,7 @@ const doublefreetest = test.macro(async (t, mode) => { // mockGC to drop them // things.object1.set(things.collection3); // vdata ref A -> B - // return Far('root', {}); + // return makeExo('root', M.interface('root', {}, { defaultGuards: 'passable' }), {}); let firstName; let lastName; @@ -395,7 +407,11 @@ const doublefreetest = test.macro(async (t, mode) => { fromThing.init('key', toThing); } - return Far('root', {}); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + {}, + ); } const makeNS = () => ({ buildRootObject }); diff --git a/packages/swingset-liveslots/test/test-liveslots-real-gc.js b/packages/swingset-liveslots/test/test-liveslots-real-gc.js index 8832eb04546..18860657da2 100644 --- a/packages/swingset-liveslots/test/test-liveslots-real-gc.js +++ b/packages/swingset-liveslots/test/test-liveslots-real-gc.js @@ -31,21 +31,25 @@ test.serial('liveslots retains pending exported promise', async t => { let collected; const success = []; function build(_vatPowers) { - const root = Far('root', { - make() { - const pk = makePromiseKit(); - collected = watchCollected(pk.promise); - // we export the Promise, but do not retain resolve/reject - return [pk.promise]; - }, - // if liveslots fails to keep a strongref to the Promise, it will have - // been collected by now, and calling check() will fail, because - // liveslots can't create a new Promise import when the allocatedByVat - // says it was an export - check(_p) { - success.push('yes'); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + make() { + const pk = makePromiseKit(); + collected = watchCollected(pk.promise); + // we export the Promise, but do not retain resolve/reject + return [pk.promise]; + }, + // if liveslots fails to keep a strongref to the Promise, it will have + // been collected by now, and calling check() will fail, because + // liveslots can't create a new Promise import when the allocatedByVat + // says it was an export + check(_p) { + success.push('yes'); + }, }, - }); + ); return root; } @@ -70,15 +74,19 @@ test.serial('liveslots retains device nodes', async t => { const recognize = new WeakSet(); // real WeakSet const success = []; function build(_vatPowers) { - const root = Far('root', { - first(dn) { - collected = watchCollected(dn); - recognize.add(dn); - }, - second(dn) { - success.push(recognize.has(dn)); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + first(dn) { + collected = watchCollected(dn); + recognize.add(dn); + }, + second(dn) { + success.push(recognize.has(dn)); + }, }, - }); + ); return root; } @@ -97,16 +105,20 @@ test.serial('GC syscall.dropImports', async t => { let collected; function build(_vatPowers) { const holder = new Set(); - const root = Far('root', { - one(arg) { - holder.add(arg); - collected = watchCollected(arg); - }, - two() {}, - three() { - holder.clear(); // drops the import + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + one(arg) { + holder.add(arg); + collected = watchCollected(arg); + }, + two() {}, + three() { + holder.clear(); // drops the import + }, }, - }); + ); return root; } const { dispatch } = await makeDispatch(syscall, build, 'vatA', { @@ -182,11 +194,15 @@ test.serial('GC dispatch.retireImports', async t => { function build(_vatPowers) { // eslint-disable-next-line no-unused-vars let presence1; - const root = Far('root', { - one(arg) { - presence1 = arg; + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + one(arg) { + presence1 = arg; + }, }, - }); + ); return root; } const { dispatch } = await makeDispatch(syscall, build, 'vatA', { @@ -213,12 +229,20 @@ test.serial('GC dispatch.retireImports', async t => { test.serial('GC dispatch.retireExports', async t => { const { log, syscall } = buildSyscall(); function build(_vatPowers) { - const ex1 = Far('export', {}); - const root = Far('root', { - one() { - return ex1; + const ex1 = makeExo( + 'export', + M.interface('export', {}, { defaultGuards: 'passable' }), + {}, + ); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + one() { + return ex1; + }, }, - }); + ); return root; } const { dispatch } = await makeDispatch(syscall, build, 'vatA', { @@ -257,15 +281,23 @@ test.serial('GC dispatch.dropExports', async t => { const { log, syscall } = buildSyscall(); let collected; function build(_vatPowers) { - const root = Far('root', { - one() { - const ex1 = Far('export', {}); - collected = watchCollected(ex1); - return ex1; - // ex1 goes out of scope, dropping last userspace strongref + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + one() { + const ex1 = makeExo( + 'export', + M.interface('export', {}, { defaultGuards: 'passable' }), + {}, + ); + collected = watchCollected(ex1); + return ex1; + // ex1 goes out of scope, dropping last userspace strongref + }, + two() {}, }, - two() {}, - }); + ); return root; } const { dispatch } = await makeDispatch(syscall, build, 'vatA', { @@ -325,18 +357,26 @@ test.serial( let collected; function build(_vatPowers) { const holder = new Set(); - const root = Far('root', { - hold() { - const ex1 = Far('export', {}); - holder.add(ex1); - collected = watchCollected(ex1); - return ex1; - }, - two() {}, - drop() { - holder.clear(); // drop the last userspace strongref + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + hold() { + const ex1 = makeExo( + 'export', + M.interface('export', {}, { defaultGuards: 'passable' }), + {}, + ); + holder.add(ex1); + collected = watchCollected(ex1); + return ex1; + }, + two() {}, + drop() { + holder.clear(); // drop the last userspace strongref + }, }, - }); + ); return root; } const { dispatch } = await makeDispatch(syscall, build, 'vatA', { diff --git a/packages/swingset-liveslots/test/test-liveslots.js b/packages/swingset-liveslots/test/test-liveslots.js index d926212eb86..2d79b3ca22f 100644 --- a/packages/swingset-liveslots/test/test-liveslots.js +++ b/packages/swingset-liveslots/test/test-liveslots.js @@ -26,18 +26,22 @@ test('calls', async t => { const { log, syscall } = buildSyscall(); function build(_vatPowers) { - return Far('root', { - one() { - log.push('one'); - }, - two(p) { - log.push(`two ${E.resolve(p) === p}`); - p.then( - res => log.push(['res', res]), - rej => log.push(['rej', rej]), - ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + one() { + log.push('one'); + }, + two(p) { + log.push(`two ${E.resolve(p) === p}`); + p.then( + res => log.push(['res', res]), + rej => log.push(['rej', rej]), + ); + }, }, - }); + ); } const { dispatch } = await makeDispatch(syscall, build); log.length = 0; // assume pre-build vatstore operations are correct @@ -75,14 +79,18 @@ test('liveslots pipelines to syscall.send', async t => { const { log, syscall } = buildSyscall(); function build(_vatPowers) { - return Far('root', { - one(x) { - const p1 = E(x).pipe1(); - const p2 = E(p1).pipe2(); - E(p2).pipe3(); - log.push('sent p1p2p3'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + one(x) { + const p1 = E(x).pipe1(); + const p2 = E(p1).pipe2(); + E(p2).pipe3(); + log.push('sent p1p2p3'); + }, }, - }); + ); } const { dispatch } = await makeDispatch(syscall, build); log.length = 0; // assume pre-build vatstore operations are correct @@ -128,16 +136,20 @@ test('liveslots pipeline/non-pipeline calls', async t => { function build(_vatPowers) { let p1; - return Far('onetwo', { - one(p) { - p1 = p; - E(p1).pipe1(); - p1.then(o2 => E(o2).nonpipe2()); - }, - two() { - E(p1).nonpipe3(); + return makeExo( + 'onetwo', + M.interface('onetwo', {}, { defaultGuards: 'passable' }), + { + one(p) { + p1 = p; + E(p1).pipe1(); + p1.then(o2 => E(o2).nonpipe2()); + }, + two() { + E(p1).nonpipe3(); + }, }, - }); + ); } const { dispatch } = await makeDispatch(syscall, build); log.length = 0; // assume pre-build vatstore operations are correct @@ -195,24 +207,28 @@ async function doOutboundPromise(t, mode) { const { log, syscall } = buildSyscall(); function build(_vatPowers) { - return Far('root', { - run(target, resolution) { - let p; // vat creates the promise - if (resolution === 'reject') { - // eslint-disable-next-line prefer-promise-reject-errors - p = Promise.reject('reject'); - } else { - p = Promise.resolve(resolution); // resolves in future turn - } - E(target).one(p); // sends promise - // then sends resolution/rejection - - // Queue up a call that includes the promise again. This will run - // *after* the promise has been resolved. Our current implementation - // will use the same promise identifier. - void Promise.resolve().then(() => E(target).two(p)); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + run(target, resolution) { + let p; // vat creates the promise + if (resolution === 'reject') { + // eslint-disable-next-line prefer-promise-reject-errors + p = Promise.reject('reject'); + } else { + p = Promise.resolve(resolution); // resolves in future turn + } + E(target).one(p); // sends promise + // then sends resolution/rejection + + // Queue up a call that includes the promise again. This will run + // *after* the promise has been resolved. Our current implementation + // will use the same promise identifier. + void Promise.resolve().then(() => E(target).two(p)); + }, }, - }); + ); } const { dispatch } = await makeDispatch(syscall, build); log.length = 0; // assume pre-build vatstore operations are correct @@ -307,20 +323,24 @@ async function doResultPromise(t, mode) { // inhibit GC of the Presence, so the tests see stable syscalls // eslint-disable-next-line no-unused-vars let pin; - return Far('root', { - async run(target1) { - pin = target1; - const p1 = E(target1).getTarget2(); - hush(p1); - const p2 = E(p1).one(); - // p1 resolves first, then p2 resolves on a subsequent crank - await p2; - // the second call to p1 should be sent to the object, not the - // promise, since the resolution of p1 is now known - const p3 = E(p1).two(); - hush(p3); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async run(target1) { + pin = target1; + const p1 = E(target1).getTarget2(); + hush(p1); + const p2 = E(p1).one(); + // p1 resolves first, then p2 resolves on a subsequent crank + await p2; + // the second call to p1 should be sent to the object, not the + // promise, since the resolution of p1 is now known + const p3 = E(p1).two(); + hush(p3); + }, }, - }); + ); } const { dispatch } = await makeDispatch(syscall, build); log.length = 0; // assume pre-build vatstore operations are correct @@ -413,20 +433,24 @@ test('liveslots vs symbols', async t => { const arbitrarySymbol = Symbol.for('arbitrary'); function build(_vatPowers) { - return Far('root', { - [Symbol.asyncIterator](arg) { - return ['ok', 'asyncIterator', arg]; - }, - [arbitrarySymbol](arg) { - return ['ok', 'arbitrary', arg]; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + [Symbol.asyncIterator](arg) { + return ['ok', 'asyncIterator', arg]; + }, + [arbitrarySymbol](arg) { + return ['ok', 'arbitrary', arg]; + }, + sendAsyncIterator(target) { + E(target)[Symbol.asyncIterator]('arg'); + }, + sendArbitrary(target) { + E(target)[arbitrarySymbol]('arg'); + }, }, - sendAsyncIterator(target) { - E(target)[Symbol.asyncIterator]('arg'); - }, - sendArbitrary(target) { - E(target)[arbitrarySymbol]('arg'); - }, - }); + ); } const { dispatch } = await makeDispatch(syscall, build); @@ -483,11 +507,15 @@ test('remote function call', async t => { function build(_vatPowers) { const fun = Far('fun', arg => ['ok', 'funcall', arg]); - return Far('root', { - getFun() { - return fun; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + getFun() { + return fun; + }, }, - }); + ); } const { dispatch } = await makeDispatch(syscall, build); log.length = 0; // assume pre-build vatstore operations are correct @@ -520,8 +548,16 @@ test('capdata size limit on syscalls', async t => { function build(vatPowers) { const { D, VatData, exitVat, exitVatWithFailure } = vatPowers; const { makeScalarBigMapStore, defineKind } = VatData; - const obj1 = Far('obj1', {}); - const obj2 = Far('obj2', {}); + const obj1 = makeExo( + 'obj1', + M.interface('obj1', {}, { defaultGuards: 'passable' }), + {}, + ); + const obj2 = makeExo( + 'obj2', + M.interface('obj2', {}, { defaultGuards: 'passable' }), + {}, + ); const store = makeScalarBigMapStore('test'); async function doFail(f) { @@ -533,98 +569,102 @@ test('capdata size limit on syscalls', async t => { } } - return Far('root', { - async sendTooManySlots(target) { - await doFail(() => E(target).willFail(obj1, obj2)); - }, - async sendBodyTooBig(target) { - await doFail(() => E(target).willFail(longString)); - }, - async resolveTooManySlots(target) { - const pk = makePromiseKit(); - await E(target).takeThis(pk.promise); - pk.resolve([obj1, obj2]); - }, - async resolveBodyTooBig(target) { - const pk = makePromiseKit(); - await E(target).takeThis(pk.promise); - pk.resolve(longString); - }, - returnTooManySlots() { - return [obj1, obj2]; - }, - returnBodyTooBig() { - return longString; - }, - async callTooManySlots(dev) { - await doFail(() => D(dev).willFail(obj1, obj2)); - }, - async callBodyTooBig(dev) { - await doFail(() => D(dev).willFail(longString)); - }, - async voInitTooManySlots() { - await doFail(() => { - const maker = defineKind( - 'test', - () => ({ x: harden([obj1, obj2]) }), - {}, - ); - maker(); - }); - }, - async voInitBodyTooBig() { - await doFail(() => { - const maker = defineKind('test', () => ({ x: longString }), {}); - maker(); - }); - }, - async voSetTooManySlots() { - await doFail(() => { - const maker = defineKind('test', () => ({ x: 0 }), { - setx: ({ state }, x) => { - state.x = x; - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async sendTooManySlots(target) { + await doFail(() => E(target).willFail(obj1, obj2)); + }, + async sendBodyTooBig(target) { + await doFail(() => E(target).willFail(longString)); + }, + async resolveTooManySlots(target) { + const pk = makePromiseKit(); + await E(target).takeThis(pk.promise); + pk.resolve([obj1, obj2]); + }, + async resolveBodyTooBig(target) { + const pk = makePromiseKit(); + await E(target).takeThis(pk.promise); + pk.resolve(longString); + }, + returnTooManySlots() { + return [obj1, obj2]; + }, + returnBodyTooBig() { + return longString; + }, + async callTooManySlots(dev) { + await doFail(() => D(dev).willFail(obj1, obj2)); + }, + async callBodyTooBig(dev) { + await doFail(() => D(dev).willFail(longString)); + }, + async voInitTooManySlots() { + await doFail(() => { + const maker = defineKind( + 'test', + () => ({ x: harden([obj1, obj2]) }), + {}, + ); + maker(); }); - const vo = maker(); - vo.setx(harden([obj1, obj2])); - }); - }, - async voSetBodyTooBig() { - await doFail(() => { - const maker = defineKind('test', () => ({ x: 0 }), { - setx: ({ state }, x) => { - state.x = x; - }, + }, + async voInitBodyTooBig() { + await doFail(() => { + const maker = defineKind('test', () => ({ x: longString }), {}); + maker(); }); - const vo = maker(); - vo.setx(longString); - }); - }, - async storeInitTooManySlots() { - await doFail(() => store.init('key', harden([obj1, obj2]))); - }, - async storeInitBodyTooBig() { - await doFail(() => store.init('key', longString)); - }, - async storeSetTooManySlots() { - await doFail(() => store.set('key', harden([obj1, obj2]))); - }, - async storeSetBodyTooBig() { - await doFail(() => store.set('key', longString)); - }, - exitVatTooManySlots() { - exitVat([obj1, obj2]); - }, - exitVatBodyTooBig() { - exitVat(longString); - }, - exitVatFailTooManySlots() { - exitVatWithFailure([obj1, obj2]); - }, - exitVatFailBodyTooBig() { - exitVatWithFailure(longString); + }, + async voSetTooManySlots() { + await doFail(() => { + const maker = defineKind('test', () => ({ x: 0 }), { + setx: ({ state }, x) => { + state.x = x; + }, + }); + const vo = maker(); + vo.setx(harden([obj1, obj2])); + }); + }, + async voSetBodyTooBig() { + await doFail(() => { + const maker = defineKind('test', () => ({ x: 0 }), { + setx: ({ state }, x) => { + state.x = x; + }, + }); + const vo = maker(); + vo.setx(longString); + }); + }, + async storeInitTooManySlots() { + await doFail(() => store.init('key', harden([obj1, obj2]))); + }, + async storeInitBodyTooBig() { + await doFail(() => store.init('key', longString)); + }, + async storeSetTooManySlots() { + await doFail(() => store.set('key', harden([obj1, obj2]))); + }, + async storeSetBodyTooBig() { + await doFail(() => store.set('key', longString)); + }, + exitVatTooManySlots() { + exitVat([obj1, obj2]); + }, + exitVatBodyTooBig() { + exitVat(longString); + }, + exitVatFailTooManySlots() { + exitVatWithFailure([obj1, obj2]); + }, + exitVatFailBodyTooBig() { + exitVatWithFailure(longString); + }, }, - }); + ); } const { dispatch, testHooks } = await makeDispatch( syscall, @@ -893,11 +933,15 @@ test('disable disavow', async t => { const { log, syscall } = buildSyscall(); function build(vatPowers) { - return Far('root', { - one() { - log.push(!!vatPowers.disavow); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + one() { + log.push(!!vatPowers.disavow); + }, }, - }); + ); } const { dispatch } = await makeDispatch(syscall, build, 'vatA', {}); log.length = 0; // assume pre-build vatstore operations are correct @@ -913,47 +957,51 @@ test('disavow', async t => { const { log, syscall } = buildSyscall(); function build(vatPowers) { - const root = Far('root', { - async one(pres1) { - vatPowers.disavow(pres1); - log.push('disavowed pres1'); - - try { + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async one(pres1) { vatPowers.disavow(pres1); - log.push('oops duplicate disavow worked'); - } catch (err) { - log.push(err); // forbidden to disavow twice - } - log.push('tried duplicate disavow'); - - try { - const pr = Promise.resolve(); - vatPowers.disavow(pr); - log.push('oops disavow Promise worked'); - } catch (err) { - log.push(err); // forbidden to disavow promises - } - log.push('tried to disavow Promise'); - - try { - vatPowers.disavow(root); - log.push('oops disavow export worked'); - } catch (err) { - log.push(err); // forbidden to disavow exports - } - log.push('tried to disavow export'); - - const p1 = E(pres1).foo(); - // this does a syscall.exit on a subsequent turn - try { - await p1; - log.push('oops send to disavowed worked'); - } catch (err) { - log.push(err); // fatal to send to disavowed - } - log.push('tried to send to disavowed'); + log.push('disavowed pres1'); + + try { + vatPowers.disavow(pres1); + log.push('oops duplicate disavow worked'); + } catch (err) { + log.push(err); // forbidden to disavow twice + } + log.push('tried duplicate disavow'); + + try { + const pr = Promise.resolve(); + vatPowers.disavow(pr); + log.push('oops disavow Promise worked'); + } catch (err) { + log.push(err); // forbidden to disavow promises + } + log.push('tried to disavow Promise'); + + try { + vatPowers.disavow(root); + log.push('oops disavow export worked'); + } catch (err) { + log.push(err); // forbidden to disavow exports + } + log.push('tried to disavow export'); + + const p1 = E(pres1).foo(); + // this does a syscall.exit on a subsequent turn + try { + await p1; + log.push('oops send to disavowed worked'); + } catch (err) { + log.push(err); // fatal to send to disavowed + } + log.push('tried to send to disavowed'); + }, }, - }); + ); return root; } const { dispatch } = await makeDispatch(syscall, build, 'vatA', { @@ -997,7 +1045,11 @@ test('buildVatNamespace not called until after startVat', async t => { function buildRootObject() { buildCalled = true; - return Far('root', {}); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + {}, + ); } const ls = makeLiveSlots(syscall, 'vatA', {}, {}, gcTools, undefined, () => ({ @@ -1014,14 +1066,18 @@ test('simple promise resolution', async t => { const { log, syscall } = buildSyscall(); function build(_vatPowers) { const pkA = makePromiseKit(); - const root = Far('root', { - export() { - return harden({ p: pkA.promise }); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + export() { + return harden({ p: pkA.promise }); + }, + resolve() { + pkA.resolve('data'); + }, }, - resolve() { - pkA.resolve('data'); - }, - }); + ); return root; } const { dispatch } = await makeDispatch(syscall, build, 'vatA', { @@ -1058,14 +1114,18 @@ test('promise cycle', async t => { const pkB = makePromiseKit(); pkA.resolve([pkB.promise]); pkB.resolve([pkA.promise]); - const root = Far('root', { - export() { - return harden({ p: pkA.promise }); - }, - resolve() { - pkA.resolve('data'); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + export() { + return harden({ p: pkA.promise }); + }, + resolve() { + pkA.resolve('data'); + }, }, - }); + ); return root; } const { dispatch } = await makeDispatch(syscall, build, 'vatA', { @@ -1121,14 +1181,18 @@ test('unserializable promise resolution', async t => { const { log, syscall } = buildSyscall(); function build(_vatPowers) { const pkA = makePromiseKit(); - const root = Far('root', { - export() { - return harden({ p: pkA.promise }); - }, - resolve() { - pkA.resolve(unserializable); // causes serialization error + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + export() { + return harden({ p: pkA.promise }); + }, + resolve() { + pkA.resolve(unserializable); // causes serialization error + }, }, - }); + ); return root; } const { dispatch } = await makeDispatch(syscall, build, 'vatA', { @@ -1181,14 +1245,18 @@ test('unserializable promise rejection', async t => { const { log, syscall } = buildSyscall(); function build(_vatPowers) { const pkA = makePromiseKit(); - const root = Far('root', { - export() { - return harden({ p: pkA.promise }); + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + export() { + return harden({ p: pkA.promise }); + }, + resolve() { + pkA.reject(unserializable); // causes serialization error + }, }, - resolve() { - pkA.reject(unserializable); // causes serialization error - }, - }); + ); return root; } const { dispatch } = await makeDispatch(syscall, build, 'vatA', { @@ -1288,19 +1356,23 @@ test('result promise in args', async t => { // is good, because we won't recognize the vpid by that point. function build(_vatPowers) { - return Far('root', { - one(p, target) { - // the promise we receive should have the same identity as our - // result promise - E(target).two(p); - // we should be able to pipeline messages to it - E(p).three(); - // we can subscribe to it, even though we're the decider - p.then(res => vatlog.push(`res: ${res === target}`)); - // and we should be able to resolve it - return target; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + one(p, target) { + // the promise we receive should have the same identity as our + // result promise + E(target).two(p); + // we should be able to pipeline messages to it + E(p).three(); + // we can subscribe to it, even though we're the decider + p.then(res => vatlog.push(`res: ${res === target}`)); + // and we should be able to resolve it + return target; + }, }, - }); + ); } const { dispatch } = await makeDispatch(syscall, build); log.length = 0; // ignore pre-build vatstore operations diff --git a/packages/swingset-liveslots/test/test-vpid-liveslots.js b/packages/swingset-liveslots/test/test-vpid-liveslots.js index e565283c1a8..cd85c5931ea 100644 --- a/packages/swingset-liveslots/test/test-vpid-liveslots.js +++ b/packages/swingset-liveslots/test/test-vpid-liveslots.js @@ -82,14 +82,18 @@ function resolvePR(pr, mode, targets) { break; case 'local-object': pr.resolve( - Far('local-object', { - two() { - /* console.log(`local two() called`); */ + makeExo( + 'local-object', + M.interface('local-object', {}, { defaultGuards: 'passable' }), + { + two() { + /* console.log(`local two() called`); */ + }, + four() { + /* console.log(`local four() called`); */ + }, }, - four() { - /* console.log(`local four() called`); */ - }, - }), + ), ); break; case 'data': @@ -158,17 +162,21 @@ async function doVatResolveCase1(t, mode) { function build(_vatPowers) { const pr = makePromiseKit(); - return Far('root', { - async run(target1, target2) { - const p1 = pr.promise; - E(target1).one(p1); - resolvePR(pr, mode, { target2, p1 }); - // TODO: this stall shouldn't be necessary, but if I omit it, the - // resolution happens *after* two() is sent - await Promise.resolve(); - E(target1).two(p1); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async run(target1, target2) { + const p1 = pr.promise; + E(target1).one(p1); + resolvePR(pr, mode, { target2, p1 }); + // TODO: this stall shouldn't be necessary, but if I omit it, the + // resolution happens *after* two() is sent + await Promise.resolve(); + E(target1).two(p1); + }, }, - }); + ); } const { dispatch } = await makeDispatch(syscall, build); log.length = 0; // assume pre-build vatstore operations are correct @@ -252,74 +260,78 @@ async function doVatResolveCase23(t, which, mode, stalls) { let p1; const pr = makePromiseKit(); const p0 = pr.promise; - return Far('root', { - promise(p) { - p1 = p; - stashP1 = p1; - p1.then( - x => { - // console.log(`p1 resolved to`, x); - resolutionOfP1 = x; - }, - _ => { - // console.log(`p1 rejected`); - resolutionOfP1 = 'rejected'; - }, - ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + promise(p) { + p1 = p; + stashP1 = p1; + p1.then( + x => { + // console.log(`p1 resolved to`, x); + resolutionOfP1 = x; + }, + _ => { + // console.log(`p1 rejected`); + resolutionOfP1 = 'rejected'; + }, + ); + }, + result() { + return p0; + }, + async run(target1, target2) { + // console.log(`calling one()`); + const p2 = E(target1).one(p1); + hush(p2); + // console.log(`calling two()`); + const p3 = E(p1).two(); + hush(p3); + // The call to our result() method gave our vat access to p1 (along + // with resolution authority), but it didn't give this user-level + // code access to p1. When we resolve the p0 we returned from + // `result`, liveslots will resolve p1 for us. But remember that p0 + // !== p1 . This resolution will eventually cause a + // `syscall.resolve` call into the kernel, and + // will eventually cause `p1` to be resolved to something, which may + // affect both where previously-queued messages (two) wind up, and + // where subsequently sent messages (four) wind up. + + resolvePR(pr, mode, { target2, p1 }); + + // We've started the resolution process, but it cannot complete for + // another few turns. We wait some number of turns before using p1 + // again, to exercise as many race conditions as possible. + for (let i = 0; i < stalls; i += 1) { + await Promise.resolve(); + } + + // If we don't stall here, then all four messages get + // processed before we tell the kernel about the resolution + // (syscall.resolve). + + // If we stall two or more turns, then the resolve goes to the + // kernel before three() and four() are processed. We've + // retired the VPID for p1 when three() goes to serialize it, + // so a new VPID is created. + + // In all cases, two() and four() are queued on a local + // Promise object, so they do not get pipelined into the + // kernel. They are sent to directly to the resolved target + // (or not sent at all, if p1 was rejected or resolved to + // something else). + + // console.log(`calling three()`); + const p4 = E(target1).three(p1); + hush(p4); + // console.log(`calling four()`); + const p5 = E(p1).four(); + hush(p5); + // console.log(`did all calls`); + }, }, - result() { - return p0; - }, - async run(target1, target2) { - // console.log(`calling one()`); - const p2 = E(target1).one(p1); - hush(p2); - // console.log(`calling two()`); - const p3 = E(p1).two(); - hush(p3); - // The call to our result() method gave our vat access to p1 (along - // with resolution authority), but it didn't give this user-level - // code access to p1. When we resolve the p0 we returned from - // `result`, liveslots will resolve p1 for us. But remember that p0 - // !== p1 . This resolution will eventually cause a - // `syscall.resolve` call into the kernel, and - // will eventually cause `p1` to be resolved to something, which may - // affect both where previously-queued messages (two) wind up, and - // where subsequently sent messages (four) wind up. - - resolvePR(pr, mode, { target2, p1 }); - - // We've started the resolution process, but it cannot complete for - // another few turns. We wait some number of turns before using p1 - // again, to exercise as many race conditions as possible. - for (let i = 0; i < stalls; i += 1) { - await Promise.resolve(); - } - - // If we don't stall here, then all four messages get - // processed before we tell the kernel about the resolution - // (syscall.resolve). - - // If we stall two or more turns, then the resolve goes to the - // kernel before three() and four() are processed. We've - // retired the VPID for p1 when three() goes to serialize it, - // so a new VPID is created. - - // In all cases, two() and four() are queued on a local - // Promise object, so they do not get pipelined into the - // kernel. They are sent to directly to the resolved target - // (or not sent at all, if p1 was rejected or resolved to - // something else). - - // console.log(`calling three()`); - const p4 = E(target1).three(p1); - hush(p4); - // console.log(`calling four()`); - const p5 = E(p1).four(); - hush(p5); - // console.log(`did all calls`); - }, - }); + ); } const { dispatch } = await makeDispatch(syscall, build); log.length = 0; // assume pre-build vatstore operations are correct @@ -546,30 +558,34 @@ async function doVatResolveCase4(t, mode) { function build(_vatPowers) { let p1; - return Far('local-object', { - async get(p) { - p1 = p; - // if we don't add this, node will complain when the kernel notifies - // us of the rejection - hush(p1); - }, - async first(target1) { - const p2 = E(target1).one(p1); - hush(p2); - const p3 = E(p1).two(); - hush(p3); + return makeExo( + 'local-object', + M.interface('local-object', {}, { defaultGuards: 'passable' }), + { + async get(p) { + p1 = p; + // if we don't add this, node will complain when the kernel notifies + // us of the rejection + hush(p1); + }, + async first(target1) { + const p2 = E(target1).one(p1); + hush(p2); + const p3 = E(p1).two(); + hush(p3); + }, + async second(target1) { + const p4 = E(target1).three(p1); + hush(p4); + const p5 = E(p1).four(); + hush(p5); + }, + // we re-use this root object as a resolution of p1 the 'local-object' + // case, so make sure it can accept the messages + two() {}, + four() {}, }, - async second(target1) { - const p4 = E(target1).three(p1); - hush(p4); - const p5 = E(p1).four(); - hush(p5); - }, - // we re-use this root object as a resolution of p1 the 'local-object' - // case, so make sure it can accept the messages - two() {}, - four() {}, - }); + ); } const { dispatch } = await makeDispatch(syscall, build); log.length = 0; // assume pre-build vatstore operations are correct @@ -683,29 +699,33 @@ async function doVatResolveCase7(t, mode) { function build(_vatPowers) { let p1; const pr = makePromiseKit(); - return Far('root', { - acceptPromise(p) { - p1 = p; - }, - send1(target1) { - hush(E(target1).one(p1)); - hush(E(p1).two()); - }, - becomeDecider() { - return pr.promise; - }, - send2(target1) { - hush(E(target1).three(p1)); - hush(E(p1).four()); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + acceptPromise(p) { + p1 = p; + }, + send1(target1) { + hush(E(target1).one(p1)); + hush(E(p1).two()); + }, + becomeDecider() { + return pr.promise; + }, + send2(target1) { + hush(E(target1).three(p1)); + hush(E(p1).four()); + }, + resolve(target2) { + resolvePR(pr, mode, { target2, p1 }); + }, + send3(target1) { + hush(E(target1).five(p1)); + hush(E(p1).six()); + }, }, - resolve(target2) { - resolvePR(pr, mode, { target2, p1 }); - }, - send3(target1) { - hush(E(target1).five(p1)); - hush(E(p1).six()); - }, - }); + ); } const { dispatch } = await makeDispatch(syscall, build); log.length = 0; // assume pre-build vatstore operations are correct @@ -855,15 +875,19 @@ test('inter-vat circular promise references', async t => { function build(_vatPowers) { let p; let r; - return Far('root', { - genPromise() { - void ([p, r] = makePR()); - return p; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + genPromise() { + void ([p, r] = makePR()); + return p; + }, + usePromise(pa) { + r(pa); + }, }, - usePromise(pa) { - r(pa); - }, - }); + ); } const { dispatch: dispatchA } = await makeDispatch(syscall, build, 'vatA'); // const { dispatch: dispatchB } = await makeDispatch(syscall, build, 'vatB'); diff --git a/packages/swingset-liveslots/test/virtual-objects/test-kind-changes.js b/packages/swingset-liveslots/test/virtual-objects/test-kind-changes.js index 7642eb3a43b..423f903a372 100644 --- a/packages/swingset-liveslots/test/virtual-objects/test-kind-changes.js +++ b/packages/swingset-liveslots/test/virtual-objects/test-kind-changes.js @@ -148,13 +148,17 @@ test('export status across new-facet upgrade', async t => { const bOneTwo = { one, two }; const make = defineDurableKindMulti(kh, init, bOneTwo); - return Far('root', { - exportOne: () => { - const obj1 = make(); - one1 = obj1.one; - return one1; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + exportOne: () => { + const obj1 = make(); + one1 = obj1.one; + return one1; + }, }, - }); + ); } const makeNS1 = () => ({ buildRootObject: build1 }); @@ -196,7 +200,11 @@ test('export status across new-facet upgrade', async t => { const bOneTwoThreeFour = { one, two, three, four }; defineDurableKindMulti(kh, init, bOneTwoThreeFour); - return Far('root', {}); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + {}, + ); } const makeNS2 = () => ({ buildRootObject: build2 }); diff --git a/packages/swingset-liveslots/test/virtual-objects/test-state-shape.js b/packages/swingset-liveslots/test/virtual-objects/test-state-shape.js index 7c9257ba1f6..935ed3dbd40 100644 --- a/packages/swingset-liveslots/test/virtual-objects/test-state-shape.js +++ b/packages/swingset-liveslots/test/virtual-objects/test-state-shape.js @@ -138,15 +138,19 @@ test('durable stateShape refcounts', async t => { const { VatData } = vatPowers; const { makeKindHandle, defineDurableKind } = VatData; - return Far('root', { - accept: _standard1 => 0, // assign it a vref - create: standard1 => { - const kh = makeKindHandle('shaped'); - baggage.init('kh', kh); - const stateShape = { value: standard1 }; - defineDurableKind(kh, init, behavior, { stateShape }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + accept: _standard1 => 0, // assign it a vref + create: standard1 => { + const kh = makeKindHandle('shaped'); + baggage.init('kh', kh); + const stateShape = { value: standard1 }; + defineDurableKind(kh, init, behavior, { stateShape }); + }, }, - }); + ); } const makeNS1 = () => ({ buildRootObject: build1 }); @@ -179,7 +183,11 @@ test('durable stateShape refcounts', async t => { const stateShape = { value: standard2 }; defineDurableKind(kh, init, behavior, { stateShape }); - return Far('root', {}); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + {}, + ); } // to test refcount increment/decrement, we need to override the @@ -219,14 +227,18 @@ test('durable stateShape must match', async t => { const { VatData } = vatPowers; const { makeKindHandle, defineDurableKind } = VatData; - return Far('root', { - create: (obj1, obj2) => { - const kh = makeKindHandle('shaped'); - baggage.init('kh', kh); - const stateShape = { x: obj1, y: obj2 }; - defineDurableKind(kh, init, behavior, { stateShape }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + create: (obj1, obj2) => { + const kh = makeKindHandle('shaped'); + baggage.init('kh', kh); + const stateShape = { x: obj1, y: obj2 }; + defineDurableKind(kh, init, behavior, { stateShape }); + }, }, - }); + ); } const makeNS1 = () => ({ buildRootObject: build1 }); @@ -275,7 +287,11 @@ test('durable stateShape must match', async t => { defineDurableKind(kh, init, behavior, { stateShape }); t.pass(); - return Far('root', {}); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + {}, + ); } // we do *not* override allowStateShapeChanges diff --git a/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectGC.js b/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectGC.js index 2adf582af06..7c0c7448979 100644 --- a/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectGC.js +++ b/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectGC.js @@ -215,96 +215,104 @@ function buildRootObject(vatPowers) { } } - return Far('root', { - makeAndHold(isf) { - heldThing = makeNextThing(isf); - displaceCache(); - }, - makeAndHoldFacets() { - heldThing = makeFacetedThing('thing #0'); - displaceCache(); - }, - makeAndHoldDualMarkers() { - heldThing = makeDualMarkerThing().facetA; - displaceCache(); - }, - makeAndHoldAndKey(isf) { - heldThing = makeNextThing(isf); - aWeakMap.set(heldThing, 'arbitrary'); - aWeakSet.add(heldThing); - displaceCache(); - }, - makeAndHoldRemotable() { - heldThing = Far('thing', {}); - displaceCache(); - }, - dropHeld() { - heldThing = null; - displaceCache(); - }, - storeHeld() { - virtualHolderObj.setValue(heldThing); - displaceCache(); - }, - dropStored() { - virtualHolderObj.setValue(null); - displaceCache(); - }, - fetchAndHold() { - heldThing = virtualHolderObj.getValue(); - displaceCache(); - }, - exportHeld() { - return heldThing; - }, - exportHeldA() { - return heldThing.facetA; - }, - exportHeldB() { - return heldThing.facetB; - }, - importAndHold(thing) { - heldThing = thing; - displaceCache(); - }, - importAndHoldAndKey(thing) { - heldThing = thing; - aWeakMap.set(heldThing, 'arbitrary'); - aWeakSet.add(heldThing); - displaceCache(); - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + makeAndHold(isf) { + heldThing = makeNextThing(isf); + displaceCache(); + }, + makeAndHoldFacets() { + heldThing = makeFacetedThing('thing #0'); + displaceCache(); + }, + makeAndHoldDualMarkers() { + heldThing = makeDualMarkerThing().facetA; + displaceCache(); + }, + makeAndHoldAndKey(isf) { + heldThing = makeNextThing(isf); + aWeakMap.set(heldThing, 'arbitrary'); + aWeakSet.add(heldThing); + displaceCache(); + }, + makeAndHoldRemotable() { + heldThing = makeExo( + 'thing', + M.interface('thing', {}, { defaultGuards: 'passable' }), + {}, + ); + displaceCache(); + }, + dropHeld() { + heldThing = null; + displaceCache(); + }, + storeHeld() { + virtualHolderObj.setValue(heldThing); + displaceCache(); + }, + dropStored() { + virtualHolderObj.setValue(null); + displaceCache(); + }, + fetchAndHold() { + heldThing = virtualHolderObj.getValue(); + displaceCache(); + }, + exportHeld() { + return heldThing; + }, + exportHeldA() { + return heldThing.facetA; + }, + exportHeldB() { + return heldThing.facetB; + }, + importAndHold(thing) { + heldThing = thing; + displaceCache(); + }, + importAndHoldAndKey(thing) { + heldThing = thing; + aWeakMap.set(heldThing, 'arbitrary'); + aWeakSet.add(heldThing); + displaceCache(); + }, - prepareStore3() { - holders.push(makeVirtualHolder(heldThing)); - holders.push(makeVirtualHolder(heldThing)); - holders.push(makeVirtualHolder(heldThing)); - heldThing = null; - displaceCache(); - }, - finishClearHolders() { - for (let i = 0; i < holders.length; i += 1) { - holders[i].setValue(null); - } - displaceCache(); - }, - finishDropHolders() { - for (let i = 0; i < holders.length; i += 1) { - holders[i] = null; - } - displaceCache(); - }, - prepareStoreLinked() { - let holder = makeVirtualHolder(heldThing); - holder = makeVirtualHolder(holder); - holder = makeVirtualHolder(holder); - holders.push(holder); - heldThing = null; - displaceCache(); - }, - noOp() { - // used when an extra cycle is needed to pump GC + prepareStore3() { + holders.push(makeVirtualHolder(heldThing)); + holders.push(makeVirtualHolder(heldThing)); + holders.push(makeVirtualHolder(heldThing)); + heldThing = null; + displaceCache(); + }, + finishClearHolders() { + for (let i = 0; i < holders.length; i += 1) { + holders[i].setValue(null); + } + displaceCache(); + }, + finishDropHolders() { + for (let i = 0; i < holders.length; i += 1) { + holders[i] = null; + } + displaceCache(); + }, + prepareStoreLinked() { + let holder = makeVirtualHolder(heldThing); + holder = makeVirtualHolder(holder); + holder = makeVirtualHolder(holder); + holders.push(holder); + heldThing = null; + displaceCache(); + }, + noOp() { + // used when an extra cycle is needed to pump GC + }, }, - }); + ); } function thingValue(label) { diff --git a/packages/swingset-liveslots/test/virtual-objects/test-vo-real-gc.js b/packages/swingset-liveslots/test/virtual-objects/test-vo-real-gc.js index d2108e7bf9c..fb0a346144a 100644 --- a/packages/swingset-liveslots/test/virtual-objects/test-vo-real-gc.js +++ b/packages/swingset-liveslots/test/virtual-objects/test-vo-real-gc.js @@ -20,17 +20,21 @@ test('virtual object state writes', async t => { // eslint-disable-next-line no-unused-vars ping: ({ state }) => 0, }); - const root = Far('root', { - make: () => { - const thing = makeThing(); - collected = watchCollected(thing); - return thing; + const root = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + make: () => { + const thing = makeThing(); + collected = watchCollected(thing); + return thing; + }, + ping: thing => { + collected = watchCollected(thing); + return thing.ping(); + }, }, - ping: thing => { - collected = watchCollected(thing); - return thing.ping(); - }, - }); + ); return root; } diff --git a/packages/swingset-liveslots/tools/vo-test-harness.js b/packages/swingset-liveslots/tools/vo-test-harness.js index 4885246d7d9..3ee616d1270 100644 --- a/packages/swingset-liveslots/tools/vo-test-harness.js +++ b/packages/swingset-liveslots/tools/vo-test-harness.js @@ -99,32 +99,36 @@ export async function runVOTest(t, prepare, makeTestObject, testTestObject) { return cacheDisplacer.getLabel(); } - return Far('root', { - makeAndHold() { - held = makeTestObject(); - freeChecker.add(held); - displaceCache(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + makeAndHold() { + held = makeTestObject(); + freeChecker.add(held); + displaceCache(); + }, + storeHeld() { + holder.setValue(held); + displaceCache(); + }, + dropHeld() { + held = null; + displaceCache(); + }, + fetchAndHold() { + held = holder.getValue(); + t.falsy( + freeChecker.has(held), + 'somebody continues to hold test object', + ); + displaceCache(); + }, + testHeld(phase) { + testTestObject(held, phase); + }, }, - storeHeld() { - holder.setValue(held); - displaceCache(); - }, - dropHeld() { - held = null; - displaceCache(); - }, - fetchAndHold() { - held = holder.getValue(); - t.falsy( - freeChecker.has(held), - 'somebody continues to hold test object', - ); - displaceCache(); - }, - testHeld(phase) { - testTestObject(held, phase); - }, - }); + ); } const { dispatchMessage } = await setupTestLiveslots( diff --git a/packages/swingset-runner/demo/encouragementBot/bootstrap.js b/packages/swingset-runner/demo/encouragementBot/bootstrap.js index f4a7c410e1c..3ca8309254b 100644 --- a/packages/swingset-runner/demo/encouragementBot/bootstrap.js +++ b/packages/swingset-runner/demo/encouragementBot/bootstrap.js @@ -7,21 +7,25 @@ log(`=> loading bootstrap.js`); export function buildRootObject() { log(`=> setup called`); - return Far('root', { - bootstrap(vats) { - log('=> bootstrap() called'); - E(vats.user) - .talkToBot(vats.bot, 'encouragementBot') - .then( - r => - log( - `=> the promise given by the call to user.talkToBot resolved to '${r}'`, - ), - err => - log( - `=> the promise given by the call to user.talkToBot was rejected '${err}''`, - ), - ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> bootstrap() called'); + E(vats.user) + .talkToBot(vats.bot, 'encouragementBot') + .then( + r => + log( + `=> the promise given by the call to user.talkToBot resolved to '${r}'`, + ), + err => + log( + `=> the promise given by the call to user.talkToBot was rejected '${err}''`, + ), + ); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/encouragementBot/vat-bot.js b/packages/swingset-runner/demo/encouragementBot/vat-bot.js index 1c82ce0a178..238988c02e6 100644 --- a/packages/swingset-runner/demo/encouragementBot/vat-bot.js +++ b/packages/swingset-runner/demo/encouragementBot/vat-bot.js @@ -1,10 +1,14 @@ import { Far } from '@endo/marshal'; export function buildRootObject() { - return Far('root', { - encourageMe(name) { - console.log(`=> encouragementBot.encourageMe got the name: ${name}`); - return `${name}, you are awesome, keep it up!\nbot vat is happy`; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + encourageMe(name) { + console.log(`=> encouragementBot.encourageMe got the name: ${name}`); + return `${name}, you are awesome, keep it up!\nbot vat is happy`; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/encouragementBot/vat-user.js b/packages/swingset-runner/demo/encouragementBot/vat-user.js index 44cc7a801cb..df3bd87e8a7 100644 --- a/packages/swingset-runner/demo/encouragementBot/vat-user.js +++ b/packages/swingset-runner/demo/encouragementBot/vat-user.js @@ -4,15 +4,19 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - return Far('root', { - talkToBot(bot, botName) { - log(`=> user.talkToBot is called with ${botName}`); - E(bot) - .encourageMe('user') - .then(myEncouragement => - log(`=> user receives the encouragement: ${myEncouragement}`), - ); - return 'Thanks for the setup. I sure hope I get some encouragement...\nuser vat is happy\n'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + talkToBot(bot, botName) { + log(`=> user.talkToBot is called with ${botName}`); + E(bot) + .encourageMe('user') + .then(myEncouragement => + log(`=> user receives the encouragement: ${myEncouragement}`), + ); + return 'Thanks for the setup. I sure hope I get some encouragement...\nuser vat is happy\n'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/encouragementBotComms/bootstrap.js b/packages/swingset-runner/demo/encouragementBotComms/bootstrap.js index 93cd8ff1c4b..aed16f23adf 100644 --- a/packages/swingset-runner/demo/encouragementBotComms/bootstrap.js +++ b/packages/swingset-runner/demo/encouragementBotComms/bootstrap.js @@ -7,55 +7,63 @@ log(`=> loading bootstrap.js`); export function buildRootObject(vatPowers) { const { D } = vatPowers; - return Far('root', { - async bootstrap(vats, devices) { - log('=> bootstrap() called'); - - const BOT = 'bot'; - const USER = 'user'; - const BOT_CLIST_INDEX = 0; - - D(devices.loopbox).registerInboundHandler(USER, vats.uservattp); - const usersender = D(devices.loopbox).getSender(USER); - await E(vats.uservattp).registerMailboxDevice(usersender); - const { transmitter: txToBotForUser, setReceiver: setRxFromBotForUser } = - await E(vats.uservattp).addRemote(BOT); - await E(vats.usercomms).addRemote( - BOT, - txToBotForUser, - setRxFromBotForUser, - ); - - D(devices.loopbox).registerInboundHandler(BOT, vats.botvattp); - const botsender = D(devices.loopbox).getSender(BOT); - await E(vats.botvattp).registerMailboxDevice(botsender); - const { transmitter: txToUserForBot, setReceiver: setRxFromUserForBot } = - await E(vats.botvattp).addRemote(USER); - await E(vats.botcomms).addRemote( - USER, - txToUserForBot, - setRxFromUserForBot, - ); - - await E(vats.botcomms).addEgress( - USER, - BOT_CLIST_INDEX, // this would normally be autogenerated - vats.bot, - ); - - const pPBot = E(vats.usercomms).addIngress(BOT, BOT_CLIST_INDEX); - E(vats.user) - .talkToBot(pPBot, 'bot') - .then( - r => - log( - `=> the promise given by the call to user.talkToBot resolved to '${r}'`, - ), - err => - log( - `=> the promise given by the call to user.talkToBot was rejected '${err}''`, - ), + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + log('=> bootstrap() called'); + + const BOT = 'bot'; + const USER = 'user'; + const BOT_CLIST_INDEX = 0; + + D(devices.loopbox).registerInboundHandler(USER, vats.uservattp); + const usersender = D(devices.loopbox).getSender(USER); + await E(vats.uservattp).registerMailboxDevice(usersender); + const { + transmitter: txToBotForUser, + setReceiver: setRxFromBotForUser, + } = await E(vats.uservattp).addRemote(BOT); + await E(vats.usercomms).addRemote( + BOT, + txToBotForUser, + setRxFromBotForUser, + ); + + D(devices.loopbox).registerInboundHandler(BOT, vats.botvattp); + const botsender = D(devices.loopbox).getSender(BOT); + await E(vats.botvattp).registerMailboxDevice(botsender); + const { + transmitter: txToUserForBot, + setReceiver: setRxFromUserForBot, + } = await E(vats.botvattp).addRemote(USER); + await E(vats.botcomms).addRemote( + USER, + txToUserForBot, + setRxFromUserForBot, ); + + await E(vats.botcomms).addEgress( + USER, + BOT_CLIST_INDEX, // this would normally be autogenerated + vats.bot, + ); + + const pPBot = E(vats.usercomms).addIngress(BOT, BOT_CLIST_INDEX); + E(vats.user) + .talkToBot(pPBot, 'bot') + .then( + r => + log( + `=> the promise given by the call to user.talkToBot resolved to '${r}'`, + ), + err => + log( + `=> the promise given by the call to user.talkToBot was rejected '${err}''`, + ), + ); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/encouragementBotComms/vat-bot.js b/packages/swingset-runner/demo/encouragementBotComms/vat-bot.js index 0630a5f61d6..4c0ed06a6b1 100644 --- a/packages/swingset-runner/demo/encouragementBotComms/vat-bot.js +++ b/packages/swingset-runner/demo/encouragementBotComms/vat-bot.js @@ -3,10 +3,14 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - return Far('root', { - encourageMe(name) { - log(`=> encouragementBot.encourageMe got the name: ${name}`); - return `${name}, you are awesome, keep it up!\nbot vat is happy`; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + encourageMe(name) { + log(`=> encouragementBot.encourageMe got the name: ${name}`); + return `${name}, you are awesome, keep it up!\nbot vat is happy`; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/encouragementBotComms/vat-user.js b/packages/swingset-runner/demo/encouragementBotComms/vat-user.js index 44cc7a801cb..df3bd87e8a7 100644 --- a/packages/swingset-runner/demo/encouragementBotComms/vat-user.js +++ b/packages/swingset-runner/demo/encouragementBotComms/vat-user.js @@ -4,15 +4,19 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - return Far('root', { - talkToBot(bot, botName) { - log(`=> user.talkToBot is called with ${botName}`); - E(bot) - .encourageMe('user') - .then(myEncouragement => - log(`=> user receives the encouragement: ${myEncouragement}`), - ); - return 'Thanks for the setup. I sure hope I get some encouragement...\nuser vat is happy\n'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + talkToBot(bot, botName) { + log(`=> user.talkToBot is called with ${botName}`); + E(bot) + .encourageMe('user') + .then(myEncouragement => + log(`=> user receives the encouragement: ${myEncouragement}`), + ); + return 'Thanks for the setup. I sure hope I get some encouragement...\nuser vat is happy\n'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/exchangeBenchmark/bootstrap.js b/packages/swingset-runner/demo/exchangeBenchmark/bootstrap.js index ee6851ec3b7..35c29c88780 100644 --- a/packages/swingset-runner/demo/exchangeBenchmark/bootstrap.js +++ b/packages/swingset-runner/demo/exchangeBenchmark/bootstrap.js @@ -11,81 +11,87 @@ export function buildRootObject(_vatPowers, vatParameters) { let round = 0; let quiet = false; - return Far('root', { - async bootstrap(vats, devices) { - let primeContracts = false; - for (const arg of vatParameters.argv) { - if (arg === '--prime') { - primeContracts = true; - } else if (arg === '--quiet') { - quiet = true; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + let primeContracts = false; + for (const arg of vatParameters.argv) { + if (arg === '--prime') { + primeContracts = true; + } else if (arg === '--quiet') { + quiet = true; + } } - } - const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, - ); - const { zoeService: zoe } = await E(vats.zoe).buildZoe( - vatAdminSvc, - undefined, - 'zcf', - ); + const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + const { zoeService: zoe } = await E(vats.zoe).buildZoe( + vatAdminSvc, + undefined, + 'zcf', + ); - const exchange = await E(zoe).install( - exchangeBundle.bundle, - 'exchangeTestContract', - ); + const exchange = await E(zoe).install( + exchangeBundle.bundle, + 'exchangeTestContract', + ); - const grubStake = [ - [3n, 0n], // Alice: 3 moola, no simoleans - [0n, 3n], // Bob: no moola, 3 simoleans - ]; + const grubStake = [ + [3n, 0n], // Alice: 3 moola, no simoleans + [0n, 3n], // Bob: no moola, 3 simoleans + ]; - const all = [makeIssuerKit('moola'), makeIssuerKit('simoleans')]; - const mints = all.map(objs => objs.mint); - const issuers = all.map(objs => objs.issuer); - const brands = all.map(objs => objs.brand); + const all = [makeIssuerKit('moola'), makeIssuerKit('simoleans')]; + const mints = all.map(objs => objs.mint); + const issuers = all.map(objs => objs.issuer); + const brands = all.map(objs => objs.brand); - function makePayments(values) { - return mints.map((mint, i) => - mint.mintPayment(AmountMath.make(brands[i], values[i])), - ); - } + function makePayments(values) { + return mints.map((mint, i) => + mint.mintPayment(AmountMath.make(brands[i], values[i])), + ); + } - const [alicePayments, bobPayments] = grubStake.map(v => makePayments(v)); + const [alicePayments, bobPayments] = grubStake.map(v => + makePayments(v), + ); - const [moolaIssuer, simoleanIssuer] = issuers; - const issuerKeywordRecord = harden({ - Price: simoleanIssuer, - Asset: moolaIssuer, - }); - const { publicFacet } = await E(zoe).startInstance( - exchange, - issuerKeywordRecord, - undefined, - undefined, - 'contractInstance', - ); + const [moolaIssuer, simoleanIssuer] = issuers; + const issuerKeywordRecord = harden({ + Price: simoleanIssuer, + Asset: moolaIssuer, + }); + const { publicFacet } = await E(zoe).startInstance( + exchange, + issuerKeywordRecord, + undefined, + undefined, + 'contractInstance', + ); - alice = E(vats.alice).build(zoe, issuers, alicePayments, publicFacet); - bob = E(vats.bob).build(zoe, issuers, bobPayments, publicFacet); + alice = E(vats.alice).build(zoe, issuers, alicePayments, publicFacet); + bob = E(vats.bob).build(zoe, issuers, bobPayments, publicFacet); - // Zoe appears to do some one-time setup the first time it's used, so this - // is an optional, sacrificial benchmark round to prime the pump. - if (primeContracts) { - await E(alice).initiateTrade(bob, quiet); - await E(bob).initiateTrade(alice, quiet); - } - }, - async runBenchmarkRound() { - round += 1; - if (round % 2) { - await E(alice).initiateTrade(bob, quiet); - return `round ${round} (alice->bob) complete`; - } else { - await E(bob).initiateTrade(alice, quiet); - return `round ${round} (bob->alice) complete`; - } + // Zoe appears to do some one-time setup the first time it's used, so this + // is an optional, sacrificial benchmark round to prime the pump. + if (primeContracts) { + await E(alice).initiateTrade(bob, quiet); + await E(bob).initiateTrade(alice, quiet); + } + }, + async runBenchmarkRound() { + round += 1; + if (round % 2) { + await E(alice).initiateTrade(bob, quiet); + return `round ${round} (alice->bob) complete`; + } else { + await E(bob).initiateTrade(alice, quiet); + return `round ${round} (bob->alice) complete`; + } + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/exchangeBenchmark/exchanger.js b/packages/swingset-runner/demo/exchangeBenchmark/exchanger.js index c36abe77a38..2a8a56fa723 100755 --- a/packages/swingset-runner/demo/exchangeBenchmark/exchanger.js +++ b/packages/swingset-runner/demo/exchangeBenchmark/exchanger.js @@ -105,15 +105,23 @@ async function build(name, zoe, issuers, payments, publicFacet) { await postReport(quiet); } - return Far('exchanger', { - initiateTrade, - respondToTrade, - }); + return makeExo( + 'exchanger', + M.interface('exchanger', {}, { defaultGuards: 'passable' }), + { + initiateTrade, + respondToTrade, + }, + ); } export function buildRootObject(_vatPowers, vatParameters) { - return Far('root', { - build: (zoe, issuers, payments, publicFacet) => - build(vatParameters.name, zoe, issuers, payments, publicFacet), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (zoe, issuers, payments, publicFacet) => + build(vatParameters.name, zoe, issuers, payments, publicFacet), + }, + ); } diff --git a/packages/swingset-runner/demo/justReply/bootstrap.js b/packages/swingset-runner/demo/justReply/bootstrap.js index f23af9be609..6988668bb30 100644 --- a/packages/swingset-runner/demo/justReply/bootstrap.js +++ b/packages/swingset-runner/demo/justReply/bootstrap.js @@ -7,15 +7,19 @@ log(`=> loading bootstrap.js`); export function buildRootObject() { log(`=> setup called`); - return Far('root', { - bootstrap(vats) { - log('=> bootstrap() called'); - E(vats.alice) - .sayHelloTo(vats.bob) - .then( - r => log(`=> alice.hello(bob) resolved to '${r}'`), - e => log(`=> alice.hello(bob) rejected as '${e}'`), - ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> bootstrap() called'); + E(vats.alice) + .sayHelloTo(vats.bob) + .then( + r => log(`=> alice.hello(bob) resolved to '${r}'`), + e => log(`=> alice.hello(bob) rejected as '${e}'`), + ); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/justReply/vat-alice.js b/packages/swingset-runner/demo/justReply/vat-alice.js index 05be1d30f35..d7b97289eac 100644 --- a/packages/swingset-runner/demo/justReply/vat-alice.js +++ b/packages/swingset-runner/demo/justReply/vat-alice.js @@ -4,15 +4,19 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - return Far('root', { - sayHelloTo(other) { - log(`=> Alice.sayHelloTo`); - const answer = E(other).hello(); - answer.then( - r => log(`=> alice.hello() answer resolved to '${r}'`), - e => log(`=> alice.hello() answer rejected as '${e}'`), - ); - return `Alice started\n`; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + sayHelloTo(other) { + log(`=> Alice.sayHelloTo`); + const answer = E(other).hello(); + answer.then( + r => log(`=> alice.hello() answer resolved to '${r}'`), + e => log(`=> alice.hello() answer rejected as '${e}'`), + ); + return `Alice started\n`; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/justReply/vat-bob.js b/packages/swingset-runner/demo/justReply/vat-bob.js index 09e556b17dd..1c27deaf123 100644 --- a/packages/swingset-runner/demo/justReply/vat-bob.js +++ b/packages/swingset-runner/demo/justReply/vat-bob.js @@ -1,10 +1,14 @@ import { Far } from '@endo/marshal'; export function buildRootObject() { - return Far('root', { - hello() { - console.log(`=> Somebody said hello to Bob`); - return 'hi there!'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + hello() { + console.log(`=> Somebody said hello to Bob`); + return 'hi there!'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/megaPong/bootstrap.js b/packages/swingset-runner/demo/megaPong/bootstrap.js index f4cc6783c63..837e7ebb08d 100644 --- a/packages/swingset-runner/demo/megaPong/bootstrap.js +++ b/packages/swingset-runner/demo/megaPong/bootstrap.js @@ -7,19 +7,25 @@ log(`=> loading bootstrap.js`); export function buildRootObject(_vatPowers, vatParameters) { log(`=> setup called`); - return Far('root', { - bootstrap(vats) { - console.log('=> bootstrap() called'); - E(vats.alice).setNickname('alice'); - E(vats.bob).setNickname('bob'); - E(vats.alice) - .introduceYourselfTo(vats.bob) - .then( - r => log(`=> alice.introduceYourselfTo(bob) resolved to '${r}'`), - e => log(`=> alice.introduceYourselfTo(bob) rejected as '${e}'`), - ); - const count = vatParameters.argv[0] ? Number(vatParameters.argv[0]) : 10; - E(vats.alice).grind('hey!', count); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + console.log('=> bootstrap() called'); + E(vats.alice).setNickname('alice'); + E(vats.bob).setNickname('bob'); + E(vats.alice) + .introduceYourselfTo(vats.bob) + .then( + r => log(`=> alice.introduceYourselfTo(bob) resolved to '${r}'`), + e => log(`=> alice.introduceYourselfTo(bob) rejected as '${e}'`), + ); + const count = vatParameters.argv[0] + ? Number(vatParameters.argv[0]) + : 10; + E(vats.alice).grind('hey!', count); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/megaPong/vat-alice.js b/packages/swingset-runner/demo/megaPong/vat-alice.js index ee86ec9942d..e522d13038f 100644 --- a/packages/swingset-runner/demo/megaPong/vat-alice.js +++ b/packages/swingset-runner/demo/megaPong/vat-alice.js @@ -26,44 +26,52 @@ export function buildRootObject() { let otherNickname = 'unknown'; let total = 0; - return Far('contact', { - ping(tag, count) { - total += 1; - if (count > 0) { - if (ppp(count)) { - log( - `=> ${myNickname} contact for ${otherNickname} receives ping: ${count} ${tag}`, - ); + return makeExo( + 'contact', + M.interface('contact', {}, { defaultGuards: 'passable' }), + { + ping(tag, count) { + total += 1; + if (count > 0) { + if (ppp(count)) { + log( + `=> ${myNickname} contact for ${otherNickname} receives ping: ${count} ${tag}`, + ); + } + E(otherContact).ping(tag, count - 1); + } else if (count < 0) { + if (ppp(total)) { + log( + `=> ${myNickname} contact for ${otherNickname} receives ping #${total}: ${tag}`, + ); + } + E(otherContact).ping(tag, count); } - E(otherContact).ping(tag, count - 1); - } else if (count < 0) { - if (ppp(total)) { - log( - `=> ${myNickname} contact for ${otherNickname} receives ping #${total}: ${tag}`, - ); - } - E(otherContact).ping(tag, count); - } - }, - myNameIs(nickname) { - otherNickname = nickname; - log(`=> ${myNickname} contact is now named ${otherNickname}`); + }, + myNameIs(nickname) { + otherNickname = nickname; + log(`=> ${myNickname} contact is now named ${otherNickname}`); + }, }, - }); + ); } - return Far('root', { - setNickname(nickname) { - myNickname = nickname; - }, - introduceYourselfTo(other) { - log(`=> ${myNickname}.introduce`); - const myContact = makeContact(); - otherContact = E(other).hello(myContact, myNickname); - return `${myNickname} setup done\n${myNickname} vat is happy\n`; - }, - grind(tag, count) { - E(otherContact).ping(tag, count); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + setNickname(nickname) { + myNickname = nickname; + }, + introduceYourselfTo(other) { + log(`=> ${myNickname}.introduce`); + const myContact = makeContact(); + otherContact = E(other).hello(myContact, myNickname); + return `${myNickname} setup done\n${myNickname} vat is happy\n`; + }, + grind(tag, count) { + E(otherContact).ping(tag, count); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/megaPong/vat-bob.js b/packages/swingset-runner/demo/megaPong/vat-bob.js index 992779b70e6..9626fffa308 100644 --- a/packages/swingset-runner/demo/megaPong/vat-bob.js +++ b/packages/swingset-runner/demo/megaPong/vat-bob.js @@ -23,37 +23,45 @@ export function buildRootObject() { let total = 0; function makeContact(otherContact, otherNickname) { - return Far('contact', { - ping(tag, count) { - total += 1; - if (count > 0) { - if (ppp(count)) { - log( - `=> ${myNickname} contact for ${otherNickname} receives ping #${total}: ${count} ${tag}`, - ); + return makeExo( + 'contact', + M.interface('contact', {}, { defaultGuards: 'passable' }), + { + ping(tag, count) { + total += 1; + if (count > 0) { + if (ppp(count)) { + log( + `=> ${myNickname} contact for ${otherNickname} receives ping #${total}: ${count} ${tag}`, + ); + } + E(otherContact).ping(tag, count - 1); + } else if (count < 0) { + if (ppp(total)) { + log( + `=> ${myNickname} contact for ${otherNickname} receives ping #${total}: ${tag}`, + ); + } + E(otherContact).ping(tag, count); } - E(otherContact).ping(tag, count - 1); - } else if (count < 0) { - if (ppp(total)) { - log( - `=> ${myNickname} contact for ${otherNickname} receives ping #${total}: ${tag}`, - ); - } - E(otherContact).ping(tag, count); - } + }, }, - }); + ); } - return Far('root', { - setNickname(nickname) { - myNickname = nickname; - }, - hello(otherContact, otherNickname) { - const myContact = makeContact(otherContact, otherNickname); - E(otherContact).myNameIs(myNickname); - log(`=> ${myNickname}.hello sees ${otherNickname}`); - return myContact; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + setNickname(nickname) { + myNickname = nickname; + }, + hello(otherContact, otherNickname) { + const myContact = makeContact(otherContact, otherNickname); + E(otherContact).myNameIs(myNickname); + log(`=> ${myNickname}.hello sees ${otherNickname}`); + return myContact; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/meterExhaustion/bootstrap.js b/packages/swingset-runner/demo/meterExhaustion/bootstrap.js index e48c5a7edf9..2f891afebce 100644 --- a/packages/swingset-runner/demo/meterExhaustion/bootstrap.js +++ b/packages/swingset-runner/demo/meterExhaustion/bootstrap.js @@ -2,29 +2,35 @@ import { E } from '@endo/eventual-send'; import { Far } from '@endo/marshal'; export function buildRootObject() { - const self = Far('root', { - async bootstrap(vats, devices) { - const vatMaker = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - const boomVat = await E(vatMaker).createVatByName('boomer'); - try { - const boom = await E(boomVat.root).explode(); - console.log(`explode result '${boom}'`); - } catch (e) { - console.log(`explode error '${e}'`); - } - try { - await E(boomVat.adminNode).done(); - console.log(`boomer done ok`); - } catch (e) { - console.log(`boomer done with error '${e}'`); - } - try { - const boom = await E(boomVat.root).explode(); - console.log(`second explode result '${boom}'`); - } catch (e) { - console.log(`second explode error '${e}'`); - } + const self = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatMaker = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + const boomVat = await E(vatMaker).createVatByName('boomer'); + try { + const boom = await E(boomVat.root).explode(); + console.log(`explode result '${boom}'`); + } catch (e) { + console.log(`explode error '${e}'`); + } + try { + await E(boomVat.adminNode).done(); + console.log(`boomer done ok`); + } catch (e) { + console.log(`boomer done with error '${e}'`); + } + try { + const boom = await E(boomVat.root).explode(); + console.log(`second explode result '${boom}'`); + } catch (e) { + console.log(`second explode error '${e}'`); + } + }, }, - }); + ); return self; } diff --git a/packages/swingset-runner/demo/meterExhaustion/vat-boomer.js b/packages/swingset-runner/demo/meterExhaustion/vat-boomer.js index 9cabe872d17..2b2568c2b4f 100644 --- a/packages/swingset-runner/demo/meterExhaustion/vat-boomer.js +++ b/packages/swingset-runner/demo/meterExhaustion/vat-boomer.js @@ -1,10 +1,14 @@ import { Far } from '@endo/marshal'; export function buildRootObject() { - return Far('root', { - explode() { - // eslint-disable-next-line no-unused-vars - const hugantuous = Array(4e9); // arbitrarily too big + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + explode() { + // eslint-disable-next-line no-unused-vars + const hugantuous = Array(4e9); // arbitrarily too big + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/pingPongBenchmark/bootstrap.js b/packages/swingset-runner/demo/pingPongBenchmark/bootstrap.js index 226cf84ff9d..21502b17124 100644 --- a/packages/swingset-runner/demo/pingPongBenchmark/bootstrap.js +++ b/packages/swingset-runner/demo/pingPongBenchmark/bootstrap.js @@ -9,22 +9,26 @@ export function buildRootObject() { log(`=> setup called`); let alice; let bob; - return Far('root', { - bootstrap(vats) { - alice = vats.alice; - bob = vats.bob; - log('=> bootstrap() called'); - E(alice).setNickname('alice'); - E(bob).setNickname('bob'); - E(alice) - .introduceYourselfTo(bob) - .then( - r => log(`=> alice.introduceYourselfTo(bob) resolved to '${r}'`), - e => log(`=> alice.introduceYourselfTo(bob) rejected as '${e}'`), - ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + alice = vats.alice; + bob = vats.bob; + log('=> bootstrap() called'); + E(alice).setNickname('alice'); + E(bob).setNickname('bob'); + E(alice) + .introduceYourselfTo(bob) + .then( + r => log(`=> alice.introduceYourselfTo(bob) resolved to '${r}'`), + e => log(`=> alice.introduceYourselfTo(bob) rejected as '${e}'`), + ); + }, + runBenchmarkRound() { + E(alice).doPing('hey!'); + }, }, - runBenchmarkRound() { - E(alice).doPing('hey!'); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/pingPongBenchmark/vat-alice.js b/packages/swingset-runner/demo/pingPongBenchmark/vat-alice.js index 267aea2bc01..6d16b02f1c7 100644 --- a/packages/swingset-runner/demo/pingPongBenchmark/vat-alice.js +++ b/packages/swingset-runner/demo/pingPongBenchmark/vat-alice.js @@ -9,30 +9,38 @@ export function buildRootObject() { let otherContact = null; function makeContact() { - return Far('contact', { - myNameIs(nickname) { - otherNickname = nickname; - log(`${myNickname}: contact is now named ${otherNickname}`); + return makeExo( + 'contact', + M.interface('contact', {}, { defaultGuards: 'passable' }), + { + myNameIs(nickname) { + otherNickname = nickname; + log(`${myNickname}: contact is now named ${otherNickname}`); + }, + pong(tag, ponger) { + log(`${myNickname}: ponged with "${tag}" by ${ponger}`); + }, }, - pong(tag, ponger) { - log(`${myNickname}: ponged with "${tag}" by ${ponger}`); - }, - }); + ); } - return Far('root', { - setNickname(nickname) { - myNickname = nickname; - }, - introduceYourselfTo(other) { - log(`${myNickname}.introduce`); - const myContact = makeContact(); - otherContact = E(other).hello(myContact, myNickname); - return `${myNickname} setup done\n${myNickname} vat is happy\n`; - }, - doPing(tag) { - log(`${myNickname}: pings ${otherNickname} with ${tag}`); - E(otherContact).ping(tag); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + setNickname(nickname) { + myNickname = nickname; + }, + introduceYourselfTo(other) { + log(`${myNickname}.introduce`); + const myContact = makeContact(); + otherContact = E(other).hello(myContact, myNickname); + return `${myNickname} setup done\n${myNickname} vat is happy\n`; + }, + doPing(tag) { + log(`${myNickname}: pings ${otherNickname} with ${tag}`); + E(otherContact).ping(tag); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/pingPongBenchmark/vat-bob.js b/packages/swingset-runner/demo/pingPongBenchmark/vat-bob.js index 33edb9d5bff..632d55634cb 100644 --- a/packages/swingset-runner/demo/pingPongBenchmark/vat-bob.js +++ b/packages/swingset-runner/demo/pingPongBenchmark/vat-bob.js @@ -7,23 +7,31 @@ export function buildRootObject() { let myNickname; function makeContact(otherContact, otherNickname) { - return Far('contact', { - ping(tag) { - log(`${myNickname}: pinged with "${tag}", ponging ${otherNickname}`); - E(otherContact).pong(tag, myNickname); + return makeExo( + 'contact', + M.interface('contact', {}, { defaultGuards: 'passable' }), + { + ping(tag) { + log(`${myNickname}: pinged with "${tag}", ponging ${otherNickname}`); + E(otherContact).pong(tag, myNickname); + }, }, - }); + ); } - return Far('root', { - setNickname(nickname) { - myNickname = nickname; - }, - hello(otherContact, otherNickname) { - const myContact = makeContact(otherContact, otherNickname); - E(otherContact).myNameIs(myNickname); - log(`${myNickname}.hello sees ${otherNickname}`); - return myContact; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + setNickname(nickname) { + myNickname = nickname; + }, + hello(otherContact, otherNickname) { + const myContact = makeContact(otherContact, otherNickname); + E(otherContact).myNameIs(myNickname); + log(`${myNickname}.hello sees ${otherNickname}`); + return myContact; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/promiseChainBenchmark/bootstrap.js b/packages/swingset-runner/demo/promiseChainBenchmark/bootstrap.js index 7af99b1e461..077cf27bbd1 100644 --- a/packages/swingset-runner/demo/promiseChainBenchmark/bootstrap.js +++ b/packages/swingset-runner/demo/promiseChainBenchmark/bootstrap.js @@ -21,14 +21,18 @@ export function buildRootObject() { ); } - return Far('root', { - bootstrap(vats) { - bob = vats.bob; - p = E(bob).init(); - E(bob).gen(); - }, - runBenchmarkRound() { - waitForNextResolution(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + bob = vats.bob; + p = E(bob).init(); + E(bob).gen(); + }, + runBenchmarkRound() { + waitForNextResolution(); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/promiseChainBenchmark/vat-bob.js b/packages/swingset-runner/demo/promiseChainBenchmark/vat-bob.js index 0686f250230..d7c80c1254d 100644 --- a/packages/swingset-runner/demo/promiseChainBenchmark/vat-bob.js +++ b/packages/swingset-runner/demo/promiseChainBenchmark/vat-bob.js @@ -11,20 +11,24 @@ function makePR() { export function buildRootObject() { let r = null; let value = 0; - return Far('root', { - init() { - let p; - // eslint-disable-next-line prefer-const - void ([p, r] = makePR()); - return p; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + init() { + let p; + // eslint-disable-next-line prefer-const + void ([p, r] = makePR()); + return p; + }, + gen() { + // eslint-disable-next-line prefer-const + let [p, newR] = makePR(); + const answer = [value, p]; + value += 1; + r(answer); + r = newR; + }, }, - gen() { - // eslint-disable-next-line prefer-const - let [p, newR] = makePR(); - const answer = [value, p]; - value += 1; - r(answer); - r = newR; - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCase1/bootstrap.js b/packages/swingset-runner/demo/resolveCase1/bootstrap.js index cbd2263918a..6ac0cb8c506 100644 --- a/packages/swingset-runner/demo/resolveCase1/bootstrap.js +++ b/packages/swingset-runner/demo/resolveCase1/bootstrap.js @@ -7,26 +7,30 @@ log(`=> loading bootstrap.js`); export function buildRootObject() { log(`=> setup called`); - return Far('root', { - bootstrap(vats) { - log('=> Alice: bootstrap() called'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> Alice: bootstrap() called'); - let resolver; - const param = new Promise((theResolver, _theRejector) => { - resolver = theResolver; - }); - log('Alice: sending the promise to Bob'); - const response = E(vats.bob).thisIsYourPromise(param); - log('Alice: resolving the promise that was sent to Bob'); - resolver('Alice says hi!'); - log(`Alice: awaiting Bob's response`); - // prettier-ignore - response.then( + let resolver; + const param = new Promise((theResolver, _theRejector) => { + resolver = theResolver; + }); + log('Alice: sending the promise to Bob'); + const response = E(vats.bob).thisIsYourPromise(param); + log('Alice: resolving the promise that was sent to Bob'); + resolver('Alice says hi!'); + log(`Alice: awaiting Bob's response`); + // prettier-ignore + response.then( r => log(`=> Alice: Bob's response to thisIsYourPromise resolved to '${r}'`), e => log(`=> Alice: Bobs' response to thisIsYourPromise rejected as '${e}'`), ); - log('=> Alice: bootstrap() done'); - return 'Alice started'; + log('=> Alice: bootstrap() done'); + return 'Alice started'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCase1/vat-bob.js b/packages/swingset-runner/demo/resolveCase1/vat-bob.js index 5281a542417..22d3cf311bd 100644 --- a/packages/swingset-runner/demo/resolveCase1/vat-bob.js +++ b/packages/swingset-runner/demo/resolveCase1/vat-bob.js @@ -3,15 +3,19 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - return Far('root', { - thisIsYourPromise(p) { - log('=> Bob: thisIsYourPromise begins'); - p.then( - r => log(`=> Bob: the promise parameter resolved to '${r}'`), - e => log(`=> Bob: the promise parameter rejected as '${e}'`), - ); - log('=> Bob: thisIsYourPromise done'); - return 'Bob got the promise'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + thisIsYourPromise(p) { + log('=> Bob: thisIsYourPromise begins'); + p.then( + r => log(`=> Bob: the promise parameter resolved to '${r}'`), + e => log(`=> Bob: the promise parameter rejected as '${e}'`), + ); + log('=> Bob: thisIsYourPromise done'); + return 'Bob got the promise'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCase2/bootstrap.js b/packages/swingset-runner/demo/resolveCase2/bootstrap.js index c0c1e4da76f..39eebce3587 100644 --- a/packages/swingset-runner/demo/resolveCase2/bootstrap.js +++ b/packages/swingset-runner/demo/resolveCase2/bootstrap.js @@ -7,25 +7,29 @@ log(`=> loading bootstrap.js`); export function buildRootObject() { log(`=> setup called`); - return Far('root', { - bootstrap(vats) { - log('=> Alice: bootstrap() called'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> Alice: bootstrap() called'); - let resolver; - const param = new Promise((theResolver, _theRejector) => { - resolver = theResolver; - }); - log('Alice: resolving the promise that will be sent to Bob'); - resolver('Alice says hi!'); - log(`Alice: sending the promise to Bob and awaiting Bob's response`); - const response = E(vats.bob).thisIsYourPromise(param); - // prettier-ignore - response.then( + let resolver; + const param = new Promise((theResolver, _theRejector) => { + resolver = theResolver; + }); + log('Alice: resolving the promise that will be sent to Bob'); + resolver('Alice says hi!'); + log(`Alice: sending the promise to Bob and awaiting Bob's response`); + const response = E(vats.bob).thisIsYourPromise(param); + // prettier-ignore + response.then( r => log(`=> Alice: Bob's response to thisIsYourPromise resolved to '${r}'`), e => log(`=> Alice: Bobs' response to thisIsYourPromise rejected as '${e}'`), ); - log('=> Alice: bootstrap() done'); - return 'Alice started'; + log('=> Alice: bootstrap() done'); + return 'Alice started'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCase2/vat-bob.js b/packages/swingset-runner/demo/resolveCase2/vat-bob.js index 5281a542417..22d3cf311bd 100644 --- a/packages/swingset-runner/demo/resolveCase2/vat-bob.js +++ b/packages/swingset-runner/demo/resolveCase2/vat-bob.js @@ -3,15 +3,19 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - return Far('root', { - thisIsYourPromise(p) { - log('=> Bob: thisIsYourPromise begins'); - p.then( - r => log(`=> Bob: the promise parameter resolved to '${r}'`), - e => log(`=> Bob: the promise parameter rejected as '${e}'`), - ); - log('=> Bob: thisIsYourPromise done'); - return 'Bob got the promise'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + thisIsYourPromise(p) { + log('=> Bob: thisIsYourPromise begins'); + p.then( + r => log(`=> Bob: the promise parameter resolved to '${r}'`), + e => log(`=> Bob: the promise parameter rejected as '${e}'`), + ); + log('=> Bob: thisIsYourPromise done'); + return 'Bob got the promise'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCase3/bootstrap.js b/packages/swingset-runner/demo/resolveCase3/bootstrap.js index 9d5404caff3..6363d64ec85 100644 --- a/packages/swingset-runner/demo/resolveCase3/bootstrap.js +++ b/packages/swingset-runner/demo/resolveCase3/bootstrap.js @@ -7,18 +7,21 @@ log(`=> loading bootstrap.js`); export function buildRootObject() { log(`=> setup called`); - return Far('root', { - bootstrap(vats) { - log('=> Alice: bootstrap() called'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> Alice: bootstrap() called'); - let resolver; - const param = new Promise((theResolver, _theRejector) => { - resolver = theResolver; - }); - log(`Alice: sending the promise to Bob and awaiting Bob's response`); - const response = E(vats.bob).thisIsYourPromise(param); - // prettier-ignore - response.then( + let resolver; + const param = new Promise((theResolver, _theRejector) => { + resolver = theResolver; + }); + log(`Alice: sending the promise to Bob and awaiting Bob's response`); + const response = E(vats.bob).thisIsYourPromise(param); + // prettier-ignore + response.then( r => { log(`=> Alice: Bob's response to thisIsYourPromise resolved to '${r}'`); log('=> Alice: resolving the promise that was sent to Bob'); @@ -26,8 +29,9 @@ export function buildRootObject() { }, e => log(`=> Alice: Bobs' response to thisIsYourPromise rejected as '${e}'`), ); - log('=> Alice: bootstrap() done'); - return 'Alice started'; + log('=> Alice: bootstrap() done'); + return 'Alice started'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCase3/vat-bob.js b/packages/swingset-runner/demo/resolveCase3/vat-bob.js index 5281a542417..22d3cf311bd 100644 --- a/packages/swingset-runner/demo/resolveCase3/vat-bob.js +++ b/packages/swingset-runner/demo/resolveCase3/vat-bob.js @@ -3,15 +3,19 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - return Far('root', { - thisIsYourPromise(p) { - log('=> Bob: thisIsYourPromise begins'); - p.then( - r => log(`=> Bob: the promise parameter resolved to '${r}'`), - e => log(`=> Bob: the promise parameter rejected as '${e}'`), - ); - log('=> Bob: thisIsYourPromise done'); - return 'Bob got the promise'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + thisIsYourPromise(p) { + log('=> Bob: thisIsYourPromise begins'); + p.then( + r => log(`=> Bob: the promise parameter resolved to '${r}'`), + e => log(`=> Bob: the promise parameter rejected as '${e}'`), + ); + log('=> Bob: thisIsYourPromise done'); + return 'Bob got the promise'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveChain/bootstrap.js b/packages/swingset-runner/demo/resolveChain/bootstrap.js index d834741b674..ba753849f12 100644 --- a/packages/swingset-runner/demo/resolveChain/bootstrap.js +++ b/packages/swingset-runner/demo/resolveChain/bootstrap.js @@ -24,13 +24,17 @@ export function buildRootObject(_vatPowers, options) { ); } - return Far('root', { - bootstrap(vats) { - count = options.argv[0] ? Number(options.argv[0]) : 3; - const bob = vats.bob; - const p = E(bob).init(); - E(bob).gen(); - waitFor(bob, p); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + count = options.argv[0] ? Number(options.argv[0]) : 3; + const bob = vats.bob; + const p = E(bob).init(); + E(bob).gen(); + waitFor(bob, p); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveChain/vat-bob.js b/packages/swingset-runner/demo/resolveChain/vat-bob.js index 0686f250230..d7c80c1254d 100644 --- a/packages/swingset-runner/demo/resolveChain/vat-bob.js +++ b/packages/swingset-runner/demo/resolveChain/vat-bob.js @@ -11,20 +11,24 @@ function makePR() { export function buildRootObject() { let r = null; let value = 0; - return Far('root', { - init() { - let p; - // eslint-disable-next-line prefer-const - void ([p, r] = makePR()); - return p; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + init() { + let p; + // eslint-disable-next-line prefer-const + void ([p, r] = makePR()); + return p; + }, + gen() { + // eslint-disable-next-line prefer-const + let [p, newR] = makePR(); + const answer = [value, p]; + value += 1; + r(answer); + r = newR; + }, }, - gen() { - // eslint-disable-next-line prefer-const - let [p, newR] = makePR(); - const answer = [value, p]; - value += 1; - r(answer); - r = newR; - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCircular/bootstrap.js b/packages/swingset-runner/demo/resolveCircular/bootstrap.js index 5c5f0360d07..0c801811489 100644 --- a/packages/swingset-runner/demo/resolveCircular/bootstrap.js +++ b/packages/swingset-runner/demo/resolveCircular/bootstrap.js @@ -4,11 +4,15 @@ import { Far } from '@endo/marshal'; console.log(`=> loading bootstrap.js`); export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - const pa = E(vats.bob).genPromise1(); - const pb = E(vats.bob).genPromise2(); - E(vats.bob).usePromises([pa], [pb]); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const pa = E(vats.bob).genPromise1(); + const pb = E(vats.bob).genPromise2(); + E(vats.bob).usePromises([pa], [pb]); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCircular/vat-bob.js b/packages/swingset-runner/demo/resolveCircular/vat-bob.js index f010fee593f..3d1d9d72b29 100644 --- a/packages/swingset-runner/demo/resolveCircular/vat-bob.js +++ b/packages/swingset-runner/demo/resolveCircular/vat-bob.js @@ -13,18 +13,22 @@ export function buildRootObject() { let r1; let p2; let r2; - return Far('root', { - genPromise1() { - void ([p1, r1] = makePR()); - return p1; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + genPromise1() { + void ([p1, r1] = makePR()); + return p1; + }, + genPromise2() { + void ([p2, r2] = makePR()); + return p2; + }, + usePromises(pa, pb) { + r1(pb); + r2(pa); + }, }, - genPromise2() { - void ([p2, r2] = makePR()); - return p2; - }, - usePromises(pa, pb) { - r1(pb); - r2(pa); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCircular2/bootstrap.js b/packages/swingset-runner/demo/resolveCircular2/bootstrap.js index 90e50fd17c9..e0647022a04 100644 --- a/packages/swingset-runner/demo/resolveCircular2/bootstrap.js +++ b/packages/swingset-runner/demo/resolveCircular2/bootstrap.js @@ -4,12 +4,16 @@ import { Far } from '@endo/marshal'; console.log(`=> loading bootstrap.js`); export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - const pa = E(vats.bob).genPromise1(); - const pb = E(vats.bob).genPromise2(); - E(vats.bob).usePromises([pa], [pb]); - E(vats.bob).finish(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const pa = E(vats.bob).genPromise1(); + const pb = E(vats.bob).genPromise2(); + E(vats.bob).usePromises([pa], [pb]); + E(vats.bob).finish(); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCircular2/vat-bob.js b/packages/swingset-runner/demo/resolveCircular2/vat-bob.js index 057a05bcaf6..c37f861ed01 100644 --- a/packages/swingset-runner/demo/resolveCircular2/vat-bob.js +++ b/packages/swingset-runner/demo/resolveCircular2/vat-bob.js @@ -14,21 +14,25 @@ export function buildRootObject() { let p2; let r2; let savepa; - return Far('root', { - genPromise1() { - void ([p1, r1] = makePR()); - return p1; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + genPromise1() { + void ([p1, r1] = makePR()); + return p1; + }, + genPromise2() { + void ([p2, r2] = makePR()); + return p2; + }, + usePromises(pa, pb) { + r1(pb); + savepa = pa; + }, + finish() { + r2(savepa); + }, }, - genPromise2() { - void ([p2, r2] = makePR()); - return p2; - }, - usePromises(pa, pb) { - r1(pb); - savepa = pa; - }, - finish() { - r2(savepa); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCircular3/bootstrap.js b/packages/swingset-runner/demo/resolveCircular3/bootstrap.js index 220a2dc1a30..efd47a7f03b 100644 --- a/packages/swingset-runner/demo/resolveCircular3/bootstrap.js +++ b/packages/swingset-runner/demo/resolveCircular3/bootstrap.js @@ -2,12 +2,16 @@ import { E } from '@endo/eventual-send'; import { Far } from '@endo/marshal'; export function buildRootObject() { - return Far('root', { - async bootstrap(vats) { - const pa = E(vats.bob).genPromise1(); - const pb = E(vats.bob).genPromise2(); - E(vats.bob).usePromises([pa], [pb]); - E(vats.alice).acceptPromise(pa); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + const pa = E(vats.bob).genPromise1(); + const pb = E(vats.bob).genPromise2(); + E(vats.bob).usePromises([pa], [pb]); + E(vats.alice).acceptPromise(pa); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCircular3/vat-alice.js b/packages/swingset-runner/demo/resolveCircular3/vat-alice.js index 85d28c90b18..2273a750fd4 100644 --- a/packages/swingset-runner/demo/resolveCircular3/vat-alice.js +++ b/packages/swingset-runner/demo/resolveCircular3/vat-alice.js @@ -1,9 +1,13 @@ import { Far } from '@endo/marshal'; export function buildRootObject() { - return Far('root', { - acceptPromise(_p) { - console.log('Alice got p'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + acceptPromise(_p) { + console.log('Alice got p'); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCircular3/vat-bob.js b/packages/swingset-runner/demo/resolveCircular3/vat-bob.js index f010fee593f..3d1d9d72b29 100644 --- a/packages/swingset-runner/demo/resolveCircular3/vat-bob.js +++ b/packages/swingset-runner/demo/resolveCircular3/vat-bob.js @@ -13,18 +13,22 @@ export function buildRootObject() { let r1; let p2; let r2; - return Far('root', { - genPromise1() { - void ([p1, r1] = makePR()); - return p1; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + genPromise1() { + void ([p1, r1] = makePR()); + return p1; + }, + genPromise2() { + void ([p2, r2] = makePR()); + return p2; + }, + usePromises(pa, pb) { + r1(pb); + r2(pa); + }, }, - genPromise2() { - void ([p2, r2] = makePR()); - return p2; - }, - usePromises(pa, pb) { - r1(pb); - r2(pa); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCircularMultiCrank/bootstrap.js b/packages/swingset-runner/demo/resolveCircularMultiCrank/bootstrap.js index 27e9c158273..7a3d63fc22a 100644 --- a/packages/swingset-runner/demo/resolveCircularMultiCrank/bootstrap.js +++ b/packages/swingset-runner/demo/resolveCircularMultiCrank/bootstrap.js @@ -4,12 +4,16 @@ import { Far } from '@endo/marshal'; console.log(`=> loading bootstrap.js`); export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - const pX = E(vats.bob).genPromiseX(); - const pY = E(vats.bob).genPromiseY(); - E(vats.bob).resPromiseX([pY]); - E(vats.bob).resPromiseY([pX]); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const pX = E(vats.bob).genPromiseX(); + const pY = E(vats.bob).genPromiseY(); + E(vats.bob).resPromiseX([pY]); + E(vats.bob).resPromiseY([pX]); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCircularMultiCrank/vat-bob.js b/packages/swingset-runner/demo/resolveCircularMultiCrank/vat-bob.js index 3debe11fb74..baeb1184bcf 100644 --- a/packages/swingset-runner/demo/resolveCircularMultiCrank/vat-bob.js +++ b/packages/swingset-runner/demo/resolveCircularMultiCrank/vat-bob.js @@ -13,20 +13,24 @@ export function buildRootObject() { let rX; let pY; let rY; - return Far('root', { - genPromiseX() { - void ([pX, rX] = makePR()); - return pX; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + genPromiseX() { + void ([pX, rX] = makePR()); + return pX; + }, + genPromiseY() { + void ([pY, rY] = makePR()); + return pY; + }, + resPromiseX(v) { + rX(v); + }, + resPromiseY(v) { + rY(v); + }, }, - genPromiseY() { - void ([pY, rY] = makePR()); - return pY; - }, - resPromiseX(v) { - rX(v); - }, - resPromiseY(v) { - rY(v); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCrosswise/bootstrap.js b/packages/swingset-runner/demo/resolveCrosswise/bootstrap.js index 57c8628e2e5..16881d73b4a 100644 --- a/packages/swingset-runner/demo/resolveCrosswise/bootstrap.js +++ b/packages/swingset-runner/demo/resolveCrosswise/bootstrap.js @@ -2,12 +2,16 @@ import { E } from '@endo/eventual-send'; import { Far } from '@endo/marshal'; export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - const pa = E(vats.alice).genPromise(); - const pb = E(vats.bob).genPromise(); - E(vats.alice).usePromise([pb]); - E(vats.bob).usePromise([pa]); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const pa = E(vats.alice).genPromise(); + const pb = E(vats.bob).genPromise(); + E(vats.alice).usePromise([pb]); + E(vats.bob).usePromise([pa]); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveCrosswise/vat-body.js b/packages/swingset-runner/demo/resolveCrosswise/vat-body.js index 9603cf0ec36..864d85a1447 100644 --- a/packages/swingset-runner/demo/resolveCrosswise/vat-body.js +++ b/packages/swingset-runner/demo/resolveCrosswise/vat-body.js @@ -11,13 +11,17 @@ function makePR() { export function buildRootObject() { let p; let r; - return Far('root', { - genPromise() { - void ([p, r] = makePR()); - return p; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + genPromise() { + void ([p, r] = makePR()); + return p; + }, + usePromise(pa) { + r(pa); + }, }, - usePromise(pa) { - r(pa); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveDelayedPipeline/bootstrap.js b/packages/swingset-runner/demo/resolveDelayedPipeline/bootstrap.js index b60d1acf4d7..d6609b587a1 100644 --- a/packages/swingset-runner/demo/resolveDelayedPipeline/bootstrap.js +++ b/packages/swingset-runner/demo/resolveDelayedPipeline/bootstrap.js @@ -7,27 +7,31 @@ log(`=> loading bootstrap.js`); export function buildRootObject() { log(`=> setup called`); - return Far('root', { - bootstrap(vats) { - log('=> Alice: bootstrap() called'); - const thingP = E(vats.bob).getThing(); - log('=> Alice: called bob.getThing()'); - E(thingP) - .answer() - .then( - r => { - log(`=> Alice: thing.answer #1 resolved to '${r}'`); - E(thingP) - .answer() - .then( - r2 => log(`=> Alice: thing.answer #2 resolved to '${r2}'`), - e => log(`=> Alice: thing.answer #2 rejected as '${e}'`), - ); - }, - e => log(`=> Alice: thing.answer #1 rejected as '${e}'`), - ); - log('=> Alice: bootstrap() done'); - return 'Alice started'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> Alice: bootstrap() called'); + const thingP = E(vats.bob).getThing(); + log('=> Alice: called bob.getThing()'); + E(thingP) + .answer() + .then( + r => { + log(`=> Alice: thing.answer #1 resolved to '${r}'`); + E(thingP) + .answer() + .then( + r2 => log(`=> Alice: thing.answer #2 resolved to '${r2}'`), + e => log(`=> Alice: thing.answer #2 rejected as '${e}'`), + ); + }, + e => log(`=> Alice: thing.answer #1 rejected as '${e}'`), + ); + log('=> Alice: bootstrap() done'); + return 'Alice started'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveDelayedPipeline/vat-bob.js b/packages/swingset-runner/demo/resolveDelayedPipeline/vat-bob.js index a9e4fe17700..cdfdb676092 100644 --- a/packages/swingset-runner/demo/resolveDelayedPipeline/vat-bob.js +++ b/packages/swingset-runner/demo/resolveDelayedPipeline/vat-bob.js @@ -3,16 +3,24 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - const thing = Far('thing', { - answer() { - log('=> Bob: in thing.answer1(), reply with string'); - return `Bob's thing answer`; + const thing = makeExo( + 'thing', + M.interface('thing', {}, { defaultGuards: 'passable' }), + { + answer() { + log('=> Bob: in thing.answer1(), reply with string'); + return `Bob's thing answer`; + }, }, - }); - return Far('root', { - getThing() { - log('=> Bob: in getThing(), reply with thing'); - return thing; + ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + getThing() { + log('=> Bob: in getThing(), reply with thing'); + return thing; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveInArrayCase1/bootstrap.js b/packages/swingset-runner/demo/resolveInArrayCase1/bootstrap.js index f022271fcb9..c8accd6bd8b 100644 --- a/packages/swingset-runner/demo/resolveInArrayCase1/bootstrap.js +++ b/packages/swingset-runner/demo/resolveInArrayCase1/bootstrap.js @@ -7,26 +7,30 @@ log(`=> loading bootstrap.js`); export function buildRootObject() { log(`=> setup called`); - return Far('root', { - bootstrap(vats) { - log('=> Alice: bootstrap() called'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> Alice: bootstrap() called'); - let resolver; - const param = new Promise((theResolver, _theRejector) => { - resolver = theResolver; - }); - log('Alice: sending the promise to Bob'); - const response = E(vats.bob).thisIsYourPromise([param]); - log('Alice: resolving the promise that was sent to Bob'); - resolver('Alice says hi!'); - log(`Alice: awaiting Bob's response`); - // prettier-ignore - response.then( + let resolver; + const param = new Promise((theResolver, _theRejector) => { + resolver = theResolver; + }); + log('Alice: sending the promise to Bob'); + const response = E(vats.bob).thisIsYourPromise([param]); + log('Alice: resolving the promise that was sent to Bob'); + resolver('Alice says hi!'); + log(`Alice: awaiting Bob's response`); + // prettier-ignore + response.then( r => log(`=> Alice: Bob's response to thisIsYourPromise resolved to '${r}'`), e => log(`=> Alice: Bobs' response to thisIsYourPromise rejected as '${e}'`), ); - log('=> Alice: bootstrap() done'); - return 'Alice started'; + log('=> Alice: bootstrap() done'); + return 'Alice started'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveInArrayCase1/vat-bob.js b/packages/swingset-runner/demo/resolveInArrayCase1/vat-bob.js index 79a260bc85c..6d13a3bfb3b 100644 --- a/packages/swingset-runner/demo/resolveInArrayCase1/vat-bob.js +++ b/packages/swingset-runner/demo/resolveInArrayCase1/vat-bob.js @@ -3,16 +3,20 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - return Far('root', { - thisIsYourPromise(parr) { - const p = parr[0]; - log('=> Bob: thisIsYourPromise begins'); - p.then( - r => log(`=> Bob: the promise parameter resolved to '${r}'`), - e => log(`=> Bob: the promise parameter rejected as '${e}'`), - ); - log('=> Bob: thisIsYourPromise done'); - return 'Bob got the promise'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + thisIsYourPromise(parr) { + const p = parr[0]; + log('=> Bob: thisIsYourPromise begins'); + p.then( + r => log(`=> Bob: the promise parameter resolved to '${r}'`), + e => log(`=> Bob: the promise parameter rejected as '${e}'`), + ); + log('=> Bob: thisIsYourPromise done'); + return 'Bob got the promise'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveIndirect/bootstrap.js b/packages/swingset-runner/demo/resolveIndirect/bootstrap.js index 4a2ffadd639..2523209826d 100644 --- a/packages/swingset-runner/demo/resolveIndirect/bootstrap.js +++ b/packages/swingset-runner/demo/resolveIndirect/bootstrap.js @@ -4,11 +4,15 @@ import { Far } from '@endo/marshal'; console.log(`=> loading bootstrap.js`); export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - const pa = E(vats.bob).genPromise1(); - E(vats.bob).genPromise2(); - E(vats.bob).usePromise([pa]); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const pa = E(vats.bob).genPromise1(); + E(vats.bob).genPromise2(); + E(vats.bob).usePromise([pa]); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveIndirect/vat-bob.js b/packages/swingset-runner/demo/resolveIndirect/vat-bob.js index ee695c02992..13ec6c0294d 100644 --- a/packages/swingset-runner/demo/resolveIndirect/vat-bob.js +++ b/packages/swingset-runner/demo/resolveIndirect/vat-bob.js @@ -11,16 +11,20 @@ function makePR() { export function buildRootObject() { let p1; let r1; - return Far('root', { - genPromise1() { - return 'Hello!'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + genPromise1() { + return 'Hello!'; + }, + genPromise2() { + void ([p1, r1] = makePR()); + return p1; + }, + usePromise(pa) { + r1(pa); + }, }, - genPromise2() { - void ([p1, r1] = makePR()); - return p1; - }, - usePromise(pa) { - r1(pa); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveMutualCircular/bootstrap.js b/packages/swingset-runner/demo/resolveMutualCircular/bootstrap.js index 870a041e624..af3bb7f94bd 100644 --- a/packages/swingset-runner/demo/resolveMutualCircular/bootstrap.js +++ b/packages/swingset-runner/demo/resolveMutualCircular/bootstrap.js @@ -2,12 +2,16 @@ import { E } from '@endo/eventual-send'; import { Far } from '@endo/marshal'; export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - const pa = E(vats.bob).genPromise('a'); - const pb = E(vats.bob).genPromise('b'); - E(vats.bob).usePromise('a', [pb]); - E(vats.bob).usePromise('b', [pa]); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const pa = E(vats.bob).genPromise('a'); + const pb = E(vats.bob).genPromise('b'); + E(vats.bob).usePromise('a', [pb]); + E(vats.bob).usePromise('b', [pa]); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveMutualCircular/vat-bob.js b/packages/swingset-runner/demo/resolveMutualCircular/vat-bob.js index 9408fbc2b8a..228b36a270f 100644 --- a/packages/swingset-runner/demo/resolveMutualCircular/vat-bob.js +++ b/packages/swingset-runner/demo/resolveMutualCircular/vat-bob.js @@ -10,15 +10,19 @@ function makePR() { export function buildRootObject() { const rs = new Map(); - return Far('root', { - genPromise(idx) { - const [p, r] = makePR(); - rs.set(idx, r); - return p; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + genPromise(idx) { + const [p, r] = makePR(); + rs.set(idx, r); + return p; + }, + usePromise(idx, p) { + const r = rs.get(idx); + r(p); + }, }, - usePromise(idx, p) { - const r = rs.get(idx); - r(p); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolvePassResult/bootstrap.js b/packages/swingset-runner/demo/resolvePassResult/bootstrap.js index c66e56c031c..ffa877e408e 100644 --- a/packages/swingset-runner/demo/resolvePassResult/bootstrap.js +++ b/packages/swingset-runner/demo/resolvePassResult/bootstrap.js @@ -7,25 +7,29 @@ log(`=> loading bootstrap.js`); export function buildRootObject() { log(`=> setup called`); - return Far('root', { - bootstrap(vats) { - log('=> Alice: bootstrap() called'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> Alice: bootstrap() called'); - log('Alice: sending first to Bob'); - const p1 = E(vats.bob).first(); - log('Alice: sending second to Bob'); - const p2 = E(vats.bob).second(p1); - log(`Alice: awaiting Bob's responses`); - p1.then( - r => log(`=> Alice: Bob's response to first resolved to '${r}'`), - e => log(`=> Alice: Bobs' response to first rejected as '${e}'`), - ); - p2.then( - r => log(`=> Alice: Bob's response to second resolved to '${r}'`), - e => log(`=> Alice: Bobs' response to second rejected as '${e}'`), - ); - log('=> Alice: bootstrap() done'); - return 'Alice started'; + log('Alice: sending first to Bob'); + const p1 = E(vats.bob).first(); + log('Alice: sending second to Bob'); + const p2 = E(vats.bob).second(p1); + log(`Alice: awaiting Bob's responses`); + p1.then( + r => log(`=> Alice: Bob's response to first resolved to '${r}'`), + e => log(`=> Alice: Bobs' response to first rejected as '${e}'`), + ); + p2.then( + r => log(`=> Alice: Bob's response to second resolved to '${r}'`), + e => log(`=> Alice: Bobs' response to second rejected as '${e}'`), + ); + log('=> Alice: bootstrap() done'); + return 'Alice started'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolvePassResult/vat-bob.js b/packages/swingset-runner/demo/resolvePassResult/vat-bob.js index 870b4bc1fba..c9e28d4aa56 100644 --- a/packages/swingset-runner/demo/resolvePassResult/vat-bob.js +++ b/packages/swingset-runner/demo/resolvePassResult/vat-bob.js @@ -3,19 +3,23 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - return Far('root', { - first() { - log('=> Bob: in first'); - return `Bob's first answer`; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + first() { + log('=> Bob: in first'); + return `Bob's first answer`; + }, + second(p) { + log('=> Bob: second begins'); + p.then( + r => log(`=> Bob: the parameter to second resolved to '${r}'`), + e => log(`=> Bob: the parameter to second rejected as '${e}'`), + ); + log('=> Bob: second done'); + return `Bob's second answer`; + }, }, - second(p) { - log('=> Bob: second begins'); - p.then( - r => log(`=> Bob: the parameter to second resolved to '${r}'`), - e => log(`=> Bob: the parameter to second rejected as '${e}'`), - ); - log('=> Bob: second done'); - return `Bob's second answer`; - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolvePassResultPromise/bootstrap.js b/packages/swingset-runner/demo/resolvePassResultPromise/bootstrap.js index c5b7e2357dc..08606511d58 100644 --- a/packages/swingset-runner/demo/resolvePassResultPromise/bootstrap.js +++ b/packages/swingset-runner/demo/resolvePassResultPromise/bootstrap.js @@ -6,25 +6,29 @@ const log = console.log; log(`=> loading bootstrap.js`); export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - log('=> Alice: bootstrap() called'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> Alice: bootstrap() called'); - log('Alice: sending first to Bob'); - const p1 = E(vats.bob).first(); - log('Alice: sending second to Bob'); - const p2 = E(vats.bob).second(p1); - log(`Alice: awaiting Bob's responses`); - p1.then( - r => log(`=> Alice: Bob's response to first resolved to '${r}'`), - e => log(`=> Alice: Bobs' response to first rejected as '${e}'`), - ); - p2.then( - r => log(`=> Alice: Bob's response to second resolved to '${r}'`), - e => log(`=> Alice: Bobs' response to second rejected as '${e}'`), - ); - log('=> Alice: bootstrap() done'); - return 'Alice started'; + log('Alice: sending first to Bob'); + const p1 = E(vats.bob).first(); + log('Alice: sending second to Bob'); + const p2 = E(vats.bob).second(p1); + log(`Alice: awaiting Bob's responses`); + p1.then( + r => log(`=> Alice: Bob's response to first resolved to '${r}'`), + e => log(`=> Alice: Bobs' response to first rejected as '${e}'`), + ); + p2.then( + r => log(`=> Alice: Bob's response to second resolved to '${r}'`), + e => log(`=> Alice: Bobs' response to second rejected as '${e}'`), + ); + log('=> Alice: bootstrap() done'); + return 'Alice started'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolvePassResultPromise/vat-bob.js b/packages/swingset-runner/demo/resolvePassResultPromise/vat-bob.js index 74b14d7fab6..c485dd74f4f 100644 --- a/packages/swingset-runner/demo/resolvePassResultPromise/vat-bob.js +++ b/packages/swingset-runner/demo/resolvePassResultPromise/vat-bob.js @@ -4,23 +4,27 @@ const log = console.log; export function buildRootObject() { let resolver; - return Far('root', { - first() { - log('=> Bob: in first'); - const answer = new Promise((theResolver, _theRejector) => { - resolver = theResolver; - }); - return answer; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + first() { + log('=> Bob: in first'); + const answer = new Promise((theResolver, _theRejector) => { + resolver = theResolver; + }); + return answer; + }, + second(p) { + log('=> Bob: second begins'); + resolver('Bob answers first in second'); + p.then( + r => log(`=> Bob: the parameter to second resolved to '${r}'`), + e => log(`=> Bob: the parameter to second rejected as '${e}'`), + ); + log('=> Bob: second done'); + return `Bob's second answer`; + }, }, - second(p) { - log('=> Bob: second begins'); - resolver('Bob answers first in second'); - p.then( - r => log(`=> Bob: the parameter to second resolved to '${r}'`), - e => log(`=> Bob: the parameter to second rejected as '${e}'`), - ); - log('=> Bob: second done'); - return `Bob's second answer`; - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolvePipelined/bootstrap.js b/packages/swingset-runner/demo/resolvePipelined/bootstrap.js index c1b612266f0..ca520b45f2b 100644 --- a/packages/swingset-runner/demo/resolvePipelined/bootstrap.js +++ b/packages/swingset-runner/demo/resolvePipelined/bootstrap.js @@ -7,25 +7,29 @@ log(`=> loading bootstrap.js`); export function buildRootObject() { log(`=> setup called`); - return Far('root', { - bootstrap(vats) { - log('=> Alice: bootstrap() called'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> Alice: bootstrap() called'); - log('Alice: sending first() to Bob'); - const p1 = E(vats.bob).first(); - log('Alice: sending second to result of first()'); - const p2 = E(p1).second(p1); - log(`Alice: awaiting responses to second()`); - p1.then( - r => log(`=> Alice: Bob's response to first() resolved to '${r}'`), - e => log(`=> Alice: Bobs' response to first() rejected as '${e}'`), - ); - p2.then( - r => log(`=> Alice: response to second() resolved to '${r}'`), - e => log(`=> Alice: response to second() rejected as '${e}'`), - ); - log('=> Alice: bootstrap() done'); - return 'Alice started'; + log('Alice: sending first() to Bob'); + const p1 = E(vats.bob).first(); + log('Alice: sending second to result of first()'); + const p2 = E(p1).second(p1); + log(`Alice: awaiting responses to second()`); + p1.then( + r => log(`=> Alice: Bob's response to first() resolved to '${r}'`), + e => log(`=> Alice: Bobs' response to first() rejected as '${e}'`), + ); + p2.then( + r => log(`=> Alice: response to second() resolved to '${r}'`), + e => log(`=> Alice: response to second() rejected as '${e}'`), + ); + log('=> Alice: bootstrap() done'); + return 'Alice started'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolvePipelined/vat-bob.js b/packages/swingset-runner/demo/resolvePipelined/vat-bob.js index 63f1157c688..dc222ed8f36 100644 --- a/packages/swingset-runner/demo/resolvePipelined/vat-bob.js +++ b/packages/swingset-runner/demo/resolvePipelined/vat-bob.js @@ -3,16 +3,24 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - const thing = Far('thing', { - second() { - log('=> Bob: in thing.second(), reply with string'); - return `Bob's second answer`; + const thing = makeExo( + 'thing', + M.interface('thing', {}, { defaultGuards: 'passable' }), + { + second() { + log('=> Bob: in thing.second(), reply with string'); + return `Bob's second answer`; + }, }, - }); - return Far('root', { - first() { - log('=> Bob: in first(), reply with thing'); - return thing; + ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + first() { + log('=> Bob: in first(), reply with thing'); + return thing; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolvePromiseComplicated/bootstrap.js b/packages/swingset-runner/demo/resolvePromiseComplicated/bootstrap.js index 61cd84cef5b..4a45243f5da 100644 --- a/packages/swingset-runner/demo/resolvePromiseComplicated/bootstrap.js +++ b/packages/swingset-runner/demo/resolvePromiseComplicated/bootstrap.js @@ -7,25 +7,29 @@ log(`=> loading bootstrap.js`); export function buildRootObject() { log(`=> setup called`); - return Far('root', { - bootstrap(vats) { - log('=> Alice: bootstrap() called'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> Alice: bootstrap() called'); - log('Alice: sending first to Bob'); - const p1 = E(vats.bob).first(vats.carol); - log('Alice: sending second to Bob'); - const p2 = E(vats.bob).second(p1); - log(`Alice: awaiting Bob's responses`); - p1.then( - r => log(`=> Alice: Bob's response to first resolved to '${r}'`), - e => log(`=> Alice: Bobs' response to first rejected as '${e}'`), - ); - p2.then( - r => log(`=> Alice: Bob's response to second resolved to '${r}'`), - e => log(`=> Alice: Bobs' response to second rejected as '${e}'`), - ); - log('=> Alice: bootstrap() done'); - return 'Alice started'; + log('Alice: sending first to Bob'); + const p1 = E(vats.bob).first(vats.carol); + log('Alice: sending second to Bob'); + const p2 = E(vats.bob).second(p1); + log(`Alice: awaiting Bob's responses`); + p1.then( + r => log(`=> Alice: Bob's response to first resolved to '${r}'`), + e => log(`=> Alice: Bobs' response to first rejected as '${e}'`), + ); + p2.then( + r => log(`=> Alice: Bob's response to second resolved to '${r}'`), + e => log(`=> Alice: Bobs' response to second rejected as '${e}'`), + ); + log('=> Alice: bootstrap() done'); + return 'Alice started'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolvePromiseComplicated/vat-bob.js b/packages/swingset-runner/demo/resolvePromiseComplicated/vat-bob.js index 4584b2e427e..730caced962 100644 --- a/packages/swingset-runner/demo/resolvePromiseComplicated/vat-bob.js +++ b/packages/swingset-runner/demo/resolvePromiseComplicated/vat-bob.js @@ -6,27 +6,31 @@ const log = console.log; export function buildRootObject() { let resolver; let carol; - return Far('root', { - first(carolVat) { - log('=> Bob: in first'); - const answer = new Promise((theResolver, _theRejector) => { - resolver = theResolver; - }); - carol = carolVat; - return answer; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + first(carolVat) { + log('=> Bob: in first'); + const answer = new Promise((theResolver, _theRejector) => { + resolver = theResolver; + }); + carol = carolVat; + return answer; + }, + second(p) { + log('=> Bob: second begins'); + resolver('Bob answers first in second'); + log('=> Bob: send p to carol.foo'); + E(carol).foo(p); + p.then( + r => log(`=> Bob: the parameter to second resolved to '${r}'`), + e => log(`=> Bob: the parameter to second rejected as '${e}'`), + ); + void Promise.resolve().then(E(carol).bar(p)); + log('=> Bob: second done'); + return `Bob's second answer`; + }, }, - second(p) { - log('=> Bob: second begins'); - resolver('Bob answers first in second'); - log('=> Bob: send p to carol.foo'); - E(carol).foo(p); - p.then( - r => log(`=> Bob: the parameter to second resolved to '${r}'`), - e => log(`=> Bob: the parameter to second rejected as '${e}'`), - ); - void Promise.resolve().then(E(carol).bar(p)); - log('=> Bob: second done'); - return `Bob's second answer`; - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolvePromiseComplicated/vat-carol.js b/packages/swingset-runner/demo/resolvePromiseComplicated/vat-carol.js index cdbdf122094..c5132d347f2 100644 --- a/packages/swingset-runner/demo/resolvePromiseComplicated/vat-carol.js +++ b/packages/swingset-runner/demo/resolvePromiseComplicated/vat-carol.js @@ -3,24 +3,28 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - return Far('root', { - foo(p) { - log('=> Carol: in foo'); - p.then( - r => log(`=> Carol: in foo p resolved to '${r}'`), - e => log(`=> Carol: in foo p rejected as '${e}'`), - ); - log('=> Carol: foo done'); - return 'Carol says foo'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + foo(p) { + log('=> Carol: in foo'); + p.then( + r => log(`=> Carol: in foo p resolved to '${r}'`), + e => log(`=> Carol: in foo p rejected as '${e}'`), + ); + log('=> Carol: foo done'); + return 'Carol says foo'; + }, + bar(p) { + log('=> Carol: in bar'); + p.then( + r => log(`=> Carol: in bar p resolved to '${r}'`), + e => log(`=> Carol: in bar p rejected as '${e}'`), + ); + log('=> Carol: bar done'); + return 'Carol says bar'; + }, }, - bar(p) { - log('=> Carol: in bar'); - p.then( - r => log(`=> Carol: in bar p resolved to '${r}'`), - e => log(`=> Carol: in bar p rejected as '${e}'`), - ); - log('=> Carol: bar done'); - return 'Carol says bar'; - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveSimpleCircular/bootstrap.js b/packages/swingset-runner/demo/resolveSimpleCircular/bootstrap.js index 6b2f29bc580..44fa98bcec6 100644 --- a/packages/swingset-runner/demo/resolveSimpleCircular/bootstrap.js +++ b/packages/swingset-runner/demo/resolveSimpleCircular/bootstrap.js @@ -4,10 +4,14 @@ import { Far } from '@endo/marshal'; console.log(`=> loading bootstrap.js`); export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - const pa = E(vats.bob).genPromise(); - E(vats.bob).usePromise([pa]); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const pa = E(vats.bob).genPromise(); + E(vats.bob).usePromise([pa]); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveSimpleCircular/vat-bob.js b/packages/swingset-runner/demo/resolveSimpleCircular/vat-bob.js index 9603cf0ec36..864d85a1447 100644 --- a/packages/swingset-runner/demo/resolveSimpleCircular/vat-bob.js +++ b/packages/swingset-runner/demo/resolveSimpleCircular/vat-bob.js @@ -11,13 +11,17 @@ function makePR() { export function buildRootObject() { let p; let r; - return Far('root', { - genPromise() { - void ([p, r] = makePR()); - return p; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + genPromise() { + void ([p, r] = makePR()); + return p; + }, + usePromise(pa) { + r(pa); + }, }, - usePromise(pa) { - r(pa); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveSimpleCircular2/bootstrap.js b/packages/swingset-runner/demo/resolveSimpleCircular2/bootstrap.js index fd7fd05dc7f..0fd22b20f14 100644 --- a/packages/swingset-runner/demo/resolveSimpleCircular2/bootstrap.js +++ b/packages/swingset-runner/demo/resolveSimpleCircular2/bootstrap.js @@ -4,11 +4,15 @@ import { Far } from '@endo/marshal'; console.log(`=> loading bootstrap.js`); export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - const pa = E(vats.bob).genPromise(); - E(vats.bob).usePromise([pa]); - E(vats.bob).getThing(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const pa = E(vats.bob).genPromise(); + E(vats.bob).usePromise([pa]); + E(vats.bob).getThing(); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveSimpleCircular2/vat-bob.js b/packages/swingset-runner/demo/resolveSimpleCircular2/vat-bob.js index ebede349d72..293d2a889c6 100644 --- a/packages/swingset-runner/demo/resolveSimpleCircular2/vat-bob.js +++ b/packages/swingset-runner/demo/resolveSimpleCircular2/vat-bob.js @@ -11,16 +11,20 @@ function makePR() { export function buildRootObject() { let p; let r; - return Far('root', { - genPromise() { - void ([p, r] = makePR()); - return p; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + genPromise() { + void ([p, r] = makePR()); + return p; + }, + usePromise(pa) { + r(pa); + }, + getThing() { + return p; + }, }, - usePromise(pa) { - r(pa); - }, - getThing() { - return p; - }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveWithEmbeddedPromise/bootstrap.js b/packages/swingset-runner/demo/resolveWithEmbeddedPromise/bootstrap.js index 5b600570213..23509f473be 100644 --- a/packages/swingset-runner/demo/resolveWithEmbeddedPromise/bootstrap.js +++ b/packages/swingset-runner/demo/resolveWithEmbeddedPromise/bootstrap.js @@ -6,35 +6,39 @@ const log = console.log; log(`=> loading bootstrap.js`); export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - log('=> Alice: bootstrap() called'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> Alice: bootstrap() called'); - const p1 = E(vats.bob).first(); - const p2 = E(vats.bob).second(p1); - const p3 = E(vats.bob).third(); - p1.then( - r => { - log( - `=> Alice: Bob.first resolved to '${r}' (should be a promise in an array)`, - ); - r[0].then( - rr => log(`=> Alice: Bob.first result resolved to '${rr}'`), - ee => log(`=> Alice: Bob.first result rejected as '${ee}'`), - ); - }, - e => log(`=> Alice: Bob.first rejected as '${e}'`), - ); - p2.then( - r => log(`=> Alice: Bob.second resolved to '${r}'`), - e => log(`=> Alice: Bob.second rejected as '${e}'`), - ); - p3.then( - r => log(`=> Alice: Bob.third resolved to '${r}'`), - e => log(`=> Alice: Bob.third rejected as '${e}'`), - ); - log('=> Alice: bootstrap() done'); - return 'Alice started'; + const p1 = E(vats.bob).first(); + const p2 = E(vats.bob).second(p1); + const p3 = E(vats.bob).third(); + p1.then( + r => { + log( + `=> Alice: Bob.first resolved to '${r}' (should be a promise in an array)`, + ); + r[0].then( + rr => log(`=> Alice: Bob.first result resolved to '${rr}'`), + ee => log(`=> Alice: Bob.first result rejected as '${ee}'`), + ); + }, + e => log(`=> Alice: Bob.first rejected as '${e}'`), + ); + p2.then( + r => log(`=> Alice: Bob.second resolved to '${r}'`), + e => log(`=> Alice: Bob.second rejected as '${e}'`), + ); + p3.then( + r => log(`=> Alice: Bob.third resolved to '${r}'`), + e => log(`=> Alice: Bob.third rejected as '${e}'`), + ); + log('=> Alice: bootstrap() done'); + return 'Alice started'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/resolveWithEmbeddedPromise/vat-bob.js b/packages/swingset-runner/demo/resolveWithEmbeddedPromise/vat-bob.js index 634958d85b2..56ea296cd79 100644 --- a/packages/swingset-runner/demo/resolveWithEmbeddedPromise/vat-bob.js +++ b/packages/swingset-runner/demo/resolveWithEmbeddedPromise/vat-bob.js @@ -13,29 +13,33 @@ function makePR() { export function buildRootObject() { let r1; let r2; - return Far('root', { - first() { - log('=> Bob: first begins'); - let p1; - void ([p1, r1] = makePR()); - return p1; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + first() { + log('=> Bob: first begins'); + let p1; + void ([p1, r1] = makePR()); + return p1; + }, + second(p) { + log('=> Bob: second begins'); + let p2; + void ([p2, r2] = makePR()); + r1([p2]); + p.then( + r => log(`=> Bob: second(p) resolved to '${r}'`), + e => log(`=> Bob: second(p) rejected as '${e}'`), + ); + log('=> Bob: second done'); + return p2; + }, + third(_p) { + log('=> Bob: third begins'); + r2(`Bob's resolution to p2`); + return `Bob's answer to third`; + }, }, - second(p) { - log('=> Bob: second begins'); - let p2; - void ([p2, r2] = makePR()); - r1([p2]); - p.then( - r => log(`=> Bob: second(p) resolved to '${r}'`), - e => log(`=> Bob: second(p) rejected as '${e}'`), - ); - log('=> Bob: second done'); - return p2; - }, - third(_p) { - log('=> Bob: third begins'); - r2(`Bob's resolution to p2`); - return `Bob's answer to third`; - }, - }); + ); } diff --git a/packages/swingset-runner/demo/simplePromisePass/bootstrap.js b/packages/swingset-runner/demo/simplePromisePass/bootstrap.js index 0590b7ce3c6..65f02d58760 100644 --- a/packages/swingset-runner/demo/simplePromisePass/bootstrap.js +++ b/packages/swingset-runner/demo/simplePromisePass/bootstrap.js @@ -6,17 +6,21 @@ const log = console.log; log(`=> loading bootstrap.js`); export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - log('=> Bootstrap: bootstrap() called'); - // prettier-ignore - E(vats.alice) + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + log('=> Bootstrap: bootstrap() called'); + // prettier-ignore + E(vats.alice) .sendPromiseTo(vats.bob) .then( r => log(`=> Bootstrap: alice.sendPromiseTo(bob) resolved to '${r}'`), e => log(`=> Bootstrap: alice.sendPromiseTo(bob) rejected as '${e}'`), ); - log('=> Bootstrap: bootstrap() done'); + log('=> Bootstrap: bootstrap() done'); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/simplePromisePass/vat-alice.js b/packages/swingset-runner/demo/simplePromisePass/vat-alice.js index 78937f2e10e..e69d1db3aad 100644 --- a/packages/swingset-runner/demo/simplePromisePass/vat-alice.js +++ b/packages/swingset-runner/demo/simplePromisePass/vat-alice.js @@ -4,21 +4,27 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - return Far('root', { - sendPromiseTo(other) { - log('=> Alice: sendPromiseTo() begins'); - let resolver; - const param = new Promise((theResolver, _theRejector) => { - resolver = theResolver; - }); - const response = E(other).thisIsYourPromise(param); - resolver('Alice says hi!'); - response.then( - r => log(`=> Alice: response to thisIsYourPromise resolved to '${r}'`), - e => log(`=> Alice: response to thisIsYourPromise rejected as '${e}'`), - ); - log('=> Alice: sendPromiseTo() done'); - return 'Alice started'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + sendPromiseTo(other) { + log('=> Alice: sendPromiseTo() begins'); + let resolver; + const param = new Promise((theResolver, _theRejector) => { + resolver = theResolver; + }); + const response = E(other).thisIsYourPromise(param); + resolver('Alice says hi!'); + response.then( + r => + log(`=> Alice: response to thisIsYourPromise resolved to '${r}'`), + e => + log(`=> Alice: response to thisIsYourPromise rejected as '${e}'`), + ); + log('=> Alice: sendPromiseTo() done'); + return 'Alice started'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/simplePromisePass/vat-bob.js b/packages/swingset-runner/demo/simplePromisePass/vat-bob.js index 5281a542417..22d3cf311bd 100644 --- a/packages/swingset-runner/demo/simplePromisePass/vat-bob.js +++ b/packages/swingset-runner/demo/simplePromisePass/vat-bob.js @@ -3,15 +3,19 @@ import { Far } from '@endo/marshal'; const log = console.log; export function buildRootObject() { - return Far('root', { - thisIsYourPromise(p) { - log('=> Bob: thisIsYourPromise begins'); - p.then( - r => log(`=> Bob: the promise parameter resolved to '${r}'`), - e => log(`=> Bob: the promise parameter rejected as '${e}'`), - ); - log('=> Bob: thisIsYourPromise done'); - return 'Bob got the promise'; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + thisIsYourPromise(p) { + log('=> Bob: thisIsYourPromise begins'); + p.then( + r => log(`=> Bob: the promise parameter resolved to '${r}'`), + e => log(`=> Bob: the promise parameter rejected as '${e}'`), + ); + log('=> Bob: thisIsYourPromise done'); + return 'Bob got the promise'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/swapBenchmark/bootstrap.js b/packages/swingset-runner/demo/swapBenchmark/bootstrap.js index 921b0909459..c2f37baa404 100644 --- a/packages/swingset-runner/demo/swapBenchmark/bootstrap.js +++ b/packages/swingset-runner/demo/swapBenchmark/bootstrap.js @@ -62,39 +62,43 @@ export function buildRootObject(_vatPowers, vatParameters) { let alice; let bob; let round = 0; - return Far('root', { - async bootstrap(vats, devices) { - const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, - ); - /** @type {{zoeService: ERef}} */ - const { zoeService: zoe } = await E(vats.zoe).buildZoe( - vatAdminSvc, - undefined, - 'zcf', - ); - const installations = { - atomicSwap: await E(zoe).install(atomicSwapBundle.bundle), - }; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + /** @type {{zoeService: ERef}} */ + const { zoeService: zoe } = await E(vats.zoe).buildZoe( + vatAdminSvc, + undefined, + 'zcf', + ); + const installations = { + atomicSwap: await E(zoe).install(atomicSwapBundle.bundle), + }; - const startingValues = [ - [3n, 0n], // Alice: 3 moola, no simoleans - [0n, 3n], // Bob: no moola, 3 simoleans - ]; + const startingValues = [ + [3n, 0n], // Alice: 3 moola, no simoleans + [0n, 3n], // Bob: no moola, 3 simoleans + ]; - ({ alice, bob } = makeVats(vats, zoe, installations, startingValues)); - // Zoe appears to do some one-time setup the first time it's used, so this - // is a sacrificial benchmark round to prime the pump. - if (vatParameters.argv[0] === '--prime') { + ({ alice, bob } = makeVats(vats, zoe, installations, startingValues)); + // Zoe appears to do some one-time setup the first time it's used, so this + // is a sacrificial benchmark round to prime the pump. + if (vatParameters.argv[0] === '--prime') { + await E(alice).initiateSwap(bob); + await E(bob).initiateSwap(alice); + } + }, + async runBenchmarkRound() { + round += 1; await E(alice).initiateSwap(bob); await E(bob).initiateSwap(alice); - } + return `round ${round} complete`; + }, }, - async runBenchmarkRound() { - round += 1; - await E(alice).initiateSwap(bob); - await E(bob).initiateSwap(alice); - return `round ${round} complete`; - }, - }); + ); } diff --git a/packages/swingset-runner/demo/swapBenchmark/exchanger.js b/packages/swingset-runner/demo/swapBenchmark/exchanger.js index 69bc385e87f..46bd08afa66 100755 --- a/packages/swingset-runner/demo/swapBenchmark/exchanger.js +++ b/packages/swingset-runner/demo/swapBenchmark/exchanger.js @@ -106,15 +106,23 @@ async function build(name, zoe, issuers, payments, installations) { await postReport(); } - return Far('exchanger', { - initiateSwap, - respondToSwap, - }); + return makeExo( + 'exchanger', + M.interface('exchanger', {}, { defaultGuards: 'passable' }), + { + initiateSwap, + respondToSwap, + }, + ); } export function buildRootObject(_vatPowers, vatParameters) { - return Far('root', { - build: (zoe, issuers, payments, installations) => - build(vatParameters.name, zoe, issuers, payments, installations), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (zoe, issuers, payments, installations) => + build(vatParameters.name, zoe, issuers, payments, installations), + }, + ); } diff --git a/packages/swingset-runner/demo/terminateVat/bootstrap.js b/packages/swingset-runner/demo/terminateVat/bootstrap.js index 6f16d502dac..74c0fae1e99 100644 --- a/packages/swingset-runner/demo/terminateVat/bootstrap.js +++ b/packages/swingset-runner/demo/terminateVat/bootstrap.js @@ -4,66 +4,72 @@ import { Far } from '@endo/marshal'; export function buildRootObject(_vatPowers, vatParameters) { const mode = vatParameters.argv[0] || 'kill'; let counter = 46; - const self = Far('root', { - async bootstrap(vats, devices) { - const vatMaker = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - const dude = await E(vatMaker).createVatByName('dude'); - const succBefore = await E(dude.root).dude(true); - console.log(`success result ${succBefore}`); - try { - const failBefore = await E(dude.root).dude(false); - console.log(`failure path should not yield ${failBefore} [bad]`); - } catch (e) { - console.log(`failure result ${e} [good]`); - } - await E(dude.root).elsewhere(self); // this will notify - console.log(`expected notify sent`); - const p = E(dude.root).elsewhere(self); // this will not - p.catch(() => {}); // just shut up already + const self = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatMaker = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + const dude = await E(vatMaker).createVatByName('dude'); + const succBefore = await E(dude.root).dude(true); + console.log(`success result ${succBefore}`); + try { + const failBefore = await E(dude.root).dude(false); + console.log(`failure path should not yield ${failBefore} [bad]`); + } catch (e) { + console.log(`failure result ${e} [good]`); + } + await E(dude.root).elsewhere(self); // this will notify + console.log(`expected notify sent`); + const p = E(dude.root).elsewhere(self); // this will not + p.catch(() => {}); // just shut up already - switch (mode) { - case 'kill': - await E(dude.adminNode).terminateWithFailure('with prejudice'); - break; - case 'happy': - await E(dude.root).dieHappy('I got everything I ever wanted'); - break; - case 'exceptionallyHappy': - await E(dude.root).dieHappy(Error('catch me if you can')); - break; - case 'sad': - await E(dude.root).dieSad('Goodbye cruel world'); - break; - case 'exceptionallySad': - await E(dude.root).dieSad(Error("I can't take it any more")); - break; - default: - console.log('this should never happen'); - break; - } - p.then( - () => console.log(`non-notify call notified [bad]`), - e => console.log(`non-notify call rejected: ${e} [good]`), - ); - console.log(`terminated`); - try { - const succAfter = await E(dude.root).dude(true); - console.log(`result after terminate: ${succAfter} [bad]`); - } catch (e) { - console.log(`send after terminate failed: ${e} [good]`); - } - try { - const success = await E(dude.adminNode).done(); - // prettier-ignore - console.log(`done() succeeded with ${success} (${JSON.stringify(success)})`); - } catch (e) { - console.log(`done() rejected with ${e} (${JSON.stringify(e)})`); - } + switch (mode) { + case 'kill': + await E(dude.adminNode).terminateWithFailure('with prejudice'); + break; + case 'happy': + await E(dude.root).dieHappy('I got everything I ever wanted'); + break; + case 'exceptionallyHappy': + await E(dude.root).dieHappy(Error('catch me if you can')); + break; + case 'sad': + await E(dude.root).dieSad('Goodbye cruel world'); + break; + case 'exceptionallySad': + await E(dude.root).dieSad(Error("I can't take it any more")); + break; + default: + console.log('this should never happen'); + break; + } + p.then( + () => console.log(`non-notify call notified [bad]`), + e => console.log(`non-notify call rejected: ${e} [good]`), + ); + console.log(`terminated`); + try { + const succAfter = await E(dude.root).dude(true); + console.log(`result after terminate: ${succAfter} [bad]`); + } catch (e) { + console.log(`send after terminate failed: ${e} [good]`); + } + try { + const success = await E(dude.adminNode).done(); + // prettier-ignore + console.log(`done() succeeded with ${success} (${JSON.stringify(success)})`); + } catch (e) { + console.log(`done() rejected with ${e} (${JSON.stringify(e)})`); + } + }, + query() { + counter += 1; + return counter; + }, }, - query() { - counter += 1; - return counter; - }, - }); + ); return self; } diff --git a/packages/swingset-runner/demo/terminateVat/vat-dude.js b/packages/swingset-runner/demo/terminateVat/vat-dude.js index c72d0be6278..4d79a5908b5 100644 --- a/packages/swingset-runner/demo/terminateVat/vat-dude.js +++ b/packages/swingset-runner/demo/terminateVat/vat-dude.js @@ -3,24 +3,28 @@ import { Far } from '@endo/marshal'; export function buildRootObject(vatPowers) { let count = 0; - return Far('root', { - async elsewhere(other) { - const val = await E(other).query(); - console.log(`other returns ${val}`); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async elsewhere(other) { + const val = await E(other).query(); + console.log(`other returns ${val}`); + }, + dude(truth) { + if (truth) { + count += 1; + return `DUDE${'!'.repeat(count - 1)}`; + } else { + throw Error('Sorry, dude'); + } + }, + dieHappy(completion) { + vatPowers.exitVat(completion); + }, + dieSad(reason) { + vatPowers.exitVatWithFailure(reason); + }, }, - dude(truth) { - if (truth) { - count += 1; - return `DUDE${'!'.repeat(count - 1)}`; - } else { - throw Error('Sorry, dude'); - } - }, - dieHappy(completion) { - vatPowers.exitVat(completion); - }, - dieSad(reason) { - vatPowers.exitVatWithFailure(reason); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/vatFailure/bootstrap.js b/packages/swingset-runner/demo/vatFailure/bootstrap.js index 537040740b4..d8189cae728 100644 --- a/packages/swingset-runner/demo/vatFailure/bootstrap.js +++ b/packages/swingset-runner/demo/vatFailure/bootstrap.js @@ -2,51 +2,59 @@ import { E } from '@endo/eventual-send'; import { Far } from '@endo/marshal'; export function buildRootObject(_vatPowers, vatParameters) { - const ourThing = Far('thing-like', { - pretendToBeAThing(from) { - console.log(`pretendToBeAThing invoked from ${from}`); + const ourThing = makeExo( + 'thing-like', + M.interface('thing-like', {}, { defaultGuards: 'passable' }), + { + pretendToBeAThing(from) { + console.log(`pretendToBeAThing invoked from ${from}`); + }, }, - }); - const self = Far('root', { - async bootstrap(vats, devices) { - let badvat; - let done; - if (vatParameters.argv[0] === '--bedynamic') { - const vatMaker = E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, + ); + const self = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + let badvat; + let done; + if (vatParameters.argv[0] === '--bedynamic') { + const vatMaker = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + const vat = await E(vatMaker).createVatByName('badvat', { + enableSetup: true, + }); + badvat = vat.root; + done = E(vat.adminNode).done(); + } else { + badvat = vats.badvatStatic; + } + if (done) { + done.then( + v => console.log(`done resolved (bad) to ${v}`), + e => console.log(`done rejected (good) with ${e}`), + ); + } else { + console.log('running statically, no done() facet'); + } + const p1 = E(badvat).begood(ourThing); + p1.then( + () => console.log('p1 resolve (bad!)'), + e => console.log(`p1 reject ${e}`), ); - const vat = await E(vatMaker).createVatByName('badvat', { - enableSetup: true, - }); - badvat = vat.root; - done = E(vat.adminNode).done(); - } else { - badvat = vats.badvatStatic; - } - if (done) { - done.then( - v => console.log(`done resolved (bad) to ${v}`), - e => console.log(`done rejected (good) with ${e}`), + const p2 = E(badvat).bebad(ourThing); + p2.then( + () => console.log('p2 resolve (bad!)'), + e => console.log(`p2 reject ${e}`), ); - } else { - console.log('running statically, no done() facet'); - } - const p1 = E(badvat).begood(ourThing); - p1.then( - () => console.log('p1 resolve (bad!)'), - e => console.log(`p1 reject ${e}`), - ); - const p2 = E(badvat).bebad(ourThing); - p2.then( - () => console.log('p2 resolve (bad!)'), - e => console.log(`p2 reject ${e}`), - ); - const p3 = E(badvat).begood(ourThing); - p3.then( - () => console.log('p3 resolve (bad!)'), - e => console.log(`p3 reject ${e}`), - ); + const p3 = E(badvat).begood(ourThing); + p3.then( + () => console.log('p3 resolve (bad!)'), + e => console.log(`p3 reject ${e}`), + ); + }, }, - }); + ); return self; } diff --git a/packages/swingset-runner/demo/vatResolveTest/bootstrap.js b/packages/swingset-runner/demo/vatResolveTest/bootstrap.js index 0402bc853a7..c9e109b9edc 100644 --- a/packages/swingset-runner/demo/vatResolveTest/bootstrap.js +++ b/packages/swingset-runner/demo/vatResolveTest/bootstrap.js @@ -6,40 +6,52 @@ const log = console.log; log(`=> loading bootstrap.js`); export function buildRootObject() { - const target1 = Far('target1', { - one(_p) { - log(`target1 in one`); - }, - two() { - log(`target1 in two`); - }, - three(_p) { - log(`target1 in three`); - }, - four() { - log(`target1 in four`); - }, - }); - const target2 = Far('target2', { - one(_p) { - log(`target2 in one`); - }, - two() { - log(`target2 in two`); - }, - three(_p) { - log(`target2 in three`); - }, - four() { - log(`target2 in four`); - }, - }); - return Far('root', { - bootstrap(vats) { - const bob = vats.bob; - const p1 = E(bob).result(); - E(bob).promise(p1); - E(bob).run(target1, target2); - }, - }); + const target1 = makeExo( + 'target1', + M.interface('target1', {}, { defaultGuards: 'passable' }), + { + one(_p) { + log(`target1 in one`); + }, + two() { + log(`target1 in two`); + }, + three(_p) { + log(`target1 in three`); + }, + four() { + log(`target1 in four`); + }, + }, + ); + const target2 = makeExo( + 'target2', + M.interface('target2', {}, { defaultGuards: 'passable' }), + { + one(_p) { + log(`target2 in one`); + }, + two() { + log(`target2 in two`); + }, + three(_p) { + log(`target2 in three`); + }, + four() { + log(`target2 in four`); + }, + }, + ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const bob = vats.bob; + const p1 = E(bob).result(); + E(bob).promise(p1); + E(bob).run(target1, target2); + }, + }, + ); } diff --git a/packages/swingset-runner/demo/vatResolveTest/vat-bob.js b/packages/swingset-runner/demo/vatResolveTest/vat-bob.js index 5e9b0374acb..0a90ab3d3a3 100644 --- a/packages/swingset-runner/demo/vatResolveTest/vat-bob.js +++ b/packages/swingset-runner/demo/vatResolveTest/vat-bob.js @@ -21,36 +21,40 @@ function hush(p) { export function buildRootObject() { let p1; const [p0, r0] = makePR(); - return Far('root', { - promise(p) { - p1 = p; - p1.then( - x => { - log(`p1 resolved to ${x}`); - }, - _ => { - log(`p1 rejected`); - }, - ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + promise(p) { + p1 = p; + p1.then( + x => { + log(`p1 resolved to ${x}`); + }, + _ => { + log(`p1 rejected`); + }, + ); + }, + result() { + return p0; + }, + async run(target1, target2) { + log(`calling one()`); + const p2 = E(target1).one(p1); + hush(p2); + log(`calling two()`); + const p3 = E(p1).two(); + hush(p3); + r0(target2); + log(`calling three()`); + const p4 = E(target1).three(p1); + hush(p4); + log(`calling four()`); + const p5 = E(p1).four(); + hush(p5); + log(`did all calls`); + }, }, - result() { - return p0; - }, - async run(target1, target2) { - log(`calling one()`); - const p2 = E(target1).one(p1); - hush(p2); - log(`calling two()`); - const p3 = E(p1).two(); - hush(p3); - r0(target2); - log(`calling three()`); - const p4 = E(target1).three(p1); - hush(p4); - log(`calling four()`); - const p5 = E(p1).four(); - hush(p5); - log(`did all calls`); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/vatResolveTestSimple/bootstrap.js b/packages/swingset-runner/demo/vatResolveTestSimple/bootstrap.js index 36517faf5fa..563009f4fa1 100644 --- a/packages/swingset-runner/demo/vatResolveTestSimple/bootstrap.js +++ b/packages/swingset-runner/demo/vatResolveTestSimple/bootstrap.js @@ -6,20 +6,28 @@ const log = console.log; log(`=> loading bootstrap.js`); export function buildRootObject() { - const target = Far('target', { - one() { - log(`target in one`); + const target = makeExo( + 'target', + M.interface('target', {}, { defaultGuards: 'passable' }), + { + one() { + log(`target in one`); + }, + two() { + log(`target in two`); + }, }, - two() { - log(`target in two`); + ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + const bob = vats.bob; + const p1 = E(bob).result(); + E(bob).promise(p1); + E(bob).run(target); + }, }, - }); - return Far('root', { - bootstrap(vats) { - const bob = vats.bob; - const p1 = E(bob).result(); - E(bob).promise(p1); - E(bob).run(target); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/vatResolveTestSimple/vat-bob.js b/packages/swingset-runner/demo/vatResolveTestSimple/vat-bob.js index 726a2af1bb9..a738392ea70 100644 --- a/packages/swingset-runner/demo/vatResolveTestSimple/vat-bob.js +++ b/packages/swingset-runner/demo/vatResolveTestSimple/vat-bob.js @@ -21,27 +21,31 @@ function hush(p) { export function buildRootObject() { let p1; const [p0, r0] = makePR(); - return Far('root', { - promise(p) { - p1 = p; - p1.then( - x => { - log(`p1 resolved to ${x}`); - }, - _ => { - log(`p1 rejected`); - }, - ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + promise(p) { + p1 = p; + p1.then( + x => { + log(`p1 resolved to ${x}`); + }, + _ => { + log(`p1 rejected`); + }, + ); + }, + result() { + return p0; + }, + async run(target) { + const p2 = E(p1).one(); + hush(p2); + r0(target); + const p3 = E(p1).two(); + hush(p3); + }, }, - result() { - return p0; - }, - async run(target) { - const p2 = E(p1).one(); - hush(p2); - r0(target); - const p3 = E(p1).two(); - hush(p3); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/vatStore1/bootstrap.js b/packages/swingset-runner/demo/vatStore1/bootstrap.js index 6f9e281f909..afe3807eb4c 100644 --- a/packages/swingset-runner/demo/vatStore1/bootstrap.js +++ b/packages/swingset-runner/demo/vatStore1/bootstrap.js @@ -2,11 +2,15 @@ import { E } from '@endo/eventual-send'; import { Far } from '@endo/marshal'; export function buildRootObject() { - return Far('root', { - bootstrap(vats) { - for (let i = 0; i < 5; i += 1) { - E(vats.bob).doYourStuff(i); - } + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap(vats) { + for (let i = 0; i < 5; i += 1) { + E(vats.bob).doYourStuff(i); + } + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/vatStore1/vat-bob.js b/packages/swingset-runner/demo/vatStore1/vat-bob.js index dc186eab68a..63bce334d0e 100644 --- a/packages/swingset-runner/demo/vatStore1/vat-bob.js +++ b/packages/swingset-runner/demo/vatStore1/vat-bob.js @@ -69,55 +69,59 @@ export function buildRootObject() { let zot3; let zot4; - return Far('root', { - doYourStuff(phase) { - p('=> Bob: doYourStuff!'); - switch (phase) { - case 0: - p('phase 0: start'); - break; - case 1: - p('phase 1: object creations'); - thing1 = makeThing('thing-1'); - thing2 = makeThing('thing-2', 100); - thing3 = makeThing('thing-3', 200); - thing4 = makeThing('thing-4', 300); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + doYourStuff(phase) { + p('=> Bob: doYourStuff!'); + switch (phase) { + case 0: + p('phase 0: start'); + break; + case 1: + p('phase 1: object creations'); + thing1 = makeThing('thing-1'); + thing2 = makeThing('thing-2', 100); + thing3 = makeThing('thing-3', 200); + thing4 = makeThing('thing-4', 300); - zot1 = makeZot(23, 'Alice', 'is this on?'); - zot2 = makeZot(29, 'Bob', 'what are you saying?'); - zot3 = makeZot(47, 'Carol', 'as if...'); - zot4 = makeZot(66, 'Dave', 'you and what army?'); - break; - case 2: - p('phase 2: first batch-o-stuff'); - thing1.inc(); - zot1.sayHello('hello'); - thing1.inc(); - zot2.sayHello('hi'); - thing1.inc(); - zot3.sayHello('aloha'); - zot4.sayHello('bonjour'); - zot1.sayHello('hello again'); - p(`${thing2.describe()}`); - break; - case 3: - p('phase 3: second batch-o-stuff'); - p(`thing1 counter = ${thing1.get()}`); - thing1.inc(); - thing4.reset(1000); - zot3.rename('Chester'); - zot1.printInfo(); - zot2.printInfo(); - p(`${thing2.describe()}`); - zot3.printInfo(); - zot4.printInfo(); - thing3.inc(); - p(`${thing4.describe()}`); - break; - default: - // because otherwise eslint complains - break; - } + zot1 = makeZot(23, 'Alice', 'is this on?'); + zot2 = makeZot(29, 'Bob', 'what are you saying?'); + zot3 = makeZot(47, 'Carol', 'as if...'); + zot4 = makeZot(66, 'Dave', 'you and what army?'); + break; + case 2: + p('phase 2: first batch-o-stuff'); + thing1.inc(); + zot1.sayHello('hello'); + thing1.inc(); + zot2.sayHello('hi'); + thing1.inc(); + zot3.sayHello('aloha'); + zot4.sayHello('bonjour'); + zot1.sayHello('hello again'); + p(`${thing2.describe()}`); + break; + case 3: + p('phase 3: second batch-o-stuff'); + p(`thing1 counter = ${thing1.get()}`); + thing1.inc(); + thing4.reset(1000); + zot3.rename('Chester'); + zot1.printInfo(); + zot2.printInfo(); + p(`${thing2.describe()}`); + zot3.printInfo(); + zot4.printInfo(); + thing3.inc(); + p(`${thing4.describe()}`); + break; + default: + // because otherwise eslint complains + break; + } + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/vatStore2/bootstrap.js b/packages/swingset-runner/demo/vatStore2/bootstrap.js index 83f3f5d2bba..e4bb03401d1 100644 --- a/packages/swingset-runner/demo/vatStore2/bootstrap.js +++ b/packages/swingset-runner/demo/vatStore2/bootstrap.js @@ -20,59 +20,67 @@ export function buildRootObject() { function makeZot() { const name = `zot-${nextZotNumber}`; nextZotNumber += 1; - return Far('zot', { - say(message) { - p(`${name} asked to say "${message}"`); + return makeExo( + 'zot', + M.interface('zot', {}, { defaultGuards: 'passable' }), + { + say(message) { + p(`${name} asked to say "${message}"`); + }, + getName() { + return name; + }, }, - getName() { - return name; - }, - }); + ); } - return Far('root', { - async bootstrap(vats) { - otherVats.push({ vat: vats.alice, name: 'Alice' }); - otherVats.push({ vat: vats.bob, name: 'Bob' }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + otherVats.push({ vat: vats.alice, name: 'Alice' }); + otherVats.push({ vat: vats.bob, name: 'Bob' }); - for (let i = 0; i < 5; i += 1) { - for (const { vat } of otherVats) { - const zot = makeZot(); - const companion = await E(vat).introduce(zot); - companions.push(companion); - zots.push(zot); + for (let i = 0; i < 5; i += 1) { + for (const { vat } of otherVats) { + const zot = makeZot(); + const companion = await E(vat).introduce(zot); + companions.push(companion); + zots.push(zot); + } } - } - for (let i = 0; i < 1000; i += 1) { - const action = roll(4); - const companion = companions[roll(companions.length)]; - switch (action) { - case 0: { - E(companion).echo(`profundity #${roll(10)}`); - break; - } - case 1: { - const zot = zots[roll(zots.length)]; - E(companion).changePartner(zot); - break; + for (let i = 0; i < 1000; i += 1) { + const action = roll(4); + const companion = companions[roll(companions.length)]; + switch (action) { + case 0: { + E(companion).echo(`profundity #${roll(10)}`); + break; + } + case 1: { + const zot = zots[roll(zots.length)]; + E(companion).changePartner(zot); + break; + } + case 2: { + E(companion).report(); + break; + } + case 3: { + const { vat, name } = otherVats[roll(otherVats.length)]; + const hasIt = await E(vat).doYouHave(companion); + // prettier-ignore + p(`vat ${name} ${hasIt ? 'has' : 'does not have'} ${await E(companion).getLabel()}`); + break; + } + default: + Fail`this can't happen`; } - case 2: { - E(companion).report(); - break; - } - case 3: { - const { vat, name } = otherVats[roll(otherVats.length)]; - const hasIt = await E(vat).doYouHave(companion); - // prettier-ignore - p(`vat ${name} ${hasIt ? 'has' : 'does not have'} ${await E(companion).getLabel()}`); - break; - } - default: - Fail`this can't happen`; } - } - return 'done'; + return 'done'; + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/vatStore2/thingHolder.js b/packages/swingset-runner/demo/vatStore2/thingHolder.js index b926c0da65b..5fd94f56b0b 100644 --- a/packages/swingset-runner/demo/vatStore2/thingHolder.js +++ b/packages/swingset-runner/demo/vatStore2/thingHolder.js @@ -44,28 +44,32 @@ function build(name) { } } - return Far('root', { - async introduce(other) { - const otherName = await E(other).getName(); - const thing = makeThing(`thing-${nextThingNumber}`, other, otherName); - nextThingNumber += 1; - ensureCollection(); - myThings.init(thing, 0); - return thing; - }, - doYouHave(thing) { - ensureCollection(); - if (myThings.has(thing)) { - const queryCount = myThings.get(thing) + 1; - myThings.set(thing, queryCount); - p(`${name}: ${queryCount} queries about ${thing.getLabel()}`); - return true; - } else { - p(`${name}: query about unknown thing`); - return false; - } + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async introduce(other) { + const otherName = await E(other).getName(); + const thing = makeThing(`thing-${nextThingNumber}`, other, otherName); + nextThingNumber += 1; + ensureCollection(); + myThings.init(thing, 0); + return thing; + }, + doYouHave(thing) { + ensureCollection(); + if (myThings.has(thing)) { + const queryCount = myThings.get(thing) + 1; + myThings.set(thing, queryCount); + p(`${name}: ${queryCount} queries about ${thing.getLabel()}`); + return true; + } else { + p(`${name}: query about unknown thing`); + return false; + } + }, }, - }); + ); } export function buildRootObject(_vatPowers, vatParameters) { diff --git a/packages/swingset-runner/demo/vatStore3/bootstrap.js b/packages/swingset-runner/demo/vatStore3/bootstrap.js index d89da0ec05d..affac13b799 100644 --- a/packages/swingset-runner/demo/vatStore3/bootstrap.js +++ b/packages/swingset-runner/demo/vatStore3/bootstrap.js @@ -8,24 +8,28 @@ export function buildRootObject() { let bob; let me; let goCount = 3; - return Far('root', { - async bootstrap(vats) { - me = vats.bootstrap; - bob = vats.bob; - E(bob).prepare(); - await E(me).go(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + me = vats.bootstrap; + bob = vats.bob; + E(bob).prepare(); + await E(me).go(); + }, + go() { + if (goCount > 0) { + E(bob).getThing(me); + } else { + E(bob).finish(); + } + goCount -= 1; + }, + deliverThing(thing) { + other = thing; + E(me).go(); + }, }, - go() { - if (goCount > 0) { - E(bob).getThing(me); - } else { - E(bob).finish(); - } - goCount -= 1; - }, - deliverThing(thing) { - other = thing; - E(me).go(); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/vatStore3/vat-bob.js b/packages/swingset-runner/demo/vatStore3/vat-bob.js index 01a16911ab8..938642fc547 100644 --- a/packages/swingset-runner/demo/vatStore3/vat-bob.js +++ b/packages/swingset-runner/demo/vatStore3/vat-bob.js @@ -11,40 +11,44 @@ export function buildRootObject() { let nextThingNumber = 0; - return Far('root', { - prepare() { - for (let i = 1; i <= 9; i += 1) { - things.push(makeThing(`thing #${i}`)); - } - }, - getThing(forWhom) { - let thing; - do { - thing = things[nextThingNumber]; - nextThingNumber += 1; - } while (!thing); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + prepare() { + for (let i = 1; i <= 9; i += 1) { + things.push(makeThing(`thing #${i}`)); + } + }, + getThing(forWhom) { + let thing; + do { + thing = things[nextThingNumber]; + nextThingNumber += 1; + } while (!thing); - if (nextThingNumber === 2) { - console.log(`not nulling ${thing.getLabel()}`); - console.log(`nulling ${things[3].getLabel()} instead`); - things[3] = null; // arbitrarily drop one before sending it, but don't drop the one we're sending - } else { - console.log(`nulling ${thing.getLabel()}`); - things[nextThingNumber - 1] = null; // drop the one we're sending - } - E(forWhom).deliverThing(thing); - thing = null; - }, - finish() { - while (nextThingNumber < 7) { - const deadThing = things[nextThingNumber]; - if (deadThing) { - console.log(`final nulling ${deadThing.getLabel()}`); - things[nextThingNumber] = null; + if (nextThingNumber === 2) { + console.log(`not nulling ${thing.getLabel()}`); + console.log(`nulling ${things[3].getLabel()} instead`); + things[3] = null; // arbitrarily drop one before sending it, but don't drop the one we're sending + } else { + console.log(`nulling ${thing.getLabel()}`); + things[nextThingNumber - 1] = null; // drop the one we're sending } - nextThingNumber += 1; - } - console.log(`Bob finishing`); + E(forWhom).deliverThing(thing); + thing = null; + }, + finish() { + while (nextThingNumber < 7) { + const deadThing = things[nextThingNumber]; + if (deadThing) { + console.log(`final nulling ${deadThing.getLabel()}`); + things[nextThingNumber] = null; + } + nextThingNumber += 1; + } + console.log(`Bob finishing`); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/vaultPerfTest/vat-benchmark.js b/packages/swingset-runner/demo/vaultPerfTest/vat-benchmark.js index 69b82ba7dc8..8e01486a1fa 100644 --- a/packages/swingset-runner/demo/vaultPerfTest/vat-benchmark.js +++ b/packages/swingset-runner/demo/vaultPerfTest/vat-benchmark.js @@ -27,82 +27,94 @@ export function buildRootObject() { let brand; let subscriber; - return Far('root', { - async setup(vats, devices) { - // XXX TODO: Some of this setup logic will be common to perhaps many - // benchmarks. The common portions should be factored out into a - // benchmark support library as we learn from experience which are the - // common parts and which are the benchmark-specific parts - - log( - `benchmark setup(${JSON.stringify(vats)}, ${JSON.stringify(devices)})`, - ); - await E(vats.bootstrap).consumeItem('vaultFactoryKit'); - - const walletFactoryStartResult = await E(vats.bootstrap).consumeItem( - 'walletFactoryStartResult', - ); - const agoricNames = await E(vats.bootstrap).consumeItem('agoricNames'); - const atomBrand = await E(agoricNames).lookup('brand', 'ATOM'); - const istBrand = await E(agoricNames).lookup('brand', 'IST'); - brand = { - ATOM: atomBrand, - IST: istBrand, - }; - - const bankManager = await E(vats.bootstrap).consumeItem('bankManager'); - const namesByAddressAdmin = await E(vats.bootstrap).consumeItem( - 'namesByAddressAdmin', - ); - - async function provideSmartWallet(walletAddress) { - const bank = await E(bankManager).getBankForAddress(walletAddress); - return E(walletFactoryStartResult.creatorFacet) - .provideSmartWallet(walletAddress, bank, namesByAddressAdmin) - .then(([walletPresence]) => walletPresence); - } - - await provideSmartWallet('agoric1ldmtatp24qlllgxmrsjzcpe20fvlkp448zcuce'); - await provideSmartWallet('agoric140dmkrz2e42ergjj7gyvejhzmjzurvqeq82ang'); - await provideSmartWallet('agoric1w8wktaur4zf8qmmtn3n7x3r0jhsjkjntcm3u6h'); - wallet = await provideSmartWallet('agoric1open'); - walletOffersFacet = await E(wallet).getOffersFacet(); - - const topics = await E(wallet).getPublicTopics(); - subscriber = topics.updates.subscriber; - }, - async runBenchmarkRound() { - benchmarkRounds += 1; - log(`runBenchmarkRound #${benchmarkRounds}`); - - const openVault = async (i, n) => { - const offerId = `open-vault-${i}-of-${n}-round-${benchmarkRounds}`; - const offer = Offers.vaults.OpenVault( - { brand }, - { - offerId, - collateralBrandKey, - wantMinted: 5, - giveCollateral: 1.0, - }, + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async setup(vats, devices) { + // XXX TODO: Some of this setup logic will be common to perhaps many + // benchmarks. The common portions should be factored out into a + // benchmark support library as we learn from experience which are the + // common parts and which are the benchmark-specific parts + + log( + `benchmark setup(${JSON.stringify(vats)}, ${JSON.stringify( + devices, + )})`, ); + await E(vats.bootstrap).consumeItem('vaultFactoryKit'); - await E(walletOffersFacet).executeOffer(offer); - - const upd = await E(subscriber).getUpdateSince(); - assert( - upd.value.updated === 'offerStatus' && - upd.value.status.id === offerId && - upd.value.status.numWantsSatisfied === 1, + const walletFactoryStartResult = await E(vats.bootstrap).consumeItem( + 'walletFactoryStartResult', + ); + const agoricNames = await E(vats.bootstrap).consumeItem('agoricNames'); + const atomBrand = await E(agoricNames).lookup('brand', 'ATOM'); + const istBrand = await E(agoricNames).lookup('brand', 'IST'); + brand = { + ATOM: atomBrand, + IST: istBrand, + }; + + const bankManager = await E(vats.bootstrap).consumeItem('bankManager'); + const namesByAddressAdmin = await E(vats.bootstrap).consumeItem( + 'namesByAddressAdmin', ); - }; - const openN = async n => { - const range = [...Array(n)].map((_, i) => i + 1); - await Promise.all(range.map(i => openVault(i, n))); - }; + async function provideSmartWallet(walletAddress) { + const bank = await E(bankManager).getBankForAddress(walletAddress); + return E(walletFactoryStartResult.creatorFacet) + .provideSmartWallet(walletAddress, bank, namesByAddressAdmin) + .then(([walletPresence]) => walletPresence); + } - await openN(1); + await provideSmartWallet( + 'agoric1ldmtatp24qlllgxmrsjzcpe20fvlkp448zcuce', + ); + await provideSmartWallet( + 'agoric140dmkrz2e42ergjj7gyvejhzmjzurvqeq82ang', + ); + await provideSmartWallet( + 'agoric1w8wktaur4zf8qmmtn3n7x3r0jhsjkjntcm3u6h', + ); + wallet = await provideSmartWallet('agoric1open'); + walletOffersFacet = await E(wallet).getOffersFacet(); + + const topics = await E(wallet).getPublicTopics(); + subscriber = topics.updates.subscriber; + }, + async runBenchmarkRound() { + benchmarkRounds += 1; + log(`runBenchmarkRound #${benchmarkRounds}`); + + const openVault = async (i, n) => { + const offerId = `open-vault-${i}-of-${n}-round-${benchmarkRounds}`; + const offer = Offers.vaults.OpenVault( + { brand }, + { + offerId, + collateralBrandKey, + wantMinted: 5, + giveCollateral: 1.0, + }, + ); + + await E(walletOffersFacet).executeOffer(offer); + + const upd = await E(subscriber).getUpdateSince(); + assert( + upd.value.updated === 'offerStatus' && + upd.value.status.id === offerId && + upd.value.status.numWantsSatisfied === 1, + ); + }; + + const openN = async n => { + const range = [...Array(n)].map((_, i) => i + 1); + await Promise.all(range.map(i => openVault(i, n))); + }; + + await openN(1); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/virtualObjectGC/bootstrap.js b/packages/swingset-runner/demo/virtualObjectGC/bootstrap.js index e20d5127ccf..59bc0f716a4 100644 --- a/packages/swingset-runner/demo/virtualObjectGC/bootstrap.js +++ b/packages/swingset-runner/demo/virtualObjectGC/bootstrap.js @@ -21,196 +21,200 @@ export function buildRootObject() { } } - return Far('root', { - async bootstrap(vats) { - me = vats.bootstrap; - bob = vats.bob; - // exerciseWeakKeys = true; - // E(me).continueTest('test1'); - // E(me).continueTest('test2'); - // E(me).continueTest('test3'); - // E(me).continueTest('test4'); - // E(me).continueTest('test5'); - // E(me).continueTest('test6'); - exerciseWeakKeys = false; - // E(me).continueTest('test1'); - // E(me).continueTest('test2'); - // E(me).continueTest('test3'); - // E(me).continueTest('test4'); - // E(me).continueTest('test5'); - E(me).continueTest('test6'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + me = vats.bootstrap; + bob = vats.bob; + // exerciseWeakKeys = true; + // E(me).continueTest('test1'); + // E(me).continueTest('test2'); + // E(me).continueTest('test3'); + // E(me).continueTest('test4'); + // E(me).continueTest('test5'); + // E(me).continueTest('test6'); + exerciseWeakKeys = false; + // E(me).continueTest('test1'); + // E(me).continueTest('test2'); + // E(me).continueTest('test3'); + // E(me).continueTest('test4'); + // E(me).continueTest('test5'); + E(me).continueTest('test6'); + }, + async continueTest(testTag) { + switch (testTag) { + case 'test1': { + // test 1: + // - create a locally referenced VO lerv -> Lerv + // - forget about it Lerv -> lerv + E(bob).makeAndHold(); + E(bob).dropHeld(); + E(bob).assess(); + // E(me).continueTest('test2'); + break; + } + case 'test2': { + // test 2: + // - create a locally referenced VO lerv -> Lerv + // - store virtually Lerv -> LerV + // - forget about it LerV -> lerV + // - read from virtual storage lerV -> LerV + // - export it LerV -> LERV + // - forget about it LERV -> lERV + // - read from virtual storage lERV -> LERV + // - forget about it LERV -> lERV + // - reintroduce via delivery lERV -> LERV + // - forget abut it LERV -> lERV + // - drop export lERV -> leRV + // - read from virtual storage leRV -> LeRV + // - forget about it LeRV -> leRV + // - read from virtual storage leRV -> LeRV + // - retire export LeRV -> LerV + E(bob).makeAndHold(); + E(bob).storeHeld(); + E(bob).dropHeld(); + E(bob).fetchAndHold(); + exportedThing = await E(bob).exportHeld(); + maybeRecognize(exportedThing); + E(bob).dropHeld(); + E(bob).fetchAndHold(); + E(bob).dropHeld(); + E(bob).importAndHold(exportedThing); + E(bob).dropHeld(); + exportedThing = null; + E(bob).tellMeToContinueTest(me, 'test2a'); + break; + } + case 'test2a': { + E(bob).fetchAndHold(); + E(bob).dropHeld(); + E(bob).fetchAndHold(); + maybeDontRecognizeAnything(); + E(bob).tellMeToContinueTest(me, 'test2b'); + break; + } + case 'test2b': { + E(bob).assess(); + // E(me).continueTest('test3'); + break; + } + case 'test3': { + // - create a locally referenced VO lerv -> Lerv + // - store virtually Lerv -> LerV + // - export it LerV -> LERV + // - drop export LERV -> LeRV + // - drop held LeRV -> leRV + // - retire export leRV -> lerV + E(bob).makeAndHold(); + E(bob).storeHeld(); + exportedThing = await E(bob).exportHeld(); + maybeRecognize(exportedThing); + E(bob).dropHeld(); + exportedThing = null; + E(bob).tellMeToContinueTest(me, 'test3a'); + break; + } + case 'test3a': { + maybeDontRecognizeAnything(); + E(bob).tellMeToContinueTest(me, 'test3b'); + break; + } + case 'test3b': { + E(bob).assess(); + // E(me).continueTest('test4'); + break; + } + case 'test4': { + // - create a locally referenced VO lerv -> Lerv + // - export it Lerv -> LERv + // - drop export LERv -> LeRv + // - drop it LeRv -> leRv + // - retire export leRv -> lerv + E(bob).makeAndHold(); + exportedThing = await E(bob).exportHeld(); + maybeRecognize(exportedThing); + E(bob).tellMeToContinueTest(me, 'test4a'); + break; + } + case 'test4a': { + exportedThing = null; + E(bob).tellMeToContinueTest(me, 'test4b'); + break; + } + case 'test4b': { + E(bob).dropHeld(); + maybeDontRecognizeAnything(); + E(bob).tellMeToContinueTest(me, 'test4c'); + break; + } + case 'test4c': { + E(bob).assess(); + // E(me).continueTest('test5'); + break; + } + case 'test5': { + // - create a locally referenced VO lerv -> Lerv + // - export it Lerv -> LERv + // - drop export LERv -> LeRv + // - retire export LeRv -> lerv + // - drop it LeRv -> leRv + E(bob).makeAndHold(); + exportedThing = await E(bob).exportHeld(); + maybeRecognize(exportedThing); + E(bob).tellMeToContinueTest(me, 'test5a'); + break; + } + case 'test5a': { + exportedThing = null; + E(bob).tellMeToContinueTest(me, 'test5b'); + break; + } + case 'test5b': { + maybeDontRecognizeAnything(); + E(bob).tellMeToContinueTest(me, 'test5c'); + break; + } + case 'test5c': { + E(bob).dropHeld(); + E(bob).assess(); + // E(me).continueTest('test6'); + break; + } + case 'test6': { + // - create a locally referenced VO lerv -> Lerv + // - export it Lerv -> LERv + // - drop export LERv -> LeRv + // - store virtually LeRv -> LeRV + // - drop it LeRV -> leRV + // - retire export leRV -> lerV + E(bob).makeAndHold(); + exportedThing = await E(bob).exportHeld(); + maybeRecognize(exportedThing); + E(bob).tellMeToContinueTest(me, 'test6a'); + break; + } + case 'test6a': { + exportedThing = null; + E(bob).tellMeToContinueTest(me, 'test6b'); + break; + } + case 'test6b': { + E(bob).storeHeld(); + E(bob).dropHeld(); + maybeDontRecognizeAnything(); + E(bob).tellMeToContinueTest(me, 'test6c'); + break; + } + case 'test6c': { + E(bob).assess(); + break; + } + default: + break; + } + }, }, - async continueTest(testTag) { - switch (testTag) { - case 'test1': { - // test 1: - // - create a locally referenced VO lerv -> Lerv - // - forget about it Lerv -> lerv - E(bob).makeAndHold(); - E(bob).dropHeld(); - E(bob).assess(); - // E(me).continueTest('test2'); - break; - } - case 'test2': { - // test 2: - // - create a locally referenced VO lerv -> Lerv - // - store virtually Lerv -> LerV - // - forget about it LerV -> lerV - // - read from virtual storage lerV -> LerV - // - export it LerV -> LERV - // - forget about it LERV -> lERV - // - read from virtual storage lERV -> LERV - // - forget about it LERV -> lERV - // - reintroduce via delivery lERV -> LERV - // - forget abut it LERV -> lERV - // - drop export lERV -> leRV - // - read from virtual storage leRV -> LeRV - // - forget about it LeRV -> leRV - // - read from virtual storage leRV -> LeRV - // - retire export LeRV -> LerV - E(bob).makeAndHold(); - E(bob).storeHeld(); - E(bob).dropHeld(); - E(bob).fetchAndHold(); - exportedThing = await E(bob).exportHeld(); - maybeRecognize(exportedThing); - E(bob).dropHeld(); - E(bob).fetchAndHold(); - E(bob).dropHeld(); - E(bob).importAndHold(exportedThing); - E(bob).dropHeld(); - exportedThing = null; - E(bob).tellMeToContinueTest(me, 'test2a'); - break; - } - case 'test2a': { - E(bob).fetchAndHold(); - E(bob).dropHeld(); - E(bob).fetchAndHold(); - maybeDontRecognizeAnything(); - E(bob).tellMeToContinueTest(me, 'test2b'); - break; - } - case 'test2b': { - E(bob).assess(); - // E(me).continueTest('test3'); - break; - } - case 'test3': { - // - create a locally referenced VO lerv -> Lerv - // - store virtually Lerv -> LerV - // - export it LerV -> LERV - // - drop export LERV -> LeRV - // - drop held LeRV -> leRV - // - retire export leRV -> lerV - E(bob).makeAndHold(); - E(bob).storeHeld(); - exportedThing = await E(bob).exportHeld(); - maybeRecognize(exportedThing); - E(bob).dropHeld(); - exportedThing = null; - E(bob).tellMeToContinueTest(me, 'test3a'); - break; - } - case 'test3a': { - maybeDontRecognizeAnything(); - E(bob).tellMeToContinueTest(me, 'test3b'); - break; - } - case 'test3b': { - E(bob).assess(); - // E(me).continueTest('test4'); - break; - } - case 'test4': { - // - create a locally referenced VO lerv -> Lerv - // - export it Lerv -> LERv - // - drop export LERv -> LeRv - // - drop it LeRv -> leRv - // - retire export leRv -> lerv - E(bob).makeAndHold(); - exportedThing = await E(bob).exportHeld(); - maybeRecognize(exportedThing); - E(bob).tellMeToContinueTest(me, 'test4a'); - break; - } - case 'test4a': { - exportedThing = null; - E(bob).tellMeToContinueTest(me, 'test4b'); - break; - } - case 'test4b': { - E(bob).dropHeld(); - maybeDontRecognizeAnything(); - E(bob).tellMeToContinueTest(me, 'test4c'); - break; - } - case 'test4c': { - E(bob).assess(); - // E(me).continueTest('test5'); - break; - } - case 'test5': { - // - create a locally referenced VO lerv -> Lerv - // - export it Lerv -> LERv - // - drop export LERv -> LeRv - // - retire export LeRv -> lerv - // - drop it LeRv -> leRv - E(bob).makeAndHold(); - exportedThing = await E(bob).exportHeld(); - maybeRecognize(exportedThing); - E(bob).tellMeToContinueTest(me, 'test5a'); - break; - } - case 'test5a': { - exportedThing = null; - E(bob).tellMeToContinueTest(me, 'test5b'); - break; - } - case 'test5b': { - maybeDontRecognizeAnything(); - E(bob).tellMeToContinueTest(me, 'test5c'); - break; - } - case 'test5c': { - E(bob).dropHeld(); - E(bob).assess(); - // E(me).continueTest('test6'); - break; - } - case 'test6': { - // - create a locally referenced VO lerv -> Lerv - // - export it Lerv -> LERv - // - drop export LERv -> LeRv - // - store virtually LeRv -> LeRV - // - drop it LeRV -> leRV - // - retire export leRV -> lerV - E(bob).makeAndHold(); - exportedThing = await E(bob).exportHeld(); - maybeRecognize(exportedThing); - E(bob).tellMeToContinueTest(me, 'test6a'); - break; - } - case 'test6a': { - exportedThing = null; - E(bob).tellMeToContinueTest(me, 'test6b'); - break; - } - case 'test6b': { - E(bob).storeHeld(); - E(bob).dropHeld(); - maybeDontRecognizeAnything(); - E(bob).tellMeToContinueTest(me, 'test6c'); - break; - } - case 'test6c': { - E(bob).assess(); - break; - } - default: - break; - } - }, - }); + ); } diff --git a/packages/swingset-runner/demo/virtualObjectGC/vat-bob.js b/packages/swingset-runner/demo/virtualObjectGC/vat-bob.js index 96973b34a46..5fae05abbcf 100644 --- a/packages/swingset-runner/demo/virtualObjectGC/vat-bob.js +++ b/packages/swingset-runner/demo/virtualObjectGC/vat-bob.js @@ -26,37 +26,41 @@ export function buildRootObject() { return thing; } - return Far('root', { - makeAndHold() { - heldThing = makeNextThing(); - displaceCache(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + makeAndHold() { + heldThing = makeNextThing(); + displaceCache(); + }, + dropHeld() { + heldThing = null; + displaceCache(); + }, + storeHeld() { + virtualHolder = makeVirtualHolder(heldThing); + displaceCache(); + }, + fetchAndHold() { + heldThing = virtualHolder.getValue(); + displaceCache(); + }, + exportHeld() { + return heldThing; + }, + importAndHold(thing) { + heldThing = thing; + displaceCache(); + }, + tellMeToContinueTest(other, testTag) { + displaceCache(); + E(other).continueTest(testTag); + }, + assess() { + displaceCache(); + console.log('assess here'); + }, }, - dropHeld() { - heldThing = null; - displaceCache(); - }, - storeHeld() { - virtualHolder = makeVirtualHolder(heldThing); - displaceCache(); - }, - fetchAndHold() { - heldThing = virtualHolder.getValue(); - displaceCache(); - }, - exportHeld() { - return heldThing; - }, - importAndHold(thing) { - heldThing = thing; - displaceCache(); - }, - tellMeToContinueTest(other, testTag) { - displaceCache(); - E(other).continueTest(testTag); - }, - assess() { - displaceCache(); - console.log('assess here'); - }, - }); + ); } diff --git a/packages/swingset-runner/demo/workerDeathTest/bootstrap.js b/packages/swingset-runner/demo/workerDeathTest/bootstrap.js index 3aac41c1ba1..92177fb50f4 100644 --- a/packages/swingset-runner/demo/workerDeathTest/bootstrap.js +++ b/packages/swingset-runner/demo/workerDeathTest/bootstrap.js @@ -3,12 +3,16 @@ import { Far } from '@endo/marshal'; export function buildRootObject() { console.log(`bootstrap vat initializing`); - return Far('root', { - async bootstrap(vats) { - const howMuch = 100_000_000; - console.log(`bootstrap vat invokes busy vat for ${howMuch} steps`); - await E(vats.busy).doStuff(howMuch); - await E(vats.idle).doNothing(); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats) { + const howMuch = 100_000_000; + console.log(`bootstrap vat invokes busy vat for ${howMuch} steps`); + await E(vats.busy).doStuff(howMuch); + await E(vats.idle).doNothing(); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/workerDeathTest/vat-busy.js b/packages/swingset-runner/demo/workerDeathTest/vat-busy.js index fcb12e93c0f..c12c1c2f00a 100644 --- a/packages/swingset-runner/demo/workerDeathTest/vat-busy.js +++ b/packages/swingset-runner/demo/workerDeathTest/vat-busy.js @@ -3,20 +3,24 @@ import { Far } from '@endo/marshal'; export function buildRootObject(_vatPowers, _vatParameters, baggage) { console.log(`busy vat initializing`); baggage.init('someKey', 'hello'); - return Far('root', { - doStuff(howMuch) { - let n = 2.0; - for (let i = 0; i <= howMuch; i += 1) { - n = Math.sqrt(n) * Math.sqrt(n); // introduce some computational drag - if (i % 10_000_000 === 0) { - let bv = 'no baggage'; - if (baggage) { - bv = baggage.get('someKey'); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + doStuff(howMuch) { + let n = 2.0; + for (let i = 0; i <= howMuch; i += 1) { + n = Math.sqrt(n) * Math.sqrt(n); // introduce some computational drag + if (i % 10_000_000 === 0) { + let bv = 'no baggage'; + if (baggage) { + bv = baggage.get('someKey'); + } + console.log(`busy vat doing step ${i} of ${howMuch}, bv=${bv}`); } - console.log(`busy vat doing step ${i} of ${howMuch}, bv=${bv}`); } - } - console.log(`busy vat finished ${howMuch} steps`); + console.log(`busy vat finished ${howMuch} steps`); + }, }, - }); + ); } diff --git a/packages/swingset-runner/demo/workerDeathTest/vat-idle.js b/packages/swingset-runner/demo/workerDeathTest/vat-idle.js index 23d55762320..d37ef22b6c2 100644 --- a/packages/swingset-runner/demo/workerDeathTest/vat-idle.js +++ b/packages/swingset-runner/demo/workerDeathTest/vat-idle.js @@ -2,7 +2,11 @@ import { Far } from '@endo/marshal'; export function buildRootObject() { console.log(`idle vat initializing`); - return Far('root', { - doNothing() {}, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + doNothing() {}, + }, + ); } diff --git a/packages/swingset-runner/demo/zoeTests/bootstrap.js b/packages/swingset-runner/demo/zoeTests/bootstrap.js index 83eec949464..eeb5c0671e0 100644 --- a/packages/swingset-runner/demo/zoeTests/bootstrap.js +++ b/packages/swingset-runner/demo/zoeTests/bootstrap.js @@ -93,58 +93,62 @@ const makeVats = (log, vats, zoe, installations, startingValues) => { }; export function buildRootObject(_vatPowers, vatParameters) { - const obj0 = Far('root', { - async bootstrap(vats, devices) { - const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, - ); - /** @type {{zoeService: ERef}} */ - const { zoeService: zoe } = await E(vats.zoe).buildZoe( - vatAdminSvc, - undefined, - 'zcf', - ); - const installations = { - automaticRefund: await E(zoe).install(automaticRefundBundle.bundle), - coveredCall: await E(zoe).install(coveredCallBundle.bundle), - secondPriceAuction: await E(zoe).install( - secondPriceAuctionBundle.bundle, - ), - atomicSwap: await E(zoe).install(atomicSwapBundle.bundle), - simpleExchange: await E(zoe).install(simpleExchangeBundle.bundle), - autoswap: await E(zoe).install(autoswapBundle.bundle), - sellItems: await E(zoe).install(sellItemsBundle.bundle), - mintAndSellNFT: await E(zoe).install(mintAndSellNFTBundle.bundle), - otcDesk: await E(zoe).install(otcDeskBundle.bundle), - }; - - const testName = vatParameters.argv[0] || 'simpleExchangeOk'; - const startingValuesStr = vatParameters.argv[1]; - let startingValues; - if (startingValuesStr) { - startingValues = JSON.parse(startingValuesStr); - } else if ( - vatParameters.startingValues && - vatParameters.startingValues[testName] - ) { - startingValues = vatParameters.startingValues[testName]; - } else { - throw Error( - `Cannot find startingValues for ${testName} in ${JSON.stringify( - vatParameters, - )}`, + const obj0 = makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + /** @type {{zoeService: ERef}} */ + const { zoeService: zoe } = await E(vats.zoe).buildZoe( + vatAdminSvc, + undefined, + 'zcf', ); - } + const installations = { + automaticRefund: await E(zoe).install(automaticRefundBundle.bundle), + coveredCall: await E(zoe).install(coveredCallBundle.bundle), + secondPriceAuction: await E(zoe).install( + secondPriceAuctionBundle.bundle, + ), + atomicSwap: await E(zoe).install(atomicSwapBundle.bundle), + simpleExchange: await E(zoe).install(simpleExchangeBundle.bundle), + autoswap: await E(zoe).install(autoswapBundle.bundle), + sellItems: await E(zoe).install(sellItemsBundle.bundle), + mintAndSellNFT: await E(zoe).install(mintAndSellNFTBundle.bundle), + otcDesk: await E(zoe).install(otcDeskBundle.bundle), + }; + + const testName = vatParameters.argv[0] || 'simpleExchangeOk'; + const startingValuesStr = vatParameters.argv[1]; + let startingValues; + if (startingValuesStr) { + startingValues = JSON.parse(startingValuesStr); + } else if ( + vatParameters.startingValues && + vatParameters.startingValues[testName] + ) { + startingValues = vatParameters.startingValues[testName]; + } else { + throw Error( + `Cannot find startingValues for ${testName} in ${JSON.stringify( + vatParameters, + )}`, + ); + } - const { aliceP, bobP, carolP, daveP } = makeVats( - makePrintLog(), - vats, - zoe, - installations, - startingValues, - ); - await E(aliceP).startTest(testName, bobP, carolP, daveP); + const { aliceP, bobP, carolP, daveP } = makeVats( + makePrintLog(), + vats, + zoe, + installations, + startingValues, + ); + await E(aliceP).startTest(testName, bobP, carolP, daveP); + }, }, - }); + ); return obj0; } diff --git a/packages/swingset-runner/demo/zoeTests/vat-alice.js b/packages/swingset-runner/demo/zoeTests/vat-alice.js index ffedcdbcb5e..9adcb864866 100644 --- a/packages/swingset-runner/demo/zoeTests/vat-alice.js +++ b/packages/swingset-runner/demo/zoeTests/vat-alice.js @@ -511,7 +511,11 @@ const build = async (log, zoe, issuers, payments, installations, timer) => { want: { StrikePrice: simoleans(7n) }, exit: { afterDeadline: { - timer: Far('timer', { setWakeup: () => {} }), + timer: makeExo( + 'timer', + M.interface('timer', {}, { defaultGuards: 'passable' }), + { setWakeup: () => {} }, + ), deadline: 1n, }, }, @@ -542,52 +546,60 @@ const build = async (log, zoe, issuers, payments, installations, timer) => { await showPurseBalance(simoleanPurseP, 'aliceSimoleanPurse', log); }; - return Far('build', { - startTest: async (testName, bobP, carolP, daveP) => { - switch (testName) { - case 'automaticRefundOk': { - return doAutomaticRefund(bobP); + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + startTest: async (testName, bobP, carolP, daveP) => { + switch (testName) { + case 'automaticRefundOk': { + return doAutomaticRefund(bobP); + } + case 'coveredCallOk': { + return doCoveredCall(bobP); + } + case 'swapForOptionOk': { + return doSwapForOption(bobP, carolP, daveP); + } + case 'secondPriceAuctionOk': { + return doSecondPriceAuction(bobP, carolP, daveP); + } + case 'atomicSwapOk': { + return doAtomicSwap(bobP); + } + case 'simpleExchangeOk': { + return doSimpleExchange(bobP); + } + case 'simpleExchangeNotifier': { + return doSimpleExchangeWithNotification(bobP); + } + case 'autoswapOk': { + return doAutoswap(bobP); + } + case 'sellTicketsOk': { + return doSellTickets(bobP); + } + case 'otcDeskOk': { + return doOTCDesk(bobP); + } + case 'badTimer': { + return doBadTimer(); + } + default: { + throw Fail`testName ${testName} not recognized`; + } } - case 'coveredCallOk': { - return doCoveredCall(bobP); - } - case 'swapForOptionOk': { - return doSwapForOption(bobP, carolP, daveP); - } - case 'secondPriceAuctionOk': { - return doSecondPriceAuction(bobP, carolP, daveP); - } - case 'atomicSwapOk': { - return doAtomicSwap(bobP); - } - case 'simpleExchangeOk': { - return doSimpleExchange(bobP); - } - case 'simpleExchangeNotifier': { - return doSimpleExchangeWithNotification(bobP); - } - case 'autoswapOk': { - return doAutoswap(bobP); - } - case 'sellTicketsOk': { - return doSellTickets(bobP); - } - case 'otcDeskOk': { - return doOTCDesk(bobP); - } - case 'badTimer': { - return doBadTimer(); - } - default: { - throw Fail`testName ${testName} not recognized`; - } - } + }, }, - }); + ); }; export function buildRootObject() { - return Far('root', { - build: (...args) => build(makePrintLog(), ...args), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (...args) => build(makePrintLog(), ...args), + }, + ); } diff --git a/packages/swingset-runner/demo/zoeTests/vat-bob.js b/packages/swingset-runner/demo/zoeTests/vat-bob.js index cba3b8f0acd..45f6f10ff68 100644 --- a/packages/swingset-runner/demo/zoeTests/vat-bob.js +++ b/packages/swingset-runner/demo/zoeTests/vat-bob.js @@ -18,525 +18,541 @@ const build = async (log, zoe, issuers, payments, installations, timer) => { let secondPriceAuctionSeatP; - return Far('build', { - doAutomaticRefund: async invitation => { - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - - // Bob ensures it's the contract he expects - installations.automaticRefund === installation || - Fail`should be the expected automaticRefund`; - issuerKeywordRecord.Contribution1 === moolaIssuer || - Fail`The first issuer should be the moola issuer`; - issuerKeywordRecord.Contribution2 === simoleanIssuer || - Fail`The second issuer should be the simolean issuer`; - - // 1. Bob escrows his offer - const bobProposal = harden({ - want: { Contribution1: moola(15n) }, - give: { Contribution2: simoleans(17n) }, - exit: { onDemand: null }, - }); - - const bobPayments = { Contribution2: simoleanPayment }; - - // 2. Bob makes an offer - const bobSeatP = await E(zoe).offer( - exclInvitation, - bobProposal, - bobPayments, - ); - log(await E(bobSeatP).getOfferResult()); - - const moolaPayout = await E(bobSeatP).getPayout('Contribution1'); - const simoleanPayout = await E(bobSeatP).getPayout('Contribution2'); - - // 5: Bob deposits his winnings - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); - - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - }, + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + doAutomaticRefund: async invitation => { + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + + // Bob ensures it's the contract he expects + installations.automaticRefund === installation || + Fail`should be the expected automaticRefund`; + issuerKeywordRecord.Contribution1 === moolaIssuer || + Fail`The first issuer should be the moola issuer`; + issuerKeywordRecord.Contribution2 === simoleanIssuer || + Fail`The second issuer should be the simolean issuer`; + + // 1. Bob escrows his offer + const bobProposal = harden({ + want: { Contribution1: moola(15n) }, + give: { Contribution2: simoleans(17n) }, + exit: { onDemand: null }, + }); + + const bobPayments = { Contribution2: simoleanPayment }; + + // 2. Bob makes an offer + const bobSeatP = await E(zoe).offer( + exclInvitation, + bobProposal, + bobPayments, + ); + log(await E(bobSeatP).getOfferResult()); + + const moolaPayout = await E(bobSeatP).getPayout('Contribution1'); + const simoleanPayout = await E(bobSeatP).getPayout('Contribution2'); + + // 5: Bob deposits his winnings + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + }, + + doCoveredCall: async invitation => { + // Bob claims all with the Zoe invitationIssuer + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + + const bobIntendedProposal = harden({ + want: { UnderlyingAsset: moola(3n) }, + give: { StrikePrice: simoleans(7n) }, + }); - doCoveredCall: async invitation => { - // Bob claims all with the Zoe invitationIssuer - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - - const bobIntendedProposal = harden({ - want: { UnderlyingAsset: moola(3n) }, - give: { StrikePrice: simoleans(7n) }, - }); - - // Bob checks that the invitation is for the right covered call - const { value: optionValue } = - await E(invitationIssuer).getAmountOf(exclInvitation); - const { customDetails } = optionValue[0]; - assert(typeof customDetails === 'object'); - installation === installations.coveredCall || Fail`wrong installation`; - optionValue[0].description === 'exerciseOption' || Fail`wrong invitation`; - assert( + // Bob checks that the invitation is for the right covered call + const { value: optionValue } = + await E(invitationIssuer).getAmountOf(exclInvitation); + const { customDetails } = optionValue[0]; + assert(typeof customDetails === 'object'); + installation === installations.coveredCall || Fail`wrong installation`; + optionValue[0].description === 'exerciseOption' || + Fail`wrong invitation`; + assert( + AmountMath.isEqual( + customDetails.underlyingAssets.UnderlyingAsset, + moola(3n), + ), + ); + assert( + AmountMath.isEqual( + customDetails.strikePrice.StrikePrice, + simoleans(7n), + ), + ); + customDetails.expirationDate === 1n || Fail`wrong expirationDate`; + assert(customDetails.timeAuthority === timer, 'wrong timer'); + const { UnderlyingAsset, StrikePrice } = issuerKeywordRecord; + UnderlyingAsset === moolaIssuer || + Fail`The underlying asset issuer should be the moola issuer`; + StrikePrice === simoleanIssuer || + Fail`The strike price issuer should be the simolean issuer`; + + const bobPayments = { StrikePrice: simoleanPayment }; + // Bob escrows + const seatP = await E(zoe).offer( + exclInvitation, + bobIntendedProposal, + bobPayments, + ); + + log(await E(seatP).getOfferResult()); + + const moolaPayout = await E(seatP).getPayout('UnderlyingAsset'); + const simoleanPayout = await E(seatP).getPayout('StrikePrice'); + + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + }, + + doSwapForOption: async (invitation, daveP) => { + // Bob claims all with the Zoe invitationIssuer + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + + const { UnderlyingAsset, StrikePrice } = + await E(zoe).getIssuers(instance); + + // Bob checks that the invitation is for the right covered call + const optionAmounts = + await E(invitationIssuer).getAmountOf(exclInvitation); + const optionValue = optionAmounts.value; + const { customDetails } = optionValue[0]; + assert(typeof customDetails === 'object'); + + installation === installations.coveredCall || Fail`wrong installation`; + optionValue[0].description === 'exerciseOption' || + Fail`wrong invitation`; AmountMath.isEqual( customDetails.underlyingAssets.UnderlyingAsset, moola(3n), - ), - ); - assert( + ) || Fail`wrong underlying asset`; AmountMath.isEqual( customDetails.strikePrice.StrikePrice, simoleans(7n), - ), - ); - customDetails.expirationDate === 1n || Fail`wrong expirationDate`; - assert(customDetails.timeAuthority === timer, 'wrong timer'); - const { UnderlyingAsset, StrikePrice } = issuerKeywordRecord; - UnderlyingAsset === moolaIssuer || - Fail`The underlying asset issuer should be the moola issuer`; - StrikePrice === simoleanIssuer || - Fail`The strike price issuer should be the simolean issuer`; - - const bobPayments = { StrikePrice: simoleanPayment }; - // Bob escrows - const seatP = await E(zoe).offer( - exclInvitation, - bobIntendedProposal, - bobPayments, - ); - - log(await E(seatP).getOfferResult()); - - const moolaPayout = await E(seatP).getPayout('UnderlyingAsset'); - const simoleanPayout = await E(seatP).getPayout('StrikePrice'); - - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); - - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - }, - - doSwapForOption: async (invitation, daveP) => { - // Bob claims all with the Zoe invitationIssuer - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - - const { UnderlyingAsset, StrikePrice } = - await E(zoe).getIssuers(instance); - - // Bob checks that the invitation is for the right covered call - const optionAmounts = - await E(invitationIssuer).getAmountOf(exclInvitation); - const optionValue = optionAmounts.value; - const { customDetails } = optionValue[0]; - assert(typeof customDetails === 'object'); - - installation === installations.coveredCall || Fail`wrong installation`; - optionValue[0].description === 'exerciseOption' || Fail`wrong invitation`; - AmountMath.isEqual( - customDetails.underlyingAssets.UnderlyingAsset, - moola(3n), - ) || Fail`wrong underlying asset`; - AmountMath.isEqual( - customDetails.strikePrice.StrikePrice, - simoleans(7n), - ) || Fail`wrong strike price`; - customDetails.expirationDate === 100n || Fail`wrong expiration date`; - customDetails.timeAuthority === timer || Fail`wrong timer`; - UnderlyingAsset === moolaIssuer || - Fail`The underlyingAsset issuer should be the moola issuer`; - StrikePrice === simoleanIssuer || - Fail`The strikePrice issuer should be the simolean issuer`; - - // Let's imagine that Bob wants to create a swap to trade this - // invitation for bucks. He wants to invitation Dave as the - // counter-party. - const offerIssuerKeywordRecord = harden({ - Asset: invitationIssuer, - Price: bucksIssuer, - }); - const { creatorInvitation: bobSwapInvitation } = await E( - zoe, - ).startInstance(installations.atomicSwap, offerIssuerKeywordRecord); - - // Bob wants to swap an invitation with the same amount as his - // current invitation from Alice. He wants 1 buck in return. - const bobProposalSwap = harden({ - give: { Asset: optionAmounts }, - want: { Price: bucks(1n) }, - }); - - const bobSwapPayments = harden({ Asset: exclInvitation }); - - // Bob escrows his option in the swap - const bobSeatP = await E(zoe).offer( - bobSwapInvitation, - bobProposalSwap, - bobSwapPayments, - ); - const daveSwapInvitationP = E(bobSeatP).getOfferResult(); - // Bob makes an offer to the swap with his "higher order" - log('swap invitation made'); - await E(daveP).doSwapForOption(daveSwapInvitationP, optionAmounts); - - const bucksPayout = await E(bobSeatP).getPayout('Price'); - - // Bob deposits his winnings - await E(bucksPurseP).deposit(bucksPayout); - - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - await showPurseBalance(bucksPurseP, 'bobBucksPurse;', log); - }, - doSecondPriceAuctionBid: async invitation => { - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - const { value: invitationValue } = - await E(invitationIssuer).getAmountOf(exclInvitation); - installation === installations.secondPriceAuction || - Fail`wrong installation`; - keyEQ( - harden({ Asset: moolaIssuer, Ask: simoleanIssuer }), - issuerKeywordRecord, - ) || Fail`issuerKeywordRecord was not as expected`; - assert( - keyEQ(invitationValue[0].customDetails?.minimumBid, simoleans(3n)), - ); - assert( - keyEQ(invitationValue[0].customDetails?.auctionedAssets, moola(1n)), - ); - - const proposal = harden({ - want: { Asset: moola(1n) }, - give: { Bid: simoleans(11n) }, - }); - const paymentKeywordRecord = { Bid: simoleanPayment }; - - secondPriceAuctionSeatP = E(zoe).offer( - exclInvitation, - proposal, - paymentKeywordRecord, - ); - log(`Bob: ${await E(secondPriceAuctionSeatP).getOfferResult()}`); - }, - doSecondPriceAuctionGetPayout: async () => { - const moolaPayout = await E(secondPriceAuctionSeatP).getPayout('Asset'); - const simoleanPayout = await E(secondPriceAuctionSeatP).getPayout('Bid'); - - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); + ) || Fail`wrong strike price`; + customDetails.expirationDate === 100n || Fail`wrong expiration date`; + customDetails.timeAuthority === timer || Fail`wrong timer`; + UnderlyingAsset === moolaIssuer || + Fail`The underlyingAsset issuer should be the moola issuer`; + StrikePrice === simoleanIssuer || + Fail`The strikePrice issuer should be the simolean issuer`; + + // Let's imagine that Bob wants to create a swap to trade this + // invitation for bucks. He wants to invitation Dave as the + // counter-party. + const offerIssuerKeywordRecord = harden({ + Asset: invitationIssuer, + Price: bucksIssuer, + }); + const { creatorInvitation: bobSwapInvitation } = await E( + zoe, + ).startInstance(installations.atomicSwap, offerIssuerKeywordRecord); + + // Bob wants to swap an invitation with the same amount as his + // current invitation from Alice. He wants 1 buck in return. + const bobProposalSwap = harden({ + give: { Asset: optionAmounts }, + want: { Price: bucks(1n) }, + }); - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - }, - doAtomicSwap: async invitation => { - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - const { value: invitationValue } = - await E(invitationIssuer).getAmountOf(exclInvitation); - installation === installations.atomicSwap || Fail`wrong installation`; - assert( + const bobSwapPayments = harden({ Asset: exclInvitation }); + + // Bob escrows his option in the swap + const bobSeatP = await E(zoe).offer( + bobSwapInvitation, + bobProposalSwap, + bobSwapPayments, + ); + const daveSwapInvitationP = E(bobSeatP).getOfferResult(); + // Bob makes an offer to the swap with his "higher order" + log('swap invitation made'); + await E(daveP).doSwapForOption(daveSwapInvitationP, optionAmounts); + + const bucksPayout = await E(bobSeatP).getPayout('Price'); + + // Bob deposits his winnings + await E(bucksPurseP).deposit(bucksPayout); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + await showPurseBalance(bucksPurseP, 'bobBucksPurse;', log); + }, + doSecondPriceAuctionBid: async invitation => { + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + const { value: invitationValue } = + await E(invitationIssuer).getAmountOf(exclInvitation); + installation === installations.secondPriceAuction || + Fail`wrong installation`; keyEQ( - harden({ Asset: moolaIssuer, Price: simoleanIssuer }), + harden({ Asset: moolaIssuer, Ask: simoleanIssuer }), issuerKeywordRecord, - ), - X`issuers were not as expected`, - ); - keyEQ(invitationValue[0].customDetails?.asset, moola(3n)) || - Fail`Alice made a different offer than expected`; - keyEQ(invitationValue[0].customDetails?.price, simoleans(7n)) || - Fail`Alice made a different offer than expected`; - - const proposal = harden({ - want: { Asset: moola(3n) }, - give: { Price: simoleans(7n) }, - }); - const paymentKeywordRecord = { Price: simoleanPayment }; - - const seatP = await E(zoe).offer( - exclInvitation, - proposal, - paymentKeywordRecord, - ); - - log(await E(seatP).getOfferResult()); - - const moolaPayout = await E(seatP).getPayout('Asset'); - const simoleanPayout = await E(seatP).getPayout('Price'); - - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); - - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - }, + ) || Fail`issuerKeywordRecord was not as expected`; + assert( + keyEQ(invitationValue[0].customDetails?.minimumBid, simoleans(3n)), + ); + assert( + keyEQ(invitationValue[0].customDetails?.auctionedAssets, moola(1n)), + ); + + const proposal = harden({ + want: { Asset: moola(1n) }, + give: { Bid: simoleans(11n) }, + }); + const paymentKeywordRecord = { Bid: simoleanPayment }; + + secondPriceAuctionSeatP = E(zoe).offer( + exclInvitation, + proposal, + paymentKeywordRecord, + ); + log(`Bob: ${await E(secondPriceAuctionSeatP).getOfferResult()}`); + }, + doSecondPriceAuctionGetPayout: async () => { + const moolaPayout = await E(secondPriceAuctionSeatP).getPayout('Asset'); + const simoleanPayout = await E(secondPriceAuctionSeatP).getPayout( + 'Bid', + ); + + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + }, + doAtomicSwap: async invitation => { + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + const { value: invitationValue } = + await E(invitationIssuer).getAmountOf(exclInvitation); + installation === installations.atomicSwap || Fail`wrong installation`; + assert( + keyEQ( + harden({ Asset: moolaIssuer, Price: simoleanIssuer }), + issuerKeywordRecord, + ), + X`issuers were not as expected`, + ); + keyEQ(invitationValue[0].customDetails?.asset, moola(3n)) || + Fail`Alice made a different offer than expected`; + keyEQ(invitationValue[0].customDetails?.price, simoleans(7n)) || + Fail`Alice made a different offer than expected`; + + const proposal = harden({ + want: { Asset: moola(3n) }, + give: { Price: simoleans(7n) }, + }); + const paymentKeywordRecord = { Price: simoleanPayment }; + + const seatP = await E(zoe).offer( + exclInvitation, + proposal, + paymentKeywordRecord, + ); + + log(await E(seatP).getOfferResult()); + + const moolaPayout = await E(seatP).getPayout('Asset'); + const simoleanPayout = await E(seatP).getPayout('Price'); + + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + }, + + doSimpleExchange: async invitation => { + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + installation === installations.simpleExchange || + Fail`wrong installation`; + issuerKeywordRecord.Asset === moolaIssuer || + Fail`The first issuer should be the moola issuer`; + issuerKeywordRecord.Price === simoleanIssuer || + Fail`The second issuer should be the simolean issuer`; + + const bobBuyOrderProposal = harden({ + want: { Asset: moola(3n) }, + give: { Price: simoleans(7n) }, + exit: { onDemand: null }, + }); + const paymentKeywordRecord = { Price: simoleanPayment }; + + const seatP = await E(zoe).offer( + exclInvitation, + bobBuyOrderProposal, + paymentKeywordRecord, + ); + + log(await E(seatP).getOfferResult()); + + const moolaPayout = await E(seatP).getPayout('Asset'); + const simoleanPayout = await E(seatP).getPayout('Price'); + + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + }, + doSimpleExchangeUpdates: async (invitationP, m, s) => { + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitationP, + ); + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + installation === installations.simpleExchange || + Fail`wrong installation`; + issuerKeywordRecord.Asset === moolaIssuer || + Fail`The first issuer should be the moola issuer`; + issuerKeywordRecord.Price === simoleanIssuer || + Fail`The second issuer should be the simolean issuer`; + const bobBuyOrderProposal = harden({ + want: { Asset: moola(m) }, + give: { Price: simoleans(s) }, + exit: { onDemand: null }, + }); + if (m === 3n && s === 7n) { + await E(simoleanPurseP).deposit(simoleanPayment); + } + const simoleanPayment2 = await E(simoleanPurseP).withdraw(simoleans(s)); + const paymentKeywordRecord = { Price: simoleanPayment2 }; + const seatP = await E(zoe).offer( + invitation, + bobBuyOrderProposal, + paymentKeywordRecord, + ); + + log(await E(seatP).getOfferResult()); + + E(seatP) + .getPayout('Asset') + .then(moolaPayout => { + E(moolaPurseP).deposit(moolaPayout); + }); + E(seatP) + .getPayout('Price') + .then(simoleanPayout => { + E(simoleanPurseP).deposit(simoleanPayout); + }); + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + }, + + doAutoswap: async instance => { + const publicFacet = await E(zoe).getPublicFacet(instance); + const buyBInvitation = await E(publicFacet).makeSwapInInvitation(); + const installation = await E(zoe).getInstallation(buyBInvitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + installation === installations.autoswap || Fail`wrong installation`; + const liquidityIssuer = await E(publicFacet).getLiquidityIssuer(); + assert( + keyEQ( + harden({ + Central: moolaIssuer, + Secondary: simoleanIssuer, + Liquidity: liquidityIssuer, + }), + issuerKeywordRecord, + ), + X`issuers were not as expected`, + ); + + // bob checks how many simoleans he can get for 3 moola + const simoleanAmounts = await E(publicFacet).getInputPrice( + moola(3n), + simoleans(0n).brand, + ); + log(`simoleanAmounts `, simoleanAmounts); - doSimpleExchange: async invitation => { - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - installation === installations.simpleExchange || Fail`wrong installation`; - issuerKeywordRecord.Asset === moolaIssuer || - Fail`The first issuer should be the moola issuer`; - issuerKeywordRecord.Price === simoleanIssuer || - Fail`The second issuer should be the simolean issuer`; - - const bobBuyOrderProposal = harden({ - want: { Asset: moola(3n) }, - give: { Price: simoleans(7n) }, - exit: { onDemand: null }, - }); - const paymentKeywordRecord = { Price: simoleanPayment }; - - const seatP = await E(zoe).offer( - exclInvitation, - bobBuyOrderProposal, - paymentKeywordRecord, - ); - - log(await E(seatP).getOfferResult()); - - const moolaPayout = await E(seatP).getPayout('Asset'); - const simoleanPayout = await E(seatP).getPayout('Price'); - - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); - - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - }, - doSimpleExchangeUpdates: async (invitationP, m, s) => { - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitationP, - ); - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - installation === installations.simpleExchange || Fail`wrong installation`; - issuerKeywordRecord.Asset === moolaIssuer || - Fail`The first issuer should be the moola issuer`; - issuerKeywordRecord.Price === simoleanIssuer || - Fail`The second issuer should be the simolean issuer`; - const bobBuyOrderProposal = harden({ - want: { Asset: moola(m) }, - give: { Price: simoleans(s) }, - exit: { onDemand: null }, - }); - if (m === 3n && s === 7n) { + const moolaForSimProposal = harden({ + give: { In: moola(3n) }, + want: { Out: simoleans(1n) }, + }); + + const moolaForSimPayments = harden({ In: moolaPayment }); + const buySeatP = await E(zoe).offer( + buyBInvitation, + moolaForSimProposal, + moolaForSimPayments, + ); + + log(await E(buySeatP).getOfferResult()); + + const moolaPayout1 = await E(buySeatP).getPayout('In'); + const simoleanPayout1 = await E(buySeatP).getPayout('Out'); + + await E(moolaPurseP).deposit(await moolaPayout1); + await E(simoleanPurseP).deposit(await simoleanPayout1); + + // Bob looks up how much moola he can get for 3 simoleans. It's 5 + const moolaProceeds = await E(publicFacet).getInputPrice( + simoleans(3n), + moola(0n).brand, + ); + log(`moola proceeds `, moolaProceeds); + + // Bob makes another offer and swaps + const bobSimsForMoolaProposal2 = harden({ + want: { Out: moola(5n) }, + give: { In: simoleans(3n) }, + }); await E(simoleanPurseP).deposit(simoleanPayment); - } - const simoleanPayment2 = await E(simoleanPurseP).withdraw(simoleans(s)); - const paymentKeywordRecord = { Price: simoleanPayment2 }; - const seatP = await E(zoe).offer( - invitation, - bobBuyOrderProposal, - paymentKeywordRecord, - ); - - log(await E(seatP).getOfferResult()); - - E(seatP) - .getPayout('Asset') - .then(moolaPayout => { - E(moolaPurseP).deposit(moolaPayout); + const bobSimPayment2 = await E(simoleanPurseP).withdraw(simoleans(3n)); + const simsForMoolaPayments2 = harden({ In: bobSimPayment2 }); + const invitation2 = E(publicFacet).makeSwapInInvitation(); + + const swapSeat2 = await E(zoe).offer( + invitation2, + bobSimsForMoolaProposal2, + simsForMoolaPayments2, + ); + + log(await E(swapSeat2).getOfferResult()); + + const moolaPayout2 = await E(swapSeat2).getPayout('Out'); + const simoleanPayout2 = await E(swapSeat2).getPayout('In'); + + await E(moolaPurseP).deposit(moolaPayout2); + await E(simoleanPurseP).deposit(simoleanPayout2); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + + // Bob looks up how much simoleans he'd have to pay for 3 moola. It's 6 + const simRequired = await E(publicFacet).getOutputPrice( + moola(3n), + simoleans(0n).brand, + ); + log(`simoleans required `, simRequired); + }, + + doBuyTickets: async (instance, invitation) => { + const publicFacet = await E(zoe).getPublicFacet(instance); + const terms = await E(zoe).getTerms(instance); + const ticketIssuer = await E(publicFacet).getItemsIssuer(); + const ticketBrand = await E(ticketIssuer).getBrand(); + + const availableTickets = await E(publicFacet).getAvailableItems(); + log('availableTickets: ', availableTickets); + // find the value corresponding to ticket #1 + assert(isSetValue(availableTickets.value)); + const ticket1Value = availableTickets.value.find( + ticket => ticket.number === 1, + ); + // make the corresponding amount + const ticket1Amount = AmountMath.make( + ticketBrand, + harden([ticket1Value]), + ); + const proposal = harden({ + give: { Money: terms.pricePerItem }, + want: { Items: ticket1Amount }, }); - E(seatP) - .getPayout('Price') - .then(simoleanPayout => { - E(simoleanPurseP).deposit(simoleanPayout); + + const paymentKeywordRecord = harden({ Money: moolaPayment }); + + const seat = await E(zoe).offer( + invitation, + proposal, + paymentKeywordRecord, + ); + const boughtTicketAmount = await E(ticketIssuer).getAmountOf( + E(seat).getPayout('Items'), + ); + log('boughtTicketAmount: ', boughtTicketAmount); + }, + + doOTCDesk: async untrustedInvitation => { + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + untrustedInvitation, + ); + const invitationValue = await E(zoe).getInvitationDetails(invitation); + assert(invitationValue.installation === installations.coveredCall); + + // Bob can use whatever keywords he wants + const proposal = harden({ + give: { Whatever1: simoleans(4n) }, + want: { Whatever2: moola(3n) }, + exit: { onDemand: null }, }); - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - }, + await E(simoleanPurseP).deposit(simoleanPayment); + const simoleanPayment1 = await E(simoleanPurseP).withdraw( + simoleans(4n), + ); - doAutoswap: async instance => { - const publicFacet = await E(zoe).getPublicFacet(instance); - const buyBInvitation = await E(publicFacet).makeSwapInInvitation(); - const installation = await E(zoe).getInstallation(buyBInvitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - installation === installations.autoswap || Fail`wrong installation`; - const liquidityIssuer = await E(publicFacet).getLiquidityIssuer(); - assert( - keyEQ( - harden({ - Central: moolaIssuer, - Secondary: simoleanIssuer, - Liquidity: liquidityIssuer, - }), - issuerKeywordRecord, - ), - X`issuers were not as expected`, - ); - - // bob checks how many simoleans he can get for 3 moola - const simoleanAmounts = await E(publicFacet).getInputPrice( - moola(3n), - simoleans(0n).brand, - ); - log(`simoleanAmounts `, simoleanAmounts); - - const moolaForSimProposal = harden({ - give: { In: moola(3n) }, - want: { Out: simoleans(1n) }, - }); - - const moolaForSimPayments = harden({ In: moolaPayment }); - const buySeatP = await E(zoe).offer( - buyBInvitation, - moolaForSimProposal, - moolaForSimPayments, - ); - - log(await E(buySeatP).getOfferResult()); - - const moolaPayout1 = await E(buySeatP).getPayout('In'); - const simoleanPayout1 = await E(buySeatP).getPayout('Out'); - - await E(moolaPurseP).deposit(await moolaPayout1); - await E(simoleanPurseP).deposit(await simoleanPayout1); - - // Bob looks up how much moola he can get for 3 simoleans. It's 5 - const moolaProceeds = await E(publicFacet).getInputPrice( - simoleans(3n), - moola(0n).brand, - ); - log(`moola proceeds `, moolaProceeds); - - // Bob makes another offer and swaps - const bobSimsForMoolaProposal2 = harden({ - want: { Out: moola(5n) }, - give: { In: simoleans(3n) }, - }); - await E(simoleanPurseP).deposit(simoleanPayment); - const bobSimPayment2 = await E(simoleanPurseP).withdraw(simoleans(3n)); - const simsForMoolaPayments2 = harden({ In: bobSimPayment2 }); - const invitation2 = E(publicFacet).makeSwapInInvitation(); - - const swapSeat2 = await E(zoe).offer( - invitation2, - bobSimsForMoolaProposal2, - simsForMoolaPayments2, - ); - - log(await E(swapSeat2).getOfferResult()); - - const moolaPayout2 = await E(swapSeat2).getPayout('Out'); - const simoleanPayout2 = await E(swapSeat2).getPayout('In'); - - await E(moolaPurseP).deposit(moolaPayout2); - await E(simoleanPurseP).deposit(simoleanPayout2); - - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - - // Bob looks up how much simoleans he'd have to pay for 3 moola. It's 6 - const simRequired = await E(publicFacet).getOutputPrice( - moola(3n), - simoleans(0n).brand, - ); - log(`simoleans required `, simRequired); - }, + const seat = await E(zoe).offer(invitation, proposal, { + Whatever1: simoleanPayment1, + }); - doBuyTickets: async (instance, invitation) => { - const publicFacet = await E(zoe).getPublicFacet(instance); - const terms = await E(zoe).getTerms(instance); - const ticketIssuer = await E(publicFacet).getItemsIssuer(); - const ticketBrand = await E(ticketIssuer).getBrand(); - - const availableTickets = await E(publicFacet).getAvailableItems(); - log('availableTickets: ', availableTickets); - // find the value corresponding to ticket #1 - assert(isSetValue(availableTickets.value)); - const ticket1Value = availableTickets.value.find( - ticket => ticket.number === 1, - ); - // make the corresponding amount - const ticket1Amount = AmountMath.make( - ticketBrand, - harden([ticket1Value]), - ); - const proposal = harden({ - give: { Money: terms.pricePerItem }, - want: { Items: ticket1Amount }, - }); - - const paymentKeywordRecord = harden({ Money: moolaPayment }); - - const seat = await E(zoe).offer( - invitation, - proposal, - paymentKeywordRecord, - ); - const boughtTicketAmount = await E(ticketIssuer).getAmountOf( - E(seat).getPayout('Items'), - ); - log('boughtTicketAmount: ', boughtTicketAmount); - }, + log(await E(seat).getOfferResult()); - doOTCDesk: async untrustedInvitation => { - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - untrustedInvitation, - ); - const invitationValue = await E(zoe).getInvitationDetails(invitation); - assert(invitationValue.installation === installations.coveredCall); - - // Bob can use whatever keywords he wants - const proposal = harden({ - give: { Whatever1: simoleans(4n) }, - want: { Whatever2: moola(3n) }, - exit: { onDemand: null }, - }); - await E(simoleanPurseP).deposit(simoleanPayment); - const simoleanPayment1 = await E(simoleanPurseP).withdraw(simoleans(4n)); - - const seat = await E(zoe).offer(invitation, proposal, { - Whatever1: simoleanPayment1, - }); - - log(await E(seat).getOfferResult()); - - const moolaPayout = await E(seat).getPayout('Whatever2'); - const simoleansPayout = await E(seat).getPayout('Whatever1'); - - log(await E(moolaIssuer).getAmountOf(moolaPayout)); - log(await E(simoleanIssuer).getAmountOf(simoleansPayout)); + const moolaPayout = await E(seat).getPayout('Whatever2'); + const simoleansPayout = await E(seat).getPayout('Whatever1'); + + log(await E(moolaIssuer).getAmountOf(moolaPayout)); + log(await E(simoleanIssuer).getAmountOf(simoleansPayout)); + }, }, - }); + ); }; export function buildRootObject() { - return Far('root', { - build: (...args) => build(makePrintLog(), ...args), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (...args) => build(makePrintLog(), ...args), + }, + ); } diff --git a/packages/swingset-runner/demo/zoeTests/vat-carol.js b/packages/swingset-runner/demo/zoeTests/vat-carol.js index aac126c06a2..4aac1432a2c 100644 --- a/packages/swingset-runner/demo/zoeTests/vat-carol.js +++ b/packages/swingset-runner/demo/zoeTests/vat-carol.js @@ -16,59 +16,69 @@ const build = async (log, zoe, issuers, payments, installations) => { let secondPriceAuctionSeatP; - return Far('build', { - doSecondPriceAuctionBid: async invitationP => { - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitationP, - ); - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - const { value: invitationValue } = - await E(invitationIssuer).getAmountOf(invitation); - installation === installations.secondPriceAuction || - Fail`wrong installation`; - keyEQ( - harden({ Asset: moolaIssuer, Ask: simoleanIssuer }), - issuerKeywordRecord, - ) || Fail`issuerKeywordRecord were not as expected`; - assert( - keyEQ(invitationValue[0].customDetails?.minimumBid, simoleans(3n)), - ); - assert( - keyEQ(invitationValue[0].customDetails?.auctionedAssets, moola(1n)), - ); + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + doSecondPriceAuctionBid: async invitationP => { + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitationP, + ); + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + const { value: invitationValue } = + await E(invitationIssuer).getAmountOf(invitation); + installation === installations.secondPriceAuction || + Fail`wrong installation`; + keyEQ( + harden({ Asset: moolaIssuer, Ask: simoleanIssuer }), + issuerKeywordRecord, + ) || Fail`issuerKeywordRecord were not as expected`; + assert( + keyEQ(invitationValue[0].customDetails?.minimumBid, simoleans(3n)), + ); + assert( + keyEQ(invitationValue[0].customDetails?.auctionedAssets, moola(1n)), + ); - const proposal = harden({ - want: { Asset: moola(1n) }, - give: { Bid: simoleans(7n) }, - exit: { onDemand: null }, - }); - const paymentKeywordRecord = { Bid: simoleanPayment }; + const proposal = harden({ + want: { Asset: moola(1n) }, + give: { Bid: simoleans(7n) }, + exit: { onDemand: null }, + }); + const paymentKeywordRecord = { Bid: simoleanPayment }; - secondPriceAuctionSeatP = await E(zoe).offer( - invitation, - proposal, - paymentKeywordRecord, - ); - log(`Carol: ${await E(secondPriceAuctionSeatP).getOfferResult()}`); - }, - doSecondPriceAuctionGetPayout: async () => { - const moolaPayout = await E(secondPriceAuctionSeatP).getPayout('Asset'); - const simoleanPayout = await E(secondPriceAuctionSeatP).getPayout('Bid'); + secondPriceAuctionSeatP = await E(zoe).offer( + invitation, + proposal, + paymentKeywordRecord, + ); + log(`Carol: ${await E(secondPriceAuctionSeatP).getOfferResult()}`); + }, + doSecondPriceAuctionGetPayout: async () => { + const moolaPayout = await E(secondPriceAuctionSeatP).getPayout('Asset'); + const simoleanPayout = await E(secondPriceAuctionSeatP).getPayout( + 'Bid', + ); - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); - await showPurseBalance(moolaPurseP, 'carolMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'carolSimoleanPurse', log); + await showPurseBalance(moolaPurseP, 'carolMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'carolSimoleanPurse', log); + }, }, - }); + ); }; export function buildRootObject() { - return Far('root', { - build: (...args) => build(makePrintLog(), ...args), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (...args) => build(makePrintLog(), ...args), + }, + ); } diff --git a/packages/swingset-runner/demo/zoeTests/vat-dave.js b/packages/swingset-runner/demo/zoeTests/vat-dave.js index f65526d7908..bb7ea6e75a7 100644 --- a/packages/swingset-runner/demo/zoeTests/vat-dave.js +++ b/packages/swingset-runner/demo/zoeTests/vat-dave.js @@ -17,157 +17,174 @@ const build = async (log, zoe, issuers, payments, installations, timer) => { let secondPriceAuctionSeatP; - return Far('build', { - doSecondPriceAuctionBid: async invitation => { - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - const { value: invitationValue } = - await E(invitationIssuer).getAmountOf(exclInvitation); - installation === installations.secondPriceAuction || - Fail`wrong installation`; - keyEQ( - harden({ Asset: moolaIssuer, Ask: simoleanIssuer }), - issuerKeywordRecord, - ) || Fail`issuerKeywordRecord were not as expected`; - assert( - keyEQ(invitationValue[0].customDetails?.minimumBid, simoleans(3n)), - ); - assert( - keyEQ(invitationValue[0].customDetails?.auctionedAssets, moola(1n)), - ); - - const proposal = harden({ - want: { Asset: moola(1n) }, - give: { Bid: simoleans(5n) }, - exit: { onDemand: null }, - }); - const paymentKeywordRecord = { Bid: simoleanPayment }; - - secondPriceAuctionSeatP = await E(zoe).offer( - exclInvitation, - proposal, - paymentKeywordRecord, - ); - log(`Dave: ${await E(secondPriceAuctionSeatP).getOfferResult()}`); - }, - doSecondPriceAuctionGetPayout: async () => { - const moolaPayout = await E(secondPriceAuctionSeatP).getPayout('Asset'); - const simoleanPayout = await E(secondPriceAuctionSeatP).getPayout('Bid'); - - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); - - await showPurseBalance(moolaPurseP, 'daveMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'daveSimoleanPurse', log); - }, - - doSwapForOption: async (invitation, optionAmounts) => { - // Dave is looking to buy the option to trade his 7 simoleans for - // 3 moola, and is willing to pay 1 buck for the option. - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - const { value: invitationValue } = - await E(invitationIssuer).getAmountOf(exclInvitation); - - // TODO Check the integrity of the installation by its hash. - // https://github.com/Agoric/agoric-sdk/issues/3859 - // const installation = await E(zoe).getInstallation(invitation); - // const hash = await E(installation).getHash(); - // assert.is(hash, 'XXX'); - - assert(installation === installations.atomicSwap, X`wrong installation`); - assert( + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + doSecondPriceAuctionBid: async invitation => { + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + const { value: invitationValue } = + await E(invitationIssuer).getAmountOf(exclInvitation); + installation === installations.secondPriceAuction || + Fail`wrong installation`; keyEQ( - harden({ Asset: invitationIssuer, Price: bucksIssuer }), + harden({ Asset: moolaIssuer, Ask: simoleanIssuer }), issuerKeywordRecord, - ), - X`issuerKeywordRecord were not as expected`, - ); - - const { customDetails: invitationCustomDetails } = invitationValue[0]; - assert(typeof invitationCustomDetails === 'object'); - const optionValue = optionAmounts.value; - const { customDetails: optionCustomDetails } = optionValue[0]; - assert(typeof optionCustomDetails === 'object'); - - // Dave expects that Bob has already made an offer in the swap - // with the following rules: - keyEQ(invitationCustomDetails.asset, optionAmounts) || - Fail`asset is the option`; - keyEQ(invitationCustomDetails.price, bucks(1n)) || Fail`price is 1 buck`; - - optionValue[0].description === 'exerciseOption' || Fail`wrong invitation`; - AmountMath.isEqual( - optionCustomDetails.underlyingAssets.UnderlyingAsset, - moola(3n), - ) || Fail`wrong underlying asset`; - AmountMath.isEqual( - optionCustomDetails.strikePrice.StrikePrice, - simoleans(7n), - ) || Fail`wrong strike price`; - optionCustomDetails.expirationDate === 100n || - Fail`wrong expiration date`; - optionCustomDetails.timeAuthority === timer || Fail`wrong timer`; - - // Dave escrows his 1 buck with Zoe and forms his proposal - const daveSwapProposal = harden({ - want: { Asset: optionAmounts }, - give: { Price: bucks(1n) }, - }); - const daveSwapPayments = harden({ Price: bucksPayment }); - const seatP = await E(zoe).offer( - exclInvitation, - daveSwapProposal, - daveSwapPayments, - ); - - log(await E(seatP).getOfferResult()); - - const daveOption = await E(seatP).getPayout('Asset'); - const daveBucksPayout = await E(seatP).getPayout('Price'); - - // Dave exercises his option by making an offer to the covered - // call. First, he escrows with Zoe. - - const daveCoveredCallProposal = harden({ - want: { UnderlyingAsset: moola(3n) }, - give: { StrikePrice: simoleans(7n) }, - }); - const daveCoveredCallPayments = harden({ StrikePrice: simoleanPayment }); - const optionSeatP = await E(zoe).offer( - daveOption, - daveCoveredCallProposal, - daveCoveredCallPayments, - ); - - log(await E(optionSeatP).getOfferResult()); - - const moolaPayout = await E(optionSeatP).getPayout('UnderlyingAsset'); - const simoleanPayout = await E(optionSeatP).getPayout('StrikePrice'); - - await E(bucksPurseP).deposit(daveBucksPayout); - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); - - await showPurseBalance(moolaPurseP, 'daveMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'daveSimoleanPurse', log); - await showPurseBalance(bucksPurseP, 'daveBucksPurse', log); + ) || Fail`issuerKeywordRecord were not as expected`; + assert( + keyEQ(invitationValue[0].customDetails?.minimumBid, simoleans(3n)), + ); + assert( + keyEQ(invitationValue[0].customDetails?.auctionedAssets, moola(1n)), + ); + + const proposal = harden({ + want: { Asset: moola(1n) }, + give: { Bid: simoleans(5n) }, + exit: { onDemand: null }, + }); + const paymentKeywordRecord = { Bid: simoleanPayment }; + + secondPriceAuctionSeatP = await E(zoe).offer( + exclInvitation, + proposal, + paymentKeywordRecord, + ); + log(`Dave: ${await E(secondPriceAuctionSeatP).getOfferResult()}`); + }, + doSecondPriceAuctionGetPayout: async () => { + const moolaPayout = await E(secondPriceAuctionSeatP).getPayout('Asset'); + const simoleanPayout = await E(secondPriceAuctionSeatP).getPayout( + 'Bid', + ); + + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'daveMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'daveSimoleanPurse', log); + }, + + doSwapForOption: async (invitation, optionAmounts) => { + // Dave is looking to buy the option to trade his 7 simoleans for + // 3 moola, and is willing to pay 1 buck for the option. + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + const { value: invitationValue } = + await E(invitationIssuer).getAmountOf(exclInvitation); + + // TODO Check the integrity of the installation by its hash. + // https://github.com/Agoric/agoric-sdk/issues/3859 + // const installation = await E(zoe).getInstallation(invitation); + // const hash = await E(installation).getHash(); + // assert.is(hash, 'XXX'); + + assert( + installation === installations.atomicSwap, + X`wrong installation`, + ); + assert( + keyEQ( + harden({ Asset: invitationIssuer, Price: bucksIssuer }), + issuerKeywordRecord, + ), + X`issuerKeywordRecord were not as expected`, + ); + + const { customDetails: invitationCustomDetails } = invitationValue[0]; + assert(typeof invitationCustomDetails === 'object'); + const optionValue = optionAmounts.value; + const { customDetails: optionCustomDetails } = optionValue[0]; + assert(typeof optionCustomDetails === 'object'); + + // Dave expects that Bob has already made an offer in the swap + // with the following rules: + keyEQ(invitationCustomDetails.asset, optionAmounts) || + Fail`asset is the option`; + keyEQ(invitationCustomDetails.price, bucks(1n)) || + Fail`price is 1 buck`; + + optionValue[0].description === 'exerciseOption' || + Fail`wrong invitation`; + AmountMath.isEqual( + optionCustomDetails.underlyingAssets.UnderlyingAsset, + moola(3n), + ) || Fail`wrong underlying asset`; + AmountMath.isEqual( + optionCustomDetails.strikePrice.StrikePrice, + simoleans(7n), + ) || Fail`wrong strike price`; + optionCustomDetails.expirationDate === 100n || + Fail`wrong expiration date`; + optionCustomDetails.timeAuthority === timer || Fail`wrong timer`; + + // Dave escrows his 1 buck with Zoe and forms his proposal + const daveSwapProposal = harden({ + want: { Asset: optionAmounts }, + give: { Price: bucks(1n) }, + }); + const daveSwapPayments = harden({ Price: bucksPayment }); + const seatP = await E(zoe).offer( + exclInvitation, + daveSwapProposal, + daveSwapPayments, + ); + + log(await E(seatP).getOfferResult()); + + const daveOption = await E(seatP).getPayout('Asset'); + const daveBucksPayout = await E(seatP).getPayout('Price'); + + // Dave exercises his option by making an offer to the covered + // call. First, he escrows with Zoe. + + const daveCoveredCallProposal = harden({ + want: { UnderlyingAsset: moola(3n) }, + give: { StrikePrice: simoleans(7n) }, + }); + const daveCoveredCallPayments = harden({ + StrikePrice: simoleanPayment, + }); + const optionSeatP = await E(zoe).offer( + daveOption, + daveCoveredCallProposal, + daveCoveredCallPayments, + ); + + log(await E(optionSeatP).getOfferResult()); + + const moolaPayout = await E(optionSeatP).getPayout('UnderlyingAsset'); + const simoleanPayout = await E(optionSeatP).getPayout('StrikePrice'); + + await E(bucksPurseP).deposit(daveBucksPayout); + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'daveMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'daveSimoleanPurse', log); + await showPurseBalance(bucksPurseP, 'daveBucksPurse', log); + }, }, - }); + ); }; export function buildRootObject() { - return Far('root', { - build: (...args) => build(makePrintLog(), ...args), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (...args) => build(makePrintLog(), ...args), + }, + ); } diff --git a/packages/swingset-runner/src/vat-benchmarkBootstrap.js b/packages/swingset-runner/src/vat-benchmarkBootstrap.js index 2439c293d18..3a09aa1c66c 100644 --- a/packages/swingset-runner/src/vat-benchmarkBootstrap.js +++ b/packages/swingset-runner/src/vat-benchmarkBootstrap.js @@ -14,25 +14,30 @@ import { Far } from '@endo/marshal'; export function buildRootObject(_vatPowers, vatParameters) { let benchmarkDriverVat; - return Far('root', { - async bootstrap(vatsExtended, devices) { - const { - benchmarkBootstrap: _benchmarkBootstrap, - benchmarkDriver, - ...vats - } = vatsExtended; - benchmarkDriverVat = benchmarkDriver; - const originalBootstrapVat = vatsExtended[vatParameters.config.bootstrap]; - harden(vats); - const bootstrapResult = await E(originalBootstrapVat).bootstrap( - vats, - devices, - ); - await E(benchmarkDriverVat).setup(vats, devices); - return bootstrapResult; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vatsExtended, devices) { + const { + benchmarkBootstrap: _benchmarkBootstrap, + benchmarkDriver, + ...vats + } = vatsExtended; + benchmarkDriverVat = benchmarkDriver; + const originalBootstrapVat = + vatsExtended[vatParameters.config.bootstrap]; + harden(vats); + const bootstrapResult = await E(originalBootstrapVat).bootstrap( + vats, + devices, + ); + await E(benchmarkDriverVat).setup(vats, devices); + return bootstrapResult; + }, + runBenchmarkRound() { + return E(benchmarkDriverVat).runBenchmarkRound(); + }, }, - runBenchmarkRound() { - return E(benchmarkDriverVat).runBenchmarkRound(); - }, - }); + ); } diff --git a/packages/swingset-runner/src/vat-launcher.js b/packages/swingset-runner/src/vat-launcher.js index de1d657067a..e9697a2885d 100644 --- a/packages/swingset-runner/src/vat-launcher.js +++ b/packages/swingset-runner/src/vat-launcher.js @@ -24,38 +24,44 @@ import { Far } from '@endo/marshal'; export function buildRootObject(_vatPowers, vatParameters) { let bootstrapRoot; - return Far('root', { - async bootstrap(vats, devices) { - const vatMaker = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - const criticalVatKey = await E(vats.vatAdmin).getCriticalVatKey(); - const vatRoots = {}; - for (const vatName of Object.keys(vatParameters.config.vats)) { - const vatDesc = vatParameters.config.vats[vatName]; - const bundleName = vatDesc.bundleName; - const subvatParameters = vatDesc.parameters - ? { ...vatDesc.parameters } - : {}; - if (vatParameters.config.bootstrap === vatName) { - subvatParameters.argv = vatParameters.argv; - } - let critical = vatDesc.critical; - if (critical) { - critical = criticalVatKey; - } - // prettier-ignore - const vat = await E(vatMaker).createVatByName( + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatMaker = E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + const criticalVatKey = await E(vats.vatAdmin).getCriticalVatKey(); + const vatRoots = {}; + for (const vatName of Object.keys(vatParameters.config.vats)) { + const vatDesc = vatParameters.config.vats[vatName]; + const bundleName = vatDesc.bundleName; + const subvatParameters = vatDesc.parameters + ? { ...vatDesc.parameters } + : {}; + if (vatParameters.config.bootstrap === vatName) { + subvatParameters.argv = vatParameters.argv; + } + let critical = vatDesc.critical; + if (critical) { + critical = criticalVatKey; + } + // prettier-ignore + const vat = await E(vatMaker).createVatByName( bundleName, { vatParameters: harden(subvatParameters), critical }, ); - vatRoots[vatName] = vat.root; - } - vatRoots.vatAdmin = vats.vatAdmin; - bootstrapRoot = vatRoots[vatParameters.config.bootstrap]; - // prettier-ignore - return E(bootstrapRoot).bootstrap(harden(vatRoots), devices); - }, - runBenchmarkRound() { - return E(bootstrapRoot).runBenchmarkRound(); + vatRoots[vatName] = vat.root; + } + vatRoots.vatAdmin = vats.vatAdmin; + bootstrapRoot = vatRoots[vatParameters.config.bootstrap]; + // prettier-ignore + return E(bootstrapRoot).bootstrap(harden(vatRoots), devices); + }, + runBenchmarkRound() { + return E(bootstrapRoot).runBenchmarkRound(); + }, }, - }); + ); } diff --git a/packages/vat-data/test/test-vow.js b/packages/vat-data/test/test-vow.js index e21e0d14ff2..316e4a115ec 100644 --- a/packages/vat-data/test/test-vow.js +++ b/packages/vat-data/test/test-vow.js @@ -5,9 +5,13 @@ import { E, Far } from '@endo/far'; import { V, makeVowKit } from '../vow.js'; test('heap messages', async t => { - const greeter = Far('Greeter', { - hello: /** @param {string} name */ name => `Hello, ${name}!`, - }); + const greeter = makeExo( + 'Greeter', + M.interface('Greeter', {}, { defaultGuards: 'passable' }), + { + hello: /** @param {string} name */ name => `Hello, ${name}!`, + }, + ); /** @type {ReturnType>} */ const { vow, resolver } = makeVowKit(); diff --git a/packages/vats/src/centralSupply.js b/packages/vats/src/centralSupply.js index ee0cc37366d..5b463d81bab 100644 --- a/packages/vats/src/centralSupply.js +++ b/packages/vats/src/centralSupply.js @@ -28,12 +28,16 @@ export const start = async (zcf, { feeMintAccess }) => { const bootstrapPayment = await E(userSeat).getPayout('Bootstrap'); return { - creatorFacet: Far('creator', { - getBootstrapPayment: () => { - zcf.shutdown('payment retrieved'); - return bootstrapPayment; + creatorFacet: makeExo( + 'creator', + M.interface('creator', {}, { defaultGuards: 'passable' }), + { + getBootstrapPayment: () => { + zcf.shutdown('payment retrieved'); + return bootstrapPayment; + }, }, - }), + ), }; }; harden(start); diff --git a/packages/vats/src/core/chain-behaviors.js b/packages/vats/src/core/chain-behaviors.js index 3d21d781fc3..d14a89d4584 100644 --- a/packages/vats/src/core/chain-behaviors.js +++ b/packages/vats/src/core/chain-behaviors.js @@ -53,49 +53,53 @@ export const bridgeCoreEval = async allPowers => { harden(evaluateBundleCap); // Register a coreEval handler over the bridge. - const handler = Far('coreHandler', { - async fromBridge(obj) { - switch (obj.type) { - case 'CORE_EVAL': { - /** @type {import('@agoric/cosmic-proto/dist/codegen/agoric/swingset/swingset.d.ts').CoreEvalProposalSDKType} */ - const { evals } = obj; - return Promise.all( - evals.map(({ json_permits: jsonPermit, js_code: code }) => - // Run in a new turn to avoid crosstalk of the evaluations. - Promise.resolve() - .then(() => { - const permit = JSON.parse(jsonPermit); - const powers = extractPowers(permit, { - evaluateBundleCap, - ...allPowers, - }); - - // Inspired by ../repl.js: - const globals = harden({ - ...allPowers.modules, - ...farExports, - ...endowments, - }); - - // Evaluate the code in the context of the globals. - const compartment = new Compartment(globals); - harden(compartment.globalThis); - const behavior = compartment.evaluate(code); - return behavior(powers); - }) - .catch(err => { - console.error('CORE_EVAL failed:', err); - throw err; - }), - ), - ).then(_ => {}); - } - default: { - throw Fail`Unrecognized request ${obj.type}`; + const handler = makeExo( + 'coreHandler', + M.interface('coreHandler', {}, { defaultGuards: 'passable' }), + { + async fromBridge(obj) { + switch (obj.type) { + case 'CORE_EVAL': { + /** @type {import('@agoric/cosmic-proto/dist/codegen/agoric/swingset/swingset.d.ts').CoreEvalProposalSDKType} */ + const { evals } = obj; + return Promise.all( + evals.map(({ json_permits: jsonPermit, js_code: code }) => + // Run in a new turn to avoid crosstalk of the evaluations. + Promise.resolve() + .then(() => { + const permit = JSON.parse(jsonPermit); + const powers = extractPowers(permit, { + evaluateBundleCap, + ...allPowers, + }); + + // Inspired by ../repl.js: + const globals = harden({ + ...allPowers.modules, + ...farExports, + ...endowments, + }); + + // Evaluate the code in the context of the globals. + const compartment = new Compartment(globals); + harden(compartment.globalThis); + const behavior = compartment.evaluate(code); + return behavior(powers); + }) + .catch(err => { + console.error('CORE_EVAL failed:', err); + throw err; + }), + ), + ).then(_ => {}); + } + default: { + throw Fail`Unrecognized request ${obj.type}`; + } } - } + }, }, - }); + ); coreEvalBridgeHandler.resolve(handler); const bridgeManager = await bridgeManagerP; @@ -149,39 +153,43 @@ export const bridgeProvisioner = async ({ // Register a provisioning handler over the bridge. const handler = provisioning - ? Far('provisioningHandler', { - async fromBridge(obj) { - switch (obj.type) { - case 'PLEASE_PROVISION': { - const { nickname, address, powerFlags: rawPowerFlags } = obj; - const powerFlags = rawPowerFlags || []; - let provisionP; - if (powerFlags.includes(PowerFlags.SMART_WALLET)) { - // Only provision a smart wallet. - provisionP = E(provisionWalletBridgeManager).fromBridge(obj); - } else { - // Provision a mailbox and REPL. - provisionP = E(provisioning).pleaseProvision( - nickname, - address, - powerFlags, - ); + ? makeExo( + 'provisioningHandler', + M.interface('provisioningHandler', {}, { defaultGuards: 'passable' }), + { + async fromBridge(obj) { + switch (obj.type) { + case 'PLEASE_PROVISION': { + const { nickname, address, powerFlags: rawPowerFlags } = obj; + const powerFlags = rawPowerFlags || []; + let provisionP; + if (powerFlags.includes(PowerFlags.SMART_WALLET)) { + // Only provision a smart wallet. + provisionP = E(provisionWalletBridgeManager).fromBridge(obj); + } else { + // Provision a mailbox and REPL. + provisionP = E(provisioning).pleaseProvision( + nickname, + address, + powerFlags, + ); + } + return provisionP + .catch(e => + console.error( + `Error provisioning ${nickname} ${address}:`, + e, + ), + ) + .then(_ => {}); + } + default: { + throw Fail`Unrecognized request ${obj.type}`; } - return provisionP - .catch(e => - console.error( - `Error provisioning ${nickname} ${address}:`, - e, - ), - ) - .then(_ => {}); - } - default: { - throw Fail`Unrecognized request ${obj.type}`; } - } + }, }, - }) + ) : provisionWalletBridgeManager; await E(provisionBridgeManager).initHandler(handler); }; @@ -217,67 +225,79 @@ export const setupClientManager = async ( const { subscription, publication } = makeSubscriptionKit(); /** @type {ClientManager} */ - const clientManager = Far('chainClientManager', { - assignBundle: newPropertyMakers => { - // Write the property makers to the cache, and update the subscription. - publication.updateState(newPropertyMakers); + const clientManager = makeExo( + 'chainClientManager', + M.interface('chainClientManager', {}, { defaultGuards: 'passable' }), + { + assignBundle: newPropertyMakers => { + // Write the property makers to the cache, and update the subscription. + publication.updateState(newPropertyMakers); + }, }, - }); + ); /** @type {ClientCreator} */ - const clientCreator = Far('clientCreator', { - createUserBundle: (nickname, clientAddress, powerFlags) => { - const c = E(clientCreator).createClientFacet( - nickname, - clientAddress, - powerFlags, - ); - return E(c).getChainBundle(); - }, - createClientFacet: async (_nickname, clientAddress, powerFlags) => { - /** @type {Record} */ - let clientHome = {}; - const bundleReady = makePromiseKit(); - - const makeUpdatedConfiguration = async (newPropertyMakers = []) => { - // Specialize the property makers with the client address. - const newProperties = callProperties( - newPropertyMakers, + const clientCreator = makeExo( + 'clientCreator', + M.interface('clientCreator', {}, { defaultGuards: 'passable' }), + { + createUserBundle: (nickname, clientAddress, powerFlags) => { + const c = E(clientCreator).createClientFacet( + nickname, clientAddress, powerFlags, ); - clientHome = { ...clientHome, ...newProperties }; + return E(c).getChainBundle(); + }, + createClientFacet: async (_nickname, clientAddress, powerFlags) => { + /** @type {Record} */ + let clientHome = {}; + const bundleReady = makePromiseKit(); + + const makeUpdatedConfiguration = async (newPropertyMakers = []) => { + // Specialize the property makers with the client address. + const newProperties = callProperties( + newPropertyMakers, + clientAddress, + powerFlags, + ); + clientHome = { ...clientHome, ...newProperties }; + + const todo = missingKeys(template, clientHome); + if (todo.length === 0) { + bundleReady.resolve(undefined); + } - const todo = missingKeys(template, clientHome); - if (todo.length === 0) { - bundleReady.resolve(undefined); - } + return harden({ clientAddress, clientHome }); + }; + + // Publish new configurations. + const newConfig = await makeUpdatedConfiguration([]); + const { notifier, updater } = makeNotifierKit(newConfig); + + /** @type {ClientFacet} */ + const clientFacet = makeExo( + 'chainProvisioner', + M.interface('chainProvisioner', {}, { defaultGuards: 'passable' }), + { + getChainBundle: () => + bundleReady.promise.then(_ => allValues(clientHome)), + getConfiguration: () => notifier, + }, + ); - return harden({ clientAddress, clientHome }); - }; - - // Publish new configurations. - const newConfig = await makeUpdatedConfiguration([]); - const { notifier, updater } = makeNotifierKit(newConfig); - - /** @type {ClientFacet} */ - const clientFacet = Far('chainProvisioner', { - getChainBundle: () => - bundleReady.promise.then(_ => allValues(clientHome)), - getConfiguration: () => notifier, - }); - - void observeIteration(subscription, { - updateState(newPropertyMakers) { - makeUpdatedConfiguration(newPropertyMakers) - .then(x => updater.updateState(x)) - .catch(reason => console.error(reason)); // TODO: catch and log OK? - }, - }); + void observeIteration(subscription, { + updateState(newPropertyMakers) { + makeUpdatedConfiguration(newPropertyMakers) + .then(x => updater.updateState(x)) + .catch(reason => console.error(reason)); // TODO: catch and log OK? + }, + }); - return clientFacet; + return clientFacet; + }, }, - }); + ); clientCreatorP.resolve(clientCreator); client.resolve(clientManager); @@ -486,7 +506,11 @@ export const publishAgoricNames = async ( * @param {BootstrapPowers} powers */ export const connectChainFaucet = async ({ consume: { client } }) => { - const faucet = Far('faucet', { tapFaucet: () => harden([]) }); + const faucet = makeExo( + 'faucet', + M.interface('faucet', {}, { defaultGuards: 'passable' }), + { tapFaucet: () => harden([]) }, + ); return E(client).assignBundle([_addr => ({ faucet })]); }; diff --git a/packages/vats/src/core/client-behaviors.js b/packages/vats/src/core/client-behaviors.js index 778ceb8a86a..46f4feaddf3 100644 --- a/packages/vats/src/core/client-behaviors.js +++ b/packages/vats/src/core/client-behaviors.js @@ -11,11 +11,15 @@ const PROVISIONER_INDEX = 1; function makeVattpFrom(vats) { const { vattp, comms } = vats; - return Far('vattp', { - makeNetworkHost(allegedName, console = undefined) { - return E(vattp).makeNetworkHost(allegedName, comms, console); + return makeExo( + 'vattp', + M.interface('vattp', {}, { defaultGuards: 'passable' }), + { + makeNetworkHost(allegedName, console = undefined) { + return E(vattp).makeNetworkHost(allegedName, comms, console); + }, }, - }); + ); } // objects that live in the client's solo vat. Some services should only @@ -44,30 +48,34 @@ async function createLocalBundle(vats, devices, vatAdminSvc, vatPowers) { } // This will allow dApp developers to register in their api/deploy.js - const httpRegCallback = Far('httpRegCallback', { - doneLoading(subsystems) { - return E(vats.http).doneLoading(subsystems); - }, - send(obj, connectionHandles) { - return E(vats.http).send(obj, connectionHandles); - }, - registerURLHandler(handler, path) { - return E(vats.http).registerURLHandler(handler, path); - }, - registerAPIHandler(handler) { - return E(vats.http).registerURLHandler(handler, '/api'); - }, - async registerWallet(wallet, privateWallet, privateWalletBridge) { - await Promise.all([ - E(vats.http).registerURLHandler(privateWallet, '/private/wallet'), - E(vats.http).registerURLHandler( - privateWalletBridge, - '/private/wallet-bridge', - ), - E(vats.http).setWallet(wallet), - ]); + const httpRegCallback = makeExo( + 'httpRegCallback', + M.interface('httpRegCallback', {}, { defaultGuards: 'passable' }), + { + doneLoading(subsystems) { + return E(vats.http).doneLoading(subsystems); + }, + send(obj, connectionHandles) { + return E(vats.http).send(obj, connectionHandles); + }, + registerURLHandler(handler, path) { + return E(vats.http).registerURLHandler(handler, path); + }, + registerAPIHandler(handler) { + return E(vats.http).registerURLHandler(handler, '/api'); + }, + async registerWallet(wallet, privateWallet, privateWalletBridge) { + await Promise.all([ + E(vats.http).registerURLHandler(privateWallet, '/private/wallet'), + E(vats.http).registerURLHandler( + privateWalletBridge, + '/private/wallet-bridge', + ), + E(vats.http).setWallet(wallet), + ]); + }, }, - }); + ); const bundleP = harden({ ...(plugin ? { plugin } : {}), diff --git a/packages/vats/src/core/demoIssuers.js b/packages/vats/src/core/demoIssuers.js index 24fe7c1addc..6f3b0c84c13 100644 --- a/packages/vats/src/core/demoIssuers.js +++ b/packages/vats/src/core/demoIssuers.js @@ -331,17 +331,21 @@ export const connectFaucet = async ({ const userFeePurse = await E(E(zoe).getFeeIssuer()).makeEmptyPurse(); - const faucet = Far('faucet', { - /** - * reap the spoils of our on-chain provisioning. - * - * @returns {Promise} - */ - tapFaucet: async () => faucetPaymentInfo, - getFeePurse() { - return userFeePurse; + const faucet = makeExo( + 'faucet', + M.interface('faucet', {}, { defaultGuards: 'passable' }), + { + /** + * reap the spoils of our on-chain provisioning. + * + * @returns {Promise} + */ + tapFaucet: async () => faucetPaymentInfo, + getFeePurse() { + return userFeePurse; + }, }, - }); + ); return faucet; }; diff --git a/packages/vats/src/core/lib-boot.js b/packages/vats/src/core/lib-boot.js index fcd7fe25381..172f16b50a5 100644 --- a/packages/vats/src/core/lib-boot.js +++ b/packages/vats/src/core/lib-boot.js @@ -168,53 +168,57 @@ export const makeBootstrap = ( // For testing supports const vatData = new Map(); - return Far('bootstrap', { - /** - * Bootstrap vats and devices. - * - * @param {SwingsetVats} vats - * @param {SoloDevices | ChainDevices} devices - */ - bootstrap: (vats, devices) => { - for (const [name, root] of Object.entries(vats)) { - if (name !== 'vatAdmin') { - vatData.set(name, { root }); + return makeExo( + 'bootstrap', + M.interface('bootstrap', {}, { defaultGuards: 'passable' }), + { + /** + * Bootstrap vats and devices. + * + * @param {SwingsetVats} vats + * @param {SoloDevices | ChainDevices} devices + */ + bootstrap: (vats, devices) => { + for (const [name, root] of Object.entries(vats)) { + if (name !== 'vatAdmin') { + vatData.set(name, { root }); + } } - } - return rawBootstrap(vats, devices).catch(e => { - // Terminate because the vat is in an irrecoverable state. - vatPowers.exitVatWithFailure(e); - // Throw the error to reject this promise but it will be unhandled because rawBoostrap() isn't returned. - throw e; - }); - }, - consumeItem: name => { - assert.typeof(name, 'string'); - return consume[name]; - }, - produceItem: (name, resolution) => { - assert.typeof(name, 'string'); - produce[name].resolve(resolution); - }, - resetItem: name => { - assert.typeof(name, 'string'); - produce[name].reset(); - }, - - //#region testing supports - awaitVatObject: async (presence, path = []) => { - let value = await presence; - for (const key of path) { - value = await value[key]; - } - return value; + return rawBootstrap(vats, devices).catch(e => { + // Terminate because the vat is in an irrecoverable state. + vatPowers.exitVatWithFailure(e); + // Throw the error to reject this promise but it will be unhandled because rawBoostrap() isn't returned. + throw e; + }); + }, + consumeItem: name => { + assert.typeof(name, 'string'); + return consume[name]; + }, + produceItem: (name, resolution) => { + assert.typeof(name, 'string'); + produce[name].resolve(resolution); + }, + resetItem: name => { + assert.typeof(name, 'string'); + produce[name].reset(); + }, + + //#region testing supports + awaitVatObject: async (presence, path = []) => { + let value = await presence; + for (const key of path) { + value = await value[key]; + } + return value; + }, + /** + * @template K, V + * @param {MapStore} store + */ + snapshotStore: store => harden([...store.entries()]), + //#endregion }, - /** - * @template K, V - * @param {MapStore} store - */ - snapshotStore: store => harden([...store.entries()]), - //#endregion - }); + ); }; /** @typedef {Awaited>} BootstrapRootObject */ diff --git a/packages/vats/src/core/sim-behaviors.js b/packages/vats/src/core/sim-behaviors.js index fd8a1a61d24..d5a8e24bb20 100644 --- a/packages/vats/src/core/sim-behaviors.js +++ b/packages/vats/src/core/sim-behaviors.js @@ -33,7 +33,11 @@ export const grantRunBehaviors = async ({ consume: { client }, }) => { const bundle = { - behaviors: Far('behaviors', { run: manifest => runBehaviors(manifest) }), + behaviors: makeExo( + 'behaviors', + M.interface('behaviors', {}, { defaultGuards: 'passable' }), + { run: manifest => runBehaviors(manifest) }, + ), }; return E(client).assignBundle([_addr => bundle]); }; diff --git a/packages/vats/src/core/startWalletFactory.js b/packages/vats/src/core/startWalletFactory.js index 9b04c34227d..26d18201785 100644 --- a/packages/vats/src/core/startWalletFactory.js +++ b/packages/vats/src/core/startWalletFactory.js @@ -245,15 +245,19 @@ export const startWalletFactory = async ( // TODO: move to its own producer, omitted in some configurations client.resolve( - Far('dummy client', { - assignBundle: (propertyMakers = []) => { - console.warn( - 'dummy mailbox client home: ignoring', - propertyMakers.length, - 'propertyMakers', - ); + makeExo( + 'dummy client', + M.interface('dummy client', {}, { defaultGuards: 'passable' }), + { + assignBundle: (propertyMakers = []) => { + console.warn( + 'dummy mailbox client home: ignoring', + propertyMakers.length, + 'propertyMakers', + ); + }, }, - }), + ), ); }; diff --git a/packages/vats/src/core/utils.js b/packages/vats/src/core/utils.js index 2f31632da48..7b3fb8b42e7 100644 --- a/packages/vats/src/core/utils.js +++ b/packages/vats/src/core/utils.js @@ -300,10 +300,14 @@ export const makeMyAddressNameAdminKit = address => { const { nameHub, nameAdmin: rawMyAddressNameAdmin } = makeNameHubKit(); /** @type {import('../types.js').MyAddressNameAdmin} */ - const myAddressNameAdmin = Far('myAddressNameAdmin', { - ...rawMyAddressNameAdmin, - getMyAddress: () => address, - }); + const myAddressNameAdmin = makeExo( + 'myAddressNameAdmin', + M.interface('myAddressNameAdmin', {}, { defaultGuards: 'passable' }), + { + ...rawMyAddressNameAdmin, + getMyAddress: () => address, + }, + ); // reserve space for deposit facet // XXX deprecated utility used only in solo void myAddressNameAdmin.reserve(WalletName.depositFacet); diff --git a/packages/vats/src/lib-board.js b/packages/vats/src/lib-board.js index c9d758ad437..1dccd548935 100644 --- a/packages/vats/src/lib-board.js +++ b/packages/vats/src/lib-board.js @@ -195,7 +195,7 @@ const makeSlotToVal = state => { if (typeof iface === 'string' && iface.startsWith(ifaceAllegedPrefix)) { iface = iface.slice(ifaceAllegedPrefix.length); } - return Far(`${ifaceInaccessiblePrefix}${iface}`, {}); + return makeExo(`${ifaceInaccessiblePrefix}${iface}`, M.interface(`${ifaceInaccessiblePrefix}${iface}`, {}, { defaultGuards: 'passable' }), {}); }; return slotToVal; }; diff --git a/packages/vats/src/priceAuthorityRegistry.js b/packages/vats/src/priceAuthorityRegistry.js index 85b8570f73d..99c7690ea5d 100644 --- a/packages/vats/src/priceAuthorityRegistry.js +++ b/packages/vats/src/priceAuthorityRegistry.js @@ -196,14 +196,19 @@ export const providePriceAuthorityRegistry = baggage => { priceStore.init(brandOut, harden(record)); } - return Far('deleter', { - // @ts-expect-error XXX callWhen - delete() { - (priceStore.has(brandOut) && priceStore.get(brandOut) === record) || - Fail`Price authority already dropped`; - priceStore.delete(brandOut); + return makeExo( + 'deleter', + M.interface('deleter', {}, { defaultGuards: 'passable' }), + { + // @ts-expect-error XXX callWhen + delete() { + (priceStore.has(brandOut) && + priceStore.get(brandOut) === record) || + Fail`Price authority already dropped`; + priceStore.delete(brandOut); + }, }, - }); + ); }, }, ); diff --git a/packages/vats/src/repl.js b/packages/vats/src/repl.js index 2b69100c355..8c02f615ca2 100644 --- a/packages/vats/src/repl.js +++ b/packages/vats/src/repl.js @@ -268,25 +268,33 @@ export function getReplHandler(replObjects, send) { }, }; - const commandHandler = Far('commandHandler', { - onOpen(_obj, meta) { - replHandles.add(meta.channelHandle); - }, - onClose(_obj, meta) { - replHandles.delete(meta.channelHandle); - }, + const commandHandler = makeExo( + 'commandHandler', + M.interface('commandHandler', {}, { defaultGuards: 'passable' }), + { + onOpen(_obj, meta) { + replHandles.add(meta.channelHandle); + }, + onClose(_obj, meta) { + replHandles.delete(meta.channelHandle); + }, - onMessage(obj, meta) { - if (!handler[obj.type]) { - return false; - } - return handler[obj.type](obj, meta); + onMessage(obj, meta) { + if (!handler[obj.type]) { + return false; + } + return handler[obj.type](obj, meta); + }, }, - }); - - return Far('replHandler', { - getCommandHandler() { - return commandHandler; + ); + + return makeExo( + 'replHandler', + M.interface('replHandler', {}, { defaultGuards: 'passable' }), + { + getCommandHandler() { + return commandHandler; + }, }, - }); + ); } diff --git a/packages/vats/src/vat-agoricNames.js b/packages/vats/src/vat-agoricNames.js index 601e616ee08..c863b2eb0c4 100644 --- a/packages/vats/src/vat-agoricNames.js +++ b/packages/vats/src/vat-agoricNames.js @@ -68,19 +68,23 @@ export const buildRootObject = (_vatPowers, _vatParameters, baggage) => { ); }; - return Far('vat-agoricNames', { - getNameHub: () => agoricNames, - getNameHubKit: () => kit, - publishNameHubs, - /** - * Provide a brand, with no associated mint nor issuer. - * - * @param {string} keyword - * @param {DisplayInfo} displayInfo - */ - provideInertBrand: (keyword, displayInfo) => - provideLazy(brandStore, keyword, () => - makeNatBrand(keyword, displayInfo), - ), - }); + return makeExo( + 'vat-agoricNames', + M.interface('vat-agoricNames', {}, { defaultGuards: 'passable' }), + { + getNameHub: () => agoricNames, + getNameHubKit: () => kit, + publishNameHubs, + /** + * Provide a brand, with no associated mint nor issuer. + * + * @param {string} keyword + * @param {DisplayInfo} displayInfo + */ + provideInertBrand: (keyword, displayInfo) => + provideLazy(brandStore, keyword, () => + makeNatBrand(keyword, displayInfo), + ), + }, + ); }; diff --git a/packages/vats/src/vat-bank.js b/packages/vats/src/vat-bank.js index 7263c9a8687..a68a7edb4bd 100644 --- a/packages/vats/src/vat-bank.js +++ b/packages/vats/src/vat-bank.js @@ -256,10 +256,14 @@ const makeSubscriberFromAsyncIterable = ( prior = value; } })(); - return Far('HeapSubscriber', { - ...subscriber, - ...subscribeEach(subscriber), - }); + return makeExo( + 'HeapSubscriber', + M.interface('HeapSubscriber', {}, { defaultGuards: 'passable' }), + { + ...subscriber, + ...subscribeEach(subscriber), + }, + ); }; /** @@ -847,51 +851,55 @@ export function buildRootObject(_vatPowers, _args, baggage) { makeBridgeChannelAttenuator, } = prepareFromBaggage(baggage); - return Far('bankMaker', { - /** - * @param {ERef} [bankBridgeManagerP] - * a bridge manager for the "remote" bank (such as on cosmos-sdk). If not - * supplied (such as on sim-chain), we just use local purses. - * @param {ERef<{ update: import('./types.js').NameAdmin['update'] }>} [nameAdminP] - * update facet of a NameAdmin; see addAsset() for detail. - */ - async makeBankManager( - bankBridgeManagerP = undefined, - nameAdminP = undefined, - ) { - const bankBridgeManager = await bankBridgeManagerP; - - /** @type {MapStore>} */ - const denomToAddressUpdater = detachedZone.mapStore( - 'denomToAddressUpdater', - ); + return makeExo( + 'bankMaker', + M.interface('bankMaker', {}, { defaultGuards: 'passable' }), + { + /** + * @param {ERef} [bankBridgeManagerP] + * a bridge manager for the "remote" bank (such as on cosmos-sdk). If not + * supplied (such as on sim-chain), we just use local purses. + * @param {ERef<{ update: import('./types.js').NameAdmin['update'] }>} [nameAdminP] + * update facet of a NameAdmin; see addAsset() for detail. + */ + async makeBankManager( + bankBridgeManagerP = undefined, + nameAdminP = undefined, + ) { + const bankBridgeManager = await bankBridgeManagerP; + + /** @type {MapStore>} */ + const denomToAddressUpdater = detachedZone.mapStore( + 'denomToAddressUpdater', + ); - /** @param {ERef} [bankBridgeMgr] */ - async function getBankChannel(bankBridgeMgr) { - // We do the logic here if the bridge manager is available. Otherwise, - // the bank is not "remote" (such as on sim-chain), so we just use - // immediate purses instead of virtual ones. - if (!bankBridgeMgr) { - return undefined; - } + /** @param {ERef} [bankBridgeMgr] */ + async function getBankChannel(bankBridgeMgr) { + // We do the logic here if the bridge manager is available. Otherwise, + // the bank is not "remote" (such as on sim-chain), so we just use + // immediate purses instead of virtual ones. + if (!bankBridgeMgr) { + return undefined; + } - // We need to synchronise with the remote bank. - const handler = makeBankChannelHandler(denomToAddressUpdater); - await E(bankBridgeMgr).initHandler(handler); + // We need to synchronise with the remote bank. + const handler = makeBankChannelHandler(denomToAddressUpdater); + await E(bankBridgeMgr).initHandler(handler); - // We can only downcall to the bank if there exists a bridge manager. - return makeBridgeChannelAttenuator({ target: bankBridgeMgr }); - } + // We can only downcall to the bank if there exists a bridge manager. + return makeBridgeChannelAttenuator({ target: bankBridgeMgr }); + } - const [bankChannel, nameAdmin] = await Promise.all([ - getBankChannel(bankBridgeManager), - nameAdminP, - ]); - return makeBankManager({ - bankChannel, - denomToAddressUpdater, - nameAdmin, - }); + const [bankChannel, nameAdmin] = await Promise.all([ + getBankChannel(bankBridgeManager), + nameAdminP, + ]); + return makeBankManager({ + bankChannel, + denomToAddressUpdater, + nameAdmin, + }); + }, }, - }); + ); } diff --git a/packages/vats/src/vat-board.js b/packages/vats/src/vat-board.js index 3c8096565d4..0708f604400 100644 --- a/packages/vats/src/vat-board.js +++ b/packages/vats/src/vat-board.js @@ -31,9 +31,13 @@ export function buildRootObject(_vatPowers, _vatParameters, baggage) { board.getReadonlyMarshaller(), ); - return Far('vat-board', { - getBoard: () => board, - makePublishingRecorderKit, - makeReadOnlyRecorderKit, - }); + return makeExo( + 'vat-board', + M.interface('vat-board', {}, { defaultGuards: 'passable' }), + { + getBoard: () => board, + makePublishingRecorderKit, + makeReadOnlyRecorderKit, + }, + ); } diff --git a/packages/vats/src/vat-bridge.js b/packages/vats/src/vat-bridge.js index 1a5c00b3966..81e2d84d663 100644 --- a/packages/vats/src/vat-bridge.js +++ b/packages/vats/src/vat-bridge.js @@ -43,8 +43,12 @@ export function buildRootObject(vatPowers, _args, baggage) { // We colocate these functions in this vat so that we don't pay extra cranks // to shuffle messages between a chainStorage node and the bridgeManager. - return Far('root', { - makeBridgedChainStorageRoot, - provideManagerForBridge, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + makeBridgedChainStorageRoot, + provideManagerForBridge, + }, + ); } diff --git a/packages/vats/src/vat-ibc.js b/packages/vats/src/vat-ibc.js index 08e9b0f6088..421e64ef344 100644 --- a/packages/vats/src/vat-ibc.js +++ b/packages/vats/src/vat-ibc.js @@ -18,8 +18,12 @@ export function buildRootObject(_vatPowers, _args, baggage) { return harden(ibcHandler); } - return Far('root', { - createHandlers, - makeCallbacks, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + createHandlers, + makeCallbacks, + }, + ); } diff --git a/packages/vats/src/vat-localchain.js b/packages/vats/src/vat-localchain.js index ded39990172..71a0505fe4a 100644 --- a/packages/vats/src/vat-localchain.js +++ b/packages/vats/src/vat-localchain.js @@ -8,17 +8,21 @@ export const buildRootObject = (_vatPowers, _args, baggage) => { const zone = makeDurableZone(baggage); const { makeLocalChain } = prepareLocalChainTools(zone.subZone('localchain')); - return Far('LocalChainVat', { - /** - * Create a local chain that allows permissionlessly making fresh local - * chain accounts, then using them to send chain queries and transactions. - * - * @param {import('./types').ScopedBridgeManager} system - */ - makeLocalChain(system) { - return makeLocalChain(system); + return makeExo( + 'LocalChainVat', + M.interface('LocalChainVat', {}, { defaultGuards: 'passable' }), + { + /** + * Create a local chain that allows permissionlessly making fresh local + * chain accounts, then using them to send chain queries and transactions. + * + * @param {import('./types').ScopedBridgeManager} system + */ + makeLocalChain(system) { + return makeLocalChain(system); + }, }, - }); + ); }; /** @typedef {ReturnType} LocalChainVat */ diff --git a/packages/vats/src/vat-mints.js b/packages/vats/src/vat-mints.js index 7e03cb1ed80..1dc15c32260 100644 --- a/packages/vats/src/vat-mints.js +++ b/packages/vats/src/vat-mints.js @@ -11,79 +11,83 @@ export function buildRootObject() { /** @type {MapStore} */ const mintsAndBrands = makeScalarMapStore('issuerName'); - const api = Far('api', { - getAllIssuerNames: () => [...mintsAndBrands.keys()], - getIssuer: issuerName => { - const { mint } = mintsAndBrands.get(issuerName); - return mint.getIssuer(); - }, - /** @param {string[]} issuerNames */ - getIssuers: issuerNames => issuerNames.map(api.getIssuer), + const api = makeExo( + 'api', + M.interface('api', {}, { defaultGuards: 'passable' }), + { + getAllIssuerNames: () => [...mintsAndBrands.keys()], + getIssuer: issuerName => { + const { mint } = mintsAndBrands.get(issuerName); + return mint.getIssuer(); + }, + /** @param {string[]} issuerNames */ + getIssuers: issuerNames => issuerNames.map(api.getIssuer), - /** - * WARNING: a mint is ability to mint new digital assets, a very powerful - * authority that is usually closely held. But this mint is for demo / - * faucet purposes. - * - * @param {string} name - */ - getMint: name => { - notForProductionUse(); - return mintsAndBrands.get(name).mint; - }, - /** @param {string[]} issuerNames */ - getMints: issuerNames => issuerNames.map(api.getMint), - /** - * @param {any} issuerNameSingular For example, 'moola', or 'simolean' - * @param {[AssetKind?, DisplayInfo?]} issuerArgs - */ - makeMintAndIssuer: (issuerNameSingular, ...issuerArgs) => { - notForProductionUse(); - // makeIssuerKit fails upgrade, this contract is for demo only - const { mint, issuer, brand } = makeIssuerKit( - issuerNameSingular, - ...issuerArgs, - ); - mintsAndBrands.init(issuerNameSingular, { mint, brand }); - return issuer; - }, - provideIssuerKit: (issuerName, ...issuerArgs) => { - notForProductionUse(); - if (mintsAndBrands.has(issuerName)) { - const { mint, brand } = mintsAndBrands.get(issuerName); - const issuer = mint.getIssuer(); - return { mint, issuer, brand }; - } else { + /** + * WARNING: a mint is ability to mint new digital assets, a very powerful + * authority that is usually closely held. But this mint is for demo / + * faucet purposes. + * + * @param {string} name + */ + getMint: name => { + notForProductionUse(); + return mintsAndBrands.get(name).mint; + }, + /** @param {string[]} issuerNames */ + getMints: issuerNames => issuerNames.map(api.getMint), + /** + * @param {any} issuerNameSingular For example, 'moola', or 'simolean' + * @param {[AssetKind?, DisplayInfo?]} issuerArgs + */ + makeMintAndIssuer: (issuerNameSingular, ...issuerArgs) => { + notForProductionUse(); // makeIssuerKit fails upgrade, this contract is for demo only const { mint, issuer, brand } = makeIssuerKit( - issuerName, + issuerNameSingular, ...issuerArgs, ); - mintsAndBrands.init(issuerName, { mint, brand }); - return { mint, issuer, brand }; - } - }, - /** - * @param {string} issuerName - * @param {bigint} value - */ - mintInitialPayment: (issuerName, value) => { - if (!mintsAndBrands.has(issuerName)) { - return undefined; - } - const { mint, brand } = mintsAndBrands.get(issuerName); - const amount = AmountMath.make(brand, value); - return mint.mintPayment(amount); + mintsAndBrands.init(issuerNameSingular, { mint, brand }); + return issuer; + }, + provideIssuerKit: (issuerName, ...issuerArgs) => { + notForProductionUse(); + if (mintsAndBrands.has(issuerName)) { + const { mint, brand } = mintsAndBrands.get(issuerName); + const issuer = mint.getIssuer(); + return { mint, issuer, brand }; + } else { + // makeIssuerKit fails upgrade, this contract is for demo only + const { mint, issuer, brand } = makeIssuerKit( + issuerName, + ...issuerArgs, + ); + mintsAndBrands.init(issuerName, { mint, brand }); + return { mint, issuer, brand }; + } + }, + /** + * @param {string} issuerName + * @param {bigint} value + */ + mintInitialPayment: (issuerName, value) => { + if (!mintsAndBrands.has(issuerName)) { + return undefined; + } + const { mint, brand } = mintsAndBrands.get(issuerName); + const amount = AmountMath.make(brand, value); + return mint.mintPayment(amount); + }, + /** + * @param {string[]} issuerNames + * @param {bigint[]} values + */ + mintInitialPayments: (issuerNames, values) => + issuerNames.map((issuerName, i) => + api.mintInitialPayment(issuerName, values[i]), + ), }, - /** - * @param {string[]} issuerNames - * @param {bigint[]} values - */ - mintInitialPayments: (issuerNames, values) => - issuerNames.map((issuerName, i) => - api.mintInitialPayment(issuerName, values[i]), - ), - }); + ); return api; } diff --git a/packages/vats/src/vat-network.js b/packages/vats/src/vat-network.js index f1784069f0d..7b7d9d9df19 100644 --- a/packages/vats/src/vat-network.js +++ b/packages/vats/src/vat-network.js @@ -26,16 +26,20 @@ export function buildRootObject(_vatPowers, _args, baggage) { ); const makeEchoConnectionKit = prepareEchoConnectionKit(zone); - return Far('RouterProtocol', { - makeLoopbackProtocolHandler, - makeEchoConnectionKit, - /** @param {Parameters} args */ - registerProtocolHandler: (...args) => - protocol.registerProtocolHandler(...args), - /** @param {Parameters} args */ - unregisterProtocolHandler: (...args) => - protocol.unregisterProtocolHandler(...args), - /** @param {Parameters} args */ - bind: (...args) => protocol.bind(...args), - }); + return makeExo( + 'RouterProtocol', + M.interface('RouterProtocol', {}, { defaultGuards: 'passable' }), + { + makeLoopbackProtocolHandler, + makeEchoConnectionKit, + /** @param {Parameters} args */ + registerProtocolHandler: (...args) => + protocol.registerProtocolHandler(...args), + /** @param {Parameters} args */ + unregisterProtocolHandler: (...args) => + protocol.unregisterProtocolHandler(...args), + /** @param {Parameters} args */ + bind: (...args) => protocol.bind(...args), + }, + ); } diff --git a/packages/vats/src/vat-priceAuthority.js b/packages/vats/src/vat-priceAuthority.js index 86cc49eb790..ab85bc3eff7 100644 --- a/packages/vats/src/vat-priceAuthority.js +++ b/packages/vats/src/vat-priceAuthority.js @@ -11,5 +11,9 @@ import { providePriceAuthorityRegistry } from './priceAuthorityRegistry.js'; */ export function buildRootObject(_vatPowers, _vatParams, baggage) { const registry = providePriceAuthorityRegistry(baggage); - return Far('root', { getRegistry: () => registry }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { getRegistry: () => registry }, + ); } diff --git a/packages/vats/src/vat-provisioning.js b/packages/vats/src/vat-provisioning.js index 1d50321f4d6..15092876d61 100644 --- a/packages/vats/src/vat-provisioning.js +++ b/packages/vats/src/vat-provisioning.js @@ -120,16 +120,20 @@ export function buildRootObject(_vatPowers, _vatParameters, baggage) { async function pleaseProvision(nickname, address, powerFlags) { /** @type {ERef} */ let clientFacet; - const fetch = Far('fetch', { - async getChainBundle() { - console.warn('getting chain bundle'); - return E(clientFacet).getChainBundle(); + const fetch = makeExo( + 'fetch', + M.interface('fetch', {}, { defaultGuards: 'passable' }), + { + async getChainBundle() { + console.warn('getting chain bundle'); + return E(clientFacet).getChainBundle(); + }, + getConfiguration() { + console.warn('getting configuration'); + return E(clientFacet).getConfiguration(); + }, }, - getConfiguration() { - console.warn('getting configuration'); - return E(clientFacet).getConfiguration(); - }, - }); + ); // Add a remote and egress for the pubkey. const { transmitter, setReceiver } = await E(vattp).addRemote(address); @@ -155,19 +159,27 @@ export function buildRootObject(_vatPowers, _vatParameters, baggage) { void E.when(chainBundle, clientHome => { updater.updateState(harden({ clientHome, clientAddress: address })); }); - return Far('emulatedClientFacet', { - getChainBundle: () => chainBundle, - getConfiguration: () => notifier, - }); + return makeExo( + 'emulatedClientFacet', + M.interface('emulatedClientFacet', {}, { defaultGuards: 'passable' }), + { + getChainBundle: () => chainBundle, + getConfiguration: () => notifier, + }, + ); }); return { ingressIndex: INDEX }; } - return Far('root', { - register, - pleaseProvision, - getNamesByAddressKit: () => - harden({ namesByAddress: nameHubKit.nameHub, namesByAddressAdmin }), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + register, + pleaseProvision, + getNamesByAddressKit: () => + harden({ namesByAddress: nameHubKit.nameHub, namesByAddressAdmin }), + }, + ); } diff --git a/packages/vats/src/vat-zoe.js b/packages/vats/src/vat-zoe.js index 6ee24cc21c0..fdc375b32c9 100644 --- a/packages/vats/src/vat-zoe.js +++ b/packages/vats/src/vat-zoe.js @@ -22,33 +22,37 @@ export function buildRootObject(vatPowers, _vatParams, zoeBaggage) { })); } - return Far('root', { - buildZoe: async (adminVat, feeIssuerConfig, zcfBundleName) => { - assert(zcfBundleName, `vat-zoe requires zcfBundleName`); - - const vatAdminSvc = await adminVat; - - /** @type {ZCFSpec} */ - const zcfSpec = { name: zcfBundleName }; - - zoeBaggage.init( - BUILD_PARAMS_KEY, - harden({ vatAdminSvc, feeIssuerConfig, zcfSpec }), - ); - - const { zoeService, feeMintAccess } = makeDurableZoeKit({ - vatAdminSvc, - shutdownZoeVat, - feeIssuerConfig, - zcfSpec, - zoeBaggage, - }); - - return harden({ - zoeService, - feeMintAccess, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + buildZoe: async (adminVat, feeIssuerConfig, zcfBundleName) => { + assert(zcfBundleName, `vat-zoe requires zcfBundleName`); + + const vatAdminSvc = await adminVat; + + /** @type {ZCFSpec} */ + const zcfSpec = { name: zcfBundleName }; + + zoeBaggage.init( + BUILD_PARAMS_KEY, + harden({ vatAdminSvc, feeIssuerConfig, zcfSpec }), + ); + + const { zoeService, feeMintAccess } = makeDurableZoeKit({ + vatAdminSvc, + shutdownZoeVat, + feeIssuerConfig, + zcfSpec, + zoeBaggage, + }); + + return harden({ + zoeService, + feeMintAccess, + }); + }, + getZoeConfigFacet: () => zoeConfigFacet, }, - getZoeConfigFacet: () => zoeConfigFacet, - }); + ); } diff --git a/packages/vats/test/test-board-utils.js b/packages/vats/test/test-board-utils.js index 71503212b43..121cf0907ae 100644 --- a/packages/vats/test/test-board-utils.js +++ b/packages/vats/test/test-board-utils.js @@ -187,17 +187,32 @@ test( }, ); -test('board ids', toCapData, Far('iface', { getBoardId: () => 'board123' }), { - body: '#"$0.Alleged: iface"', - slots: ['board123'], -}); +test( + 'board ids', + toCapData, + makeExo('iface', M.interface('iface', {}, { defaultGuards: 'passable' }), { + getBoardId: () => 'board123', + }), + { + body: '#"$0.Alleged: iface"', + slots: ['board123'], + }, +); test( 'nested board ids', toCapData, { - istBrand: Far('iface', { getBoardId: () => 'board123Ist' }), - atomBrand: Far('iface', { getBoardId: () => 'board123Atom' }), + istBrand: makeExo( + 'iface', + M.interface('iface', {}, { defaultGuards: 'passable' }), + { getBoardId: () => 'board123Ist' }, + ), + atomBrand: makeExo( + 'iface', + M.interface('iface', {}, { defaultGuards: 'passable' }), + { getBoardId: () => 'board123Atom' }, + ), }, { body: '#{"atomBrand":"$0.Alleged: iface","istBrand":"$1.Alleged: iface"}', diff --git a/packages/vats/test/test-clientBundle.js b/packages/vats/test/test-clientBundle.js index fcc066c55c1..e62e247a7f1 100644 --- a/packages/vats/test/test-clientBundle.js +++ b/packages/vats/test/test-clientBundle.js @@ -79,22 +79,30 @@ test('connectFaucet produces payments', async t => { produce.bankManager.resolve( Promise.resolve( // @ts-expect-error never mind other methods - Far('mockBankManager', { - getBankForAddress: _a => - Far('mockBank', { - // @ts-expect-error never mind other methods - getPurse: brand => ({ - deposit: async (pmt, _x) => { - const isBLD = brand === bldKit.brand; - const issuer = isBLD ? bldKit.issuer : stableIssuer; - const amt = await E(issuer).getAmountOf(pmt); - t.is(showAmount(amt), isBLD ? '5_000 BLD' : '53 IST'); - return amt; + makeExo( + 'mockBankManager', + M.interface('mockBankManager', {}, { defaultGuards: 'passable' }), + { + getBankForAddress: _a => + makeExo( + 'mockBank', + M.interface('mockBank', {}, { defaultGuards: 'passable' }), + { + // @ts-expect-error never mind other methods + getPurse: brand => ({ + deposit: async (pmt, _x) => { + const isBLD = brand === bldKit.brand; + const issuer = isBLD ? bldKit.issuer : stableIssuer; + const amt = await E(issuer).getAmountOf(pmt); + t.is(showAmount(amt), isBLD ? '5_000 BLD' : '53 IST'); + return amt; + }, + }), + getAssetSubscription: () => null, }, - }), - getAssetSubscription: () => null, - }), - }), + ), + }, + ), ), ); diff --git a/packages/vats/test/test-lib-board.js b/packages/vats/test/test-lib-board.js index e9ec6d264c3..10ff855d500 100644 --- a/packages/vats/test/test-lib-board.js +++ b/packages/vats/test/test-lib-board.js @@ -6,8 +6,16 @@ import { makeFakeBoard } from '../tools/board-utils.js'; test('makeBoard', async t => { const board = makeFakeBoard(); - const obj1 = Far('obj1', { lookup: async (...path) => path }); - const obj2 = Far('obj2', {}); + const obj1 = makeExo( + 'obj1', + M.interface('obj1', {}, { defaultGuards: 'passable' }), + { lookup: async (...path) => path }, + ); + const obj2 = makeExo( + 'obj2', + M.interface('obj2', {}, { defaultGuards: 'passable' }), + {}, + ); t.deepEqual(board.ids(), [], `board is empty to start`); t.is(await board.lookup(), board, 'empty lookup returns board'); @@ -57,8 +65,16 @@ test('board values must be scalar keys', async t => { }); const testBoardMarshaller = async (t, board, marshaller, publishing) => { - const published = Far('published', {}); - const unpublished = Far('unpublished', {}); + const published = makeExo( + 'published', + M.interface('published', {}, { defaultGuards: 'passable' }), + {}, + ); + const unpublished = makeExo( + 'unpublished', + M.interface('unpublished', {}, { defaultGuards: 'passable' }), + {}, + ); const published1id = board.getId(published); const ser = marshaller.toCapData( diff --git a/packages/vats/test/test-name-hub.js b/packages/vats/test/test-name-hub.js index 3911a3e6773..90eaf3b6a33 100644 --- a/packages/vats/test/test-name-hub.js +++ b/packages/vats/test/test-name-hub.js @@ -156,7 +156,11 @@ test('makeNameHubKit - listen for updates', async t => { const capture = []; nameAdmin.onUpdate( - Far('Recorder', { write: entries => capture.push(entries) }), + makeExo( + 'Recorder', + M.interface('Recorder', {}, { defaultGuards: 'passable' }), + { write: entries => capture.push(entries) }, + ), ); const brandIST = harden({ name: 'IST' }); diff --git a/packages/vats/tools/bank-utils.js b/packages/vats/tools/bank-utils.js index 13a0047b78c..e4cc47d079a 100644 --- a/packages/vats/tools/bank-utils.js +++ b/packages/vats/tools/bank-utils.js @@ -47,11 +47,15 @@ export const makeFakeBankKit = issuerKits => { }; /** @type {import('../src/vat-bank.js').Bank} */ - const bank = Far('mock bank', { - /** @param {Brand} brand */ - getPurse: async brand => purses.get(brand), - getAssetSubscription: () => subscription, - }); + const bank = makeExo( + 'mock bank', + M.interface('mock bank', {}, { defaultGuards: 'passable' }), + { + /** @param {Brand} brand */ + getPurse: async brand => purses.get(brand), + getAssetSubscription: () => subscription, + }, + ); return { addAsset, assetPublication: publication, bank }; }; diff --git a/packages/vats/tools/boot-test-utils.js b/packages/vats/tools/boot-test-utils.js index 4e938f497d5..1d13ffa2fd0 100644 --- a/packages/vats/tools/boot-test-utils.js +++ b/packages/vats/tools/boot-test-utils.js @@ -49,33 +49,58 @@ export const makeMock = log => }, vats: { vattp: /** @type {any} */ ( - Far('vattp', { - registerMailboxDevice: noop, - addRemote: () => harden({}), - }) + makeExo( + 'vattp', + M.interface('vattp', {}, { defaultGuards: 'passable' }), + { + registerMailboxDevice: noop, + addRemote: () => harden({}), + }, + ) + ), + comms: makeExo( + 'comms', + M.interface('comms', {}, { defaultGuards: 'passable' }), + { + addRemote: noop, + addEgress: noop, + addIngress: async () => + harden({ + getConfiguration: () => harden({ _: 'client configuration' }), + }), + }, ), - comms: Far('comms', { - addRemote: noop, - addEgress: noop, - addIngress: async () => - harden({ - getConfiguration: () => harden({ _: 'client configuration' }), - }), - }), http: { setPresences: noop, setCommandDevice: noop }, spawner: { buildSpawner: () => harden({ _: 'spawner' }), }, - timer: Far('TimerVat', { - createTimerService: async () => buildManualTimer(log), - }), + timer: makeExo( + 'TimerVat', + M.interface('TimerVat', {}, { defaultGuards: 'passable' }), + { + createTimerService: async () => buildManualTimer(log), + }, + ), uploads: { getUploads: () => harden({ _: 'uploads' }) }, - network: Far('network', { - registerProtocolHandler: noop, - makeLoopbackProtocolHandler: noop, - bind: () => Far('network - listener', { addListener: noop }), - }), + network: makeExo( + 'network', + M.interface('network', {}, { defaultGuards: 'passable' }), + { + registerProtocolHandler: noop, + makeLoopbackProtocolHandler: noop, + bind: () => + makeExo( + 'network - listener', + M.interface( + 'network - listener', + {}, + { defaultGuards: 'passable' }, + ), + { addListener: noop }, + ), + }, + ), }, }); @@ -133,11 +158,15 @@ export const makePopulatedFakeVatAdmin = () => { return createVat(fakeNameToCap.get(name) || Fail`unknown vat ${name}`); }; - const vatAdminService = Far('vatAdminSvc', { - ...fakeVatAdmin, - createVat, - createVatByName, - }); + const vatAdminService = makeExo( + 'vatAdminSvc', + M.interface('vatAdminSvc', {}, { defaultGuards: 'passable' }), + { + ...fakeVatAdmin, + createVat, + createVatByName, + }, + ); const criticalVatKey = vatAdminState.getCriticalVatKey(); const getCriticalVatKey = () => criticalVatKey; const createVatAdminService = () => vatAdminService; diff --git a/packages/wallet/api/src/actions.js b/packages/wallet/api/src/actions.js index c5bf3469969..5712bd98d0c 100644 --- a/packages/wallet/api/src/actions.js +++ b/packages/wallet/api/src/actions.js @@ -14,122 +14,126 @@ export const makePaymentActions = ({ }) => { const depositedPK = makePromiseKit(); - return Far('payment actions', { - deposit: async (purseOrPetname = undefined) => { - const oldPaymentRecord = getRecord(); - const { brand, payment } = oldPaymentRecord; - assert(payment); + return makeExo( + 'payment actions', + M.interface('payment actions', {}, { defaultGuards: 'passable' }), + { + deposit: async (purseOrPetname = undefined) => { + const oldPaymentRecord = getRecord(); + const { brand, payment } = oldPaymentRecord; + assert(payment); - /** @type {Purse} */ - let purse; - if (purseOrPetname === undefined) { - const autoDepositPurse = getAutoDepositPurse(brand); - if (!autoDepositPurse) { - // No automatic purse right now. - return depositedPK.promise; + /** @type {Purse} */ + let purse; + if (purseOrPetname === undefined) { + const autoDepositPurse = getAutoDepositPurse(brand); + if (!autoDepositPurse) { + // No automatic purse right now. + return depositedPK.promise; + } + // Plop into the current autodeposit purse. + purse = getAutoDepositPurse(brand); + } else if ( + Array.isArray(purseOrPetname) || + typeof purseOrPetname === 'string' + ) { + purse = getPurseByPetname(purseOrPetname); + } else { + purse = purseOrPetname; + } + const brandRecord = getBrandRecord(brand); + updateRecord({ ...oldPaymentRecord, status: 'pending' }, brandRecord); + // Now try depositing. + E(purse) + .deposit(payment) + .then( + depositedAmount => { + updateRecord( + { + ...getRecord(), + // Remove the payment so it can be GCed. + payment: undefined, + status: 'deposited', + depositedAmount, + }, + brandRecord, + ); + depositedPK.resolve(depositedAmount); + }, + e => { + console.error( + 'Error depositing payment in', + purseOrPetname || 'default purse', + e, + ); + if (purseOrPetname === undefined) { + // Error in auto-deposit purse, just fail. They can try + // again. + updateRecord({ + ...getRecord(), + status: undefined, + }); + depositedPK.reject(e); + } else { + // Error in designated deposit, so retry automatically without + // a designated purse. + depositedPK.resolve(getRecord().actions.deposit(undefined)); + } + }, + ); + return depositedPK.promise; + }, + refresh: async () => { + const oldPaymentRecord = getRecord(); + const { brand, issuer, payment } = oldPaymentRecord; + const brandRecord = getBrandRecord(brand); + if (!brandRecord) { + return false; } - // Plop into the current autodeposit purse. - purse = getAutoDepositPurse(brand); - } else if ( - Array.isArray(purseOrPetname) || - typeof purseOrPetname === 'string' - ) { - purse = getPurseByPetname(purseOrPetname); - } else { - purse = purseOrPetname; - } - const brandRecord = getBrandRecord(brand); - updateRecord({ ...oldPaymentRecord, status: 'pending' }, brandRecord); - // Now try depositing. - E(purse) - .deposit(payment) - .then( - depositedAmount => { - updateRecord( - { - ...getRecord(), - // Remove the payment so it can be GCed. - payment: undefined, - status: 'deposited', - depositedAmount, - }, - brandRecord, - ); - depositedPK.resolve(depositedAmount); - }, - e => { - console.error( - 'Error depositing payment in', - purseOrPetname || 'default purse', - e, - ); - if (purseOrPetname === undefined) { - // Error in auto-deposit purse, just fail. They can try - // again. - updateRecord({ - ...getRecord(), - status: undefined, - }); - depositedPK.reject(e); - } else { - // Error in designated deposit, so retry automatically without - // a designated purse. - depositedPK.resolve(getRecord().actions.deposit(undefined)); - } - }, - ); - return depositedPK.promise; - }, - refresh: async () => { - const oldPaymentRecord = getRecord(); - const { brand, issuer, payment } = oldPaymentRecord; - const brandRecord = getBrandRecord(brand); - if (!brandRecord) { - return false; - } - if (!issuer) { - updateRecord( - { - ...oldPaymentRecord, - issuerBoardId: getIssuerBoardId(brandRecord.issuer), - }, - brandRecord, - ); - return true; - } + if (!issuer) { + updateRecord( + { + ...oldPaymentRecord, + issuerBoardId: getIssuerBoardId(brandRecord.issuer), + }, + brandRecord, + ); + return true; + } - if (!payment) { - return false; - } + if (!payment) { + return false; + } - const isLive = await E(issuer).isLive(payment); - if (isLive) { - return false; - } + const isLive = await E(issuer).isLive(payment); + if (isLive) { + return false; + } - updateRecord({ - ...oldPaymentRecord, - // Remove the payment itself so it can be GCed. - payment: undefined, - status: 'expired', - }); - return true; - }, - getAmountOf: async () => { - const oldPaymentRecord = getRecord(); - const { issuer, payment } = oldPaymentRecord; - assert(issuer); - assert(payment); + updateRecord({ + ...oldPaymentRecord, + // Remove the payment itself so it can be GCed. + payment: undefined, + status: 'expired', + }); + return true; + }, + getAmountOf: async () => { + const oldPaymentRecord = getRecord(); + const { issuer, payment } = oldPaymentRecord; + assert(issuer); + assert(payment); - // Fetch the current amount of the payment. - const lastAmount = await E(issuer).getAmountOf(payment); + // Fetch the current amount of the payment. + const lastAmount = await E(issuer).getAmountOf(payment); - updateRecord({ - ...oldPaymentRecord, - lastAmount, - }); - return true; + updateRecord({ + ...oldPaymentRecord, + lastAmount, + }); + return true; + }, }, - }); + ); }; diff --git a/packages/wallet/api/src/lib-wallet.js b/packages/wallet/api/src/lib-wallet.js index 6da348d70d4..d79ee567580 100644 --- a/packages/wallet/api/src/lib-wallet.js +++ b/packages/wallet/api/src/lib-wallet.js @@ -273,20 +273,24 @@ export function makeWalletRoot({ currentAmount, }); const filter = state => state.map(innerFilter); - const pu = Far('pursesUpdater', { - updateState: newState => { - ipu.updateState(newState); - apu.updateState(filter(newState)); - }, - finish: finalState => { - ipu.finish(finalState); - apu.finish(filter(finalState)); - }, - fail: reason => { - ipu.fail(reason); - apu.fail(reason); + const pu = makeExo( + 'pursesUpdater', + M.interface('pursesUpdater', {}, { defaultGuards: 'passable' }), + { + updateState: newState => { + ipu.updateState(newState); + apu.updateState(filter(newState)); + }, + finish: finalState => { + ipu.finish(finalState); + apu.finish(filter(finalState)); + }, + fail: reason => { + ipu.fail(reason); + apu.fail(reason); + }, }, - }); + ); return harden({ pursesNotifier: ipn, attenuatedPursesNotifier: apn, @@ -346,27 +350,31 @@ export function makeWalletRoot({ ...jstate, purse, brand, - actions: Far('purse.actions', { - // Send a value from this purse. - async send(receiverP, sendValue) { - const amount = AmountMath.make(brand, sendValue); - const payment = await E(purse).withdraw(amount); - try { - await E(receiverP).receive(payment); - } catch (e) { - // Recover the failed payment. - await E(purse).deposit(payment); - throw e; - } - }, - async receive(paymentP) { - const payment = await paymentP; - return E(purse).deposit(payment); - }, - deposit(payment, amount = undefined) { - return E(purse).deposit(payment, amount); + actions: makeExo( + 'purse.actions', + M.interface('purse.actions', {}, { defaultGuards: 'passable' }), + { + // Send a value from this purse. + async send(receiverP, sendValue) { + const amount = AmountMath.make(brand, sendValue); + const payment = await E(purse).withdraw(amount); + try { + await E(receiverP).receive(payment); + } catch (e) { + // Recover the failed payment. + await E(purse).deposit(payment); + throw e; + } + }, + async receive(paymentP) { + const payment = await paymentP; + return E(purse).deposit(payment); + }, + deposit(payment, amount = undefined) { + return E(purse).deposit(payment, amount); + }, }, - }), + ), }), ); pursesUpdater.updateState([...pursesFullState.values()]); @@ -1016,59 +1024,63 @@ export function makeWalletRoot({ cacheCoordinator, approvalP, enable: false, - actions: Far('dapp.actions', { - setPetname(petname) { - if (dappRecord.petname === petname) { + actions: makeExo( + 'dapp.actions', + M.interface('dapp.actions', {}, { defaultGuards: 'passable' }), + { + setPetname(petname) { + if (dappRecord.petname === petname) { + return dappRecord.actions; + } + if (edgeMapping.valToPetname.has(origin)) { + edgeMapping.renamePetname(petname, origin); + } else { + petname = edgeMapping.suggestPetname(petname, origin); + } + dappRecord = addMeta({ + ...dappRecord, + petname, + }); + updateDapp(dappRecord); + updateAllState(); return dappRecord.actions; - } - if (edgeMapping.valToPetname.has(origin)) { - edgeMapping.renamePetname(petname, origin); - } else { - petname = edgeMapping.suggestPetname(petname, origin); - } - dappRecord = addMeta({ - ...dappRecord, - petname, - }); - updateDapp(dappRecord); - updateAllState(); - return dappRecord.actions; - }, - enable() { - // Enable the dapp with the attached petname. - dappRecord = addMeta({ - ...dappRecord, - enable: true, - }); - edgeMapping.suggestPetname(dappRecord.petname, origin); - updateDapp(dappRecord); - - // Allow the pending requests to pass. - resolve(); - return dappRecord.actions; - }, - disable(reason = undefined) { - // Reject the pending dapp requests. - if (reject) { - reject(reason); - } - // Create a new, suspended-approval record. - ({ resolve, reject, promise: approvalP } = makePromiseKit()); - dappRecord = addMeta({ - ...dappRecord, - enable: false, - approvalP, - }); - updateDapp(dappRecord); - return dappRecord.actions; - }, - delete() { - if (reject) { - reject('Dapp deleted'); - } - deleteDapp(dappRecord); + }, + enable() { + // Enable the dapp with the attached petname. + dappRecord = addMeta({ + ...dappRecord, + enable: true, + }); + edgeMapping.suggestPetname(dappRecord.petname, origin); + updateDapp(dappRecord); + + // Allow the pending requests to pass. + resolve(); + return dappRecord.actions; + }, + disable(reason = undefined) { + // Reject the pending dapp requests. + if (reject) { + reject(reason); + } + // Create a new, suspended-approval record. + ({ resolve, reject, promise: approvalP } = makePromiseKit()); + dappRecord = addMeta({ + ...dappRecord, + enable: false, + approvalP, + }); + updateDapp(dappRecord); + return dappRecord.actions; + }, + delete() { + if (reject) { + reject('Dapp deleted'); + } + deleteDapp(dappRecord); + }, }, - }), + ), }); // Prepare the table entry to be updated. @@ -1529,33 +1541,37 @@ export function makeWalletRoot({ const instanceManager = makeManager(instanceMapping, 'InstanceManager'); /** @type {IssuerManager} */ - const issuerManager = Far('IssuerManager', { - rename: async (petname, issuer) => { - brandTable.hasByIssuer(issuer) || - Fail`issuer has not been previously added`; - const brandRecord = brandTable.getByIssuer(issuer); - brandMapping.renamePetname(petname, brandRecord.brand); - await updateAllState(); - }, - get: petname => { - const brand = brandMapping.petnameToVal.get(petname); - return brandTable.getByBrand(brand).issuer; - }, - getAll: () => { - return [...brandMapping.petnameToVal.entries()].map( - ([petname, brand]) => { - const { issuer } = brandTable.getByBrand(brand); - return [petname, issuer]; - }, - ); - }, - add: async (petname, issuerP) => { - const { brand, issuer } = await brandTable.initIssuer(issuerP, addMeta); - await initIssuerToBoardId(issuer, brand); - brandMapping.suggestPetname(petname, brand); - await updateAllIssuersState(); + const issuerManager = makeExo( + 'IssuerManager', + M.interface('IssuerManager', {}, { defaultGuards: 'passable' }), + { + rename: async (petname, issuer) => { + brandTable.hasByIssuer(issuer) || + Fail`issuer has not been previously added`; + const brandRecord = brandTable.getByIssuer(issuer); + brandMapping.renamePetname(petname, brandRecord.brand); + await updateAllState(); + }, + get: petname => { + const brand = brandMapping.petnameToVal.get(petname); + return brandTable.getByBrand(brand).issuer; + }, + getAll: () => { + return [...brandMapping.petnameToVal.entries()].map( + ([petname, brand]) => { + const { issuer } = brandTable.getByBrand(brand); + return [petname, issuer]; + }, + ); + }, + add: async (petname, issuerP) => { + const { brand, issuer } = await brandTable.initIssuer(issuerP, addMeta); + await initIssuerToBoardId(issuer, brand); + brandMapping.suggestPetname(petname, brand); + await updateAllIssuersState(); + }, }, - }); + ); function getInstallationManager() { return installationManager; @@ -1646,7 +1662,7 @@ export function makeWalletRoot({ const makeLookup = (kind, lookup) => { rootPathToLookup.init( kind, - Far(`${kind}Lookup`, { + makeExo(`${kind}Lookup`, M.interface(`${kind}Lookup`, {}, { defaultGuards: 'passable' }), { lookup, }), ); @@ -1735,134 +1751,142 @@ export function makeWalletRoot({ } }; - const wallet = Far('wallet', { - lookup: (...path) => { - // Provide an entrypoint to the wallet's naming hub. - if (path.length === 0) { - return wallet; - } - const [first, ...remaining] = path; - const firstValue = firstPathToLookup.get(first); - if (remaining.length === 0) { - return firstValue; - } - return E(firstValue).lookup(...remaining); - }, - getMarshaller: () => marshaller, - getDappCacheCoordinator: dappOrigin => - dappOrigins.get(dappOrigin).cacheCoordinator, - getCacheCoordinator: () => sharedCacheCoordinator, - saveOfferResult, - getOfferResult, - waitForDappApproval, - getDappsNotifier() { - return dappsNotifier; - }, - getPursesNotifier() { - return pursesNotifier; - }, - getAttenuatedPursesNotifier() { - return attenuatedPursesNotifier; - }, - getIssuersNotifier() { - return issuersNotifier; - }, - getOffersNotifier() { - return offersNotifier; - }, - /** @deprecated use issuerManager.add instead */ - addIssuer: issuerManager.add, - getBrand, - getBrandPetnames, - publishIssuer, - /** @deprecated use instanceManager.add instead */ - addInstance: instanceManager.add, - /** @deprecated use installationManager.add instead */ - addInstallation: installationManager.add, - getInstallationManager, - getInstanceManager, - getIssuerManager, - /** @deprecated use issuerManager.rename instead */ - renameIssuer: issuerManager.rename, - /** @deprecated use instanceManager.rename instead */ - renameInstance: instanceManager.rename, - /** @deprecated use installationManager.rename instead */ - renameInstallation: installationManager.rename, - getSelfContact, - /** @deprecated use instanceManager.get instead */ - getInstance: instanceManager.get, - /** @deprecated use installationManager.get instead */ - getInstallation: installationManager.get, - /** @deprecated use installationManager.getAll instead */ - getInstallations: installationManager.getAll, - makeEmptyPurse, - deposit, - /** @deprecated use issuerManager.get instead */ - getIssuer: issuerManager.get, - /** @deprecated use issuerManager.getAll instead */ - getIssuers: issuerManager.getAll, - getPurses, - getPurse, - getPurseIssuer, - addOffer, - declineOffer, - cancelOffer, - acceptOffer, - getOffers, - getSeat: id => idToSeat.get(id), - getSeats: ids => ids.map(wallet.getSeat), - enableAutoDeposit(pursePetname) { - // Enable the autodeposit with intermediary state updates. - return doEnableAutoDeposit(pursePetname, true); - }, - disableAutoDeposit, - performAction, - getDepositFacetId, - suggestIssuer, - suggestInstance, - suggestInstallation, - addContact, - getContactsNotifier() { - return contactsNotifier; - }, - addPayment, - getPaymentsNotifier() { - return paymentsNotifier; - }, - /** @deprecated use `getPublicSubscribers` instead. */ - getUINotifier, - /** @deprecated use `getPublicSubscribers` instead. */ - getPublicNotifiers, - getPublicSubscribers, - getZoe() { - return zoe; - }, - getBoard() { - return board; - }, - getAgoricNames(...path) { - if (!agoricNames) { - throw Fail`agoricNames was not supplied to the wallet maker`; - } - return E(agoricNames).lookup(...path); - }, - getNamesByAddress(...path) { - if (namesByAddress === undefined) { - // TypeScript confused about `||` control flow so use `if` instead - // https://github.com/microsoft/TypeScript/issues/50739 - throw Fail`namesByAddress was not supplied to the wallet maker`; - } - return E(namesByAddress).lookup(...path); + const wallet = makeExo( + 'wallet', + M.interface('wallet', {}, { defaultGuards: 'passable' }), + { + lookup: (...path) => { + // Provide an entrypoint to the wallet's naming hub. + if (path.length === 0) { + return wallet; + } + const [first, ...remaining] = path; + const firstValue = firstPathToLookup.get(first); + if (remaining.length === 0) { + return firstValue; + } + return E(firstValue).lookup(...remaining); + }, + getMarshaller: () => marshaller, + getDappCacheCoordinator: dappOrigin => + dappOrigins.get(dappOrigin).cacheCoordinator, + getCacheCoordinator: () => sharedCacheCoordinator, + saveOfferResult, + getOfferResult, + waitForDappApproval, + getDappsNotifier() { + return dappsNotifier; + }, + getPursesNotifier() { + return pursesNotifier; + }, + getAttenuatedPursesNotifier() { + return attenuatedPursesNotifier; + }, + getIssuersNotifier() { + return issuersNotifier; + }, + getOffersNotifier() { + return offersNotifier; + }, + /** @deprecated use issuerManager.add instead */ + addIssuer: issuerManager.add, + getBrand, + getBrandPetnames, + publishIssuer, + /** @deprecated use instanceManager.add instead */ + addInstance: instanceManager.add, + /** @deprecated use installationManager.add instead */ + addInstallation: installationManager.add, + getInstallationManager, + getInstanceManager, + getIssuerManager, + /** @deprecated use issuerManager.rename instead */ + renameIssuer: issuerManager.rename, + /** @deprecated use instanceManager.rename instead */ + renameInstance: instanceManager.rename, + /** @deprecated use installationManager.rename instead */ + renameInstallation: installationManager.rename, + getSelfContact, + /** @deprecated use instanceManager.get instead */ + getInstance: instanceManager.get, + /** @deprecated use installationManager.get instead */ + getInstallation: installationManager.get, + /** @deprecated use installationManager.getAll instead */ + getInstallations: installationManager.getAll, + makeEmptyPurse, + deposit, + /** @deprecated use issuerManager.get instead */ + getIssuer: issuerManager.get, + /** @deprecated use issuerManager.getAll instead */ + getIssuers: issuerManager.getAll, + getPurses, + getPurse, + getPurseIssuer, + addOffer, + declineOffer, + cancelOffer, + acceptOffer, + getOffers, + getSeat: id => idToSeat.get(id), + getSeats: ids => ids.map(wallet.getSeat), + enableAutoDeposit(pursePetname) { + // Enable the autodeposit with intermediary state updates. + return doEnableAutoDeposit(pursePetname, true); + }, + disableAutoDeposit, + performAction, + getDepositFacetId, + suggestIssuer, + suggestInstance, + suggestInstallation, + addContact, + getContactsNotifier() { + return contactsNotifier; + }, + addPayment, + getPaymentsNotifier() { + return paymentsNotifier; + }, + /** @deprecated use `getPublicSubscribers` instead. */ + getUINotifier, + /** @deprecated use `getPublicSubscribers` instead. */ + getPublicNotifiers, + getPublicSubscribers, + getZoe() { + return zoe; + }, + getBoard() { + return board; + }, + getAgoricNames(...path) { + if (!agoricNames) { + throw Fail`agoricNames was not supplied to the wallet maker`; + } + return E(agoricNames).lookup(...path); + }, + getNamesByAddress(...path) { + if (namesByAddress === undefined) { + // TypeScript confused about `||` control flow so use `if` instead + // https://github.com/microsoft/TypeScript/issues/50739 + throw Fail`namesByAddress was not supplied to the wallet maker`; + } + return E(namesByAddress).lookup(...path); + }, }, - }); + ); const initialize = async () => { // Allow people to send us payments. - const selfDepositFacet = Far('contact', { - receive(payment) { - return addPayment(payment); + const selfDepositFacet = makeExo( + 'contact', + M.interface('contact', {}, { defaultGuards: 'passable' }), + { + receive(payment) { + return addPayment(payment); + }, }, - }); + ); const address = await E(myAddressNameAdmin).getMyAddress(); // We need to do this before we can enable auto deposit. diff --git a/packages/wallet/api/src/wallet.js b/packages/wallet/api/src/wallet.js index a37de6fd49f..b42ff04bb4f 100644 --- a/packages/wallet/api/src/wallet.js +++ b/packages/wallet/api/src/wallet.js @@ -168,162 +168,170 @@ export function buildRootObject(vatPowers) { harden(makeApprovedNotifier); /** @type {WalletBridge} */ - const bridge = Far('bridge', { - async getPursesNotifier() { - await approve(); - const pursesNotifier = walletAdmin.getAttenuatedPursesNotifier(); - const { notifier, updater } = makeNotifierKit(); - observeIteration(makeApprovedNotifier(pursesNotifier), updater); - return notifier; + const bridge = makeExo( + 'bridge', + M.interface('bridge', {}, { defaultGuards: 'passable' }), + { + async getPursesNotifier() { + await approve(); + const pursesNotifier = walletAdmin.getAttenuatedPursesNotifier(); + const { notifier, updater } = makeNotifierKit(); + observeIteration(makeApprovedNotifier(pursesNotifier), updater); + return notifier; + }, + async getCacheCoordinator() { + await approve(); + return walletAdmin.getDappCacheCoordinator(dappOrigin); + }, + async getIssuersNotifier() { + await approve(); + return walletAdmin.getIssuersNotifier(); + }, + async addOffer(offer) { + await approve(); + return walletAdmin.addOffer(offer, { ...meta, dappOrigin }); + }, + async getOffersNotifier(status = null) { + await approve(); + const { notifier, updater } = makeNotifierKit(inboxState); + const filter = offer => + (status === null || offer.status === status) && + offer.requestContext && + offer.requestContext.dappOrigin === dappOrigin; + const filteredOffers = offers => { + return offers.filter(filter).map(({ rawId, ...v }) => ({ + ...v, + id: rawId, + })); + }; + + observeIteration(makeApprovedNotifier(offerNotifier), { + updateState(offers) { + updater.updateState(filteredOffers(offers)); + }, + finish(offers) { + updater.finish(filteredOffers(offers)); + }, + fail(e) { + updater.fail(e); + }, + }); + return notifier; + }, + async getDepositFacetId(brandBoardId) { + await approve(); + return walletAdmin.getDepositFacetId(brandBoardId); + }, + async suggestIssuer(petname, boardId) { + await approve(); + return walletAdmin.suggestIssuer(petname, boardId, dappOrigin); + }, + async suggestInstallation(petname, boardId) { + await approve(); + return walletAdmin.suggestInstallation(petname, boardId, dappOrigin); + }, + async suggestInstance(petname, boardId) { + await approve(); + return walletAdmin.suggestInstance(petname, boardId, dappOrigin); + }, + async getUINotifier(rawId) { + await approve(); + return walletAdmin.getUINotifier(rawId, dappOrigin); + }, + async getPublicNotifiers(rawId) { + await approve(); + return walletAdmin.getPublicNotifiers(rawId, dappOrigin); + }, + async getZoe() { + await approve(); + return walletAdmin.getZoe(); + }, + async getBoard() { + await approve(); + return walletAdmin.getBoard(); + }, + async getAgoricNames(...path) { + await approve(); + return walletAdmin.getAgoricNames(...path); + }, + async getNamesByAddress(...path) { + await approve(); + return walletAdmin.getNamesByAddress(...path); + }, + async getBrandPetnames(brands) { + await approve(); + return walletAdmin.getBrandPetnames(brands); + }, }, - async getCacheCoordinator() { - await approve(); - return walletAdmin.getDappCacheCoordinator(dappOrigin); + ); + return bridge; + }; + + /** + * This bridge doesn't wait for approvals before acting. This can be obtained + * from `home.wallet~.getBridge()` in the REPL as a WalletBridge to grab and + * use for testing and exploration without having to think about approvals. + * + * @type {WalletBridge} + */ + const preapprovedBridge = makeExo( + 'preapprovedBridge', + M.interface('preapprovedBridge', {}, { defaultGuards: 'passable' }), + { + /** + * @param {unknown} offer + * @param {{}} [meta] + */ + addOffer(offer, meta) { + return walletAdmin.addOffer(offer, meta); }, - async getIssuersNotifier() { - await approve(); - return walletAdmin.getIssuersNotifier(); + getDepositFacetId(brandBoardId) { + return walletAdmin.getDepositFacetId(brandBoardId); }, - async addOffer(offer) { - await approve(); - return walletAdmin.addOffer(offer, { ...meta, dappOrigin }); + async getOffersNotifier() { + return walletAdmin.getOffersNotifier(); }, - async getOffersNotifier(status = null) { - await approve(); - const { notifier, updater } = makeNotifierKit(inboxState); - const filter = offer => - (status === null || offer.status === status) && - offer.requestContext && - offer.requestContext.dappOrigin === dappOrigin; - const filteredOffers = offers => { - return offers.filter(filter).map(({ rawId, ...v }) => ({ - ...v, - id: rawId, - })); - }; - - observeIteration(makeApprovedNotifier(offerNotifier), { - updateState(offers) { - updater.updateState(filteredOffers(offers)); - }, - finish(offers) { - updater.finish(filteredOffers(offers)); - }, - fail(e) { - updater.fail(e); - }, - }); - return notifier; + async getPursesNotifier() { + return walletAdmin.getAttenuatedPursesNotifier(); }, - async getDepositFacetId(brandBoardId) { - await approve(); - return walletAdmin.getDepositFacetId(brandBoardId); + async getIssuersNotifier() { + return walletAdmin.getIssuersNotifier(); }, - async suggestIssuer(petname, boardId) { - await approve(); - return walletAdmin.suggestIssuer(petname, boardId, dappOrigin); + async getCacheCoordinator() { + return walletAdmin.getCacheCoordinator(); }, - async suggestInstallation(petname, boardId) { - await approve(); - return walletAdmin.suggestInstallation(petname, boardId, dappOrigin); + suggestInstallation(petname, installationBoardId) { + return walletAdmin.suggestInstallation(petname, installationBoardId); }, - async suggestInstance(petname, boardId) { - await approve(); - return walletAdmin.suggestInstance(petname, boardId, dappOrigin); + suggestInstance(petname, instanceBoardId) { + return walletAdmin.suggestInstance(petname, instanceBoardId); }, - async getUINotifier(rawId) { - await approve(); - return walletAdmin.getUINotifier(rawId, dappOrigin); + suggestIssuer(petname, issuerBoardId) { + return walletAdmin.suggestIssuer(petname, issuerBoardId); }, - async getPublicNotifiers(rawId) { - await approve(); - return walletAdmin.getPublicNotifiers(rawId, dappOrigin); + getUINotifier(rawId) { + return walletAdmin.getUINotifier(rawId); + }, + getPublicNotifiers(rawId) { + return walletAdmin.getPublicNotifiers(rawId); }, async getZoe() { - await approve(); return walletAdmin.getZoe(); }, async getBoard() { - await approve(); return walletAdmin.getBoard(); }, async getAgoricNames(...path) { - await approve(); return walletAdmin.getAgoricNames(...path); }, async getNamesByAddress(...path) { - await approve(); return walletAdmin.getNamesByAddress(...path); }, async getBrandPetnames(brands) { - await approve(); return walletAdmin.getBrandPetnames(brands); }, - }); - return bridge; - }; - - /** - * This bridge doesn't wait for approvals before acting. This can be obtained - * from `home.wallet~.getBridge()` in the REPL as a WalletBridge to grab and - * use for testing and exploration without having to think about approvals. - * - * @type {WalletBridge} - */ - const preapprovedBridge = Far('preapprovedBridge', { - /** - * @param {unknown} offer - * @param {{}} [meta] - */ - addOffer(offer, meta) { - return walletAdmin.addOffer(offer, meta); - }, - getDepositFacetId(brandBoardId) { - return walletAdmin.getDepositFacetId(brandBoardId); - }, - async getOffersNotifier() { - return walletAdmin.getOffersNotifier(); - }, - async getPursesNotifier() { - return walletAdmin.getAttenuatedPursesNotifier(); - }, - async getIssuersNotifier() { - return walletAdmin.getIssuersNotifier(); - }, - async getCacheCoordinator() { - return walletAdmin.getCacheCoordinator(); - }, - suggestInstallation(petname, installationBoardId) { - return walletAdmin.suggestInstallation(petname, installationBoardId); - }, - suggestInstance(petname, instanceBoardId) { - return walletAdmin.suggestInstance(petname, instanceBoardId); - }, - suggestIssuer(petname, issuerBoardId) { - return walletAdmin.suggestIssuer(petname, issuerBoardId); }, - getUINotifier(rawId) { - return walletAdmin.getUINotifier(rawId); - }, - getPublicNotifiers(rawId) { - return walletAdmin.getPublicNotifiers(rawId); - }, - async getZoe() { - return walletAdmin.getZoe(); - }, - async getBoard() { - return walletAdmin.getBoard(); - }, - async getAgoricNames(...path) { - return walletAdmin.getAgoricNames(...path); - }, - async getNamesByAddress(...path) { - return walletAdmin.getNamesByAddress(...path); - }, - async getBrandPetnames(brands) { - return walletAdmin.getBrandPetnames(brands); - }, - }); + ); harden(preapprovedBridge); async function getWallet(bank) { @@ -332,38 +340,46 @@ export function buildRootObject(vatPowers) { /** * @type {WalletAdmin} */ - const wallet = Far('wallet', { - addPayment: walletAdmin.addPayment, - async getScopedBridge(suggestedDappPetname, dappOrigin) { - const approve = async () => { - await walletAdmin.waitForDappApproval( - suggestedDappPetname, - dappOrigin, - ); - }; + const wallet = makeExo( + 'wallet', + M.interface('wallet', {}, { defaultGuards: 'passable' }), + { + addPayment: walletAdmin.addPayment, + async getScopedBridge(suggestedDappPetname, dappOrigin) { + const approve = async () => { + await walletAdmin.waitForDappApproval( + suggestedDappPetname, + dappOrigin, + ); + }; - return makeBridge(approve, dappOrigin); - }, - async getBridge() { - return preapprovedBridge; - }, - getDepositFacetId: walletAdmin.getDepositFacetId, - getAdminFacet() { - return Far('adminFacet', { - ...walletAdmin, - ...notifiers, - getScopedBridge: wallet.getScopedBridge, - }); - }, - getIssuer: walletAdmin.getIssuer, - getIssuers: walletAdmin.getIssuers, - getPurse: walletAdmin.getPurse, - getPurses: walletAdmin.getPurses, + return makeBridge(approve, dappOrigin); + }, + async getBridge() { + return preapprovedBridge; + }, + getDepositFacetId: walletAdmin.getDepositFacetId, + getAdminFacet() { + return makeExo( + 'adminFacet', + M.interface('adminFacet', {}, { defaultGuards: 'passable' }), + { + ...walletAdmin, + ...notifiers, + getScopedBridge: wallet.getScopedBridge, + }, + ); + }, + getIssuer: walletAdmin.getIssuer, + getIssuers: walletAdmin.getIssuers, + getPurse: walletAdmin.getPurse, + getPurses: walletAdmin.getPurses, - getMarshaller: walletAdmin.getMarshaller, + getMarshaller: walletAdmin.getMarshaller, - lookup: walletAdmin.lookup, - }); + lookup: walletAdmin.lookup, + }, + ); return harden(wallet); } @@ -401,248 +417,260 @@ export function buildRootObject(vatPowers) { } function getBridgeURLHandler() { - return Far('bridgeURLHandler', { - /** - * @typedef {object} WalletOtherSide - * The callbacks from a CapTP wallet client. - * @property {(dappOrigin: string, - * suggestedDappPetname: Petname - * ) => void} needDappApproval - * Let the other side know that this dapp is still unapproved - * @property {(dappOrigin: string) => void} dappApproved - * Let the other side know that the dapp has been approved - */ - - /** - * Use CapTP over WebSocket for a dapp to interact with the wallet. - * - * @param {ERef} otherSide - * @param {Record} meta - * @param {Record} obj - */ - async getBootstrap(otherSide, meta, obj) { - const { dappOrigin = meta.origin } = obj; - const suggestedDappPetname = String( - (meta.query && meta.query.suggestedDappPetname) || - meta.dappOrigin || - dappOrigin, - ); - - const approve = async () => { - let notYetEnabled = false; - await walletAdmin.waitForDappApproval( - suggestedDappPetname, - dappOrigin, - () => { - notYetEnabled = true; - E(otherSide) - .needDappApproval(dappOrigin, suggestedDappPetname) - .catch(_ => {}); - }, + return makeExo( + 'bridgeURLHandler', + M.interface('bridgeURLHandler', {}, { defaultGuards: 'passable' }), + { + /** + * @typedef {object} WalletOtherSide + * The callbacks from a CapTP wallet client. + * @property {(dappOrigin: string, + * suggestedDappPetname: Petname + * ) => void} needDappApproval + * Let the other side know that this dapp is still unapproved + * @property {(dappOrigin: string) => void} dappApproved + * Let the other side know that the dapp has been approved + */ + + /** + * Use CapTP over WebSocket for a dapp to interact with the wallet. + * + * @param {ERef} otherSide + * @param {Record} meta + * @param {Record} obj + */ + async getBootstrap(otherSide, meta, obj) { + const { dappOrigin = meta.origin } = obj; + const suggestedDappPetname = String( + (meta.query && meta.query.suggestedDappPetname) || + meta.dappOrigin || + dappOrigin, ); - if (notYetEnabled) { - E(otherSide).dappApproved(dappOrigin); - } - }; - - return makeBridge(approve, dappOrigin, meta); - }, - /** - * This is the legacy WebSocket wrapper for an origin-specific - * WalletBridge. This wrapper is accessible from a dapp UI via the - * wallet-bridge.html iframe. - * - * This custom RPC protocol must maintain compatibility with existing - * dapps. It would be preferable not to add to it either, since that - * means more legacy code that must be supported. - * - * We hope to migrate dapps to use the ocap interfaces (such as - * getBootstrap() above) so that they can interact with the WalletBridge - * methods directly. Then we would like to deprecate this handler. - */ - getCommandHandler() { - return Far('commandHandler', { - onOpen(_obj, meta) { - bridgeHandles.add(meta.channelHandle); - }, - onClose(_obj, meta) { - bridgeHandles.delete(meta.channelHandle); - offerSubscriptions.delete(meta.channelHandle); - }, - - async onMessage(obj, meta) { - const { - type, - dappOrigin = meta.origin, - suggestedDappPetname = (meta.query && - meta.query.suggestedDappPetname) || - obj.dappOrigin || - meta.origin, - } = obj; - - // When we haven't been enabled, tell our caller. - let needApproval = false; + const approve = async () => { + let notYetEnabled = false; await walletAdmin.waitForDappApproval( suggestedDappPetname, dappOrigin, () => { - needApproval = true; - httpSend( - { - type: 'walletNeedDappApproval', - data: { - dappOrigin, - suggestedDappPetname, - }, - }, - [meta.channelHandle], - ); + notYetEnabled = true; + E(otherSide) + .needDappApproval(dappOrigin, suggestedDappPetname) + .catch(_ => {}); }, ); - if (needApproval) { - httpSend( - { - type: 'walletHaveDappApproval', - data: { - dappOrigin, - }, - }, - [meta.channelHandle], - ); + if (notYetEnabled) { + E(otherSide).dappApproved(dappOrigin); } + }; - switch (type) { - case 'walletGetPurses': { - return { - type: 'walletUpdatePurses', - data: bigintStringify(pursesState), - }; - } - case 'walletAddOffer': { - let handled = false; - const actions = Far('actions', { - handled(offer) { - if (handled) { - return; - } - handled = true; + return makeBridge(approve, dappOrigin, meta); + }, + + /** + * This is the legacy WebSocket wrapper for an origin-specific + * WalletBridge. This wrapper is accessible from a dapp UI via the + * wallet-bridge.html iframe. + * + * This custom RPC protocol must maintain compatibility with existing + * dapps. It would be preferable not to add to it either, since that + * means more legacy code that must be supported. + * + * We hope to migrate dapps to use the ocap interfaces (such as + * getBootstrap() above) so that they can interact with the WalletBridge + * methods directly. Then we would like to deprecate this handler. + */ + getCommandHandler() { + return makeExo( + 'commandHandler', + M.interface('commandHandler', {}, { defaultGuards: 'passable' }), + { + onOpen(_obj, meta) { + bridgeHandles.add(meta.channelHandle); + }, + onClose(_obj, meta) { + bridgeHandles.delete(meta.channelHandle); + offerSubscriptions.delete(meta.channelHandle); + }, + + async onMessage(obj, meta) { + const { + type, + dappOrigin = meta.origin, + suggestedDappPetname = (meta.query && + meta.query.suggestedDappPetname) || + obj.dappOrigin || + meta.origin, + } = obj; + + // When we haven't been enabled, tell our caller. + let needApproval = false; + await walletAdmin.waitForDappApproval( + suggestedDappPetname, + dappOrigin, + () => { + needApproval = true; httpSend( { - type: 'walletOfferHandled', - data: offer.id, + type: 'walletNeedDappApproval', + data: { + dappOrigin, + suggestedDappPetname, + }, }, [meta.channelHandle], ); }, - }); - return { - type: 'walletOfferAdded', - data: await walletAdmin.addOffer( - { ...obj.data, actions }, - { ...meta, dappOrigin }, - ), - }; - } - - case 'walletSubscribeOffers': { - const { status = null } = obj; - const { channelHandle } = meta; - - if (!channelHandle) { - return { - type: 'walletSubscribedOffers', - data: false, - }; - } - - // TODO: Maybe use the contract instanceId instead. - subscribeToOffers(channelHandle, { - origin: dappOrigin, - status, - }); - return { - type: 'walletSubscribedOffers', - data: true, - }; - } - - case 'walletGetOffers': { - const { status = null } = obj; - - // Override the origin since we got it from the bridge. - let result = await walletAdmin.getOffers({ - origin: dappOrigin, - }); - if (status !== null) { - // Filter by status. - result = harden( - result.filter(offer => offer.status === status), + ); + if (needApproval) { + httpSend( + { + type: 'walletHaveDappApproval', + data: { + dappOrigin, + }, + }, + [meta.channelHandle], ); } - return { - type: 'walletOfferDescriptions', - data: result, - }; - } - - case 'walletGetDepositFacetId': { - const { brandBoardId } = obj; - const result = - await walletAdmin.getDepositFacetId(brandBoardId); - return { - type: 'walletDepositFacetIdResponse', - data: result, - }; - } - - case 'walletSuggestIssuer': { - const { petname, boardId } = obj; - const result = await walletAdmin.suggestIssuer( - petname, - boardId, - dappOrigin, - ); - return { - type: 'walletSuggestIssuerResponse', - data: result, - }; - } - - case 'walletSuggestInstance': { - const { petname, boardId } = obj; - const result = await walletAdmin.suggestInstance( - petname, - boardId, - dappOrigin, - ); - return { - type: 'walletSuggestInstanceResponse', - data: result, - }; - } - - case 'walletSuggestInstallation': { - const { petname, boardId } = obj; - const result = await walletAdmin.suggestInstallation( - petname, - boardId, - dappOrigin, - ); - return { - type: 'walletSuggestInstallationResponse', - data: result, - }; - } - - default: - return Promise.resolve(false); - } - }, - }); + switch (type) { + case 'walletGetPurses': { + return { + type: 'walletUpdatePurses', + data: bigintStringify(pursesState), + }; + } + case 'walletAddOffer': { + let handled = false; + const actions = makeExo( + 'actions', + M.interface('actions', {}, { defaultGuards: 'passable' }), + { + handled(offer) { + if (handled) { + return; + } + handled = true; + httpSend( + { + type: 'walletOfferHandled', + data: offer.id, + }, + [meta.channelHandle], + ); + }, + }, + ); + return { + type: 'walletOfferAdded', + data: await walletAdmin.addOffer( + { ...obj.data, actions }, + { ...meta, dappOrigin }, + ), + }; + } + + case 'walletSubscribeOffers': { + const { status = null } = obj; + const { channelHandle } = meta; + + if (!channelHandle) { + return { + type: 'walletSubscribedOffers', + data: false, + }; + } + + // TODO: Maybe use the contract instanceId instead. + subscribeToOffers(channelHandle, { + origin: dappOrigin, + status, + }); + return { + type: 'walletSubscribedOffers', + data: true, + }; + } + + case 'walletGetOffers': { + const { status = null } = obj; + + // Override the origin since we got it from the bridge. + let result = await walletAdmin.getOffers({ + origin: dappOrigin, + }); + if (status !== null) { + // Filter by status. + result = harden( + result.filter(offer => offer.status === status), + ); + } + + return { + type: 'walletOfferDescriptions', + data: result, + }; + } + + case 'walletGetDepositFacetId': { + const { brandBoardId } = obj; + const result = + await walletAdmin.getDepositFacetId(brandBoardId); + return { + type: 'walletDepositFacetIdResponse', + data: result, + }; + } + + case 'walletSuggestIssuer': { + const { petname, boardId } = obj; + const result = await walletAdmin.suggestIssuer( + petname, + boardId, + dappOrigin, + ); + return { + type: 'walletSuggestIssuerResponse', + data: result, + }; + } + + case 'walletSuggestInstance': { + const { petname, boardId } = obj; + const result = await walletAdmin.suggestInstance( + petname, + boardId, + dappOrigin, + ); + return { + type: 'walletSuggestInstanceResponse', + data: result, + }; + } + + case 'walletSuggestInstallation': { + const { petname, boardId } = obj; + const result = await walletAdmin.suggestInstallation( + petname, + boardId, + dappOrigin, + ); + return { + type: 'walletSuggestInstallationResponse', + data: result, + }; + } + + default: + return Promise.resolve(false); + } + }, + }, + ); + }, }, - }); + ); } startSubscriptions(); @@ -654,13 +682,17 @@ export function buildRootObject(vatPowers) { ); } - return Far('root', { - startup, - getWallet, - setHTTPObject, - getBridgeURLHandler, - getCommandHandler, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + startup, + getWallet, + setHTTPObject, + getBridgeURLHandler, + getCommandHandler, + }, + ); } /** diff --git a/packages/wallet/api/test/continuingInvitationExample.js b/packages/wallet/api/test/continuingInvitationExample.js index 8f3094667f9..5332a59114d 100644 --- a/packages/wallet/api/test/continuingInvitationExample.js +++ b/packages/wallet/api/test/continuingInvitationExample.js @@ -24,9 +24,13 @@ export const start = zcf => { return harden({ uiNotifier: notifier, publicSubscribers: { offers: subscriber }, - invitationMakers: Far('second thing inviter', { - SecondThing: makeDoSecondThingInvitation, - }), + invitationMakers: makeExo( + 'second thing inviter', + M.interface('second thing inviter', {}, { defaultGuards: 'passable' }), + { + SecondThing: makeDoSecondThingInvitation, + }, + ), }); }; diff --git a/packages/wallet/api/test/test-lib-dehydrate.js b/packages/wallet/api/test/test-lib-dehydrate.js index 0b1ffa5a448..ac278d5df86 100644 --- a/packages/wallet/api/test/test-lib-dehydrate.js +++ b/packages/wallet/api/test/test-lib-dehydrate.js @@ -90,10 +90,14 @@ test('makeDehydrator', async t => { ); const makeMockBrand = () => - Far('mock brand', { - isMyIssuer: _allegedIssuer => {}, - getAllegedName: () => {}, - }); + makeExo( + 'mock brand', + M.interface('mock brand', {}, { defaultGuards: 'passable' }), + { + isMyIssuer: _allegedIssuer => {}, + getAllegedName: () => {}, + }, + ); const brand1 = makeMockBrand(); const brand2 = makeMockBrand(); @@ -159,7 +163,11 @@ test('makeDehydrator', async t => { }, exit: { afterDeadline: { - timer: Far('timer', {}), + timer: makeExo( + 'timer', + M.interface('timer', {}, { defaultGuards: 'passable' }), + {}, + ), deadline: 55, }, }, diff --git a/packages/wallet/api/test/test-middleware.js b/packages/wallet/api/test/test-middleware.js index 6cbb124fc6b..ffb084dee17 100644 --- a/packages/wallet/api/test/test-middleware.js +++ b/packages/wallet/api/test/test-middleware.js @@ -18,9 +18,13 @@ test('makeLoggingPresence logs calls on purse/payment actions', async t => { const purse = { actions: await makeLoggingPresence('Alleged: purse.actions', enqueue), }; - const myPayment = Far('payment', { - getAllegedBrand: () => assert.fail('mock'), - }); + const myPayment = makeExo( + 'payment', + M.interface('payment', {}, { defaultGuards: 'passable' }), + { + getAllegedBrand: () => assert.fail('mock'), + }, + ); await E(purse.actions).deposit(myPayment); // promise resolves??? await E(purse.actions)(1, 'thing'); t.deepEqual(msgs, [ diff --git a/packages/zoe/src/contractFacet/vatRoot.js b/packages/zoe/src/contractFacet/vatRoot.js index befea18e9c6..27d14963115 100644 --- a/packages/zoe/src/contractFacet/vatRoot.js +++ b/packages/zoe/src/contractFacet/vatRoot.js @@ -60,28 +60,40 @@ export async function buildRootObject(powers, vatParameters, baggage) { if (!firstTime) { return E.when(E(zcfZygote).restartContract(vatParameters.privateArgs), () => - Far('upgraded contractRunner', {}), + makeExo( + 'upgraded contractRunner', + M.interface( + 'upgraded contractRunner', + {}, + { defaultGuards: 'passable' }, + ), + {}, + ), ); } - return Far('contractRunner', { - // initialize instance-specific state of the contract - /** @type {StartZcf} */ - startZcf: ( - zoeInstanceAdmin, - instanceRecordFromZoe, - issuerStorageFromZoe, - privateArgs = undefined, - ) => { - /** @type {ZCFZygote} */ - return E(zcfZygote).startContract( + return makeExo( + 'contractRunner', + M.interface('contractRunner', {}, { defaultGuards: 'passable' }), + { + // initialize instance-specific state of the contract + /** @type {StartZcf} */ + startZcf: ( zoeInstanceAdmin, instanceRecordFromZoe, issuerStorageFromZoe, - privateArgs, - ); + privateArgs = undefined, + ) => { + /** @type {ZCFZygote} */ + return E(zcfZygote).startContract( + zoeInstanceAdmin, + instanceRecordFromZoe, + issuerStorageFromZoe, + privateArgs, + ); + }, }, - }); + ); } harden(buildRootObject); diff --git a/packages/zoe/src/contractSupport/priceAuthority.js b/packages/zoe/src/contractSupport/priceAuthority.js index 02ac349adf3..8698d1a270b 100644 --- a/packages/zoe/src/contractSupport/priceAuthority.js +++ b/packages/zoe/src/contractSupport/priceAuthority.js @@ -185,20 +185,27 @@ export const makeOnewayPriceAuthorityKit = opts => { const triggerPK = makePromiseKit(); /** @type {MutableQuote} */ - const mutableQuote = Far('MutableQuote', { - cancel: e => triggerPK.reject(e), - updateLevel: (newAmountIn, newAmountOutLimit) => { - const coercedAmountIn = AmountMath.coerce(actualBrandIn, newAmountIn); - const coercedAmountOutLimit = AmountMath.coerce( - actualBrandOut, - newAmountOutLimit, - ); - amountIn = coercedAmountIn; - amountOutLimit = coercedAmountOutLimit; - fireTriggers(createQuote); + const mutableQuote = makeExo( + 'MutableQuote', + M.interface('MutableQuote', {}, { defaultGuards: 'passable' }), + { + cancel: e => triggerPK.reject(e), + updateLevel: (newAmountIn, newAmountOutLimit) => { + const coercedAmountIn = AmountMath.coerce( + actualBrandIn, + newAmountIn, + ); + const coercedAmountOutLimit = AmountMath.coerce( + actualBrandOut, + newAmountOutLimit, + ); + amountIn = coercedAmountIn; + amountOutLimit = coercedAmountOutLimit; + fireTriggers(createQuote); + }, + getPromise: () => triggerPK.promise, }, - getPromise: () => triggerPK.promise, - }); + ); /** @type {PriceQuoteTrigger} */ const mutableTrigger = async createInstantQuote => { @@ -255,128 +262,140 @@ export const makeOnewayPriceAuthorityKit = opts => { }; /** @type {PriceAuthority} */ - const priceAuthority = Far('PriceAuthority', { - getQuoteIssuer(brandIn, brandOut) { - assertBrands(brandIn, brandOut); - return quoteIssuer; - }, - getTimerService(brandIn, brandOut) { - assertBrands(brandIn, brandOut); - return timer; - }, - makeQuoteNotifier(amountIn, brandOut) { - AmountMath.coerce(actualBrandIn, amountIn); - assertBrands(amountIn.brand, brandOut); - - // Wrap our underlying notifier with specific quotes. - const specificBaseNotifier = harden({ - async getUpdateSince(updateCount = undefined) { - // We use the same updateCount as our underlying notifier. - const record = await E(notifier).getUpdateSince(updateCount); - - // We create a quote inline. - let quote; - // createQuote can throw if priceAuthority is replaced. - // eslint-disable-next-line no-useless-catch - try { - quote = createQuote(calcAmountOut => ({ - amountIn, - amountOut: calcAmountOut(amountIn), - })); - } catch (e) { - // fall through - } - - if (!quote) { - throw Fail`createQuote returned nothing`; - } - - const value = await quote; - return harden({ - value, - updateCount: record.updateCount, - }); - }, - }); - - /** @type {Notifier} */ - const specificNotifier = Far('QuoteNotifier', { - ...makeNotifier(specificBaseNotifier), - // TODO stop exposing baseNotifier methods directly. - ...specificBaseNotifier, - }); - return specificNotifier; - }, - async quoteGiven(amountIn, brandOut) { - trace('quoteGiven', amountIn, brandOut); - AmountMath.coerce(actualBrandIn, amountIn); - assertBrands(amountIn.brand, brandOut); - - await E(notifier).getUpdateSince(); - const quote = createQuote(calcAmountOut => ({ - amountIn, - amountOut: calcAmountOut(amountIn), - })); - assert(quote); - return quote; - }, - async quoteWanted(brandIn, amountOut) { - AmountMath.coerce(actualBrandOut, amountOut); - assertBrands(brandIn, amountOut.brand); - - await E(notifier).getUpdateSince(); - const quote = createQuote((calcAmountOut, calcAmountIn) => { - // We need to determine an amountIn that guarantees at least the amountOut. - const amountIn = calcAmountIn(amountOut); - const actualAmountOut = calcAmountOut(amountIn); - AmountMath.isGTE(actualAmountOut, amountOut) || - Fail`Calculation of ${actualAmountOut} didn't cover expected ${amountOut}`; - return { amountIn, amountOut }; - }); - assert(quote); - return quote; - }, - async quoteAtTime(deadline, amountIn, brandOut) { - AmountMath.coerce(actualBrandIn, amountIn); - assertBrands(amountIn.brand, brandOut); - - await E(notifier).getUpdateSince(); - const quotePK = makePromiseKit(); - await E(timer).setWakeup( - deadline, - Far('wakeObj', { - async wake(timestamp) { - await null; + const priceAuthority = makeExo( + 'PriceAuthority', + M.interface('PriceAuthority', {}, { defaultGuards: 'passable' }), + { + getQuoteIssuer(brandIn, brandOut) { + assertBrands(brandIn, brandOut); + return quoteIssuer; + }, + getTimerService(brandIn, brandOut) { + assertBrands(brandIn, brandOut); + return timer; + }, + makeQuoteNotifier(amountIn, brandOut) { + AmountMath.coerce(actualBrandIn, amountIn); + assertBrands(amountIn.brand, brandOut); + + // Wrap our underlying notifier with specific quotes. + const specificBaseNotifier = harden({ + async getUpdateSince(updateCount = undefined) { + // We use the same updateCount as our underlying notifier. + const record = await E(notifier).getUpdateSince(updateCount); + + // We create a quote inline. + let quote; + // createQuote can throw if priceAuthority is replaced. + // eslint-disable-next-line no-useless-catch try { - const quoteP = createQuote(calcAmountOut => ({ + quote = createQuote(calcAmountOut => ({ amountIn, amountOut: calcAmountOut(amountIn), - timestamp, })); - - // We don't wait for the quote to be authenticated; resolve - // immediately. - quotePK.resolve(quoteP); - await quotePK.promise; } catch (e) { - quotePK.reject(e); + // fall through + } + + if (!quote) { + throw Fail`createQuote returned nothing`; } - }, - }), - ); - // Wait until the wakeup passes. - return quotePK.promise; + const value = await quote; + return harden({ + value, + updateCount: record.updateCount, + }); + }, + }); + + /** @type {Notifier} */ + const specificNotifier = makeExo( + 'QuoteNotifier', + M.interface('QuoteNotifier', {}, { defaultGuards: 'passable' }), + { + ...makeNotifier(specificBaseNotifier), + // TODO stop exposing baseNotifier methods directly. + ...specificBaseNotifier, + }, + ); + return specificNotifier; + }, + async quoteGiven(amountIn, brandOut) { + trace('quoteGiven', amountIn, brandOut); + AmountMath.coerce(actualBrandIn, amountIn); + assertBrands(amountIn.brand, brandOut); + + await E(notifier).getUpdateSince(); + const quote = createQuote(calcAmountOut => ({ + amountIn, + amountOut: calcAmountOut(amountIn), + })); + assert(quote); + return quote; + }, + async quoteWanted(brandIn, amountOut) { + AmountMath.coerce(actualBrandOut, amountOut); + assertBrands(brandIn, amountOut.brand); + + await E(notifier).getUpdateSince(); + const quote = createQuote((calcAmountOut, calcAmountIn) => { + // We need to determine an amountIn that guarantees at least the amountOut. + const amountIn = calcAmountIn(amountOut); + const actualAmountOut = calcAmountOut(amountIn); + AmountMath.isGTE(actualAmountOut, amountOut) || + Fail`Calculation of ${actualAmountOut} didn't cover expected ${amountOut}`; + return { amountIn, amountOut }; + }); + assert(quote); + return quote; + }, + async quoteAtTime(deadline, amountIn, brandOut) { + AmountMath.coerce(actualBrandIn, amountIn); + assertBrands(amountIn.brand, brandOut); + + await E(notifier).getUpdateSince(); + const quotePK = makePromiseKit(); + await E(timer).setWakeup( + deadline, + makeExo( + 'wakeObj', + M.interface('wakeObj', {}, { defaultGuards: 'passable' }), + { + async wake(timestamp) { + await null; + try { + const quoteP = createQuote(calcAmountOut => ({ + amountIn, + amountOut: calcAmountOut(amountIn), + timestamp, + })); + + // We don't wait for the quote to be authenticated; resolve + // immediately. + quotePK.resolve(quoteP); + await quotePK.promise; + } catch (e) { + quotePK.reject(e); + } + }, + }, + ), + ); + + // Wait until the wakeup passes. + return quotePK.promise; + }, + quoteWhenLT: makeQuoteWhenOut(isLT), + quoteWhenLTE: makeQuoteWhenOut(isLTE), + quoteWhenGTE: makeQuoteWhenOut(isGTE), + quoteWhenGT: makeQuoteWhenOut(isGT), + mutableQuoteWhenLT: makeMutableQuote(isLT), + mutableQuoteWhenLTE: makeMutableQuote(isLTE), + mutableQuoteWhenGT: makeMutableQuote(isGT), + mutableQuoteWhenGTE: makeMutableQuote(isGTE), }, - quoteWhenLT: makeQuoteWhenOut(isLT), - quoteWhenLTE: makeQuoteWhenOut(isLTE), - quoteWhenGTE: makeQuoteWhenOut(isGTE), - quoteWhenGT: makeQuoteWhenOut(isGT), - mutableQuoteWhenLT: makeMutableQuote(isLT), - mutableQuoteWhenLTE: makeMutableQuote(isLTE), - mutableQuoteWhenGT: makeMutableQuote(isGT), - mutableQuoteWhenGTE: makeMutableQuote(isGTE), - }); + ); return { priceAuthority, adminFacet: { fireTriggers } }; }; diff --git a/packages/zoe/src/contractSupport/priceAuthorityInitial.js b/packages/zoe/src/contractSupport/priceAuthorityInitial.js index 9c1178f61c3..f3321199077 100644 --- a/packages/zoe/src/contractSupport/priceAuthorityInitial.js +++ b/packages/zoe/src/contractSupport/priceAuthorityInitial.js @@ -88,11 +88,15 @@ export const makeInitialTransform = ( }); /** @type {Notifier} */ - const farNotifier = Far('QuoteNotifier', { - ...makeNotifier(prefixedNotifier), - // TODO stop exposing baseNotifier methods directly. - ...prefixedNotifier, - }); + const farNotifier = makeExo( + 'QuoteNotifier', + M.interface('QuoteNotifier', {}, { defaultGuards: 'passable' }), + { + ...makeNotifier(prefixedNotifier), + // TODO stop exposing baseNotifier methods directly. + ...prefixedNotifier, + }, + ); return farNotifier; }; @@ -108,9 +112,13 @@ export const makeInitialTransform = ( : quoteP; }; - return Far('PriceAuthority', { - ...priceAuthority, - makeQuoteNotifier, - quoteGiven, - }); + return makeExo( + 'PriceAuthority', + M.interface('PriceAuthority', {}, { defaultGuards: 'passable' }), + { + ...priceAuthority, + makeQuoteNotifier, + quoteGiven, + }, + ); }; diff --git a/packages/zoe/src/contractSupport/priceAuthorityTransform.js b/packages/zoe/src/contractSupport/priceAuthorityTransform.js index de7a8feff13..866a8885859 100644 --- a/packages/zoe/src/contractSupport/priceAuthorityTransform.js +++ b/packages/zoe/src/contractSupport/priceAuthorityTransform.js @@ -160,109 +160,121 @@ export const makePriceAuthorityTransform = async ({ ); /** @type {EOnly} */ - const mutableQuote = Far('MutableQuote', { - cancel: e => E(sourceMutableQuote).cancel(e), - updateLevel: (newAmountIn, newAmountOutLimit) => { - AmountMath.coerce(actualBrandIn, newAmountIn); - AmountMath.coerce(actualBrandOut, newAmountOutLimit); + const mutableQuote = makeExo( + 'MutableQuote', + M.interface('MutableQuote', {}, { defaultGuards: 'passable' }), + { + cancel: e => E(sourceMutableQuote).cancel(e), + updateLevel: (newAmountIn, newAmountOutLimit) => { + AmountMath.coerce(actualBrandIn, newAmountIn); + AmountMath.coerce(actualBrandOut, newAmountOutLimit); - return E(sourceMutableQuote).updateLevel( - makeSourceAmountIn(newAmountIn), - makeSourceAmountOut(newAmountOutLimit), - ); + return E(sourceMutableQuote).updateLevel( + makeSourceAmountIn(newAmountIn), + makeSourceAmountOut(newAmountOutLimit), + ); + }, + getPromise: () => E(sourceMutableQuote).getPromise().then(scaleQuote), }, - getPromise: () => E(sourceMutableQuote).getPromise().then(scaleQuote), - }); + ); return mutableQuote; }; return mutableQuoteWhenOut; }; /** @type {PriceAuthority} */ - const priceAuthority = Far('PriceAuthority', { - getQuoteIssuer(brandIn, brandOut) { - assertBrands(brandIn, brandOut); - return quoteIssuer; - }, - getTimerService(brandIn, brandOut) { - assertBrands(brandIn, brandOut); - return E(sourcePriceAuthority).getTimerService( - sourceBrandIn, - sourceBrandOut, - ); - }, - makeQuoteNotifier(amountIn, brandOut) { - AmountMath.coerce(actualBrandIn, amountIn); - assertBrands(amountIn.brand, brandOut); + const priceAuthority = makeExo( + 'PriceAuthority', + M.interface('PriceAuthority', {}, { defaultGuards: 'passable' }), + { + getQuoteIssuer(brandIn, brandOut) { + assertBrands(brandIn, brandOut); + return quoteIssuer; + }, + getTimerService(brandIn, brandOut) { + assertBrands(brandIn, brandOut); + return E(sourcePriceAuthority).getTimerService( + sourceBrandIn, + sourceBrandOut, + ); + }, + makeQuoteNotifier(amountIn, brandOut) { + AmountMath.coerce(actualBrandIn, amountIn); + assertBrands(amountIn.brand, brandOut); - const notifier = E(sourcePriceAuthority).makeQuoteNotifier( - makeSourceAmountIn(amountIn), - sourceBrandOut, - ); + const notifier = E(sourcePriceAuthority).makeQuoteNotifier( + makeSourceAmountIn(amountIn), + sourceBrandOut, + ); - // Wrap our underlying notifier with scaled quotes. - const scaledBaseNotifier = harden({ - async getUpdateSince(updateCount = undefined) { - // We use the same updateCount as our underlying notifier. - const record = await E(notifier).getUpdateSince(updateCount); + // Wrap our underlying notifier with scaled quotes. + const scaledBaseNotifier = harden({ + async getUpdateSince(updateCount = undefined) { + // We use the same updateCount as our underlying notifier. + const record = await E(notifier).getUpdateSince(updateCount); - const quote = await scaleQuote(record.value); - return harden({ - value: quote, - updateCount: record.updateCount, - }); - }, - }); + const quote = await scaleQuote(record.value); + return harden({ + value: quote, + updateCount: record.updateCount, + }); + }, + }); - /** @type {Notifier} */ - const scaledNotifier = Far('QuoteNotifier', { - ...makeNotifier(scaledBaseNotifier), - // TODO stop exposing baseNotifier methods directly. - ...scaledBaseNotifier, - }); - return scaledNotifier; - }, - async quoteGiven(amountIn, brandOut) { - AmountMath.coerce(actualBrandIn, amountIn); - assertBrands(amountIn.brand, brandOut); + /** @type {Notifier} */ + const scaledNotifier = makeExo( + 'QuoteNotifier', + M.interface('QuoteNotifier', {}, { defaultGuards: 'passable' }), + { + ...makeNotifier(scaledBaseNotifier), + // TODO stop exposing baseNotifier methods directly. + ...scaledBaseNotifier, + }, + ); + return scaledNotifier; + }, + async quoteGiven(amountIn, brandOut) { + AmountMath.coerce(actualBrandIn, amountIn); + assertBrands(amountIn.brand, brandOut); - const sourceQuote = await E(sourcePriceAuthority).quoteGiven( - makeSourceAmountIn(amountIn), - sourceBrandOut, - ); - return scaleQuote(sourceQuote); - }, - async quoteWanted(brandIn, amountOut) { - AmountMath.coerce(actualBrandOut, amountOut); - assertBrands(brandIn, amountOut.brand); + const sourceQuote = await E(sourcePriceAuthority).quoteGiven( + makeSourceAmountIn(amountIn), + sourceBrandOut, + ); + return scaleQuote(sourceQuote); + }, + async quoteWanted(brandIn, amountOut) { + AmountMath.coerce(actualBrandOut, amountOut); + assertBrands(brandIn, amountOut.brand); - const sourceQuote = await E(sourcePriceAuthority).quoteWanted( - sourceBrandIn, - makeSourceAmountOut(amountOut), - ); - return scaleQuote(sourceQuote); - }, - async quoteAtTime(deadline, amountIn, brandOut) { - assert.typeof(deadline, 'bigint'); - AmountMath.coerce(actualBrandIn, amountIn); - assertBrands(amountIn.brand, brandOut); + const sourceQuote = await E(sourcePriceAuthority).quoteWanted( + sourceBrandIn, + makeSourceAmountOut(amountOut), + ); + return scaleQuote(sourceQuote); + }, + async quoteAtTime(deadline, amountIn, brandOut) { + assert.typeof(deadline, 'bigint'); + AmountMath.coerce(actualBrandIn, amountIn); + assertBrands(amountIn.brand, brandOut); - const sourceQuote = await E(sourcePriceAuthority).quoteAtTime( - deadline, - makeSourceAmountIn(amountIn), - sourceBrandOut, - ); - return scaleQuote(sourceQuote); + const sourceQuote = await E(sourcePriceAuthority).quoteAtTime( + deadline, + makeSourceAmountIn(amountIn), + sourceBrandOut, + ); + return scaleQuote(sourceQuote); + }, + quoteWhenLT: makeQuoteWhenOut('quoteWhenLT'), + quoteWhenLTE: makeQuoteWhenOut('quoteWhenLTE'), + quoteWhenGTE: makeQuoteWhenOut('quoteWhenGTE'), + quoteWhenGT: makeQuoteWhenOut('quoteWhenGT'), + mutableQuoteWhenLT: makeMutableQuote('mutableQuoteWhenLT'), + mutableQuoteWhenLTE: makeMutableQuote('mutableQuoteWhenLTE'), + mutableQuoteWhenGT: makeMutableQuote('mutableQuoteWhenGT'), + mutableQuoteWhenGTE: makeMutableQuote('mutableQuoteWhenGTE'), }, - quoteWhenLT: makeQuoteWhenOut('quoteWhenLT'), - quoteWhenLTE: makeQuoteWhenOut('quoteWhenLTE'), - quoteWhenGTE: makeQuoteWhenOut('quoteWhenGTE'), - quoteWhenGT: makeQuoteWhenOut('quoteWhenGT'), - mutableQuoteWhenLT: makeMutableQuote('mutableQuoteWhenLT'), - mutableQuoteWhenLTE: makeMutableQuote('mutableQuoteWhenLTE'), - mutableQuoteWhenGT: makeMutableQuote('mutableQuoteWhenGT'), - mutableQuoteWhenGTE: makeMutableQuote('mutableQuoteWhenGTE'), - }); + ); return priceAuthority; }; diff --git a/packages/zoe/src/contracts/auction/index.js b/packages/zoe/src/contracts/auction/index.js index cfeed7ca0b9..a26c4a9624f 100644 --- a/packages/zoe/src/contracts/auction/index.js +++ b/packages/zoe/src/contracts/auction/index.js @@ -79,12 +79,16 @@ const start = zcf => { E(timeAuthority) .setWakeup( closesAfter, - Far('wakeObj', { - wake: () => { - isClosed = true; - priceLogic.calcWinnerAndClose(zcf, sellSeat, bidSeats); + makeExo( + 'wakeObj', + M.interface('wakeObj', {}, { defaultGuards: 'passable' }), + { + wake: () => { + isClosed = true; + priceLogic.calcWinnerAndClose(zcf, sellSeat, bidSeats); + }, }, - }), + ), ) .catch(err => { console.error( @@ -151,13 +155,21 @@ const start = zcf => { // The bid invitations can only be sent out after the assets to be // auctioned are escrowed. - return Far('offerResult', { makeBidInvitation, getSessionDetails }); + return makeExo( + 'offerResult', + M.interface('offerResult', {}, { defaultGuards: 'passable' }), + { makeBidInvitation, getSessionDetails }, + ); }; - const publicFacet = Far('auctioneerPublicFacet', { - getCurrentBids, - getSessionDetails, - }); + const publicFacet = makeExo( + 'auctioneerPublicFacet', + M.interface('auctioneerPublicFacet', {}, { defaultGuards: 'passable' }), + { + getCurrentBids, + getSessionDetails, + }, + ); const creatorInvitation = zcf.makeInvitation(sell, 'sellAssets'); diff --git a/packages/zoe/src/contracts/automaticRefund.js b/packages/zoe/src/contracts/automaticRefund.js index 1167ff9cecb..d208d65048d 100644 --- a/packages/zoe/src/contracts/automaticRefund.js +++ b/packages/zoe/src/contracts/automaticRefund.js @@ -25,10 +25,14 @@ const start = zcf => { }; const makeRefundInvitation = () => zcf.makeInvitation(refund, 'getRefund'); - const publicFacet = Far('publicFacet', { - getOffersCount: () => offersCount, - makeInvitation: makeRefundInvitation, - }); + const publicFacet = makeExo( + 'publicFacet', + M.interface('publicFacet', {}, { defaultGuards: 'passable' }), + { + getOffersCount: () => offersCount, + makeInvitation: makeRefundInvitation, + }, + ); const creatorInvitation = makeRefundInvitation(); diff --git a/packages/zoe/src/contracts/autoswap.js b/packages/zoe/src/contracts/autoswap.js index 1b9f58f40a3..6ddac036ae0 100644 --- a/packages/zoe/src/contracts/autoswap.js +++ b/packages/zoe/src/contracts/autoswap.js @@ -376,18 +376,22 @@ const start = async zcf => { const getPoolAllocation = () => poolSeat.getCurrentAllocation(); /** @type {AutoswapPublicFacet} */ - const publicFacet = Far('publicFacet', { - getInputPrice: getOutputForGivenInput, - getOutputPrice: getInputForGivenOutput, - getLiquidityIssuer: () => liquidityIssuer, - getLiquiditySupply: () => liqTokenSupply, - getPoolAllocation, - makeSwapInvitation: makeSwapInInvitation, - makeSwapInInvitation, - makeSwapOutInvitation, - makeAddLiquidityInvitation, - makeRemoveLiquidityInvitation, - }); + const publicFacet = makeExo( + 'publicFacet', + M.interface('publicFacet', {}, { defaultGuards: 'passable' }), + { + getInputPrice: getOutputForGivenInput, + getOutputPrice: getInputForGivenOutput, + getLiquidityIssuer: () => liquidityIssuer, + getLiquiditySupply: () => liqTokenSupply, + getPoolAllocation, + makeSwapInvitation: makeSwapInInvitation, + makeSwapInInvitation, + makeSwapOutInvitation, + makeAddLiquidityInvitation, + makeRemoveLiquidityInvitation, + }, + ); return harden({ publicFacet }); }; diff --git a/packages/zoe/src/contracts/barterExchange.js b/packages/zoe/src/contracts/barterExchange.js index 5320359e212..701edb9d5aa 100644 --- a/packages/zoe/src/contracts/barterExchange.js +++ b/packages/zoe/src/contracts/barterExchange.js @@ -121,9 +121,14 @@ const start = zcf => { return 'Trade completed.'; }; - const publicFacet = Far('publicFacet', { - makeInvitation: () => zcf.makeInvitation(exchangeOfferHandler, 'exchange'), - }); + const publicFacet = makeExo( + 'publicFacet', + M.interface('publicFacet', {}, { defaultGuards: 'passable' }), + { + makeInvitation: () => + zcf.makeInvitation(exchangeOfferHandler, 'exchange'), + }, + ); return { publicFacet }; }; diff --git a/packages/zoe/src/contracts/callSpread/pricedCallSpread.js b/packages/zoe/src/contracts/callSpread/pricedCallSpread.js index 9d4da2aa319..90cdebca2bb 100644 --- a/packages/zoe/src/contracts/callSpread/pricedCallSpread.js +++ b/packages/zoe/src/contracts/callSpread/pricedCallSpread.js @@ -166,7 +166,11 @@ const start = zcf => { return { longInvitation, shortInvitation }; } - const creatorFacet = Far('creatorFacet', { makeInvitationPair }); + const creatorFacet = makeExo( + 'creatorFacet', + M.interface('creatorFacet', {}, { defaultGuards: 'passable' }), + { makeInvitationPair }, + ); return harden({ creatorFacet }); }; diff --git a/packages/zoe/src/contracts/loan/borrow.js b/packages/zoe/src/contracts/loan/borrow.js index f24a039ed26..38ce0ad87f8 100644 --- a/packages/zoe/src/contracts/loan/borrow.js +++ b/packages/zoe/src/contracts/loan/borrow.js @@ -127,17 +127,21 @@ export const makeBorrowInvitation = (zcf, config) => { // TODO: Add ability to repay partially /** @type {BorrowFacet} */ - const borrowFacet = Far('borrowFacet', { - makeCloseLoanInvitation: () => - makeCloseLoanInvitation(zcf, configWithBorrower), - makeAddCollateralInvitation: () => - makeAddCollateralInvitation(zcf, configWithBorrower), - getLiquidationPromise: () => liquidationPromiseKit.promise, - getDebtNotifier, - getLastCalculationTimestamp, - getRecentCollateralAmount: () => - collateralSeat.getAmountAllocated('Collateral'), - }); + const borrowFacet = makeExo( + 'borrowFacet', + M.interface('borrowFacet', {}, { defaultGuards: 'passable' }), + { + makeCloseLoanInvitation: () => + makeCloseLoanInvitation(zcf, configWithBorrower), + makeAddCollateralInvitation: () => + makeAddCollateralInvitation(zcf, configWithBorrower), + getLiquidationPromise: () => liquidationPromiseKit.promise, + getDebtNotifier, + getLastCalculationTimestamp, + getRecentCollateralAmount: () => + collateralSeat.getAmountAllocated('Collateral'), + }, + ); return borrowFacet; }; diff --git a/packages/zoe/src/contracts/loan/updateDebt.js b/packages/zoe/src/contracts/loan/updateDebt.js index 94c4678e405..5753f16dcc3 100644 --- a/packages/zoe/src/contracts/loan/updateDebt.js +++ b/packages/zoe/src/contracts/loan/updateDebt.js @@ -44,39 +44,43 @@ export const makeDebtCalculator = debtCalculatorConfig => { const config = { ...configMinusGetDebt, getDebt }; - const periodObserver = Far('periodObserver', { - /** @type {(timestamp: import('@agoric/time').TimestampRecord) => void} */ - updateState: timestamp => { - let updatedLoan = false; - // we could calculate the number of required updates and multiply by a power - // of the interest rate, but this seems easier to read. - while ( - TimeMath.compareAbs( - TimeMath.addAbsRel(lastCalculationTimestamp, interestPeriod), - timestamp, - ) <= 0 - ) { - lastCalculationTimestamp = TimeMath.addAbsRel( - lastCalculationTimestamp, - interestPeriod, + const periodObserver = makeExo( + 'periodObserver', + M.interface('periodObserver', {}, { defaultGuards: 'passable' }), + { + /** @type {(timestamp: import('@agoric/time').TimestampRecord) => void} */ + updateState: timestamp => { + let updatedLoan = false; + // we could calculate the number of required updates and multiply by a power + // of the interest rate, but this seems easier to read. + while ( + TimeMath.compareAbs( + TimeMath.addAbsRel(lastCalculationTimestamp, interestPeriod), + timestamp, + ) <= 0 + ) { + lastCalculationTimestamp = TimeMath.addAbsRel( + lastCalculationTimestamp, + interestPeriod, + ); + const interest = calcInterestFn(debt, interestRate); + debt = AmountMath.add(debt, interest); + updatedLoan = true; + } + if (updatedLoan) { + debtNotifierUpdater.updateState(debt); + scheduleLiquidation(zcf, config); + } + }, + fail: reason => { + assert.note( + reason, + X`Period problem: ${originalDebt}, started: ${basetime}, debt: ${debt}`, ); - const interest = calcInterestFn(debt, interestRate); - debt = AmountMath.add(debt, interest); - updatedLoan = true; - } - if (updatedLoan) { - debtNotifierUpdater.updateState(debt); - scheduleLiquidation(zcf, config); - } + console.error(reason); + }, }, - fail: reason => { - assert.note( - reason, - X`Period problem: ${originalDebt}, started: ${basetime}, debt: ${debt}`, - ); - console.error(reason); - }, - }); + ); observeNotifier(periodNotifier, periodObserver).catch(reason => { assert.note( @@ -88,9 +92,13 @@ export const makeDebtCalculator = debtCalculatorConfig => { debtNotifierUpdater.updateState(debt); - return Far('debtCalculator', { - getDebt, - getLastCalculationTimestamp: _ => lastCalculationTimestamp, - getDebtNotifier: _ => debtNotifier, - }); + return makeExo( + 'debtCalculator', + M.interface('debtCalculator', {}, { defaultGuards: 'passable' }), + { + getDebt, + getLastCalculationTimestamp: _ => lastCalculationTimestamp, + getDebtNotifier: _ => debtNotifier, + }, + ); }; diff --git a/packages/zoe/src/contracts/mintAndSellNFT.js b/packages/zoe/src/contracts/mintAndSellNFT.js index ae8f7863239..6b22063159f 100644 --- a/packages/zoe/src/contracts/mintAndSellNFT.js +++ b/packages/zoe/src/contracts/mintAndSellNFT.js @@ -111,10 +111,14 @@ const start = zcf => { }; /** @type {MintAndSellNFTCreatorFacet} */ - const creatorFacet = Far('creatorFacet', { - sellTokens, - getIssuer: () => issuer, - }); + const creatorFacet = makeExo( + 'creatorFacet', + M.interface('creatorFacet', {}, { defaultGuards: 'passable' }), + { + sellTokens, + getIssuer: () => issuer, + }, + ); return harden({ creatorFacet }); }; diff --git a/packages/zoe/src/contracts/mintPayments.js b/packages/zoe/src/contracts/mintPayments.js index 8536abaef6d..f9dd8a9c569 100644 --- a/packages/zoe/src/contracts/mintPayments.js +++ b/packages/zoe/src/contracts/mintPayments.js @@ -37,19 +37,27 @@ const start = async zcf => { return 'Offer completed. You should receive a payment from Zoe'; }; - const creatorFacet = Far('creatorFacet', { - // The creator of the instance can send invitations to anyone - // they wish to. - makeInvitation: (value = 1000n) => - zcf.makeInvitation(mintPayment(value), 'mint a payment'), - getTokenIssuer: () => issuer, - }); + const creatorFacet = makeExo( + 'creatorFacet', + M.interface('creatorFacet', {}, { defaultGuards: 'passable' }), + { + // The creator of the instance can send invitations to anyone + // they wish to. + makeInvitation: (value = 1000n) => + zcf.makeInvitation(mintPayment(value), 'mint a payment'), + getTokenIssuer: () => issuer, + }, + ); - const publicFacet = Far('publicFacet', { - // Make the token issuer public. Note that only the mint can - // make new digital assets. The issuer is ok to make public. - getTokenIssuer: () => issuer, - }); + const publicFacet = makeExo( + 'publicFacet', + M.interface('publicFacet', {}, { defaultGuards: 'passable' }), + { + // Make the token issuer public. Note that only the mint can + // make new digital assets. The issuer is ok to make public. + getTokenIssuer: () => issuer, + }, + ); // Return the creatorFacet to the creator, so they can make // invitations for others to get payments of tokens. Publish the diff --git a/packages/zoe/src/contracts/oracle.js b/packages/zoe/src/contracts/oracle.js index e7efd817506..808a50d705b 100644 --- a/packages/zoe/src/contracts/oracle.js +++ b/packages/zoe/src/contracts/oracle.js @@ -24,79 +24,91 @@ const start = async zcf => { const { zcfSeat: feeSeat } = zcf.makeEmptySeatKit(); /** @type {OracleCreatorFacet} */ - const realCreatorFacet = Far('realCreatorFacet', { - makeWithdrawInvitation(total = false) { - return zcf.makeInvitation(seat => { - const gains = total - ? feeSeat.getCurrentAllocation() - : seat.getProposal().want; + const realCreatorFacet = makeExo( + 'realCreatorFacet', + M.interface('realCreatorFacet', {}, { defaultGuards: 'passable' }), + { + makeWithdrawInvitation(total = false) { + return zcf.makeInvitation(seat => { + const gains = total + ? feeSeat.getCurrentAllocation() + : seat.getProposal().want; - atomicTransfer(zcf, feeSeat, seat, gains); + atomicTransfer(zcf, feeSeat, seat, gains); - seat.exit(); - return 'Successfully withdrawn'; - }, 'withdraw'); - }, - getCurrentFees() { - return feeSeat.getCurrentAllocation(); - }, - makeShutdownInvitation: () => { - const shutdown = seat => { - revoked = true; - atomicTransfer(zcf, feeSeat, seat, feeSeat.getCurrentAllocation()); + seat.exit(); + return 'Successfully withdrawn'; + }, 'withdraw'); + }, + getCurrentFees() { + return feeSeat.getCurrentAllocation(); + }, + makeShutdownInvitation: () => { + const shutdown = seat => { + revoked = true; + atomicTransfer(zcf, feeSeat, seat, feeSeat.getCurrentAllocation()); - zcf.shutdown(revokedMsg); - }; - return zcf.makeInvitation(shutdown, 'shutdown'); + zcf.shutdown(revokedMsg); + }; + return zcf.makeInvitation(shutdown, 'shutdown'); + }, }, - }); + ); - const creatorFacet = Far('creatorFacet', { - initialize(privateParams) { - ({ oracleHandler: handler } = privateParams); - return realCreatorFacet; + const creatorFacet = makeExo( + 'creatorFacet', + M.interface('creatorFacet', {}, { defaultGuards: 'passable' }), + { + initialize(privateParams) { + ({ oracleHandler: handler } = privateParams); + return realCreatorFacet; + }, }, - }); + ); - const publicFacet = Far('publicFacet', { - /** @param {OracleQuery} query */ - async query(query) { - await null; - try { - assert(!revoked, revokedMsg); - const noFee = AmountMath.makeEmpty(feeBrand); - const { requiredFee, reply } = await E(handler).onQuery(query, noFee); - !requiredFee || - AmountMath.isGTE(noFee, requiredFee) || - Fail`Oracle required a fee but the query had none`; - return reply; - } catch (e) { - E(handler).onError(query, e); - throw e; - } - }, - /** @param {OracleQuery} query */ - async makeQueryInvitation(query) { - /** @type {OfferHandler} */ - const doQuery = async querySeat => { + const publicFacet = makeExo( + 'publicFacet', + M.interface('publicFacet', {}, { defaultGuards: 'passable' }), + { + /** @param {OracleQuery} query */ + async query(query) { await null; try { - const fee = querySeat.getAmountAllocated('Fee', feeBrand); - const { requiredFee, reply } = await E(handler).onQuery(query, fee); - if (requiredFee) { - atomicTransfer(zcf, querySeat, feeSeat, { Fee: requiredFee }); - } - querySeat.exit(); - E(handler).onReply(query, reply, requiredFee); + assert(!revoked, revokedMsg); + const noFee = AmountMath.makeEmpty(feeBrand); + const { requiredFee, reply } = await E(handler).onQuery(query, noFee); + !requiredFee || + AmountMath.isGTE(noFee, requiredFee) || + Fail`Oracle required a fee but the query had none`; return reply; } catch (e) { E(handler).onError(query, e); throw e; } - }; - return zcf.makeInvitation(doQuery, 'oracle query', { query }); + }, + /** @param {OracleQuery} query */ + async makeQueryInvitation(query) { + /** @type {OfferHandler} */ + const doQuery = async querySeat => { + await null; + try { + const fee = querySeat.getAmountAllocated('Fee', feeBrand); + const { requiredFee, reply } = await E(handler).onQuery(query, fee); + if (requiredFee) { + atomicTransfer(zcf, querySeat, feeSeat, { Fee: requiredFee }); + } + querySeat.exit(); + E(handler).onReply(query, reply, requiredFee); + return reply; + } catch (e) { + E(handler).onError(query, e); + throw e; + } + }; + return zcf.makeInvitation(doQuery, 'oracle query', { query }); + }, }, - }); + ); return harden({ creatorFacet, publicFacet }); }; diff --git a/packages/zoe/src/contracts/otcDesk.js b/packages/zoe/src/contracts/otcDesk.js index 6259dfa1791..e255969ac9a 100644 --- a/packages/zoe/src/contracts/otcDesk.js +++ b/packages/zoe/src/contracts/otcDesk.js @@ -112,30 +112,34 @@ const start = zcf => { return 'Inventory removed'; }; - const creatorFacet = Far('creatorFacet', { - /** - * The inventory can be added in bulk before any quotes are made - * or can be added immediately before a quote. - * - * @param {IssuerKeywordRecord} [issuerKeywordRecord] - * @returns {Promise} - */ - makeAddInventoryInvitation: async (issuerKeywordRecord = harden({})) => { - await saveAllIssuers(zcf, issuerKeywordRecord); - return zcf.makeInvitation(addInventory, 'addInventory'); - }, - /** - * The inventory can be removed at any time, since the inventory - * used for active quotes is escrowed separately within the coveredCall - * instance. - * - * @returns {Promise} - */ - makeRemoveInventoryInvitation: () => { - return zcf.makeInvitation(removeInventory, 'removeInventory'); + const creatorFacet = makeExo( + 'creatorFacet', + M.interface('creatorFacet', {}, { defaultGuards: 'passable' }), + { + /** + * The inventory can be added in bulk before any quotes are made + * or can be added immediately before a quote. + * + * @param {IssuerKeywordRecord} [issuerKeywordRecord] + * @returns {Promise} + */ + makeAddInventoryInvitation: async (issuerKeywordRecord = harden({})) => { + await saveAllIssuers(zcf, issuerKeywordRecord); + return zcf.makeInvitation(addInventory, 'addInventory'); + }, + /** + * The inventory can be removed at any time, since the inventory + * used for active quotes is escrowed separately within the coveredCall + * instance. + * + * @returns {Promise} + */ + makeRemoveInventoryInvitation: () => { + return zcf.makeInvitation(removeInventory, 'removeInventory'); + }, + makeQuote, }, - makeQuote, - }); + ); return harden({ creatorFacet }); }; diff --git a/packages/zoe/src/contracts/priceAggregator.js b/packages/zoe/src/contracts/priceAggregator.js index 11e9d0701fe..6b260398c25 100644 --- a/packages/zoe/src/contracts/priceAggregator.js +++ b/packages/zoe/src/contracts/priceAggregator.js @@ -143,23 +143,27 @@ const start = async (zcf, privateArgs) => { // Wake every POLL_INTERVAL and run the queriers. const repeaterP = E(timer).makeRepeater(0n, POLL_INTERVAL); /** @type {import('@agoric/time').TimerWaker} */ - const waker = Far('waker', { - async wake(timestamp) { - // Run all the queriers. - const querierPs = []; - oracleRecords.forEach(({ querier }) => { - if (querier) { - querierPs.push(querier(timestamp)); + const waker = makeExo( + 'waker', + M.interface('waker', {}, { defaultGuards: 'passable' }), + { + async wake(timestamp) { + // Run all the queriers. + const querierPs = []; + oracleRecords.forEach(({ querier }) => { + if (querier) { + querierPs.push(querier(timestamp)); + } + }); + if (!querierPs.length) { + // Only have push results, so publish them. + // eslint-disable-next-line no-use-before-define + querierPs.push(updateQuote(timestamp)); } - }); - if (!querierPs.length) { - // Only have push results, so publish them. - // eslint-disable-next-line no-use-before-define - querierPs.push(updateQuote(timestamp)); - } - await Promise.all(querierPs).catch(console.error); + await Promise.all(querierPs).catch(console.error); + }, }, - }); + ); E(repeaterP).schedule(waker); /** @@ -428,206 +432,236 @@ const start = async (zcf, privateArgs) => { E(oracleNotifier).getUpdateSince().then(recurse); }; - const creatorFacet = Far('PriceAggregatorCreatorFacet', { - /** - * An "oracle invitation" is an invitation to be able to submit data to - * include in the priceAggregator's results. - * - * The offer result from this invitation is a OracleAdmin, which can be used - * directly to manage the price submissions as well as to terminate the - * relationship. - * - * @param {Instance | string} [oracleKey] - */ - makeOracleInvitation: async oracleKey => { + const creatorFacet = makeExo( + 'PriceAggregatorCreatorFacet', + M.interface( + 'PriceAggregatorCreatorFacet', + {}, + { defaultGuards: 'passable' }, + ), + { /** - * If custom arguments are supplied to the `zoe.offer` call, they can - * indicate an OraclePriceSubmission notifier and a corresponding - * `shiftValueOut` that should be adapted as part of the priceAuthority's - * reported data. + * An "oracle invitation" is an invitation to be able to submit data to + * include in the priceAggregator's results. * - * @param {ZCFSeat} seat - * @param {object} param1 - * @param {Notifier} [param1.notifier] optional notifier that produces oracle price submissions - * @param {number} [param1.scaleValueOut] - * @returns {Promise<{admin: OracleAdmin, invitationMakers: {PushPrice: (price: ParsableNumber) => Promise>} }>} + * The offer result from this invitation is a OracleAdmin, which can be used + * directly to manage the price submissions as well as to terminate the + * relationship. + * + * @param {Instance | string} [oracleKey] */ - const offerHandler = async ( - seat, - { notifier: oracleNotifier, scaleValueOut = 1 } = {}, - ) => { - seat.exit(); - const admin = await creatorFacet.initOracle(oracleKey); - const invitationMakers = Far('invitation makers', { - /** @param {ParsableNumber} price */ - PushPrice(price) { - assertParsableNumber(price); - return zcf.makeInvitation(cSeat => { - cSeat.exit(); - admin.pushResult(price); - }, 'PushPrice'); - }, - }); - - if (oracleNotifier) { - pushFromOracle(oracleNotifier, scaleValueOut, r => - admin.pushResult(r), - ); - } - - return harden({ - admin: Far('oracleAdmin', { - ...admin, - /** @override */ - delete: async () => { - // Stop tracking the notifier on delete. - oracleNotifier = undefined; - return admin.delete(); + makeOracleInvitation: async oracleKey => { + /** + * If custom arguments are supplied to the `zoe.offer` call, they can + * indicate an OraclePriceSubmission notifier and a corresponding + * `shiftValueOut` that should be adapted as part of the priceAuthority's + * reported data. + * + * @param {ZCFSeat} seat + * @param {object} param1 + * @param {Notifier} [param1.notifier] optional notifier that produces oracle price submissions + * @param {number} [param1.scaleValueOut] + * @returns {Promise<{admin: OracleAdmin, invitationMakers: {PushPrice: (price: ParsableNumber) => Promise>} }>} + */ + const offerHandler = async ( + seat, + { notifier: oracleNotifier, scaleValueOut = 1 } = {}, + ) => { + seat.exit(); + const admin = await creatorFacet.initOracle(oracleKey); + const invitationMakers = makeExo( + 'invitation makers', + M.interface('invitation makers', {}, { defaultGuards: 'passable' }), + { + /** @param {ParsableNumber} price */ + PushPrice(price) { + assertParsableNumber(price); + return zcf.makeInvitation(cSeat => { + cSeat.exit(); + admin.pushResult(price); + }, 'PushPrice'); + }, }, - }), - - invitationMakers, - }); - }; - - return zcf.makeInvitation(offerHandler, 'oracle invitation'); - }, - /** @param {OracleKey} oracleKey */ - deleteOracle: async oracleKey => { - for (const record of instanceToRecords.get(oracleKey)) { - oracleRecords.delete(record); - } + ); - // We should remove the entry entirely, as it is empty. - instanceToRecords.delete(oracleKey); + if (oracleNotifier) { + pushFromOracle(oracleNotifier, scaleValueOut, r => + admin.pushResult(r), + ); + } - // Delete complete, so try asynchronously updating the quote. - const deletedNow = await E(timer).getCurrentTimestamp(); - await updateQuote(deletedNow); - }, - /** - * @param {Instance | string} [oracleInstance] - * @param {OracleQuery} [query] - * @returns {Promise>} - */ - initOracle: async (oracleInstance, query) => { - /** @type {OracleKey} */ - const oracleKey = oracleInstance || Far('fresh key', {}); - - /** @type {OracleRecord} */ - const record = { - oracleKey, - lastSample: makeRatio(0n, brandOut, 1n, brandIn), - }; + return harden({ + admin: makeExo( + 'oracleAdmin', + M.interface('oracleAdmin', {}, { defaultGuards: 'passable' }), + { + ...admin, + /** @override */ + delete: async () => { + // Stop tracking the notifier on delete. + oracleNotifier = undefined; + return admin.delete(); + }, + }, + ), + + invitationMakers, + }); + }; + + return zcf.makeInvitation(offerHandler, 'oracle invitation'); + }, + /** @param {OracleKey} oracleKey */ + deleteOracle: async oracleKey => { + for (const record of instanceToRecords.get(oracleKey)) { + oracleRecords.delete(record); + } - /** @type {Set} */ - let records; - if (instanceToRecords.has(oracleKey)) { - records = instanceToRecords.get(oracleKey); - } else { - records = new Set(); - instanceToRecords.init(oracleKey, records); - } - records.add(record); - oracleRecords.add(record); + // We should remove the entry entirely, as it is empty. + instanceToRecords.delete(oracleKey); + // Delete complete, so try asynchronously updating the quote. + const deletedNow = await E(timer).getCurrentTimestamp(); + await updateQuote(deletedNow); + }, /** - * Push the current price ratio. - * - * @param {ParsableNumber | Ratio} result + * @param {Instance | string} [oracleInstance] + * @param {OracleQuery} [query] + * @returns {Promise>} */ - const pushResult = result => { - // Sample of NaN, 0, or negative numbers get culled in the median - // calculation. - /** @type {Ratio | undefined} */ - let ratio; - if (typeof result === 'object') { - ratio = makeRatioFromAmounts(result.numerator, result.denominator); - AmountMath.coerce(brandOut, ratio.numerator); - AmountMath.coerce(brandIn, ratio.denominator); + initOracle: async (oracleInstance, query) => { + /** @type {OracleKey} */ + const oracleKey = + oracleInstance || + makeExo( + 'fresh key', + M.interface('fresh key', {}, { defaultGuards: 'passable' }), + {}, + ); + + /** @type {OracleRecord} */ + const record = { + oracleKey, + lastSample: makeRatio(0n, brandOut, 1n, brandIn), + }; + + /** @type {Set} */ + let records; + if (instanceToRecords.has(oracleKey)) { + records = instanceToRecords.get(oracleKey); } else { - ratio = makeRatioFromData(result); + records = new Set(); + instanceToRecords.init(oracleKey, records); } - record.lastSample = ratio; - }; + records.add(record); + oracleRecords.add(record); + + /** + * Push the current price ratio. + * + * @param {ParsableNumber | Ratio} result + */ + const pushResult = result => { + // Sample of NaN, 0, or negative numbers get culled in the median + // calculation. + /** @type {Ratio | undefined} */ + let ratio; + if (typeof result === 'object') { + ratio = makeRatioFromAmounts(result.numerator, result.denominator); + AmountMath.coerce(brandOut, ratio.numerator); + AmountMath.coerce(brandIn, ratio.denominator); + } else { + ratio = makeRatioFromData(result); + } + record.lastSample = ratio; + }; + + /** @type {OracleAdmin} */ + const oracleAdmin = makeExo( + 'OracleAdmin', + M.interface('OracleAdmin', {}, { defaultGuards: 'passable' }), + { + async delete() { + assert(records.has(record), 'Oracle record is already deleted'); + + // The actual deletion is synchronous. + oracleRecords.delete(record); + records.delete(record); + + if ( + records.size === 0 && + instanceToRecords.has(oracleKey) && + instanceToRecords.get(oracleKey) === records + ) { + // We should remove the entry entirely, as it is empty. + instanceToRecords.delete(oracleKey); + } + + // Delete complete, so try asynchronously updating the quote. + const deletedNow = await E(timer).getCurrentTimestamp(); + await updateQuote(deletedNow); + }, + async pushResult(result) { + // Sample of NaN, 0, or negative numbers get culled in + // the median calculation. + pushResult(result); + }, + }, + ); - /** @type {OracleAdmin} */ - const oracleAdmin = Far('OracleAdmin', { - async delete() { - assert(records.has(record), 'Oracle record is already deleted'); + if (query === undefined || typeof oracleInstance === 'string') { + // They don't want to be polled. + return oracleAdmin; + } - // The actual deletion is synchronous. - oracleRecords.delete(record); - records.delete(record); - - if ( - records.size === 0 && - instanceToRecords.has(oracleKey) && - instanceToRecords.get(oracleKey) === records - ) { - // We should remove the entry entirely, as it is empty. - instanceToRecords.delete(oracleKey); + // Obtain the oracle's publicFacet. + assert(oracleInstance); + /** @type {import('./oracle.js').OracleContract['publicFacet']} */ + const oracle = await E(zoe).getPublicFacet(oracleInstance); + assert(records.has(record), 'Oracle record is already deleted'); + + /** @type {import('@agoric/time').Timestamp} */ + let lastWakeTimestamp = 0n; + + /** + * @param {import('@agoric/time').Timestamp} timestamp + */ + record.querier = async timestamp => { + // Submit the query. + const result = await E(oracle).query(query); + assertParsableNumber(result); + // Now that we've received the result, check if we're out of date. + if (timestamp < lastWakeTimestamp || !records.has(record)) { + return; } + lastWakeTimestamp = timestamp; - // Delete complete, so try asynchronously updating the quote. - const deletedNow = await E(timer).getCurrentTimestamp(); - await updateQuote(deletedNow); - }, - async pushResult(result) { - // Sample of NaN, 0, or negative numbers get culled in - // the median calculation. pushResult(result); - }, - }); + await updateQuote(timestamp); + }; + const now = await E(timer).getCurrentTimestamp(); + await record.querier(now); - if (query === undefined || typeof oracleInstance === 'string') { - // They don't want to be polled. + // Return the oracle admin object. return oracleAdmin; - } - - // Obtain the oracle's publicFacet. - assert(oracleInstance); - /** @type {import('./oracle.js').OracleContract['publicFacet']} */ - const oracle = await E(zoe).getPublicFacet(oracleInstance); - assert(records.has(record), 'Oracle record is already deleted'); - - /** @type {import('@agoric/time').Timestamp} */ - let lastWakeTimestamp = 0n; - - /** - * @param {import('@agoric/time').Timestamp} timestamp - */ - record.querier = async timestamp => { - // Submit the query. - const result = await E(oracle).query(query); - assertParsableNumber(result); - // Now that we've received the result, check if we're out of date. - if (timestamp < lastWakeTimestamp || !records.has(record)) { - return; - } - lastWakeTimestamp = timestamp; - - pushResult(result); - await updateQuote(timestamp); - }; - const now = await E(timer).getCurrentTimestamp(); - await record.querier(now); - - // Return the oracle admin object. - return oracleAdmin; + }, }, - }); + ); - const publicFacet = Far('publicFacet', { - getPriceAuthority() { - return priceAuthority; - }, - getSubscriber: () => subscriber, - /** Diagnostic tool */ - async getRoundCompleteNotifier() { - return roundCompleteNotifier; + const publicFacet = makeExo( + 'publicFacet', + M.interface('publicFacet', {}, { defaultGuards: 'passable' }), + { + getPriceAuthority() { + return priceAuthority; + }, + getSubscriber: () => subscriber, + /** Diagnostic tool */ + async getRoundCompleteNotifier() { + return roundCompleteNotifier; + }, }, - }); + ); return harden({ creatorFacet, publicFacet }); }; diff --git a/packages/zoe/src/contracts/sellItems.js b/packages/zoe/src/contracts/sellItems.js index 5aa7a757409..9c5236bbd5d 100644 --- a/packages/zoe/src/contracts/sellItems.js +++ b/packages/zoe/src/contracts/sellItems.js @@ -138,19 +138,27 @@ const start = zcf => { }; /** @type {SellItemsPublicFacet} */ - const publicFacet = Far('SellItemsPublicFacet', { - getAvailableItems, - getAvailableItemsNotifier, - getItemsIssuer: () => issuers.Items, - makeBuyerInvitation, - }); + const publicFacet = makeExo( + 'SellItemsPublicFacet', + M.interface('SellItemsPublicFacet', {}, { defaultGuards: 'passable' }), + { + getAvailableItems, + getAvailableItemsNotifier, + getItemsIssuer: () => issuers.Items, + makeBuyerInvitation, + }, + ); /** @type {SellItemsCreatorFacet} */ - const creatorFacet = Far('SellItemsCreatorFacet', { - makeBuyerInvitation, - getAvailableItems: publicFacet.getAvailableItems, - getItemsIssuer: publicFacet.getItemsIssuer, - }); + const creatorFacet = makeExo( + 'SellItemsCreatorFacet', + M.interface('SellItemsCreatorFacet', {}, { defaultGuards: 'passable' }), + { + makeBuyerInvitation, + getAvailableItems: publicFacet.getAvailableItems, + getItemsIssuer: publicFacet.getItemsIssuer, + }, + ); const creatorInvitation = zcf.makeInvitation(sell, 'seller'); diff --git a/packages/zoe/src/contracts/simpleExchange.js b/packages/zoe/src/contracts/simpleExchange.js index 46915503549..00c4940f127 100644 --- a/packages/zoe/src/contracts/simpleExchange.js +++ b/packages/zoe/src/contracts/simpleExchange.js @@ -131,10 +131,14 @@ const start = zcf => { const makeExchangeInvitation = () => zcf.makeInvitation(exchangeOfferHandler, 'exchange'); - const publicFacet = Far('SimpleExchangePublicFacet', { - makeInvitation: makeExchangeInvitation, - getNotifier: () => notifier, - }); + const publicFacet = makeExo( + 'SimpleExchangePublicFacet', + M.interface('SimpleExchangePublicFacet', {}, { defaultGuards: 'passable' }), + { + makeInvitation: makeExchangeInvitation, + getNotifier: () => notifier, + }, + ); // set the initial state of the notifier bookOrdersChanged(); diff --git a/packages/zoe/test/privateArgsUsageContract.js b/packages/zoe/test/privateArgsUsageContract.js index b3be8fa8d2b..a8729a279f0 100644 --- a/packages/zoe/test/privateArgsUsageContract.js +++ b/packages/zoe/test/privateArgsUsageContract.js @@ -3,9 +3,13 @@ import { Far } from '@endo/marshal'; /** @type {ContractStartFn} */ const start = (_zcf, privateArgs) => { - const creatorFacet = Far('creatorFacet', { - usePrivateArgs: () => E(privateArgs.myArg).doTest(), - }); + const creatorFacet = makeExo( + 'creatorFacet', + M.interface('creatorFacet', {}, { defaultGuards: 'passable' }), + { + usePrivateArgs: () => E(privateArgs.myArg).doTest(), + }, + ); // @ts-expect-error missing publicFacet for ContractStartFn return harden({ creatorFacet }); }; diff --git a/packages/zoe/test/runMintContract.js b/packages/zoe/test/runMintContract.js index ab851e78167..c26c3b7d943 100644 --- a/packages/zoe/test/runMintContract.js +++ b/packages/zoe/test/runMintContract.js @@ -11,14 +11,18 @@ const start = async (zcf, privateArgs) => { const run10 = AmountMath.make(runMint.getIssuerRecord().brand, 10n); - const creatorFacet = Far('creatorFacet', { - mintRun: () => { - const { zcfSeat, userSeat } = zcf.makeEmptySeatKit(); - runMint.mintGains(harden({ RUN: run10 }), zcfSeat); - zcfSeat.exit(); - return E(userSeat).getPayout('RUN'); + const creatorFacet = makeExo( + 'creatorFacet', + M.interface('creatorFacet', {}, { defaultGuards: 'passable' }), + { + mintRun: () => { + const { zcfSeat, userSeat } = zcf.makeEmptySeatKit(); + runMint.mintGains(harden({ RUN: run10 }), zcfSeat); + zcfSeat.exit(); + return E(userSeat).getPayout('RUN'); + }, }, - }); + ); return harden({ creatorFacet }); }; harden(start); diff --git a/packages/zoe/test/swingsetTests/brokenContracts/bootstrap.js b/packages/zoe/test/swingsetTests/brokenContracts/bootstrap.js index f29b387c32d..e27b69ab1f6 100644 --- a/packages/zoe/test/swingsetTests/brokenContracts/bootstrap.js +++ b/packages/zoe/test/swingsetTests/brokenContracts/bootstrap.js @@ -36,33 +36,38 @@ const makeVats = (log, vats, zoe, installations, startingValues) => { export function buildRootObject(vatPowers, vatParameters) { const { D } = vatPowers; - return Far('root', { - async bootstrap(vats, devices) { - const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, - ); - /** @type {{zoeService: ERef}} */ - const { zoeService: zoe } = await E(vats.zoe).buildZoe( - vatAdminSvc, - undefined, - 'zcf', - ); - const bcap = await E(vatAdminSvc).getNamedBundleCap('crashingAutoRefund'); - const id = D(bcap).getBundleID(); - const installations = { - crashAutoRefund: await E(zoe).installBundleID(id), - }; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + /** @type {{zoeService: ERef}} */ + const { zoeService: zoe } = await E(vats.zoe).buildZoe( + vatAdminSvc, + undefined, + 'zcf', + ); + const bcap = + await E(vatAdminSvc).getNamedBundleCap('crashingAutoRefund'); + const id = D(bcap).getBundleID(); + const installations = { + crashAutoRefund: await E(zoe).installBundleID(id), + }; - const [testName, startingValues] = vatParameters.argv; + const [testName, startingValues] = vatParameters.argv; - const aliceP = makeVats( - vatPowers.testLog, - vats, - zoe, - installations, - startingValues, - ); - await E(aliceP).startTest(testName); + const aliceP = makeVats( + vatPowers.testLog, + vats, + zoe, + installations, + startingValues, + ); + await E(aliceP).startTest(testName); + }, }, - }); + ); } diff --git a/packages/zoe/test/swingsetTests/brokenContracts/crashingAutoRefund.js b/packages/zoe/test/swingsetTests/brokenContracts/crashingAutoRefund.js index a6eb29bdd0e..e215f0c860f 100644 --- a/packages/zoe/test/swingsetTests/brokenContracts/crashingAutoRefund.js +++ b/packages/zoe/test/swingsetTests/brokenContracts/crashingAutoRefund.js @@ -65,21 +65,25 @@ const start = zcf => { zcf.makeInvitation(makeMatchingInvitation, 'firstOffer'); offersCount += 1n; - const publicFacet = Far('publicFacet', { - getOffersCount: () => { - offersCount += 1n; - return offersCount; + const publicFacet = makeExo( + 'publicFacet', + M.interface('publicFacet', {}, { defaultGuards: 'passable' }), + { + getOffersCount: () => { + offersCount += 1n; + return offersCount; + }, + makeSafeInvitation, + makeSwapInvitation, + makeThrowingInvitation, + zcfShutdown, + zcfShutdownWithFailure, + throwSomething: () => { + offersCount += 1n; + throw Error('someException'); + }, }, - makeSafeInvitation, - makeSwapInvitation, - makeThrowingInvitation, - zcfShutdown, - zcfShutdownWithFailure, - throwSomething: () => { - offersCount += 1n; - throw Error('someException'); - }, - }); + ); const creatorInvitation = makeSafeInvitation(); diff --git a/packages/zoe/test/swingsetTests/brokenContracts/vat-alice.js b/packages/zoe/test/swingsetTests/brokenContracts/vat-alice.js index da1a5ee3737..61a8d872946 100644 --- a/packages/zoe/test/swingsetTests/brokenContracts/vat-alice.js +++ b/packages/zoe/test/swingsetTests/brokenContracts/vat-alice.js @@ -375,40 +375,48 @@ const build = async (log, zoe, issuers, payments, installations) => { E(publicFacet).zcfShutdownWithFailure('Sadness'); }; - return Far('build', { - startTest: async testName => { - switch (testName) { - case 'throwInOfferHook': { - return doThrowInHook(); + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + startTest: async testName => { + switch (testName) { + case 'throwInOfferHook': { + return doThrowInHook(); + } + case 'throwInApiCall': { + return doThrowInApiCall(); + } + case 'throwInStart': { + return doThrowInStart(); + } + case 'happyTermination': { + return doHappyTermination(); + } + case 'happyTerminationWOffers': { + return doHappyTerminationWithOffers(); + } + case 'doHappyTerminationRefusesContact': { + return doHappyTerminationRefusesContact(); + } + case 'sadTermination': { + return doSadTermination(); + } + default: { + assert.fail(X`testName ${testName} not recognized`); + } } - case 'throwInApiCall': { - return doThrowInApiCall(); - } - case 'throwInStart': { - return doThrowInStart(); - } - case 'happyTermination': { - return doHappyTermination(); - } - case 'happyTerminationWOffers': { - return doHappyTerminationWithOffers(); - } - case 'doHappyTerminationRefusesContact': { - return doHappyTerminationRefusesContact(); - } - case 'sadTermination': { - return doSadTermination(); - } - default: { - assert.fail(X`testName ${testName} not recognized`); - } - } + }, }, - }); + ); }; export function buildRootObject(vatPowers) { - return Far('root', { - build: (...args) => build(vatPowers.testLog, ...args), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (...args) => build(vatPowers.testLog, ...args), + }, + ); } diff --git a/packages/zoe/test/swingsetTests/makeKind/bootstrap.js b/packages/zoe/test/swingsetTests/makeKind/bootstrap.js index 3f6babe74f2..00d250b2bb1 100644 --- a/packages/zoe/test/swingsetTests/makeKind/bootstrap.js +++ b/packages/zoe/test/swingsetTests/makeKind/bootstrap.js @@ -3,27 +3,31 @@ import { Far } from '@endo/marshal'; export function buildRootObject(vatPowers) { const { D } = vatPowers; - return Far('root', { - async bootstrap(vats, devices) { - const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, - ); - /** @type {{zoeService: ERef}} */ - const { zoeService: zoe } = await E(vats.zoe).buildZoe( - vatAdminSvc, - undefined, - 'zcf', - ); - const bcap = await E(vatAdminSvc).getNamedBundleCap( - 'minimalMakeKindContract', - ); - const id = D(bcap).getBundleID(); - const installations = { - minimalMakeKind: await E(zoe).installBundleID(id), - }; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + /** @type {{zoeService: ERef}} */ + const { zoeService: zoe } = await E(vats.zoe).buildZoe( + vatAdminSvc, + undefined, + 'zcf', + ); + const bcap = await E(vatAdminSvc).getNamedBundleCap( + 'minimalMakeKindContract', + ); + const id = D(bcap).getBundleID(); + const installations = { + minimalMakeKind: await E(zoe).installBundleID(id), + }; - const aliceP = E(vats.alice).build(zoe, installations); - await E(aliceP).minimalMakeKindTest(); + const aliceP = E(vats.alice).build(zoe, installations); + await E(aliceP).minimalMakeKindTest(); + }, }, - }); + ); } diff --git a/packages/zoe/test/swingsetTests/makeKind/vat-alice.js b/packages/zoe/test/swingsetTests/makeKind/vat-alice.js index 98c4af7a01e..487d9c34087 100644 --- a/packages/zoe/test/swingsetTests/makeKind/vat-alice.js +++ b/packages/zoe/test/swingsetTests/makeKind/vat-alice.js @@ -2,16 +2,26 @@ import { E } from '@endo/eventual-send'; import { Far } from '@endo/marshal'; const build = async (log, zoe, installations) => { - return Far('build', { - minimalMakeKindTest: async () => { - const result = await E(zoe).startInstance(installations.minimalMakeKind); - log(result); + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + minimalMakeKindTest: async () => { + const result = await E(zoe).startInstance( + installations.minimalMakeKind, + ); + log(result); + }, }, - }); + ); }; export function buildRootObject(vatPowers) { - return Far('root', { - build: (...args) => build(vatPowers.testLog, ...args), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (...args) => build(vatPowers.testLog, ...args), + }, + ); } diff --git a/packages/zoe/test/swingsetTests/offerArgs/bootstrap.js b/packages/zoe/test/swingsetTests/offerArgs/bootstrap.js index a45a0dc319f..13fe9d672c7 100644 --- a/packages/zoe/test/swingsetTests/offerArgs/bootstrap.js +++ b/packages/zoe/test/swingsetTests/offerArgs/bootstrap.js @@ -3,27 +3,31 @@ import { Far } from '@endo/marshal'; export function buildRootObject(vatPowers) { const { D } = vatPowers; - return Far('root', { - async bootstrap(vats, devices) { - const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, - ); - /** @type {{zoeService: ERef}} */ - const { zoeService: zoe } = await E(vats.zoe).buildZoe( - vatAdminSvc, - undefined, - 'zcf', - ); - const bcap = await E(vatAdminSvc).getNamedBundleCap( - 'offerArgsUsageContract', - ); - const id = D(bcap).getBundleID(); - const installations = { - offerArgsUsageContract: await E(zoe).installBundleID(id), - }; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + /** @type {{zoeService: ERef}} */ + const { zoeService: zoe } = await E(vats.zoe).buildZoe( + vatAdminSvc, + undefined, + 'zcf', + ); + const bcap = await E(vatAdminSvc).getNamedBundleCap( + 'offerArgsUsageContract', + ); + const id = D(bcap).getBundleID(); + const installations = { + offerArgsUsageContract: await E(zoe).installBundleID(id), + }; - const aliceP = E(vats.alice).build(zoe, installations); - await E(aliceP).offerArgsUsageTest(); + const aliceP = E(vats.alice).build(zoe, installations); + await E(aliceP).offerArgsUsageTest(); + }, }, - }); + ); } diff --git a/packages/zoe/test/swingsetTests/offerArgs/vat-alice.js b/packages/zoe/test/swingsetTests/offerArgs/vat-alice.js index 23687b0d19c..1a919e4fd14 100644 --- a/packages/zoe/test/swingsetTests/offerArgs/vat-alice.js +++ b/packages/zoe/test/swingsetTests/offerArgs/vat-alice.js @@ -2,30 +2,38 @@ import { E } from '@endo/eventual-send'; import { Far } from '@endo/marshal'; const build = async (log, zoe, installations) => { - return Far('build', { - offerArgsUsageTest: async () => { - const { creatorInvitation } = await E(zoe).startInstance( - installations.offerArgsUsageContract, - ); + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + offerArgsUsageTest: async () => { + const { creatorInvitation } = await E(zoe).startInstance( + installations.offerArgsUsageContract, + ); - const offerArgs = harden({ - myArg: 'offerArgs.myArg was accessed in the contract', - }); + const offerArgs = harden({ + myArg: 'offerArgs.myArg was accessed in the contract', + }); - const userSeat = await E(zoe).offer( - creatorInvitation, - undefined, - undefined, - offerArgs, - ); - const offerResult = await E(userSeat).getOfferResult(); - log(offerResult); + const userSeat = await E(zoe).offer( + creatorInvitation, + undefined, + undefined, + offerArgs, + ); + const offerResult = await E(userSeat).getOfferResult(); + log(offerResult); + }, }, - }); + ); }; export function buildRootObject(vatPowers) { - return Far('root', { - build: (...args) => build(vatPowers.testLog, ...args), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (...args) => build(vatPowers.testLog, ...args), + }, + ); } diff --git a/packages/zoe/test/swingsetTests/privateArgs/bootstrap.js b/packages/zoe/test/swingsetTests/privateArgs/bootstrap.js index d1c238d7469..36b905f649c 100644 --- a/packages/zoe/test/swingsetTests/privateArgs/bootstrap.js +++ b/packages/zoe/test/swingsetTests/privateArgs/bootstrap.js @@ -3,27 +3,31 @@ import { Far } from '@endo/marshal'; export function buildRootObject(vatPowers) { const { D } = vatPowers; - return Far('root', { - async bootstrap(vats, devices) { - const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, - ); - /** @type {{zoeService: ERef}} */ - const { zoeService: zoe } = await E(vats.zoe).buildZoe( - vatAdminSvc, - undefined, - 'zcf', - ); - const bcap = await E(vatAdminSvc).getNamedBundleCap( - 'privateArgsUsageContract', - ); - const id = D(bcap).getBundleID(); - const installations = { - privateArgsUsageContract: await E(zoe).installBundleID(id), - }; + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + /** @type {{zoeService: ERef}} */ + const { zoeService: zoe } = await E(vats.zoe).buildZoe( + vatAdminSvc, + undefined, + 'zcf', + ); + const bcap = await E(vatAdminSvc).getNamedBundleCap( + 'privateArgsUsageContract', + ); + const id = D(bcap).getBundleID(); + const installations = { + privateArgsUsageContract: await E(zoe).installBundleID(id), + }; - const aliceP = E(vats.alice).build(zoe, installations); - await E(aliceP).privateArgsUsageTest(); + const aliceP = E(vats.alice).build(zoe, installations); + await E(aliceP).privateArgsUsageTest(); + }, }, - }); + ); } diff --git a/packages/zoe/test/swingsetTests/privateArgs/vat-alice.js b/packages/zoe/test/swingsetTests/privateArgs/vat-alice.js index fd1a2a773fa..3997cc7a98b 100644 --- a/packages/zoe/test/swingsetTests/privateArgs/vat-alice.js +++ b/packages/zoe/test/swingsetTests/privateArgs/vat-alice.js @@ -2,28 +2,40 @@ import { E } from '@endo/eventual-send'; import { Far } from '@endo/marshal'; const build = async (log, zoe, installations) => { - return Far('build', { - privateArgsUsageTest: async () => { - const privateArgs = harden({ - myArg: Far('arg', { - doTest: () => 'privateArgs.myArg was accessed in the contract', - }), - }); - const { creatorFacet } = await E(zoe).startInstance( - installations.privateArgsUsageContract, - undefined, - undefined, - privateArgs, - ); + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + privateArgsUsageTest: async () => { + const privateArgs = harden({ + myArg: makeExo( + 'arg', + M.interface('arg', {}, { defaultGuards: 'passable' }), + { + doTest: () => 'privateArgs.myArg was accessed in the contract', + }, + ), + }); + const { creatorFacet } = await E(zoe).startInstance( + installations.privateArgsUsageContract, + undefined, + undefined, + privateArgs, + ); - const testResult = await E(creatorFacet).usePrivateArgs(); - log(testResult); + const testResult = await E(creatorFacet).usePrivateArgs(); + log(testResult); + }, }, - }); + ); }; export function buildRootObject(vatPowers) { - return Far('root', { - build: (...args) => build(vatPowers.testLog, ...args), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (...args) => build(vatPowers.testLog, ...args), + }, + ); } diff --git a/packages/zoe/test/swingsetTests/runMint/bootstrap.js b/packages/zoe/test/swingsetTests/runMint/bootstrap.js index 23747ec4092..8577b287e50 100644 --- a/packages/zoe/test/swingsetTests/runMint/bootstrap.js +++ b/packages/zoe/test/swingsetTests/runMint/bootstrap.js @@ -3,29 +3,33 @@ import { Far } from '@endo/marshal'; export function buildRootObject(vatPowers, vatParameters) { const { D } = vatPowers; - return Far('root', { - async bootstrap(vats, devices) { - const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, - ); - const { zoeService: zoe, feeMintAccess } = await E(vats.zoe).buildZoe( - vatAdminSvc, - undefined, - 'zcf', - ); - const installations = {}; - const installedPs = vatParameters.contractNames.map(name => - E(vatAdminSvc) - .getNamedBundleCap(name) - .then(bcap => E(zoe).installBundleID(D(bcap).getBundleID())) - .then(installation => { - installations[name] = installation; - }), - ); - await Promise.all(installedPs); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + const { zoeService: zoe, feeMintAccess } = await E(vats.zoe).buildZoe( + vatAdminSvc, + undefined, + 'zcf', + ); + const installations = {}; + const installedPs = vatParameters.contractNames.map(name => + E(vatAdminSvc) + .getNamedBundleCap(name) + .then(bcap => E(zoe).installBundleID(D(bcap).getBundleID())) + .then(installation => { + installations[name] = installation; + }), + ); + await Promise.all(installedPs); - const aliceP = E(vats.alice).build(zoe, installations, feeMintAccess); - await E(aliceP).runMintTest(); + const aliceP = E(vats.alice).build(zoe, installations, feeMintAccess); + await E(aliceP).runMintTest(); + }, }, - }); + ); } diff --git a/packages/zoe/test/swingsetTests/runMint/vat-alice.js b/packages/zoe/test/swingsetTests/runMint/vat-alice.js index e3b778f35be..74570cab528 100644 --- a/packages/zoe/test/swingsetTests/runMint/vat-alice.js +++ b/packages/zoe/test/swingsetTests/runMint/vat-alice.js @@ -8,54 +8,62 @@ import { Far } from '@endo/marshal'; * @param {FeeMintAccess} feeMintAccess */ const build = async (log, zoe, installations, feeMintAccess) => { - return Far('build', { - runMintTest: async () => { - log('starting runMintTest'); - const { instance } = await E(zoe).startInstance( - installations.offerArgsUsageContract, - harden({ - RUN: E(zoe).getFeeIssuer(), - }), - undefined, - ); - const issuers = await E(zoe).getIssuers(instance); - log(issuers); - const { creatorFacet: cf1 } = await E(zoe).startInstance( - installations.runMintContract, - undefined, - undefined, - { - feeMintAccess, - }, - ); - log('first instance started'); - const { creatorFacet: cf2 } = await E(zoe).startInstance( - installations.runMintContract, - undefined, - undefined, - { - feeMintAccess, - }, - ); - log('second instance started'); + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + runMintTest: async () => { + log('starting runMintTest'); + const { instance } = await E(zoe).startInstance( + installations.offerArgsUsageContract, + harden({ + RUN: E(zoe).getFeeIssuer(), + }), + undefined, + ); + const issuers = await E(zoe).getIssuers(instance); + log(issuers); + const { creatorFacet: cf1 } = await E(zoe).startInstance( + installations.runMintContract, + undefined, + undefined, + { + feeMintAccess, + }, + ); + log('first instance started'); + const { creatorFacet: cf2 } = await E(zoe).startInstance( + installations.runMintContract, + undefined, + undefined, + { + feeMintAccess, + }, + ); + log('second instance started'); - const payment1 = await E(cf1).mintRun(); - log('first payment minted'); - const payment2 = await E(cf2).mintRun(); - log('second payment minted'); + const payment1 = await E(cf1).mintRun(); + log('first payment minted'); + const payment2 = await E(cf2).mintRun(); + log('second payment minted'); - const stableIssuer = E(zoe).getFeeIssuer(); - const amount1 = await E(stableIssuer).getAmountOf(payment1); - const amount2 = await E(stableIssuer).getAmountOf(payment2); - log(amount1); - log(amount2); + const stableIssuer = E(zoe).getFeeIssuer(); + const amount1 = await E(stableIssuer).getAmountOf(payment1); + const amount2 = await E(stableIssuer).getAmountOf(payment2); + log(amount1); + log(amount2); + }, }, - }); + ); }; export function buildRootObject(vatPowers) { - return Far('root', { - build: (zoe, installations, feeMintAccess) => - build(vatPowers.testLog, zoe, installations, feeMintAccess), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (zoe, installations, feeMintAccess) => + build(vatPowers.testLog, zoe, installations, feeMintAccess), + }, + ); } diff --git a/packages/zoe/test/swingsetTests/upgradeCoveredCall/bootstrap-coveredCall-service-upgrade.js b/packages/zoe/test/swingsetTests/upgradeCoveredCall/bootstrap-coveredCall-service-upgrade.js index 3a40423e9ad..508ed77dada 100644 --- a/packages/zoe/test/swingsetTests/upgradeCoveredCall/bootstrap-coveredCall-service-upgrade.js +++ b/packages/zoe/test/swingsetTests/upgradeCoveredCall/bootstrap-coveredCall-service-upgrade.js @@ -78,125 +78,150 @@ export const buildRootObject = () => { const timer = buildManualTimer(console.log); let installation; - return Far('root', { - bootstrap: async (vats, devices) => { - await timer.tick('bootstrap'); - vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); - [{ zoeService: zoe }, ertpService] = await Promise.all([ - E(vats.zoe).buildZoe(vatAdmin, undefined, 'zcf'), - E(vats.ertp).getErtpService(), - ]); - - doubloonsKit = await E(ertpService).makeIssuerKit('Doubloons'); - bucksKit = await E(ertpService).makeIssuerKit('Bucks'); - kits = { doubloonsKit, bucksKit }; - doubloons = v => AmountMath.make(doubloonsKit.brand, v); - bucks = v => AmountMath.make(bucksKit.brand, v); - - const v2BundleId = await E(vatAdmin).getBundleIDByName('coveredCallV2'); - assert(v2BundleId, 'bundleId must not be empty'); - installation = await E(zoe).installBundleID(v2BundleId); - - issuerRecord = harden({ - Bucks: bucksKit.issuer, - Doubloons: doubloonsKit.issuer, - }); - }, - - buildV1: async () => { - console.log(`BOOT starting buildV1`); - await timer.tick('buildV1'); - // build the contract vat from ZCF and the contract bundlecap - - const doubloonPurse = await E(doubloonsKit.issuer).makeEmptyPurse(); - const bucksPurse = await E(bucksKit.issuer).makeEmptyPurse(); - await mintInto(doubloonsKit, doubloonPurse, 20n); - - // Complete round-trip without upgrade - const facets1 = await E(zoe).startInstance(installation, issuerRecord); - const creator1 = facets1.creatorFacet; - const seat1A = await offerCall(zoe, creator1, kits, timer, 15n, 30n); - const invitation1B = await E(seat1A).getOfferResult(); - const seat1B = await acceptCall(zoe, invitation1B, kits, 30n, 15n); - const doubloonsPurse = E(doubloonsKit.issuer).makeEmptyPurse(); - const offerResult1B = await E(seat1B).getOfferResult(); - assert.equal( - offerResult1B, - 'The option was exercised. Please collect the assets in your payout.', - ); - await depositPayout(seat1A, 'Bucks', bucksPurse, bucks(30n)); - await depositPayout(seat1A, 'Doubloons', doubloonPurse, doubloons(0n)); - await depositPayout(seat1B, 'Bucks', bucksPurse, bucks(0n)); - await depositPayout(seat1B, 'Doubloons', doubloonsPurse, doubloons(15n)); - - // Create the call, and hand off the invitation for exercise after upgrade - const facets2 = await E(zoe).startInstance(installation, issuerRecord); - ({ adminFacet: instanceAdmin2 } = facets2); - creator2 = facets2.creatorFacet; - const seat2A = await offerCall(zoe, creator2, kits, timer, 22n, 42n); - const invitation2BP = E(seat2A).getOfferResult(); - - E(seat2A) - .getOfferResult() - .then(async _invitation => { - await depositPayout(seat2A, 'Bucks', bucksPurse, bucks(42n)); - await depositPayout( - seat2A, - 'Doubloons', - doubloonPurse, - doubloons(0n), - ); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + bootstrap: async (vats, devices) => { + await timer.tick('bootstrap'); + vatAdmin = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + [{ zoeService: zoe }, ertpService] = await Promise.all([ + E(vats.zoe).buildZoe(vatAdmin, undefined, 'zcf'), + E(vats.ertp).getErtpService(), + ]); + + doubloonsKit = await E(ertpService).makeIssuerKit('Doubloons'); + bucksKit = await E(ertpService).makeIssuerKit('Bucks'); + kits = { doubloonsKit, bucksKit }; + doubloons = v => AmountMath.make(doubloonsKit.brand, v); + bucks = v => AmountMath.make(bucksKit.brand, v); + + const v2BundleId = await E(vatAdmin).getBundleIDByName('coveredCallV2'); + assert(v2BundleId, 'bundleId must not be empty'); + installation = await E(zoe).installBundleID(v2BundleId); + + issuerRecord = harden({ + Bucks: bucksKit.issuer, + Doubloons: doubloonsKit.issuer, }); + }, - invitation2B = await invitation2BP; - return true; - }, + buildV1: async () => { + console.log(`BOOT starting buildV1`); + await timer.tick('buildV1'); + // build the contract vat from ZCF and the contract bundlecap + + const doubloonPurse = await E(doubloonsKit.issuer).makeEmptyPurse(); + const bucksPurse = await E(bucksKit.issuer).makeEmptyPurse(); + await mintInto(doubloonsKit, doubloonPurse, 20n); + + // Complete round-trip without upgrade + const facets1 = await E(zoe).startInstance(installation, issuerRecord); + const creator1 = facets1.creatorFacet; + const seat1A = await offerCall(zoe, creator1, kits, timer, 15n, 30n); + const invitation1B = await E(seat1A).getOfferResult(); + const seat1B = await acceptCall(zoe, invitation1B, kits, 30n, 15n); + const doubloonsPurse = E(doubloonsKit.issuer).makeEmptyPurse(); + const offerResult1B = await E(seat1B).getOfferResult(); + assert.equal( + offerResult1B, + 'The option was exercised. Please collect the assets in your payout.', + ); + await depositPayout(seat1A, 'Bucks', bucksPurse, bucks(30n)); + await depositPayout(seat1A, 'Doubloons', doubloonPurse, doubloons(0n)); + await depositPayout(seat1B, 'Bucks', bucksPurse, bucks(0n)); + await depositPayout( + seat1B, + 'Doubloons', + doubloonsPurse, + doubloons(15n), + ); + + // Create the call, and hand off the invitation for exercise after upgrade + const facets2 = await E(zoe).startInstance(installation, issuerRecord); + ({ adminFacet: instanceAdmin2 } = facets2); + creator2 = facets2.creatorFacet; + const seat2A = await offerCall(zoe, creator2, kits, timer, 22n, 42n); + const invitation2BP = E(seat2A).getOfferResult(); + + E(seat2A) + .getOfferResult() + .then(async _invitation => { + await depositPayout(seat2A, 'Bucks', bucksPurse, bucks(42n)); + await depositPayout( + seat2A, + 'Doubloons', + doubloonPurse, + doubloons(0n), + ); + }); + + invitation2B = await invitation2BP; + return true; + }, + + upgradeV2: async () => { + await timer.tick('upgradeV2'); + const v3BundleId = await E(vatAdmin).getBundleIDByName('coveredCallV3'); + const bucksPurse = await E(bucksKit.issuer).makeEmptyPurse(); + const doubloonsPurse = await E(doubloonsKit.issuer).makeEmptyPurse(); + + const upgradeResult = + await E(instanceAdmin2).upgradeContract(v3BundleId); + assert.equal(upgradeResult.incarnationNumber, 1); + console.log('Boot starting upgrade V2'); + + // exercise an invitation from before the upgrade + const seat2BP = acceptCall(zoe, invitation2B, kits, 42n, 22n); + seat2BP.then( + seat => console.log(`Boot upgrade seat2b ${seat}`), + e => console.log(` BOOT upgrade seat2b fail: ${e}`), + ); + const seat2B = await seat2BP; + + const offerResult2B = await E(seat2B).getOfferResult(); + assert.equal( + offerResult2B, + 'The V3 upgraded option was exercised. Please collect the assets in your payout.', + ); + + // Complete round-trip with post-upgraded instance + console.log('Boot starting post-upgrade contract'); + const installationV3 = await E(zoe).installBundleID(v3BundleId); + const facets3 = await E(zoe).startInstance( + installationV3, + issuerRecord, + ); + const creator3 = facets3.creatorFacet; + const seat3A = await offerCall(zoe, creator3, kits, timer, 15n, 30n); + const invitation3B = await E(seat3A).getOfferResult(); + const seat3B = await acceptCall(zoe, invitation3B, kits, 30n, 15n); + const offerResult3B = await E(seat3B).getOfferResult(); + assert.equal( + offerResult3B, + 'The V3 option was exercised. Please collect the assets in your payout.', + ); + await depositPayout(seat3A, 'Bucks', bucksPurse, bucks(30n)); + await depositPayout(seat3A, 'Doubloons', doubloonsPurse, doubloons(0n)); + await depositPayout(seat3B, 'Bucks', bucksPurse, bucks(0n)); + await depositPayout( + seat3B, + 'Doubloons', + doubloonsPurse, + doubloons(15n), + ); + await depositPayout( + seat2B, + 'Doubloons', + doubloonsPurse, + doubloons(22n), + ); - upgradeV2: async () => { - await timer.tick('upgradeV2'); - const v3BundleId = await E(vatAdmin).getBundleIDByName('coveredCallV3'); - const bucksPurse = await E(bucksKit.issuer).makeEmptyPurse(); - const doubloonsPurse = await E(doubloonsKit.issuer).makeEmptyPurse(); - - const upgradeResult = await E(instanceAdmin2).upgradeContract(v3BundleId); - assert.equal(upgradeResult.incarnationNumber, 1); - console.log('Boot starting upgrade V2'); - - // exercise an invitation from before the upgrade - const seat2BP = acceptCall(zoe, invitation2B, kits, 42n, 22n); - seat2BP.then( - seat => console.log(`Boot upgrade seat2b ${seat}`), - e => console.log(` BOOT upgrade seat2b fail: ${e}`), - ); - const seat2B = await seat2BP; - - const offerResult2B = await E(seat2B).getOfferResult(); - assert.equal( - offerResult2B, - 'The V3 upgraded option was exercised. Please collect the assets in your payout.', - ); - - // Complete round-trip with post-upgraded instance - console.log('Boot starting post-upgrade contract'); - const installationV3 = await E(zoe).installBundleID(v3BundleId); - const facets3 = await E(zoe).startInstance(installationV3, issuerRecord); - const creator3 = facets3.creatorFacet; - const seat3A = await offerCall(zoe, creator3, kits, timer, 15n, 30n); - const invitation3B = await E(seat3A).getOfferResult(); - const seat3B = await acceptCall(zoe, invitation3B, kits, 30n, 15n); - const offerResult3B = await E(seat3B).getOfferResult(); - assert.equal( - offerResult3B, - 'The V3 option was exercised. Please collect the assets in your payout.', - ); - await depositPayout(seat3A, 'Bucks', bucksPurse, bucks(30n)); - await depositPayout(seat3A, 'Doubloons', doubloonsPurse, doubloons(0n)); - await depositPayout(seat3B, 'Bucks', bucksPurse, bucks(0n)); - await depositPayout(seat3B, 'Doubloons', doubloonsPurse, doubloons(15n)); - await depositPayout(seat2B, 'Doubloons', doubloonsPurse, doubloons(22n)); - - console.log('Boot finished test'); - return true; + console.log('Boot finished test'); + return true; + }, }, - }); + ); }; diff --git a/packages/zoe/test/swingsetTests/upgradeCoveredCall/vat-ertp-service.js b/packages/zoe/test/swingsetTests/upgradeCoveredCall/vat-ertp-service.js index 90ba1196fd6..835ba5288f6 100644 --- a/packages/zoe/test/swingsetTests/upgradeCoveredCall/vat-ertp-service.js +++ b/packages/zoe/test/swingsetTests/upgradeCoveredCall/vat-ertp-service.js @@ -3,10 +3,18 @@ import { AmountMath } from '@agoric/ertp'; import { prepareErtpService } from '@agoric/ertp/test/swingsetTests/ertpService/vat-ertp-service.js'; export const buildRootObject = async (vatPowers, _vatParams, baggage) => { - const exportableAmountMath = Far('AmountMath', { ...AmountMath }); + const exportableAmountMath = makeExo( + 'AmountMath', + M.interface('AmountMath', {}, { defaultGuards: 'passable' }), + { ...AmountMath }, + ); const ertpService = prepareErtpService(baggage, vatPowers.exitVatWithFailure); - return Far('root', { - getErtpService: () => ertpService, - getAmountMath: () => exportableAmountMath, - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + getErtpService: () => ertpService, + getAmountMath: () => exportableAmountMath, + }, + ); }; diff --git a/packages/zoe/test/swingsetTests/zoe/bootstrap.js b/packages/zoe/test/swingsetTests/zoe/bootstrap.js index a04e6bbed6d..87ad013e3d2 100644 --- a/packages/zoe/test/swingsetTests/zoe/bootstrap.js +++ b/packages/zoe/test/swingsetTests/zoe/bootstrap.js @@ -81,38 +81,42 @@ const makeVats = (log, vats, zoe, installations, startingValues) => { export function buildRootObject(vatPowers, vatParameters) { const { D } = vatPowers; const { argv } = vatParameters; - return Far('root', { - async bootstrap(vats, devices) { - const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( - devices.vatAdmin, - ); - /** @type {{zoeService: ERef}} */ - const { zoeService: zoe } = await E(vats.zoe).buildZoe( - vatAdminSvc, - undefined, - 'zcf', - ); - const installations = {}; - const installedPs = vatParameters.contractNames.map(name => - E(vatAdminSvc) - .getNamedBundleCap(name) - .then(bcap => E(zoe).installBundleID(D(bcap).getBundleID())) - .then(installation => { - installations[name] = installation; - }), - ); - await Promise.all(installedPs); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + async bootstrap(vats, devices) { + const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( + devices.vatAdmin, + ); + /** @type {{zoeService: ERef}} */ + const { zoeService: zoe } = await E(vats.zoe).buildZoe( + vatAdminSvc, + undefined, + 'zcf', + ); + const installations = {}; + const installedPs = vatParameters.contractNames.map(name => + E(vatAdminSvc) + .getNamedBundleCap(name) + .then(bcap => E(zoe).installBundleID(D(bcap).getBundleID())) + .then(installation => { + installations[name] = installation; + }), + ); + await Promise.all(installedPs); - const [testName, startingValues] = argv; + const [testName, startingValues] = argv; - const { aliceP, bobP, carolP, daveP } = makeVats( - vatPowers.testLog, - vats, - zoe, - installations, - startingValues, - ); - await E(aliceP).startTest(testName, bobP, carolP, daveP); + const { aliceP, bobP, carolP, daveP } = makeVats( + vatPowers.testLog, + vats, + zoe, + installations, + startingValues, + ); + await E(aliceP).startTest(testName, bobP, carolP, daveP); + }, }, - }); + ); } diff --git a/packages/zoe/test/swingsetTests/zoe/vat-alice.js b/packages/zoe/test/swingsetTests/zoe/vat-alice.js index 7e6d66c74dc..91ead525315 100644 --- a/packages/zoe/test/swingsetTests/zoe/vat-alice.js +++ b/packages/zoe/test/swingsetTests/zoe/vat-alice.js @@ -509,7 +509,11 @@ const build = async (log, zoe, issuers, payments, installations, timer) => { want: { StrikePrice: simoleans(7n) }, exit: { afterDeadline: { - timer: Far('timer', { setWakeup: () => {} }), + timer: makeExo( + 'timer', + M.interface('timer', {}, { defaultGuards: 'passable' }), + { setWakeup: () => {} }, + ), deadline: 1n, }, }, @@ -540,52 +544,60 @@ const build = async (log, zoe, issuers, payments, installations, timer) => { await showPurseBalance(simoleanPurseP, 'aliceSimoleanPurse', log); }; - return Far('build', { - startTest: async (testName, bobP, carolP, daveP) => { - switch (testName) { - case 'automaticRefundOk': { - return doAutomaticRefund(bobP); + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + startTest: async (testName, bobP, carolP, daveP) => { + switch (testName) { + case 'automaticRefundOk': { + return doAutomaticRefund(bobP); + } + case 'coveredCallOk': { + return doCoveredCall(bobP); + } + case 'swapForOptionOk': { + return doSwapForOption(bobP, carolP, daveP); + } + case 'secondPriceAuctionOk': { + return doSecondPriceAuction(bobP, carolP, daveP); + } + case 'atomicSwapOk': { + return doAtomicSwap(bobP); + } + case 'simpleExchangeOk': { + return doSimpleExchange(bobP); + } + case 'simpleExchangeNotifier': { + return doSimpleExchangeWithNotification(bobP); + } + case 'autoswapOk': { + return doAutoswap(bobP); + } + case 'sellTicketsOk': { + return doSellTickets(bobP); + } + case 'otcDeskOk': { + return doOTCDesk(bobP); + } + case 'badTimer': { + return doBadTimer(); + } + default: { + assert.fail(X`testName ${testName} not recognized`); + } } - case 'coveredCallOk': { - return doCoveredCall(bobP); - } - case 'swapForOptionOk': { - return doSwapForOption(bobP, carolP, daveP); - } - case 'secondPriceAuctionOk': { - return doSecondPriceAuction(bobP, carolP, daveP); - } - case 'atomicSwapOk': { - return doAtomicSwap(bobP); - } - case 'simpleExchangeOk': { - return doSimpleExchange(bobP); - } - case 'simpleExchangeNotifier': { - return doSimpleExchangeWithNotification(bobP); - } - case 'autoswapOk': { - return doAutoswap(bobP); - } - case 'sellTicketsOk': { - return doSellTickets(bobP); - } - case 'otcDeskOk': { - return doOTCDesk(bobP); - } - case 'badTimer': { - return doBadTimer(); - } - default: { - assert.fail(X`testName ${testName} not recognized`); - } - } + }, }, - }); + ); }; export function buildRootObject(vatPowers) { - return Far('root', { - build: (...args) => build(vatPowers.testLog, ...args), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (...args) => build(vatPowers.testLog, ...args), + }, + ); } diff --git a/packages/zoe/test/swingsetTests/zoe/vat-bob.js b/packages/zoe/test/swingsetTests/zoe/vat-bob.js index c236266ae13..1461e85f6f1 100644 --- a/packages/zoe/test/swingsetTests/zoe/vat-bob.js +++ b/packages/zoe/test/swingsetTests/zoe/vat-bob.js @@ -16,540 +16,563 @@ const build = async (log, zoe, issuers, payments, installations, timer) => { let secondPriceAuctionSeatP; - return Far('build', { - doAutomaticRefund: async invitation => { - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - - // Bob ensures it's the contract he expects - installations.automaticRefund === installation || - assert.fail(X`should be the expected automaticRefund`); - issuerKeywordRecord.Contribution1 === moolaIssuer || - assert.fail(X`The first issuer should be the moola issuer`); - issuerKeywordRecord.Contribution2 === simoleanIssuer || - assert.fail(X`The second issuer should be the simolean issuer`); - - // 1. Bob escrows his offer - const bobProposal = harden({ - want: { Contribution1: moola(15n) }, - give: { Contribution2: simoleans(17n) }, - exit: { onDemand: null }, - }); - - const bobPayments = { Contribution2: simoleanPayment }; - - // 2. Bob makes an offer - const bobSeatP = await E(zoe).offer( - exclInvitation, - bobProposal, - bobPayments, - ); - log(await E(bobSeatP).getOfferResult()); - - const moolaPayout = await E(bobSeatP).getPayout('Contribution1'); - const simoleanPayout = await E(bobSeatP).getPayout('Contribution2'); - - // 5: Bob deposits his winnings - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); - - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - }, + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + doAutomaticRefund: async invitation => { + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + + // Bob ensures it's the contract he expects + installations.automaticRefund === installation || + assert.fail(X`should be the expected automaticRefund`); + issuerKeywordRecord.Contribution1 === moolaIssuer || + assert.fail(X`The first issuer should be the moola issuer`); + issuerKeywordRecord.Contribution2 === simoleanIssuer || + assert.fail(X`The second issuer should be the simolean issuer`); + + // 1. Bob escrows his offer + const bobProposal = harden({ + want: { Contribution1: moola(15n) }, + give: { Contribution2: simoleans(17n) }, + exit: { onDemand: null }, + }); - doCoveredCall: async invitation => { - // Bob claims all with the Zoe invitationIssuer - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - - const bobIntendedProposal = harden({ - want: { UnderlyingAsset: moola(3n) }, - give: { StrikePrice: simoleans(7n) }, - }); - - // Bob checks that the invitation is for the right covered call - const { value: optionValue } = - await E(invitationIssuer).getAmountOf(exclInvitation); - const { customDetails } = optionValue[0]; - assert(typeof customDetails === 'object'); - - assert(installation === installations.coveredCall, X`wrong installation`); - optionValue[0].description === 'exerciseOption' || - assert.fail(X`wrong invitation`); - assert( - AmountMath.isEqual( - customDetails.underlyingAssets.UnderlyingAsset, - moola(3n), - ), - ); - assert( - AmountMath.isEqual( - customDetails.strikePrice.StrikePrice, - simoleans(7n), - ), - ); - assert(customDetails.expirationDate === 1n, X`wrong expirationDate`); - assert(customDetails.timeAuthority === timer, 'wrong timer'); - const { UnderlyingAsset, StrikePrice } = issuerKeywordRecord; - UnderlyingAsset === moolaIssuer || - assert.fail(X`The underlying asset issuer should be the moola issuer`); - StrikePrice === simoleanIssuer || - assert.fail(X`The strike price issuer should be the simolean issuer`); - - const bobPayments = { StrikePrice: simoleanPayment }; - // Bob escrows - const seatP = await E(zoe).offer( - exclInvitation, - bobIntendedProposal, - bobPayments, - ); - - log(await E(seatP).getOfferResult()); - - const moolaPayout = await E(seatP).getPayout('UnderlyingAsset'); - const simoleanPayout = await E(seatP).getPayout('StrikePrice'); - - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); - - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - }, + const bobPayments = { Contribution2: simoleanPayment }; + + // 2. Bob makes an offer + const bobSeatP = await E(zoe).offer( + exclInvitation, + bobProposal, + bobPayments, + ); + log(await E(bobSeatP).getOfferResult()); + + const moolaPayout = await E(bobSeatP).getPayout('Contribution1'); + const simoleanPayout = await E(bobSeatP).getPayout('Contribution2'); + + // 5: Bob deposits his winnings + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + }, + + doCoveredCall: async invitation => { + // Bob claims all with the Zoe invitationIssuer + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + + const bobIntendedProposal = harden({ + want: { UnderlyingAsset: moola(3n) }, + give: { StrikePrice: simoleans(7n) }, + }); - doSwapForOption: async (invitation, daveP) => { - // Bob claims all with the Zoe invitationIssuer - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - - const { UnderlyingAsset, StrikePrice } = - await E(zoe).getIssuers(instance); - - // Bob checks that the invitation is for the right covered call - const optionAmounts = - await E(invitationIssuer).getAmountOf(exclInvitation); - const optionValue = optionAmounts.value; - const { customDetails } = optionValue[0]; - assert(typeof customDetails === 'object'); - - assert(installation === installations.coveredCall, X`wrong installation`); - optionValue[0].description === 'exerciseOption' || - assert.fail(X`wrong invitation`); - assert( - AmountMath.isEqual( - customDetails.underlyingAssets.UnderlyingAsset, + // Bob checks that the invitation is for the right covered call + const { value: optionValue } = + await E(invitationIssuer).getAmountOf(exclInvitation); + const { customDetails } = optionValue[0]; + assert(typeof customDetails === 'object'); + + assert( + installation === installations.coveredCall, + X`wrong installation`, + ); + optionValue[0].description === 'exerciseOption' || + assert.fail(X`wrong invitation`); + assert( + AmountMath.isEqual( + customDetails.underlyingAssets.UnderlyingAsset, + moola(3n), + ), + ); + assert( + AmountMath.isEqual( + customDetails.strikePrice.StrikePrice, + simoleans(7n), + ), + ); + assert(customDetails.expirationDate === 1n, X`wrong expirationDate`); + assert(customDetails.timeAuthority === timer, 'wrong timer'); + const { UnderlyingAsset, StrikePrice } = issuerKeywordRecord; + UnderlyingAsset === moolaIssuer || + assert.fail( + X`The underlying asset issuer should be the moola issuer`, + ); + StrikePrice === simoleanIssuer || + assert.fail(X`The strike price issuer should be the simolean issuer`); + + const bobPayments = { StrikePrice: simoleanPayment }; + // Bob escrows + const seatP = await E(zoe).offer( + exclInvitation, + bobIntendedProposal, + bobPayments, + ); + + log(await E(seatP).getOfferResult()); + + const moolaPayout = await E(seatP).getPayout('UnderlyingAsset'); + const simoleanPayout = await E(seatP).getPayout('StrikePrice'); + + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + }, + + doSwapForOption: async (invitation, daveP) => { + // Bob claims all with the Zoe invitationIssuer + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + + const { UnderlyingAsset, StrikePrice } = + await E(zoe).getIssuers(instance); + + // Bob checks that the invitation is for the right covered call + const optionAmounts = + await E(invitationIssuer).getAmountOf(exclInvitation); + const optionValue = optionAmounts.value; + const { customDetails } = optionValue[0]; + assert(typeof customDetails === 'object'); + + assert( + installation === installations.coveredCall, + X`wrong installation`, + ); + optionValue[0].description === 'exerciseOption' || + assert.fail(X`wrong invitation`); + assert( + AmountMath.isEqual( + customDetails.underlyingAssets.UnderlyingAsset, + moola(3n), + ), + X`wrong underlying asset`, + ); + assert( + AmountMath.isEqual( + customDetails.strikePrice.StrikePrice, + simoleans(7n), + ), + X`wrong strike price`, + ); + assert(customDetails.expirationDate === 100n, X`wrong expiration date`); + assert(customDetails.timeAuthority === timer, X`wrong timer`); + UnderlyingAsset === moolaIssuer || + assert.fail(X`The underlyingAsset issuer should be the moola issuer`); + StrikePrice === simoleanIssuer || + assert.fail(X`The strikePrice issuer should be the simolean issuer`); + + // Let's imagine that Bob wants to create a swap to trade this + // invitation for bucks. He wants to invitation Dave as the + // counter-party. + const offerIssuerKeywordRecord = harden({ + Asset: invitationIssuer, + Price: bucksIssuer, + }); + const { creatorInvitation: bobSwapInvitation } = await E( + zoe, + ).startInstance(installations.atomicSwap, offerIssuerKeywordRecord); + + // Bob wants to swap an invitation with the same amount as his + // current invitation from Alice. He wants 1 buck in return. + const bobProposalSwap = harden({ + give: { Asset: optionAmounts }, + want: { Price: bucks(1n) }, + }); + + const bobSwapPayments = harden({ Asset: exclInvitation }); + + // Bob escrows his option in the swap + const bobSeatP = await E(zoe).offer( + bobSwapInvitation, + bobProposalSwap, + bobSwapPayments, + ); + const daveSwapInvitationP = E(bobSeatP).getOfferResult(); + // Bob makes an offer to the swap with his "higher order" + log('swap invitation made'); + await E(daveP).doSwapForOption(daveSwapInvitationP, optionAmounts); + + const bucksPayout = await E(bobSeatP).getPayout('Price'); + + // Bob deposits his winnings + await E(bucksPurseP).deposit(bucksPayout); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + await showPurseBalance(bucksPurseP, 'bobBucksPurse;', log); + }, + doSecondPriceAuctionBid: async invitation => { + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + const { value: invitationValue } = + await E(invitationIssuer).getAmountOf(exclInvitation); + installation === installations.secondPriceAuction || + assert.fail(X`wrong installation`); + assert( + keyEQ( + harden({ Asset: moolaIssuer, Ask: simoleanIssuer }), + issuerKeywordRecord, + ), + X`issuerKeywordRecord was not as expected`, + ); + assert( + keyEQ(invitationValue[0].customDetails?.minimumBid, simoleans(3n)), + ); + assert( + keyEQ(invitationValue[0].customDetails?.auctionedAssets, moola(1n)), + ); + + const proposal = harden({ + want: { Asset: moola(1n) }, + give: { Bid: simoleans(11n) }, + }); + const paymentKeywordRecord = { Bid: simoleanPayment }; + + secondPriceAuctionSeatP = E(zoe).offer( + exclInvitation, + proposal, + paymentKeywordRecord, + ); + log(`Bob: ${await E(secondPriceAuctionSeatP).getOfferResult()}`); + }, + doSecondPriceAuctionGetPayout: async () => { + const moolaPayout = await E(secondPriceAuctionSeatP).getPayout('Asset'); + const simoleanPayout = await E(secondPriceAuctionSeatP).getPayout( + 'Bid', + ); + + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + }, + doAtomicSwap: async invitation => { + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + const { value: invitationValue } = + await E(invitationIssuer).getAmountOf(exclInvitation); + + assert( + installation === installations.atomicSwap, + X`wrong installation`, + ); + assert( + keyEQ( + harden({ Asset: moolaIssuer, Price: simoleanIssuer }), + issuerKeywordRecord, + ), + X`issuers were not as expected`, + ); + keyEQ(invitationValue[0].customDetails?.asset, moola(3n)) || + assert.fail(X`Alice made a different offer than expected`); + keyEQ(invitationValue[0].customDetails?.price, simoleans(7n)) || + assert.fail(X`Alice made a different offer than expected`); + + const proposal = harden({ + want: { Asset: moola(3n) }, + give: { Price: simoleans(7n) }, + }); + const paymentKeywordRecord = { Price: simoleanPayment }; + + const seatP = await E(zoe).offer( + exclInvitation, + proposal, + paymentKeywordRecord, + ); + + log(await E(seatP).getOfferResult()); + + const moolaPayout = await E(seatP).getPayout('Asset'); + const simoleanPayout = await E(seatP).getPayout('Price'); + + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + }, + + doSimpleExchange: async invitation => { + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + installation === installations.simpleExchange || + assert.fail(X`wrong installation`); + issuerKeywordRecord.Asset === moolaIssuer || + assert.fail(X`The first issuer should be the moola issuer`); + issuerKeywordRecord.Price === simoleanIssuer || + assert.fail(X`The second issuer should be the simolean issuer`); + + const bobBuyOrderProposal = harden({ + want: { Asset: moola(3n) }, + give: { Price: simoleans(7n) }, + exit: { onDemand: null }, + }); + const paymentKeywordRecord = { Price: simoleanPayment }; + + const seatP = await E(zoe).offer( + exclInvitation, + bobBuyOrderProposal, + paymentKeywordRecord, + ); + + log(await E(seatP).getOfferResult()); + + const moolaPayout = await E(seatP).getPayout('Asset'); + const simoleanPayout = await E(seatP).getPayout('Price'); + + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + }, + doSimpleExchangeUpdates: async (invitationP, m, s) => { + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitationP, + ); + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + installation === installations.simpleExchange || + assert.fail(X`wrong installation`); + issuerKeywordRecord.Asset === moolaIssuer || + assert.fail(X`The first issuer should be the moola issuer`); + issuerKeywordRecord.Price === simoleanIssuer || + assert.fail(X`The second issuer should be the simolean issuer`); + const bobBuyOrderProposal = harden({ + want: { Asset: moola(m) }, + give: { Price: simoleans(s) }, + exit: { onDemand: null }, + }); + if (m === 3n && s === 7n) { + await E(simoleanPurseP).deposit(simoleanPayment); + } + const simoleanPayment2 = await E(simoleanPurseP).withdraw(simoleans(s)); + const paymentKeywordRecord = { Price: simoleanPayment2 }; + const seatP = await E(zoe).offer( + invitation, + bobBuyOrderProposal, + paymentKeywordRecord, + ); + + log(await E(seatP).getOfferResult()); + + E(seatP) + .getPayout('Asset') + .then(moolaPayout => { + E(moolaPurseP).deposit(moolaPayout); + }); + E(seatP) + .getPayout('Price') + .then(simoleanPayout => { + E(simoleanPurseP).deposit(simoleanPayout); + }); + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + }, + + doAutoswap: async instance => { + const publicFacet = await E(zoe).getPublicFacet(instance); + const buyBInvitation = await E(publicFacet).makeSwapInInvitation(); + const installation = await E(zoe).getInstallation(buyBInvitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + assert(installation === installations.autoswap, X`wrong installation`); + const liquidityIssuer = await E(publicFacet).getLiquidityIssuer(); + assert( + keyEQ( + harden({ + Central: moolaIssuer, + Secondary: simoleanIssuer, + Liquidity: liquidityIssuer, + }), + issuerKeywordRecord, + ), + X`issuers were not as expected`, + ); + + // bob checks how many simoleans he can get for 3 moola + const simoleanAmounts = await E(publicFacet).getInputPrice( moola(3n), - ), - X`wrong underlying asset`, - ); - assert( - AmountMath.isEqual( - customDetails.strikePrice.StrikePrice, - simoleans(7n), - ), - X`wrong strike price`, - ); - assert(customDetails.expirationDate === 100n, X`wrong expiration date`); - assert(customDetails.timeAuthority === timer, X`wrong timer`); - UnderlyingAsset === moolaIssuer || - assert.fail(X`The underlyingAsset issuer should be the moola issuer`); - StrikePrice === simoleanIssuer || - assert.fail(X`The strikePrice issuer should be the simolean issuer`); - - // Let's imagine that Bob wants to create a swap to trade this - // invitation for bucks. He wants to invitation Dave as the - // counter-party. - const offerIssuerKeywordRecord = harden({ - Asset: invitationIssuer, - Price: bucksIssuer, - }); - const { creatorInvitation: bobSwapInvitation } = await E( - zoe, - ).startInstance(installations.atomicSwap, offerIssuerKeywordRecord); - - // Bob wants to swap an invitation with the same amount as his - // current invitation from Alice. He wants 1 buck in return. - const bobProposalSwap = harden({ - give: { Asset: optionAmounts }, - want: { Price: bucks(1n) }, - }); - - const bobSwapPayments = harden({ Asset: exclInvitation }); - - // Bob escrows his option in the swap - const bobSeatP = await E(zoe).offer( - bobSwapInvitation, - bobProposalSwap, - bobSwapPayments, - ); - const daveSwapInvitationP = E(bobSeatP).getOfferResult(); - // Bob makes an offer to the swap with his "higher order" - log('swap invitation made'); - await E(daveP).doSwapForOption(daveSwapInvitationP, optionAmounts); - - const bucksPayout = await E(bobSeatP).getPayout('Price'); - - // Bob deposits his winnings - await E(bucksPurseP).deposit(bucksPayout); - - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - await showPurseBalance(bucksPurseP, 'bobBucksPurse;', log); - }, - doSecondPriceAuctionBid: async invitation => { - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - const { value: invitationValue } = - await E(invitationIssuer).getAmountOf(exclInvitation); - installation === installations.secondPriceAuction || - assert.fail(X`wrong installation`); - assert( - keyEQ( - harden({ Asset: moolaIssuer, Ask: simoleanIssuer }), - issuerKeywordRecord, - ), - X`issuerKeywordRecord was not as expected`, - ); - assert( - keyEQ(invitationValue[0].customDetails?.minimumBid, simoleans(3n)), - ); - assert( - keyEQ(invitationValue[0].customDetails?.auctionedAssets, moola(1n)), - ); - - const proposal = harden({ - want: { Asset: moola(1n) }, - give: { Bid: simoleans(11n) }, - }); - const paymentKeywordRecord = { Bid: simoleanPayment }; - - secondPriceAuctionSeatP = E(zoe).offer( - exclInvitation, - proposal, - paymentKeywordRecord, - ); - log(`Bob: ${await E(secondPriceAuctionSeatP).getOfferResult()}`); - }, - doSecondPriceAuctionGetPayout: async () => { - const moolaPayout = await E(secondPriceAuctionSeatP).getPayout('Asset'); - const simoleanPayout = await E(secondPriceAuctionSeatP).getPayout('Bid'); + simoleans(0n).brand, + ); + log(`simoleanAmounts `, simoleanAmounts); - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); + const moolaForSimProposal = harden({ + give: { In: moola(3n) }, + want: { Out: simoleans(1n) }, + }); - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - }, - doAtomicSwap: async invitation => { - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - const { value: invitationValue } = - await E(invitationIssuer).getAmountOf(exclInvitation); - - assert(installation === installations.atomicSwap, X`wrong installation`); - assert( - keyEQ( - harden({ Asset: moolaIssuer, Price: simoleanIssuer }), - issuerKeywordRecord, - ), - X`issuers were not as expected`, - ); - keyEQ(invitationValue[0].customDetails?.asset, moola(3n)) || - assert.fail(X`Alice made a different offer than expected`); - keyEQ(invitationValue[0].customDetails?.price, simoleans(7n)) || - assert.fail(X`Alice made a different offer than expected`); - - const proposal = harden({ - want: { Asset: moola(3n) }, - give: { Price: simoleans(7n) }, - }); - const paymentKeywordRecord = { Price: simoleanPayment }; - - const seatP = await E(zoe).offer( - exclInvitation, - proposal, - paymentKeywordRecord, - ); - - log(await E(seatP).getOfferResult()); - - const moolaPayout = await E(seatP).getPayout('Asset'); - const simoleanPayout = await E(seatP).getPayout('Price'); - - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); - - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - }, + const moolaForSimPayments = harden({ In: moolaPayment }); + const buySeatP = await E(zoe).offer( + buyBInvitation, + moolaForSimProposal, + moolaForSimPayments, + ); - doSimpleExchange: async invitation => { - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - installation === installations.simpleExchange || - assert.fail(X`wrong installation`); - issuerKeywordRecord.Asset === moolaIssuer || - assert.fail(X`The first issuer should be the moola issuer`); - issuerKeywordRecord.Price === simoleanIssuer || - assert.fail(X`The second issuer should be the simolean issuer`); - - const bobBuyOrderProposal = harden({ - want: { Asset: moola(3n) }, - give: { Price: simoleans(7n) }, - exit: { onDemand: null }, - }); - const paymentKeywordRecord = { Price: simoleanPayment }; - - const seatP = await E(zoe).offer( - exclInvitation, - bobBuyOrderProposal, - paymentKeywordRecord, - ); - - log(await E(seatP).getOfferResult()); - - const moolaPayout = await E(seatP).getPayout('Asset'); - const simoleanPayout = await E(seatP).getPayout('Price'); - - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); - - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - }, - doSimpleExchangeUpdates: async (invitationP, m, s) => { - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitationP, - ); - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - installation === installations.simpleExchange || - assert.fail(X`wrong installation`); - issuerKeywordRecord.Asset === moolaIssuer || - assert.fail(X`The first issuer should be the moola issuer`); - issuerKeywordRecord.Price === simoleanIssuer || - assert.fail(X`The second issuer should be the simolean issuer`); - const bobBuyOrderProposal = harden({ - want: { Asset: moola(m) }, - give: { Price: simoleans(s) }, - exit: { onDemand: null }, - }); - if (m === 3n && s === 7n) { + log(await E(buySeatP).getOfferResult()); + + const moolaPayout1 = await E(buySeatP).getPayout('In'); + const simoleanPayout1 = await E(buySeatP).getPayout('Out'); + + await E(moolaPurseP).deposit(await moolaPayout1); + await E(simoleanPurseP).deposit(await simoleanPayout1); + + // Bob looks up how much moola he can get for 3 simoleans. It's 5 + const moolaProceeds = await E(publicFacet).getInputPrice( + simoleans(3n), + moola(0n).brand, + ); + log(`moola proceeds `, moolaProceeds); + + // Bob makes another offer and swaps + const bobSimsForMoolaProposal2 = harden({ + want: { Out: moola(5n) }, + give: { In: simoleans(3n) }, + }); await E(simoleanPurseP).deposit(simoleanPayment); - } - const simoleanPayment2 = await E(simoleanPurseP).withdraw(simoleans(s)); - const paymentKeywordRecord = { Price: simoleanPayment2 }; - const seatP = await E(zoe).offer( - invitation, - bobBuyOrderProposal, - paymentKeywordRecord, - ); - - log(await E(seatP).getOfferResult()); - - E(seatP) - .getPayout('Asset') - .then(moolaPayout => { - E(moolaPurseP).deposit(moolaPayout); + const bobSimPayment2 = await E(simoleanPurseP).withdraw(simoleans(3n)); + const simsForMoolaPayments2 = harden({ In: bobSimPayment2 }); + const invitation2 = E(publicFacet).makeSwapInInvitation(); + + const swapSeat2 = await E(zoe).offer( + invitation2, + bobSimsForMoolaProposal2, + simsForMoolaPayments2, + ); + + log(await E(swapSeat2).getOfferResult()); + + const moolaPayout2 = await E(swapSeat2).getPayout('Out'); + const simoleanPayout2 = await E(swapSeat2).getPayout('In'); + + await E(moolaPurseP).deposit(moolaPayout2); + await E(simoleanPurseP).deposit(simoleanPayout2); + + await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); + + // Bob looks up how much simoleans he'd have to pay for 3 moola. It's 6 + const simRequired = await E(publicFacet).getOutputPrice( + moola(3n), + simoleans(0n).brand, + ); + log(`simoleans required `, simRequired); + }, + + doBuyTickets: async (instance, invitation) => { + const publicFacet = await E(zoe).getPublicFacet(instance); + const terms = await E(zoe).getTerms(instance); + const ticketIssuer = await E(publicFacet).getItemsIssuer(); + const ticketBrand = await E(ticketIssuer).getBrand(); + + const availableTickets = await E(publicFacet).getAvailableItems(); + log('availableTickets: ', availableTickets); + // find the value corresponding to ticket #1 + assert(isSetValue(availableTickets.value)); + const ticket1Value = availableTickets.value.find( + ticket => ticket.number === 1, + ); + // make the corresponding amount + const ticket1Amount = AmountMath.make( + ticketBrand, + harden([ticket1Value]), + ); + const proposal = harden({ + give: { Money: terms.pricePerItem }, + want: { Items: ticket1Amount }, }); - E(seatP) - .getPayout('Price') - .then(simoleanPayout => { - E(simoleanPurseP).deposit(simoleanPayout); + + const paymentKeywordRecord = harden({ Money: moolaPayment }); + + const seat = await E(zoe).offer( + invitation, + proposal, + paymentKeywordRecord, + ); + const boughtTicketAmount = await E(ticketIssuer).getAmountOf( + E(seat).getPayout('Items'), + ); + log('boughtTicketAmount: ', boughtTicketAmount); + }, + + doOTCDesk: async untrustedInvitation => { + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + untrustedInvitation, + ); + const invitationValue = await E(zoe).getInvitationDetails(invitation); + assert(invitationValue.installation === installations.coveredCall); + + // Bob can use whatever keywords he wants + const proposal = harden({ + give: { Whatever1: simoleans(4n) }, + want: { Whatever2: moola(3n) }, + exit: { onDemand: null }, }); - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - }, + await E(simoleanPurseP).deposit(simoleanPayment); + const simoleanPayment1 = await E(simoleanPurseP).withdraw( + simoleans(4n), + ); - doAutoswap: async instance => { - const publicFacet = await E(zoe).getPublicFacet(instance); - const buyBInvitation = await E(publicFacet).makeSwapInInvitation(); - const installation = await E(zoe).getInstallation(buyBInvitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - assert(installation === installations.autoswap, X`wrong installation`); - const liquidityIssuer = await E(publicFacet).getLiquidityIssuer(); - assert( - keyEQ( - harden({ - Central: moolaIssuer, - Secondary: simoleanIssuer, - Liquidity: liquidityIssuer, - }), - issuerKeywordRecord, - ), - X`issuers were not as expected`, - ); - - // bob checks how many simoleans he can get for 3 moola - const simoleanAmounts = await E(publicFacet).getInputPrice( - moola(3n), - simoleans(0n).brand, - ); - log(`simoleanAmounts `, simoleanAmounts); - - const moolaForSimProposal = harden({ - give: { In: moola(3n) }, - want: { Out: simoleans(1n) }, - }); - - const moolaForSimPayments = harden({ In: moolaPayment }); - const buySeatP = await E(zoe).offer( - buyBInvitation, - moolaForSimProposal, - moolaForSimPayments, - ); - - log(await E(buySeatP).getOfferResult()); - - const moolaPayout1 = await E(buySeatP).getPayout('In'); - const simoleanPayout1 = await E(buySeatP).getPayout('Out'); - - await E(moolaPurseP).deposit(await moolaPayout1); - await E(simoleanPurseP).deposit(await simoleanPayout1); - - // Bob looks up how much moola he can get for 3 simoleans. It's 5 - const moolaProceeds = await E(publicFacet).getInputPrice( - simoleans(3n), - moola(0n).brand, - ); - log(`moola proceeds `, moolaProceeds); - - // Bob makes another offer and swaps - const bobSimsForMoolaProposal2 = harden({ - want: { Out: moola(5n) }, - give: { In: simoleans(3n) }, - }); - await E(simoleanPurseP).deposit(simoleanPayment); - const bobSimPayment2 = await E(simoleanPurseP).withdraw(simoleans(3n)); - const simsForMoolaPayments2 = harden({ In: bobSimPayment2 }); - const invitation2 = E(publicFacet).makeSwapInInvitation(); - - const swapSeat2 = await E(zoe).offer( - invitation2, - bobSimsForMoolaProposal2, - simsForMoolaPayments2, - ); - - log(await E(swapSeat2).getOfferResult()); - - const moolaPayout2 = await E(swapSeat2).getPayout('Out'); - const simoleanPayout2 = await E(swapSeat2).getPayout('In'); - - await E(moolaPurseP).deposit(moolaPayout2); - await E(simoleanPurseP).deposit(simoleanPayout2); - - await showPurseBalance(moolaPurseP, 'bobMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'bobSimoleanPurse', log); - - // Bob looks up how much simoleans he'd have to pay for 3 moola. It's 6 - const simRequired = await E(publicFacet).getOutputPrice( - moola(3n), - simoleans(0n).brand, - ); - log(`simoleans required `, simRequired); - }, + const seat = await E(zoe).offer(invitation, proposal, { + Whatever1: simoleanPayment1, + }); - doBuyTickets: async (instance, invitation) => { - const publicFacet = await E(zoe).getPublicFacet(instance); - const terms = await E(zoe).getTerms(instance); - const ticketIssuer = await E(publicFacet).getItemsIssuer(); - const ticketBrand = await E(ticketIssuer).getBrand(); - - const availableTickets = await E(publicFacet).getAvailableItems(); - log('availableTickets: ', availableTickets); - // find the value corresponding to ticket #1 - assert(isSetValue(availableTickets.value)); - const ticket1Value = availableTickets.value.find( - ticket => ticket.number === 1, - ); - // make the corresponding amount - const ticket1Amount = AmountMath.make( - ticketBrand, - harden([ticket1Value]), - ); - const proposal = harden({ - give: { Money: terms.pricePerItem }, - want: { Items: ticket1Amount }, - }); - - const paymentKeywordRecord = harden({ Money: moolaPayment }); - - const seat = await E(zoe).offer( - invitation, - proposal, - paymentKeywordRecord, - ); - const boughtTicketAmount = await E(ticketIssuer).getAmountOf( - E(seat).getPayout('Items'), - ); - log('boughtTicketAmount: ', boughtTicketAmount); - }, + log(await E(seat).getOfferResult()); - doOTCDesk: async untrustedInvitation => { - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - untrustedInvitation, - ); - const invitationValue = await E(zoe).getInvitationDetails(invitation); - assert(invitationValue.installation === installations.coveredCall); - - // Bob can use whatever keywords he wants - const proposal = harden({ - give: { Whatever1: simoleans(4n) }, - want: { Whatever2: moola(3n) }, - exit: { onDemand: null }, - }); - await E(simoleanPurseP).deposit(simoleanPayment); - const simoleanPayment1 = await E(simoleanPurseP).withdraw(simoleans(4n)); - - const seat = await E(zoe).offer(invitation, proposal, { - Whatever1: simoleanPayment1, - }); - - log(await E(seat).getOfferResult()); - - const moolaPayout = await E(seat).getPayout('Whatever2'); - const simoleansPayout = await E(seat).getPayout('Whatever1'); - - log(await E(moolaIssuer).getAmountOf(moolaPayout)); - log(await E(simoleanIssuer).getAmountOf(simoleansPayout)); + const moolaPayout = await E(seat).getPayout('Whatever2'); + const simoleansPayout = await E(seat).getPayout('Whatever1'); + + log(await E(moolaIssuer).getAmountOf(moolaPayout)); + log(await E(simoleanIssuer).getAmountOf(simoleansPayout)); + }, }, - }); + ); }; export function buildRootObject(vatPowers) { - return Far('root', { - build: (...args) => build(vatPowers.testLog, ...args), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (...args) => build(vatPowers.testLog, ...args), + }, + ); } diff --git a/packages/zoe/test/swingsetTests/zoe/vat-carol.js b/packages/zoe/test/swingsetTests/zoe/vat-carol.js index 717ae70ca7e..31ecd790446 100644 --- a/packages/zoe/test/swingsetTests/zoe/vat-carol.js +++ b/packages/zoe/test/swingsetTests/zoe/vat-carol.js @@ -14,62 +14,72 @@ const build = async (log, zoe, issuers, payments, installations) => { let secondPriceAuctionSeatP; - return Far('build', { - doSecondPriceAuctionBid: async invitationP => { - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitationP, - ); - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - const { value: invitationValue } = - await E(invitationIssuer).getAmountOf(invitation); - installation === installations.secondPriceAuction || - assert.fail(X`wrong installation`); - assert( - keyEQ( - harden({ Asset: moolaIssuer, Ask: simoleanIssuer }), - issuerKeywordRecord, - ), - X`issuerKeywordRecord were not as expected`, - ); - assert( - keyEQ(invitationValue[0].customDetails?.minimumBid, simoleans(3n)), - ); - assert( - keyEQ(invitationValue[0].customDetails?.auctionedAssets, moola(1n)), - ); + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + doSecondPriceAuctionBid: async invitationP => { + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitationP, + ); + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + const { value: invitationValue } = + await E(invitationIssuer).getAmountOf(invitation); + installation === installations.secondPriceAuction || + assert.fail(X`wrong installation`); + assert( + keyEQ( + harden({ Asset: moolaIssuer, Ask: simoleanIssuer }), + issuerKeywordRecord, + ), + X`issuerKeywordRecord were not as expected`, + ); + assert( + keyEQ(invitationValue[0].customDetails?.minimumBid, simoleans(3n)), + ); + assert( + keyEQ(invitationValue[0].customDetails?.auctionedAssets, moola(1n)), + ); - const proposal = harden({ - want: { Asset: moola(1n) }, - give: { Bid: simoleans(7n) }, - exit: { onDemand: null }, - }); - const paymentKeywordRecord = { Bid: simoleanPayment }; + const proposal = harden({ + want: { Asset: moola(1n) }, + give: { Bid: simoleans(7n) }, + exit: { onDemand: null }, + }); + const paymentKeywordRecord = { Bid: simoleanPayment }; - secondPriceAuctionSeatP = await E(zoe).offer( - invitation, - proposal, - paymentKeywordRecord, - ); - log(`Carol: ${await E(secondPriceAuctionSeatP).getOfferResult()}`); - }, - doSecondPriceAuctionGetPayout: async () => { - const moolaPayout = await E(secondPriceAuctionSeatP).getPayout('Asset'); - const simoleanPayout = await E(secondPriceAuctionSeatP).getPayout('Bid'); + secondPriceAuctionSeatP = await E(zoe).offer( + invitation, + proposal, + paymentKeywordRecord, + ); + log(`Carol: ${await E(secondPriceAuctionSeatP).getOfferResult()}`); + }, + doSecondPriceAuctionGetPayout: async () => { + const moolaPayout = await E(secondPriceAuctionSeatP).getPayout('Asset'); + const simoleanPayout = await E(secondPriceAuctionSeatP).getPayout( + 'Bid', + ); - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); - await showPurseBalance(moolaPurseP, 'carolMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'carolSimoleanPurse', log); + await showPurseBalance(moolaPurseP, 'carolMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'carolSimoleanPurse', log); + }, }, - }); + ); }; export function buildRootObject(vatPowers) { - return Far('root', { - build: (...args) => build(vatPowers.testLog, ...args), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (...args) => build(vatPowers.testLog, ...args), + }, + ); } diff --git a/packages/zoe/test/swingsetTests/zoe/vat-dave.js b/packages/zoe/test/swingsetTests/zoe/vat-dave.js index f6eba02fe3c..f8c50a824c7 100644 --- a/packages/zoe/test/swingsetTests/zoe/vat-dave.js +++ b/packages/zoe/test/swingsetTests/zoe/vat-dave.js @@ -15,160 +15,177 @@ const build = async (log, zoe, issuers, payments, installations, timer) => { let secondPriceAuctionSeatP; - return Far('build', { - doSecondPriceAuctionBid: async invitation => { - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - const { value: invitationValue } = - await E(invitationIssuer).getAmountOf(exclInvitation); - installation === installations.secondPriceAuction || - assert.fail(X`wrong installation`); - assert( - keyEQ( - harden({ Asset: moolaIssuer, Ask: simoleanIssuer }), - issuerKeywordRecord, - ), - X`issuerKeywordRecord were not as expected`, - ); - assert( - keyEQ(invitationValue[0].customDetails?.minimumBid, simoleans(3n)), - ); - assert( - keyEQ(invitationValue[0].customDetails?.auctionedAssets, moola(1n)), - ); - - const proposal = harden({ - want: { Asset: moola(1n) }, - give: { Bid: simoleans(5n) }, - exit: { onDemand: null }, - }); - const paymentKeywordRecord = { Bid: simoleanPayment }; - - secondPriceAuctionSeatP = await E(zoe).offer( - exclInvitation, - proposal, - paymentKeywordRecord, - ); - log(`Dave: ${await E(secondPriceAuctionSeatP).getOfferResult()}`); + return makeExo( + 'build', + M.interface('build', {}, { defaultGuards: 'passable' }), + { + doSecondPriceAuctionBid: async invitation => { + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + const { value: invitationValue } = + await E(invitationIssuer).getAmountOf(exclInvitation); + installation === installations.secondPriceAuction || + assert.fail(X`wrong installation`); + assert( + keyEQ( + harden({ Asset: moolaIssuer, Ask: simoleanIssuer }), + issuerKeywordRecord, + ), + X`issuerKeywordRecord were not as expected`, + ); + assert( + keyEQ(invitationValue[0].customDetails?.minimumBid, simoleans(3n)), + ); + assert( + keyEQ(invitationValue[0].customDetails?.auctionedAssets, moola(1n)), + ); + + const proposal = harden({ + want: { Asset: moola(1n) }, + give: { Bid: simoleans(5n) }, + exit: { onDemand: null }, + }); + const paymentKeywordRecord = { Bid: simoleanPayment }; + + secondPriceAuctionSeatP = await E(zoe).offer( + exclInvitation, + proposal, + paymentKeywordRecord, + ); + log(`Dave: ${await E(secondPriceAuctionSeatP).getOfferResult()}`); + }, + doSecondPriceAuctionGetPayout: async () => { + const moolaPayout = await E(secondPriceAuctionSeatP).getPayout('Asset'); + const simoleanPayout = await E(secondPriceAuctionSeatP).getPayout( + 'Bid', + ); + + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'daveMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'daveSimoleanPurse', log); + }, + + doSwapForOption: async (invitation, optionAmounts) => { + // Dave is looking to buy the option to trade his 7 simoleans for + // 3 moola, and is willing to pay 1 buck for the option. + const instance = await E(zoe).getInstance(invitation); + const installation = await E(zoe).getInstallation(invitation); + const issuerKeywordRecord = await E(zoe).getIssuers(instance); + const exclInvitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + invitation, + ); + const { value: invitationValue } = + await E(invitationIssuer).getAmountOf(exclInvitation); + + // TODO Check the integrity of the installation by its hash. + // https://github.com/Agoric/agoric-sdk/issues/3859 + // const installation = await E(zoe).getInstallation(invitation); + // const hash = await E(installation).getHash(); + // assert.is(hash, 'XXX'); + + assert( + installation === installations.atomicSwap, + X`wrong installation`, + ); + assert( + keyEQ( + harden({ Asset: invitationIssuer, Price: bucksIssuer }), + issuerKeywordRecord, + ), + X`issuerKeywordRecord were not as expected`, + ); + + const { customDetails: invitationCustomDetails } = invitationValue[0]; + assert(typeof invitationCustomDetails === 'object'); + const optionValue = optionAmounts.value; + const { customDetails: optionCustomDetails } = optionValue[0]; + assert(typeof optionCustomDetails === 'object'); + + // Dave expects that Bob has already made an offer in the swap + // with the following rules: + keyEQ(invitationCustomDetails.asset, optionAmounts) || + Fail`asset is the option`; + keyEQ(invitationCustomDetails.price, bucks(1n)) || + Fail`price is 1 buck`; + + optionValue[0].description === 'exerciseOption' || + Fail`wrong invitation`; + AmountMath.isEqual( + optionCustomDetails.underlyingAssets.UnderlyingAsset, + moola(3n), + ) || Fail`wrong underlying asset`; + AmountMath.isEqual( + optionCustomDetails.strikePrice.StrikePrice, + simoleans(7n), + ) || Fail`wrong strike price`; + optionCustomDetails.expirationDate === 100n || + Fail`wrong expiration date`; + optionCustomDetails.timeAuthority === timer || Fail`wrong timer`; + + // Dave escrows his 1 buck with Zoe and forms his proposal + const daveSwapProposal = harden({ + want: { Asset: optionAmounts }, + give: { Price: bucks(1n) }, + }); + const daveSwapPayments = harden({ Price: bucksPayment }); + const seatP = await E(zoe).offer( + exclInvitation, + daveSwapProposal, + daveSwapPayments, + ); + + log(await E(seatP).getOfferResult()); + + const daveOption = await E(seatP).getPayout('Asset'); + const daveBucksPayout = await E(seatP).getPayout('Price'); + + // Dave exercises his option by making an offer to the covered + // call. First, he escrows with Zoe. + + const daveCoveredCallProposal = harden({ + want: { UnderlyingAsset: moola(3n) }, + give: { StrikePrice: simoleans(7n) }, + }); + const daveCoveredCallPayments = harden({ + StrikePrice: simoleanPayment, + }); + const optionSeatP = await E(zoe).offer( + daveOption, + daveCoveredCallProposal, + daveCoveredCallPayments, + ); + + log(await E(optionSeatP).getOfferResult()); + + const moolaPayout = await E(optionSeatP).getPayout('UnderlyingAsset'); + const simoleanPayout = await E(optionSeatP).getPayout('StrikePrice'); + + await E(bucksPurseP).deposit(daveBucksPayout); + await E(moolaPurseP).deposit(moolaPayout); + await E(simoleanPurseP).deposit(simoleanPayout); + + await showPurseBalance(moolaPurseP, 'daveMoolaPurse', log); + await showPurseBalance(simoleanPurseP, 'daveSimoleanPurse', log); + await showPurseBalance(bucksPurseP, 'daveBucksPurse', log); + }, }, - doSecondPriceAuctionGetPayout: async () => { - const moolaPayout = await E(secondPriceAuctionSeatP).getPayout('Asset'); - const simoleanPayout = await E(secondPriceAuctionSeatP).getPayout('Bid'); - - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); - - await showPurseBalance(moolaPurseP, 'daveMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'daveSimoleanPurse', log); - }, - - doSwapForOption: async (invitation, optionAmounts) => { - // Dave is looking to buy the option to trade his 7 simoleans for - // 3 moola, and is willing to pay 1 buck for the option. - const instance = await E(zoe).getInstance(invitation); - const installation = await E(zoe).getInstallation(invitation); - const issuerKeywordRecord = await E(zoe).getIssuers(instance); - const exclInvitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - invitation, - ); - const { value: invitationValue } = - await E(invitationIssuer).getAmountOf(exclInvitation); - - // TODO Check the integrity of the installation by its hash. - // https://github.com/Agoric/agoric-sdk/issues/3859 - // const installation = await E(zoe).getInstallation(invitation); - // const hash = await E(installation).getHash(); - // assert.is(hash, 'XXX'); - - assert(installation === installations.atomicSwap, X`wrong installation`); - assert( - keyEQ( - harden({ Asset: invitationIssuer, Price: bucksIssuer }), - issuerKeywordRecord, - ), - X`issuerKeywordRecord were not as expected`, - ); - - const { customDetails: invitationCustomDetails } = invitationValue[0]; - assert(typeof invitationCustomDetails === 'object'); - const optionValue = optionAmounts.value; - const { customDetails: optionCustomDetails } = optionValue[0]; - assert(typeof optionCustomDetails === 'object'); - - // Dave expects that Bob has already made an offer in the swap - // with the following rules: - keyEQ(invitationCustomDetails.asset, optionAmounts) || - Fail`asset is the option`; - keyEQ(invitationCustomDetails.price, bucks(1n)) || Fail`price is 1 buck`; - - optionValue[0].description === 'exerciseOption' || Fail`wrong invitation`; - AmountMath.isEqual( - optionCustomDetails.underlyingAssets.UnderlyingAsset, - moola(3n), - ) || Fail`wrong underlying asset`; - AmountMath.isEqual( - optionCustomDetails.strikePrice.StrikePrice, - simoleans(7n), - ) || Fail`wrong strike price`; - optionCustomDetails.expirationDate === 100n || - Fail`wrong expiration date`; - optionCustomDetails.timeAuthority === timer || Fail`wrong timer`; - - // Dave escrows his 1 buck with Zoe and forms his proposal - const daveSwapProposal = harden({ - want: { Asset: optionAmounts }, - give: { Price: bucks(1n) }, - }); - const daveSwapPayments = harden({ Price: bucksPayment }); - const seatP = await E(zoe).offer( - exclInvitation, - daveSwapProposal, - daveSwapPayments, - ); - - log(await E(seatP).getOfferResult()); - - const daveOption = await E(seatP).getPayout('Asset'); - const daveBucksPayout = await E(seatP).getPayout('Price'); - - // Dave exercises his option by making an offer to the covered - // call. First, he escrows with Zoe. - - const daveCoveredCallProposal = harden({ - want: { UnderlyingAsset: moola(3n) }, - give: { StrikePrice: simoleans(7n) }, - }); - const daveCoveredCallPayments = harden({ StrikePrice: simoleanPayment }); - const optionSeatP = await E(zoe).offer( - daveOption, - daveCoveredCallProposal, - daveCoveredCallPayments, - ); - - log(await E(optionSeatP).getOfferResult()); - - const moolaPayout = await E(optionSeatP).getPayout('UnderlyingAsset'); - const simoleanPayout = await E(optionSeatP).getPayout('StrikePrice'); - - await E(bucksPurseP).deposit(daveBucksPayout); - await E(moolaPurseP).deposit(moolaPayout); - await E(simoleanPurseP).deposit(simoleanPayout); - - await showPurseBalance(moolaPurseP, 'daveMoolaPurse', log); - await showPurseBalance(simoleanPurseP, 'daveSimoleanPurse', log); - await showPurseBalance(bucksPurseP, 'daveBucksPurse', log); - }, - }); + ); }; export function buildRootObject(vatPowers) { - return Far('root', { - build: (...args) => build(vatPowers.testLog, ...args), - }); + return makeExo( + 'root', + M.interface('root', {}, { defaultGuards: 'passable' }), + { + build: (...args) => build(vatPowers.testLog, ...args), + }, + ); } diff --git a/packages/zoe/test/unitTests/bounty.js b/packages/zoe/test/unitTests/bounty.js index 0882826b1ee..9db65fd89e1 100644 --- a/packages/zoe/test/unitTests/bounty.js +++ b/packages/zoe/test/unitTests/bounty.js @@ -59,16 +59,20 @@ const start = async zcf => { Fee: feeAmount, }); - const wakeHandler = Far('wakeHandler', { - wake: async () => { - const reply = await E(oracle).query('state'); - if (reply.event === condition) { - payOffBounty(bountySeat); - } else { - refundBounty(bountySeat); - } + const wakeHandler = makeExo( + 'wakeHandler', + M.interface('wakeHandler', {}, { defaultGuards: 'passable' }), + { + wake: async () => { + const reply = await E(oracle).query('state'); + if (reply.event === condition) { + payOffBounty(bountySeat); + } else { + refundBounty(bountySeat); + } + }, }, - }); + ); timer.setWakeup(deadline, wakeHandler); } diff --git a/packages/zoe/test/unitTests/contractSupport/test-zoeHelpers.js b/packages/zoe/test/unitTests/contractSupport/test-zoeHelpers.js index 03f7e19a100..3dda8e5f844 100644 --- a/packages/zoe/test/unitTests/contractSupport/test-zoeHelpers.js +++ b/packages/zoe/test/unitTests/contractSupport/test-zoeHelpers.js @@ -21,30 +21,42 @@ function makeMockTradingZcfBuilder() { const allocs = makeScalarMapStore('offerHandle'); const reallocatedStagings = []; - return Far('mockTradingZcfBuilder', { - addOffer: (keyword, offer) => offers.init(keyword, offer), - addAllocation: (keyword, alloc) => allocs.init(keyword, alloc), - /** @returns {ZCF} */ - build: () => - Far('mockZCF', { - // @ts-expect-error mock - getZoeService: () => {}, - reallocate: (...seatStagings) => { - reallocatedStagings.push(...seatStagings); - }, - getReallocatedStagings: () => reallocatedStagings, - }), - }); + return makeExo( + 'mockTradingZcfBuilder', + M.interface('mockTradingZcfBuilder', {}, { defaultGuards: 'passable' }), + { + addOffer: (keyword, offer) => offers.init(keyword, offer), + addAllocation: (keyword, alloc) => allocs.init(keyword, alloc), + /** @returns {ZCF} */ + build: () => + makeExo( + 'mockZCF', + M.interface('mockZCF', {}, { defaultGuards: 'passable' }), + { + // @ts-expect-error mock + getZoeService: () => {}, + reallocate: (...seatStagings) => { + reallocatedStagings.push(...seatStagings); + }, + getReallocatedStagings: () => reallocatedStagings, + }, + ), + }, + ); } test('ZoeHelpers satisfies blank proposal', t => { const { moola } = setup(); /** @type {ZCFSeat} */ // @ts-expect-error cast - const fakeZcfSeat = Far('fakeZcfSeat', { - getCurrentAllocation: () => harden({ Asset: moola(10n) }), - getProposal: () => harden({}), - }); + const fakeZcfSeat = makeExo( + 'fakeZcfSeat', + M.interface('fakeZcfSeat', {}, { defaultGuards: 'passable' }), + { + getCurrentAllocation: () => harden({ Asset: moola(10n) }), + getProposal: () => harden({}), + }, + ); const mockZCFBuilder = makeMockTradingZcfBuilder(); const mockZCF = mockZCFBuilder.build(); t.truthy( @@ -57,10 +69,14 @@ test('ZoeHelpers satisfies simple proposal', t => { const { moola, simoleans } = setup(); /** @type {ZCFSeat} */ // @ts-expect-error cast - const fakeZcfSeat = Far('fakeZcfSeat', { - getCurrentAllocation: () => harden({ Asset: moola(10n) }), - getProposal: () => harden({ want: { Desire: moola(30n) } }), - }); + const fakeZcfSeat = makeExo( + 'fakeZcfSeat', + M.interface('fakeZcfSeat', {}, { defaultGuards: 'passable' }), + { + getCurrentAllocation: () => harden({ Asset: moola(10n) }), + getProposal: () => harden({ want: { Desire: moola(30n) } }), + }, + ); const mockZCFBuilder = makeMockTradingZcfBuilder(); const mockZCF = mockZCFBuilder.build(); t.falsy( @@ -92,11 +108,15 @@ test('ZoeHelpers satisfies() with give', t => { const { moola, bucks } = setup(); /** @type {ZCFSeat} */ // @ts-expect-error cast - const fakeZcfSeat = Far('fakeZcfSeat', { - getCurrentAllocation: () => harden({ Charge: moola(30n) }), - getProposal: () => - harden({ give: { Charge: moola(30n) }, want: { Desire: bucks(5n) } }), - }); + const fakeZcfSeat = makeExo( + 'fakeZcfSeat', + M.interface('fakeZcfSeat', {}, { defaultGuards: 'passable' }), + { + getCurrentAllocation: () => harden({ Charge: moola(30n) }), + getProposal: () => + harden({ give: { Charge: moola(30n) }, want: { Desire: bucks(5n) } }), + }, + ); const mockZCFBuilder = makeMockTradingZcfBuilder(); const mockZCF = mockZCFBuilder.build(); t.falsy( diff --git a/packages/zoe/test/unitTests/contracts/escrowToVote.js b/packages/zoe/test/unitTests/contracts/escrowToVote.js index eb342e1275f..9ae982cc1f1 100644 --- a/packages/zoe/test/unitTests/contracts/escrowToVote.js +++ b/packages/zoe/test/unitTests/contracts/escrowToVote.js @@ -49,59 +49,67 @@ const start = zcf => { assertProposalShape(voterSeat, { give: { Assets: null }, }); - const voter = Far('voter', { - /** - * Vote on a particular issue - * - * @param {string} response - 'YES' || 'NO' - */ - vote: response => { - // Throw if the offer is no longer active, i.e. the user has - // completed their offer and the assets are no longer escrowed. - assert(!voterSeat.hasExited(), 'the voter seat has exited'); + const voter = makeExo( + 'voter', + M.interface('voter', {}, { defaultGuards: 'passable' }), + { + /** + * Vote on a particular issue + * + * @param {string} response - 'YES' || 'NO' + */ + vote: response => { + // Throw if the offer is no longer active, i.e. the user has + // completed their offer and the assets are no longer escrowed. + assert(!voterSeat.hasExited(), 'the voter seat has exited'); - assertResponse(response); + assertResponse(response); - // Record the response - if (seatToResponse.has(voterSeat)) { - seatToResponse.set(voterSeat, response); - } else { - seatToResponse.init(voterSeat, response); - } - return `Successfully voted '${response}'`; + // Record the response + if (seatToResponse.has(voterSeat)) { + seatToResponse.set(voterSeat, response); + } else { + seatToResponse.init(voterSeat, response); + } + return `Successfully voted '${response}'`; + }, }, - }); + ); return voter; }; - const creatorFacet = Far('creatorFacet', { - closeElection: () => { - assert(electionOpen, 'the election is already closed'); - // YES | NO to Nat - const tally = new Map(); - tally.set('YES', AmountMath.makeEmpty(assetsBrand)); - tally.set('NO', AmountMath.makeEmpty(assetsBrand)); + const creatorFacet = makeExo( + 'creatorFacet', + M.interface('creatorFacet', {}, { defaultGuards: 'passable' }), + { + closeElection: () => { + assert(electionOpen, 'the election is already closed'); + // YES | NO to Nat + const tally = new Map(); + tally.set('YES', AmountMath.makeEmpty(assetsBrand)); + tally.set('NO', AmountMath.makeEmpty(assetsBrand)); - for (const [seat, response] of seatToResponse.entries()) { - if (!seat.hasExited()) { - const escrowedAmount = seat.getAmountAllocated('Assets'); - const sumSoFar = tally.get(response); - tally.set(response, AmountMath.add(escrowedAmount, sumSoFar)); - seat.exit('Thank you for voting'); + for (const [seat, response] of seatToResponse.entries()) { + if (!seat.hasExited()) { + const escrowedAmount = seat.getAmountAllocated('Assets'); + const sumSoFar = tally.get(response); + tally.set(response, AmountMath.add(escrowedAmount, sumSoFar)); + seat.exit('Thank you for voting'); + } } - } - electionOpen = false; + electionOpen = false; - return harden({ - YES: tally.get('YES'), - NO: tally.get('NO'), - }); - }, - makeVoterInvitation: () => { - assert(electionOpen, 'the election is closed'); - return zcf.makeInvitation(voteHandler, 'voter'); + return harden({ + YES: tally.get('YES'), + NO: tally.get('NO'), + }); + }, + makeVoterInvitation: () => { + assert(electionOpen, 'the election is closed'); + return zcf.makeInvitation(voteHandler, 'voter'); + }, }, - }); + ); // Return the creatorFacet so that the creator of the // contract instance can hand out scarce votes and close the election. diff --git a/packages/zoe/test/unitTests/contracts/test-atomicSwap.js b/packages/zoe/test/unitTests/contracts/test-atomicSwap.js index dd72fb4750c..025427dd4b3 100644 --- a/packages/zoe/test/unitTests/contracts/test-atomicSwap.js +++ b/packages/zoe/test/unitTests/contracts/test-atomicSwap.js @@ -86,73 +86,77 @@ test('zoe - atomicSwap', async t => { const makeBob = (installation, simoleanPayment) => { const moolaPurse = moolaKit.issuer.makeEmptyPurse(); const simoleanPurse = simoleanKit.issuer.makeEmptyPurse(); - return Far('bob', { - offer: async untrustedInvitation => { - const invitationIssuer = await E(zoe).getInvitationIssuer(); - - // Bob is able to use the trusted invitationIssuer from Zoe to - // transform an untrusted invitation that Alice also has access to, to - // an - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - untrustedInvitation, - ); - const invitationValue = await E(zoe).getInvitationDetails(invitation); - t.is( - invitationValue.installation, - installation, - 'installation is atomicSwap', - ); - t.deepEqual( - invitationValue.customDetails?.asset, - moola(3n), - `asset to be traded is 3 moola`, - ); - t.deepEqual( - invitationValue.customDetails?.price, - simoleans(7n), - `price is 7 simoleans, so bob must give that`, - ); - - const proposal = harden({ - give: { Price: simoleans(7n) }, - want: { Asset: moola(3n) }, - exit: { onDemand: null }, - }); - const payments = { Price: simoleanPayment }; + return makeExo( + 'bob', + M.interface('bob', {}, { defaultGuards: 'passable' }), + { + offer: async untrustedInvitation => { + const invitationIssuer = await E(zoe).getInvitationIssuer(); + + // Bob is able to use the trusted invitationIssuer from Zoe to + // transform an untrusted invitation that Alice also has access to, to + // an + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + untrustedInvitation, + ); + const invitationValue = await E(zoe).getInvitationDetails(invitation); + t.is( + invitationValue.installation, + installation, + 'installation is atomicSwap', + ); + t.deepEqual( + invitationValue.customDetails?.asset, + moola(3n), + `asset to be traded is 3 moola`, + ); + t.deepEqual( + invitationValue.customDetails?.price, + simoleans(7n), + `price is 7 simoleans, so bob must give that`, + ); - const seat = await E(zoe).offer(invitation, proposal, payments); + const proposal = harden({ + give: { Price: simoleans(7n) }, + want: { Asset: moola(3n) }, + exit: { onDemand: null }, + }); + const payments = { Price: simoleanPayment }; - t.is( - await E(seat).getOfferResult(), - 'The offer has been accepted. Once the contract has been completed, please check your payout', - ); + const seat = await E(zoe).offer(invitation, proposal, payments); - const r1 = E(seat) - .getPayout('Asset') - .then(payment => moolaPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual( - amountDeposited, - proposal.want.Asset, - `Bob got what he wanted`, - ), + t.is( + await E(seat).getOfferResult(), + 'The offer has been accepted. Once the contract has been completed, please check your payout', ); - const r2 = E(seat) - .getPayout('Price') - .then(payment => simoleanPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual( - amountDeposited, - simoleans(0n), - `Bob didn't get anything back`, - ), - ); - await r1; - await r2; + const r1 = E(seat) + .getPayout('Asset') + .then(payment => moolaPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual( + amountDeposited, + proposal.want.Asset, + `Bob got what he wanted`, + ), + ); + + const r2 = E(seat) + .getPayout('Price') + .then(payment => simoleanPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual( + amountDeposited, + simoleans(0n), + `Bob didn't get anything back`, + ), + ); + await r1; + await r2; + }, }, - }); + ); }; const alice = await makeAlice(await E(moolaKit.mint).mintPayment(moola(3n))); @@ -250,75 +254,79 @@ test('zoe - non-fungible atomicSwap', async t => { }; const makeBob = (installation, rpgPayment) => { - return Far('bob', { - offer: async (untrustedInvitation, calico37Amount, vorpalAmount) => { - const ccPurse = ccIssuer.makeEmptyPurse(); - const rpgPurse = rpgIssuer.makeEmptyPurse(); - - const invitationIssuer = await E(zoe).getInvitationIssuer(); - - // Bob is able to use the trusted invitationIssuer from Zoe to - // transform an untrusted invitation that Alice also has access to, to - // an - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - untrustedInvitation, - ); - const invitationValue = await E(zoe).getInvitationDetails(invitation); - - t.is( - invitationValue.installation, - installation, - 'installation is atomicSwap', - ); - t.deepEqual( - invitationValue.customDetails?.asset, - calico37Amount, - `asset to be traded is a particular crypto cat`, - ); - t.deepEqual( - invitationValue.customDetails?.price, - vorpalAmount, - `price is vorpalAmount, so bob must give that`, - ); + return makeExo( + 'bob', + M.interface('bob', {}, { defaultGuards: 'passable' }), + { + offer: async (untrustedInvitation, calico37Amount, vorpalAmount) => { + const ccPurse = ccIssuer.makeEmptyPurse(); + const rpgPurse = rpgIssuer.makeEmptyPurse(); + + const invitationIssuer = await E(zoe).getInvitationIssuer(); + + // Bob is able to use the trusted invitationIssuer from Zoe to + // transform an untrusted invitation that Alice also has access to, to + // an + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + untrustedInvitation, + ); + const invitationValue = await E(zoe).getInvitationDetails(invitation); - const proposal = harden({ - give: { Price: vorpalAmount }, - want: { Asset: calico37Amount }, - exit: { onDemand: null }, - }); - const payments = { Price: rpgPayment }; + t.is( + invitationValue.installation, + installation, + 'installation is atomicSwap', + ); + t.deepEqual( + invitationValue.customDetails?.asset, + calico37Amount, + `asset to be traded is a particular crypto cat`, + ); + t.deepEqual( + invitationValue.customDetails?.price, + vorpalAmount, + `price is vorpalAmount, so bob must give that`, + ); - const seat = await E(zoe).offer(invitation, proposal, payments); + const proposal = harden({ + give: { Price: vorpalAmount }, + want: { Asset: calico37Amount }, + exit: { onDemand: null }, + }); + const payments = { Price: rpgPayment }; - t.is( - await E(seat).getOfferResult(), - 'The offer has been accepted. Once the contract has been completed, please check your payout', - ); + const seat = await E(zoe).offer(invitation, proposal, payments); - await seat - .getPayout('Asset') - .then(payment => ccPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual( - amountDeposited, - proposal.want.Asset, - `Bob got what he wanted`, - ), + t.is( + await E(seat).getOfferResult(), + 'The offer has been accepted. Once the contract has been completed, please check your payout', ); - await seat - .getPayout('Price') - .then(payment => rpgPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual( - amountDeposited, - rpgItems(harden([])), - `Bob didn't get anything back`, - ), - ); + await seat + .getPayout('Asset') + .then(payment => ccPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual( + amountDeposited, + proposal.want.Asset, + `Bob got what he wanted`, + ), + ); + + await seat + .getPayout('Price') + .then(payment => rpgPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual( + amountDeposited, + rpgItems(harden([])), + `Bob didn't get anything back`, + ), + ); + }, }, - }); + ); }; const calico37Amount = cryptoCats(harden(['calico #37'])); diff --git a/packages/zoe/test/unitTests/contracts/test-auction.js b/packages/zoe/test/unitTests/contracts/test-auction.js index 4419cc8c899..586c1575d6c 100644 --- a/packages/zoe/test/unitTests/contracts/test-auction.js +++ b/packages/zoe/test/unitTests/contracts/test-auction.js @@ -90,119 +90,127 @@ test('zoe - secondPriceAuction w/ 3 bids', async t => { const makeBob = (installation, simoleanPayment) => { const moolaPurse = moolaKit.issuer.makeEmptyPurse(); const simoleanPurse = simoleanKit.issuer.makeEmptyPurse(); - return Far('bob', { - offer: async untrustedInvitation => { - const invitationIssuer = await E(zoe).getInvitationIssuer(); - - // Bob is able to use the trusted invitationIssuer from Zoe to - // transform an untrusted invitation that Alice also has access to, to - // an - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - untrustedInvitation, - ); + return makeExo( + 'bob', + M.interface('bob', {}, { defaultGuards: 'passable' }), + { + offer: async untrustedInvitation => { + const invitationIssuer = await E(zoe).getInvitationIssuer(); + + // Bob is able to use the trusted invitationIssuer from Zoe to + // transform an untrusted invitation that Alice also has access to, to + // an + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + untrustedInvitation, + ); - const invitationValue = await E(zoe).getInvitationDetails(invitation); + const invitationValue = await E(zoe).getInvitationDetails(invitation); - t.is( - invitationValue.installation, - installation, - 'installation is secondPriceAuction', - ); - t.deepEqual( - invitationValue.customDetails?.auctionedAssets, - moola(1n), - `asset to be auctioned is 1 moola`, - ); - t.deepEqual( - invitationValue.customDetails?.minimumBid, - simoleans(3n), - `minimum bid is 3 simoleans`, - ); - - t.deepEqual( - invitationValue.customDetails?.bidDuration, - 1n, - `auction will be closed after 1 tick according to the timeAuthority`, - ); + t.is( + invitationValue.installation, + installation, + 'installation is secondPriceAuction', + ); + t.deepEqual( + invitationValue.customDetails?.auctionedAssets, + moola(1n), + `asset to be auctioned is 1 moola`, + ); + t.deepEqual( + invitationValue.customDetails?.minimumBid, + simoleans(3n), + `minimum bid is 3 simoleans`, + ); - const proposal = harden({ - give: { Bid: simoleans(11n) }, - want: { Asset: moola(1n) }, - }); - const payments = { Bid: simoleanPayment }; + t.deepEqual( + invitationValue.customDetails?.bidDuration, + 1n, + `auction will be closed after 1 tick according to the timeAuthority`, + ); - const seat = await E(zoe).offer(invitation, proposal, payments); + const proposal = harden({ + give: { Bid: simoleans(11n) }, + want: { Asset: moola(1n) }, + }); + const payments = { Bid: simoleanPayment }; - t.is( - await E(seat).getOfferResult(), - 'The offer has been accepted. Once the contract has been completed, please check your payout', - ); - return seat; - }, - collectPayout: async seat => { - await E(seat) - .getPayout('Asset') - .then(payment => moolaPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual(amountDeposited, moola(1n), `Bob wins the auction`), - ); + const seat = await E(zoe).offer(invitation, proposal, payments); - await E(seat) - .getPayout('Bid') - .then(payment => simoleanPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual( - amountDeposited, - simoleans(4n), - `Bob gets the difference between the second-price bid (Carol's 7 simoleans) and his bid back`, - ), + t.is( + await E(seat).getOfferResult(), + 'The offer has been accepted. Once the contract has been completed, please check your payout', ); + return seat; + }, + collectPayout: async seat => { + await E(seat) + .getPayout('Asset') + .then(payment => moolaPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual(amountDeposited, moola(1n), `Bob wins the auction`), + ); + + await E(seat) + .getPayout('Bid') + .then(payment => simoleanPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual( + amountDeposited, + simoleans(4n), + `Bob gets the difference between the second-price bid (Carol's 7 simoleans) and his bid back`, + ), + ); + }, }, - }); + ); }; const makeLosingBidder = (bidAmount, simoleanPayment) => { const moolaPurse = moolaKit.issuer.makeEmptyPurse(); const simoleanPurse = simoleanKit.issuer.makeEmptyPurse(); - return Far('losing bidder', { - offer: async untrustedInvitation => { - const invitationIssuer = await E(zoe).getInvitationIssuer(); - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - untrustedInvitation, - ); - - const proposal = harden({ - give: { Bid: bidAmount }, - want: { Asset: moola(1n) }, - }); - const payments = { Bid: simoleanPayment }; + return makeExo( + 'losing bidder', + M.interface('losing bidder', {}, { defaultGuards: 'passable' }), + { + offer: async untrustedInvitation => { + const invitationIssuer = await E(zoe).getInvitationIssuer(); + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + untrustedInvitation, + ); - const seat = await E(zoe).offer(invitation, proposal, payments); + const proposal = harden({ + give: { Bid: bidAmount }, + want: { Asset: moola(1n) }, + }); + const payments = { Bid: simoleanPayment }; - t.is( - await E(seat).getOfferResult(), - 'The offer has been accepted. Once the contract has been completed, please check your payout', - ); - return seat; - }, - collectPayout: async seat => { - await E(seat) - .getPayout('Asset') - .then(payment => moolaPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual(amountDeposited, moola(0n), `didn't win the auction`), - ); + const seat = await E(zoe).offer(invitation, proposal, payments); - await E(seat) - .getPayout('Bid') - .then(payment => simoleanPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual(amountDeposited, bidAmount, `full refund`), + t.is( + await E(seat).getOfferResult(), + 'The offer has been accepted. Once the contract has been completed, please check your payout', ); + return seat; + }, + collectPayout: async seat => { + await E(seat) + .getPayout('Asset') + .then(payment => moolaPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual(amountDeposited, moola(0n), `didn't win the auction`), + ); + + await E(seat) + .getPayout('Bid') + .then(payment => simoleanPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual(amountDeposited, bidAmount, `full refund`), + ); + }, }, - }); + ); }; // Setup Alice @@ -917,119 +925,127 @@ test('zoe - firstPriceAuction w/ 3 bids', async t => { const makeBob = (installation, simoleanPayment) => { const moolaPurse = moolaKit.issuer.makeEmptyPurse(); const simoleanPurse = simoleanKit.issuer.makeEmptyPurse(); - return Far('bob', { - offer: async untrustedInvitation => { - const invitationIssuer = await E(zoe).getInvitationIssuer(); - - // Bob is able to use the trusted invitationIssuer from Zoe to - // transform an untrusted invitation that Alice also has access to, to - // an - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - untrustedInvitation, - ); + return makeExo( + 'bob', + M.interface('bob', {}, { defaultGuards: 'passable' }), + { + offer: async untrustedInvitation => { + const invitationIssuer = await E(zoe).getInvitationIssuer(); + + // Bob is able to use the trusted invitationIssuer from Zoe to + // transform an untrusted invitation that Alice also has access to, to + // an + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + untrustedInvitation, + ); - const invitationValue = await E(zoe).getInvitationDetails(invitation); + const invitationValue = await E(zoe).getInvitationDetails(invitation); - t.is( - invitationValue.installation, - installation, - 'installation is secondPriceAuction', - ); - t.deepEqual( - invitationValue.customDetails?.auctionedAssets, - moola(1n), - `asset to be auctioned is 1 moola`, - ); - t.deepEqual( - invitationValue.customDetails?.minimumBid, - simoleans(3n), - `minimum bid is 3 simoleans`, - ); - - t.deepEqual( - invitationValue.customDetails?.bidDuration, - 1n, - `auction will be closed after 1 tick according to the timeAuthority`, - ); + t.is( + invitationValue.installation, + installation, + 'installation is secondPriceAuction', + ); + t.deepEqual( + invitationValue.customDetails?.auctionedAssets, + moola(1n), + `asset to be auctioned is 1 moola`, + ); + t.deepEqual( + invitationValue.customDetails?.minimumBid, + simoleans(3n), + `minimum bid is 3 simoleans`, + ); - const proposal = harden({ - give: { Bid: simoleans(11n) }, - want: { Asset: moola(1n) }, - }); - const payments = { Bid: simoleanPayment }; + t.deepEqual( + invitationValue.customDetails?.bidDuration, + 1n, + `auction will be closed after 1 tick according to the timeAuthority`, + ); - const seat = await E(zoe).offer(invitation, proposal, payments); + const proposal = harden({ + give: { Bid: simoleans(11n) }, + want: { Asset: moola(1n) }, + }); + const payments = { Bid: simoleanPayment }; - t.is( - await E(seat).getOfferResult(), - 'The offer has been accepted. Once the contract has been completed, please check your payout', - ); - return seat; - }, - collectPayout: async seat => { - await E(seat) - .getPayout('Asset') - .then(payment => moolaPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual(amountDeposited, moola(1n), `Bob wins the auction`), - ); + const seat = await E(zoe).offer(invitation, proposal, payments); - await E(seat) - .getPayout('Bid') - .then(payment => simoleanPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual( - amountDeposited, - simoleans(0n), - `Bob gets the difference between his bid back`, - ), + t.is( + await E(seat).getOfferResult(), + 'The offer has been accepted. Once the contract has been completed, please check your payout', ); + return seat; + }, + collectPayout: async seat => { + await E(seat) + .getPayout('Asset') + .then(payment => moolaPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual(amountDeposited, moola(1n), `Bob wins the auction`), + ); + + await E(seat) + .getPayout('Bid') + .then(payment => simoleanPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual( + amountDeposited, + simoleans(0n), + `Bob gets the difference between his bid back`, + ), + ); + }, }, - }); + ); }; const makeLosingBidder = (bidAmount, simoleanPayment) => { const moolaPurse = moolaKit.issuer.makeEmptyPurse(); const simoleanPurse = simoleanKit.issuer.makeEmptyPurse(); - return Far('losing bidder', { - offer: async untrustedInvitation => { - const invitationIssuer = await E(zoe).getInvitationIssuer(); - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - untrustedInvitation, - ); - - const proposal = harden({ - give: { Bid: bidAmount }, - want: { Asset: moola(1n) }, - }); - const payments = { Bid: simoleanPayment }; + return makeExo( + 'losing bidder', + M.interface('losing bidder', {}, { defaultGuards: 'passable' }), + { + offer: async untrustedInvitation => { + const invitationIssuer = await E(zoe).getInvitationIssuer(); + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + untrustedInvitation, + ); - const seat = await E(zoe).offer(invitation, proposal, payments); + const proposal = harden({ + give: { Bid: bidAmount }, + want: { Asset: moola(1n) }, + }); + const payments = { Bid: simoleanPayment }; - t.is( - await E(seat).getOfferResult(), - 'The offer has been accepted. Once the contract has been completed, please check your payout', - ); - return seat; - }, - collectPayout: async seat => { - await E(seat) - .getPayout('Asset') - .then(payment => moolaPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual(amountDeposited, moola(0n), `didn't win the auction`), - ); + const seat = await E(zoe).offer(invitation, proposal, payments); - await E(seat) - .getPayout('Bid') - .then(payment => simoleanPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual(amountDeposited, bidAmount, `full refund`), + t.is( + await E(seat).getOfferResult(), + 'The offer has been accepted. Once the contract has been completed, please check your payout', ); + return seat; + }, + collectPayout: async seat => { + await E(seat) + .getPayout('Asset') + .then(payment => moolaPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual(amountDeposited, moola(0n), `didn't win the auction`), + ); + + await E(seat) + .getPayout('Bid') + .then(payment => simoleanPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual(amountDeposited, bidAmount, `full refund`), + ); + }, }, - }); + ); }; // Setup Alice diff --git a/packages/zoe/test/unitTests/contracts/test-coveredCall.js b/packages/zoe/test/unitTests/contracts/test-coveredCall.js index 12eda702891..06d11329bb8 100644 --- a/packages/zoe/test/unitTests/contracts/test-coveredCall.js +++ b/packages/zoe/test/unitTests/contracts/test-coveredCall.js @@ -121,89 +121,93 @@ test('zoe - coveredCall', async t => { const moolaPurse = moolaKit.issuer.makeEmptyPurse(); const simoleanPurse = simoleanKit.issuer.makeEmptyPurse(); const bucksPurse = bucksKit.issuer.makeEmptyPurse(); - return Far('bob', { - offer: async untrustedInvitation => { - const invitationIssuer = await E(zoe).getInvitationIssuer(); - - // Bob is able to use the trusted invitationIssuer from Zoe to - // transform an untrusted invitation that Alice also has access to - const invitation = await claim( - E(invitationIssuer).makeEmptyPurse(), - untrustedInvitation, - ); - - const invitationValue = await E(zoe).getInvitationDetails(invitation); - - t.is( - invitationValue.installation, - installation, - 'installation is coveredCall', - ); - t.is(invitationValue.description, 'exerciseOption'); + return makeExo( + 'bob', + M.interface('bob', {}, { defaultGuards: 'passable' }), + { + offer: async untrustedInvitation => { + const invitationIssuer = await E(zoe).getInvitationIssuer(); + + // Bob is able to use the trusted invitationIssuer from Zoe to + // transform an untrusted invitation that Alice also has access to + const invitation = await claim( + E(invitationIssuer).makeEmptyPurse(), + untrustedInvitation, + ); - t.deepEqual( - invitationValue.customDetails?.underlyingAssets, - { Moola: moola(3n) }, - `underlying assets are 3 moola`, - ); - t.deepEqual( - invitationValue.customDetails?.strikePrice, - { Simoleans: simoleans(7n), Bucks: bucks(2n) }, - `strike price is 7 simoleans and 2 bucks, so bob must give that`, - ); + const invitationValue = await E(zoe).getInvitationDetails(invitation); - t.deepEqual(invitationValue.customDetails?.expirationDate, toTS(1n)); - t.deepEqual(invitationValue.customDetails?.timeAuthority, timer); + t.is( + invitationValue.installation, + installation, + 'installation is coveredCall', + ); + t.is(invitationValue.description, 'exerciseOption'); - const proposal = harden({ - give: { StrikePrice1: simoleans(7n), StrikePrice2: bucks(2n) }, - want: { UnderlyingAsset: moola(3n) }, - exit: { onDemand: null }, - }); - const payments = { - StrikePrice1: simoleanPayment, - StrikePrice2: bucksPayment, - }; + t.deepEqual( + invitationValue.customDetails?.underlyingAssets, + { Moola: moola(3n) }, + `underlying assets are 3 moola`, + ); + t.deepEqual( + invitationValue.customDetails?.strikePrice, + { Simoleans: simoleans(7n), Bucks: bucks(2n) }, + `strike price is 7 simoleans and 2 bucks, so bob must give that`, + ); - const seat = await E(zoe).offer(invitation, proposal, payments); + t.deepEqual(invitationValue.customDetails?.expirationDate, toTS(1n)); + t.deepEqual(invitationValue.customDetails?.timeAuthority, timer); - t.is( - await E(seat).getOfferResult(), - `The option was exercised. Please collect the assets in your payout.`, - ); - return seat; - }, - processPayouts: async seat => { - await E(seat) - .getPayout('UnderlyingAsset') - .then(payment => moolaPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual(amountDeposited, moola(3n), `Bob got what he wanted`), - ); + const proposal = harden({ + give: { StrikePrice1: simoleans(7n), StrikePrice2: bucks(2n) }, + want: { UnderlyingAsset: moola(3n) }, + exit: { onDemand: null }, + }); + const payments = { + StrikePrice1: simoleanPayment, + StrikePrice2: bucksPayment, + }; - await E(seat) - .getPayout('StrikePrice1') - .then(payment => simoleanPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual( - amountDeposited, - simoleans(0n), - `Bob didn't get anything back`, - ), - ); + const seat = await E(zoe).offer(invitation, proposal, payments); - await E(seat) - .getPayout('StrikePrice2') - .then(payment => bucksPurse.deposit(payment)) - .then(amountDeposited => - t.deepEqual( - amountDeposited, - bucks(0n), - `Bob didn't get anything back`, - ), + t.is( + await E(seat).getOfferResult(), + `The option was exercised. Please collect the assets in your payout.`, ); + return seat; + }, + processPayouts: async seat => { + await E(seat) + .getPayout('UnderlyingAsset') + .then(payment => moolaPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual(amountDeposited, moola(3n), `Bob got what he wanted`), + ); + + await E(seat) + .getPayout('StrikePrice1') + .then(payment => simoleanPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual( + amountDeposited, + simoleans(0n), + `Bob didn't get anything back`, + ), + ); + + await E(seat) + .getPayout('StrikePrice2') + .then(payment => bucksPurse.deposit(payment)) + .then(amountDeposited => + t.deepEqual( + amountDeposited, + bucks(0n), + `Bob didn't get anything back`, + ), + ); + }, }, - }); + ); }; // Setup Alice diff --git a/packages/zoe/test/unitTests/contracts/test-oracle.js b/packages/zoe/test/unitTests/contracts/test-oracle.js index 10e02e4fd3b..ad9492b48ee 100644 --- a/packages/zoe/test/unitTests/contracts/test-oracle.js +++ b/packages/zoe/test/unitTests/contracts/test-oracle.js @@ -58,24 +58,30 @@ test.before( */ const makePingOracle = async _t => { /** @type {OracleHandler} */ - const oracleHandler = Far('OracleHandler', { - async onQuery(query, fee) { - let requiredFee; - if (query.kind === 'Paid') { - requiredFee = feeAmount; - AmountMath.isGTE(fee, requiredFee) || - assert.fail(X`Minimum fee of ${feeAmount} not met; have ${fee}`); - } - const reply = { pong: query }; - return harden({ reply, requiredFee }); + const oracleHandler = makeExo( + 'OracleHandler', + M.interface('OracleHandler', {}, { defaultGuards: 'passable' }), + { + async onQuery(query, fee) { + let requiredFee; + if (query.kind === 'Paid') { + requiredFee = feeAmount; + AmountMath.isGTE(fee, requiredFee) || + assert.fail( + X`Minimum fee of ${feeAmount} not met; have ${fee}`, + ); + } + const reply = { pong: query }; + return harden({ reply, requiredFee }); + }, + async onError(_query, _reason) { + // do nothing + }, + async onReply(_query, _reply, _fee) { + // do nothing + }, }, - async onError(_query, _reason) { - // do nothing - }, - async onReply(_query, _reply, _fee) { - // do nothing - }, - }); + ); const startResult = await E(zoe).startInstance( installation, diff --git a/packages/zoe/test/unitTests/contracts/test-otcDesk.js b/packages/zoe/test/unitTests/contracts/test-otcDesk.js index f45df387c2a..20be5039f3c 100644 --- a/packages/zoe/test/unitTests/contracts/test-otcDesk.js +++ b/packages/zoe/test/unitTests/contracts/test-otcDesk.js @@ -120,7 +120,7 @@ const makeBob = ( moolaPurse.deposit(moolaPayment); simoleanPurse.deposit(simoleanPayment); bucksPurse.deposit(bucksPayment); - return Far('Bob', { + return makeExo('Bob', M.interface('Bob', {}, { defaultGuards: 'passable' }), { offerOk: async untrustedInvitation => { const invitationIssuer = await E(zoe).getInvitationIssuer(); const invitation = await claim( diff --git a/packages/zoe/test/unitTests/contracts/test-priceAggregator.js b/packages/zoe/test/unitTests/contracts/test-priceAggregator.js index ad478c62660..68fbd1aa545 100644 --- a/packages/zoe/test/unitTests/contracts/test-priceAggregator.js +++ b/packages/zoe/test/unitTests/contracts/test-priceAggregator.js @@ -123,20 +123,24 @@ test.before('setup aggregator and oracles', async t => { */ const makeFakePriceOracle = async (valueOut = 0n) => { /** @type {OracleHandler} */ - const oracleHandler = Far('OracleHandler', { - async onQuery({ increment }, _fee) { - assert(increment); - valueOut += increment; - return harden({ - reply: `${valueOut}`, - requiredFee: AmountMath.makeEmpty(link.brand), - }); - }, - onError(query, reason) { - console.error('query', query, 'failed with', reason); + const oracleHandler = makeExo( + 'OracleHandler', + M.interface('OracleHandler', {}, { defaultGuards: 'passable' }), + { + async onQuery({ increment }, _fee) { + assert(increment); + valueOut += increment; + return harden({ + reply: `${valueOut}`, + requiredFee: AmountMath.makeEmpty(link.brand), + }); + }, + onError(query, reason) { + console.error('query', query, 'failed with', reason); + }, + onReply(_query, _reply) {}, }, - onReply(_query, _reply) {}, - }); + ); const startResult = await E(zoe).startInstance( oracleInstallation, @@ -158,7 +162,11 @@ test.before('setup aggregator and oracles', async t => { */ const makeMedianAggregator = async (unitValueIn = 1n) => { // ??? why do we need the Far here and not in VaultFactory tests? - const marshaller = Far('fake marshaller', { ...makeFakeMarshaller() }); + const marshaller = makeExo( + 'fake marshaller', + M.interface('fake marshaller', {}, { defaultGuards: 'passable' }), + { ...makeFakeMarshaller() }, + ); const storageRoot = makeMockChainStorageRoot(); const timer = buildManualTimer(() => {}, 0n, { eventLoopIteration }); @@ -616,14 +624,18 @@ test('quoteAtTime', async t => { const userQuotePK = makePromiseKit(); await E(userTimer).setWakeup( manualTS(1n), - Far('wakeHandler', { - async wake(_timestamp) { - userQuotePK.resolve( - E(pa).quoteGiven(AmountMath.make(brandIn, 23n), usdBrand), - ); - await userQuotePK.promise; + makeExo( + 'wakeHandler', + M.interface('wakeHandler', {}, { defaultGuards: 'passable' }), + { + async wake(_timestamp) { + userQuotePK.resolve( + E(pa).quoteGiven(AmountMath.make(brandIn, 23n), usdBrand), + ); + await userQuotePK.promise; + }, }, - }), + ), ); const quoteAtUserTime = userQuotePK.promise; diff --git a/packages/zoe/test/unitTests/contracts/throwInOfferHandler.js b/packages/zoe/test/unitTests/contracts/throwInOfferHandler.js index 1c1686bc58b..bad633c2db0 100644 --- a/packages/zoe/test/unitTests/contracts/throwInOfferHandler.js +++ b/packages/zoe/test/unitTests/contracts/throwInOfferHandler.js @@ -29,10 +29,14 @@ const start = zcf => { const makeThrowInDepositToSeatInvitation = () => zcf.makeInvitation(throwInDepositToSeat, 'throwInDepositToSeat'); - const creatorFacet = Far('creatorFacet', { - makeThrowInOfferHandlerInvitation, - makeThrowInDepositToSeatInvitation, - }); + const creatorFacet = makeExo( + 'creatorFacet', + M.interface('creatorFacet', {}, { defaultGuards: 'passable' }), + { + makeThrowInOfferHandlerInvitation, + makeThrowInDepositToSeatInvitation, + }, + ); return harden({ creatorFacet }); }; diff --git a/packages/zoe/test/unitTests/contracts/useObjExample.js b/packages/zoe/test/unitTests/contracts/useObjExample.js index 599971e7e5e..b53661ba571 100644 --- a/packages/zoe/test/unitTests/contracts/useObjExample.js +++ b/packages/zoe/test/unitTests/contracts/useObjExample.js @@ -24,42 +24,50 @@ const start = zcf => { assertProposalShape(seat, { give: { Pixels: null }, }); - const useObj = Far('useObj', { - /** - * (Pretend to) color some pixels. - * - * @param {string} color - * @param {Amount} [amountToColor] - */ - colorPixels: (color, amountToColor = undefined) => { - // Throw if the offer is no longer active, i.e. the user has - // completed their offer and the assets are no longer escrowed. - assert(!seat.hasExited(), 'the escrowing offer is no longer active'); - const escrowedAmount = seat.getAmountAllocated('Pixels', pixelBrand); - // If no amountToColor is provided, color all the pixels - // escrowed for this offer. - if (amountToColor === undefined) { - amountToColor = escrowedAmount; - } - assert(amountToColor); - // Ensure that the amount of pixels that we want to color is - // covered by what is actually escrowed. - AmountMath.isGTE(escrowedAmount, amountToColor) || - assert.fail( - X`The pixels to color were not all escrowed. Currently escrowed: ${escrowedAmount}, amount to color: ${amountToColor}`, - ); + const useObj = makeExo( + 'useObj', + M.interface('useObj', {}, { defaultGuards: 'passable' }), + { + /** + * (Pretend to) color some pixels. + * + * @param {string} color + * @param {Amount} [amountToColor] + */ + colorPixels: (color, amountToColor = undefined) => { + // Throw if the offer is no longer active, i.e. the user has + // completed their offer and the assets are no longer escrowed. + assert(!seat.hasExited(), 'the escrowing offer is no longer active'); + const escrowedAmount = seat.getAmountAllocated('Pixels', pixelBrand); + // If no amountToColor is provided, color all the pixels + // escrowed for this offer. + if (amountToColor === undefined) { + amountToColor = escrowedAmount; + } + assert(amountToColor); + // Ensure that the amount of pixels that we want to color is + // covered by what is actually escrowed. + AmountMath.isGTE(escrowedAmount, amountToColor) || + assert.fail( + X`The pixels to color were not all escrowed. Currently escrowed: ${escrowedAmount}, amount to color: ${amountToColor}`, + ); - // Pretend to color - return `successfully colored ${amountToColor.value} pixels ${color}`; + // Pretend to color + return `successfully colored ${amountToColor.value} pixels ${color}`; + }, }, - }); + ); return useObj; }; - const publicFacet = Far('publicFacet', { - // The only publicFacet method is to make an invitation. - makeInvitation: () => zcf.makeInvitation(makeUseObj, 'use object'), - }); + const publicFacet = makeExo( + 'publicFacet', + M.interface('publicFacet', {}, { defaultGuards: 'passable' }), + { + // The only publicFacet method is to make an invitation. + makeInvitation: () => zcf.makeInvitation(makeUseObj, 'use object'), + }, + ); return harden({ publicFacet }); }; diff --git a/packages/zoe/test/unitTests/test-instanceStorage.js b/packages/zoe/test/unitTests/test-instanceStorage.js index b09ca9b3f8d..40e5673bc61 100644 --- a/packages/zoe/test/unitTests/test-instanceStorage.js +++ b/packages/zoe/test/unitTests/test-instanceStorage.js @@ -32,9 +32,17 @@ const setupIssuersForTest = () => { test('makeInstanceRecordStorage', async t => { const { stableKit, ticketKit } = setupIssuersForTest(); const bundle = await bundleSource(root); - const fakeInstallation = Far('fakeInstallation', { getBundle: () => bundle }); + const fakeInstallation = makeExo( + 'fakeInstallation', + M.interface('fakeInstallation', {}, { defaultGuards: 'passable' }), + { getBundle: () => bundle }, + ); const fakeInstance = /** @type {Instance} */ ( - Far('fakeInstance', { a: () => 0 }) + makeExo( + 'fakeInstance', + M.interface('fakeInstance', {}, { defaultGuards: 'passable' }), + { a: () => 0 }, + ) ); const issuers = harden({ Stable: stableKit.issuer, diff --git a/packages/zoe/test/unitTests/test-manualTimer.js b/packages/zoe/test/unitTests/test-manualTimer.js index 9ed76e880df..8a7d03a03a1 100644 --- a/packages/zoe/test/unitTests/test-manualTimer.js +++ b/packages/zoe/test/unitTests/test-manualTimer.js @@ -34,18 +34,22 @@ test('manualTimer makeNotifier', async t => { const makeHandler = () => { let calls = 0n; const args = []; - return Far('wake handler', { - getCalls() { - return calls; + return makeExo( + 'wake handler', + M.interface('wake handler', {}, { defaultGuards: 'passable' }), + { + getCalls() { + return calls; + }, + getArgs() { + return args; + }, + wake(arg) { + args.push(arg); + calls += 1n; + }, }, - getArgs() { - return args; - }, - wake(arg) { - args.push(arg); - calls += 1n; - }, - }); + ); }; test('manualTimer makeRepeater', async t => { @@ -75,12 +79,16 @@ test('tick does not flush by default', async t => { const toTS = ts => coerceTimestampRecord(ts, manualTimer.getTimerBrand()); let woken = toTS(666666n); let later = false; - const handler = Far('handler', { - wake: scheduled => { - woken = scheduled; - stallLots().then(() => (later = true)); + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { + wake: scheduled => { + woken = scheduled; + stallLots().then(() => (later = true)); + }, }, - }); + ); manualTimer.setWakeup(toTS(1n), handler); t.deepEqual(woken, toTS(666666n)); t.is(later, false); @@ -102,12 +110,16 @@ test('tick can flush promise queue', async t => { const toTS = ts => coerceTimestampRecord(ts, manualTimer.getTimerBrand()); let woken = toTS(666666n); let later = false; - const handler = Far('handler', { - wake: scheduled => { - woken = scheduled; - stallLots().then(() => (later = true)); + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { + wake: scheduled => { + woken = scheduled; + stallLots().then(() => (later = true)); + }, }, - }); + ); manualTimer.setWakeup(toTS(1n), handler); t.deepEqual(woken, toTS(666666n)); t.is(later, false); @@ -131,12 +143,16 @@ test('tick does not await makeRepeater by default', async t => { const toTS = ts => coerceTimestampRecord(ts, manualTimer.getTimerBrand()); let woken = toTS(666666n); let later = false; - const handler = Far('handler', { - wake: scheduled => { - woken = scheduled; - stallLots().then(() => (later = true)); + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { + wake: scheduled => { + woken = scheduled; + stallLots().then(() => (later = true)); + }, }, - }); + ); const r = manualTimer.makeRepeater(toRT(1n), toRT(1n)); r.schedule(handler); @@ -160,12 +176,16 @@ test('tick can flush makeRepeater', async t => { const toTS = ts => coerceTimestampRecord(ts, manualTimer.getTimerBrand()); let woken = toTS(666666n); let later = false; - const handler = Far('handler', { - wake: scheduled => { - woken = scheduled; - stallLots().then(() => (later = true)); + const handler = makeExo( + 'handler', + M.interface('handler', {}, { defaultGuards: 'passable' }), + { + wake: scheduled => { + woken = scheduled; + stallLots().then(() => (later = true)); + }, }, - }); + ); const r = manualTimer.makeRepeater(toRT(1n), toRT(1n)); r.schedule(handler); diff --git a/packages/zoe/test/unitTests/test-zoe-startInstance.js b/packages/zoe/test/unitTests/test-zoe-startInstance.js index 318e237e48c..ca9f82fd1f9 100644 --- a/packages/zoe/test/unitTests/test-zoe-startInstance.js +++ b/packages/zoe/test/unitTests/test-zoe-startInstance.js @@ -109,17 +109,25 @@ test('terms, issuerKeywordRecord switched', async t => { test('bad issuer, makeEmptyPurse throws', async t => { const { zoe } = setup(); const installation = await E(zoe).installBundleID('b1-contract'); - const brand = Far('brand', { - // eslint-disable-next-line no-use-before-define - isMyIssuer: i => i === badIssuer, - getDisplayInfo: () => ({ decimalPlaces: 6, assetKind: AssetKind.NAT }), - }); - const badIssuer = Far('issuer', { - makeEmptyPurse: async () => { - throw Error('bad issuer'); + const brand = makeExo( + 'brand', + M.interface('brand', {}, { defaultGuards: 'passable' }), + { + // eslint-disable-next-line no-use-before-define + isMyIssuer: i => i === badIssuer, + getDisplayInfo: () => ({ decimalPlaces: 6, assetKind: AssetKind.NAT }), }, - getBrand: () => brand, - }); + ); + const badIssuer = makeExo( + 'issuer', + M.interface('issuer', {}, { defaultGuards: 'passable' }), + { + makeEmptyPurse: async () => { + throw Error('bad issuer'); + }, + getBrand: () => brand, + }, + ); await t.throwsAsync( () => E(zoe).startInstance(installation, { Money: badIssuer }), { diff --git a/packages/zoe/test/unitTests/zcf/registerFeeMintContract.js b/packages/zoe/test/unitTests/zcf/registerFeeMintContract.js index c2364b59dc7..43cb40c2b59 100644 --- a/packages/zoe/test/unitTests/zcf/registerFeeMintContract.js +++ b/packages/zoe/test/unitTests/zcf/registerFeeMintContract.js @@ -28,13 +28,17 @@ const start = async (zcf, privateArgs) => { zcfSeat, ); - const creatorFacet = Far('mint creator facet', { - getMintedAmount: () => zcfSeat.getAmountAllocated('Winnings'), - getMintedPayout: () => { - zcfSeat.exit(); - return E(userSeat).getPayout('Winnings'); + const creatorFacet = makeExo( + 'mint creator facet', + M.interface('mint creator facet', {}, { defaultGuards: 'passable' }), + { + getMintedAmount: () => zcfSeat.getAmountAllocated('Winnings'), + getMintedPayout: () => { + zcfSeat.exit(); + return E(userSeat).getPayout('Winnings'); + }, }, - }); + ); return harden({ creatorFacet }); }; diff --git a/packages/zoe/test/unitTests/zcf/test-zcf.js b/packages/zoe/test/unitTests/zcf/test-zcf.js index 9859a0500f7..5e241aecf2b 100644 --- a/packages/zoe/test/unitTests/zcf/test-zcf.js +++ b/packages/zoe/test/unitTests/zcf/test-zcf.js @@ -200,17 +200,25 @@ test(`zcf.saveIssuer - bad issuer`, async t => { test(`zcf.saveIssuer - bad issuer, makeEmptyPurse throws`, async t => { const { zcf } = await setupZCFTest(); - const brand = Far('brand', { - // eslint-disable-next-line no-use-before-define - isMyIssuer: i => i === badIssuer, - getDisplayInfo: () => ({ decimalPlaces: 6, assetKind: AssetKind.NAT }), - }); - const badIssuer = Far('issuer', { - makeEmptyPurse: async () => { - throw Error('bad issuer'); + const brand = makeExo( + 'brand', + M.interface('brand', {}, { defaultGuards: 'passable' }), + { + // eslint-disable-next-line no-use-before-define + isMyIssuer: i => i === badIssuer, + getDisplayInfo: () => ({ decimalPlaces: 6, assetKind: AssetKind.NAT }), }, - getBrand: () => brand, - }); + ); + const badIssuer = makeExo( + 'issuer', + M.interface('issuer', {}, { defaultGuards: 'passable' }), + { + makeEmptyPurse: async () => { + throw Error('bad issuer'); + }, + getBrand: () => brand, + }, + ); await t.throwsAsync( // @ts-expect-error deliberate invalid arguments for testing () => zcf.saveIssuer(badIssuer, 'A'), diff --git a/packages/zoe/test/unitTests/zcf/zcfTesterContract.js b/packages/zoe/test/unitTests/zcf/zcfTesterContract.js index 95e5af88a2e..3843db1901c 100644 --- a/packages/zoe/test/unitTests/zcf/zcfTesterContract.js +++ b/packages/zoe/test/unitTests/zcf/zcfTesterContract.js @@ -10,9 +10,13 @@ const start = async zcf => { const instance = zcf.getInstance(); zcf.setTestJig(() => harden({ instance })); - const publicFacet = Far('public facet', { - makeInvitation: () => zcf.makeInvitation(() => 17, 'simple'), - }); + const publicFacet = makeExo( + 'public facet', + M.interface('public facet', {}, { defaultGuards: 'passable' }), + { + makeInvitation: () => zcf.makeInvitation(() => 17, 'simple'), + }, + ); return { publicFacet }; }; diff --git a/packages/zoe/test/unitTests/zoe/test-burnInvitation.js b/packages/zoe/test/unitTests/zoe/test-burnInvitation.js index 1b5f7c3b1ea..d720e834684 100644 --- a/packages/zoe/test/unitTests/zoe/test-burnInvitation.js +++ b/packages/zoe/test/unitTests/zoe/test-burnInvitation.js @@ -10,8 +10,16 @@ import { burnInvitation } from '../../../src/zoeService/offer/burnInvitation.js' test('burnInvitation', async t => { const mockInvitationKit = makeIssuerKit('mockInvitation', AssetKind.SET); - const instanceHandle = Far('handle', {}); - const invitationHandle = Far('handle', {}); + const instanceHandle = makeExo( + 'handle', + M.interface('handle', {}, { defaultGuards: 'passable' }), + {}, + ); + const invitationHandle = makeExo( + 'handle', + M.interface('handle', {}, { defaultGuards: 'passable' }), + {}, + ); const invitation = mockInvitationKit.mint.mintPayment( AmountMath.make( @@ -39,8 +47,16 @@ test('burnInvitation - not an invitation', async t => { test('burnInvitation - invitation already used', async t => { const mockInvitationKit = makeIssuerKit('mockInvitation', AssetKind.SET); - const instanceHandle = Far('handle', {}); - const invitationHandle = Far('handle', {}); + const instanceHandle = makeExo( + 'handle', + M.interface('handle', {}, { defaultGuards: 'passable' }), + {}, + ); + const invitationHandle = makeExo( + 'handle', + M.interface('handle', {}, { defaultGuards: 'passable' }), + {}, + ); const invitation = mockInvitationKit.mint.mintPayment( AmountMath.make( @@ -66,9 +82,21 @@ test('burnInvitation - invitation already used', async t => { test('burnInvitation - multiple invitations', async t => { const mockInvitationKit = makeIssuerKit('mockInvitation', AssetKind.SET); - const instanceHandle = Far('handle', {}); - const invitationHandle1 = Far('handle', {}); - const invitationHandle2 = Far('handle', {}); + const instanceHandle = makeExo( + 'handle', + M.interface('handle', {}, { defaultGuards: 'passable' }), + {}, + ); + const invitationHandle1 = makeExo( + 'handle', + M.interface('handle', {}, { defaultGuards: 'passable' }), + {}, + ); + const invitationHandle2 = makeExo( + 'handle', + M.interface('handle', {}, { defaultGuards: 'passable' }), + {}, + ); const invitations = mockInvitationKit.mint.mintPayment( AmountMath.make( diff --git a/packages/zoe/test/unitTests/zoe/test-instanceAdminStorage.js b/packages/zoe/test/unitTests/zoe/test-instanceAdminStorage.js index 33cbfacab01..58fc945ce09 100644 --- a/packages/zoe/test/unitTests/zoe/test-instanceAdminStorage.js +++ b/packages/zoe/test/unitTests/zoe/test-instanceAdminStorage.js @@ -13,24 +13,36 @@ test('makeInstanceAdminStorage', async t => { ); const { moolaKit } = setup(); - const mockInstallation1 = Far('mockInstallation', {}); - const mockInstance1 = Far('mockInstance', {}); + const mockInstallation1 = makeExo( + 'mockInstallation', + M.interface('mockInstallation', {}, { defaultGuards: 'passable' }), + {}, + ); + const mockInstance1 = makeExo( + 'mockInstance', + M.interface('mockInstance', {}, { defaultGuards: 'passable' }), + {}, + ); const mockBrandRecord = harden({ M: moolaKit.brand }); const mockIssuerRecord = harden({ M: moolaKit.issuer }); const mockTerms = harden({ something: 'anything' }); const mockFacet = harden( - Far('mock', { + makeExo('mock', M.interface('mock', {}, { defaultGuards: 'passable' }), { identity: a => a, }), ); - const mockInstanceAdmin = Far('mockInstanceAdmin', { - getInstallation: () => mockInstallation1, - getBrands: () => mockBrandRecord, - getPublicFacet: () => mockFacet, - getIssuers: () => mockIssuerRecord, - getTerms: () => mockTerms, - getOfferFilter: () => ['filter'], - }); + const mockInstanceAdmin = makeExo( + 'mockInstanceAdmin', + M.interface('mockInstanceAdmin', {}, { defaultGuards: 'passable' }), + { + getInstallation: () => mockInstallation1, + getBrands: () => mockBrandRecord, + getPublicFacet: () => mockFacet, + getIssuers: () => mockIssuerRecord, + getTerms: () => mockTerms, + getOfferFilter: () => ['filter'], + }, + ); ias.updater.initInstanceAdmin(mockInstance1, mockInstanceAdmin); t.is(await ias.accessor.getInstallation(mockInstance1), mockInstallation1); @@ -45,21 +57,37 @@ test('add another instance admin for same instance', async t => { makeScalarBigMapStore('zoe baggage', { durable: true }), ); - const mockInstallation1 = Far('mockInstallation', {}); - const mockInstance1 = Far('mockInstance', {}); - const mockInstanceAdmin1 = Far('mockInstanceAdmin', { - getInstallation: () => mockInstallation1, - getBrands: () => 'brands', - getPublicFacet: () => 'publicFacet', - getIssuers: () => 'issuers', - getTerms: () => 'terms', - getOfferFilter: () => 'filter', - }); + const mockInstallation1 = makeExo( + 'mockInstallation', + M.interface('mockInstallation', {}, { defaultGuards: 'passable' }), + {}, + ); + const mockInstance1 = makeExo( + 'mockInstance', + M.interface('mockInstance', {}, { defaultGuards: 'passable' }), + {}, + ); + const mockInstanceAdmin1 = makeExo( + 'mockInstanceAdmin', + M.interface('mockInstanceAdmin', {}, { defaultGuards: 'passable' }), + { + getInstallation: () => mockInstallation1, + getBrands: () => 'brands', + getPublicFacet: () => 'publicFacet', + getIssuers: () => 'issuers', + getTerms: () => 'terms', + getOfferFilter: () => 'filter', + }, + ); ias.updater.initInstanceAdmin(mockInstance1, mockInstanceAdmin1); t.is(await ias.accessor.getInstallation(mockInstance1), mockInstallation1); - const mockInstanceAdmin2 = Far('mockInstanceAdmin', {}); + const mockInstanceAdmin2 = makeExo( + 'mockInstanceAdmin', + M.interface('mockInstanceAdmin', {}, { defaultGuards: 'passable' }), + {}, + ); await t.throwsAsync( () => ias.updater.initInstanceAdmin(mockInstance1, mockInstanceAdmin2), { message: /"\[Alleged: mockInstance\]" already registered/ }, diff --git a/packages/zoe/tools/fakePriceAuthority.js b/packages/zoe/tools/fakePriceAuthority.js index 625f3cf5b2a..6fb281c3ca6 100644 --- a/packages/zoe/tools/fakePriceAuthority.js +++ b/packages/zoe/tools/fakePriceAuthority.js @@ -183,35 +183,39 @@ export async function makeFakePriceAuthority(options) { async function startTicker() { let firstTime = true; - const handler = Far('wake handler', { - wake: async t => { - if (t === 0n) { - // just in case makeRepeater() was called with delay=0, - // which schedules an immediate wakeup - return; - } - if (firstTime) { - firstTime = false; - } else { - currentPriceIndex += 1; - } - latestTick = t; - tickUpdater.updateState(t); - const remainingTimeClients = []; - for (const entry of timeClients) { - const [when, resolve] = entry; - if (timestampGTE(latestTick, when)) { - resolve(latestTick); + const handler = makeExo( + 'wake handler', + M.interface('wake handler', {}, { defaultGuards: 'passable' }), + { + wake: async t => { + if (t === 0n) { + // just in case makeRepeater() was called with delay=0, + // which schedules an immediate wakeup + return; + } + if (firstTime) { + firstTime = false; } else { - remainingTimeClients.push(entry); + currentPriceIndex += 1; } - } - timeClients = remainingTimeClients; - for (const req of comparisonQueue) { - checkComparisonRequest(req); - } + latestTick = t; + tickUpdater.updateState(t); + const remainingTimeClients = []; + for (const entry of timeClients) { + const [when, resolve] = entry; + if (timestampGTE(latestTick, when)) { + resolve(latestTick); + } else { + remainingTimeClients.push(entry); + } + } + timeClients = remainingTimeClients; + for (const req of comparisonQueue) { + checkComparisonRequest(req); + } + }, }, - }); + ); const timerBrand = await E(timer).getTimerBrand(); const soonRT = coerceRelativeTimeRecord(1n, timerBrand); const quoteIntervalRT = coerceRelativeTimeRecord(quoteInterval, timerBrand); @@ -262,72 +266,78 @@ export async function makeFakePriceAuthority(options) { harden(generateQuotes); /** @type {PriceAuthority} */ - const priceAuthority = Far('fake price authority', { - getQuoteIssuer: (brandIn, brandOut) => { - assertBrands(brandIn, brandOut); - return quoteIssuer; - }, - getTimerService: (brandIn, brandOut) => { - assertBrands(brandIn, brandOut); - return timer; - }, - makeQuoteNotifier: async (amountIn, brandOut) => { - assertBrands(amountIn.brand, brandOut); - return makeNotifierFromAsyncIterable(generateQuotes(amountIn, brandOut)); - }, - quoteAtTime: (timeStamp, amountIn, brandOut) => { - timeStamp = TimeMath.absValue(timeStamp); - assert.typeof(timeStamp, 'bigint'); - assertBrands(amountIn.brand, brandOut); - if (latestTick && timestampLTE(timeStamp, latestTick)) { - return Promise.resolve(priceInQuote(amountIn, brandOut, timeStamp)); - } else { - // follow ticker until it fires with >= timeStamp - const { promise, resolve } = makePromiseKit(); - timeClients.push([timeStamp, resolve]); - return promise.then(ts => { - return priceInQuote(amountIn, brandOut, ts); - }); - } - }, - quoteGiven: async (amountIn, brandOut) => { - assertBrands(amountIn.brand, brandOut); - const timestamp = await E(timer).getCurrentTimestamp(); - return priceInQuote(amountIn, brandOut, timestamp); - }, - quoteWanted: async (brandIn, amountOut) => { - assertBrands(brandIn, amountOut.brand); - const timestamp = await E(timer).getCurrentTimestamp(); - return priceOutQuote(brandIn, amountOut, timestamp); - }, - quoteWhenGTE: (amountIn, amountOutLimit) => { - const compareGTE = amount => AmountMath.isGTE(amount, amountOutLimit); - return resolveQuoteWhen(compareGTE, amountIn, amountOutLimit); - }, - quoteWhenGT: (amountIn, amountOutLimit) => { - const compareGT = amount => !AmountMath.isGTE(amountOutLimit, amount); - return resolveQuoteWhen(compareGT, amountIn, amountOutLimit); - }, - quoteWhenLTE: (amountIn, amountOutLimit) => { - const compareLTE = amount => AmountMath.isGTE(amountOutLimit, amount); - return resolveQuoteWhen(compareLTE, amountIn, amountOutLimit); - }, - quoteWhenLT: (amountIn, amountOutLimit) => { - const compareLT = amount => !AmountMath.isGTE(amount, amountOutLimit); - return resolveQuoteWhen(compareLT, amountIn, amountOutLimit); - }, - mutableQuoteWhenLT: () => { - throw Error('use ScriptedPriceAuthority'); - }, - mutableQuoteWhenLTE: () => { - throw Error('use ScriptedPriceAuthority'); - }, - mutableQuoteWhenGT: () => { - throw Error('use ScriptedPriceAuthority'); - }, - mutableQuoteWhenGTE: () => { - throw Error('use ScriptedPriceAuthority'); + const priceAuthority = makeExo( + 'fake price authority', + M.interface('fake price authority', {}, { defaultGuards: 'passable' }), + { + getQuoteIssuer: (brandIn, brandOut) => { + assertBrands(brandIn, brandOut); + return quoteIssuer; + }, + getTimerService: (brandIn, brandOut) => { + assertBrands(brandIn, brandOut); + return timer; + }, + makeQuoteNotifier: async (amountIn, brandOut) => { + assertBrands(amountIn.brand, brandOut); + return makeNotifierFromAsyncIterable( + generateQuotes(amountIn, brandOut), + ); + }, + quoteAtTime: (timeStamp, amountIn, brandOut) => { + timeStamp = TimeMath.absValue(timeStamp); + assert.typeof(timeStamp, 'bigint'); + assertBrands(amountIn.brand, brandOut); + if (latestTick && timestampLTE(timeStamp, latestTick)) { + return Promise.resolve(priceInQuote(amountIn, brandOut, timeStamp)); + } else { + // follow ticker until it fires with >= timeStamp + const { promise, resolve } = makePromiseKit(); + timeClients.push([timeStamp, resolve]); + return promise.then(ts => { + return priceInQuote(amountIn, brandOut, ts); + }); + } + }, + quoteGiven: async (amountIn, brandOut) => { + assertBrands(amountIn.brand, brandOut); + const timestamp = await E(timer).getCurrentTimestamp(); + return priceInQuote(amountIn, brandOut, timestamp); + }, + quoteWanted: async (brandIn, amountOut) => { + assertBrands(brandIn, amountOut.brand); + const timestamp = await E(timer).getCurrentTimestamp(); + return priceOutQuote(brandIn, amountOut, timestamp); + }, + quoteWhenGTE: (amountIn, amountOutLimit) => { + const compareGTE = amount => AmountMath.isGTE(amount, amountOutLimit); + return resolveQuoteWhen(compareGTE, amountIn, amountOutLimit); + }, + quoteWhenGT: (amountIn, amountOutLimit) => { + const compareGT = amount => !AmountMath.isGTE(amountOutLimit, amount); + return resolveQuoteWhen(compareGT, amountIn, amountOutLimit); + }, + quoteWhenLTE: (amountIn, amountOutLimit) => { + const compareLTE = amount => AmountMath.isGTE(amountOutLimit, amount); + return resolveQuoteWhen(compareLTE, amountIn, amountOutLimit); + }, + quoteWhenLT: (amountIn, amountOutLimit) => { + const compareLT = amount => !AmountMath.isGTE(amount, amountOutLimit); + return resolveQuoteWhen(compareLT, amountIn, amountOutLimit); + }, + mutableQuoteWhenLT: () => { + throw Error('use ScriptedPriceAuthority'); + }, + mutableQuoteWhenLTE: () => { + throw Error('use ScriptedPriceAuthority'); + }, + mutableQuoteWhenGT: () => { + throw Error('use ScriptedPriceAuthority'); + }, + mutableQuoteWhenGTE: () => { + throw Error('use ScriptedPriceAuthority'); + }, }, - }); + ); return priceAuthority; } diff --git a/packages/zoe/tools/fakeVatAdmin.js b/packages/zoe/tools/fakeVatAdmin.js index 8587db4e19a..ca6df84fac3 100644 --- a/packages/zoe/tools/fakeVatAdmin.js +++ b/packages/zoe/tools/fakeVatAdmin.js @@ -53,76 +53,84 @@ function makeFakeVatAdmin(testContextSetter = undefined, makeRemote = x => x) { // This is explicitly intended to be mutable so that // test-only state can be provided from contracts // to their tests. - const admin = Far('vatAdmin', { - getBundleCap: bundleID => { - if (!idToBundleCap.has(bundleID)) { - idToBundleCap.init(bundleID, bogusBundleCap()); - } - return Promise.resolve(idToBundleCap.get(bundleID)); - }, - waitForBundleCap: bundleID => { - if (!idToBundleCap.has(bundleID)) { - idToBundleCap.init(bundleID, bogusBundleCap()); - } - return Promise.resolve(idToBundleCap.get(bundleID)); - }, - getNamedBundleCap: name => { - if (name === 'zcf') { - return Promise.resolve(zcfBundleCap); - } - const id = nameToBundleID.get(name); - return Promise.resolve(idToBundleCap.get(id)); - }, - getBundleIDByName: name => { - return Promise.resolve().then(() => nameToBundleID.get(name)); - }, - createVat: (bundleCap, { vatParameters = {} } = {}) => { - bundleCap === zcfBundleCap || Fail`fakeVatAdmin only knows ZCF`; - const exitKit = makePromiseKit(); - handlePKitWarning(exitKit); - const exitVat = completion => { - exitMessage = completion; - hasExited = true; - exitWithFailure = false; - exitKit.resolve(completion); - }; - const vpow = harden({ - ...fakeVatPowers, - exitVat, - }); - const vatBaggage = makeScalarBigMapStore('fake vat baggage', { - durable: true, - }); + const admin = makeExo( + 'vatAdmin', + M.interface('vatAdmin', {}, { defaultGuards: 'passable' }), + { + getBundleCap: bundleID => { + if (!idToBundleCap.has(bundleID)) { + idToBundleCap.init(bundleID, bogusBundleCap()); + } + return Promise.resolve(idToBundleCap.get(bundleID)); + }, + waitForBundleCap: bundleID => { + if (!idToBundleCap.has(bundleID)) { + idToBundleCap.init(bundleID, bogusBundleCap()); + } + return Promise.resolve(idToBundleCap.get(bundleID)); + }, + getNamedBundleCap: name => { + if (name === 'zcf') { + return Promise.resolve(zcfBundleCap); + } + const id = nameToBundleID.get(name); + return Promise.resolve(idToBundleCap.get(id)); + }, + getBundleIDByName: name => { + return Promise.resolve().then(() => nameToBundleID.get(name)); + }, + createVat: (bundleCap, { vatParameters = {} } = {}) => { + bundleCap === zcfBundleCap || Fail`fakeVatAdmin only knows ZCF`; + const exitKit = makePromiseKit(); + handlePKitWarning(exitKit); + const exitVat = completion => { + exitMessage = completion; + hasExited = true; + exitWithFailure = false; + exitKit.resolve(completion); + }; + const vpow = harden({ + ...fakeVatPowers, + exitVat, + }); + const vatBaggage = makeScalarBigMapStore('fake vat baggage', { + durable: true, + }); - // XXX Notice that this call isn't wrapping vatParams. We (BW, CH) tried - // doing this, but backed out when it got complex. - // - // const ns = await evalContractBundle(zcfBundle); - // const ns2 = makeRemote( - // Far('wrappedRoot', { - // buildRootObject: vp => ns.buildRootObject(vpow, vp, vatBaggage), - // }), - // ); - return Promise.resolve( - harden({ - root: makeRemote( - E(evalContractBundle(zcfBundle)).buildRootObject( - vpow, - vatParameters, - vatBaggage, + // XXX Notice that this call isn't wrapping vatParams. We (BW, CH) tried + // doing this, but backed out when it got complex. + // + // const ns = await evalContractBundle(zcfBundle); + // const ns2 = makeRemote( + // makeExo('wrappedRoot', M.interface('wrappedRoot', {}, { defaultGuards: 'passable' }), { + // buildRootObject: vp => ns.buildRootObject(vpow, vp, vatBaggage), + // }), + // ); + return Promise.resolve( + harden({ + root: makeRemote( + E(evalContractBundle(zcfBundle)).buildRootObject( + vpow, + vatParameters, + vatBaggage, + ), + ), + adminNode: makeExo( + 'adminNode', + M.interface('adminNode', {}, { defaultGuards: 'passable' }), + { + done: () => { + return exitKit.promise; + }, + terminateWithFailure: () => {}, + upgrade: (_bundleCap, _options) => Fail`upgrade not faked`, + }, ), - ), - adminNode: Far('adminNode', { - done: () => { - return exitKit.promise; - }, - terminateWithFailure: () => {}, - upgrade: (_bundleCap, _options) => Fail`upgrade not faked`, }), - }), - ); + ); + }, }, - }); + ); const criticalVatKey = harden({}); const vatPowers = harden({ D: bcap => { diff --git a/packages/zoe/tools/manualPriceAuthority.js b/packages/zoe/tools/manualPriceAuthority.js index 93ffdc64e54..a2f8076c613 100644 --- a/packages/zoe/tools/manualPriceAuthority.js +++ b/packages/zoe/tools/manualPriceAuthority.js @@ -84,17 +84,21 @@ export function makeManualPriceAuthority(options) { adminFacet: { fireTriggers }, } = makeOnewayPriceAuthorityKit(priceAuthorityOptions); - return Far('ManualPriceAuthority', { - setPrice: newPrice => { - currentPrice = newPrice; - updater.updateState(currentPrice); - fireTriggers(createQuote); + return makeExo( + 'ManualPriceAuthority', + M.interface('ManualPriceAuthority', {}, { defaultGuards: 'passable' }), + { + setPrice: newPrice => { + currentPrice = newPrice; + updater.updateState(currentPrice); + fireTriggers(createQuote); + }, + disable: () => { + disabled = true; + updater.updateState(false); + }, + ...priceAuthority, }, - disable: () => { - disabled = true; - updater.updateState(false); - }, - ...priceAuthority, - }); + ); } /** @typedef {ReturnType} ManualPriceAuthority */ diff --git a/packages/zoe/tools/manualTimer.js b/packages/zoe/tools/manualTimer.js index 622e2c6cd97..1b7cb1b9f4c 100644 --- a/packages/zoe/tools/manualTimer.js +++ b/packages/zoe/tools/manualTimer.js @@ -104,12 +104,16 @@ const buildManualTimer = (log = nolog, startValue = 0n, options = {}) => { return timerService.setWakeup(when, handler, cancelToken); }; - return Far('ManualTimer', { - ...bindAllMethods(timerService), - tick, - tickN, - setWakeup, - }); + return makeExo( + 'ManualTimer', + M.interface('ManualTimer', {}, { defaultGuards: 'passable' }), + { + ...bindAllMethods(timerService), + tick, + tickN, + setWakeup, + }, + ); }; harden(buildManualTimer); diff --git a/packages/zoe/tools/scriptedOracle.js b/packages/zoe/tools/scriptedOracle.js index 41e91096507..3b6adaa0c90 100644 --- a/packages/zoe/tools/scriptedOracle.js +++ b/packages/zoe/tools/scriptedOracle.js @@ -26,21 +26,25 @@ export async function makeScriptedOracle( feeIssuer, ) { /** @type {OracleHandler} */ - const oracleHandler = Far('oracleHandler', { - async onQuery(query) { - const timeRecord = await E(timer).getCurrentTimestamp(); - const time = TimeMath.absValue(timeRecord); - const event = script[`${time}`] || 'Nothing to report'; - const reply = { event, time, query }; - return harden({ reply }); + const oracleHandler = makeExo( + 'oracleHandler', + M.interface('oracleHandler', {}, { defaultGuards: 'passable' }), + { + async onQuery(query) { + const timeRecord = await E(timer).getCurrentTimestamp(); + const time = TimeMath.absValue(timeRecord); + const event = script[`${time}`] || 'Nothing to report'; + const reply = { event, time, query }; + return harden({ reply }); + }, + async onError(_query, _reason) { + // do nothing + }, + async onReply(_query, _reply, _fee) { + // do nothing + }, }, - async onError(_query, _reason) { - // do nothing - }, - async onReply(_query, _reply, _fee) { - // do nothing - }, - }); + ); const startResult = await E(zoe).startInstance(oracleInstallation, { Fee: feeIssuer, diff --git a/packages/zoe/tools/scriptedPriceAuthority.js b/packages/zoe/tools/scriptedPriceAuthority.js index 939ba641b8e..f6071c67885 100644 --- a/packages/zoe/tools/scriptedPriceAuthority.js +++ b/packages/zoe/tools/scriptedPriceAuthority.js @@ -81,15 +81,19 @@ export function makeScriptedPriceAuthority(options) { adminFacet: { fireTriggers }, } = makeOnewayPriceAuthorityKit(priceAuthorityOptions); - const priceObserver = Far('priceObserver', { - updateState: t => { - t = TimeMath.absValue(t); - currentPrice = - priceList[Number(Number(t / quoteInterval) % priceList.length)]; + const priceObserver = makeExo( + 'priceObserver', + M.interface('priceObserver', {}, { defaultGuards: 'passable' }), + { + updateState: t => { + t = TimeMath.absValue(t); + currentPrice = + priceList[Number(Number(t / quoteInterval) % priceList.length)]; - fireTriggers(createQuote); + fireTriggers(createQuote); + }, }, - }); + ); observeNotifier(notifier, priceObserver); return priceAuthority; diff --git a/packages/zone/README.md b/packages/zone/README.md index ca833b939a2..e850df7838b 100644 --- a/packages/zone/README.md +++ b/packages/zone/README.md @@ -26,7 +26,7 @@ export const buildRootObject = (vatPowers, _args, baggage) => { const makeFrobulator = prepareFrobulator(frobZone); const widgetToFrob = frobZone.mapStore('widgetToFrob'); - return Far('WidgetFrobulator', { + return makeExo('WidgetFrobulator', M.interface('WidgetFrobulator', {}, { defaultGuards: 'passable' }), { makeWidget, registerWidget(w) { const frobulator = makeFrobulator(); diff --git a/packages/zone/src/durable.js b/packages/zone/src/durable.js index 22cfe4b733a..70bcf49b902 100644 --- a/packages/zone/src/durable.js +++ b/packages/zone/src/durable.js @@ -52,15 +52,19 @@ const attachDurableStores = getBaggage => { provideDurableWeakMapStore(getBaggage(), label, options); /** @type {import('.').Stores} */ - return Far('durableStores', { - // eslint-disable-next-line no-use-before-define - detached: () => detachedDurableStores, - isStorable, - mapStore, - setStore, - weakMapStore, - weakSetStore, - }); + return makeExo( + 'durableStores', + M.interface('durableStores', {}, { defaultGuards: 'passable' }), + { + // eslint-disable-next-line no-use-before-define + detached: () => detachedDurableStores, + isStorable, + mapStore, + setStore, + weakMapStore, + weakSetStore, + }, + ); }; /** @type {import('.').Stores} */ @@ -101,20 +105,24 @@ export const makeDurableZone = (baggage, baseLabel = 'durableZone') => { return makeDurableZone(subBaggage, `${baseLabel}.${label}`); }; - return Far('durableZone', { - exo: wrapProvider(exo, keys.exo), - exoClass: wrapProvider(exoClass, keys.exoClass), - exoClassKit: wrapProvider(exoClassKit, keys.exoClassKit), - subZone, - - makeOnce, - detached: attachedStores.detached, - isStorable: attachedStores.isStorable, - - mapStore: wrapProvider(attachedStores.mapStore, keys.store), - setStore: wrapProvider(attachedStores.setStore, keys.store), - weakMapStore: wrapProvider(attachedStores.weakMapStore, keys.store), - weakSetStore: wrapProvider(attachedStores.weakSetStore, keys.store), - }); + return makeExo( + 'durableZone', + M.interface('durableZone', {}, { defaultGuards: 'passable' }), + { + exo: wrapProvider(exo, keys.exo), + exoClass: wrapProvider(exoClass, keys.exoClass), + exoClassKit: wrapProvider(exoClassKit, keys.exoClassKit), + subZone, + + makeOnce, + detached: attachedStores.detached, + isStorable: attachedStores.isStorable, + + mapStore: wrapProvider(attachedStores.mapStore, keys.store), + setStore: wrapProvider(attachedStores.setStore, keys.store), + weakMapStore: wrapProvider(attachedStores.weakMapStore, keys.store), + weakSetStore: wrapProvider(attachedStores.weakSetStore, keys.store), + }, + ); }; harden(makeDurableZone); diff --git a/packages/zone/src/virtual.js b/packages/zone/src/virtual.js index 95410799db0..c8ca69f3674 100644 --- a/packages/zone/src/virtual.js +++ b/packages/zone/src/virtual.js @@ -47,14 +47,18 @@ const makeVirtualExo = ( }; /** @type {import('.').Stores} */ -const detachedVirtualStores = Far('virtualStores', { - detached: () => detachedVirtualStores, - isStorable: isPassable, - mapStore: makeScalarBigMapStore, - setStore: makeScalarBigSetStore, - weakMapStore: makeScalarBigWeakMapStore, - weakSetStore: makeScalarBigWeakSetStore, -}); +const detachedVirtualStores = makeExo( + 'virtualStores', + M.interface('virtualStores', {}, { defaultGuards: 'passable' }), + { + detached: () => detachedVirtualStores, + isStorable: isPassable, + mapStore: makeScalarBigMapStore, + setStore: makeScalarBigSetStore, + weakMapStore: makeScalarBigWeakMapStore, + weakSetStore: makeScalarBigWeakSetStore, + }, +); /** * A zone that utilizes external storage to reduce the memory footprint of the @@ -76,19 +80,23 @@ export const makeVirtualZone = (baseLabel = 'virtualZone') => { const makeSubZone = (label, _options) => makeVirtualZone(`${baseLabel}.${label}`); - return Far('virtualZone', { - exo: wrapProvider(makeVirtualExo, keys.exo), - exoClass: wrapProvider(defineVirtualExoClass, keys.exoClass), - exoClassKit: wrapProvider(defineVirtualExoClassKit, keys.exoClassKit), - subZone: wrapProvider(makeSubZone), + return makeExo( + 'virtualZone', + M.interface('virtualZone', {}, { defaultGuards: 'passable' }), + { + exo: wrapProvider(makeVirtualExo, keys.exo), + exoClass: wrapProvider(defineVirtualExoClass, keys.exoClass), + exoClassKit: wrapProvider(defineVirtualExoClassKit, keys.exoClassKit), + subZone: wrapProvider(makeSubZone), - makeOnce, - detached: detachedVirtualStores.detached, - isStorable: detachedVirtualStores.isStorable, + makeOnce, + detached: detachedVirtualStores.detached, + isStorable: detachedVirtualStores.isStorable, - mapStore: wrapProvider(detachedVirtualStores.mapStore), - setStore: wrapProvider(detachedVirtualStores.setStore), - weakMapStore: wrapProvider(detachedVirtualStores.weakMapStore), - weakSetStore: wrapProvider(detachedVirtualStores.weakSetStore), - }); + mapStore: wrapProvider(detachedVirtualStores.mapStore), + setStore: wrapProvider(detachedVirtualStores.setStore), + weakMapStore: wrapProvider(detachedVirtualStores.weakMapStore), + weakSetStore: wrapProvider(detachedVirtualStores.weakSetStore), + }, + ); }; From 7070a29221d0ebfb25cb310cd7e60ee1cf58d34d Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Thu, 7 Mar 2024 07:43:42 -0800 Subject: [PATCH 02/12] fixup! format --- .../upgrade/bootstrap-scripted-upgrade.js | 8 +- .../bootstrap-vat-timer-upgrade.js | 12 +- .../bootstrap-collection-slots.js | 6 +- .../bootstrap-delete-stored-vo.js | 6 +- .../double-retire-import/bootstrap-dri.js | 12 +- packages/casting/src/defaults.js | 10 +- .../src/contractGovernance/paramManager.js | 38 +++-- packages/governance/src/electorateTools.js | 6 +- .../committeeBinary/vat-voter.js | 24 ++- .../contractGovernor/vat-voter.js | 159 +++++++++--------- packages/inter-protocol/src/auction/util.js | 11 +- packages/inter-protocol/src/feeDistributor.js | 72 +++++--- packages/internal/src/marshal.js | 6 +- packages/pegasus/src/pegasus.js | 30 ++-- .../test/test-marshal-contexts.js | 10 +- packages/store/src/stores/scalarMapStore.js | 24 ++- packages/store/src/stores/scalarSetStore.js | 14 +- .../store/src/stores/scalarWeakMapStore.js | 24 ++- .../store/src/stores/scalarWeakSetStore.js | 14 +- packages/store/test/test-AtomicProvider.js | 10 +- packages/vats/src/lib-board.js | 10 +- packages/vats/src/vat-localchain.js | 3 +- packages/wallet/api/src/lib-wallet.js | 10 +- 23 files changed, 334 insertions(+), 185 deletions(-) diff --git a/packages/SwingSet/test/upgrade/bootstrap-scripted-upgrade.js b/packages/SwingSet/test/upgrade/bootstrap-scripted-upgrade.js index 93553d9fbc2..0e2fa7b47ac 100644 --- a/packages/SwingSet/test/upgrade/bootstrap-scripted-upgrade.js +++ b/packages/SwingSet/test/upgrade/bootstrap-scripted-upgrade.js @@ -36,7 +36,13 @@ export const buildRootObject = () => { /** @type {[string, ...object]} */ const importSensors = ['skip0']; for (let i = 1; i <= NUM_SENSORS; i += 1) { - importSensors.push(makeExo(`import-${i}`, M.interface(`import-${i}`, {}, { defaultGuards: 'passable' }), {})); + importSensors.push( + makeExo( + `import-${i}`, + M.interface(`import-${i}`, {}, { defaultGuards: 'passable' }), + {}, + ), + ); } const { promise, resolve } = makePromiseKit(); let dur; diff --git a/packages/SwingSet/test/vat-timer-upgrade/bootstrap-vat-timer-upgrade.js b/packages/SwingSet/test/vat-timer-upgrade/bootstrap-vat-timer-upgrade.js index bc9c450c88e..1432c983a08 100644 --- a/packages/SwingSet/test/vat-timer-upgrade/bootstrap-vat-timer-upgrade.js +++ b/packages/SwingSet/test/vat-timer-upgrade/bootstrap-vat-timer-upgrade.js @@ -10,11 +10,15 @@ export function buildRootObject() { const fromTS = timestamp => TimeMath.absValue(timestamp); const events = []; function makeHandler(name) { - return makeExo(`handler-${name}`, M.interface(`handler-${name}`, {}, { defaultGuards: 'passable' }), { - wake(time) { - events.push(`${name}-${fromTS(time)}`); + return makeExo( + `handler-${name}`, + M.interface(`handler-${name}`, {}, { defaultGuards: 'passable' }), + { + wake(time) { + events.push(`${name}-${fromTS(time)}`); + }, }, - }); + ); } const cancelToken = makeExo( 'cancel', diff --git a/packages/SwingSet/test/virtualObjects/collection-slots/bootstrap-collection-slots.js b/packages/SwingSet/test/virtualObjects/collection-slots/bootstrap-collection-slots.js index dcc5cc42dfc..64703291462 100644 --- a/packages/SwingSet/test/virtualObjects/collection-slots/bootstrap-collection-slots.js +++ b/packages/SwingSet/test/virtualObjects/collection-slots/bootstrap-collection-slots.js @@ -2,7 +2,11 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { // build the import sensor - const imp1 = makeExo(`import-1`, M.interface(`import-1`, {}, { defaultGuards: 'passable' }), {}); + const imp1 = makeExo( + `import-1`, + M.interface(`import-1`, {}, { defaultGuards: 'passable' }), + {}, + ); let targetvat; diff --git a/packages/SwingSet/test/virtualObjects/delete-stored-vo/bootstrap-delete-stored-vo.js b/packages/SwingSet/test/virtualObjects/delete-stored-vo/bootstrap-delete-stored-vo.js index 356e3bc8233..cd6c04792ef 100644 --- a/packages/SwingSet/test/virtualObjects/delete-stored-vo/bootstrap-delete-stored-vo.js +++ b/packages/SwingSet/test/virtualObjects/delete-stored-vo/bootstrap-delete-stored-vo.js @@ -2,7 +2,11 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { // build the import sensor - const imp1 = makeExo(`import-1`, M.interface(`import-1`, {}, { defaultGuards: 'passable' }), {}); + const imp1 = makeExo( + `import-1`, + M.interface(`import-1`, {}, { defaultGuards: 'passable' }), + {}, + ); let targetvat; diff --git a/packages/SwingSet/test/virtualObjects/double-retire-import/bootstrap-dri.js b/packages/SwingSet/test/virtualObjects/double-retire-import/bootstrap-dri.js index fa6f948ad4a..ac31f67c1f7 100644 --- a/packages/SwingSet/test/virtualObjects/double-retire-import/bootstrap-dri.js +++ b/packages/SwingSet/test/virtualObjects/double-retire-import/bootstrap-dri.js @@ -3,8 +3,16 @@ import { Far, E } from '@endo/far'; export function buildRootObject() { let vatAdmin; let root; - const sensor0 = makeExo(`sensor-0`, M.interface(`sensor-0`, {}, { defaultGuards: 'passable' }), {}); - const sensor1 = makeExo(`sensor-1`, M.interface(`sensor-1`, {}, { defaultGuards: 'passable' }), {}); + const sensor0 = makeExo( + `sensor-0`, + M.interface(`sensor-0`, {}, { defaultGuards: 'passable' }), + {}, + ); + const sensor1 = makeExo( + `sensor-1`, + M.interface(`sensor-1`, {}, { defaultGuards: 'passable' }), + {}, + ); return makeExo( 'root', diff --git a/packages/casting/src/defaults.js b/packages/casting/src/defaults.js index e101adbb91e..81877aeaada 100644 --- a/packages/casting/src/defaults.js +++ b/packages/casting/src/defaults.js @@ -109,7 +109,15 @@ export const MAKE_DEFAULT_UNSERIALIZER = () => { if (typeof iface === 'string' && iface.startsWith(ifaceAllegedPrefix)) { iface = iface.slice(ifaceAllegedPrefix.length); } - const obj = makeExo(`${ifaceInaccessiblePrefix}${iface}`, M.interface(`${ifaceInaccessiblePrefix}${iface}`, {}, { defaultGuards: 'passable' }), {}); + const obj = makeExo( + `${ifaceInaccessiblePrefix}${iface}`, + M.interface( + `${ifaceInaccessiblePrefix}${iface}`, + {}, + { defaultGuards: 'passable' }, + ), + {}, + ); seen.set(slot, obj); return obj; }; diff --git a/packages/governance/src/contractGovernance/paramManager.js b/packages/governance/src/contractGovernance/paramManager.js index b629003394e..3ac7013f0a7 100644 --- a/packages/governance/src/contractGovernance/paramManager.js +++ b/packages/governance/src/contractGovernance/paramManager.js @@ -109,13 +109,17 @@ const makeParamManagerBuilder = (publisherKit, zoe) => { return proposed; }; - const publicMethods = makeExo(`Parameter ${name}`, M.interface(`Parameter ${name}`, {}, { defaultGuards: 'passable' }), { - getValue: () => current, - assertType: assertion, - makeDescription: () => ({ type, value: current }), - getVisibleValue, - getType: () => type, - }); + const publicMethods = makeExo( + `Parameter ${name}`, + M.interface(`Parameter ${name}`, {}, { defaultGuards: 'passable' }), + { + getValue: () => current, + assertType: assertion, + makeDescription: () => ({ type, value: current }), + getVisibleValue, + getType: () => type, + }, + ); // names are keywords so they will necessarily be TitleCase // eslint-disable-next-line no-use-before-define @@ -281,14 +285,18 @@ const makeParamManagerBuilder = (publisherKit, zoe) => { const getVisibleValue = async allegedInvitation => E(E(zoe).getInvitationIssuer()).getAmountOf(allegedInvitation); - const publicMethods = makeExo(`Parameter ${name}`, M.interface(`Parameter ${name}`, {}, { defaultGuards: 'passable' }), { - getValue: () => currentAmount, - getInternalValue: () => currentInvitation, - assertType: assertInvitation, - makeDescription, - getType: () => ParamTypes.INVITATION, - getVisibleValue, - }); + const publicMethods = makeExo( + `Parameter ${name}`, + M.interface(`Parameter ${name}`, {}, { defaultGuards: 'passable' }), + { + getValue: () => currentAmount, + getInternalValue: () => currentInvitation, + assertType: assertInvitation, + makeDescription, + getType: () => ParamTypes.INVITATION, + getVisibleValue, + }, + ); // eslint-disable-next-line no-use-before-define getters[`get${name}`] = () => getTypedParam(ParamTypes.INVITATION, name); diff --git a/packages/governance/src/electorateTools.js b/packages/governance/src/electorateTools.js index 1ef9cb9aa2a..49e9ca77bcf 100644 --- a/packages/governance/src/electorateTools.js +++ b/packages/governance/src/electorateTools.js @@ -89,7 +89,11 @@ const getQuestion = (questionHandleP, questionStore) => const getPoserInvitation = (zcf, addQuestion) => { const questionPoserHandler = seat => { seat.exit(); - return makeExo(`questionPoser`, M.interface(`questionPoser`, {}, { defaultGuards: 'passable' }), { addQuestion }); + return makeExo( + `questionPoser`, + M.interface(`questionPoser`, {}, { defaultGuards: 'passable' }), + { addQuestion }, + ); }; return zcf.makeInvitation( questionPoserHandler, diff --git a/packages/governance/test/swingsetTests/committeeBinary/vat-voter.js b/packages/governance/test/swingsetTests/committeeBinary/vat-voter.js index b08c2944735..2dde9c46059 100644 --- a/packages/governance/test/swingsetTests/committeeBinary/vat-voter.js +++ b/packages/governance/test/swingsetTests/committeeBinary/vat-voter.js @@ -70,10 +70,14 @@ const build = async (log, zoe) => { votingObserver, ); - return makeExo(`Voter ${name}`, M.interface(`Voter ${name}`, {}, { defaultGuards: 'passable' }), { - verifyBallot: (question, instances) => - verify(log, question, electoratePublicFacet, instances), - }); + return makeExo( + `Voter ${name}`, + M.interface(`Voter ${name}`, {}, { defaultGuards: 'passable' }), + { + verifyBallot: (question, instances) => + verify(log, question, electoratePublicFacet, instances), + }, + ); }, createMultiVoter: async (name, invitation, choices) => { const electorateInstance = await E(zoe).getInstance(invitation); @@ -103,10 +107,14 @@ const build = async (log, zoe) => { votingObserver, ); - return makeExo(`Voter ${name}`, M.interface(`Voter ${name}`, {}, { defaultGuards: 'passable' }), { - verifyBallot: (question, instances) => - verify(log, question, electoratePublicFacet, instances), - }); + return makeExo( + `Voter ${name}`, + M.interface(`Voter ${name}`, {}, { defaultGuards: 'passable' }), + { + verifyBallot: (question, instances) => + verify(log, question, electoratePublicFacet, instances), + }, + ); }, }, ); diff --git a/packages/governance/test/swingsetTests/contractGovernor/vat-voter.js b/packages/governance/test/swingsetTests/contractGovernor/vat-voter.js index 207335605a4..ad982190f1d 100644 --- a/packages/governance/test/swingsetTests/contractGovernor/vat-voter.js +++ b/packages/governance/test/swingsetTests/contractGovernor/vat-voter.js @@ -21,89 +21,98 @@ const build = async (log, zoe) => { const seat = E(zoe).offer(invitation); const { voter } = E.get(E(seat).getOfferResult()); - return makeExo(`Voter ${name}`, M.interface(`Voter ${name}`, {}, { defaultGuards: 'passable' }), { - castBallotFor: async (questionHandle, choice) => { - log(`Voter ${name} voted for ${q(choice)}`); - return E(voter).castBallotFor(questionHandle, [choice]); - }, - /** - * - * @param {Instance} counterInstance - * @param {Instance} governedInstance - * @param {Instance} electorateInstance - * @param {Instance} governorInstance - * @param {Record} installations - * @returns {Promise} - */ - validate: async ( - counterInstance, - governedInstance, - electorateInstance, - governorInstance, - installations, - ) => { - const validateQuestionFromCounterP = validateQuestionFromCounter( - zoe, - electorateInstance, + return makeExo( + `Voter ${name}`, + M.interface(`Voter ${name}`, {}, { defaultGuards: 'passable' }), + { + castBallotFor: async (questionHandle, choice) => { + log(`Voter ${name} voted for ${q(choice)}`); + return E(voter).castBallotFor(questionHandle, [choice]); + }, + /** + * + * @param {Instance} counterInstance + * @param {Instance} governedInstance + * @param {Instance} electorateInstance + * @param {Instance} governorInstance + * @param {Record} installations + * @returns {Promise} + */ + validate: async ( counterInstance, - ); - - const contractGovernanceP = assertContractGovernance( - zoe, governedInstance, + electorateInstance, governorInstance, - installations.contractGovernor, - ); + installations, + ) => { + const validateQuestionFromCounterP = validateQuestionFromCounter( + zoe, + electorateInstance, + counterInstance, + ); - const [ - questionDetails, - electorateInstallation, - voteCounterInstallation, - governedInstallation, - governorInstallation, - validatedQuestion, - contractGovernance, - ] = await Promise.all([ - E(E(zoe).getPublicFacet(counterInstance)).getDetails(), - E(zoe).getInstallationForInstance(electorateInstance), - E(zoe).getInstallationForInstance(counterInstance), - E(zoe).getInstallationForInstance(governedInstance), - E(zoe).getInstallationForInstance(governorInstance), - validateQuestionFromCounterP, - contractGovernanceP, - ]); + const contractGovernanceP = assertContractGovernance( + zoe, + governedInstance, + governorInstance, + installations.contractGovernor, + ); - assertBallotConcernsParam( - harden({ - paramPath: { key: 'governedParams' }, - parameterName: MALLEABLE_NUMBER, - }), - questionDetails, - ); - assert(installations.binaryVoteCounter === voteCounterInstallation); - assert(installations.governedContract === governedInstallation); - assert(installations.contractGovernor === governorInstallation); - assert(installations.committee === electorateInstallation); - await assertContractElectorate( - zoe, - governorInstance, - electorateInstance, - ); + const [ + questionDetails, + electorateInstallation, + voteCounterInstallation, + governedInstallation, + governorInstallation, + validatedQuestion, + contractGovernance, + ] = await Promise.all([ + E(E(zoe).getPublicFacet(counterInstance)).getDetails(), + E(zoe).getInstallationForInstance(electorateInstance), + E(zoe).getInstallationForInstance(counterInstance), + E(zoe).getInstallationForInstance(governedInstance), + E(zoe).getInstallationForInstance(governorInstance), + validateQuestionFromCounterP, + contractGovernanceP, + ]); - await validateQuestionDetails( - zoe, - electorateInstance, - questionDetails, - ); - assert(validatedQuestion, 'governor failed to validate electorate'); - assert( - contractGovernance, - "governor and governed aren't tightly linked", - ); + assertBallotConcernsParam( + harden({ + paramPath: { key: 'governedParams' }, + parameterName: MALLEABLE_NUMBER, + }), + questionDetails, + ); + assert( + installations.binaryVoteCounter === voteCounterInstallation, + ); + assert(installations.governedContract === governedInstallation); + assert(installations.contractGovernor === governorInstallation); + assert(installations.committee === electorateInstallation); + await assertContractElectorate( + zoe, + governorInstance, + electorateInstance, + ); + + await validateQuestionDetails( + zoe, + electorateInstance, + questionDetails, + ); + assert( + validatedQuestion, + 'governor failed to validate electorate', + ); + assert( + contractGovernance, + "governor and governed aren't tightly linked", + ); - log(`Voter ${name} validated all the things`); + log(`Voter ${name} validated all the things`); + }, }, - }); + ); }, }, ); diff --git a/packages/inter-protocol/src/auction/util.js b/packages/inter-protocol/src/auction/util.js index 5a3a0e3c682..15b6a1b72ac 100644 --- a/packages/inter-protocol/src/auction/util.js +++ b/packages/inter-protocol/src/auction/util.js @@ -51,5 +51,14 @@ export const priceFrom = quote => export const makeCancelTokenMaker = name => { let tokenCount = 1; - return () => makeExo(`cancelToken-${name}-${(tokenCount += 1)}`, M.interface(`cancelToken-${name}-${(tokenCount += 1)}`, {}, { defaultGuards: 'passable' }), {}); + return () => + makeExo( + `cancelToken-${name}-${(tokenCount += 1)}`, + M.interface( + `cancelToken-${name}-${(tokenCount += 1)}`, + {}, + { defaultGuards: 'passable' }, + ), + {}, + ); }; diff --git a/packages/inter-protocol/src/feeDistributor.js b/packages/inter-protocol/src/feeDistributor.js index b297befff3f..4ac7014cf9f 100644 --- a/packages/inter-protocol/src/feeDistributor.js +++ b/packages/inter-protocol/src/feeDistributor.js @@ -297,11 +297,19 @@ export const makeFeeDistributor = (feeIssuer, terms) => { /** @param {import('@endo/far').EOnly} depositFacet */ makeDepositFacetDestination: depositFacet => { - return makeExo(`DepositFacetDestination`, M.interface(`DepositFacetDestination`, {}, { defaultGuards: 'passable' }), { - pushPayment: async (payment, _issuer) => { - return E(depositFacet).receive(payment); + return makeExo( + `DepositFacetDestination`, + M.interface( + `DepositFacetDestination`, + {}, + { defaultGuards: 'passable' }, + ), + { + pushPayment: async (payment, _issuer) => { + return E(depositFacet).receive(payment); + }, }, - }); + ); }, /** * Create a destination that generates invitations and makes Zoe offers. @@ -319,32 +327,40 @@ export const makeFeeDistributor = (feeIssuer, terms) => { makeInvitationMethod, args = [], ) => { - return makeExo(`${String(makeInvitationMethod)} OfferDestination`, M.interface(`${String(makeInvitationMethod)} OfferDestination`, {}, { defaultGuards: 'passable' }), { - pushPayment: async (payment, issuer) => { - const paymentAmount = await E(issuer).getAmountOf(payment); - - // Give the payment to the contract via its invitation. - const invitation = E(target)[makeInvitationMethod](...args); - const result = E(zoe).offer( - invitation, - { - give: { - [keyword]: paymentAmount, + return makeExo( + `${String(makeInvitationMethod)} OfferDestination`, + M.interface( + `${String(makeInvitationMethod)} OfferDestination`, + {}, + { defaultGuards: 'passable' }, + ), + { + pushPayment: async (payment, issuer) => { + const paymentAmount = await E(issuer).getAmountOf(payment); + + // Give the payment to the contract via its invitation. + const invitation = E(target)[makeInvitationMethod](...args); + const result = E(zoe).offer( + invitation, + { + give: { + [keyword]: paymentAmount, + }, + }, + { + [keyword]: payment, }, - }, - { - [keyword]: payment, - }, - ); - - // Assert that the offer completed. - await E(result).getOfferResult(); - - // We deliberately drop our payouts on the floor, since the ERTP purse - // recovery mechanism can get them back to the distributor contract. - return paymentAmount; + ); + + // Assert that the offer completed. + await E(result).getOfferResult(); + + // We deliberately drop our payouts on the floor, since the ERTP purse + // recovery mechanism can get them back to the distributor contract. + return paymentAmount; + }, }, - }); + ); }, /** @param {Record>} newDestinations */ diff --git a/packages/internal/src/marshal.js b/packages/internal/src/marshal.js index 0d8c40bdbc6..b3e835e6631 100644 --- a/packages/internal/src/marshal.js +++ b/packages/internal/src/marshal.js @@ -17,7 +17,11 @@ const { Fail } = assert; */ export const makeBoardRemote = ({ boardId, iface }) => { const nonalleged = iface ? iface.replace(/^Alleged: /, '') : ''; - return makeExo(`BoardRemote${nonalleged}`, M.interface(`BoardRemote${nonalleged}`, {}, { defaultGuards: 'passable' }), { getBoardId: () => boardId }); + return makeExo( + `BoardRemote${nonalleged}`, + M.interface(`BoardRemote${nonalleged}`, {}, { defaultGuards: 'passable' }), + { getBoardId: () => boardId }, + ); }; /** diff --git a/packages/pegasus/src/pegasus.js b/packages/pegasus/src/pegasus.js index 93ec89295cc..8ff59f7d08c 100644 --- a/packages/pegasus/src/pegasus.js +++ b/packages/pegasus/src/pegasus.js @@ -82,20 +82,24 @@ export const makePegasus = ({ zcf, board, namesByAddress, when }) => { */ const makePeg = (state, desc) => { /** @type {Peg} */ - const peg = makeExo(`${desc.allegedName} peg`, M.interface(`${desc.allegedName} peg`, {}, { defaultGuards: 'passable' }), { - getAllegedName() { - return desc.allegedName; - }, - getLocalBrand() { - return desc.localBrand; - }, - getReceiveDenom() { - return desc.receiveDenom; - }, - getSendDenom() { - return desc.sendDenom; + const peg = makeExo( + `${desc.allegedName} peg`, + M.interface(`${desc.allegedName} peg`, {}, { defaultGuards: 'passable' }), + { + getAllegedName() { + return desc.allegedName; + }, + getLocalBrand() { + return desc.localBrand; + }, + getReceiveDenom() { + return desc.receiveDenom; + }, + getSendDenom() { + return desc.sendDenom; + }, }, - }); + ); pegToDenomState.init(peg, state); return peg; diff --git a/packages/smart-wallet/test/test-marshal-contexts.js b/packages/smart-wallet/test/test-marshal-contexts.js index a5182a2e78a..61f1bd18f9b 100644 --- a/packages/smart-wallet/test/test-marshal-contexts.js +++ b/packages/smart-wallet/test/test-marshal-contexts.js @@ -26,9 +26,13 @@ const makeOnChainWallet = board => { return harden({ suggestIssuer: (name, boardId) => { brand = board.getValue(boardId); - const purse = makeExo(`${name} purse`, M.interface(`${name} purse`, {}, { defaultGuards: 'passable' }), { - getCurrentAmount: () => harden({ brand, value: 100 }), - }); + const purse = makeExo( + `${name} purse`, + M.interface(`${name} purse`, {}, { defaultGuards: 'passable' }), + { + getCurrentAmount: () => harden({ brand, value: 100 }), + }, + ); // only for private brands // context.initBrandId(boardId, brand); context.initBoardId(boardId, brand); diff --git a/packages/store/src/stores/scalarMapStore.js b/packages/store/src/stores/scalarMapStore.js index f5c32319174..1e32dfd1d3b 100644 --- a/packages/store/src/stores/scalarMapStore.js +++ b/packages/store/src/stores/scalarMapStore.js @@ -168,14 +168,22 @@ export const makeScalarMapStore = ( assertKVOkToSet(key, value); }; - return makeExo(`scalar MapStore of ${q(tag)}`, M.interface(`scalar MapStore of ${q(tag)}`, {}, { defaultGuards: 'passable' }), { - ...makeMapStoreMethods( - jsmap, - assertKVOkToAdd, - assertKVOkToSet, - undefined, - tag, + return makeExo( + `scalar MapStore of ${q(tag)}`, + M.interface( + `scalar MapStore of ${q(tag)}`, + {}, + { defaultGuards: 'passable' }, ), - }); + { + ...makeMapStoreMethods( + jsmap, + assertKVOkToAdd, + assertKVOkToSet, + undefined, + tag, + ), + }, + ); }; harden(makeScalarMapStore); diff --git a/packages/store/src/stores/scalarSetStore.js b/packages/store/src/stores/scalarSetStore.js index b0194dea767..3fd5782825e 100644 --- a/packages/store/src/stores/scalarSetStore.js +++ b/packages/store/src/stores/scalarSetStore.js @@ -109,8 +109,16 @@ export const makeScalarSetStore = ( } }; - return makeExo(`scalar SetStore of ${q(tag)}`, M.interface(`scalar SetStore of ${q(tag)}`, {}, { defaultGuards: 'passable' }), { - ...makeSetStoreMethods(jsset, assertKeyOkToAdd, undefined, tag), - }); + return makeExo( + `scalar SetStore of ${q(tag)}`, + M.interface( + `scalar SetStore of ${q(tag)}`, + {}, + { defaultGuards: 'passable' }, + ), + { + ...makeSetStoreMethods(jsset, assertKeyOkToAdd, undefined, tag), + }, + ); }; harden(makeScalarSetStore); diff --git a/packages/store/src/stores/scalarWeakMapStore.js b/packages/store/src/stores/scalarWeakMapStore.js index b4f97d94c20..a8e58e8a56b 100644 --- a/packages/store/src/stores/scalarWeakMapStore.js +++ b/packages/store/src/stores/scalarWeakMapStore.js @@ -131,14 +131,22 @@ export const makeScalarWeakMapStore = ( assertKVOkToSet(key, value); }; - return makeExo(`scalar WeakMapStore of ${q(tag)}`, M.interface(`scalar WeakMapStore of ${q(tag)}`, {}, { defaultGuards: 'passable' }), { - ...makeWeakMapStoreMethods( - jsmap, - assertKVOkToAdd, - assertKVOkToSet, - undefined, - tag, + return makeExo( + `scalar WeakMapStore of ${q(tag)}`, + M.interface( + `scalar WeakMapStore of ${q(tag)}`, + {}, + { defaultGuards: 'passable' }, ), - }); + { + ...makeWeakMapStoreMethods( + jsmap, + assertKVOkToAdd, + assertKVOkToSet, + undefined, + tag, + ), + }, + ); }; harden(makeScalarWeakMapStore); diff --git a/packages/store/src/stores/scalarWeakSetStore.js b/packages/store/src/stores/scalarWeakSetStore.js index 7742894f3f5..5335f3e3027 100644 --- a/packages/store/src/stores/scalarWeakSetStore.js +++ b/packages/store/src/stores/scalarWeakSetStore.js @@ -98,8 +98,16 @@ export const makeScalarWeakSetStore = ( } }; - return makeExo(`scalar WeakSetStore of ${q(tag)}`, M.interface(`scalar WeakSetStore of ${q(tag)}`, {}, { defaultGuards: 'passable' }), { - ...makeWeakSetStoreMethods(jsset, assertKeyOkToAdd, undefined, tag), - }); + return makeExo( + `scalar WeakSetStore of ${q(tag)}`, + M.interface( + `scalar WeakSetStore of ${q(tag)}`, + {}, + { defaultGuards: 'passable' }, + ), + { + ...makeWeakSetStoreMethods(jsset, assertKeyOkToAdd, undefined, tag), + }, + ); }; harden(makeScalarWeakSetStore); diff --git a/packages/store/test/test-AtomicProvider.js b/packages/store/test/test-AtomicProvider.js index 85867bee450..dc95685a7eb 100644 --- a/packages/store/test/test-AtomicProvider.js +++ b/packages/store/test/test-AtomicProvider.js @@ -77,9 +77,13 @@ test('far keys', async t => { let i = 0; const makeBrand = name => - makeExo(`brand ${name}`, M.interface(`brand ${name}`, {}, { defaultGuards: 'passable' }), { - getAllegedName: () => `${name} ${(i += 1)}`, - }); + makeExo( + `brand ${name}`, + M.interface(`brand ${name}`, {}, { defaultGuards: 'passable' }), + { + getAllegedName: () => `${name} ${(i += 1)}`, + }, + ); const makeValue = brand => Promise.resolve(brand.getAllegedName()); diff --git a/packages/vats/src/lib-board.js b/packages/vats/src/lib-board.js index 1dccd548935..6292d753847 100644 --- a/packages/vats/src/lib-board.js +++ b/packages/vats/src/lib-board.js @@ -195,7 +195,15 @@ const makeSlotToVal = state => { if (typeof iface === 'string' && iface.startsWith(ifaceAllegedPrefix)) { iface = iface.slice(ifaceAllegedPrefix.length); } - return makeExo(`${ifaceInaccessiblePrefix}${iface}`, M.interface(`${ifaceInaccessiblePrefix}${iface}`, {}, { defaultGuards: 'passable' }), {}); + return makeExo( + `${ifaceInaccessiblePrefix}${iface}`, + M.interface( + `${ifaceInaccessiblePrefix}${iface}`, + {}, + { defaultGuards: 'passable' }, + ), + {}, + ); }; return slotToVal; }; diff --git a/packages/vats/src/vat-localchain.js b/packages/vats/src/vat-localchain.js index 71a0505fe4a..ad51a1cdb3b 100644 --- a/packages/vats/src/vat-localchain.js +++ b/packages/vats/src/vat-localchain.js @@ -14,7 +14,8 @@ export const buildRootObject = (_vatPowers, _args, baggage) => { { /** * Create a local chain that allows permissionlessly making fresh local - * chain accounts, then using them to send chain queries and transactions. + * chain accounts, then using them to send chain queries and + * transactions. * * @param {import('./types').ScopedBridgeManager} system */ diff --git a/packages/wallet/api/src/lib-wallet.js b/packages/wallet/api/src/lib-wallet.js index d79ee567580..04a81f47f35 100644 --- a/packages/wallet/api/src/lib-wallet.js +++ b/packages/wallet/api/src/lib-wallet.js @@ -1662,9 +1662,13 @@ export function makeWalletRoot({ const makeLookup = (kind, lookup) => { rootPathToLookup.init( kind, - makeExo(`${kind}Lookup`, M.interface(`${kind}Lookup`, {}, { defaultGuards: 'passable' }), { - lookup, - }), + makeExo( + `${kind}Lookup`, + M.interface(`${kind}Lookup`, {}, { defaultGuards: 'passable' }), + { + lookup, + }, + ), ); }; From be05c683e47b759b1456e735c370a9b8c4d3a30b Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Thu, 7 Mar 2024 08:03:18 -0800 Subject: [PATCH 03/12] fixup! fix store, mostly revert base-zone --- packages/base-zone/src/heap.js | 56 ++++++++----------- packages/base-zone/src/make-once.js | 2 +- packages/store/src/stores/scalarMapStore.js | 9 +-- packages/store/src/stores/scalarSetStore.js | 4 +- .../store/src/stores/scalarWeakMapStore.js | 4 +- .../store/src/stores/scalarWeakSetStore.js | 4 +- packages/store/src/stores/store-utils.js | 3 +- packages/store/test/perf-patterns.js | 3 +- packages/store/test/test-AtomicProvider.js | 3 +- packages/store/test/test-store.js | 4 +- 10 files changed, 46 insertions(+), 46 deletions(-) diff --git a/packages/base-zone/src/heap.js b/packages/base-zone/src/heap.js index 5abc789ebb1..5c74e05c203 100644 --- a/packages/base-zone/src/heap.js +++ b/packages/base-zone/src/heap.js @@ -1,7 +1,7 @@ // @ts-check // @jessie-check -import { Far } from '@endo/far'; +import { Far } from '@endo/pass-style'; import { makeExo, defineExoClass, defineExoClassKit } from '@endo/exo'; import { makeScalarMapStore, @@ -17,19 +17,15 @@ import { isPassable } from './is-passable.js'; /** * @type {import('./types.js').Stores} */ -const detachedHeapStores = makeExo( - 'heapStores', - M.interface('heapStores', {}, { defaultGuards: 'passable' }), - { - detached: () => detachedHeapStores, - isStorable: isPassable, +const detachedHeapStores = Far('heapStores', { + detached: () => detachedHeapStores, + isStorable: isPassable, - setStore: makeScalarSetStore, - mapStore: makeScalarMapStore, - weakMapStore: makeScalarWeakMapStore, - weakSetStore: makeScalarWeakSetStore, - }, -); + setStore: makeScalarSetStore, + mapStore: makeScalarMapStore, + weakMapStore: makeScalarWeakMapStore, + weakSetStore: makeScalarWeakSetStore, +}); /** * Create a heap (in-memory) zone that uses the default exo and store implementations. @@ -47,24 +43,20 @@ export const makeHeapZone = (baseLabel = 'heapZone') => { const makeSubZone = (label, _options) => makeHeapZone(`${baseLabel}.${label}`); - return makeExo( - 'heapZone', - M.interface('heapZone', {}, { defaultGuards: 'passable' }), - { - exo: wrapProvider(makeExo, keys.exo), - exoClass: wrapProvider(defineExoClass, keys.exoClass), - exoClassKit: wrapProvider(defineExoClassKit, keys.exoClassKit), - subZone: wrapProvider(makeSubZone), - - makeOnce, - detached: detachedHeapStores.detached, - isStorable: detachedHeapStores.isStorable, - - mapStore: wrapProvider(detachedHeapStores.mapStore), - setStore: wrapProvider(detachedHeapStores.setStore), - weakMapStore: wrapProvider(detachedHeapStores.weakMapStore), - weakSetStore: wrapProvider(detachedHeapStores.weakSetStore), - }, - ); + return Far('heapZone', { + exo: wrapProvider(makeExo, keys.exo), + exoClass: wrapProvider(defineExoClass, keys.exoClass), + exoClassKit: wrapProvider(defineExoClassKit, keys.exoClassKit), + subZone: wrapProvider(makeSubZone), + + makeOnce, + detached: detachedHeapStores.detached, + isStorable: detachedHeapStores.isStorable, + + mapStore: wrapProvider(detachedHeapStores.mapStore), + setStore: wrapProvider(detachedHeapStores.setStore), + weakMapStore: wrapProvider(detachedHeapStores.weakMapStore), + weakSetStore: wrapProvider(detachedHeapStores.weakSetStore), + }); }; harden(makeHeapZone); diff --git a/packages/base-zone/src/make-once.js b/packages/base-zone/src/make-once.js index e0b6f5d639e..d9654b32110 100644 --- a/packages/base-zone/src/make-once.js +++ b/packages/base-zone/src/make-once.js @@ -8,7 +8,7 @@ harden(defaultLabelToKeys); /** * @param {string} debugName Only used internally for diagnostics, not available to user code * @param {import('./types.js').Stores} stores - * @param {import('@agoric/swingset-liveslots').MapStore} [backingStore] + * @param {MapStore} [backingStore] */ export const makeOnceKit = (debugName, stores, backingStore = undefined) => { // We need a detached setStore so that it isn't persisted as part of the zone. diff --git a/packages/store/src/stores/scalarMapStore.js b/packages/store/src/stores/scalarMapStore.js index 1e32dfd1d3b..821f5c64019 100644 --- a/packages/store/src/stores/scalarMapStore.js +++ b/packages/store/src/stores/scalarMapStore.js @@ -1,9 +1,4 @@ -import { - Far, - assertPassable, - filterIterable, - mapIterable, -} from '@endo/pass-style'; +import { assertPassable, filterIterable, mapIterable } from '@endo/pass-style'; import { compareRank } from '@endo/marshal'; import { assertScalarKey, @@ -11,7 +6,9 @@ import { matches, mustMatch, assertPattern, + M, } from '@endo/patterns'; +import { makeExo } from '@endo/exo'; import { makeWeakMapStoreMethods } from './scalarWeakMapStore.js'; import { makeCurrentKeysKit } from './store-utils.js'; diff --git a/packages/store/src/stores/scalarSetStore.js b/packages/store/src/stores/scalarSetStore.js index 3fd5782825e..8aef2f3f7af 100644 --- a/packages/store/src/stores/scalarSetStore.js +++ b/packages/store/src/stores/scalarSetStore.js @@ -1,4 +1,4 @@ -import { Far, filterIterable } from '@endo/pass-style'; +import { filterIterable } from '@endo/pass-style'; import { compareRank } from '@endo/marshal'; import { assertScalarKey, @@ -6,7 +6,9 @@ import { matches, mustMatch, assertPattern, + M, } from '@endo/patterns'; +import { makeExo } from '@endo/exo'; import { makeWeakSetStoreMethods } from './scalarWeakSetStore.js'; import { makeCurrentKeysKit } from './store-utils.js'; diff --git a/packages/store/src/stores/scalarWeakMapStore.js b/packages/store/src/stores/scalarWeakMapStore.js index a8e58e8a56b..cb1017f98bd 100644 --- a/packages/store/src/stores/scalarWeakMapStore.js +++ b/packages/store/src/stores/scalarWeakMapStore.js @@ -1,10 +1,12 @@ -import { Far, assertPassable, passStyleOf } from '@endo/pass-style'; +import { assertPassable, passStyleOf } from '@endo/pass-style'; import { getCopyMapEntries, mustMatch, assertPattern, isCopyMap, + M, } from '@endo/patterns'; +import { makeExo } from '@endo/exo'; const { quote: q, Fail } = assert; diff --git a/packages/store/src/stores/scalarWeakSetStore.js b/packages/store/src/stores/scalarWeakSetStore.js index 5335f3e3027..6777c344b33 100644 --- a/packages/store/src/stores/scalarWeakSetStore.js +++ b/packages/store/src/stores/scalarWeakSetStore.js @@ -1,10 +1,12 @@ -import { Far, passStyleOf } from '@endo/pass-style'; +import { passStyleOf } from '@endo/pass-style'; import { getCopySetKeys, mustMatch, assertPattern, isCopySet, + M, } from '@endo/patterns'; +import { makeExo } from '@endo/exo'; const { quote: q, Fail } = assert; diff --git a/packages/store/src/stores/store-utils.js b/packages/store/src/stores/store-utils.js index 034cbecee40..7c74826e8b2 100644 --- a/packages/store/src/stores/store-utils.js +++ b/packages/store/src/stores/store-utils.js @@ -1,4 +1,5 @@ -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; /** @typedef {import('@endo/marshal').RankCompare} RankCompare */ diff --git a/packages/store/test/perf-patterns.js b/packages/store/test/perf-patterns.js index 407b5725d8b..97962d45fe7 100644 --- a/packages/store/test/perf-patterns.js +++ b/packages/store/test/perf-patterns.js @@ -1,4 +1,5 @@ -import { Far, makeTagged } from '@endo/marshal'; +import { makeTagged } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; import { makeCopyBag, makeCopyMap, diff --git a/packages/store/test/test-AtomicProvider.js b/packages/store/test/test-AtomicProvider.js index dc95685a7eb..69748f1fb32 100644 --- a/packages/store/test/test-AtomicProvider.js +++ b/packages/store/test/test-AtomicProvider.js @@ -1,7 +1,8 @@ /* eslint-disable no-use-before-define */ import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { setTimeout } from 'timers'; import { makeScalarMapStore } from '../src/stores/scalarMapStore.js'; diff --git a/packages/store/test/test-store.js b/packages/store/test/test-store.js index 8d563029def..31366c21a42 100644 --- a/packages/store/test/test-store.js +++ b/packages/store/test/test-store.js @@ -2,7 +2,9 @@ import test from 'ava'; -import { Far, passStyleOf } from '@endo/marshal'; +import { passStyleOf } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { makeLegacyMap } from '../src/legacy/legacyMap.js'; import { makeLegacyWeakMap } from '../src/legacy/legacyWeakMap.js'; import { makeScalarMapStore } from '../src/stores/scalarMapStore.js'; From fa397aaa30eefaae51b83288cc12dee42a046597 Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Thu, 7 Mar 2024 08:06:02 -0800 Subject: [PATCH 04/12] fixup! fix store, mostly revert base-zone --- packages/base-zone/src/heap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/base-zone/src/heap.js b/packages/base-zone/src/heap.js index 5c74e05c203..839cd2abaf1 100644 --- a/packages/base-zone/src/heap.js +++ b/packages/base-zone/src/heap.js @@ -1,7 +1,7 @@ // @ts-check // @jessie-check -import { Far } from '@endo/pass-style'; +import { Far } from '@endo/far'; import { makeExo, defineExoClass, defineExoClassKit } from '@endo/exo'; import { makeScalarMapStore, From a3efda97b0162b4e89286510201d378512e5f2d5 Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Thu, 7 Mar 2024 08:30:13 -0800 Subject: [PATCH 05/12] fixup! internal --- packages/internal/package.json | 1 + packages/internal/src/marshal.js | 3 ++- packages/internal/src/priority-senders.js | 4 +++- packages/internal/src/scratch.js | 4 +++- packages/internal/src/storage-test-utils.js | 3 ++- packages/internal/test/test-callback.js | 3 ++- packages/internal/test/test-utils.js | 3 ++- 7 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/internal/package.json b/packages/internal/package.json index e5fc76a1869..22b49e0d346 100755 --- a/packages/internal/package.json +++ b/packages/internal/package.json @@ -23,6 +23,7 @@ "@agoric/assert": "^0.6.0", "@agoric/base-zone": "^0.1.0", "@endo/common": "^1.1.0", + "@endo/exo": "^1.2.1", "@endo/far": "^1.0.4", "@endo/init": "^1.0.4", "@endo/marshal": "^1.3.0", diff --git a/packages/internal/src/marshal.js b/packages/internal/src/marshal.js index b3e835e6631..14c52270c86 100644 --- a/packages/internal/src/marshal.js +++ b/packages/internal/src/marshal.js @@ -1,5 +1,6 @@ // @ts-check -import { Far } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { makeMarshal } from '@endo/marshal'; import { isStreamCell } from './lib-chainStorage.js'; diff --git a/packages/internal/src/priority-senders.js b/packages/internal/src/priority-senders.js index 79ebd265dda..d20d928fb58 100644 --- a/packages/internal/src/priority-senders.js +++ b/packages/internal/src/priority-senders.js @@ -1,4 +1,6 @@ -import { E, Far } from '@endo/far'; +import { E } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; const { Fail, quote: q } = assert; diff --git a/packages/internal/src/scratch.js b/packages/internal/src/scratch.js index b7c2171bc2c..437f8df423d 100644 --- a/packages/internal/src/scratch.js +++ b/packages/internal/src/scratch.js @@ -1,4 +1,6 @@ -import { E, Far } from '@endo/far'; +import { E } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; export default function makeScratchPad() { const map = new Map(); diff --git a/packages/internal/src/storage-test-utils.js b/packages/internal/src/storage-test-utils.js index cf1ae302aa2..76e5602dc3d 100644 --- a/packages/internal/src/storage-test-utils.js +++ b/packages/internal/src/storage-test-utils.js @@ -1,5 +1,6 @@ // @ts-check -import { Far } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { makeMarshal, Remotable } from '@endo/marshal'; import { unmarshalFromVstorage } from './marshal.js'; import { makeTracer } from './debug.js'; diff --git a/packages/internal/test/test-callback.js b/packages/internal/test/test-callback.js index 8dc0852da05..b77e3d67279 100644 --- a/packages/internal/test/test-callback.js +++ b/packages/internal/test/test-callback.js @@ -1,7 +1,8 @@ // @ts-check import test from 'ava'; -import { Far } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { makeHeapZone } from '@agoric/base-zone/heap.js'; import * as cb from '../src/callback.js'; diff --git a/packages/internal/test/test-utils.js b/packages/internal/test/test-utils.js index d3a40837352..c91529f91ac 100644 --- a/packages/internal/test/test-utils.js +++ b/packages/internal/test/test-utils.js @@ -1,7 +1,8 @@ // @ts-check import test from 'ava'; -import { Far } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { makeMeasureSeconds, assertAllDefined, From 4fc3c25f5e997fb50ea0f48aa131aba46d462aab Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Thu, 7 Mar 2024 08:31:28 -0800 Subject: [PATCH 06/12] fixup! revert test-storage-test-utils.js to Far because structural --- .../internal/test/test-storage-test-utils.js | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/packages/internal/test/test-storage-test-utils.js b/packages/internal/test/test-storage-test-utils.js index d47e1eb6533..9da39b76c36 100644 --- a/packages/internal/test/test-storage-test-utils.js +++ b/packages/internal/test/test-storage-test-utils.js @@ -62,8 +62,7 @@ test('makeFakeStorageKit', async t => { ); // Valid path segments are strings of up to 100 ASCII alphanumeric/dash/underscore characters. - const validSegmentChars = `${ - Array(26) + const validSegmentChars = `${Array(26) .fill(undefined) .map((_, i) => 'a'.charCodeAt(0) + i) .map(code => String.fromCharCode(code)) @@ -78,7 +77,7 @@ test('makeFakeStorageKit', async t => { .map((_, i) => '0'.charCodeAt(0) + i) .map(code => String.fromCharCode(code)) .join('') - }-_`; + }-_`; const extremeSegments = validSegmentChars .repeat(Math.ceil(100 / validSegmentChars.length)) @@ -272,22 +271,10 @@ const testUnmarshaller = test.macro((t, format) => { // create capdata with specific slots /** @typedef { { getBoardId: () => string } } SlottedRemotable */ const foo = Far('foo'); - const foo1 = makeExo( - 'foo', - M.interface('foo', {}, { defaultGuards: 'passable' }), - { getBoardId: () => 'board1' }, - ); - const foo2 = makeExo( - 'foo', - M.interface('foo', {}, { defaultGuards: 'passable' }), - { getBoardId: () => 'board2' }, - ); + const foo1 = Far('foo', { getBoardId: () => 'board1' }); + const foo2 = Far('foo', { getBoardId: () => 'board2' }); const bar = Far('bar'); - const bar1 = makeExo( - 'bar', - M.interface('bar', {}, { defaultGuards: 'passable' }), - { getBoardId: () => 'board1' }, - ); + const bar1 = Far('bar', { getBoardId: () => 'board1' }); const foo1CD = m.toCapData(harden({ o: foo1 })); const foo2CD = m.toCapData(harden({ o: foo2 })); const bar1CD = m.toCapData(harden({ o: bar1 })); From 77fe1c0f353d42eccf85c743cef1e2245c9cf136 Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Thu, 7 Mar 2024 08:32:50 -0800 Subject: [PATCH 07/12] fixup! format --- packages/internal/test/test-storage-test-utils.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/internal/test/test-storage-test-utils.js b/packages/internal/test/test-storage-test-utils.js index 9da39b76c36..5eab748c657 100644 --- a/packages/internal/test/test-storage-test-utils.js +++ b/packages/internal/test/test-storage-test-utils.js @@ -62,7 +62,8 @@ test('makeFakeStorageKit', async t => { ); // Valid path segments are strings of up to 100 ASCII alphanumeric/dash/underscore characters. - const validSegmentChars = `${Array(26) + const validSegmentChars = `${ + Array(26) .fill(undefined) .map((_, i) => 'a'.charCodeAt(0) + i) .map(code => String.fromCharCode(code)) @@ -77,7 +78,7 @@ test('makeFakeStorageKit', async t => { .map((_, i) => '0'.charCodeAt(0) + i) .map(code => String.fromCharCode(code)) .join('') - }-_`; + }-_`; const extremeSegments = validSegmentChars .repeat(Math.ceil(100 / validSegmentChars.length)) From 5d3952e22a0a5ceef317bb67e6265219f047a91e Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Thu, 7 Mar 2024 08:51:03 -0800 Subject: [PATCH 08/12] fixup! swingset-liveslots --- .../swingset-liveslots/src/virtualObjectManager.js | 12 ++---------- packages/swingset-liveslots/test/gc-helpers.js | 4 ++-- packages/swingset-liveslots/test/test-baggage.js | 3 ++- .../test/test-collection-schema-refcount.js | 3 ++- .../test/test-collection-upgrade.js | 4 ++-- .../test/test-dropped-collection-weakrefs.js | 3 ++- .../swingset-liveslots/test/test-durabilityChecks.js | 3 ++- .../swingset-liveslots/test/test-gc-sensitivity.js | 3 ++- .../swingset-liveslots/test/test-handled-promises.js | 5 +++-- .../swingset-liveslots/test/test-initial-vrefs.js | 4 ++-- .../test/test-liveslots-mock-gc.js | 3 ++- .../test/test-liveslots-real-gc.js | 3 ++- packages/swingset-liveslots/test/test-liveslots.js | 3 ++- .../swingset-liveslots/test/test-vpid-liveslots.js | 3 ++- .../test/virtual-objects/test-kind-changes.js | 3 ++- .../test/virtual-objects/test-state-shape.js | 3 ++- .../test/virtual-objects/test-virtualObjectGC.js | 3 ++- .../test/virtual-objects/test-vo-real-gc.js | 3 ++- packages/swingset-liveslots/tools/vo-test-harness.js | 3 ++- 19 files changed, 39 insertions(+), 32 deletions(-) diff --git a/packages/swingset-liveslots/src/virtualObjectManager.js b/packages/swingset-liveslots/src/virtualObjectManager.js index c382d92ff06..1b4728559a8 100644 --- a/packages/swingset-liveslots/src/virtualObjectManager.js +++ b/packages/swingset-liveslots/src/virtualObjectManager.js @@ -1090,11 +1090,7 @@ export const makeVirtualObjectManager = ( const nextInstanceID = loadNextInstanceID(kindID); kindIDToDescriptor.set(kindID, durableKindDescriptor); nextInstanceIDs.set(kindID, nextInstanceID); - const kindHandle = makeExo( - 'kind', - M.interface('kind', {}, { defaultGuards: 'passable' }), - {}, - ); + const kindHandle = Far('kind', {}); kindHandleToID.set(kindHandle, kindID); // KindHandles are held strongly for the remainder of the incarnation, so // their components do not provide GC sensors @@ -1175,11 +1171,7 @@ export const makeVirtualObjectManager = ( /** @type {import('@agoric/vat-data').DurableKindHandle} */ // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error -- https://github.com/Agoric/agoric-sdk/issues/4620 // @ts-ignore cast - const kindHandle = makeExo( - 'kind', - M.interface('kind', {}, { defaultGuards: 'passable' }), - {}, - ); + const kindHandle = Far('kind', {}); kindHandleToID.set(kindHandle, kindID); const kindIDvref = makeBaseRef(kindIDID, kindID, true); registerValue(kindIDvref, kindHandle, false); diff --git a/packages/swingset-liveslots/test/gc-helpers.js b/packages/swingset-liveslots/test/gc-helpers.js index 4fb11793c16..020a5134cce 100644 --- a/packages/swingset-liveslots/test/gc-helpers.js +++ b/packages/swingset-liveslots/test/gc-helpers.js @@ -1,7 +1,7 @@ // eslint-disable-next-line import/order -import { Far } from '@endo/marshal'; -import { M } from '@agoric/store'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { kslot, kser } from '@agoric/kmarshal'; import { parseVatSlot } from '../src/parseVatSlots.js'; diff --git a/packages/swingset-liveslots/test/test-baggage.js b/packages/swingset-liveslots/test/test-baggage.js index 997555611fe..01d1db7b887 100644 --- a/packages/swingset-liveslots/test/test-baggage.js +++ b/packages/swingset-liveslots/test/test-baggage.js @@ -1,6 +1,7 @@ import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { kunser } from '@agoric/kmarshal'; import { setupTestLiveslots } from './liveslots-helpers.js'; import { vstr } from './util.js'; diff --git a/packages/swingset-liveslots/test/test-collection-schema-refcount.js b/packages/swingset-liveslots/test/test-collection-schema-refcount.js index 6bf40adc3f7..e9e9112e736 100644 --- a/packages/swingset-liveslots/test/test-collection-schema-refcount.js +++ b/packages/swingset-liveslots/test/test-collection-schema-refcount.js @@ -1,6 +1,7 @@ import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { kser } from '@agoric/kmarshal'; import { makeLiveSlots } from '../src/liveslots.js'; import { parseVatSlot } from '../src/parseVatSlots.js'; diff --git a/packages/swingset-liveslots/test/test-collection-upgrade.js b/packages/swingset-liveslots/test/test-collection-upgrade.js index 45afca41a2b..016fc08becd 100644 --- a/packages/swingset-liveslots/test/test-collection-upgrade.js +++ b/packages/swingset-liveslots/test/test-collection-upgrade.js @@ -1,8 +1,8 @@ import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { kser } from '@agoric/kmarshal'; -import { M } from '@agoric/store'; import { makeLiveSlots } from '../src/liveslots.js'; import { parseVatSlot } from '../src/parseVatSlots.js'; import { buildSyscall } from './liveslots-helpers.js'; diff --git a/packages/swingset-liveslots/test/test-dropped-collection-weakrefs.js b/packages/swingset-liveslots/test/test-dropped-collection-weakrefs.js index eb7add831ae..be81ac07024 100644 --- a/packages/swingset-liveslots/test/test-dropped-collection-weakrefs.js +++ b/packages/swingset-liveslots/test/test-dropped-collection-weakrefs.js @@ -1,5 +1,6 @@ import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { kser } from '@agoric/kmarshal'; import { makeLiveSlots } from '../src/liveslots.js'; import { buildSyscall } from './liveslots-helpers.js'; diff --git a/packages/swingset-liveslots/test/test-durabilityChecks.js b/packages/swingset-liveslots/test/test-durabilityChecks.js index 5e373c482b3..9d45ac540ac 100644 --- a/packages/swingset-liveslots/test/test-durabilityChecks.js +++ b/packages/swingset-liveslots/test/test-durabilityChecks.js @@ -1,6 +1,7 @@ import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { makeFakeVirtualStuff } from '../tools/fakeVirtualSupport.js'; async function runDurabilityCheckTest(t, relaxDurabilityRules) { diff --git a/packages/swingset-liveslots/test/test-gc-sensitivity.js b/packages/swingset-liveslots/test/test-gc-sensitivity.js index d36474e1057..20d77a7bb25 100644 --- a/packages/swingset-liveslots/test/test-gc-sensitivity.js +++ b/packages/swingset-liveslots/test/test-gc-sensitivity.js @@ -1,6 +1,7 @@ // @ts-nocheck import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { kser } from '@agoric/kmarshal'; import { buildSyscall } from './liveslots-helpers.js'; import { makeLiveSlots } from '../src/liveslots.js'; diff --git a/packages/swingset-liveslots/test/test-handled-promises.js b/packages/swingset-liveslots/test/test-handled-promises.js index 052a9633c80..872d5cd9cbe 100644 --- a/packages/swingset-liveslots/test/test-handled-promises.js +++ b/packages/swingset-liveslots/test/test-handled-promises.js @@ -1,8 +1,9 @@ import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { Fail } from '@agoric/assert'; -import { M, provideLazy as provide } from '@agoric/store'; +import { provideLazy as provide } from '@agoric/store'; import { makePromiseKit } from '@endo/promise-kit'; // Disabled to avoid circular dependencies. // import { makeStoreUtils } from '@agoric/vat-data/src/vat-data-bindings.js'; diff --git a/packages/swingset-liveslots/test/test-initial-vrefs.js b/packages/swingset-liveslots/test/test-initial-vrefs.js index 7c9a35c3ebf..81b2339199e 100644 --- a/packages/swingset-liveslots/test/test-initial-vrefs.js +++ b/packages/swingset-liveslots/test/test-initial-vrefs.js @@ -1,8 +1,8 @@ import test from 'ava'; -import { Far } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { kunser } from '@agoric/kmarshal'; -import { M } from '@agoric/store'; import { setupTestLiveslots } from './liveslots-helpers.js'; function buildRootObject(vatPowers, vatParameters, baggage) { diff --git a/packages/swingset-liveslots/test/test-liveslots-mock-gc.js b/packages/swingset-liveslots/test/test-liveslots-mock-gc.js index 8f7c7532165..83c1f41f810 100644 --- a/packages/swingset-liveslots/test/test-liveslots-mock-gc.js +++ b/packages/swingset-liveslots/test/test-liveslots-mock-gc.js @@ -1,7 +1,8 @@ // @ts-nocheck import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { kslot, kser } from '@agoric/kmarshal'; import { makeLiveSlots } from '../src/liveslots.js'; import { parseVatSlot } from '../src/parseVatSlots.js'; diff --git a/packages/swingset-liveslots/test/test-liveslots-real-gc.js b/packages/swingset-liveslots/test/test-liveslots-real-gc.js index 18860657da2..38b5b50a02d 100644 --- a/packages/swingset-liveslots/test/test-liveslots-real-gc.js +++ b/packages/swingset-liveslots/test/test-liveslots-real-gc.js @@ -2,7 +2,8 @@ /* global process */ import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { makePromiseKit } from '@endo/promise-kit'; import { kslot, kser } from '@agoric/kmarshal'; import engineGC from './engine-gc.js'; diff --git a/packages/swingset-liveslots/test/test-liveslots.js b/packages/swingset-liveslots/test/test-liveslots.js index 2d79b3ca22f..152eb3f6136 100644 --- a/packages/swingset-liveslots/test/test-liveslots.js +++ b/packages/swingset-liveslots/test/test-liveslots.js @@ -3,10 +3,11 @@ import test from 'ava'; import { E } from '@endo/eventual-send'; import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { makePromiseKit } from '@endo/promise-kit'; import { Fail } from '@agoric/assert'; import { kslot, kser, kunser } from '@agoric/kmarshal'; -import { M } from '@agoric/store'; import { makeLiveSlots, makeMarshaller } from '../src/liveslots.js'; import { buildSyscall, makeDispatch } from './liveslots-helpers.js'; import { makeMessage, makeStartVat, makeResolve, makeReject } from './util.js'; diff --git a/packages/swingset-liveslots/test/test-vpid-liveslots.js b/packages/swingset-liveslots/test/test-vpid-liveslots.js index cd85c5931ea..86b71d57412 100644 --- a/packages/swingset-liveslots/test/test-vpid-liveslots.js +++ b/packages/swingset-liveslots/test/test-vpid-liveslots.js @@ -3,7 +3,8 @@ import test from 'ava'; import { E } from '@endo/eventual-send'; import { makePromiseKit } from '@endo/promise-kit'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { Fail } from '@agoric/assert'; import { kser, kslot } from '@agoric/kmarshal'; import { buildSyscall, makeDispatch } from './liveslots-helpers.js'; diff --git a/packages/swingset-liveslots/test/virtual-objects/test-kind-changes.js b/packages/swingset-liveslots/test/virtual-objects/test-kind-changes.js index 423f903a372..1be00ed67f4 100644 --- a/packages/swingset-liveslots/test/virtual-objects/test-kind-changes.js +++ b/packages/swingset-liveslots/test/virtual-objects/test-kind-changes.js @@ -1,6 +1,7 @@ // @ts-nocheck import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { kser } from '@agoric/kmarshal'; import { makeFakeVirtualStuff } from '../../tools/fakeVirtualSupport.js'; import { makeLiveSlots } from '../../src/liveslots.js'; diff --git a/packages/swingset-liveslots/test/virtual-objects/test-state-shape.js b/packages/swingset-liveslots/test/virtual-objects/test-state-shape.js index 935ed3dbd40..ca6032f0e86 100644 --- a/packages/swingset-liveslots/test/virtual-objects/test-state-shape.js +++ b/packages/swingset-liveslots/test/virtual-objects/test-state-shape.js @@ -2,8 +2,9 @@ import test from 'ava'; import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { kser, kslot } from '@agoric/kmarshal'; -import { M } from '@agoric/store'; import { makeLiveSlots } from '../../src/liveslots.js'; import { buildSyscall } from '../liveslots-helpers.js'; import { makeStartVat, makeMessage } from '../util.js'; diff --git a/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectGC.js b/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectGC.js index 7c0c7448979..0d6da98eba9 100644 --- a/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectGC.js +++ b/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectGC.js @@ -1,7 +1,8 @@ // @ts-nocheck import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { krefOf, kser, kslot } from '@agoric/kmarshal'; import { setupTestLiveslots, diff --git a/packages/swingset-liveslots/test/virtual-objects/test-vo-real-gc.js b/packages/swingset-liveslots/test/virtual-objects/test-vo-real-gc.js index fb0a346144a..36f4344532b 100644 --- a/packages/swingset-liveslots/test/virtual-objects/test-vo-real-gc.js +++ b/packages/swingset-liveslots/test/virtual-objects/test-vo-real-gc.js @@ -1,7 +1,8 @@ // @ts-nocheck import test from 'ava'; -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { kser, kunser } from '@agoric/kmarshal'; import { setupTestLiveslots } from '../liveslots-helpers.js'; import { watchCollected } from '../gc-and-finalize.js'; diff --git a/packages/swingset-liveslots/tools/vo-test-harness.js b/packages/swingset-liveslots/tools/vo-test-harness.js index 3ee616d1270..8340c5d9f10 100644 --- a/packages/swingset-liveslots/tools/vo-test-harness.js +++ b/packages/swingset-liveslots/tools/vo-test-harness.js @@ -1,4 +1,5 @@ -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { setupTestLiveslots } from '../test/liveslots-helpers.js'; // This file contains a test harness for virtual objects. runVOTest() From 5ddd54b203355e12a962a8ca5bd34a4a93ec6e04 Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Thu, 7 Mar 2024 08:56:02 -0800 Subject: [PATCH 09/12] fixup! vat-data --- packages/vat-data/package.json | 2 ++ packages/vat-data/test/test-vow.js | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/vat-data/package.json b/packages/vat-data/package.json index 30740d20216..fa837f4a5bb 100644 --- a/packages/vat-data/package.json +++ b/packages/vat-data/package.json @@ -21,7 +21,9 @@ "dependencies": { "@agoric/assert": "^0.6.0", "@agoric/base-zone": "^0.1.0", + "@endo/exo": "^1.2.1", "@agoric/internal": "^0.3.2", + "@endo/patterns": "^1.2.0", "@agoric/store": "^0.9.2", "@agoric/swingset-liveslots": "^0.10.2", "@agoric/vow": "^0.1.0" diff --git a/packages/vat-data/test/test-vow.js b/packages/vat-data/test/test-vow.js index 316e4a115ec..56a7a88c87c 100644 --- a/packages/vat-data/test/test-vow.js +++ b/packages/vat-data/test/test-vow.js @@ -1,6 +1,8 @@ // @ts-check import test from 'ava'; -import { E, Far } from '@endo/far'; +import { E } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { V, makeVowKit } from '../vow.js'; From f31c98bb57529e40ac2ea0b8f393c512748f0a2d Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Thu, 7 Mar 2024 09:00:25 -0800 Subject: [PATCH 10/12] fixup! revert zone --- packages/zone/src/virtual.js | 50 +++++++++++++++--------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/packages/zone/src/virtual.js b/packages/zone/src/virtual.js index c8ca69f3674..95410799db0 100644 --- a/packages/zone/src/virtual.js +++ b/packages/zone/src/virtual.js @@ -47,18 +47,14 @@ const makeVirtualExo = ( }; /** @type {import('.').Stores} */ -const detachedVirtualStores = makeExo( - 'virtualStores', - M.interface('virtualStores', {}, { defaultGuards: 'passable' }), - { - detached: () => detachedVirtualStores, - isStorable: isPassable, - mapStore: makeScalarBigMapStore, - setStore: makeScalarBigSetStore, - weakMapStore: makeScalarBigWeakMapStore, - weakSetStore: makeScalarBigWeakSetStore, - }, -); +const detachedVirtualStores = Far('virtualStores', { + detached: () => detachedVirtualStores, + isStorable: isPassable, + mapStore: makeScalarBigMapStore, + setStore: makeScalarBigSetStore, + weakMapStore: makeScalarBigWeakMapStore, + weakSetStore: makeScalarBigWeakSetStore, +}); /** * A zone that utilizes external storage to reduce the memory footprint of the @@ -80,23 +76,19 @@ export const makeVirtualZone = (baseLabel = 'virtualZone') => { const makeSubZone = (label, _options) => makeVirtualZone(`${baseLabel}.${label}`); - return makeExo( - 'virtualZone', - M.interface('virtualZone', {}, { defaultGuards: 'passable' }), - { - exo: wrapProvider(makeVirtualExo, keys.exo), - exoClass: wrapProvider(defineVirtualExoClass, keys.exoClass), - exoClassKit: wrapProvider(defineVirtualExoClassKit, keys.exoClassKit), - subZone: wrapProvider(makeSubZone), + return Far('virtualZone', { + exo: wrapProvider(makeVirtualExo, keys.exo), + exoClass: wrapProvider(defineVirtualExoClass, keys.exoClass), + exoClassKit: wrapProvider(defineVirtualExoClassKit, keys.exoClassKit), + subZone: wrapProvider(makeSubZone), - makeOnce, - detached: detachedVirtualStores.detached, - isStorable: detachedVirtualStores.isStorable, + makeOnce, + detached: detachedVirtualStores.detached, + isStorable: detachedVirtualStores.isStorable, - mapStore: wrapProvider(detachedVirtualStores.mapStore), - setStore: wrapProvider(detachedVirtualStores.setStore), - weakMapStore: wrapProvider(detachedVirtualStores.weakMapStore), - weakSetStore: wrapProvider(detachedVirtualStores.weakSetStore), - }, - ); + mapStore: wrapProvider(detachedVirtualStores.mapStore), + setStore: wrapProvider(detachedVirtualStores.setStore), + weakMapStore: wrapProvider(detachedVirtualStores.weakMapStore), + weakSetStore: wrapProvider(detachedVirtualStores.weakSetStore), + }); }; From dbfc121f96467524fb3a5b7f0c09ceb2a209a49d Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Thu, 7 Mar 2024 09:01:06 -0800 Subject: [PATCH 11/12] fixup! revert zone --- packages/zone/src/durable.js | 56 ++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/packages/zone/src/durable.js b/packages/zone/src/durable.js index 70bcf49b902..22cfe4b733a 100644 --- a/packages/zone/src/durable.js +++ b/packages/zone/src/durable.js @@ -52,19 +52,15 @@ const attachDurableStores = getBaggage => { provideDurableWeakMapStore(getBaggage(), label, options); /** @type {import('.').Stores} */ - return makeExo( - 'durableStores', - M.interface('durableStores', {}, { defaultGuards: 'passable' }), - { - // eslint-disable-next-line no-use-before-define - detached: () => detachedDurableStores, - isStorable, - mapStore, - setStore, - weakMapStore, - weakSetStore, - }, - ); + return Far('durableStores', { + // eslint-disable-next-line no-use-before-define + detached: () => detachedDurableStores, + isStorable, + mapStore, + setStore, + weakMapStore, + weakSetStore, + }); }; /** @type {import('.').Stores} */ @@ -105,24 +101,20 @@ export const makeDurableZone = (baggage, baseLabel = 'durableZone') => { return makeDurableZone(subBaggage, `${baseLabel}.${label}`); }; - return makeExo( - 'durableZone', - M.interface('durableZone', {}, { defaultGuards: 'passable' }), - { - exo: wrapProvider(exo, keys.exo), - exoClass: wrapProvider(exoClass, keys.exoClass), - exoClassKit: wrapProvider(exoClassKit, keys.exoClassKit), - subZone, - - makeOnce, - detached: attachedStores.detached, - isStorable: attachedStores.isStorable, - - mapStore: wrapProvider(attachedStores.mapStore, keys.store), - setStore: wrapProvider(attachedStores.setStore, keys.store), - weakMapStore: wrapProvider(attachedStores.weakMapStore, keys.store), - weakSetStore: wrapProvider(attachedStores.weakSetStore, keys.store), - }, - ); + return Far('durableZone', { + exo: wrapProvider(exo, keys.exo), + exoClass: wrapProvider(exoClass, keys.exoClass), + exoClassKit: wrapProvider(exoClassKit, keys.exoClassKit), + subZone, + + makeOnce, + detached: attachedStores.detached, + isStorable: attachedStores.isStorable, + + mapStore: wrapProvider(attachedStores.mapStore, keys.store), + setStore: wrapProvider(attachedStores.setStore, keys.store), + weakMapStore: wrapProvider(attachedStores.weakMapStore, keys.store), + weakSetStore: wrapProvider(attachedStores.weakSetStore, keys.store), + }); }; harden(makeDurableZone); From 0905188b4ab54337a2d0f2061834a75c77d3f233 Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Thu, 7 Mar 2024 09:11:03 -0800 Subject: [PATCH 12/12] fixup! progress on notifier but still broken --- packages/notifier/package.json | 1 + packages/notifier/src/notifier.js | 4 +++- packages/notifier/src/publish-kit.js | 3 ++- packages/notifier/src/stored-notifier.js | 4 +++- packages/notifier/src/storesub.js | 4 +++- packages/notifier/src/subscribe.js | 4 +++- packages/notifier/src/subscriber.js | 4 +++- packages/notifier/src/topic.js | 3 ++- packages/notifier/test/vat-integration/vat-pubsub.js | 3 ++- packages/notifier/tools/testSupports.js | 4 +++- 10 files changed, 25 insertions(+), 9 deletions(-) diff --git a/packages/notifier/package.json b/packages/notifier/package.json index 645573fbdf4..54f395696be 100644 --- a/packages/notifier/package.json +++ b/packages/notifier/package.json @@ -36,6 +36,7 @@ "@agoric/assert": "^0.6.0", "@agoric/internal": "^0.3.2", "@agoric/vat-data": "^0.5.2", + "@endo/exo": "^1.2.1", "@endo/far": "^1.0.4", "@endo/marshal": "^1.3.0", "@endo/patterns": "^1.2.0", diff --git a/packages/notifier/src/notifier.js b/packages/notifier/src/notifier.js index 512ac602d61..f0ad7e16d48 100644 --- a/packages/notifier/src/notifier.js +++ b/packages/notifier/src/notifier.js @@ -1,7 +1,9 @@ /// import { assert } from '@agoric/assert'; -import { E, Far } from '@endo/far'; +import { E } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import './types-ambient.js'; import { makePublishKit } from './publish-kit.js'; diff --git a/packages/notifier/src/publish-kit.js b/packages/notifier/src/publish-kit.js index 52c46892bb0..59d467263ce 100644 --- a/packages/notifier/src/publish-kit.js +++ b/packages/notifier/src/publish-kit.js @@ -1,7 +1,8 @@ /// import { canBeDurable, prepareExoClassKit } from '@agoric/vat-data'; -import { E, Far } from '@endo/far'; +import { E } from '@endo/far'; +import { makeExo } from '@endo/exo'; import { M, getInterfaceGuardPayload } from '@endo/patterns'; import { makePromiseKit } from '@endo/promise-kit'; diff --git a/packages/notifier/src/stored-notifier.js b/packages/notifier/src/stored-notifier.js index 82e770977ed..3212c1e81d3 100644 --- a/packages/notifier/src/stored-notifier.js +++ b/packages/notifier/src/stored-notifier.js @@ -2,7 +2,9 @@ import { assertAllDefined } from '@agoric/internal'; import { makeSerializeToStorage } from '@agoric/internal/src/lib-chainStorage.js'; -import { E, Far } from '@endo/far'; +import { E } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { observeNotifier } from './asyncIterableAdaptor.js'; /** diff --git a/packages/notifier/src/storesub.js b/packages/notifier/src/storesub.js index 6238e2e4d26..baf7fc1579b 100644 --- a/packages/notifier/src/storesub.js +++ b/packages/notifier/src/storesub.js @@ -1,4 +1,6 @@ -import { E, Far } from '@endo/far'; +import { E } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { makeMarshal } from '@endo/marshal'; import { assertAllDefined } from '@agoric/internal'; import { makeSerializeToStorage } from '@agoric/internal/src/lib-chainStorage.js'; diff --git a/packages/notifier/src/subscribe.js b/packages/notifier/src/subscribe.js index 0bb0992a755..814cd73f442 100644 --- a/packages/notifier/src/subscribe.js +++ b/packages/notifier/src/subscribe.js @@ -1,4 +1,6 @@ -import { E, Far } from '@endo/far'; +import { E } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { isObject } from '@endo/marshal'; import { isUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js'; diff --git a/packages/notifier/src/subscriber.js b/packages/notifier/src/subscriber.js index 63081416a9a..7fa5c7ee18a 100644 --- a/packages/notifier/src/subscriber.js +++ b/packages/notifier/src/subscriber.js @@ -2,7 +2,9 @@ /// -import { E, Far } from '@endo/far'; +import { E } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { subscribeEach } from './subscribe.js'; import { makePublishKit } from './publish-kit.js'; diff --git a/packages/notifier/src/topic.js b/packages/notifier/src/topic.js index ff76bf233fa..96eecb1c9ca 100644 --- a/packages/notifier/src/topic.js +++ b/packages/notifier/src/topic.js @@ -1,6 +1,7 @@ // @jessie-check -import { Far } from '@endo/far'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import './types-ambient.js'; /** diff --git a/packages/notifier/test/vat-integration/vat-pubsub.js b/packages/notifier/test/vat-integration/vat-pubsub.js index 6cb1b62f934..1713f01f277 100644 --- a/packages/notifier/test/vat-integration/vat-pubsub.js +++ b/packages/notifier/test/vat-integration/vat-pubsub.js @@ -1,4 +1,5 @@ -import { Far } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import { provide } from '@agoric/vat-data'; import { prepareDurablePublishKit, diff --git a/packages/notifier/tools/testSupports.js b/packages/notifier/tools/testSupports.js index 994a4211a7b..3cd49490143 100644 --- a/packages/notifier/tools/testSupports.js +++ b/packages/notifier/tools/testSupports.js @@ -1,5 +1,7 @@ // eslint-disable-next-line import/order -import { Far, makeMarshal } from '@endo/marshal'; +import { makeMarshal } from '@endo/marshal'; +import { makeExo } from '@endo/exo'; +import { M } from '@endo/patterns'; import '../src/types-ambient.js';