diff --git a/.changeset/heavy-eyes-smile.md b/.changeset/heavy-eyes-smile.md new file mode 100644 index 0000000000..f5508a6445 --- /dev/null +++ b/.changeset/heavy-eyes-smile.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/cli": patch +--- + +Deploys now continue if they detect a `Module_AlreadyInstalled` revert error. diff --git a/packages/cli/src/deploy/common.ts b/packages/cli/src/deploy/common.ts index 8b515b9e8b..885942ecc9 100644 --- a/packages/cli/src/deploy/common.ts +++ b/packages/cli/src/deploy/common.ts @@ -2,6 +2,7 @@ import { Abi, Address, Hex, padHex } from "viem"; import storeConfig from "@latticexyz/store/mud.config.js"; import worldConfig from "@latticexyz/world/mud.config.js"; import IBaseWorldAbi from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json" assert { type: "json" }; +import IModuleAbi from "@latticexyz/world-modules/out/IModule.sol/IModule.abi.json" assert { type: "json" }; import { Tables, configToTables } from "./configToTables"; import { StoreConfig, helloStoreEvent } from "@latticexyz/store"; import { WorldConfig, helloWorldEvent } from "@latticexyz/world"; @@ -14,7 +15,7 @@ export const worldTables = configToTables(worldConfig); export const worldDeployEvents = [helloStoreEvent, helloWorldEvent] as const; -export const worldAbi = IBaseWorldAbi; +export const worldAbi = [...IBaseWorldAbi, ...IModuleAbi] as const; export type WorldDeploy = { readonly address: Address; diff --git a/packages/cli/src/deploy/ensureModules.ts b/packages/cli/src/deploy/ensureModules.ts index 98c331f09a..5e64991392 100644 --- a/packages/cli/src/deploy/ensureModules.ts +++ b/packages/cli/src/deploy/ensureModules.ts @@ -1,8 +1,8 @@ -import { Client, Transport, Chain, Account, Hex } from "viem"; +import { Client, Transport, Chain, Account, Hex, BaseError } from "viem"; import { writeContract } from "@latticexyz/common"; import { Module, WorldDeploy, worldAbi } from "./common"; import { debug } from "./debug"; -import { wait } from "@latticexyz/common/utils"; +import { isDefined, wait } from "@latticexyz/common/utils"; import pRetry from "p-retry"; export async function ensureModules({ @@ -17,49 +17,47 @@ export async function ensureModules({ if (!modules.length) return []; debug("installing modules:", modules.map((mod) => mod.name).join(", ")); - const installTxs = await Promise.all( - modules.map((mod) => - mod.installAsRoot - ? pRetry( - () => - writeContract(client, { - chain: client.chain ?? null, - address: worldDeploy.address, - abi: worldAbi, - // TODO: replace with batchCall (https://github.com/latticexyz/mud/issues/1645) - functionName: "installRootModule", - args: [mod.address, mod.installData], - }), - { - retries: 3, - onFailedAttempt: async (error) => { - const delay = error.attemptNumber * 500; - debug(`failed to install root module ${mod.name}, retrying in ${delay}ms...`); - await wait(delay); - }, + return ( + await Promise.all( + modules.map((mod) => + pRetry( + async () => { + try { + return mod.installAsRoot + ? await writeContract(client, { + chain: client.chain ?? null, + address: worldDeploy.address, + abi: worldAbi, + // TODO: replace with batchCall (https://github.com/latticexyz/mud/issues/1645) + functionName: "installRootModule", + args: [mod.address, mod.installData], + }) + : await writeContract(client, { + chain: client.chain ?? null, + address: worldDeploy.address, + abi: worldAbi, + // TODO: replace with batchCall (https://github.com/latticexyz/mud/issues/1645) + functionName: "installModule", + args: [mod.address, mod.installData], + }); + } catch (error) { + if (error instanceof BaseError && error.message.includes("Module_AlreadyInstalled")) { + debug(`module ${mod.name} already installed`); + return; + } + throw error; } - ) - : pRetry( - () => - writeContract(client, { - chain: client.chain ?? null, - address: worldDeploy.address, - abi: worldAbi, - // TODO: replace with batchCall (https://github.com/latticexyz/mud/issues/1645) - functionName: "installModule", - args: [mod.address, mod.installData], - }), - { - retries: 3, - onFailedAttempt: async (error) => { - const delay = error.attemptNumber * 500; - debug(`failed to install module ${mod.name}, retrying in ${delay}ms...`); - await wait(delay); - }, - } - ) + }, + { + retries: 3, + onFailedAttempt: async (error) => { + const delay = error.attemptNumber * 500; + debug(`failed to install module ${mod.name}, retrying in ${delay}ms...`); + await wait(delay); + }, + } + ) + ) ) - ); - - return await Promise.all(installTxs); + ).filter(isDefined); }