@@ -28,6 +28,8 @@ export async function makeWallet({
28
28
const { makeMapping, dehydrate } = makeDehydrator ( ) ;
29
29
const purseMapping = makeMapping ( 'purse' ) ;
30
30
const brandMapping = makeMapping ( 'brand' ) ;
31
+ const instanceMapping = makeMapping ( 'instance' ) ;
32
+ const installationMapping = makeMapping ( 'installation' ) ;
31
33
32
34
// Brand Table
33
35
// Columns: key:brand | issuer | amountMath
@@ -75,6 +77,7 @@ export async function makeWallet({
75
77
} ) ;
76
78
} ,
77
79
getBrandForIssuer : issuerToBrand . get ,
80
+ hasIssuer : issuerToBrand . has ,
78
81
} ) ;
79
82
const brandTable = makeTable (
80
83
validateSomewhat ,
@@ -147,12 +150,83 @@ export async function makeWallet({
147
150
pursesStateChangeHandler ( getPursesState ( ) ) ;
148
151
}
149
152
153
+ async function updateAllPurseState ( ) {
154
+ return Promise . all (
155
+ purseMapping . petnameToVal
156
+ . entries ( )
157
+ . map ( ( [ petname , purse ] ) => updatePursesState ( petname , purse ) ) ,
158
+ ) ;
159
+ }
160
+
161
+ const display = value => fillInSlots ( dehydrate ( harden ( value ) ) ) ;
162
+
163
+ const displayProposal = proposalTemplate => {
164
+ const { want, give, exit = { onDemand : null } } = proposalTemplate ;
165
+ const compile = pursePetnameExtentKeywordRecord => {
166
+ if ( pursePetnameExtentKeywordRecord === undefined ) {
167
+ return undefined ;
168
+ }
169
+ return Object . fromEntries (
170
+ Object . entries ( pursePetnameExtentKeywordRecord ) . map (
171
+ ( [ keyword , { pursePetname, extent } ] ) => {
172
+ // eslint-disable-next-line no-use-before-define
173
+ const purse = getPurse ( pursePetname ) ;
174
+ const brand = purseToBrand . get ( purse ) ;
175
+ const amount = { brand, extent } ;
176
+ return [ keyword , { pursePetname, amount : display ( amount ) } ] ;
177
+ } ,
178
+ ) ,
179
+ ) ;
180
+ } ;
181
+ const proposal = {
182
+ want : compile ( want ) ,
183
+ give : compile ( give ) ,
184
+ exit,
185
+ } ;
186
+ return proposal ;
187
+ } ;
188
+
150
189
async function updateInboxState ( id , offer ) {
151
190
// Only sent the uncompiled offer to the client.
152
- inboxState . set ( id , offer ) ;
191
+ const {
192
+ instanceHandleBoardId,
193
+ installationHandleBoardId,
194
+ proposalTemplate,
195
+ } = offer ;
196
+ // We could get the instanceHandle and installationHandle from the
197
+ // board and store them to prevent having to make this call each
198
+ // time, but if we want the offers to be able to sent to the
199
+ // frontend, we cannot store the instanceHandle and
200
+ // installationHandle in these offer objects because the handles
201
+ // are presences and we don't wish to send presences to the
202
+ // frontend.
203
+ const instanceHandle = await E ( board ) . getValue ( instanceHandleBoardId ) ;
204
+ const installationHandle = await E ( board ) . getValue (
205
+ installationHandleBoardId ,
206
+ ) ;
207
+ const offerForDisplay = {
208
+ ...offer ,
209
+ instancePetname : display ( instanceHandle ) . petname ,
210
+ installationPetname : display ( installationHandle ) . petname ,
211
+ proposalForDisplay : displayProposal ( proposalTemplate ) ,
212
+ } ;
213
+
214
+ inboxState . set ( id , offerForDisplay ) ;
153
215
inboxStateChangeHandler ( getInboxState ( ) ) ;
154
216
}
155
217
218
+ async function updateAllInboxState ( ) {
219
+ return Array . from ( inboxState . entries ( ) ) . map ( ( [ id , offer ] ) =>
220
+ updateInboxState ( id , offer ) ,
221
+ ) ;
222
+ }
223
+
224
+ // TODO: fix this horribly inefficient update on every potential
225
+ // petname change.
226
+ async function updateAllState ( ) {
227
+ return Promise . all ( [ updateAllPurseState ( ) , updateAllInboxState ( ) ] ) ;
228
+ }
229
+
156
230
// handle the update, which has already resolved to a record. If the offer is
157
231
// 'done', mark the offer 'complete', otherwise resubscribe to the notifier.
158
232
function updateOrResubscribe ( id , offerHandle , update ) {
@@ -293,7 +367,27 @@ export async function makeWallet({
293
367
brandMapping . addPetname ( petnameForBrand , brand ) ;
294
368
return `issuer ${ q ( petnameForBrand ) } successfully added to wallet` ;
295
369
} ;
296
- return issuerSavedP . then ( addBrandPetname ) ;
370
+ return issuerSavedP . then ( addBrandPetname ) . then ( updateAllState ) ;
371
+ } ;
372
+
373
+ const addInstance = ( petname , instanceHandle ) => {
374
+ // We currently just add the petname mapped to the instanceHandle
375
+ // value, but we could have a list of known instances for
376
+ // possible display in the wallet.
377
+ instanceMapping . addPetname ( petname , instanceHandle ) ;
378
+ // We don't wait for the update before returning.
379
+ updateAllState ( ) ;
380
+ return `instance ${ q ( petname ) } successfully added to wallet` ;
381
+ } ;
382
+
383
+ const addInstallation = ( petname , installationHandle ) => {
384
+ // We currently just add the petname mapped to the installationHandle
385
+ // value, but we could have a list of known installations for
386
+ // possible display in the wallet.
387
+ installationMapping . addPetname ( petname , installationHandle ) ;
388
+ // We don't wait for the update before returning.
389
+ updateAllState ( ) ;
390
+ return `installation ${ q ( petname ) } successfully added to wallet` ;
297
391
} ;
298
392
299
393
const makeEmptyPurse = async ( brandPetname , petnameForPurse ) => {
@@ -382,34 +476,6 @@ export async function makeWallet({
382
476
return { proposal, purseKeywordRecord } ;
383
477
} ;
384
478
385
- const display = value => fillInSlots ( dehydrate ( harden ( value ) ) ) ;
386
-
387
- const displayProposal = proposalTemplate => {
388
- const {
389
- want = { } ,
390
- give = { } ,
391
- exit = { onDemand : null } ,
392
- } = proposalTemplate ;
393
- const compile = pursePetnameExtentKeywordRecord => {
394
- return Object . fromEntries (
395
- Object . entries ( pursePetnameExtentKeywordRecord ) . map (
396
- ( [ keyword , { pursePetname, extent } ] ) => {
397
- const purse = getPurse ( pursePetname ) ;
398
- const brand = purseToBrand . get ( purse ) ;
399
- const amount = { brand, extent } ;
400
- return [ keyword , { pursePetname, amount : display ( amount ) } ] ;
401
- } ,
402
- ) ,
403
- ) ;
404
- } ;
405
- const proposal = {
406
- want : compile ( want ) ,
407
- give : compile ( give ) ,
408
- exit,
409
- } ;
410
- return proposal ;
411
- } ;
412
-
413
479
const compileOffer = async offer => {
414
480
const { inviteHandleBoardId } = offer ;
415
481
const { proposal, purseKeywordRecord } = compileProposal (
@@ -437,7 +503,6 @@ export async function makeWallet({
437
503
id : rawId ,
438
504
instanceHandleBoardId,
439
505
installationHandleBoardId,
440
- proposalTemplate,
441
506
} = rawOffer ;
442
507
const id = `${ requestContext . origin } #${ rawId } ` ;
443
508
assert (
@@ -448,24 +513,17 @@ export async function makeWallet({
448
513
typeof installationHandleBoardId === 'string' ,
449
514
details `installationHandleBoardId must be a string` ,
450
515
) ;
451
- const instanceHandle = await E ( board ) . getValue ( instanceHandleBoardId ) ;
452
- const installationHandle = await E ( board ) . getValue (
453
- installationHandleBoardId ,
454
- ) ;
455
516
const offer = harden ( {
456
517
...rawOffer ,
457
518
id,
458
519
requestContext,
459
520
status : undefined ,
460
- instancePetname : display ( instanceHandle ) . petname ,
461
- installationPetname : display ( installationHandle ) . petname ,
462
- proposalForDisplay : displayProposal ( proposalTemplate ) ,
463
521
} ) ;
464
522
idToOffer . init ( id , offer ) ;
465
523
updateInboxState ( id , offer ) ;
466
524
467
- // Start compiling the template, saving a promise for it.
468
- idToCompiledOfferP . set ( id , compileOffer ( offer ) ) ;
525
+ // Compile the offer
526
+ idToCompiledOfferP . set ( id , await compileOffer ( offer ) ) ;
469
527
470
528
// Our inbox state may have an enriched offer.
471
529
updateInboxState ( id , idToOffer . get ( id ) ) ;
@@ -615,10 +673,100 @@ export async function makeWallet({
615
673
. then ( saveAsDefault ) ;
616
674
}
617
675
676
+ function acceptPetname ( acceptFn , suggestedPetname , boardId ) {
677
+ return E ( board )
678
+ . getValue ( boardId )
679
+ . then ( value => acceptFn ( suggestedPetname , value ) ) ;
680
+ }
681
+
682
+ async function suggestIssuer ( suggestedPetname , issuerBoardId ) {
683
+ // TODO: add an approval step in the wallet UI in which
684
+ // suggestion can be rejected and the suggested petname can be
685
+ // changed
686
+ // eslint-disable-next-line no-use-before-define
687
+ return acceptPetname ( wallet . addIssuer , suggestedPetname , issuerBoardId ) ;
688
+ }
689
+
690
+ async function suggestInstance ( suggestedPetname , instanceHandleBoardId ) {
691
+ // TODO: add an approval step in the wallet UI in which
692
+ // suggestion can be rejected and the suggested petname can be
693
+ // changed
694
+
695
+ return acceptPetname (
696
+ // eslint-disable-next-line no-use-before-define
697
+ wallet . addInstance ,
698
+ suggestedPetname ,
699
+ instanceHandleBoardId ,
700
+ ) ;
701
+ }
702
+
703
+ async function suggestInstallation (
704
+ suggestedPetname ,
705
+ installationHandleBoardId ,
706
+ ) {
707
+ // TODO: add an approval step in the wallet UI in which
708
+ // suggestion can be rejected and the suggested petname can be
709
+ // changed
710
+
711
+ return acceptPetname (
712
+ // eslint-disable-next-line no-use-before-define
713
+ wallet . addInstallation ,
714
+ suggestedPetname ,
715
+ installationHandleBoardId ,
716
+ ) ;
717
+ }
718
+
719
+ function renameIssuer ( petname , issuer ) {
720
+ assert (
721
+ brandTable . hasIssuer ( issuer ) ,
722
+ `issuer has not been previously added` ,
723
+ ) ;
724
+ const brand = brandTable . getBrandForIssuer ( issuer ) ;
725
+ brandMapping . renamePetname ( petname , brand ) ;
726
+ // We don't wait for the update before returning.
727
+ updateAllState ( ) ;
728
+ return `issuer ${ q ( petname ) } successfully renamed in wallet` ;
729
+ }
730
+
731
+ function renameInstance ( petname , instance ) {
732
+ instanceMapping . renamePetname ( petname , instance ) ;
733
+ // We don't wait for the update before returning.
734
+ updateAllState ( ) ;
735
+ return `instance ${ q ( petname ) } successfully renamed in wallet` ;
736
+ }
737
+
738
+ function renameInstallation ( petname , installation ) {
739
+ installationMapping . renamePetname ( petname , installation ) ;
740
+ // We don't wait for the update before returning.
741
+ updateAllState ( ) ;
742
+ return `installation ${ q ( petname ) } successfully renamed in wallet` ;
743
+ }
744
+
745
+ function getIssuer ( petname ) {
746
+ const brand = brandMapping . petnameToVal . get ( petname ) ;
747
+ return brandTable . get ( brand ) . issuer ;
748
+ }
749
+
750
+ function getInstance ( petname ) {
751
+ return instanceMapping . petnameToVal . get ( petname ) ;
752
+ }
753
+
754
+ function getInstallation ( petname ) {
755
+ return installationMapping . petnameToVal . get ( petname ) ;
756
+ }
757
+
618
758
const wallet = harden ( {
619
759
addIssuer,
760
+ addInstance,
761
+ addInstallation,
762
+ renameIssuer,
763
+ renameInstance,
764
+ renameInstallation,
765
+ getInstance,
766
+ getInstallation,
620
767
makeEmptyPurse,
621
768
deposit,
769
+ getIssuer,
622
770
getIssuers,
623
771
getPurses,
624
772
getPurse,
@@ -632,6 +780,9 @@ export async function makeWallet({
632
780
getOfferHandles : ids => ids . map ( wallet . getOfferHandle ) ,
633
781
addDepositFacet,
634
782
getDepositFacetId,
783
+ suggestIssuer,
784
+ suggestInstance,
785
+ suggestInstallation,
635
786
} ) ;
636
787
637
788
// Make Zoe invite purse
0 commit comments