@latticexyz/cli 2.0.0-main-20ffc95f → 2.0.0-main-252a1852
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/dist/commands-A7SMYXOO.js +36 -0
- package/dist/commands-A7SMYXOO.js.map +1 -0
- package/dist/mud.js +1 -1
- package/package.json +12 -12
- package/src/build.ts +8 -5
- package/src/commands/build.ts +2 -3
- package/src/commands/dev-contracts.ts +3 -4
- package/src/commands/tablegen.ts +2 -2
- package/src/commands/trace.ts +5 -4
- package/src/commands/worldgen.ts +7 -6
- package/src/deploy/common.ts +4 -2
- package/src/runDeploy.ts +4 -4
- package/dist/commands-EJAOLM32.js +0 -36
- package/dist/commands-EJAOLM32.js.map +0 -1
package/src/commands/tablegen.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import type { CommandModule } from "yargs";
|
|
3
3
|
import { loadConfig } from "@latticexyz/config/node";
|
|
4
|
-
import { StoreConfig } from "@latticexyz/store";
|
|
4
|
+
import { Store as StoreConfig } from "@latticexyz/store/config/v2";
|
|
5
5
|
import { tablegen } from "@latticexyz/store/codegen";
|
|
6
6
|
import { getRemappings, getSrcDirectory } from "@latticexyz/common/foundry";
|
|
7
7
|
|
|
@@ -25,7 +25,7 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
25
25
|
const srcDir = await getSrcDirectory();
|
|
26
26
|
const remappings = await getRemappings();
|
|
27
27
|
|
|
28
|
-
await tablegen(config, path.join(srcDir, config.
|
|
28
|
+
await tablegen(config, path.join(srcDir, config.codegen.outputDirectory), remappings);
|
|
29
29
|
|
|
30
30
|
process.exit(0);
|
|
31
31
|
},
|
package/src/commands/trace.ts
CHANGED
|
@@ -5,20 +5,20 @@ import { ethers } from "ethers";
|
|
|
5
5
|
import { loadConfig } from "@latticexyz/config/node";
|
|
6
6
|
import { MUDError } from "@latticexyz/common/errors";
|
|
7
7
|
import { cast, getRpcUrl, getSrcDirectory } from "@latticexyz/common/foundry";
|
|
8
|
-
import {
|
|
9
|
-
import { resolveWorldConfig, WorldConfig } from "@latticexyz/world";
|
|
8
|
+
import { resolveWorldConfig } from "@latticexyz/world";
|
|
10
9
|
import IBaseWorldAbi from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json" assert { type: "json" };
|
|
11
10
|
import worldConfig from "@latticexyz/world/mud.config";
|
|
12
11
|
import { resourceToHex } from "@latticexyz/common";
|
|
13
12
|
import { getExistingContracts } from "../utils/getExistingContracts";
|
|
14
13
|
import { createClient, http } from "viem";
|
|
15
14
|
import { getChainId } from "viem/actions";
|
|
15
|
+
import { World as WorldConfig, worldToV1 } from "@latticexyz/world/config/v2";
|
|
16
16
|
|
|
17
17
|
// TODO account for multiple namespaces (https://github.com/latticexyz/mud/issues/994)
|
|
18
18
|
const systemsTableId = resourceToHex({
|
|
19
19
|
type: "system",
|
|
20
20
|
namespace: worldConfig.namespace,
|
|
21
|
-
name: worldConfig.tables.
|
|
21
|
+
name: worldConfig.tables.world__Systems.name,
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
type Options = {
|
|
@@ -59,7 +59,8 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
59
59
|
const existingContracts = getExistingContracts(srcDir);
|
|
60
60
|
|
|
61
61
|
// Load the config
|
|
62
|
-
const
|
|
62
|
+
const configV2 = (await loadConfig(configPath)) as WorldConfig;
|
|
63
|
+
const mudConfig = worldToV1(configV2);
|
|
63
64
|
|
|
64
65
|
const resolvedConfig = resolveWorldConfig(
|
|
65
66
|
mudConfig,
|
package/src/commands/worldgen.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { CommandModule } from "yargs";
|
|
2
2
|
import { loadConfig } from "@latticexyz/config/node";
|
|
3
|
-
import {
|
|
4
|
-
import { WorldConfig } from "@latticexyz/world";
|
|
3
|
+
import { World as WorldConfig } from "@latticexyz/world/config/v2";
|
|
5
4
|
import { worldgen } from "@latticexyz/world/node";
|
|
6
5
|
import { getSrcDirectory } from "@latticexyz/common/foundry";
|
|
7
6
|
import path from "path";
|
|
@@ -12,7 +11,7 @@ type Options = {
|
|
|
12
11
|
configPath?: string;
|
|
13
12
|
clean?: boolean;
|
|
14
13
|
srcDir?: string;
|
|
15
|
-
config?:
|
|
14
|
+
config?: WorldConfig;
|
|
16
15
|
};
|
|
17
16
|
|
|
18
17
|
const commandModule: CommandModule<Options, Options> = {
|
|
@@ -43,12 +42,14 @@ export async function worldgenHandler(args: Options) {
|
|
|
43
42
|
const existingContracts = getExistingContracts(srcDir);
|
|
44
43
|
|
|
45
44
|
// Load the config
|
|
46
|
-
const mudConfig = args.config ?? ((await loadConfig(args.configPath)) as
|
|
45
|
+
const mudConfig = args.config ?? ((await loadConfig(args.configPath)) as WorldConfig);
|
|
47
46
|
|
|
48
|
-
const outputBaseDirectory = path.join(srcDir, mudConfig.
|
|
47
|
+
const outputBaseDirectory = path.join(srcDir, mudConfig.codegen.outputDirectory);
|
|
49
48
|
|
|
50
49
|
// clear the worldgen directory
|
|
51
|
-
if (args.clean)
|
|
50
|
+
if (args.clean) {
|
|
51
|
+
rmSync(path.join(outputBaseDirectory, mudConfig.codegen.worldgenDirectory), { recursive: true, force: true });
|
|
52
|
+
}
|
|
52
53
|
|
|
53
54
|
// generate new interfaces
|
|
54
55
|
await worldgen(mudConfig, existingContracts, outputBaseDirectory);
|
package/src/deploy/common.ts
CHANGED
|
@@ -6,6 +6,8 @@ import IModuleAbi from "@latticexyz/world-modules/out/IModule.sol/IModule.abi.js
|
|
|
6
6
|
import { Tables, configToTables } from "./configToTables";
|
|
7
7
|
import { StoreConfig, helloStoreEvent } from "@latticexyz/store";
|
|
8
8
|
import { WorldConfig, helloWorldEvent } from "@latticexyz/world";
|
|
9
|
+
import { storeToV1 } from "@latticexyz/store/config/v2";
|
|
10
|
+
import { worldToV1 } from "@latticexyz/world/config/v2";
|
|
9
11
|
|
|
10
12
|
export const salt = padHex("0x", { size: 32 });
|
|
11
13
|
|
|
@@ -13,8 +15,8 @@ export const salt = padHex("0x", { size: 32 });
|
|
|
13
15
|
export const contractSizeLimit = parseInt("6000", 16);
|
|
14
16
|
|
|
15
17
|
// TODO: add `as const` to mud config so these get more strongly typed (blocked by current config parsing not using readonly)
|
|
16
|
-
export const storeTables = configToTables(storeConfig);
|
|
17
|
-
export const worldTables = configToTables(worldConfig);
|
|
18
|
+
export const storeTables = configToTables(storeToV1(storeConfig));
|
|
19
|
+
export const worldTables = configToTables(worldToV1(worldConfig));
|
|
18
20
|
|
|
19
21
|
export const worldDeployEvents = [helloStoreEvent, helloWorldEvent] as const;
|
|
20
22
|
|
package/src/runDeploy.ts
CHANGED
|
@@ -5,8 +5,7 @@ import { deploy } from "./deploy/deploy";
|
|
|
5
5
|
import { createWalletClient, http, Hex, isHex } from "viem";
|
|
6
6
|
import { privateKeyToAccount } from "viem/accounts";
|
|
7
7
|
import { loadConfig } from "@latticexyz/config/node";
|
|
8
|
-
import {
|
|
9
|
-
import { WorldConfig } from "@latticexyz/world";
|
|
8
|
+
import { World as WorldConfig, worldToV1 } from "@latticexyz/world/config/v2";
|
|
10
9
|
import { getOutDirectory, getRpcUrl, getSrcDirectory } from "@latticexyz/common/foundry";
|
|
11
10
|
import chalk from "chalk";
|
|
12
11
|
import { MUDError } from "@latticexyz/common/errors";
|
|
@@ -57,7 +56,8 @@ export async function runDeploy(opts: DeployOptions): Promise<WorldDeploy> {
|
|
|
57
56
|
|
|
58
57
|
const profile = opts.profile ?? process.env.FOUNDRY_PROFILE;
|
|
59
58
|
|
|
60
|
-
const
|
|
59
|
+
const configV2 = (await loadConfig(opts.configPath)) as WorldConfig;
|
|
60
|
+
const config = worldToV1(configV2);
|
|
61
61
|
if (opts.printConfig) {
|
|
62
62
|
console.log(chalk.green("\nResolved config:\n"), JSON.stringify(config, null, 2));
|
|
63
63
|
}
|
|
@@ -74,7 +74,7 @@ export async function runDeploy(opts: DeployOptions): Promise<WorldDeploy> {
|
|
|
74
74
|
|
|
75
75
|
// Run build
|
|
76
76
|
if (!opts.skipBuild) {
|
|
77
|
-
await build({ config, srcDir, foundryProfile: profile });
|
|
77
|
+
await build({ config: configV2, srcDir, foundryProfile: profile });
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
const privateKey = process.env.PRIVATE_KEY as Hex;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import{a as J}from"./chunk-QXUPZVZL.js";import ms from"@latticexyz/gas-report";import ps from"@latticexyz/abi-ts";import{loadConfig as Ko}from"@latticexyz/config/node";import{getSrcDirectory as Jo}from"@latticexyz/common/foundry";import{existsSync as $o,readFileSync as Wo,writeFileSync as Ho}from"node:fs";import ae from"node:path";import{tablegen as Eo}from"@latticexyz/store/codegen";import{worldgen as No}from"@latticexyz/world/node";import{forge as zo,getForgeConfig as Lo,getRemappings as Uo}from"@latticexyz/common/foundry";import Ro from"glob";import{basename as Mo}from"path";function I(e){return Ro.sync(`${e}/**/*.sol`).map(o=>({path:o,basename:Mo(o,".sol")}))}import he from"debug";var M=he("mud:cli"),Fo=he("mud:cli");M.log=console.debug.bind(console);Fo.log=console.error.bind(console);import{execa as Vo}from"execa";var _o=M.extend("runDeploy");async function q({config:e,srcDir:o,foundryProfile:r=process.env.FOUNDRY_PROFILE}){let t=ae.join(o,e.codegenDirectory),n=await Uo(r);await Promise.all([Eo(e,t,n),No(e,I(o),t)]);let s=await Lo(r);if(s.cache){let i=ae.join(s.cache_path,"solidity-files-cache.json");if($o(i)){_o("Unsetting cached content hash of IWorld.sol to force it to regenerate");let a=JSON.parse(Wo(i,"utf8")),m=ae.join(t,"world","IWorld.sol");a.files[m].contentHash="",Ho(i,JSON.stringify(a,null,2))}}await zo(["build"],{profile:r}),await Vo("mud",["abi-ts"],{stdio:"inherit"})}var qo={command:"build",describe:"Build contracts and generate MUD artifacts (table libraries, world interface, ABI)",builder(e){return e.options({configPath:{type:"string",desc:"Path to the config file"},profile:{type:"string",desc:"The foundry profile to use"}})},async handler({configPath:e,profile:o}){let r=await Ko(e),t=await Jo();await q({config:r,srcDir:t,foundryProfile:o}),process.exit(0)}},we=qo;import{rmSync as Yo}from"fs";import{homedir as Go}from"os";import Zo from"path";import{execa as Qo}from"execa";var Xo={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=Go();Yo(Zo.join(o,".foundry","anvil","tmp"),{recursive:!0,force:!0});let r=["-b",String(e),"--block-base-fee-per-gas","0"];console.log(`Running: anvil ${r.join(" ")}`);let t=Qo("anvil",r,{stdio:["inherit","inherit","inherit"]});process.on("SIGINT",()=>{console.log(`
|
|
2
|
-
gracefully shutting down from SIGINT (Crtl-C)`),t.kill(),process.exit()}),await t}},xe=Xo;import{FaucetServiceDefinition as et}from"@latticexyz/services/faucet";import{createChannel as ot,createClient as tt}from"nice-grpc-web";import Se from"chalk";import{NodeHttpTransport as rt}from"@improbable-eng/grpc-web-node-http-transport";function nt(e){return tt(et,ot(e,rt()))}var st={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:r}){let t=nt(o);e&&(console.log(Se.yellow("Dripping to",r)),await t.dripDev({address:r}),console.log(Se.yellow("Success"))),process.exit(0)}},Ce=st;var at={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)}},De=at;import it from"path";import{loadConfig as ct}from"@latticexyz/config/node";import{tablegen as dt}from"@latticexyz/store/codegen";import{getRemappings as lt,getSrcDirectory as mt}from"@latticexyz/common/foundry";var pt={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 ct(e),r=await mt(),t=await lt();await dt(o,it.join(r,o.codegenDirectory),t),process.exit(0)}},ve=pt;import fe from"node:path";import{existsSync as Qr,mkdirSync as Xr,readFileSync as en,writeFileSync as ye}from"node:fs";import{getBalance as ut,getBytecode as gt,sendRawTransaction as bt,sendTransaction as Te,waitForTransactionReceipt as Ae}from"viem/actions";var A={gasPrice:1e11,gasLimit:1e5,signerAddress:"3fab184622dc19b6109349b94811493bf2a45362",transaction:"f8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222",address:"4e59b44847b379578588920ca78fbf26c0b4956c",bytecode:"604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"};var l=M.extend("deploy"),yt=M.extend("deploy");l.log=console.debug.bind(console);yt.log=console.error.bind(console);var R=`0x${A.address}`,ke=`0x${A.bytecode}`;async function Ie(e){let o=await gt(e,{address:R});if(o)return l("found CREATE2 deployer at",R),o!==ke&&console.warn(`
|
|
3
|
-
\u26A0\uFE0F Bytecode for deployer at ${R} did not match the expected CREATE2 bytecode. You may have unexpected results.
|
|
4
|
-
`),R;let r=BigInt(A.gasLimit)*BigInt(A.gasPrice),t=await ut(e,{address:`0x${A.signerAddress}`}),n=r-t;if(n>0){l("sending gas for CREATE2 deployer to signer at",A.signerAddress);let a=await Te(e,{chain:e.chain??null,to:`0x${A.signerAddress}`,value:n}),m=await Ae(e,{hash:a});if(m.status!=="success")throw console.error("failed to send gas to deployer signer",m),new Error("failed to send gas to deployer signer")}l("deploying CREATE2 deployer at",R);let s=await bt(e,{serializedTransaction:`0x${A.transaction}`}).catch(a=>{if(String(a).includes("only replay-protected (EIP-155) transactions allowed over RPC"))return console.warn(`
|
|
5
|
-
\u26A0\uFE0F Your chain or RPC does not allow for non EIP-155 signed transactions, so your deploys will not be determinstic and contract addresses may change between deploys.
|
|
6
|
-
|
|
7
|
-
We recommend running your chain's node with \`--rpc.allow-unprotected-txs\` to enable determinstic deployments.
|
|
8
|
-
`),l("deploying CREATE2 deployer"),Te(e,{chain:e.chain??null,data:ke});throw a}),i=await Ae(e,{hash:s});if(!i.contractAddress)throw new Error("Deploy receipt did not have contract address, was the deployer not deployed?");return i.contractAddress!==R&&console.warn(`
|
|
9
|
-
\u26A0\uFE0F CREATE2 deployer created at ${i.contractAddress} does not match the CREATE2 determinstic deployer we expected (${R})`),i.contractAddress}import{waitForTransactionReceipt as Nt}from"viem/actions";import Re from"@latticexyz/world/out/AccessManagementSystem.sol/AccessManagementSystem.json"assert{type:"json"};import Me from"@latticexyz/world/out/BalanceTransferSystem.sol/BalanceTransferSystem.json"assert{type:"json"};import Fe from"@latticexyz/world/out/BatchCallSystem.sol/BatchCallSystem.json"assert{type:"json"};import $e from"@latticexyz/world/out/RegistrationSystem.sol/RegistrationSystem.json"assert{type:"json"};import We from"@latticexyz/world/out/InitModule.sol/InitModule.json"assert{type:"json"};import Mt from"@latticexyz/world/out/InitModule.sol/InitModule.abi.json"assert{type:"json"};import He from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.json"assert{type:"json"};import Ft from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json"assert{type:"json"};import{getCreate2Address as $,encodeDeployData as Ee,size as W}from"viem";import{padHex as wt}from"viem";import xt from"@latticexyz/store/mud.config";import St from"@latticexyz/world/mud.config";import Ct from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import Dt from"@latticexyz/world-modules/out/IModule.sol/IModule.abi.json"assert{type:"json"};import{resourceToHex as ht}from"@latticexyz/common";import{resolveUserTypes as Pe}from"@latticexyz/store";function L(e){let o={...e.userTypes,...Object.fromEntries(Object.entries(e.enums).map(([r])=>[r,{internalType:"uint8"}]))};return Object.fromEntries(Object.entries(e.tables).map(([r,t])=>[`${e.namespace}_${r}`,{namespace:e.namespace,name:t.name,tableId:ht({type:t.offchainOnly?"offchainTable":"table",namespace:e.namespace,name:t.name}),keySchema:Pe(t.keySchema,o),valueSchema:Pe(t.valueSchema,o)}]))}import{helloStoreEvent as vt}from"@latticexyz/store";import{helloWorldEvent as Tt}from"@latticexyz/world";var v=wt("0x",{size:32}),U=parseInt("6000",16),F=L(xt),T=L(St),Y=[vt,Tt],S=[...Ct,...Dt],Be=["2.0.0"],Oe=["2.0.0"];import{waitForTransactionReceipt as jt}from"viem/actions";import{concatHex as At,getCreate2Address as kt}from"viem";import{getBytecode as It}from"viem/actions";import{sendTransaction as Pt}from"@latticexyz/common";import Bt from"p-retry";import{wait as Ot}from"@latticexyz/common/utils";async function je({client:e,deployerAddress:o,bytecode:r,deployedBytecodeSize:t,label:n="contract"}){if(r.includes("__$"))throw new Error(`Found unlinked public library in ${n} bytecode`);let s=kt({from:o,salt:v,bytecode:r});return await It(e,{address:s,blockTag:"pending"})?(l("found",n,"at",s),[]):(t>U?console.warn(`
|
|
10
|
-
Bytecode for ${n} (${t} bytes) is over the contract size limit (${U} bytes). Run \`forge build --sizes\` for more info.
|
|
11
|
-
`):t>U*.95&&console.warn(`
|
|
12
|
-
Bytecode for ${n} (${t} bytes) is almost over the contract size limit (${U} bytes). Run \`forge build --sizes\` for more info.
|
|
13
|
-
`),l("deploying",n,"at",s),[await Bt(()=>Pt(e,{chain:e.chain??null,to:o,data:At([v,r])}),{retries:3,onFailedAttempt:async a=>{let m=a.attemptNumber*500;l(`failed to deploy ${n}, retrying in ${m}ms...`),await Ot(m)}})])}import{uniqueBy as Rt}from"@latticexyz/common/utils";async function P({client:e,deployerAddress:o,contracts:r}){let t=Rt(r,s=>s.bytecode),n=(await Promise.all(t.map(s=>je({client:e,deployerAddress:o,...s})))).flat();if(n.length){l("waiting for contracts");for(let s of n)await jt(e,{hash:s})}return n}async function G(e,o){let r=W(Re.deployedBytecode.object),t=Re.bytecode.object,n=$({from:o,bytecode:t,salt:v}),s=W(Me.deployedBytecode.object),i=Me.bytecode.object,a=$({from:o,bytecode:i,salt:v}),m=W(Fe.deployedBytecode.object),c=Fe.bytecode.object,f=$({from:o,bytecode:c,salt:v}),y=W($e.deployedBytecode.object),x=$e.bytecode.object,C=$({from:o,bytecode:x,salt:v}),d=W(We.deployedBytecode.object),u=Ee({bytecode:We.bytecode.object,abi:Mt,args:[n,a,f,C]}),w=$({from:o,bytecode:u,salt:v}),g=W(He.deployedBytecode.object),D=Ee({bytecode:He.bytecode.object,abi:Ft,args:[w]}),p=$({from:o,bytecode:D,salt:v});return await P({client:e,deployerAddress:o,contracts:[{bytecode:t,deployedBytecodeSize:r,label:"access management system"},{bytecode:i,deployedBytecodeSize:s,label:"balance transfer system"},{bytecode:c,deployedBytecodeSize:m,label:"batch call system"},{bytecode:x,deployedBytecodeSize:y,label:"core registration system"},{bytecode:u,deployedBytecodeSize:d,label:"core module"},{bytecode:D,deployedBytecodeSize:g,label:"world factory"}]}),p}import zt from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json"assert{type:"json"};import{writeContract as Lt}from"@latticexyz/common";import{AbiEventSignatureNotFoundError as $t,decodeEventLog as Wt,hexToString as Ne,parseAbi as Ht}from"viem";import{isDefined as Et}from"@latticexyz/common/utils";function Z(e){let o=e.map(i=>{try{return{...i,...Wt({strict:!0,abi:Ht(Y),topics:i.topics,data:i.data})}}catch(a){if(a instanceof $t)return;throw a}}).filter(Et),{address:r,deployBlock:t,worldVersion:n,storeVersion:s}=o.reduce((i,a)=>({...i,address:a.address,deployBlock:a.blockNumber,...a.eventName==="HelloWorld"?{worldVersion:Ne(a.args.worldVersion).replace(/\0+$/,"")}:null,...a.eventName==="HelloStore"?{storeVersion:Ne(a.args.storeVersion).replace(/\0+$/,"")}:null}),{});if(r==null)throw new Error("could not find world address");if(t==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:r,deployBlock:t,worldVersion:n,storeVersion:s}}async function ze(e,o,r){let t=await G(e,o);l("deploying world");let n=await Lt(e,{chain:e.chain??null,address:t,abi:zt,functionName:"deployWorld",args:[r]});l("waiting for world deploy");let s=await Nt(e,{hash:n});if(s.status!=="success")throw console.error("world deploy failed",s),new Error("world deploy failed");let i=Z(s.logs.map(a=>a));return l("deployed world to",i.address,"at block",i.deployBlock),{...i,stateBlock:i.deployBlock}}import{resourceToLabel as ie,writeContract as Yt}from"@latticexyz/common";import{valueSchemaToFieldLayoutHex as Gt,keySchemaToHex as Zt,valueSchemaToHex as Qt}from"@latticexyz/protocol-parser/internal";import{parseAbiItem as Ut,decodeAbiParameters as Le,parseAbiParameters as Ue}from"viem";import{hexToResource as Vt}from"@latticexyz/common";import{storeSetRecordEvent as _t}from"@latticexyz/store";import{getLogs as Kt}from"viem/actions";import{decodeKey as Jt,decodeValueArgs as qt,hexToSchema as Ve}from"@latticexyz/protocol-parser/internal";async function _e({client:e,worldDeploy:o}){l("looking up tables for",o.address);let t=(await Kt(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:Ut(_t),args:{tableId:F.store_Tables.tableId}})).map(n=>{let{tableId:s}=Jt(F.store_Tables.keySchema,n.args.keyTuple),{namespace:i,name:a}=Vt(s),m=qt(F.store_Tables.valueSchema,n.args),c=Ve(m.keySchema),f=Ve(m.valueSchema),y=Le(Ue("string[]"),m.abiEncodedKeyNames)[0],x=Le(Ue("string[]"),m.abiEncodedFieldNames)[0],C=[...f.staticFields,...f.dynamicFields],d=Object.fromEntries(c.staticFields.map((w,g)=>[y[g],w])),u=Object.fromEntries(C.map((w,g)=>[x[g],w]));return{namespace:i,name:a,tableId:s,keySchema:d,valueSchema:u}});return l("found",t.length,"tables for",o.address),t}import Xt from"p-retry";import{wait as er}from"@latticexyz/common/utils";async function Ke({client:e,worldDeploy:o,tables:r}){let n=(await _e({client:e,worldDeploy:o})).map(a=>a.tableId),s=r.filter(a=>n.includes(a.tableId));s.length&&l("existing tables",s.map(ie).join(", "));let i=r.filter(a=>!n.includes(a.tableId));return i.length?(l("registering tables",i.map(ie).join(", ")),await Promise.all(i.map(a=>Xt(()=>Yt(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"registerTable",args:[a.tableId,Gt(a.valueSchema),Zt(a.keySchema),Qt(a.valueSchema),Object.keys(a.keySchema),Object.keys(a.valueSchema)]}),{retries:3,onFailedAttempt:async m=>{let c=m.attemptNumber*500;l(`failed to register table ${ie(a)}, retrying in ${c}ms...`),await er(c)}})))):[]}import{getAddress as O}from"viem";import{writeContract as ce,resourceToLabel as V}from"@latticexyz/common";import{parseAbiItem as or}from"viem";import{getLogs as tr}from"viem/actions";import{storeSpliceStaticDataEvent as rr}from"@latticexyz/store";async function Q({client:e,worldDeploy:o}){l("looking up resource IDs for",o.address);let t=(await tr(e,{strict:!0,address:o.address,fromBlock:o.deployBlock,toBlock:o.stateBlock,event:or(rr),args:{tableId:F.store_ResourceIds.tableId}})).map(n=>n.args.keyTuple[0]);return l("found",t.length,"resource IDs for",o.address),t}import{hexToResource as hr,resourceToLabel as wr}from"@latticexyz/common";import{decodeValueArgs as nr,encodeKey as sr}from"@latticexyz/protocol-parser/internal";import{readContract as ar}from"viem/actions";async function B({client:e,worldDeploy:o,table:r,key:t}){let[n,s,i]=await ar(e,{blockNumber:o.stateBlock,address:o.address,abi:S,functionName:"getRecord",args:[r.tableId,sr(r.keySchema,t)]});return nr(r.valueSchema,{staticData:n,encodedLengths:s,dynamicData:i})}import{toFunctionSelector as ir,parseAbiItem as cr}from"viem";import{storeSetRecordEvent as dr}from"@latticexyz/store";import{getLogs as lr}from"viem/actions";import{decodeValueArgs as mr}from"@latticexyz/protocol-parser/internal";import{hexToResource as pr}from"@latticexyz/common";async function X({client:e,worldDeploy:o}){l("looking up function signatures for",o.address);let t=(await lr(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:cr(dr),args:{tableId:T.world_FunctionSignatures.tableId}})).map(s=>mr(T.world_FunctionSignatures.valueSchema,s.args).functionSignature);return l("found",t.length,"function signatures for",o.address),await Promise.all(t.map(async s=>{let i=ir(s),{systemId:a,systemFunctionSelector:m}=await B({client:e,worldDeploy:o,table:T.world_FunctionSelectors,key:{worldFunctionSelector:i}}),{namespace:c,name:f}=pr(a),y=c===""?s:s.replace(`${c}_${f}_`,"");return{signature:s,selector:i,systemId:a,systemFunctionSignature:y,systemFunctionSelector:m}}))}import{parseAbiItem as fr,getAddress as yr}from"viem";import{storeSpliceStaticDataEvent as ur}from"@latticexyz/store";import{getLogs as gr}from"viem/actions";import{decodeKey as br}from"@latticexyz/protocol-parser/internal";async function ee({client:e,worldDeploy:o}){l("looking up resource access for",o.address);let t=(await gr(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:fr(ur),args:{tableId:T.world_ResourceAccess.tableId}})).map(s=>br(T.world_ResourceAccess.keySchema,s.args.keyTuple)),n=(await Promise.all(t.map(async s=>[s,await B({client:e,worldDeploy:o,table:T.world_ResourceAccess,key:s})]))).filter(([,s])=>s.access).map(([s])=>({resourceId:s.resourceId,address:yr(s.caller)}));return l("found",n.length,"resource<>address access pairs"),n}async function Je({client:e,worldDeploy:o}){let[r,t,n]=await Promise.all([Q({client:e,worldDeploy:o}),X({client:e,worldDeploy:o}),ee({client:e,worldDeploy:o})]),s=r.map(hr).filter(i=>i.type==="system");return l("looking up systems",s.map(wr).join(", ")),await Promise.all(s.map(async i=>{let{system:a,publicAccess:m}=await B({client:e,worldDeploy:o,table:T.world_Systems,key:{systemId:i.resourceId}}),c=t.filter(f=>f.systemId===i.resourceId);return{address:a,namespace:i.namespace,name:i.name,systemId:i.resourceId,allowAll:m,allowedAddresses:n.filter(({resourceId:f})=>f===i.resourceId).map(({address:f})=>f),functions:c}}))}import{wait as de}from"@latticexyz/common/utils";import le from"p-retry";async function qe({client:e,deployerAddress:o,libraries:r,worldDeploy:t,systems:n}){let[s,i]=await Promise.all([Je({client:e,worldDeploy:t}),ee({client:e,worldDeploy:t})]),a=n.filter(p=>s.some(b=>b.systemId===p.systemId&&O(b.address)===O(p.prepareDeploy(o,r).address)));a.length&&l("existing systems",a.map(V).join(", "));let m=a.map(p=>p.systemId),c=n.filter(p=>!m.includes(p.systemId));if(!c.length)return[];let f=c.filter(p=>s.some(b=>b.systemId===p.systemId&&O(b.address)!==O(p.prepareDeploy(o,r).address)));f.length&&l("upgrading systems",f.map(V).join(", "));let y=c.filter(p=>!s.some(b=>b.systemId===p.systemId));y.length&&l("registering new systems",y.map(V).join(", ")),await P({client:e,deployerAddress:o,contracts:c.map(p=>({bytecode:p.prepareDeploy(o,r).bytecode,deployedBytecodeSize:p.deployedBytecodeSize,label:`${V(p)} system`}))});let x=await Promise.all(c.map(p=>le(()=>ce(e,{chain:e.chain??null,address:t.address,abi:S,functionName:"registerSystem",args:[p.systemId,p.prepareDeploy(o,r).address,p.allowAll]}),{retries:3,onFailedAttempt:async b=>{let h=b.attemptNumber*500;l(`failed to register system ${V(p)}, retrying in ${h}ms...`),await de(h)}}))),C=n.map(p=>p.systemId),d=i.filter(({resourceId:p})=>C.includes(p)),u=[...n.flatMap(p=>p.allowedAddresses.map(b=>({resourceId:p.systemId,address:b}))),...n.flatMap(p=>p.allowedSystemIds.map(b=>({resourceId:p.systemId,address:s.find(h=>h.systemId===b)?.address??n.find(h=>h.systemId===b)?.prepareDeploy(o,r).address})).filter(b=>b.address!=null))],w=u.filter(p=>!d.some(({resourceId:b,address:h})=>b===p.resourceId&&O(h)===O(p.address))),g=d.filter(p=>!u.some(({resourceId:b,address:h})=>b===p.resourceId&&O(h)===O(p.address)));g.length&&l("revoking",g.length,"access grants"),w.length&&l("adding",w.length,"access grants");let D=await Promise.all([...g.map(p=>le(()=>ce(e,{chain:e.chain??null,address:t.address,abi:S,functionName:"revokeAccess",args:[p.resourceId,p.address]}),{retries:3,onFailedAttempt:async b=>{let h=b.attemptNumber*500;l(`failed to revoke access, retrying in ${h}ms...`),await de(h)}})),...w.map(p=>le(()=>ce(e,{chain:e.chain??null,address:t.address,abi:S,functionName:"grantAccess",args:[p.resourceId,p.address]}),{retries:3,onFailedAttempt:async b=>{let h=b.attemptNumber*500;l(`failed to grant access, retrying in ${h}ms...`),await de(h)}}))]);return[...x,...D]}import{waitForTransactionReceipt as io}from"viem/actions";import{getAddress as xr,parseAbi as Sr}from"viem";import{getBlockNumber as Cr,getLogs as Dr}from"viem/actions";var Ye=new Map;async function Ge(e,o){let r=xr(o),t=Ye.get(r);if(t!=null)return t;l("looking up world deploy for",r);let n=await Cr(e),s=await Dr(e,{strict:!0,address:r,events:Sr(Y),fromBlock:"earliest",toBlock:n});return t={...Z(s),stateBlock:n},Ye.set(r,t),l("found world deploy for",r,"at block",t.deployBlock),t}import{hexToResource as vr,writeContract as Ze}from"@latticexyz/common";import Qe from"p-retry";import{wait as Xe}from"@latticexyz/common/utils";async function eo({client:e,worldDeploy:o,functions:r}){let t=await X({client:e,worldDeploy:o}),n=Object.fromEntries(t.map(a=>[a.selector,a])),s=r.filter(a=>n[a.selector]),i=r.filter(a=>!s.includes(a));if(s.length){l("functions already registered:",s.map(m=>m.signature).join(", "));let a=s.filter(m=>m.systemId!==n[m.selector]?.systemId);a.length&&console.warn("found",a.length,"functions already registered but pointing at a different system ID:",a.map(m=>m.signature).join(", "))}return i.length?(l("registering functions:",i.map(a=>a.signature).join(", ")),Promise.all(i.map(a=>{let{namespace:m}=vr(a.systemId);return m===""?Qe(()=>Ze(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"registerRootFunctionSelector",args:[a.systemId,a.systemFunctionSignature,a.systemFunctionSignature]}),{retries:3,onFailedAttempt:async c=>{let f=c.attemptNumber*500;l(`failed to register function ${a.signature}, retrying in ${f}ms...`),await Xe(f)}}):Qe(()=>Ze(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"registerFunctionSelector",args:[a.systemId,a.systemFunctionSignature]}),{retries:3,onFailedAttempt:async c=>{let f=c.attemptNumber*500;l(`failed to register function ${a.signature}, retrying in ${f}ms...`),await Xe(f)}})}))):[]}import{BaseError as Tr}from"viem";import{writeContract as oo}from"@latticexyz/common";import{isDefined as Ar,wait as kr}from"@latticexyz/common/utils";import Ir from"p-retry";async function to({client:e,deployerAddress:o,libraries:r,worldDeploy:t,modules:n}){return n.length?(await P({client:e,deployerAddress:o,contracts:n.map(s=>({bytecode:s.prepareDeploy(o,r).bytecode,deployedBytecodeSize:s.deployedBytecodeSize,label:`${s.name} module`}))}),l("installing modules:",n.map(s=>s.name).join(", ")),(await Promise.all(n.map(s=>Ir(async()=>{try{let i=s.prepareDeploy(o,r).address;return s.installAsRoot?await oo(e,{chain:e.chain??null,address:t.address,abi:S,functionName:"installRootModule",args:[i,s.installData]}):await oo(e,{chain:e.chain??null,address:t.address,abi:S,functionName:"installModule",args:[i,s.installData]})}catch(i){if(i instanceof Tr&&i.message.includes("Module_AlreadyInstalled")){l(`module ${s.name} already installed`);return}throw i}},{retries:3,onFailedAttempt:async i=>{let a=i.attemptNumber*500;l(`failed to install module ${s.name}, retrying in ${a}ms...`),await kr(a)}})))).filter(Ar)):[]}import{getAddress as ro}from"viem";import{hexToResource as no,resourceToHex as so,writeContract as Pr}from"@latticexyz/common";async function ao({client:e,worldDeploy:o,resourceIds:r}){let t=Array.from(new Set(r.map(y=>no(y).namespace))),n=await Q({client:e,worldDeploy:o}),s=new Set(n.map(y=>no(y).namespace));s.size&&l("found",s.size,"existing namespaces:",Array.from(s).map(y=>y===""?"<root>":y).join(", "));let i=t.filter(y=>s.has(y)),m=(await Promise.all(i.map(async y=>{let{owner:x}=await B({client:e,worldDeploy:o,table:T.world_NamespaceOwner,key:{namespaceId:so({type:"namespace",namespace:y,name:""})}});return[y,x]}))).filter(([,y])=>ro(y)!==ro(e.account.address)).map(([y])=>y);if(m.length)throw new Error(`You are attempting to deploy to namespaces you do not own: ${m.join(", ")}`);let c=t.filter(y=>!s.has(y));return c.length>0&&l("registering namespaces",Array.from(c).join(", ")),Promise.all(c.map(y=>Pr(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"registerNamespace",args:[so({namespace:y,type:"namespace",name:""})]})))}import{resourceToLabel as Br}from"@latticexyz/common";import{randomBytes as Or}from"crypto";async function co({client:e,config:o,salt:r,worldAddress:t,deployerAddress:n}){let s=Object.values(o.tables),i=n??await Ie(e);await G(e,i),await P({client:e,deployerAddress:i,contracts:[...o.libraries.map(d=>({bytecode:d.prepareDeploy(i,o.libraries).bytecode,deployedBytecodeSize:d.deployedBytecodeSize,label:`${d.path}:${d.name} library`})),...o.systems.map(d=>({bytecode:d.prepareDeploy(i,o.libraries).bytecode,deployedBytecodeSize:d.deployedBytecodeSize,label:`${Br(d)} system`})),...o.modules.map(d=>({bytecode:d.prepareDeploy(i,o.libraries).bytecode,deployedBytecodeSize:d.deployedBytecodeSize,label:`${d.name} module`}))]});let a=t?await Ge(e,t):await ze(e,i,r??`0x${Or(32).toString("hex")}`);if(!Be.includes(a.storeVersion))throw new Error(`Unsupported Store version: ${a.storeVersion}`);if(!Oe.includes(a.worldVersion))throw new Error(`Unsupported World version: ${a.worldVersion}`);let m=await ao({client:e,worldDeploy:a,resourceIds:[...s.map(d=>d.tableId),...o.systems.map(d=>d.systemId)]});l("waiting for all namespace registration transactions to confirm");for(let d of m)await io(e,{hash:d});let c=await Ke({client:e,worldDeploy:a,tables:s}),f=await qe({client:e,deployerAddress:i,libraries:o.libraries,worldDeploy:a,systems:o.systems}),y=await eo({client:e,worldDeploy:a,functions:o.systems.flatMap(d=>d.functions)}),x=await to({client:e,deployerAddress:i,libraries:o.libraries,worldDeploy:a,modules:o.modules}),C=[...c,...f,...y,...x];l("waiting for all transactions to confirm");for(let d of C)await io(e,{hash:d});return l("deploy complete"),a}import{createWalletClient as on,http as tn,isHex as rn}from"viem";import{privateKeyToAccount as nn}from"viem/accounts";import{loadConfig as sn}from"@latticexyz/config/node";import{getOutDirectory as an,getRpcUrl as cn,getSrcDirectory as dn}from"@latticexyz/common/foundry";import E from"chalk";import{MUDError as bo}from"@latticexyz/common/errors";import Nr from"path";import{resolveWorldConfig as zr}from"@latticexyz/world";import{resourceToHex as pe}from"@latticexyz/common";import{resolveWithContext as Lr}from"@latticexyz/config/library";import{encodeField as Ur}from"@latticexyz/protocol-parser/internal";import{hexToBytes as Vr,bytesToHex as _r,toFunctionSelector as fo,toFunctionSignature as yo}from"viem";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 me}from"viem";function H(e){return Object.entries(e).flatMap(([o,r])=>Object.entries(r).flatMap(([t,n])=>n.map(s=>({path:o,name:t,start:s.start,length:s.length}))))}var lo=[{name:"KeysWithValueModule",abi:oe.abi,bytecode:oe.bytecode.object,placeholders:H(oe.bytecode.linkReferences),deployedBytecodeSize:me(oe.deployedBytecode.object)},{name:"KeysInTableModule",abi:te.abi,bytecode:te.bytecode.object,placeholders:H(te.bytecode.linkReferences),deployedBytecodeSize:me(te.deployedBytecode.object)},{name:"UniqueEntityModule",abi:re.abi,bytecode:re.bytecode.object,placeholders:H(re.bytecode.linkReferences),deployedBytecodeSize:me(re.deployedBytecode.object)}];import{readFileSync as jr}from"fs";import Rr from"path";import{MUDError as ne}from"@latticexyz/common/errors";import{size as Mr}from"viem";function _(e,o,r){let t,n=Rr.join(r,e,o+".json");try{t=JSON.parse(jr(n,"utf8"))}catch{throw new ne(`Error reading file at ${n}`)}let s=t?.bytecode?.object;if(!s)throw new ne(`No bytecode found in ${n}`);let i=t?.deployedBytecode?.object;if(!i)throw new ne(`No deployed bytecode found in ${n}`);let a=t?.abi;if(!a)throw new ne(`No ABI found in ${n}`);let m=H(t?.bytecode?.linkReferences??{});return{abi:a,bytecode:s,placeholders:m,deployedBytecodeSize:Mr(i)}}import{groupBy as Kr}from"@latticexyz/common/utils";import{readFileSync as $r}from"fs";import Wr from"glob";import Fr from"toposort";function mo(e,o,r){let t=Fr(e.flatMap(n=>r(n).map(s=>[o(n),s])));return[...e].sort((n,s)=>t.indexOf(o(n))-t.indexOf(o(s)))}function po(e){let r=Wr.sync(`${e}/**/*.json`,{ignore:"**/*.abi.json"}).map(t=>JSON.parse($r(t,"utf8"))).flatMap(t=>{if(!t.metadata)return[];let n=Object.keys(t.metadata.settings.compilationTarget)[0],s=t.metadata.settings.compilationTarget[n],i=t.bytecode.linkReferences;return Object.entries(i).flatMap(([a,m])=>Object.keys(m).map(c=>({path:a,name:c,dependentPath:n,dependentName:s})))});return mo(r,t=>`${t.path}:${t.name}`,t=>[`${t.dependentPath}:${t.dependentName}`])}import{spliceHex as Hr}from"@latticexyz/common";import{getCreate2Address as Er}from"viem";function se(e,o){return function(t,n){let s=e;for(let i of o){let a=n.find(m=>m.path===i.path&&m.name===i.name);if(!a)throw new Error(`Could not find library for bytecode placeholder ${i.path}:${i.name}`);s=Hr(s,i.start,i.length,a.prepareDeploy(t,n).address)}return{bytecode:s,address:Er({from:t,bytecode:s,salt:v})}}}function uo({config:e,forgeSourceDir:o,forgeOutDir:r}){let t=po(r).map(d=>{let u=_(Nr.basename(d.path),d.name,r);return{path:d.path,name:d.name,abi:u.abi,prepareDeploy:se(u.bytecode,u.placeholders),deployedBytecodeSize:u.deployedBytecodeSize}}),n=L(e),s=I(o).map(({basename:d})=>d),i=zr(e,s),m=_("System.sol","System",r).abi.filter(d=>d.type==="function").map(yo),c=Object.entries(i.systems).map(([d,u])=>{let w=e.namespace,g=u.name,D=pe({type:"system",namespace:w,name:g}),p=_(`${d}.sol`,d,r),b=p.abi.filter(h=>h.type==="function").map(yo).filter(h=>!m.includes(h)).map(h=>{let be=w===""?h:`${w}__${h}`;return{signature:be,selector:fo(be),systemId:D,systemFunctionSignature:h,systemFunctionSelector:fo(h)}});return{namespace:w,name:g,systemId:D,allowAll:u.openAccess,allowedAddresses:u.accessListAddresses,allowedSystemIds:u.accessListSystems.map(h=>pe({type:"system",namespace:w,name:i.systems[h].name})),prepareDeploy:se(p.bytecode,p.placeholders),deployedBytecodeSize:p.deployedBytecodeSize,abi:p.abi,functions:b}}),f=Kr(c,d=>d.systemId),y=Array.from(f.values()).filter(d=>d.length>1).flat();if(y.length){let d=y.map(u=>u.name);throw new Error(`Found systems with overlapping system ID: ${d.join(", ")}.
|
|
14
|
-
|
|
15
|
-
System IDs are generated from the first 16 bytes of the name, so you may need to rename them to avoid the overlap.`)}let x={tableIds:Object.fromEntries(Object.entries(e.tables).map(([d,u])=>[d,Vr(pe({type:u.offchainOnly?"offchainTable":"table",namespace:e.namespace,name:u.name}))]))},C=e.modules.map(d=>{let u=lo.find(g=>g.name===d.name)??_(`${d.name}.sol`,d.name,r),w=d.args.map(g=>Lr(g,x)).map(g=>{let D=g.value instanceof Uint8Array?_r(g.value):g.value;return Ur(g.type,D)});if(w.length>1)throw new Error(`${d.name} module should only have 0-1 args, but had ${w.length} args.`);return{name:d.name,installAsRoot:d.root,installData:w.length===0?"0x":w[0],prepareDeploy:se(u.bytecode,u.placeholders),deployedBytecodeSize:u.deployedBytecodeSize,abi:u.abi}});return{tables:n,systems:c,modules:C,libraries:t}}import{getChainId as ln}from"viem/actions";import{existsSync as Jr}from"fs";import qr from"path";import Yr from"chalk";import{getScriptDirectory as Gr,forge as Zr}from"@latticexyz/common/foundry";async function go(e,o,r,t){let n=qr.join(await Gr(),e+".s.sol");Jr(n)?(console.log(Yr.blue(`Executing post deploy script at ${n}`)),await Zr(["script",e,"--sig","run(address)",o,"--broadcast","--rpc-url",r,"-vvv"],{profile:t})):console.log(`No script at ${n}, skipping post deploy hook`)}var 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"},rpcBatch:{type:"boolean",desc:"Enable batch processing of RPC requests in viem client (defaults to batch size of 100 and wait of 1s)"},deployerAddress:{type:"string",desc:"Deploy using an existing deterministic deployer (https://github.com/Arachnid/deterministic-deployment-proxy)"},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."},salt:{type:"string",desc:"The deployment salt to use. Defaults to a random salt."}};async function N(e){let o=e.salt;if(o!=null&&!rn(o))throw new bo("Expected hex string for salt");let r=e.profile??process.env.FOUNDRY_PROFILE,t=await sn(e.configPath);e.printConfig&&console.log(E.green(`
|
|
16
|
-
Resolved config:
|
|
17
|
-
`),JSON.stringify(t,null,2));let n=e.srcDir??await dn(r),s=await an(r),i=e.rpc??await cn(r);console.log(E.bgBlue(E.whiteBright(`
|
|
18
|
-
Deploying MUD contracts${r?" with profile "+r:""} to RPC ${i}
|
|
19
|
-
`))),e.skipBuild||await q({config:t,srcDir:n,foundryProfile:r});let a=process.env.PRIVATE_KEY;if(!a)throw new bo(`Missing PRIVATE_KEY environment variable.
|
|
20
|
-
Run 'echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" > .env'
|
|
21
|
-
in your contracts directory to use the default anvil private key.`);let m=uo({config:t,forgeSourceDir:n,forgeOutDir:s}),c=on({transport:tn(i,{batch:e.rpcBatch?{batchSize:100,wait:1e3}:void 0}),account:nn(a)});console.log("Deploying from",c.account.address);let f=Date.now(),y=await co({deployerAddress:e.deployerAddress,salt:o,worldAddress:e.worldAddress,client:c,config:m});(e.worldAddress==null||e.alwaysRunPostDeploy)&&await go(t.postDeployScript,y.address,i,r),console.log(E.green("Deployment completed in",(Date.now()-f)/1e3,"seconds"));let x={worldAddress:y.address,blockNumber:Number(y.deployBlock)};if(e.saveDeployment){let C=await ln(c),d=fe.join(t.deploysDirectory,C.toString());Xr(d,{recursive:!0}),ye(fe.join(d,"latest.json"),JSON.stringify(x,null,2)),ye(fe.join(d,Date.now()+".json"),JSON.stringify(x,null,2));let u=[1337,31337],w=Qr(t.worldsFile)?JSON.parse(en(t.worldsFile,"utf-8")):{};w[C]={address:x.worldAddress,blockNumber:u.includes(C)?void 0:x.blockNumber},ye(t.worldsFile,JSON.stringify(w,null,2)),console.log(E.bgGreen(E.whiteBright(`
|
|
22
|
-
Deployment result (written to ${t.worldsFile} and ${d}):
|
|
23
|
-
`)))}return console.log(x),y}var mn={command:"deploy",describe:"Deploy MUD contracts",builder(e){return e.options(k)},async handler(e){try{await N(e)}catch(o){J(o),process.exit(1)}process.exit(0)}},ho=mn;import{loadConfig as pn}from"@latticexyz/config/node";import{worldgen as fn}from"@latticexyz/world/node";import{getSrcDirectory as yn}from"@latticexyz/common/foundry";import wo from"path";import{rmSync as un}from"fs";var gn={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 bn(e),process.exit(0)}};async function bn(e){let o=e.srcDir??await yn(),r=I(o),t=e.config??await pn(e.configPath),n=wo.join(o,t.codegenDirectory);e.clean&&un(wo.join(n,t.worldgenDirectory),{recursive:!0,force:!0}),await fn(t,r,n)}var xo=gn;import K from"chalk";import{readFileSync as Cn,writeFileSync as Dn}from"fs";import ge from"path";import{MUDError as z}from"@latticexyz/common/errors";var So={name:"@latticexyz/cli",version:"2.0.0-next.17",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",toposort:"^2.0.2",typescript:"5.4.2",viem:"2.7.12",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/toposort":"^2.0.6","@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.34.6"}};import vn from"glob";import{ZodError as wn,z as Co}from"zod";var xn=Co.object({MUD_PACKAGES:Co.string().transform(e=>JSON.parse(e))});function Sn(){try{return xn.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/protocol-parser":{"localPath":"packages/protocol-parser"},"@latticexyz/query":{"localPath":"packages/query"},"@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 wn){let{...o}=e.format();console.error(`
|
|
24
|
-
Missing or invalid environment variables:
|
|
25
|
-
|
|
26
|
-
${Object.keys(o).join(`
|
|
27
|
-
`)}
|
|
28
|
-
`),process.exit(1)}throw e}}var ue=Sn().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"],r=o.reduce((n,s)=>e[s]?n+1:n,0);if(r===0)throw new z(`You need to provide one these options: ${o.join(", ")}`);if(r>1)throw new z(`These options are mutually exclusive: ${o.join(", ")}`);e.link||(e.mudVersion=await An(e));let t=vn.sync("**/package.json").filter(n=>!n.includes("node_modules"));for(let n of t)kn(n,e)}catch(o){J(o)}finally{process.exit(0)}}};async function An(e){e.mudVersion==="canary"&&(e.tag="main");let o;try{console.log(K.blue("Fetching available versions")),o=await(await fetch(`https://registry.npmjs.org/${So.name}`)).json()}catch{throw new z("Could not fetch available MUD versions")}if(e.tag){let r=o["dist-tags"][e.tag];if(!r)throw new z(`Could not find npm version with tag "${e.tag}"`);return console.log(K.green(`Latest version with tag ${e.tag}: ${r}`)),r}if(e.commit){let r=e.commit.substring(0,8),t=Object.keys(o.versions).find(n=>n.includes(r));if(!t)throw new z(`Could not find npm version based on commit "${e.commit}"`);return console.log(K.green(`Version from commit ${e.commit}: ${t}`)),t}return e.mudVersion}function kn(e,o){let{link:r}=o,{mudVersion:t}=o,n=In(e),s=Object.keys(ue),i={};for(let c in n.dependencies)s.includes(c)&&(i[c]=n.dependencies[c]);let a={};for(let c in n.devDependencies)s.includes(c)&&(a[c]=n.devDependencies[c]);for(let c in n.dependencies)s.includes(c)&&(n.dependencies[c]=m(c,"dependencies"));for(let c in n.devDependencies)s.includes(c)&&(n.devDependencies[c]=m(c,"devDependencies"));return Dn(e,JSON.stringify(n,null,2)+`
|
|
29
|
-
`),console.log(`Updating ${e}`),Do(i,n.dependencies),Do(a,n.devDependencies),n;function m(c,f){return r&&(t=Pn(e,r,c)),t||n[f][c]}}function In(e){try{let o=Cn(e,"utf8");return JSON.parse(o)}catch{throw new z("Could not read JSON at "+e)}}function Do(e,o){for(let r in e)e[r]!==o[r]&&console.log(`${r}: ${K.red(e[r])} -> ${K.green(o[r])}`)}function Pn(e,o,r){let t=ge.relative(ge.dirname(e),process.cwd());return"link:"+ge.join(t,o,ue[r].localPath)}var vo=Tn;import{anvil as Bn,forge as On,getRpcUrl as jn}from"@latticexyz/common/foundry";import Rn from"chalk";var Mn={...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(Mn)},async handler(e){if(!e.worldAddress){let n=["--block-base-fee-per-gas","0","--port",String(e.port)];Bn(n)}let o=e.worldAddress?await jn(e.profile):`http://127.0.0.1:${e.port}`,r=e.worldAddress??(await N({...e,saveDeployment:!1,rpc:o})).address;console.log(Rn.blue("World address",r));let t=e.forgeOptions?.replaceAll("\\","").split(" ")??[];try{await On(["test","--fork-url",o,...t],{profile:e.profile,env:{WORLD_ADDRESS:r}}),process.exit(0)}catch(n){console.error(n),process.exit(1)}}},To=Fn;import{existsSync as $n,readFileSync as Wn}from"fs";import{ethers as Ao}from"ethers";import{loadConfig as Hn}from"@latticexyz/config/node";import{MUDError as ko}from"@latticexyz/common/errors";import{cast as En,getRpcUrl as Nn,getSrcDirectory as zn}from"@latticexyz/common/foundry";import{resolveWorldConfig as Ln}from"@latticexyz/world";import Un from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import Io from"@latticexyz/world/mud.config";import{resourceToHex as Bo}from"@latticexyz/common";import{createClient as Vn,http as _n}from"viem";import{getChainId as Kn}from"viem/actions";var Po=Bo({type:"system",namespace:Io.namespace,name:Io.tables.Systems.name}),Jn={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 zn(o),e.rpc??=await Nn(o);let{tx:r,configPath:t,srcDir:n,rpc:s}=e,i=I(n),a=await Hn(t),m=Ln(a,i.map(({basename:g})=>g)),c=e.worldAddress??await qn(a.worldsFile,s),f=new Ao.providers.StaticJsonRpcProvider(s),y=new Ao.Contract(c,Un,f),x=a.namespace,C=Object.values(m.systems).map(({name:g})=>g),d=await y.getFieldLayout(Po),u=[];for(let g of C){let D=Bo({type:"system",namespace:x,name:g}),p=await y.getField(Po,[D],0,d);u.push({name:g,address:p})}let w=await En(["run","--label",`${c}:World`,...u.map(({name:g,address:D})=>["--label",`${D}:${g}`]).flat(),`${r}`]);console.log(w),process.exit(0)}},Oo=Jn;async function qn(e,o){if($n(e)){let r=Vn({transport:_n(o)}),t=await Kn(r),n=JSON.parse(Wn(e,"utf-8"));if(!n[t])throw new ko(`chainId ${t} is missing in worldsFile "${e}"`);return n[t].address}else throw new ko("worldAddress is not specified and worldsFile is missing")}import{anvil as Yn,getScriptDirectory as Gn,getSrcDirectory as Zn}from"@latticexyz/common/foundry";import j from"chalk";import Qn from"chokidar";import{loadConfig as Xn,resolveConfigPath as es}from"@latticexyz/config/node";import os from"path";import{homedir as ts}from"os";import{rmSync as rs}from"fs";import{BehaviorSubject as ns,debounceTime as ss,exhaustMap as as,filter as is}from"rxjs";import{isDefined as cs}from"@latticexyz/common/utils";var ds={rpc:k.rpc,configPath:k.configPath,alwaysRunPostDeploy:k.alwaysRunPostDeploy,worldAddress:k.worldAddress},ls={command:"dev-contracts",describe:"Start a development server for MUD contracts",builder(e){return e.options(ds)},async handler(e){let o=e.rpc,r=e.configPath??await es(e.configPath),t=await Zn(),n=await Gn(),s=await Xn(r);if(!e.rpc){console.log(j.gray("Cleaning devnode cache"));let c=ts();rs(os.join(c,".foundry","anvil","tmp"),{recursive:!0,force:!0}),Yn(["--block-time","1","--block-base-fee-per-gas","0"]),o="http://127.0.0.1:8545"}let i=new ns(Date.now());Qn.watch([r,t,n],{ignoreInitial:!0}).on("all",async(c,f)=>{f.includes(r)&&(console.log(j.blue("Config changed, queuing deploy\u2026")),i.next(Date.now())),(f.includes(t)||f.includes(n))&&(f.includes(s.codegenDirectory)||(console.log(j.blue("Contracts changed, queuing deploy\u2026")),i.next(Date.now())))});let a=e.worldAddress;i.pipe(ss(200),as(async c=>{a&&console.log(j.blue("Rebuilding and upgrading world\u2026"));try{let f=await N({...e,configPath:r,rpc:o,rpcBatch:!1,skipBuild:!1,printConfig:!1,profile:void 0,saveDeployment:!0,deployerAddress:void 0,worldAddress:a,srcDir:t,salt:"0x"});return a=f.address,c<i.value?i.next(i.value):console.log(j.gray(`
|
|
30
|
-
Waiting for file changes\u2026
|
|
31
|
-
`)),f}catch(f){console.error(j.bgRed(j.whiteBright(`
|
|
32
|
-
Error while attempting deploy
|
|
33
|
-
`))),console.error(f),console.log(j.gray(`
|
|
34
|
-
Waiting for file changes\u2026
|
|
35
|
-
`))}}),is(cs)).subscribe()}},jo=ls;var jp=[we,ho,xe,Ce,ms,De,ve,xo,vo,To,Oo,jo,ps];export{jp as commands};
|
|
36
|
-
//# sourceMappingURL=commands-EJAOLM32.js.map
|