From 4f20bbf7f8de3755a6e72b03e46f4613971b3abd Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 1 Jul 2022 15:03:12 -0700 Subject: [PATCH 1/5] refactor(chainStorage): getChildNode helper --- .../src/proposals/econ-behaviors.js | 41 ++++++++----------- .../run-protocol/src/proposals/startPSM.js | 7 ++-- packages/vats/src/core/basic-behaviors.js | 5 +-- packages/vats/src/lib-chainStorage.js | 15 ++++++- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/packages/run-protocol/src/proposals/econ-behaviors.js b/packages/run-protocol/src/proposals/econ-behaviors.js index 8e787aacee9..363f0febe3c 100644 --- a/packages/run-protocol/src/proposals/econ-behaviors.js +++ b/packages/run-protocol/src/proposals/econ-behaviors.js @@ -1,24 +1,23 @@ // @ts-check -import { E, Far } from '@endo/far'; -import { makeRatio } from '@agoric/zoe/src/contractSupport/index.js'; -import { CENTRAL_ISSUER_NAME } from '@agoric/vats/src/core/utils.js'; +import '../../exported.js'; + +import { AmountMath } from '@agoric/ertp'; import '@agoric/governance/exported.js'; import '@agoric/vats/exported.js'; import '@agoric/vats/src/core/types.js'; - -import { AmountMath } from '@agoric/ertp'; -import { makeGovernedTerms } from '../vaultFactory/params.js'; -import { makeAmmTerms } from '../vpool-xyk-amm/params.js'; -import { makeReserveTerms } from '../reserve/params.js'; - -import '../../exported.js'; - +import { CENTRAL_ISSUER_NAME } from '@agoric/vats/src/core/utils.js'; +import { getChildNode } from '@agoric/vats/src/lib-chainStorage.js'; +import { makeRatio } from '@agoric/zoe/src/contractSupport/index.js'; +import { E, Far } from '@endo/far'; import * as Collect from '../collect.js'; +import { makeTracer } from '../makeTracer.js'; +import { makeStakeReporter } from '../my-lien.js'; +import { makeReserveTerms } from '../reserve/params.js'; import { makeRunStakeTerms } from '../runStake/params.js'; import { liquidationDetailTerms } from '../vaultFactory/liquidation.js'; -import { makeStakeReporter } from '../my-lien.js'; -import { makeTracer } from '../makeTracer.js'; +import { makeGovernedTerms } from '../vaultFactory/params.js'; +import { makeAmmTerms } from '../vpool-xyk-amm/params.js'; const trace = makeTracer('RunEconBehaviors', false); @@ -216,9 +215,7 @@ export const setupAmm = async ( AmountMath.make(runBrand, minInitialPoolLiquidity), ); - const chainStoragePresence = await chainStorage; - const storageNode = await (chainStoragePresence && - E(chainStoragePresence).getChildNode(AMM_STORAGE_PATH)); + const storageNode = await getChildNode(chainStorage, AMM_STORAGE_PATH); const marshaller = await E(board).getPublishingMarshaller(); const ammGovernorTerms = { @@ -312,9 +309,7 @@ export const setupReserve = async ({ const feeMintAccess = await feeMintAccessP; - const chainStoragePresence = await chainStorage; - const storageNode = await (chainStoragePresence && - E(chainStoragePresence).getChildNode(STORAGE_PATH)); + const storageNode = await getChildNode(chainStorage, STORAGE_PATH); const marshaller = E(board).getReadonlyMarshaller(); const reserveGovernorTerms = { @@ -444,9 +439,7 @@ export const startVaultFactory = async ( const reservePublicFacet = await E(zoe).getPublicFacet(reserveInstance); const timer = await chainTimerService; - const chainStoragePresence = await chainStorage; - const storageNode = await (chainStoragePresence && - E(chainStoragePresence).getChildNode(STORAGE_PATH)); + const storageNode = await getChildNode(chainStorage, STORAGE_PATH); const marshaller = E(board).getReadonlyMarshaller(); const vaultFactoryTerms = makeGovernedTerms( @@ -851,9 +844,7 @@ export const startRunStake = async ( }, ); - const chainStoragePresence = await chainStorage; - const storageNode = await (chainStoragePresence && - E(chainStoragePresence).getChildNode(STORAGE_PATH)); + const storageNode = await getChildNode(chainStorage, STORAGE_PATH); const marshaller = await E(board).getReadonlyMarshaller(); /** @type {{ publicFacet: GovernorPublic, creatorFacet: GovernedContractFacetAccess}} */ diff --git a/packages/run-protocol/src/proposals/startPSM.js b/packages/run-protocol/src/proposals/startPSM.js index b5e6ee73c4e..1e831904f1e 100644 --- a/packages/run-protocol/src/proposals/startPSM.js +++ b/packages/run-protocol/src/proposals/startPSM.js @@ -1,8 +1,9 @@ // @ts-check -import { E } from '@endo/far'; import { AmountMath, AssetKind } from '@agoric/ertp'; import { CONTRACT_ELECTORATE, ParamTypes } from '@agoric/governance'; +import { getChildNode } from '@agoric/vats/src/lib-chainStorage.js'; import { makeRatio } from '@agoric/zoe/src/contractSupport/index.js'; +import { E } from '@endo/far'; import { reserveThenGetNamePaths } from './utils.js'; const BASIS_POINTS = 10000n; @@ -107,9 +108,7 @@ export const startPSM = async ( }, }; - const chainStoragePresence = await chainStorage; - const storageNode = await (chainStoragePresence && - E(chainStoragePresence).getChildNode('psm')); + const storageNode = await getChildNode(chainStorage, 'psm'); const marshaller = E(board).getPublishingMarshaller(); const governorFacets = await E(zoe).startInstance( diff --git a/packages/vats/src/core/basic-behaviors.js b/packages/vats/src/core/basic-behaviors.js index 889751b10f7..2473334ed84 100644 --- a/packages/vats/src/core/basic-behaviors.js +++ b/packages/vats/src/core/basic-behaviors.js @@ -1,12 +1,11 @@ // @ts-check -import { E, Far } from '@endo/far'; import { AssetKind, makeIssuerKit } from '@agoric/ertp'; - import { Nat } from '@agoric/nat'; import { makeScalarMapStore } from '@agoric/store'; import { provide } from '@agoric/store/src/stores/store-utils.js'; +import { E, Far } from '@endo/far'; +import { getChildNode } from '../lib-chainStorage.js'; import { makeNameHubKit } from '../nameHub.js'; - import { feeIssuerConfig } from './utils.js'; const { details: X } = assert; diff --git a/packages/vats/src/lib-chainStorage.js b/packages/vats/src/lib-chainStorage.js index 56ee2f32979..44b606d10e2 100644 --- a/packages/vats/src/lib-chainStorage.js +++ b/packages/vats/src/lib-chainStorage.js @@ -1,6 +1,6 @@ // @ts-check -import { Far } from '@endo/far'; +import { E, Far } from '@endo/far'; const { details: X } = assert; @@ -59,3 +59,16 @@ export function makeChainStorageRoot(toStorage, storeName, rootPath) { const rootNode = makeChainStorageNode(rootPath); return rootNode; } + +/** + * + * @param {ERef} chainStorage + * @param {string} childName + */ +export async function getChildNode(chainStorage, childName) { + const chainStoragePresence = await chainStorage; + const storageNode = await (chainStoragePresence && + E(chainStoragePresence).getChildNode(childName)); + return storageNode; +} +harden(getChildNode); From 0184a89403a3719f21dc61de37865512cdc819ae Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 30 Jun 2022 13:57:33 -0700 Subject: [PATCH 2/5] feat: contract for single on-chain wallet --- .github/workflows/test-all-packages.yml | 2 + package.json | 1 + packages/agoric-cli/src/sdk-package-names.js | 1 + packages/casting/src/follower-cosmjs.js | 4 + packages/vats/decentral-core-config.json | 6 +- packages/vats/decentral-demo-config.json | 6 +- packages/vats/scripts/build-bundles.js | 4 + packages/vats/src/core/basic-behaviors.js | 37 +++- packages/vats/src/core/manifest.js | 8 + packages/vats/src/core/types.js | 3 +- packages/vats/src/core/utils.js | 1 + packages/vats/src/vat-walletManager.js | 5 +- packages/vats/test/devices.js | 15 +- packages/vats/test/test-clientBundle.js | 32 ++- packages/wallet/contract/README.md | 31 +++ packages/wallet/contract/jsconfig.json | 25 +++ packages/wallet/contract/package.json | 49 +++++ packages/wallet/contract/src/singleWallet.js | 90 ++++++++ packages/wallet/contract/test/devices.js | 22 ++ .../wallet/contract/test/test-singleWallet.js | 198 ++++++++++++++++++ 20 files changed, 518 insertions(+), 22 deletions(-) create mode 100644 packages/wallet/contract/README.md create mode 100644 packages/wallet/contract/jsconfig.json create mode 100644 packages/wallet/contract/package.json create mode 100644 packages/wallet/contract/src/singleWallet.js create mode 100644 packages/wallet/contract/test/devices.js create mode 100644 packages/wallet/contract/test/test-singleWallet.js diff --git a/.github/workflows/test-all-packages.yml b/.github/workflows/test-all-packages.yml index c09879dfea0..f8441bde93a 100644 --- a/.github/workflows/test-all-packages.yml +++ b/.github/workflows/test-all-packages.yml @@ -93,6 +93,8 @@ jobs: run: cd packages/assert && yarn ${{ steps.vars.outputs.test }} - name: yarn test (wallet/api) run: cd packages/wallet/api && yarn ${{ steps.vars.outputs.test }} + - name: yarn test (wallet/contract) + run: cd packages/wallet/contract && yarn ${{ steps.vars.outputs.test }} - name: yarn test (deployment) run: cd packages/deployment && yarn ${{ steps.vars.outputs.test }} - name: yarn test (ERTP) diff --git a/package.json b/package.json index e6b7bb186ab..09f80c7fb50 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "golang/cosmos", "packages/*", "packages/wallet/api", + "packages/wallet/contract", "packages/wallet/ui" ], "type": "module", diff --git a/packages/agoric-cli/src/sdk-package-names.js b/packages/agoric-cli/src/sdk-package-names.js index e4aaac41118..b271bf1c0a6 100644 --- a/packages/agoric-cli/src/sdk-package-names.js +++ b/packages/agoric-cli/src/sdk-package-names.js @@ -19,6 +19,7 @@ export default [ "@agoric/run-protocol", "@agoric/same-structure", "@agoric/sharing-service", + "@agoric/smart-wallet", "@agoric/solo", "@agoric/sparse-ints", "@agoric/spawner", diff --git a/packages/casting/src/follower-cosmjs.js b/packages/casting/src/follower-cosmjs.js index 6bca5494eaa..0a95a278f6e 100644 --- a/packages/casting/src/follower-cosmjs.js +++ b/packages/casting/src/follower-cosmjs.js @@ -317,6 +317,10 @@ export const makeCosmjsFollower = ( const getProvenValue = () => getProvenValueAtHeight(allegedBlockHeight); const buf = await queryVerifier(getProvenValue, crash, getAllegedValue); + if (buf.length === 0) { + fail(Error('No query results')); + return; + } attempt = 0; if (!committer.isValid()) { return; diff --git a/packages/vats/decentral-core-config.json b/packages/vats/decentral-core-config.json index 963112eff01..679270179d2 100644 --- a/packages/vats/decentral-core-config.json +++ b/packages/vats/decentral-core-config.json @@ -42,12 +42,12 @@ "sharing": { "sourceSpec": "@agoric/vats/src/vat-sharing.js" }, - "walletManager": { - "sourceSpec": "@agoric/vats/src/vat-walletManager.js" + "singleWallet": { + "sourceSpec": "@agoric/wallet/contract/src/singleWallet.js" }, "zoe": { "sourceSpec": "@agoric/vats/src/vat-zoe.js" } }, "defaultManagerType": "xs-worker" -} +} \ No newline at end of file diff --git a/packages/vats/decentral-demo-config.json b/packages/vats/decentral-demo-config.json index 7494dcaffca..11464698846 100644 --- a/packages/vats/decentral-demo-config.json +++ b/packages/vats/decentral-demo-config.json @@ -49,12 +49,12 @@ "sharing": { "sourceSpec": "@agoric/vats/src/vat-sharing.js" }, - "walletManager": { - "sourceSpec": "@agoric/vats/src/vat-walletManager.js" + "singleWallet": { + "sourceSpec": "@agoric/wallet/contract/src/singleWallet.js" }, "zoe": { "sourceSpec": "@agoric/vats/src/vat-zoe.js" } }, "defaultManagerType": "xs-worker" -} +} \ No newline at end of file diff --git a/packages/vats/scripts/build-bundles.js b/packages/vats/scripts/build-bundles.js index 5c9f1d982fa..07150873389 100755 --- a/packages/vats/scripts/build-bundles.js +++ b/packages/vats/scripts/build-bundles.js @@ -8,6 +8,10 @@ const dirname = url.fileURLToPath(new URL('.', import.meta.url)); const sourceToBundle = [ [`../src/centralSupply.js`, `../bundles/bundle-centralSupply.js`], [`../src/mintHolder.js`, `../bundles/bundle-mintHolder.js`], + [ + `@agoric/wallet/contract/src/singleWallet.js`, + `../bundles/bundle-singleWallet.js`, + ], ]; createBundles(sourceToBundle, dirname); diff --git a/packages/vats/src/core/basic-behaviors.js b/packages/vats/src/core/basic-behaviors.js index 2473334ed84..fd351f18a9c 100644 --- a/packages/vats/src/core/basic-behaviors.js +++ b/packages/vats/src/core/basic-behaviors.js @@ -224,9 +224,39 @@ export const makeAddressNameHubs = async ({ harden(makeAddressNameHubs); /** @param {BootstrapSpace} powers */ -export const makeClientBanks = async ({ consume: { client, bankManager } }) => { +export const makeClientBanks = async ({ + consume: { + agoricNames, + board, + namesByAddress, + namesByAddressAdmin, + client, + chainStorage, + bankManager, + zoe, + }, + installation: { + consume: { singleWallet }, + }, +}) => { + const STORAGE_PATH = 'wallet'; + + const storageNode = await getChildNode(chainStorage, STORAGE_PATH); + const marshaller = E(board).getPublishingMarshaller(); return E(client).assignBundle([ - address => ({ bank: E(bankManager).getBankForAddress(address) }), + address => { + const bank = E(bankManager).getBankForAddress(address); + const myAddressNameAdmin = E(namesByAddressAdmin).lookupAdmin(address); + const smartWallet = E(zoe).startInstance( + singleWallet, + {}, + { agoricNames, bank, namesByAddress, myAddressNameAdmin, board }, + { storageNode, marshaller }, + ); + + // sets these values in REPL home by way of registerWallet + return { bank, smartWallet }; + }, ]); }; harden(makeClientBanks); @@ -237,12 +267,13 @@ export const installBootContracts = async ({ devices: { vatAdmin }, consume: { zoe }, installation: { - produce: { centralSupply, mintHolder }, + produce: { centralSupply, mintHolder, singleWallet }, }, }) => { for (const [name, producer] of Object.entries({ centralSupply, mintHolder, + singleWallet, })) { const bundleCap = D(vatAdmin).getNamedBundleCap(name); const bundle = D(bundleCap).getBundle(); diff --git a/packages/vats/src/core/manifest.js b/packages/vats/src/core/manifest.js index ef4cc9717a7..bb2ded15e19 100644 --- a/packages/vats/src/core/manifest.js +++ b/packages/vats/src/core/manifest.js @@ -104,9 +104,16 @@ const SHARED_CHAIN_BOOTSTRAP_MANIFEST = harden({ }, makeClientBanks: { consume: { + agoricNames: true, + namesByAddress: true, + namesByAddressAdmin: true, bankManager: 'bank', + board: 'board', client: true, + chainStorage: true, + zoe: 'zoe', }, + installation: { consume: { singleWallet: 'zoe' } }, home: { produce: { bank: 'bank' } }, }, installBootContracts: { @@ -117,6 +124,7 @@ const SHARED_CHAIN_BOOTSTRAP_MANIFEST = harden({ produce: { centralSupply: 'zoe', mintHolder: 'zoe', + singleWallet: 'zoe', }, }, }, diff --git a/packages/vats/src/core/types.js b/packages/vats/src/core/types.js index 16a02cdb3d2..c56045291e6 100644 --- a/packages/vats/src/core/types.js +++ b/packages/vats/src/core/types.js @@ -136,7 +136,8 @@ * issuer: | * 'RUN' | 'BLD' | 'Attestation' | 'AUSD', * installation: | - * 'centralSupply' | 'mintHolder' | 'feeDistributor' | + * 'centralSupply' | 'mintHolder' | 'singleWallet' | + * 'feeDistributor' | * 'contractGovernor' | 'committee' | 'noActionElectorate' | 'binaryVoteCounter' | * 'amm' | 'VaultFactory' | 'liquidate' | 'runStake' | * 'Pegasus' | 'reserve' | 'psm' | 'interchainPool', diff --git a/packages/vats/src/core/utils.js b/packages/vats/src/core/utils.js index c3faa0c964d..cd4285b8ae7 100644 --- a/packages/vats/src/core/utils.js +++ b/packages/vats/src/core/utils.js @@ -35,6 +35,7 @@ export const agoricNamesReserved = harden({ installation: { centralSupply: 'central supply', mintHolder: 'mint holder', + singleWallet: 'single smart wallet', contractGovernor: 'contract governor', committee: 'committee electorate', noActionElectorate: 'no action electorate', diff --git a/packages/vats/src/vat-walletManager.js b/packages/vats/src/vat-walletManager.js index e5645a9f707..1d80496b8cb 100644 --- a/packages/vats/src/vat-walletManager.js +++ b/packages/vats/src/vat-walletManager.js @@ -1,7 +1,10 @@ import { E, Far } from '@endo/far'; import walletBundle from '@agoric/wallet-backend/bundles/bundle-wallet.js'; -export const buildRootObject = _vatPowers => { +/** + * @deprecated + */ +export const buildRootObject = () => { return Far('walletManager root', { buildWalletManager: vatAdminSvc => Far('walletManager', { diff --git a/packages/vats/test/devices.js b/packages/vats/test/devices.js index 347cc402920..dcaf0c07401 100644 --- a/packages/vats/test/devices.js +++ b/packages/vats/test/devices.js @@ -1,16 +1,21 @@ import bundleCentralSupply from '../bundles/bundle-centralSupply.js'; import bundleMintHolder from '../bundles/bundle-mintHolder.js'; +import bundleSingleWallet from '../bundles/bundle-singleWallet.js'; export const devices = { vatAdmin: { getNamedBundleCap: name => ({ getBundle: () => { - if (name === 'centralSupply') { - return bundleCentralSupply; - } else if (name === 'mintHolder') { - return bundleMintHolder; + switch (name) { + case 'centralSupply': + return bundleCentralSupply; + case 'mintHolder': + return bundleMintHolder; + case 'singleWallet': + return bundleSingleWallet; + default: + throw new Error(`unknown bundle ${name}`); } - throw new Error(`unknown bundle ${name}`); }, }), }, diff --git a/packages/vats/test/test-clientBundle.js b/packages/vats/test/test-clientBundle.js index 58480555acf..831baf375cf 100644 --- a/packages/vats/test/test-clientBundle.js +++ b/packages/vats/test/test-clientBundle.js @@ -14,9 +14,12 @@ import { } from '@agoric/run-protocol/src/proposals/demoIssuers.js'; import { makeClientManager } from '../src/core/chain-behaviors.js'; import { makeAgoricNamesAccess, makePromiseSpace } from '../src/core/utils.js'; -import { buildRootObject as bldMintRoot } from '../src/vat-mints.js'; +import { buildRootObject as mintsRoot } from '../src/vat-mints.js'; +import { buildRootObject as boardRoot } from '../src/vat-board.js'; import { installBootContracts, + makeAddressNameHubs, + makeBoard, makeClientBanks, } from '../src/core/basic-behaviors.js'; @@ -37,12 +40,16 @@ const setUpZoeForTest = async () => { }; harden(setUpZoeForTest); +/** + * @typedef {{ + * (n: 'board'): import('../src/core/basic-behaviors.js').BoardVat + * (n: 'mint'): MintsVat + * }} LoadVat + */ test('connectFaucet produces payments', async t => { const space = /** @type {any} */ (makePromiseSpace(t.log)); const { consume, produce } = - /** @type { BootstrapPowers & { consume: { loadVat: (n: 'mints') => MintsVat }} } */ ( - space - ); + /** @type { BootstrapPowers & { consume: { loadVat: LoadVat }} } */ (space); const { agoricNames, spaces } = makeAgoricNamesAccess(); produce.agoricNames.resolve(agoricNames); @@ -51,14 +58,22 @@ test('connectFaucet produces payments', async t => { produce.feeMintAccess.resolve(feeMintAccess); produce.loadVat.resolve(name => { - assert.equal(name, 'mints'); - return bldMintRoot(); + switch (name) { + case 'mints': + return mintsRoot(); + case 'board': + return boardRoot(); + default: + throw Error('unknown loadVat name'); + } }); t.plan(4); // be sure bank.deposit() gets called const bldKit = makeIssuerKit('BLD'); produce.bldIssuerKit.resolve(bldKit); + produce.chainStorage.resolve(undefined); + const runIssuer = E(zoe).getFeeIssuer(); produce.bankManager.resolve( Promise.resolve( @@ -76,6 +91,8 @@ test('connectFaucet produces payments', async t => { return amt; }, }), + // @ts-expect-error mock + getAssetSubscription: () => null, }), }), ), @@ -98,6 +115,9 @@ test('connectFaucet produces payments', async t => { }; await Promise.all([ + // @ts-expect-error missing keys: devices, vats, vatPowers, vatParameters, and 2 more. + makeBoard({ consume, produce, ...spaces }), + makeAddressNameHubs({ consume, produce, ...spaces }), installBootContracts({ vatPowers, devices, consume, produce, ...spaces }), makeClientManager({ consume, produce, ...spaces }), connectFaucet({ consume, produce, ...spaces }), diff --git a/packages/wallet/contract/README.md b/packages/wallet/contract/README.md new file mode 100644 index 00000000000..23ae74a292c --- /dev/null +++ b/packages/wallet/contract/README.md @@ -0,0 +1,31 @@ +# Smart Wallet contracts + +## Single contract + +The `singleWalet` contract manages a single smart wallet. + +# Multi-tenant contract + +The `walletFactory` contract provisions and manages smart wallets. + +# Common + +There can be zero or one wallets per Cosmos address. + +lib-wallet has makeWallet but that's really makeWalletKit + +1. Generate an address (off-chain) +2. Provision an account using that address, which causes a Bank to get created + ??? What happens if you try to provision again using the same address? It's a Cosmos level transaction; maybe that fails. +3. Create a Wallet using the Bank (it includes the implementation of Virtual Purses so when you getAmount it goes down to the Golang layer) + ??? What happens if you try to create another wallet using that bank? + +1 Address : 0/1 Bank +1 Address : 1 `myAddressNamesAdmin` +1 Bank : 0/1 Wallet + +By design there's a 1:1 across all four. + +`namesByAddress` and `board` are shared by everybody. + +`myAddressNamesAdmin` is from the account you provision. diff --git a/packages/wallet/contract/jsconfig.json b/packages/wallet/contract/jsconfig.json new file mode 100644 index 00000000000..0f3b5a4bfc9 --- /dev/null +++ b/packages/wallet/contract/jsconfig.json @@ -0,0 +1,25 @@ +// This file can contain .js-specific Typescript compiler config. +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + + "noEmit": true, +/* + // The following flags are for creating .d.ts files: + "noEmit": false, + "declaration": true, + "emitDeclarationOnly": true, +*/ + "downlevelIteration": true, + "strictNullChecks": true, + "moduleResolution": "node", + }, + "include": [ + "*.js", + "scripts/**/*.js", + "src/**/*.js", + "test/**/*.js", + "tools/**/*.js", + ], +} diff --git a/packages/wallet/contract/package.json b/packages/wallet/contract/package.json new file mode 100644 index 00000000000..a1bf4890503 --- /dev/null +++ b/packages/wallet/contract/package.json @@ -0,0 +1,49 @@ +{ + "name": "@agoric/smart-wallet", + "version": "0.1.1", + "description": "Wallet contract", + "type": "module", + "scripts": { + "build": "exit 0", + "test": "ava", + "test:xs": "exit 0", + "lint": "run-s --continue-on-error lint:*", + "lint-fix": "yarn lint:eslint --fix", + "lint:types": "tsc --maxNodeModuleJsDepth 5 -p jsconfig.json", + "lint:eslint": "eslint ." + }, + "devDependencies": { + "ava": "^3.12.1", + "@agoric/ertp": "^0.14.2", + "@agoric/run-protocol": "^0.11.0", + "@agoric/vats": "^0.10.0", + "@endo/captp": "^2.0.9" + }, + "dependencies": { + "@agoric/wallet-backend": "0.12.1", + "@agoric/deploy-script-support": "^0.9.0", + "@agoric/zoe": "^0.24.0", + "@agoric/notifier": "^0.4.0", + "@endo/far": "^0.2.5" + }, + "keywords": [], + "repository": { + "type": "git", + "url": "git+https://github.com/Agoric/agoric" + }, + "author": "Agoric", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/Agoric/agoric/issues" + }, + "homepage": "https://github.com/Agoric/agoric#readme", + "ava": { + "files": [ + "test/**/test-*.js" + ], + "timeout": "2m" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/wallet/contract/src/singleWallet.js b/packages/wallet/contract/src/singleWallet.js new file mode 100644 index 00000000000..bb63d13c188 --- /dev/null +++ b/packages/wallet/contract/src/singleWallet.js @@ -0,0 +1,90 @@ +// @ts-check +import { E, Far } from '@endo/far'; +import { + makeStoredSubscription, + makeSubscriptionKit, + observeIteration, +} from '@agoric/notifier'; +import '@agoric/deploy-script-support/exported.js'; +import '@agoric/zoe/exported.js'; +import spawn from '@agoric/wallet-backend/src/wallet.js'; + +import '@agoric/wallet-backend/src/types.js'; // TODO avoid ambient types + +const { assign, entries, keys, fromEntries } = Object; + +/** + * @typedef {{ + * agoricNames: NameHub, + * bank: import('@agoric/vats/src/vat-bank').Bank, + * board: Board, + * myAddressNameAdmin: MyAddressNameAdmin, + * namesByAddress: NameHub, + * }} SmartWalletContractTerms + */ + +/** + * @param {ZCF} zcf + * @param {{ + * storageNode?: ERef, + * marshaller?: ERef, + * }} privateArgs + */ +export const start = async (zcf, privateArgs) => { + const { agoricNames, bank, namesByAddress, myAddressNameAdmin, board } = + zcf.getTerms(); + assert(board, 'missing board'); + assert(myAddressNameAdmin, 'missing myAddressNameAdmin'); + assert(namesByAddress, 'missing namesByAddress'); + assert(agoricNames, 'missing agoricNames'); + const zoe = zcf.getZoeService(); + + const walletVat = spawn({ + agoricNames, + namesByAddress, + myAddressNameAdmin, + zoe, + board, + localTimerService: undefined, + }); + + const wallet = await E(walletVat).getWallet(bank); + const address = await E(myAddressNameAdmin).getMyAddress(); + const { storageNode, marshaller } = privateArgs; + + const myWalletStorageNode = + storageNode && E(storageNode).getChildNode(address); + const admin = E(wallet).getAdminFacet(); + + /** @type {Record>>} */ + const notifierParts = { + contacts: E(admin).getContactsNotifier(), + dapps: E(admin).getDappsNotifier(), + issuers: E(admin).getIssuersNotifier(), + offers: E(admin).getOffersNotifier(), + payments: E(admin).getPaymentsNotifier(), + purses: E(admin).getPursesNotifier(), + }; + const mutableState = fromEntries(keys(notifierParts).map(key => [key, []])); + const { subscription, publication } = makeSubscriptionKit(); + publication.updateState({ ...mutableState }); + + entries(notifierParts).forEach(([key, notifier]) => { + void observeIteration(notifier, { + updateState: value => + publication.updateState({ ...assign(mutableState, { [key]: value }) }), + }); + }); + + const storedSubscription = makeStoredSubscription( + subscription, + myWalletStorageNode, + marshaller, + ); + return { + creatorFacet: Far('SingleWallet', { + ...wallet, + getSubscription: () => storedSubscription, + }), + }; +}; diff --git a/packages/wallet/contract/test/devices.js b/packages/wallet/contract/test/devices.js new file mode 100644 index 00000000000..dde3c23906a --- /dev/null +++ b/packages/wallet/contract/test/devices.js @@ -0,0 +1,22 @@ +import bundleCentralSupply from '@agoric/vats/bundles/bundle-centralSupply.js'; +import bundleMintHolder from '@agoric/vats/bundles/bundle-mintHolder.js'; +import bundleSingleWallet from '@agoric/vats/bundles/bundle-singleWallet.js'; + +export const devices = { + vatAdmin: { + getNamedBundleCap: name => ({ + getBundle: () => { + switch (name) { + case 'centralSupply': + return bundleCentralSupply; + case 'mintHolder': + return bundleMintHolder; + case 'singleWallet': + return bundleSingleWallet; + default: + throw new Error(`unknown bundle ${name}`); + } + }, + }), + }, +}; diff --git a/packages/wallet/contract/test/test-singleWallet.js b/packages/wallet/contract/test/test-singleWallet.js new file mode 100644 index 00000000000..c72d268e803 --- /dev/null +++ b/packages/wallet/contract/test/test-singleWallet.js @@ -0,0 +1,198 @@ +// @ts-nocheck FIXME + +import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; + +import '@agoric/vats/src/core/types.js'; +import '@agoric/zoe/exported.js'; + +import { makeIssuerKit } from '@agoric/ertp'; +import { connectFaucet } from '@agoric/run-protocol/src/proposals/demoIssuers.js'; +import { unsafeMakeBundleCache } from '@agoric/run-protocol/test/bundleTool.js'; +import { subscriptionKey } from '@agoric/run-protocol/test/supports.js'; +import { + installBootContracts, + makeAddressNameHubs, + makeBoard, +} from '@agoric/vats/src/core/basic-behaviors.js'; +import { makeClientManager } from '@agoric/vats/src/core/chain-behaviors.js'; +import { + makeAgoricNamesAccess, + makePromiseSpace, +} from '@agoric/vats/src/core/utils.js'; +import { + getChildNode, + makeChainStorageRoot, +} from '@agoric/vats/src/lib-chainStorage.js'; +import { makeNameHubKit } from '@agoric/vats/src/nameHub.js'; +import { buildRootObject as boardRoot } from '@agoric/vats/src/vat-board.js'; +import { buildRootObject as mintsRoot } from '@agoric/vats/src/vat-mints.js'; +import { makeZoeKit } from '@agoric/zoe'; +import { makeFakeVatAdmin } from '@agoric/zoe/tools/fakeVatAdmin.js'; +import { makeLoopback } from '@endo/captp'; +import { E, Far } from '@endo/far'; +import path from 'path'; +import { devices } from './devices.js'; + +/** @type {import('ava').TestInterface>>} */ +// @ts-expect-error cast +const test = anyTest; + +const setUpZoeForTest = async () => { + const { makeFar } = makeLoopback('zoeTest'); + const { zoeService, feeMintAccess: nonFarFeeMintAccess } = makeZoeKit( + makeFakeVatAdmin(() => {}).admin, + ); + /** @type {import('@endo/far').ERef} */ + const zoe = makeFar(zoeService); + const feeMintAccess = await makeFar(nonFarFeeMintAccess); + return { + zoe, + feeMintAccess, + }; +}; +harden(setUpZoeForTest); + +export const mockChainStorageRoot = () => { + const toStorage = v => v; + return makeChainStorageRoot(toStorage, 'swingset', 'mockChainStorageRoot'); +}; + +const makeTestContext = async t => { + const space = /** @type {any} */ (makePromiseSpace(t.log)); + const { consume, produce } = + /** @type { BootstrapPowers & { consume: { loadVat: (n: 'mints') => MintsVat }} } */ ( + space + ); + const { agoricNames, spaces } = makeAgoricNamesAccess(); + produce.agoricNames.resolve(agoricNames); + + const { zoe, feeMintAccess } = await setUpZoeForTest(); + produce.zoe.resolve(zoe); + produce.feeMintAccess.resolve(feeMintAccess); + + produce.loadVat.resolve(name => { + switch (name) { + case 'mints': + return mintsRoot(); + case 'board': + return boardRoot(); + default: + throw Error('unknown loadVat name'); + } + }); + + const bldKit = makeIssuerKit('BLD'); + produce.bldIssuerKit.resolve(bldKit); + produce.chainStorage.resolve(mockChainStorageRoot()); + + produce.bankManager.resolve( + Promise.resolve( + Far('mockBankManager', { + getBankForAddress: _a => + Far('mockBank', { + getPurse: () => ({ + deposit: async (_, _x) => { + return null; + }, + }), + getAssetSubscription: () => null, + }), + }), + ), + ); + + const vatPowers = { + D: x => x, + }; + + await Promise.all([ + // @ts-expect-error + makeBoard({ consume, produce, ...spaces }), + makeAddressNameHubs({ consume, produce, ...spaces }), + installBootContracts({ vatPowers, devices, consume, produce, ...spaces }), + makeClientManager({ consume, produce, ...spaces }), + connectFaucet({ consume, produce, ...spaces }), + ]); + + // Adapted from perAddress in makeAddressNameHubs() + const reserveAddress = address => { + // Create a name hub for this address. + const { nameHub: myAddressNameHub, nameAdmin: rawMyAddressNameAdmin } = + makeNameHubKit(); + + /** @type {MyAddressNameAdmin} */ + const myAddressNameAdmin = Far('myAddressNameAdmin', { + ...rawMyAddressNameAdmin, + getMyAddress: () => address, + }); + // reserve space for deposit facet + myAddressNameAdmin.reserve('depositFacet'); + // Register it with the namesByAddress hub. + return E(consume.namesByAddressAdmin).update( + address, + myAddressNameHub, + myAddressNameAdmin, + ); + }; + + const address = 'bogusAddress'; + await reserveAddress(address); + + // #region Installs + const pathname = new URL(import.meta.url).pathname; + const dirname = path.dirname(pathname); + + const bundleCache = await unsafeMakeBundleCache('bundles/'); + const bundle = await bundleCache.load( + `${dirname}/../src/singleWallet.js`, + 'singleWallet', + ); + /** @type {Installation} */ + const installation = E(zoe).install(bundle); + // #endregion + + // copied from makeClientBanks() + const bank = E(consume.bankManager).getBankForAddress(address); + const myAddressNameAdmin = E(consume.namesByAddressAdmin).lookupAdmin( + address, + ); + + // copied from makeClientBanks() + const storageNode = await getChildNode(consume.chainStorage, 'wallet'); + const marshaller = E(consume.board).getPublishingMarshaller(); + + const singleWallet = E(zoe).startInstance( + installation, + {}, + { + agoricNames, + bank, + namesByAddress: consume.namesByAddress, + myAddressNameAdmin, + board: consume.board, + }, + { storageNode, marshaller }, + ); + + return { + singleWallet, + zoe, + }; +}; + +test.before(async t => { + t.context = await makeTestContext(t); +}); + +test('basic', async t => { + const { singleWallet, zoe } = t.context; + const { creatorFacet } = await singleWallet; + + const bridge = await E(creatorFacet).getBridge(); + t.is(await E(bridge).getZoe(), await zoe); + + t.is( + await subscriptionKey(E(creatorFacet).getSubscription()), + 'mockChainStorageRoot.wallet.bogusAddress', + ); +}); From 11e90d0ac3a576f2d149fd8149f30ddd308ab874 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 5 Jul 2022 15:27:24 -0700 Subject: [PATCH 3/5] refactor: rename setupClientManager --- packages/run-protocol/test/test-gov-collateral.js | 4 ++-- packages/vats/src/core/chain-behaviors.js | 6 +++--- packages/vats/src/core/manifest.js | 2 +- packages/vats/src/core/types.js | 6 +++--- packages/vats/test/test-clientBundle.js | 4 ++-- packages/wallet/contract/test/test-singleWallet.js | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/run-protocol/test/test-gov-collateral.js b/packages/run-protocol/test/test-gov-collateral.js index 2c12698affc..c4ff4a9abb4 100644 --- a/packages/run-protocol/test/test-gov-collateral.js +++ b/packages/run-protocol/test/test-gov-collateral.js @@ -15,7 +15,7 @@ import { import centralSupplyBundle from '@agoric/vats/bundles/bundle-centralSupply.js'; import { bridgeCoreEval, - makeClientManager, + setupClientManager, } from '@agoric/vats/src/core/chain-behaviors.js'; import { extractCoreProposalBundles } from '@agoric/deploy-script-support/src/extract-proposal.js'; import { makeCoreProposalBehavior } from '@agoric/deploy-script-support/src/coreProposalBehavior.js'; @@ -169,7 +169,7 @@ const makeScenario = async (t, { env = process.env } = {}) => { return Promise.all([ // @ts-expect-error TODO: align types better addBankAssets(space), - makeClientManager(space), + setupClientManager(space), makeAddressNameHubs(space), // @ts-expect-error TODO: align types better makeBoard(space), diff --git a/packages/vats/src/core/chain-behaviors.js b/packages/vats/src/core/chain-behaviors.js index 1060ec7459c..0df8cbc7239 100644 --- a/packages/vats/src/core/chain-behaviors.js +++ b/packages/vats/src/core/chain-behaviors.js @@ -172,7 +172,7 @@ const missingKeys = (pattern, specimen) => * @param {BootstrapSpace} powers * @param {{ template?: Record }} config */ -export const makeClientManager = async ( +export const setupClientManager = async ( { produce: { client, clientCreator: clientCreatorP } }, { template = { @@ -187,7 +187,7 @@ export const makeClientManager = async ( } = {}, ) => { // Create a subscription of chain configurations. - /** @type {SubscriptionRecord} */ + /** @type {SubscriptionRecord} */ const { subscription, publication } = makeSubscriptionKit(); /** @type {ClientManager} */ @@ -252,7 +252,7 @@ export const makeClientManager = async ( clientCreatorP.resolve(clientCreator); client.resolve(clientManager); }; -harden(makeClientManager); +harden(setupClientManager); /** @param {BootstrapPowers} powers */ export const startTimerService = async ({ diff --git a/packages/vats/src/core/manifest.js b/packages/vats/src/core/manifest.js index bb2ded15e19..0a16ab63b6a 100644 --- a/packages/vats/src/core/manifest.js +++ b/packages/vats/src/core/manifest.js @@ -180,7 +180,7 @@ const SHARED_CHAIN_BOOTSTRAP_MANIFEST = harden({ bridgeManager: true, }, }, - makeClientManager: { + setupClientManager: { produce: { client: true, clientCreator: true, diff --git a/packages/vats/src/core/types.js b/packages/vats/src/core/types.js index c56045291e6..1b5fd732129 100644 --- a/packages/vats/src/core/types.js +++ b/packages/vats/src/core/types.js @@ -95,10 +95,10 @@ * }} PromiseSpace * * @typedef {{ - * assignBundle: (ps: PropertyMakers) => void - * }} ClientManager + * assignBundle: (ps: PropertyMaker[]) => void + * }} ClientManager tool to put properties onto the `home` object of the client * - * @typedef {Array<(addr: string) => Record>} PropertyMakers + * @typedef {(addr: string) => Record} PropertyMaker callback to assign a property onto the `home` object of the client */ /** diff --git a/packages/vats/test/test-clientBundle.js b/packages/vats/test/test-clientBundle.js index 831baf375cf..9fc40d80870 100644 --- a/packages/vats/test/test-clientBundle.js +++ b/packages/vats/test/test-clientBundle.js @@ -12,7 +12,7 @@ import { connectFaucet, showAmount, } from '@agoric/run-protocol/src/proposals/demoIssuers.js'; -import { makeClientManager } from '../src/core/chain-behaviors.js'; +import { setupClientManager } from '../src/core/chain-behaviors.js'; import { makeAgoricNamesAccess, makePromiseSpace } from '../src/core/utils.js'; import { buildRootObject as mintsRoot } from '../src/vat-mints.js'; import { buildRootObject as boardRoot } from '../src/vat-board.js'; @@ -119,7 +119,7 @@ test('connectFaucet produces payments', async t => { makeBoard({ consume, produce, ...spaces }), makeAddressNameHubs({ consume, produce, ...spaces }), installBootContracts({ vatPowers, devices, consume, produce, ...spaces }), - makeClientManager({ consume, produce, ...spaces }), + setupClientManager({ consume, produce, ...spaces }), connectFaucet({ consume, produce, ...spaces }), makeClientBanks({ consume, produce, ...spaces }), stubProps({ consume, produce, ...spaces }), diff --git a/packages/wallet/contract/test/test-singleWallet.js b/packages/wallet/contract/test/test-singleWallet.js index c72d268e803..8d9c172f909 100644 --- a/packages/wallet/contract/test/test-singleWallet.js +++ b/packages/wallet/contract/test/test-singleWallet.js @@ -14,7 +14,7 @@ import { makeAddressNameHubs, makeBoard, } from '@agoric/vats/src/core/basic-behaviors.js'; -import { makeClientManager } from '@agoric/vats/src/core/chain-behaviors.js'; +import { setupClientManager } from '@agoric/vats/src/core/chain-behaviors.js'; import { makeAgoricNamesAccess, makePromiseSpace, @@ -110,7 +110,7 @@ const makeTestContext = async t => { makeBoard({ consume, produce, ...spaces }), makeAddressNameHubs({ consume, produce, ...spaces }), installBootContracts({ vatPowers, devices, consume, produce, ...spaces }), - makeClientManager({ consume, produce, ...spaces }), + setupClientManager({ consume, produce, ...spaces }), connectFaucet({ consume, produce, ...spaces }), ]); From 8396fe1ea242a1d3775aad98afbd62cdfb0f13a7 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Wed, 6 Jul 2022 09:57:47 -0700 Subject: [PATCH 4/5] test(smartWallet): describe manual test --- packages/wallet/contract/README.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/wallet/contract/README.md b/packages/wallet/contract/README.md index 23ae74a292c..20d36cf27ed 100644 --- a/packages/wallet/contract/README.md +++ b/packages/wallet/contract/README.md @@ -8,7 +8,7 @@ The `singleWalet` contract manages a single smart wallet. The `walletFactory` contract provisions and manages smart wallets. -# Common +## Common There can be zero or one wallets per Cosmos address. @@ -29,3 +29,28 @@ By design there's a 1:1 across all four. `namesByAddress` and `board` are shared by everybody. `myAddressNamesAdmin` is from the account you provision. + +# Testing +There are no automated tests yet verifying the smart wallet running on chain. Here are procedures you can use instead. + +## Notifiers + +``` +# tab 1 (chain) +cd packages/cosmic-swingset/ +make scenario2-setup scenario2-run-chain +# starts bare chain, don’t need AMM + +# tab 2 (client server) +cd packages/cosmic-swingset/ +make scenario2-run-client +# confirm no errors in logs + +# tab 3 (interactive) +agoric open --repl +# confirm in browser that `home.wallet` and `home.smartWallet` exist +agd query vstorage keys 'published.wallet' +# confirm it has a key like `published.wallet.agoric1nqxg4pye30n3trct0hf7dclcwfxz8au84hr3ht` +agoric follow :published.wallet.agoric1nqxg4pye30n3trct0hf7dclcwfxz8au84hr3ht +# confirm it has JSON data +``` From 80f642b413d4e0ecc812ea92e031da09069b5d4c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 5 Jul 2022 15:13:27 -0700 Subject: [PATCH 5/5] chore: types --- .../src/depositInvitation.js | 5 ++- packages/deploy-script-support/src/install.js | 10 ++++-- .../src/internalTypes.js | 33 ------------------- packages/deploy-script-support/src/offer.js | 8 ++++- .../deploy-script-support/src/saveIssuer.js | 7 +++- .../test/unitTests/test-install.js | 7 +++- packages/run-protocol/src/proposals/utils.js | 2 +- packages/vats/src/core/types.js | 4 ++- 8 files changed, 35 insertions(+), 41 deletions(-) delete mode 100644 packages/deploy-script-support/src/internalTypes.js diff --git a/packages/deploy-script-support/src/depositInvitation.js b/packages/deploy-script-support/src/depositInvitation.js index cb55053b797..aedfe2ab9c4 100644 --- a/packages/deploy-script-support/src/depositInvitation.js +++ b/packages/deploy-script-support/src/depositInvitation.js @@ -2,7 +2,10 @@ import { E } from '@endo/far'; -/** @type {MakeDepositInvitation} */ +/** + * @param {ERef} zoeInvitationPurse + * @returns {DepositInvitation} + */ export const makeDepositInvitation = zoeInvitationPurse => { /** @type {DepositInvitation} */ const depositInvitation = async invitationP => { diff --git a/packages/deploy-script-support/src/install.js b/packages/deploy-script-support/src/install.js index fcc8d82eed2..38cafeaaa17 100644 --- a/packages/deploy-script-support/src/install.js +++ b/packages/deploy-script-support/src/install.js @@ -1,11 +1,17 @@ // @ts-check import './externalTypes.js'; -import './internalTypes.js'; import { E } from '@endo/far'; -/** @type {MakeInstallSaveAndPublish} */ +// XXX board is Board but specifying that leads to type errors with imports which aren't worth fixing right now +/** + * @param {BundleSource} bundleSource + * @param {ERef} zoe + * @param {ERef} installationManager + * @param {ERef} board + * @returns {InstallSaveAndPublish} + */ export const makeInstall = (bundleSource, zoe, installationManager, board) => { /** @type {InstallSaveAndPublish} */ const install = async (resolvedPath, contractPetname) => { diff --git a/packages/deploy-script-support/src/internalTypes.js b/packages/deploy-script-support/src/internalTypes.js deleted file mode 100644 index 4879c744164..00000000000 --- a/packages/deploy-script-support/src/internalTypes.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @callback MakeInstallSaveAndPublish - * @param {BundleSource} bundleSource - * @param {ERef} zoe - * @param {ERef} installationManager - * @param {ERef} board - * @returns {InstallSaveAndPublish} - */ - -// TODO: import this from agoric-cli - -/** - * @callback MakeOfferAndFindInvitationAmount - * @param {ERef} walletAdmin - an internal type of the - * wallet, not defined here - * @param {ERef} zoe - * @param {ERef} zoeInvitationPurse - * @returns {{ offer: OfferHelper, findInvitationAmount: FindInvitationAmount }} - */ - -/** - * @callback MakeSaveIssuerHelper - * @param {ERef} walletAdmin - an internal type of the - * wallet, not defined here - * @param {ERef} issuerManager - * @returns {SaveIssuerHelper} - */ - -/** - * @callback MakeDepositInvitation - * @param {ERef} zoeInvitationPurse - * @returns {DepositInvitation} - */ diff --git a/packages/deploy-script-support/src/offer.js b/packages/deploy-script-support/src/offer.js index e1fe5c2b742..3830c8abe29 100644 --- a/packages/deploy-script-support/src/offer.js +++ b/packages/deploy-script-support/src/offer.js @@ -4,7 +4,13 @@ import { E } from '@endo/far'; import { assert } from '@agoric/assert'; import { AmountMath } from '@agoric/ertp'; -/** @type {MakeOfferAndFindInvitationAmount} */ +/** + * @param {ERef} walletAdmin - an internal type of the + * wallet, not defined here + * @param {ERef} zoe + * @param {ERef} zoeInvitationPurse + * @returns {{ offer: OfferHelper, findInvitationAmount: FindInvitationAmount }} + */ export const makeOfferAndFindInvitationAmount = ( walletAdmin, zoe, diff --git a/packages/deploy-script-support/src/saveIssuer.js b/packages/deploy-script-support/src/saveIssuer.js index 4dd7283fe5a..507138543f6 100644 --- a/packages/deploy-script-support/src/saveIssuer.js +++ b/packages/deploy-script-support/src/saveIssuer.js @@ -2,7 +2,12 @@ import { E } from '@endo/far'; -/** @type {MakeSaveIssuerHelper} */ +/** + * @param {ERef} walletAdmin - an internal type of the + * wallet, not defined here + * @param {ERef} issuerManager + * @returns {SaveIssuerHelper} + */ export const makeSaveIssuer = (walletAdmin, issuerManager) => { /** @type {SaveIssuerHelper} */ const saveIssuer = async (issuerP, brandPetname, pursePetname) => { diff --git a/packages/deploy-script-support/test/unitTests/test-install.js b/packages/deploy-script-support/test/unitTests/test-install.js index c752f764ca2..4beaeb72ac7 100644 --- a/packages/deploy-script-support/test/unitTests/test-install.js +++ b/packages/deploy-script-support/test/unitTests/test-install.js @@ -16,8 +16,13 @@ test('install', async t => { let addedInstallation; + /** @type {import('../../src/startInstance.js').InstallationManager} */ + // @ts-expect-error mock const installationManager = { - add: (_petname, installation) => (addedInstallation = installation), + add: (_petname, installation) => { + addedInstallation = installation; + return Promise.resolve(); + }, }; const board = makeBoard(); diff --git a/packages/run-protocol/src/proposals/utils.js b/packages/run-protocol/src/proposals/utils.js index 311d6c458b9..89a8c687521 100644 --- a/packages/run-protocol/src/proposals/utils.js +++ b/packages/run-protocol/src/proposals/utils.js @@ -67,7 +67,7 @@ export const reserveThenDeposit = async ( console.info('confirmed deposit for', debugName); }; -/** @type {(store: any, key: string, make: () => T) => Promise} */ +/** @type {(store: ERef, key: string, make: () => T) => Promise} */ const provide = async (store, key, make) => { const found = await E(store).get(key); if (found) { diff --git a/packages/vats/src/core/types.js b/packages/vats/src/core/types.js index 1b5fd732129..5457f4517eb 100644 --- a/packages/vats/src/core/types.js +++ b/packages/vats/src/core/types.js @@ -169,7 +169,9 @@ * }, * installation:{ * produce: Record>, - * consume: Record>, + * consume: Record>> & { + * singleWallet: Promise>, + * }, * }, * instance:{ * produce: Record>,