@@ -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 ,
@@ -670,7 +676,11 @@ export type AllowedActions =
670676 | Update
671677 | ResolveVersion
672678 | CreateInterface
673- | GetInterface ;
679+ | GetInterface
680+ | StorageServiceSetItemAction
681+ | StorageServiceGetItemAction
682+ | StorageServiceRemoveItemAction
683+ | StorageServiceClearAction ;
674684
675685export type AllowedEvents =
676686 | ExecutionServiceEvents
@@ -943,6 +953,8 @@ export class SnapController extends BaseController<
943953
944954 readonly #ensureOnboardingComplete: ( ) => Promise < void > ;
945955
956+ readonly #controllerSetup = createDeferredPromise ( ) ;
957+
946958 constructor ( {
947959 closeAllConnections,
948960 messenger,
@@ -991,7 +1003,6 @@ export class SnapController extends BaseController<
9911003 return Object . values ( snaps ) . reduce < Record < SnapId , Partial < Snap > > > (
9921004 ( acc , snap ) => {
9931005 const snapCopy : Partial < Snap > = { ...snap } ;
994- delete snapCopy . sourceCode ;
9951006 delete snapCopy . auxiliaryFiles ;
9961007 acc [ snap . id ] = snapCopy ;
9971008 return acc ;
@@ -1115,10 +1126,6 @@ export class SnapController extends BaseController<
11151126 this . #setupRuntime( snap . id ) ,
11161127 ) ;
11171128
1118- if ( this . #preinstalledSnaps) {
1119- this . #handlePreinstalledSnaps( this . #preinstalledSnaps) ;
1120- }
1121-
11221129 this . #trackSnapExport = throttleTracking (
11231130 ( snapId : SnapId , handler : string , success : boolean , origin : string ) => {
11241131 const snapMetadata = this . messenger . call (
@@ -1215,8 +1222,9 @@ export class SnapController extends BaseController<
12151222 * actions.
12161223 */
12171224 #registerMessageHandlers( ) : void {
1218- this . messenger . registerActionHandler ( `${ controllerName } :init` , ( ...args ) =>
1219- this . init ( ...args ) ,
1225+ this . messenger . registerActionHandler (
1226+ `${ controllerName } :init` ,
1227+ async ( ...args ) => this . init ( ...args ) ,
12201228 ) ;
12211229
12221230 this . messenger . registerActionHandler (
@@ -1331,17 +1339,23 @@ export class SnapController extends BaseController<
13311339 /**
13321340 * Initialise the SnapController.
13331341 *
1334- * Currently this method calls the `onStart` lifecycle hook for all
1342+ * Currently this method sets up the preinstalled snaps and calls the `onStart` lifecycle hook for all
13351343 * runnable Snaps.
13361344 */
1337- init ( ) {
1345+ async init ( ) {
13381346 // Lazily populate the `isReady` state.
13391347 this . #ensureCanUsePlatform( ) . catch ( logWarning ) ;
13401348
1349+ if ( this . #preinstalledSnaps) {
1350+ await this . #handlePreinstalledSnaps( this . #preinstalledSnaps) ;
1351+ }
1352+
13411353 this . #callLifecycleHooks( METAMASK_ORIGIN , HandlerType . OnStart ) ;
1354+
1355+ this . #controllerSetup. resolve ( ) ;
13421356 }
13431357
1344- #handlePreinstalledSnaps( preinstalledSnaps : PreinstalledSnap [ ] ) {
1358+ async #handlePreinstalledSnaps( preinstalledSnaps : PreinstalledSnap [ ] ) {
13451359 for ( const {
13461360 snapId,
13471361 manifest,
@@ -1413,7 +1427,7 @@ export class SnapController extends BaseController<
14131427 } ;
14141428
14151429 // Add snap to the SnapController state
1416- this . #set( {
1430+ await this . #set( {
14171431 id : snapId ,
14181432 origin : METAMASK_ORIGIN ,
14191433 files : filesObject ,
@@ -1732,6 +1746,9 @@ export class SnapController extends BaseController<
17321746 // Ensure the user has onboarded before allowing access to Snaps.
17331747 await this . #ensureOnboardingComplete( ) ;
17341748
1749+ // Ensure the controller has finished setting up.
1750+ await this . #controllerSetup. promise ;
1751+
17351752 const flags = this . #getFeatureFlags( ) ;
17361753
17371754 // If the user has onboarded, the Snaps Platform is considered ready,
@@ -1831,9 +1848,11 @@ export class SnapController extends BaseController<
18311848 throw new Error ( `Snap "${ snapId } " is disabled.` ) ;
18321849 }
18331850
1851+ const sourceCode = await this . #getSourceCode( snapId ) ;
1852+
18341853 await this . #startSnap( {
18351854 snapId,
1836- sourceCode : snap . sourceCode ,
1855+ sourceCode,
18371856 } ) ;
18381857 }
18391858
@@ -2417,9 +2436,11 @@ export class SnapController extends BaseController<
24172436 this . #snapsRuntimeData. clear ( ) ;
24182437 this . #rollbackSnapshots. clear ( ) ;
24192438
2439+ await this . #clearStorageService( ) ;
2440+
24202441 // We want to remove all snaps & permissions, except for preinstalled snaps
24212442 if ( this . #preinstalledSnaps) {
2422- this . #handlePreinstalledSnaps( this . #preinstalledSnaps) ;
2443+ await this . #handlePreinstalledSnaps( this . #preinstalledSnaps) ;
24232444 }
24242445 }
24252446
@@ -2470,6 +2491,8 @@ export class SnapController extends BaseController<
24702491 delete state . unencryptedSnapStates [ snapId ] ;
24712492 } ) ;
24722493
2494+ await this . #removeSourceCode( snapId ) ;
2495+
24732496 // If the snap has been fully installed before, also emit snapUninstalled.
24742497 if ( snap . status !== SnapStatus . Installing ) {
24752498 this . messenger . publish ( `SnapController:snapUninstalled` , truncated ) ;
@@ -3118,7 +3141,7 @@ export class SnapController extends BaseController<
31183141
31193142 this . #transition( snapId , SnapStatusEvents . Update ) ;
31203143
3121- this . #set( {
3144+ await this . #set( {
31223145 origin,
31233146 id : snapId ,
31243147 files : newSnap ,
@@ -3373,7 +3396,7 @@ export class SnapController extends BaseController<
33733396 * @param args - The add snap args.
33743397 * @returns The resulting snap object.
33753398 */
3376- #set( args : SetSnapArgs ) : PersistedSnap {
3399+ async #set( args : SetSnapArgs ) : Promise < PersistedSnap > {
33773400 const {
33783401 id : snapId ,
33793402 origin,
@@ -3446,7 +3469,6 @@ export class SnapController extends BaseController<
34463469 initialPermissions : manifest . result . initialPermissions ,
34473470 manifest : manifest . result ,
34483471 status : this . #statusMachine. config . initial as StatusStates [ 'value' ] ,
3449- sourceCode,
34503472 version,
34513473 versionHistory,
34523474 auxiliaryFiles,
@@ -3456,13 +3478,16 @@ export class SnapController extends BaseController<
34563478 // If the snap was blocked, it isn't any longer
34573479 delete snap . blockInformation ;
34583480
3481+ await this . #setSourceCode( snapId , sourceCode ) ;
3482+
34593483 // store the snap back in state
34603484 const { inversePatches } = this . update ( ( state : any ) => {
34613485 state . snaps [ snapId ] = snap ;
34623486 } ) ;
34633487
34643488 // checking for isUpdate here as this function is also used in
34653489 // the install flow, we do not care to create snapshots for installs
3490+ // @TODO (guillaumerx): Find a way to add the sourceCode to the rollback snapshot
34663491 if ( isUpdate ) {
34673492 const rollbackSnapshot = this . #getRollbackSnapshot( snapId ) ;
34683493 if ( rollbackSnapshot !== undefined ) {
@@ -4664,4 +4689,53 @@ export class SnapController extends BaseController<
46644689 runtime . state = undefined ;
46654690 }
46664691 }
4692+
4693+ /**
4694+ * Retrieve the source code for a snap from storage.
4695+ *
4696+ * @param snapId - The snap ID.
4697+ * @returns The source code for the snap.
4698+ */
4699+ async #getSourceCode( snapId : SnapId ) {
4700+ const { result } = await this . messenger . call (
4701+ 'StorageService:getItem' ,
4702+ this . name ,
4703+ snapId ,
4704+ ) ;
4705+
4706+ assert ( result , `Source code for snap "${ snapId } " not found.` ) ;
4707+
4708+ return result as string ;
4709+ }
4710+
4711+ /**
4712+ * Store the source code for a snap in storage.
4713+ *
4714+ * @param snapId - The snap ID.
4715+ * @param sourceCode - The source code for the snap.
4716+ */
4717+ async #setSourceCode( snapId : SnapId , sourceCode : string ) {
4718+ await this . messenger . call (
4719+ 'StorageService:setItem' ,
4720+ this . name ,
4721+ snapId ,
4722+ sourceCode ,
4723+ ) ;
4724+ }
4725+
4726+ /**
4727+ * Remove the source code for a snap from storage.
4728+ *
4729+ * @param snapId - The snap ID.
4730+ */
4731+ async #removeSourceCode( snapId : SnapId ) {
4732+ await this . messenger . call ( 'StorageService:removeItem' , this . name , snapId ) ;
4733+ }
4734+
4735+ /**
4736+ * Clear all snap source code from storage.
4737+ */
4738+ async #clearStorageService( ) {
4739+ await this . messenger . call ( 'StorageService:clear' , this . name ) ;
4740+ }
46674741}
0 commit comments