From eb33d670f7a1587c920f13cb0afec19b0a04adf7 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 29 Sep 2022 16:25:52 -0700 Subject: [PATCH] feat(wallet-ui): use new wallet.current node --- .../src/components/SmartWalletConnection.jsx | 17 ++-- .../ui/src/util/WalletBackendAdapter.js | 91 ++++++++++++++----- 2 files changed, 76 insertions(+), 32 deletions(-) diff --git a/packages/wallet/ui/src/components/SmartWalletConnection.jsx b/packages/wallet/ui/src/components/SmartWalletConnection.jsx index a9fe397ac4b8..510646d53d68 100644 --- a/packages/wallet/ui/src/components/SmartWalletConnection.jsx +++ b/packages/wallet/ui/src/components/SmartWalletConnection.jsx @@ -14,7 +14,7 @@ import { bridgeStorageMessages } from '../util/BridgeStorage'; import { SmartConnectionMethod } from '../util/connections'; import { makeBackendFromWalletBridge, - makeWalletBridgeFromFollower, + makeWalletBridgeFromFollowers, } from '../util/WalletBackendAdapter'; import ProvisionDialog from './ProvisionDialog'; @@ -98,14 +98,13 @@ const SmartWalletConnection = ({ const follow = async () => { const context = makeImportContext(); const leader = makeLeader(href); - const follower = makeFollower( - `:published.wallet.${publicAddress}`, - leader, - { unserializer: context.fromMyWallet }, - ); - // TODO try making a smart-wallet version of this - const bridge = makeWalletBridgeFromFollower( - follower, + const followPublished = path => + makeFollower(`:published.${path}`, leader, { + unserializer: context.fromMyWallet, + }); + const bridge = makeWalletBridgeFromFollowers( + followPublished(`wallet.${publicAddress}.current`), + followPublished(`wallet.${publicAddress}`), leader, context.fromBoard, publicAddress, diff --git a/packages/wallet/ui/src/util/WalletBackendAdapter.js b/packages/wallet/ui/src/util/WalletBackendAdapter.js index 6c19c043f5e4..29b9607639be 100644 --- a/packages/wallet/ui/src/util/WalletBackendAdapter.js +++ b/packages/wallet/ui/src/util/WalletBackendAdapter.js @@ -1,12 +1,10 @@ +// @ts-check import { iterateEach } from '@agoric/casting'; import { makeAsyncIterableFromNotifier, makeNotifierKit, } from '@agoric/notifier'; -import { - getFirstHeight, - NO_SMART_WALLET_ERROR, -} from '@agoric/smart-wallet/src/utils.js'; +import { NO_SMART_WALLET_ERROR } from '@agoric/smart-wallet/src/utils.js'; import { E } from '@endo/eventual-send'; import { Far } from '@endo/marshal'; import { getDappService } from '../service/Dapps.js'; @@ -14,6 +12,8 @@ import { getIssuerService } from '../service/Issuers.js'; import { getOfferService } from '../service/Offers.js'; import { getScopedBridge } from '../service/ScopedBridge.js'; +/** @typedef {import('@agoric/smart-wallet/src/types.js').Petname} Petname */ + const newId = kind => `${kind}${Math.random()}`; /** @typedef {{actions: object, issuerSuggestions: Promise}} BackendSchema */ @@ -76,6 +76,7 @@ export const makeBackendFromWalletBridge = walletBridge => { dapps: iterateNotifier(E(walletBridge).getDappsNotifier()), issuers: iterateNotifier(E(walletBridge).getIssuersNotifier()), offers: wrapOffersIterator( + // @ts-expect-error xxx iterateNotifier(E(walletBridge).getOffersNotifier()), ), payments: iterateNotifier(E(walletBridge).getPaymentsNotifier()), @@ -101,7 +102,8 @@ export const makeBackendFromWalletBridge = walletBridge => { }; /** - * @param {import('@agoric/casting').Follower} follower + * @param {import('@agoric/casting').ValueFollower} currentFollower + * @param {import('@agoric/casting').ValueFollower} updateFollower * @param {import('@agoric/casting').Leader} leader * @param {ReturnType} marshaller * @param {string} publicAddress @@ -110,8 +112,9 @@ export const makeBackendFromWalletBridge = walletBridge => { * @param {(e: unknown) => void} [errorHandler] * @param {() => void} [firstCallback] */ -export const makeWalletBridgeFromFollower = ( - follower, +export const makeWalletBridgeFromFollowers = ( + currentFollower, + updateFollower, leader, marshaller, publicAddress, @@ -139,14 +142,35 @@ export const makeWalletBridgeFromFollower = ( ); // We assume just one cosmos purse per brand. + /** @type {Record} */ const offers = {}; + /** + * @typedef {{ + * brand?: Brand, + * brandPetname?: Petname, + * currentAmount: Amount, + * pursePetname?: Petname, + * displayInfo?: DisplayInfo, + * }} PurseInfo + * @type {Map} + */ const brandToPurse = new Map(); + /** @type {Map} */ const pursePetnameToBrand = new Map(); + if (firstCallback) { + firstCallback(); + Object.values(notifierKits).forEach(({ updater }) => + updater.updateState([]), + ); + firstCallback = undefined; + } + const updatePurses = () => { const purses = []; for (const [brand, purse] of brandToPurse.entries()) { if (purse.currentAmount && purse.brandPetname) { + assert(purse.pursePetname, 'missing purse.pursePetname'); pursePetnameToBrand.set(purse.pursePetname, brand); purses.push(purse); } @@ -154,21 +178,38 @@ export const makeWalletBridgeFromFollower = ( notifierKits.purses.updater.updateState(harden(purses)); }; - const followLatest = async () => { - const firstHeight = await getFirstHeight(follower); + const fetchCurrent = async () => { + console.log('fetchCurrent()'); + const latestIterable = await E(currentFollower).getLatestIterable(); + const iterator = latestIterable[Symbol.asyncIterator](); + const latest = await iterator.next(); + /** @type {import('@agoric/smart-wallet/src/smartWallet').CurrentWalletRecord} */ + const current = latest.value.value; + console.log('fetcHCurrent', current); + for (const purse of current.purses) { + console.log('registering purse', purse); + const brandDescriptor = current.brands.find( + bd => purse.brand === bd.brand, + ); + assert(brandDescriptor, `missing descriptor for brand ${purse.brand}`); + /** @type {PurseInfo} */ + const purseInfo = { + currentAmount: purse.balance, + brandPetname: brandDescriptor.petname, + pursePetname: brandDescriptor.petname, + displayInfo: brandDescriptor.displayInfo, + }; + brandToPurse.set(purse.brand, purseInfo); + } + console.log('brandToPurse map', brandToPurse); + updatePurses(); + }; - for await (const { value } of iterateEach(follower, { - height: firstHeight, - })) { + const followLatest = async () => { + console.log('followLatest()'); + for await (const { value } of iterateEach(updateFollower)) { /** @type {import('@agoric/smart-wallet/src/smartWallet').UpdateRecord} */ const updateRecord = value; - if (firstCallback) { - firstCallback(); - Object.values(notifierKits).forEach(({ updater }) => - updater.updateState([]), - ); - firstCallback = undefined; - } switch (updateRecord.updated) { case 'brand': { const { descriptor } = updateRecord; @@ -207,7 +248,7 @@ export const makeWalletBridgeFromFollower = ( if ('error' in status) { offers[status.id] = { ...oldOffer, - id: `${status.id}`, + id: status.id, status: 'rejected', error: `${status.error}`, }; @@ -217,24 +258,28 @@ export const makeWalletBridgeFromFollower = ( ) { offers[status.id] = { ...oldOffer, - id: `${status.id}`, + id: status.id, status: 'accept', }; } notifierKits.offers.updater.updateState( + // @ts-expect-error xxx harden(Object.values(offers)), ); break; } default: { + // @ts-expect-error exhaustive switch throw Error(`Unknown updateRecord ${updateRecord.updated}`); } } } }; + const loadData = () => fetchCurrent().then(followLatest); + const retry = () => { - followLatest().catch(e => { + loadData().catch(e => { if (e.message === NO_SMART_WALLET_ERROR) { setTimeout(retry, 5000); } else { @@ -243,7 +288,7 @@ export const makeWalletBridgeFromFollower = ( }); }; - followLatest().catch(e => { + loadData().catch(e => { errorHandler(e); if (e.message === NO_SMART_WALLET_ERROR) { setTimeout(retry, 5000);