@@ -111,6 +111,12 @@ import {
111111 OnAssetsConversionResponseStruct ,
112112 OnAssetsMarketDataResponseStruct ,
113113} from '@metamask/snaps-utils' ;
114+ import type {
115+ StorageServiceGetItemAction ,
116+ StorageServiceSetItemAction ,
117+ StorageServiceRemoveItemAction ,
118+ StorageServiceClearAction ,
119+ } from '@metamask/storage-service' ;
114120import type {
115121 Json ,
116122 NonEmptyArray ,
@@ -669,7 +675,11 @@ export type AllowedActions =
669675 | Update
670676 | ResolveVersion
671677 | CreateInterface
672- | GetInterface ;
678+ | GetInterface
679+ | StorageServiceSetItemAction
680+ | StorageServiceGetItemAction
681+ | StorageServiceRemoveItemAction
682+ | StorageServiceClearAction ;
673683
674684export type AllowedEvents =
675685 | ExecutionServiceEvents
@@ -941,6 +951,8 @@ export class SnapController extends BaseController<
941951
942952 readonly #ensureOnboardingComplete: ( ) => Promise < void > ;
943953
954+ readonly #controllerSetup = createDeferredPromise ( ) ;
955+
944956 constructor ( {
945957 closeAllConnections,
946958 messenger,
@@ -983,7 +995,6 @@ export class SnapController extends BaseController<
983995 return Object . values ( snaps ) . reduce < Record < SnapId , Partial < Snap > > > (
984996 ( acc , snap ) => {
985997 const snapCopy : Partial < Snap > = { ...snap } ;
986- delete snapCopy . sourceCode ;
987998 delete snapCopy . auxiliaryFiles ;
988999 acc [ snap . id ] = snapCopy ;
9891000 return acc ;
@@ -1107,10 +1118,6 @@ export class SnapController extends BaseController<
11071118 this . #setupRuntime( snap . id ) ,
11081119 ) ;
11091120
1110- if ( this . #preinstalledSnaps) {
1111- this . #handlePreinstalledSnaps( this . #preinstalledSnaps) ;
1112- }
1113-
11141121 this . #trackSnapExport = throttleTracking (
11151122 ( snapId : SnapId , handler : string , success : boolean , origin : string ) => {
11161123 const snapMetadata = this . messenger . call (
@@ -1207,8 +1214,9 @@ export class SnapController extends BaseController<
12071214 * actions.
12081215 */
12091216 #registerMessageHandlers( ) : void {
1210- this . messenger . registerActionHandler ( `${ controllerName } :init` , ( ...args ) =>
1211- this . init ( ...args ) ,
1217+ this . messenger . registerActionHandler (
1218+ `${ controllerName } :init` ,
1219+ async ( ...args ) => this . init ( ...args ) ,
12121220 ) ;
12131221
12141222 this . messenger . registerActionHandler (
@@ -1323,14 +1331,20 @@ export class SnapController extends BaseController<
13231331 /**
13241332 * Initialise the SnapController.
13251333 *
1326- * Currently this method calls the `onStart` lifecycle hook for all
1334+ * Currently this method sets up the preinstalled snaps and calls the `onStart` lifecycle hook for all
13271335 * runnable Snaps.
13281336 */
1329- init ( ) {
1337+ async init ( ) {
1338+ if ( this . #preinstalledSnaps) {
1339+ await this . #handlePreinstalledSnaps( this . #preinstalledSnaps) ;
1340+ }
1341+
13301342 this . #callLifecycleHooks( METAMASK_ORIGIN , HandlerType . OnStart ) ;
1343+
1344+ this . #controllerSetup. resolve ( ) ;
13311345 }
13321346
1333- #handlePreinstalledSnaps( preinstalledSnaps : PreinstalledSnap [ ] ) {
1347+ async #handlePreinstalledSnaps( preinstalledSnaps : PreinstalledSnap [ ] ) {
13341348 for ( const {
13351349 snapId,
13361350 manifest,
@@ -1402,7 +1416,7 @@ export class SnapController extends BaseController<
14021416 } ;
14031417
14041418 // Add snap to the SnapController state
1405- this . #set( {
1419+ await this . #set( {
14061420 id : snapId ,
14071421 origin : METAMASK_ORIGIN ,
14081422 files : filesObject ,
@@ -1721,6 +1735,9 @@ export class SnapController extends BaseController<
17211735 // Ensure the user has onboarded before allowing access to Snaps.
17221736 await this . #ensureOnboardingComplete( ) ;
17231737
1738+ // Ensure the controller has finished setting up.
1739+ await this . #controllerSetup. promise ;
1740+
17241741 const flags = this . #getFeatureFlags( ) ;
17251742 assert (
17261743 flags . disableSnaps !== true ,
@@ -1810,9 +1827,11 @@ export class SnapController extends BaseController<
18101827 throw new Error ( `Snap "${ snapId } " is disabled.` ) ;
18111828 }
18121829
1830+ const sourceCode = await this . #getSourceCode( snapId ) ;
1831+
18131832 await this . #startSnap( {
18141833 snapId,
1815- sourceCode : snap . sourceCode ,
1834+ sourceCode,
18161835 } ) ;
18171836 }
18181837
@@ -2395,9 +2414,11 @@ export class SnapController extends BaseController<
23952414 this . #snapsRuntimeData. clear ( ) ;
23962415 this . #rollbackSnapshots. clear ( ) ;
23972416
2417+ await this . #clearStorageService( ) ;
2418+
23982419 // We want to remove all snaps & permissions, except for preinstalled snaps
23992420 if ( this . #preinstalledSnaps) {
2400- this . #handlePreinstalledSnaps( this . #preinstalledSnaps) ;
2421+ await this . #handlePreinstalledSnaps( this . #preinstalledSnaps) ;
24012422 }
24022423 }
24032424
@@ -2448,6 +2469,8 @@ export class SnapController extends BaseController<
24482469 delete state . unencryptedSnapStates [ snapId ] ;
24492470 } ) ;
24502471
2472+ await this . #removeSourceCode( snapId ) ;
2473+
24512474 // If the snap has been fully installed before, also emit snapUninstalled.
24522475 if ( snap . status !== SnapStatus . Installing ) {
24532476 this . messenger . publish ( `SnapController:snapUninstalled` , truncated ) ;
@@ -3096,7 +3119,7 @@ export class SnapController extends BaseController<
30963119
30973120 this . #transition( snapId , SnapStatusEvents . Update ) ;
30983121
3099- this . #set( {
3122+ await this . #set( {
31003123 origin,
31013124 id : snapId ,
31023125 files : newSnap ,
@@ -3351,7 +3374,7 @@ export class SnapController extends BaseController<
33513374 * @param args - The add snap args.
33523375 * @returns The resulting snap object.
33533376 */
3354- #set( args : SetSnapArgs ) : PersistedSnap {
3377+ async #set( args : SetSnapArgs ) : Promise < PersistedSnap > {
33553378 const {
33563379 id : snapId ,
33573380 origin,
@@ -3424,7 +3447,6 @@ export class SnapController extends BaseController<
34243447 initialPermissions : manifest . result . initialPermissions ,
34253448 manifest : manifest . result ,
34263449 status : this . #statusMachine. config . initial as StatusStates [ 'value' ] ,
3427- sourceCode,
34283450 version,
34293451 versionHistory,
34303452 auxiliaryFiles,
@@ -3434,13 +3456,16 @@ export class SnapController extends BaseController<
34343456 // If the snap was blocked, it isn't any longer
34353457 delete snap . blockInformation ;
34363458
3459+ await this . #setSourceCode( snapId , sourceCode ) ;
3460+
34373461 // store the snap back in state
34383462 const { inversePatches } = this . update ( ( state : any ) => {
34393463 state . snaps [ snapId ] = snap ;
34403464 } ) ;
34413465
34423466 // checking for isUpdate here as this function is also used in
34433467 // the install flow, we do not care to create snapshots for installs
3468+ // @TODO (guillaumerx): Find a way to add the sourceCode to the rollback snapshot
34443469 if ( isUpdate ) {
34453470 const rollbackSnapshot = this . #getRollbackSnapshot( snapId ) ;
34463471 if ( rollbackSnapshot !== undefined ) {
@@ -4642,4 +4667,53 @@ export class SnapController extends BaseController<
46424667 runtime . state = undefined ;
46434668 }
46444669 }
4670+
4671+ /**
4672+ * Retrieve the source code for a snap from storage.
4673+ *
4674+ * @param snapId - The snap ID.
4675+ * @returns The source code for the snap.
4676+ */
4677+ async #getSourceCode( snapId : SnapId ) {
4678+ const { result } = await this . messenger . call (
4679+ 'StorageService:getItem' ,
4680+ this . name ,
4681+ snapId ,
4682+ ) ;
4683+
4684+ assert ( result , `Source code for snap "${ snapId } " not found.` ) ;
4685+
4686+ return result as string ;
4687+ }
4688+
4689+ /**
4690+ * Store the source code for a snap in storage.
4691+ *
4692+ * @param snapId - The snap ID.
4693+ * @param sourceCode - The source code for the snap.
4694+ */
4695+ async #setSourceCode( snapId : SnapId , sourceCode : string ) {
4696+ await this . messenger . call (
4697+ 'StorageService:setItem' ,
4698+ this . name ,
4699+ snapId ,
4700+ sourceCode ,
4701+ ) ;
4702+ }
4703+
4704+ /**
4705+ * Remove the source code for a snap from storage.
4706+ *
4707+ * @param snapId - The snap ID.
4708+ */
4709+ async #removeSourceCode( snapId : SnapId ) {
4710+ await this . messenger . call ( 'StorageService:removeItem' , this . name , snapId ) ;
4711+ }
4712+
4713+ /**
4714+ * Clear all snap source code from storage.
4715+ */
4716+ async #clearStorageService( ) {
4717+ await this . messenger . call ( 'StorageService:clear' , this . name ) ;
4718+ }
46454719}
0 commit comments