@latticexyz/cli 2.0.0-main-e48fb3b0 → 2.0.0-main-7b73f44d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/build.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { tablegen } from "@latticexyz/store/codegen";
4
+ import { worldgen } from "@latticexyz/world/node";
5
+ import { StoreConfig } from "@latticexyz/store";
6
+ import { WorldConfig } from "@latticexyz/world";
7
+ import { forge, getForgeConfig, getRemappings } from "@latticexyz/common/foundry";
8
+ import { getExistingContracts } from "./utils/getExistingContracts";
9
+ import { debug as parentDebug } from "./debug";
10
+ import { execa } from "execa";
11
+
12
+ const debug = parentDebug.extend("runDeploy");
13
+
14
+ type BuildOptions = {
15
+ foundryProfile?: string;
16
+ srcDir: string;
17
+ config: StoreConfig & WorldConfig;
18
+ };
19
+
20
+ export async function build({
21
+ config,
22
+ srcDir,
23
+ foundryProfile = process.env.FOUNDRY_PROFILE,
24
+ }: BuildOptions): Promise<void> {
25
+ const outPath = path.join(srcDir, config.codegenDirectory);
26
+ const remappings = await getRemappings(foundryProfile);
27
+ await Promise.all([tablegen(config, outPath, remappings), worldgen(config, getExistingContracts(srcDir), outPath)]);
28
+
29
+ // TODO remove when https://github.com/foundry-rs/foundry/issues/6241 is resolved
30
+ const forgeConfig = await getForgeConfig(foundryProfile);
31
+ if (forgeConfig.cache) {
32
+ const cacheFilePath = path.join(forgeConfig.cache_path, "solidity-files-cache.json");
33
+ if (existsSync(cacheFilePath)) {
34
+ debug("Unsetting cached content hash of IWorld.sol to force it to regenerate");
35
+ const solidityFilesCache = JSON.parse(readFileSync(cacheFilePath, "utf8"));
36
+ const worldInterfacePath = path.join(outPath, "world", "IWorld.sol");
37
+ solidityFilesCache["files"][worldInterfacePath]["contentHash"] = "";
38
+ writeFileSync(cacheFilePath, JSON.stringify(solidityFilesCache, null, 2));
39
+ }
40
+ }
41
+
42
+ await forge(["build"], { profile: foundryProfile });
43
+ await execa("mud", ["abi-ts"], { stdio: "inherit" });
44
+ }
@@ -0,0 +1,36 @@
1
+ import type { CommandModule } from "yargs";
2
+ import { loadConfig } from "@latticexyz/config/node";
3
+ import { StoreConfig } from "@latticexyz/store";
4
+ import { WorldConfig } from "@latticexyz/world";
5
+
6
+ import { getSrcDirectory } from "@latticexyz/common/foundry";
7
+ import { build } from "../build";
8
+
9
+ type Options = {
10
+ configPath?: string;
11
+ profile?: string;
12
+ };
13
+
14
+ const commandModule: CommandModule<Options, Options> = {
15
+ command: "build",
16
+
17
+ describe: "Build contracts and generate MUD artifacts (table libraries, world interface, ABI)",
18
+
19
+ builder(yargs) {
20
+ return yargs.options({
21
+ configPath: { type: "string", desc: "Path to the config file" },
22
+ profile: { type: "string", desc: "The foundry profile to use" },
23
+ });
24
+ },
25
+
26
+ async handler({ configPath, profile }) {
27
+ const config = (await loadConfig(configPath)) as StoreConfig & WorldConfig;
28
+ const srcDir = await getSrcDirectory();
29
+
30
+ await build({ config, srcDir, foundryProfile: profile });
31
+
32
+ process.exit(0);
33
+ },
34
+ };
35
+
36
+ export default commandModule;
@@ -3,6 +3,7 @@ import { CommandModule } from "yargs";
3
3
  import gasReport from "@latticexyz/gas-report";
4
4
  import abiTs from "@latticexyz/abi-ts";
5
5
 
6
+ import build from "./build";
6
7
  import devnode from "./devnode";
7
8
  import faucet from "./faucet";
8
9
  import hello from "./hello";
@@ -16,6 +17,7 @@ import devContracts from "./dev-contracts";
16
17
 
17
18
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options
18
19
  export const commands: CommandModule<any, any>[] = [
20
+ build,
19
21
  deploy,
20
22
  devnode,
21
23
  faucet,
package/src/runDeploy.ts CHANGED
@@ -7,27 +7,14 @@ import { privateKeyToAccount } from "viem/accounts";
7
7
  import { loadConfig } from "@latticexyz/config/node";
8
8
  import { StoreConfig } from "@latticexyz/store";
9
9
  import { WorldConfig } from "@latticexyz/world";
10
- import {
11
- forge,
12
- getForgeConfig,
13
- getOutDirectory,
14
- getRemappings,
15
- getRpcUrl,
16
- getSrcDirectory,
17
- } from "@latticexyz/common/foundry";
10
+ import { getOutDirectory, getRpcUrl, getSrcDirectory } from "@latticexyz/common/foundry";
18
11
  import chalk from "chalk";
19
- import { execa } from "execa";
20
12
  import { MUDError } from "@latticexyz/common/errors";
21
13
  import { resolveConfig } from "./deploy/resolveConfig";
22
14
  import { getChainId } from "viem/actions";
23
15
  import { postDeploy } from "./utils/utils/postDeploy";
24
16
  import { WorldDeploy } from "./deploy/common";
25
- import { tablegen } from "@latticexyz/store/codegen";
26
- import { worldgen } from "@latticexyz/world/node";
27
- import { getExistingContracts } from "./utils/getExistingContracts";
28
- import { debug as parentDebug } from "./debug";
29
-
30
- const debug = parentDebug.extend("runDeploy");
17
+ import { build } from "./build";
31
18
 
32
19
  export const deployOptions = {
33
20
  configPath: { type: "string", desc: "Path to the config file" },
@@ -60,7 +47,6 @@ export async function runDeploy(opts: DeployOptions): Promise<WorldDeploy> {
60
47
 
61
48
  const srcDir = opts.srcDir ?? (await getSrcDirectory(profile));
62
49
  const outDir = await getOutDirectory(profile);
63
- const remappings = await getRemappings();
64
50
 
65
51
  const rpc = opts.rpc ?? (await getRpcUrl(profile));
66
52
  console.log(
@@ -71,24 +57,7 @@ export async function runDeploy(opts: DeployOptions): Promise<WorldDeploy> {
71
57
 
72
58
  // Run build
73
59
  if (!opts.skipBuild) {
74
- const outPath = path.join(srcDir, config.codegenDirectory);
75
- await Promise.all([tablegen(config, outPath, remappings), worldgen(config, getExistingContracts(srcDir), outPath)]);
76
-
77
- // TODO remove when https://github.com/foundry-rs/foundry/issues/6241 is resolved
78
- const forgeConfig = await getForgeConfig(profile);
79
- if (forgeConfig.cache) {
80
- const cacheFilePath = path.join(forgeConfig.cache_path, "solidity-files-cache.json");
81
- if (existsSync(cacheFilePath)) {
82
- debug("Unsetting cached content hash of IWorld.sol to force it to regenerate");
83
- const solidityFilesCache = JSON.parse(readFileSync(cacheFilePath, "utf8"));
84
- const worldInterfacePath = path.join(outPath, "world", "IWorld.sol");
85
- solidityFilesCache["files"][worldInterfacePath]["contentHash"] = "";
86
- writeFileSync(cacheFilePath, JSON.stringify(solidityFilesCache, null, 2));
87
- }
88
- }
89
-
90
- await forge(["build"], { profile });
91
- await execa("mud", ["abi-ts"], { stdio: "inherit" });
60
+ await build({ config, srcDir, foundryProfile: profile });
92
61
  }
93
62
 
94
63
  const privateKey = process.env.PRIVATE_KEY as Hex;
@@ -1,27 +0,0 @@
1
- import{a as z}from"./chunk-22IIKR4S.js";import Vn from"@latticexyz/gas-report";import _n from"@latticexyz/abi-ts";import{rmSync as vo}from"fs";import{homedir as Do}from"os";import To from"path";import{execa as Ao}from"execa";var ko={command:"devnode",describe:"Start a local Ethereum node for development",builder(e){return e.options({blocktime:{type:"number",default:1,decs:"Interval in which new blocks are produced"}})},async handler({blocktime:e}){console.log("Clearing devnode history");let o=Do();vo(To.join(o,".foundry","anvil","tmp"),{recursive:!0,force:!0});let t=["-b",String(e),"--block-base-fee-per-gas","0"];console.log(`Running: anvil ${t.join(" ")}`);let r=Ao("anvil",t,{stdio:["inherit","inherit","inherit"]});process.on("SIGINT",()=>{console.log(`
2
- gracefully shutting down from SIGINT (Crtl-C)`),r.kill(),process.exit()}),await r}},de=ko;import{FaucetServiceDefinition as Io}from"@latticexyz/services/faucet";import{createChannel as Oo,createClient as Po}from"nice-grpc-web";import le from"chalk";import{NodeHttpTransport as jo}from"@improbable-eng/grpc-web-node-http-transport";function Fo(e){return Po(Io,Oo(e,jo()))}var Wo={command:"faucet",describe:"Interact with a MUD faucet",builder(e){return e.options({dripDev:{type:"boolean",desc:"Request a drip from the dev endpoint (requires faucet to have dev mode enabled)",default:!0},faucetUrl:{type:"string",desc:"URL of the MUD faucet",default:"https://faucet.testnet-mud-services.linfra.xyz"},address:{type:"string",desc:"Ethereum address to fund",required:!0}})},async handler({dripDev:e,faucetUrl:o,address:t}){let r=Fo(o);e&&(console.log(le.yellow("Dripping to",t)),await r.dripDev({address:t}),console.log(le.yellow("Success"))),process.exit(0)}},me=Wo;var Bo={command:"hello <name>",describe:"Greet <name> with Hello",builder(e){return e.options({upper:{type:"boolean"}}).positional("name",{type:"string",demandOption:!0})},handler({name:e}){let o=`Gm, ${e}!`;console.log(o),process.exit(0)}},pe=Bo;import Mo from"path";import{loadConfig as Ro}from"@latticexyz/config/node";import{tablegen as $o}from"@latticexyz/store/codegen";import{getRemappings as Eo,getSrcDirectory as Ho}from"@latticexyz/common/foundry";var No={command:"tablegen",describe:"Autogenerate MUD Store table libraries based on the config file",builder(e){return e.options({configPath:{type:"string",desc:"Path to the config file"}})},async handler({configPath:e}){let o=await Ro(e),t=await Ho(),r=await Eo();await $o(o,Mo.join(t,o.codegenDirectory),r),process.exit(0)}},fe=No;import B from"node:path";import{existsSync as so,mkdirSync as Tr,readFileSync as io,writeFileSync as Y}from"node:fs";import{getAddress as Ye}from"viem";import{getBytecode as Vo,sendRawTransaction as _o,sendTransaction as Lo,waitForTransactionReceipt as ye}from"viem/actions";var F={gasPrice:1e11,gasLimit:1e5,signerAddress:"3fab184622dc19b6109349b94811493bf2a45362",transaction:"f8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222",address:"4e59b44847b379578588920ca78fbf26c0b4956c"};import Uo from"debug";var U=Uo("mud:cli");var l=U.extend("deploy");var v=`0x${F.address}`;async function ue(e){if(await Vo(e,{address:v})){l("found create2 deployer at",v);return}l("sending gas for create2 deployer to signer at",F.signerAddress);let t=await Lo(e,{chain:e.chain??null,to:`0x${F.signerAddress}`,value:BigInt(F.gasLimit)*BigInt(F.gasPrice)}),r=await ye(e,{hash:t});if(r.status!=="success")throw console.error("failed to send gas to deployer signer",r),new Error("failed to send gas to deployer signer");l("deploying create2 deployer at",v);let n=await _o(e,{serializedTransaction:`0x${F.transaction}`}),s=await ye(e,{hash:n});if(s.contractAddress!==v)throw console.error("unexpected contract address for deployer",s),new Error("unexpected contract address for deployer")}import{waitForTransactionReceipt as ut}from"viem/actions";import xe from"@latticexyz/world/out/CoreModule.sol/CoreModule.json"assert{type:"json"};import Se from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.json"assert{type:"json"};import{parseAbi as at,getCreate2Address as Ce,encodeDeployData as ve,size as De}from"viem";import{padHex as Jo}from"viem";import qo from"@latticexyz/store/mud.config";import Go from"@latticexyz/world/mud.config";import Yo from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import Zo from"@latticexyz/world-modules/out/IModule.sol/IModule.abi.json"assert{type:"json"};import{resourceToHex as Ko}from"@latticexyz/common";import{resolveUserTypes as ge}from"@latticexyz/store";function E(e){let o={...e.userTypes,...Object.fromEntries(Object.entries(e.enums).map(([t])=>[t,{internalType:"uint8"}]))};return Object.fromEntries(Object.entries(e.tables).map(([t,r])=>[`${e.namespace}_${t}`,{namespace:e.namespace,name:r.name,tableId:Ko({type:r.offchainOnly?"offchainTable":"table",namespace:e.namespace,name:r.name}),keySchema:ge(r.keySchema,o),valueSchema:ge(r.valueSchema,o)}]))}import{helloStoreEvent as Qo}from"@latticexyz/store";import{helloWorldEvent as Xo}from"@latticexyz/world";var T=Jo("0x",{size:32}),H=parseInt("6000",16),W=E(qo),D=E(Go),V=[Qo,Xo],C=[...Yo,...Zo],be=["1.0.0-unaudited"],he=["1.0.0-unaudited"];import{waitForTransactionReceipt as it}from"viem/actions";import{concatHex as et,getCreate2Address as ot}from"viem";import{getBytecode as tt}from"viem/actions";import{sendTransaction as rt}from"@latticexyz/common";import nt from"p-retry";import{wait as st}from"@latticexyz/common/utils";async function we({client:e,bytecode:o,deployedBytecodeSize:t,label:r="contract"}){let n=ot({from:v,salt:T,bytecode:o});return await tt(e,{address:n,blockTag:"pending"})?(l("found",r,"at",n),[]):(t>H?console.warn(`
3
- Bytecode for ${r} (${t} bytes) is over the contract size limit (${H} bytes). Run \`forge build --sizes\` for more info.
4
- `):t>H*.95&&console.warn(`
5
- Bytecode for ${r} (${t} bytes) is almost over the contract size limit (${H} bytes). Run \`forge build --sizes\` for more info.
6
- `),l("deploying",r,"at",n),[await nt(()=>rt(e,{chain:e.chain??null,to:v,data:et([T,o])}),{retries:3,onFailedAttempt:async d=>{let i=d.attemptNumber*500;l(`failed to deploy ${r}, retrying in ${i}ms...`),await st(i)}})])}async function I({client:e,contracts:o}){let t=(await Promise.all(o.map(r=>we({client:e,...r})))).flat();if(t.length){l("waiting for contracts");for(let r of t)await it(e,{hash:r})}return t}var ct=De(xe.deployedBytecode.object),Te=ve({bytecode:xe.bytecode.object,abi:[]}),dt=Ce({from:v,bytecode:Te,salt:T}),lt=De(Se.deployedBytecode.object),Ae=ve({bytecode:Se.bytecode.object,abi:at(["constructor(address)"]),args:[dt]}),ke=Ce({from:v,bytecode:Ae,salt:T}),Z=[{bytecode:Te,deployedBytecodeSize:ct,label:"core module"},{bytecode:Ae,deployedBytecodeSize:lt,label:"world factory"}];async function Ie(e){return await I({client:e,contracts:Z})}import gt from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json"assert{type:"json"};import{writeContract as bt}from"@latticexyz/common";import{AbiEventSignatureNotFoundError as mt,decodeEventLog as pt,hexToString as Oe,parseAbi as ft,trim as Pe}from"viem";import{isDefined as yt}from"@latticexyz/common/utils";function _(e){let o=e.map(d=>{try{return{...d,...pt({strict:!0,abi:ft(V),topics:d.topics,data:d.data})}}catch(i){if(i instanceof mt)return;throw i}}).filter(yt),{address:t,deployBlock:r,worldVersion:n,storeVersion:s}=o.reduce((d,i)=>({...d,address:i.address,deployBlock:i.blockNumber,...i.eventName==="HelloWorld"?{worldVersion:Oe(Pe(i.args.worldVersion,{dir:"right"}))}:null,...i.eventName==="HelloStore"?{storeVersion:Oe(Pe(i.args.storeVersion,{dir:"right"}))}:null}),{});if(t==null)throw new Error("could not find world address");if(r==null)throw new Error("could not find world deploy block number");if(n==null)throw new Error("could not find world version");if(s==null)throw new Error("could not find store version");return{address:t,deployBlock:r,worldVersion:n,storeVersion:s}}async function je(e){await Ie(e),l("deploying world");let o=await bt(e,{chain:e.chain??null,address:ke,abi:gt,functionName:"deployWorld"});l("waiting for world deploy");let t=await ut(e,{hash:o});if(t.status!=="success")throw console.error("world deploy failed",t),new Error("world deploy failed");let r=_(t.logs.map(n=>n));return l("deployed world to",r.address,"at block",r.deployBlock),{...r,stateBlock:r.deployBlock}}import{writeContract as Dt}from"@latticexyz/common";import{valueSchemaToFieldLayoutHex as Tt,keySchemaToHex as At,valueSchemaToHex as kt}from"@latticexyz/protocol-parser";function S({namespace:e,name:o}){return`${e}:${o}`}import{parseAbiItem as ht,decodeAbiParameters as Fe,parseAbiParameters as We}from"viem";import{hexToResource as wt}from"@latticexyz/common";import{storeSetRecordEvent as xt}from"@latticexyz/store";import{getLogs as St}from"viem/actions";import{decodeKey as Ct,decodeValueArgs as vt,hexToSchema as Be}from"@latticexyz/protocol-parser";async function Me({client:e,worldDeploy:o}){l("looking up tables for",o.address);let r=(await St(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:ht(xt),args:{tableId:W.store_Tables.tableId}})).map(n=>{let{tableId:s}=Ct(W.store_Tables.keySchema,n.args.keyTuple),{namespace:d,name:i}=wt(s),p=vt(W.store_Tables.valueSchema,n.args),a=Be(p.keySchema),m=Be(p.valueSchema),f=Fe(We("string[]"),p.abiEncodedKeyNames)[0],u=Fe(We("string[]"),p.abiEncodedFieldNames)[0],y=[...m.staticFields,...m.dynamicFields],g=Object.fromEntries(a.staticFields.map((x,c)=>[f[c],x])),b=Object.fromEntries(y.map((x,c)=>[u[c],x]));return{namespace:d,name:i,tableId:s,keySchema:g,valueSchema:b}});return l("found",r.length,"tables for",o.address),r}import It from"p-retry";import{wait as Ot}from"@latticexyz/common/utils";async function Re({client:e,worldDeploy:o,tables:t}){let n=(await Me({client:e,worldDeploy:o})).map(i=>i.tableId),s=t.filter(i=>n.includes(i.tableId));s.length&&l("existing tables",s.map(S).join(", "));let d=t.filter(i=>!n.includes(i.tableId));return d.length?(l("registering tables",d.map(S).join(", ")),await Promise.all(d.map(i=>It(()=>Dt(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"registerTable",args:[i.tableId,Tt(i.valueSchema),At(i.keySchema),kt(i.valueSchema),Object.keys(i.keySchema),Object.keys(i.valueSchema)]}),{retries:3,onFailedAttempt:async p=>{let a=p.attemptNumber*500;l(`failed to register table ${S(i)}, retrying in ${a}ms...`),await Ot(a)}})))):[]}import{getAddress as A}from"viem";import{writeContract as Q}from"@latticexyz/common";import{parseAbiItem as Pt}from"viem";import{getLogs as jt}from"viem/actions";import{storeSpliceStaticDataEvent as Ft}from"@latticexyz/store";async function L({client:e,worldDeploy:o}){l("looking up resource IDs for",o.address);let r=(await jt(e,{strict:!0,address:o.address,fromBlock:o.deployBlock,toBlock:o.stateBlock,event:Pt(Ft),args:{tableId:W.store_ResourceIds.tableId}})).map(n=>n.args.keyTuple[0]);return l("found",r.length,"resource IDs for",o.address),r}import{hexToResource as Jt}from"@latticexyz/common";import{decodeValueArgs as Wt,encodeKey as Bt}from"@latticexyz/protocol-parser";import{readContract as Mt}from"viem/actions";async function O({client:e,worldDeploy:o,table:t,key:r}){let[n,s,d]=await Mt(e,{blockNumber:o.stateBlock,address:o.address,abi:C,functionName:"getRecord",args:[t.tableId,Bt(t.keySchema,r)]});return Wt(t.valueSchema,{staticData:n,encodedLengths:s,dynamicData:d})}import{getFunctionSelector as Rt,parseAbiItem as $t}from"viem";import{storeSetRecordEvent as Et}from"@latticexyz/store";import{getLogs as Ht}from"viem/actions";import{decodeValueArgs as Nt}from"@latticexyz/protocol-parser";import{hexToResource as zt}from"@latticexyz/common";async function K({client:e,worldDeploy:o}){l("looking up function signatures for",o.address);let r=(await Ht(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:$t(Et),args:{tableId:D.world_FunctionSignatures.tableId}})).map(s=>Nt(D.world_FunctionSignatures.valueSchema,s.args).functionSignature);return l("found",r.length,"function signatures for",o.address),await Promise.all(r.map(async s=>{let d=Rt(s),{systemId:i,systemFunctionSelector:p}=await O({client:e,worldDeploy:o,table:D.world_FunctionSelectors,key:{functionSelector:d}}),{namespace:a,name:m}=zt(i),f=a===""?s:s.replace(`${a}_${m}_`,"");return{signature:s,selector:d,systemId:i,systemFunctionSignature:f,systemFunctionSelector:p}}))}import{parseAbiItem as Ut,getAddress as Vt}from"viem";import{storeSpliceStaticDataEvent as _t}from"@latticexyz/store";import{getLogs as Lt}from"viem/actions";import{decodeKey as Kt}from"@latticexyz/protocol-parser";async function J({client:e,worldDeploy:o}){l("looking up resource access for",o.address);let r=(await Lt(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:Ut(_t),args:{tableId:D.world_ResourceAccess.tableId}})).map(s=>Kt(D.world_ResourceAccess.keySchema,s.args.keyTuple)),n=(await Promise.all(r.map(async s=>[s,await O({client:e,worldDeploy:o,table:D.world_ResourceAccess,key:s})]))).filter(([,s])=>s.access).map(([s])=>({resourceId:s.resourceId,address:Vt(s.caller)}));return l("found",n.length,"resource<>address access pairs"),n}async function $e({client:e,worldDeploy:o}){let[t,r,n]=await Promise.all([L({client:e,worldDeploy:o}),K({client:e,worldDeploy:o}),J({client:e,worldDeploy:o})]),s=t.map(Jt).filter(d=>d.type==="system");return l("looking up systems",s.map(S).join(", ")),await Promise.all(s.map(async d=>{let{system:i,publicAccess:p}=await O({client:e,worldDeploy:o,table:D.world_Systems,key:{systemId:d.resourceId}}),a=r.filter(m=>m.systemId===d.resourceId);return{address:i,namespace:d.namespace,name:d.name,systemId:d.resourceId,allowAll:p,allowedAddresses:n.filter(({resourceId:m})=>m===d.resourceId).map(({address:m})=>m),functions:a}}))}import{uniqueBy as qt,wait as X}from"@latticexyz/common/utils";import ee from"p-retry";async function Ee({client:e,worldDeploy:o,systems:t}){let[r,n]=await Promise.all([$e({client:e,worldDeploy:o}),J({client:e,worldDeploy:o})]),s=t.map(c=>c.systemId),d=n.filter(({resourceId:c})=>s.includes(c)),i=t.flatMap(c=>c.allowedAddresses.map(h=>({resourceId:c.systemId,address:h}))),p=i.filter(c=>!d.some(({resourceId:h,address:w})=>h===c.resourceId&&A(w)===A(c.address))),a=d.filter(c=>!i.some(({resourceId:h,address:w})=>h===c.resourceId&&A(w)===A(c.address)));a.length&&l("revoking",a.length,"access grants"),p.length&&l("adding",p.length,"access grants");let m=[...a.map(c=>ee(()=>Q(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"revokeAccess",args:[c.resourceId,c.address]}),{retries:3,onFailedAttempt:async h=>{let w=h.attemptNumber*500;l(`failed to revoke access, retrying in ${w}ms...`),await X(w)}})),...p.map(c=>ee(()=>Q(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"grantAccess",args:[c.resourceId,c.address]}),{retries:3,onFailedAttempt:async h=>{let w=h.attemptNumber*500;l(`failed to grant access, retrying in ${w}ms...`),await X(w)}}))],f=t.filter(c=>r.some(h=>h.systemId===c.systemId&&A(h.address)===A(c.address)));f.length&&l("existing systems",f.map(S).join(", "));let u=f.map(c=>c.systemId),y=t.filter(c=>!u.includes(c.systemId));if(!y.length)return[];let g=y.filter(c=>r.some(h=>h.systemId===c.systemId&&A(h.address)!==A(c.address)));g.length&&l("upgrading systems",g.map(S).join(", "));let b=y.filter(c=>!r.some(h=>h.systemId===c.systemId));b.length&&l("registering new systems",b.map(S).join(", ")),await I({client:e,contracts:qt(y,c=>A(c.address)).map(c=>({bytecode:c.bytecode,deployedBytecodeSize:c.deployedBytecodeSize,label:`${S(c)} system`}))});let x=y.map(c=>ee(()=>Q(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"registerSystem",args:[c.systemId,c.address,c.allowAll]}),{retries:3,onFailedAttempt:async h=>{let w=h.attemptNumber*500;l(`failed to register system ${S(c)}, retrying in ${w}ms...`),await X(w)}}));return await Promise.all([...m,...x])}import{waitForTransactionReceipt as ar}from"viem/actions";import{getAddress as Gt,parseAbi as Yt}from"viem";import{getBlockNumber as Zt,getLogs as Qt}from"viem/actions";var He=new Map;async function Ne(e,o){let t=Gt(o),r=He.get(t);if(r!=null)return r;l("looking up world deploy for",t);let n=await Zt(e),s=await Qt(e,{strict:!0,address:t,events:Yt(V),fromBlock:"earliest",toBlock:n});return r={..._(s),stateBlock:n},He.set(t,r),l("found world deploy for",t,"at block",r.deployBlock),r}import{hexToResource as Xt,writeContract as ze}from"@latticexyz/common";import Ue from"p-retry";import{wait as Ve}from"@latticexyz/common/utils";async function _e({client:e,worldDeploy:o,functions:t}){let r=await K({client:e,worldDeploy:o}),n=Object.fromEntries(r.map(i=>[i.selector,i])),s=t.filter(i=>n[i.selector]),d=t.filter(i=>!s.includes(i));if(s.length){l("functions already registered:",s.map(p=>p.signature).join(", "));let i=s.filter(p=>p.systemId!==n[p.selector]?.systemId);i.length&&console.warn("found",i.length,"functions already registered but pointing at a different system ID:",i.map(p=>p.signature).join(", "))}return d.length?(l("registering functions:",d.map(i=>i.signature).join(", ")),Promise.all(d.map(i=>{let{namespace:p}=Xt(i.systemId);return p===""?Ue(()=>ze(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"registerRootFunctionSelector",args:[i.systemId,i.systemFunctionSignature,i.systemFunctionSelector]}),{retries:3,onFailedAttempt:async a=>{let m=a.attemptNumber*500;l(`failed to register function ${i.signature}, retrying in ${m}ms...`),await Ve(m)}}):Ue(()=>ze(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"registerFunctionSelector",args:[i.systemId,i.systemFunctionSignature]}),{retries:3,onFailedAttempt:async a=>{let m=a.attemptNumber*500;l(`failed to register function ${i.signature}, retrying in ${m}ms...`),await Ve(m)}})}))):[]}import{BaseError as er,getAddress as or}from"viem";import{writeContract as Le}from"@latticexyz/common";import{isDefined as tr,uniqueBy as rr,wait as nr}from"@latticexyz/common/utils";import sr from"p-retry";async function Ke({client:e,worldDeploy:o,modules:t}){return t.length?(await I({client:e,contracts:rr(t,r=>or(r.address)).map(r=>({bytecode:r.bytecode,deployedBytecodeSize:r.deployedBytecodeSize,label:`${r.name} module`}))}),l("installing modules:",t.map(r=>r.name).join(", ")),(await Promise.all(t.map(r=>sr(async()=>{try{return r.installAsRoot?await Le(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"installRootModule",args:[r.address,r.installData]}):await Le(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"installModule",args:[r.address,r.installData]})}catch(n){if(n instanceof er&&n.message.includes("Module_AlreadyInstalled")){l(`module ${r.name} already installed`);return}throw n}},{retries:3,onFailedAttempt:async n=>{let s=n.attemptNumber*500;l(`failed to install module ${r.name}, retrying in ${s}ms...`),await nr(s)}})))).filter(tr)):[]}import{getAddress as Je}from"viem";import{hexToResource as qe,resourceToHex as ir}from"@latticexyz/common";async function Ge({client:e,worldDeploy:o,resourceIds:t}){let r=Array.from(new Set(t.map(a=>qe(a).namespace))),n=await L({client:e,worldDeploy:o}),s=Array.from(new Set(n.map(a=>qe(a).namespace))),d=r.filter(a=>s.includes(a)),p=(await Promise.all(d.map(async a=>{let{owner:m}=await O({client:e,worldDeploy:o,table:D.world_NamespaceOwner,key:{namespaceId:ir({type:"namespace",namespace:a,name:""})}});return[a,m]}))).filter(([,a])=>Je(a)!==Je(e.account.address)).map(([a])=>a);if(p.length)throw new Error(`You are attempting to deploy to namespaces you do not own: ${p.join(", ")}`)}import{uniqueBy as Ze}from"@latticexyz/common/utils";async function Qe({client:e,config:o,worldAddress:t}){let r=Object.values(o.tables),n=Object.values(o.systems);await ue(e),await I({client:e,contracts:[...Z,...Ze(n,f=>Ye(f.address)).map(f=>({bytecode:f.bytecode,deployedBytecodeSize:f.deployedBytecodeSize,label:`${S(f)} system`})),...Ze(o.modules,f=>Ye(f.address)).map(f=>({bytecode:f.bytecode,deployedBytecodeSize:f.deployedBytecodeSize,label:`${f.name} module`}))]});let s=t?await Ne(e,t):await je(e);if(!be.includes(s.storeVersion))throw new Error(`Unsupported Store version: ${s.storeVersion}`);if(!he.includes(s.worldVersion))throw new Error(`Unsupported World version: ${s.worldVersion}`);await Ge({client:e,worldDeploy:s,resourceIds:[...r.map(f=>f.tableId),...n.map(f=>f.systemId)]});let d=await Re({client:e,worldDeploy:s,tables:r}),i=await Ee({client:e,worldDeploy:s,systems:n}),p=await _e({client:e,worldDeploy:s,functions:n.flatMap(f=>f.functions)}),a=await Ke({client:e,worldDeploy:s,modules:o.modules}),m=[...d,...i,...p,...a];l("waiting for all transactions to confirm");for(let f of m)await ar(e,{hash:f});return l("deploy complete"),s}import{createWalletClient as Ar,http as kr}from"viem";import{privateKeyToAccount as Ir}from"viem/accounts";import{loadConfig as Or}from"@latticexyz/config/node";import{forge as Pr,getForgeConfig as jr,getOutDirectory as Fr,getRemappings as Wr,getRpcUrl as Br,getSrcDirectory as Mr}from"@latticexyz/common/foundry";import M from"chalk";import{execa as Rr}from"execa";import{MUDError as $r}from"@latticexyz/common/errors";import{resolveWorldConfig as fr}from"@latticexyz/world";import{resourceToHex as se,hexToResource as yr}from"@latticexyz/common";import{resolveWithContext as ur}from"@latticexyz/config";import{encodeField as gr}from"@latticexyz/protocol-parser";import{getFunctionSelector as eo,getCreate2Address as oo,getAddress as br,hexToBytes as hr,bytesToHex as wr,getFunctionSignature as to}from"viem";import cr from"glob";import{basename as dr}from"path";function P(e){return cr.sync(`${e}/**/*.sol`).map(o=>({path:o,basename:dr(o,".sol")}))}import oe from"@latticexyz/world-modules/out/KeysWithValueModule.sol/KeysWithValueModule.json"assert{type:"json"};import te from"@latticexyz/world-modules/out/KeysInTableModule.sol/KeysInTableModule.json"assert{type:"json"};import re from"@latticexyz/world-modules/out/UniqueEntityModule.sol/UniqueEntityModule.json"assert{type:"json"};import{size as ne}from"viem";var Xe=[{name:"KeysWithValueModule",abi:oe.abi,bytecode:oe.bytecode.object,deployedBytecodeSize:ne(oe.deployedBytecode.object)},{name:"KeysInTableModule",abi:te.abi,bytecode:te.bytecode.object,deployedBytecodeSize:ne(te.deployedBytecode.object)},{name:"UniqueEntityModule",abi:re.abi,bytecode:re.bytecode.object,deployedBytecodeSize:ne(re.deployedBytecode.object)}];import{readFileSync as lr}from"fs";import mr from"path";import{MUDError as q}from"@latticexyz/common/errors";import{size as pr}from"viem";function G(e,o){let t,r=mr.join(o,e+".sol",e+".json");try{t=JSON.parse(lr(r,"utf8"))}catch{throw new q(`Error reading file at ${r}`)}let n=t?.bytecode?.object;if(!n)throw new q(`No bytecode found in ${r}`);let s=t?.deployedBytecode?.object;if(!s)throw new q(`No deployed bytecode found in ${r}`);let d=t?.abi;if(!d)throw new q(`No ABI found in ${r}`);return{abi:d,bytecode:n,deployedBytecodeSize:pr(s)}}function ro({config:e,forgeSourceDir:o,forgeOutDir:t}){let r=E(e),n=P(o).map(({basename:u})=>u),s=fr(e,n),i=G("System",t).abi.filter(u=>u.type==="function").map(to),p=Object.entries(s.systems).map(([u,y])=>{let g=e.namespace,b=y.name,x=se({type:"system",namespace:g,name:b}),c=G(u,t),h=c.abi.filter(w=>w.type==="function").map(to).filter(w=>!i.includes(w)).map(w=>{let ce=g===""?w:`${g}_${b}_${w}`;return{signature:ce,selector:eo(ce),systemId:x,systemFunctionSignature:w,systemFunctionSelector:eo(w)}});return{namespace:g,name:b,systemId:x,allowAll:y.openAccess,allowedAddresses:y.accessListAddresses,allowedSystemIds:y.accessListSystems.map(w=>se({type:"system",namespace:g,name:s.systems[w].name})),address:oo({from:v,bytecode:c.bytecode,salt:T}),bytecode:c.bytecode,deployedBytecodeSize:c.deployedBytecodeSize,abi:c.abi,functions:h}}),a=p.map(({allowedAddresses:u,allowedSystemIds:y,...g})=>{let b=y.map(x=>{let c=p.find(h=>h.systemId===x);if(!c)throw new Error(`System ${S(g)} wanted access to ${S(yr(x))}, but it wasn't found in the config.`);return c.address});return{...g,allowedAddresses:Array.from(new Set([...u,...b].map(x=>br(x))))}}),m={tableIds:Object.fromEntries(Object.entries(e.tables).map(([u,y])=>[u,hr(se({type:y.offchainOnly?"offchainTable":"table",namespace:e.namespace,name:y.name}))]))},f=e.modules.map(u=>{let y=Xe.find(b=>b.name===u.name)??G(u.name,t),g=u.args.map(b=>ur(b,m)).map(b=>{let x=b.value instanceof Uint8Array?wr(b.value):b.value;return gr(b.type,x)});if(g.length>1)throw new Error(`${u.name} module should only have 0-1 args, but had ${g.length} args.`);return{name:u.name,installAsRoot:u.root,installData:g.length===0?"0x":g[0],address:oo({from:v,bytecode:y.bytecode,salt:T}),bytecode:y.bytecode,deployedBytecodeSize:y.deployedBytecodeSize,abi:y.abi}});return{tables:r,systems:a,modules:f}}import{getChainId as Er}from"viem/actions";import{existsSync as xr}from"fs";import Sr from"path";import Cr from"chalk";import{getScriptDirectory as vr,forge as Dr}from"@latticexyz/common/foundry";async function no(e,o,t,r){let n=Sr.join(await vr(),e+".s.sol");xr(n)?(console.log(Cr.blue(`Executing post deploy script at ${n}`)),await Dr(["script",e,"--sig","run(address)",o,"--broadcast","--rpc-url",t,"-vvv"],{profile:r})):console.log(`No script at ${n}, skipping post deploy hook`)}import{tablegen as Hr}from"@latticexyz/store/codegen";import{worldgen as Nr}from"@latticexyz/world/node";var zr=U.extend("runDeploy"),k={configPath:{type:"string",desc:"Path to the config file"},printConfig:{type:"boolean",desc:"Print the resolved config"},profile:{type:"string",desc:"The foundry profile to use"},saveDeployment:{type:"boolean",desc:"Save the deployment info to a file",default:!0},rpc:{type:"string",desc:"The RPC URL to use. Defaults to the RPC url from the local foundry.toml"},worldAddress:{type:"string",desc:"Deploy to an existing World at the given address"},srcDir:{type:"string",desc:"Source directory. Defaults to foundry src directory."},skipBuild:{type:"boolean",desc:"Skip rebuilding the contracts before deploying"},alwaysRunPostDeploy:{type:"boolean",desc:"Always run PostDeploy.s.sol after each deploy (including during upgrades). By default, PostDeploy.s.sol is only run once after a new world is deployed."}};async function R(e){let o=e.profile??process.env.FOUNDRY_PROFILE,t=await Or(e.configPath);e.printConfig&&console.log(M.green(`
7
- Resolved config:
8
- `),JSON.stringify(t,null,2));let r=e.srcDir??await Mr(o),n=await Fr(o),s=await Wr(),d=e.rpc??await Br(o);if(console.log(M.bgBlue(M.whiteBright(`
9
- Deploying MUD contracts${o?" with profile "+o:""} to RPC ${d}
10
- `))),!e.skipBuild){let y=B.join(r,t.codegenDirectory);await Promise.all([Hr(t,y,s),Nr(t,P(r),y)]);let g=await jr(o);if(g.cache){let b=B.join(g.cache_path,"solidity-files-cache.json");if(so(b)){zr("Unsetting cached content hash of IWorld.sol to force it to regenerate");let x=JSON.parse(io(b,"utf8")),c=B.join(y,"world","IWorld.sol");x.files[c].contentHash="",Y(b,JSON.stringify(x,null,2))}}await Pr(["build"],{profile:o}),await Rr("mud",["abi-ts"],{stdio:"inherit"})}let i=process.env.PRIVATE_KEY;if(!i)throw new $r(`Missing PRIVATE_KEY environment variable.
11
- Run 'echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" > .env'
12
- in your contracts directory to use the default anvil private key.`);let p=ro({config:t,forgeSourceDir:r,forgeOutDir:n}),a=Ar({transport:kr(d),account:Ir(i)});console.log("Deploying from",a.account.address);let m=Date.now(),f=await Qe({worldAddress:e.worldAddress,client:a,config:p});(e.worldAddress==null||e.alwaysRunPostDeploy)&&await no(t.postDeployScript,f.address,d,o),console.log(M.green("Deployment completed in",(Date.now()-m)/1e3,"seconds"));let u={worldAddress:f.address,blockNumber:Number(f.deployBlock)};if(e.saveDeployment){let y=await Er(a),g=B.join(t.deploysDirectory,y.toString());Tr(g,{recursive:!0}),Y(B.join(g,"latest.json"),JSON.stringify(u,null,2)),Y(B.join(g,Date.now()+".json"),JSON.stringify(u,null,2));let b=[1337,31337],x=so(t.worldsFile)?JSON.parse(io(t.worldsFile,"utf-8")):{};x[y]={address:u.worldAddress,blockNumber:b.includes(y)?void 0:u.blockNumber},Y(t.worldsFile,JSON.stringify(x,null,2)),console.log(M.bgGreen(M.whiteBright(`
13
- Deployment result (written to ${t.worldsFile} and ${g}):
14
- `)))}return console.log(u),f}var Ur={command:"deploy",describe:"Deploy MUD contracts",builder(e){return e.options(k)},async handler(e){try{await R(e)}catch(o){z(o),process.exit(1)}process.exit(0)}},ao=Ur;import{loadConfig as Vr}from"@latticexyz/config/node";import{worldgen as _r}from"@latticexyz/world/node";import{getSrcDirectory as Lr}from"@latticexyz/common/foundry";import co from"path";import{rmSync as Kr}from"fs";var Jr={command:"worldgen",describe:"Autogenerate interfaces for Systems and World based on existing contracts and the config file",builder(e){return e.options({configPath:{type:"string",desc:"Path to the config file"},clean:{type:"boolean",desc:"Clear the worldgen directory before generating new interfaces (defaults to true)",default:!0}})},async handler(e){await qr(e),process.exit(0)}};async function qr(e){let o=e.srcDir??await Lr(),t=P(o),r=e.config??await Vr(e.configPath),n=co.join(o,r.codegenDirectory);e.clean&&Kr(co.join(n,r.worldgenDirectory),{recursive:!0,force:!0}),await _r(r,t,n)}var lo=Jr;import N from"chalk";import{readFileSync as Xr,writeFileSync as en}from"fs";import ae from"path";import{MUDError as $}from"@latticexyz/common/errors";var mo={name:"@latticexyz/cli",version:"2.0.0-next.14",description:"Command line interface for mud",repository:{type:"git",url:"https://github.com/latticexyz/mud.git",directory:"packages/cli"},license:"MIT",type:"module",exports:{".":"./dist/index.js"},types:"src/index.ts",bin:{mud:"./dist/mud.js"},scripts:{build:"pnpm run build:js && pnpm run build:test-tables","build:js":"tsup && chmod +x ./dist/mud.js","build:test-tables":"tsx ./scripts/generate-test-tables.ts",clean:"pnpm run clean:js && pnpm run clean:test-tables","clean:js":"rimraf dist","clean:test-tables":"rimraf src/codegen",dev:"tsup --watch",lint:"eslint . --ext .ts",prepare:"mkdir -p ./dist && touch ./dist/mud.js",test:"tsc --noEmit && forge test","test:ci":"pnpm run test"},dependencies:{"@ethersproject/abi":"^5.7.0","@ethersproject/providers":"^5.7.2","@improbable-eng/grpc-web":"^0.15.0","@improbable-eng/grpc-web-node-http-transport":"^0.15.0","@latticexyz/abi-ts":"workspace:*","@latticexyz/common":"workspace:*","@latticexyz/config":"workspace:*","@latticexyz/gas-report":"workspace:*","@latticexyz/protocol-parser":"workspace:*","@latticexyz/schema-type":"workspace:*","@latticexyz/services":"workspace:*","@latticexyz/store":"workspace:*","@latticexyz/utils":"workspace:*","@latticexyz/world":"workspace:*","@latticexyz/world-modules":"workspace:*",chalk:"^5.0.1",chokidar:"^3.5.3",debug:"^4.3.4",dotenv:"^16.0.3",ejs:"^3.1.8",ethers:"^5.7.2",execa:"^7.0.0",glob:"^8.0.3","nice-grpc-web":"^2.0.1",openurl:"^1.1.1","p-retry":"^5.1.2",path:"^0.12.7",rxjs:"7.5.5","throttle-debounce":"^5.0.0",typescript:"5.1.6",viem:"1.14.0",yargs:"^17.7.1",zod:"^3.21.4","zod-validation-error":"^1.3.0"},devDependencies:{"@types/debug":"^4.1.7","@types/ejs":"^3.1.1","@types/glob":"^7.2.0","@types/node":"^18.15.11","@types/openurl":"^1.0.0","@types/throttle-debounce":"^5.0.0","@types/yargs":"^17.0.10","ds-test":"https://github.com/dapphub/ds-test.git#e282159d5170298eb2455a6c05280ab5a73a4ef0","forge-std":"https://github.com/foundry-rs/forge-std.git#74cfb77e308dd188d2f58864aaf44963ae6b88b1",tsup:"^6.7.0",tsx:"^3.12.6",vitest:"0.31.4"},gitHead:"914a1e0ae4a573d685841ca2ea921435057deb8f"};import on from"glob";import{ZodError as Yr,z as po}from"zod";var Zr=po.object({MUD_PACKAGES:po.string().transform(e=>JSON.parse(e))});function Qr(){try{return Zr.parse({MUD_PACKAGES:'{"@latticexyz/abi-ts":{"localPath":"packages/abi-ts"},"@latticexyz/block-logs-stream":{"localPath":"packages/block-logs-stream"},"@latticexyz/cli":{"localPath":"packages/cli"},"@latticexyz/common":{"localPath":"packages/common"},"@latticexyz/config":{"localPath":"packages/config"},"create-mud":{"localPath":"packages/create-mud"},"@latticexyz/dev-tools":{"localPath":"packages/dev-tools"},"@latticexyz/faucet":{"localPath":"packages/faucet"},"@latticexyz/gas-report":{"localPath":"packages/gas-report"},"@latticexyz/noise":{"localPath":"packages/noise"},"@latticexyz/phaserx":{"localPath":"packages/phaserx"},"@latticexyz/protocol-parser":{"localPath":"packages/protocol-parser"},"@latticexyz/react":{"localPath":"packages/react"},"@latticexyz/recs":{"localPath":"packages/recs"},"@latticexyz/schema-type":{"localPath":"packages/schema-type"},"@latticexyz/services":{"localPath":"packages/services"},"solhint-config-mud":{"localPath":"packages/solhint-config-mud"},"solhint-plugin-mud":{"localPath":"packages/solhint-plugin-mud"},"@latticexyz/store-indexer":{"localPath":"packages/store-indexer"},"@latticexyz/store-sync":{"localPath":"packages/store-sync"},"@latticexyz/store":{"localPath":"packages/store"},"@latticexyz/utils":{"localPath":"packages/utils"},"@latticexyz/world-modules":{"localPath":"packages/world-modules"},"@latticexyz/world":{"localPath":"packages/world"}}'})}catch(e){if(e instanceof Yr){let{_errors:o,...t}=e.format();console.error(`
15
- Missing or invalid environment variables:
16
-
17
- ${Object.keys(t).join(`
18
- `)}
19
- `),process.exit(1)}throw e}}var ie=Qr().MUD_PACKAGES;var tn={command:"set-version",describe:"Set MUD version in all package.json files and optionally backup the previously installed version",builder(e){return e.options({mudVersion:{alias:"v",type:"string",description:"Set MUD to the given version"},tag:{alias:"t",type:"string",description:"Set MUD to the latest version with the given tag from npm"},commit:{alias:"c",type:"string",description:"Set MUD to the version based on a given git commit hash from npm"},link:{alias:"l",type:"string",description:"Relative path to the local MUD root directory to link"}})},async handler(e){try{let o=["mudVersion","link","tag","commit","restore"],t=o.reduce((n,s)=>e[s]?n+1:n,0);if(t===0)throw new $(`You need to provide one these options: ${o.join(", ")}`);if(t>1)throw new $(`These options are mutually exclusive: ${o.join(", ")}`);e.mudVersion=await rn(e);let r=on.sync("**/package.json").filter(n=>!n.includes("node_modules"));for(let n of r)nn(n,e)}catch(o){z(o)}finally{process.exit(0)}}};async function rn(e){e.mudVersion==="canary"&&(e.tag="main");let o;try{console.log(N.blue("Fetching available versions")),o=await(await fetch(`https://registry.npmjs.org/${mo.name}`)).json()}catch{throw new $("Could not fetch available MUD versions")}if(e.tag){let t=o["dist-tags"][e.tag];if(!t)throw new $(`Could not find npm version with tag "${e.tag}"`);return console.log(N.green(`Latest version with tag ${e.tag}: ${t}`)),t}if(e.commit){let t=e.commit.substring(0,8),r=Object.keys(o.versions).find(n=>n.includes(t));if(!r)throw new $(`Could not find npm version based on commit "${e.commit}"`);return console.log(N.green(`Version from commit ${e.commit}: ${r}`)),r}return e.mudVersion}function nn(e,o){let{link:t}=o,{mudVersion:r}=o,n=sn(e),s=Object.keys(ie),d={};for(let a in n.dependencies)s.includes(a)&&(d[a]=n.dependencies[a]);let i={};for(let a in n.devDependencies)s.includes(a)&&(i[a]=n.devDependencies[a]);for(let a in n.dependencies)s.includes(a)&&(n.dependencies[a]=p(a,"dependencies"));for(let a in n.devDependencies)s.includes(a)&&(n.devDependencies[a]=p(a,"devDependencies"));return en(e,JSON.stringify(n,null,2)+`
20
- `),console.log(`Updating ${e}`),fo(d,n.dependencies),fo(i,n.devDependencies),n;function p(a,m){return t&&(r=an(e,t,a)),r||n[m][a]}}function sn(e){try{let o=Xr(e,"utf8");return JSON.parse(o)}catch{throw new $("Could not read JSON at "+e)}}function fo(e,o){for(let t in e)e[t]!==o[t]&&console.log(`${t}: ${N.red(e[t])} -> ${N.green(o[t])}`)}function an(e,o,t){let r=ae.relative(ae.dirname(e),process.cwd());return"link:"+ae.join(r,o,ie[t].localPath)}var yo=tn;import{anvil as cn,forge as dn,getRpcUrl as ln}from"@latticexyz/common/foundry";import mn from"chalk";var pn={...k,port:{type:"number",description:"Port to run internal node for fork testing on",default:4242},worldAddress:{type:"string",description:"Address of an existing world contract. If provided, deployment is skipped and the RPC provided in the foundry.toml is used for fork testing."},forgeOptions:{type:"string",description:"Options to pass to forge test"}},fn={command:"test",describe:"Run tests in MUD contracts",builder(e){return e.options(pn)},async handler(e){if(!e.worldAddress){let n=["--block-base-fee-per-gas","0","--port",String(e.port)];cn(n)}let o=e.worldAddress?await ln(e.profile):`http://127.0.0.1:${e.port}`,t=e.worldAddress??(await R({...e,saveDeployment:!1,rpc:o})).address;console.log(mn.blue("World address",t));let r=e.forgeOptions?.replaceAll("\\","").split(" ")??[];try{await dn(["test","--fork-url",o,...r],{profile:e.profile,env:{WORLD_ADDRESS:t}}),process.exit(0)}catch(n){console.error(n),process.exit(1)}}},uo=fn;import{existsSync as yn,readFileSync as un}from"fs";import{ethers as go}from"ethers";import{loadConfig as gn}from"@latticexyz/config/node";import{MUDError as bo}from"@latticexyz/common/errors";import{cast as bn,getRpcUrl as hn,getSrcDirectory as wn}from"@latticexyz/common/foundry";import{resolveWorldConfig as xn}from"@latticexyz/world";import Sn from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import ho from"@latticexyz/world/mud.config";import{resourceToHex as xo}from"@latticexyz/common";import{createClient as Cn,http as vn}from"viem";import{getChainId as Dn}from"viem/actions";var wo=xo({type:"system",namespace:ho.namespace,name:ho.tables.Systems.name}),Tn={command:"trace",describe:"Display the trace of a transaction",builder(e){return e.options({tx:{type:"string",required:!0,description:"Transaction hash to replay"},worldAddress:{type:"string",description:"World contract address. Defaults to the value from worlds.json, based on rpc's chainId"},configPath:{type:"string",description:"Path to the config file"},profile:{type:"string",description:"The foundry profile to use"},srcDir:{type:"string",description:"Source directory. Defaults to foundry src directory."},rpc:{type:"string",description:"json rpc endpoint. Defaults to foundry's configured eth_rpc_url"}})},async handler(e){e.profile??=process.env.FOUNDRY_PROFILE;let{profile:o}=e;e.srcDir??=await wn(o),e.rpc??=await hn(o);let{tx:t,configPath:r,srcDir:n,rpc:s}=e,d=P(n),i=await gn(r),p=xn(i,d.map(({basename:c})=>c)),a=e.worldAddress??await An(i.worldsFile,s),m=new go.providers.StaticJsonRpcProvider(s),f=new go.Contract(a,Sn,m),u=i.namespace,y=Object.values(p.systems).map(({name:c})=>c),g=await f.getFieldLayout(wo),b=[];for(let c of y){let h=xo({type:"system",namespace:u,name:c}),w=await f.getField(wo,[h],0,g);b.push({name:c,address:w})}let x=await bn(["run","--label",`${a}:World`,...b.map(({name:c,address:h})=>["--label",`${h}:${c}`]).flat(),`${t}`]);console.log(x),process.exit(0)}},So=Tn;async function An(e,o){if(yn(e)){let t=Cn({transport:vn(o)}),r=await Dn(t),n=JSON.parse(un(e,"utf-8"));if(!n[r])throw new bo(`chainId ${r} is missing in worldsFile "${e}"`);return n[r].address}else throw new bo("worldAddress is not specified and worldsFile is missing")}import{anvil as kn,getScriptDirectory as In,getSrcDirectory as On}from"@latticexyz/common/foundry";import j from"chalk";import Pn from"chokidar";import{loadConfig as jn,resolveConfigPath as Fn}from"@latticexyz/config/node";import Wn from"path";import{homedir as Bn}from"os";import{rmSync as Mn}from"fs";import{BehaviorSubject as Rn,debounceTime as $n,exhaustMap as En,filter as Hn}from"rxjs";import{isDefined as Nn}from"@latticexyz/common/utils";var zn={rpc:k.rpc,configPath:k.configPath,alwaysRunPostDeploy:k.alwaysRunPostDeploy,worldAddress:k.worldAddress},Un={command:"dev-contracts",describe:"Start a development server for MUD contracts",builder(e){return e.options(zn)},async handler(e){let o=e.rpc,t=e.configPath??await Fn(e.configPath),r=await On(),n=await In(),s=await jn(t);if(!e.rpc){console.log(j.gray("Cleaning devnode cache"));let a=Bn();Mn(Wn.join(a,".foundry","anvil","tmp"),{recursive:!0,force:!0}),kn(["--block-time","1","--block-base-fee-per-gas","0"]),o="http://127.0.0.1:8545"}let d=new Rn(Date.now());Pn.watch([t,r,n],{ignoreInitial:!0}).on("all",async(a,m)=>{m.includes(t)&&(console.log(j.blue("Config changed, queuing deploy\u2026")),d.next(Date.now())),(m.includes(r)||m.includes(n))&&(m.includes(s.codegenDirectory)||(console.log(j.blue("Contracts changed, queuing deploy\u2026")),d.next(Date.now())))});let i=e.worldAddress;d.pipe($n(200),En(async a=>{i&&console.log(j.blue("Rebuilding and upgrading world\u2026"));try{let m=await R({...e,configPath:t,rpc:o,skipBuild:!1,printConfig:!1,profile:void 0,saveDeployment:!0,worldAddress:i,srcDir:r});return i=m.address,a<d.value?d.next(d.value):console.log(j.gray(`
21
- Waiting for file changes\u2026
22
- `)),m}catch(m){console.error(j.bgRed(j.whiteBright(`
23
- Error while attempting deploy
24
- `))),console.error(m),console.log(j.gray(`
25
- Waiting for file changes\u2026
26
- `))}}),Hn(Nn)).subscribe()}},Co=Un;var Um=[ao,de,me,Vn,pe,fe,lo,yo,uo,So,Co,_n];export{Um as commands};
27
- //# sourceMappingURL=commands-GPZ5M7TR.js.map