import type { DeploymentLoader } from "./types.js"; import type { Artifact, ArtifactResolver, BuildInfo, } from "../../types/artifact.js"; import type { ExecutionEventListener } from "../../types/execution-events.js"; import type { JournalMessage } from "../execution/types/messages.js"; import type { Journal } from "../journal/types/index.js"; import { MemoryJournal } from "../journal/memory-journal.js"; import { assertIgnitionInvariant } from "../utils/assertions.js"; /** * Stores and loads deployment related information without making changes * on disk, by either storing in memory or loading already existing files. * Used when running in environments like Hardhat tests. */ export class EphemeralDeploymentLoader implements DeploymentLoader { private readonly _journal: Journal; private _deployedAddresses: { [key: string]: string }; private _savedArtifacts: { [key: string]: | { _kind: "artifact"; artifact: Artifact } | { _kind: "contractName"; contractName: string }; }; constructor( private readonly _artifactResolver: ArtifactResolver, private readonly _executionEventListener?: | ExecutionEventListener | undefined, ) { this._journal = new MemoryJournal(this._executionEventListener); this._deployedAddresses = {}; this._savedArtifacts = {}; } public async recordToJournal(message: JournalMessage): Promise { // NOTE: the journal record is sync, even though this call is async await this._journal.record(message); } public readFromJournal(): AsyncGenerator { return this._journal.read(); } public async recordDeployedAddress( futureId: string, contractAddress: string, ): Promise { this._deployedAddresses[futureId] = contractAddress; } public async storeBuildInfo( _futureId: string, _buildInfo: BuildInfo, ): Promise { // For ephemeral we are ignoring build info } public async storeNamedArtifact( futureId: string, contractName: string, _artifact: Artifact, ): Promise { this._savedArtifacts[futureId] = { _kind: "contractName", contractName }; } public async storeUserProvidedArtifact( futureId: string, artifact: Artifact, ): Promise { this._savedArtifacts[futureId] = { _kind: "artifact", artifact }; } public async loadArtifact(artifactId: string): Promise { const futureId = artifactId; const saved = this._savedArtifacts[futureId]; assertIgnitionInvariant( saved !== undefined, `No stored artifact for ${futureId}`, ); switch (saved._kind) { case "artifact": { return saved.artifact; } case "contractName": { const fileArtifact = this._artifactResolver.loadArtifact( saved.contractName, ); assertIgnitionInvariant( fileArtifact !== undefined, `Unable to load artifact, underlying resolver returned undefined for ${saved.contractName}`, ); return await fileArtifact; } } } }