create-mud 2.0.0-next.7 → 2.0.0-next.8

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.
Files changed (29) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/templates/phaser/packages/client/src/mud/createClientComponents.ts +11 -0
  3. package/dist/templates/phaser/packages/client/src/mud/createSystemCalls.ts +34 -0
  4. package/dist/templates/phaser/packages/client/src/mud/getNetworkConfig.ts +59 -3
  5. package/dist/templates/phaser/packages/client/src/mud/setupNetwork.ts +41 -1
  6. package/dist/templates/phaser/packages/client/src/mud/supportedChains.ts +16 -1
  7. package/dist/templates/phaser/packages/contracts/worlds.json.d.ts +2 -0
  8. package/dist/templates/react/packages/client/src/mud/createClientComponents.ts +11 -0
  9. package/dist/templates/react/packages/client/src/mud/createSystemCalls.ts +28 -0
  10. package/dist/templates/react/packages/client/src/mud/getNetworkConfig.ts +60 -3
  11. package/dist/templates/react/packages/client/src/mud/setup.ts +5 -0
  12. package/dist/templates/react/packages/client/src/mud/setupNetwork.ts +43 -1
  13. package/dist/templates/react/packages/client/src/mud/supportedChains.ts +17 -1
  14. package/dist/templates/react/packages/contracts/worlds.json.d.ts +2 -0
  15. package/dist/templates/threejs/packages/client/src/mud/createClientComponents.ts +11 -0
  16. package/dist/templates/threejs/packages/client/src/mud/createSystemCalls.ts +26 -0
  17. package/dist/templates/threejs/packages/client/src/mud/getNetworkConfig.ts +63 -3
  18. package/dist/templates/threejs/packages/client/src/mud/setup.ts +3 -0
  19. package/dist/templates/threejs/packages/client/src/mud/setupNetwork.ts +41 -1
  20. package/dist/templates/threejs/packages/client/src/mud/supportedChains.ts +15 -1
  21. package/dist/templates/threejs/packages/contracts/worlds.json.d.ts +2 -0
  22. package/dist/templates/vanilla/packages/client/src/mud/createClientComponents.ts +11 -0
  23. package/dist/templates/vanilla/packages/client/src/mud/createSystemCalls.ts +29 -0
  24. package/dist/templates/vanilla/packages/client/src/mud/getNetworkConfig.ts +61 -3
  25. package/dist/templates/vanilla/packages/client/src/mud/setup.ts +5 -0
  26. package/dist/templates/vanilla/packages/client/src/mud/setupNetwork.ts +43 -1
  27. package/dist/templates/vanilla/packages/client/src/mud/supportedChains.ts +16 -1
  28. package/dist/templates/vanilla/packages/contracts/worlds.json.d.ts +2 -0
  29. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var t=require("create-create-app"),s=require("path");var e={name:"create-mud",version:"2.0.0-next.7",description:"Create a new MUD project",license:"MIT",author:"Lattice <mud@lattice.xyz>",bin:"dist/cli.js",files:["dist"],scripts:{build:"pnpm run build:js","build:js":"tsup && ./scripts/copy-templates.sh",clean:"pnpm run clean:js","clean:js":"rimraf dist",dev:"tsup --watch",prepublishOnly:"npm run clean && npm run build",test:"pnpm run test:vanilla && pnpm run test:react && pnpm run test:phaser && pnpm run test:threejs","test:ci":"pnpm run test","test:phaser":"dist/cli.js test-project --template phaser && rimraf test-project","test:react":"dist/cli.js test-project --template react && rimraf test-project","test:threejs":"dist/cli.js test-project --template threejs && rimraf test-project","test:vanilla":"dist/cli.js test-project --template vanilla && rimraf test-project"},dependencies:{"create-create-app":"git+https://github.com/holic/create-create-app#74376c59b48a04aabbe94d9cacfe9cb1cecccd63"},devDependencies:{"@types/node":"^18.15.11",tsup:"^6.7.0"},publishConfig:{access:"public",registry:"https://registry.npmjs.org"},gitHead:"914a1e0ae4a573d685841ca2ea921435057deb8f"};var i=(0,s.resolve)(__dirname,"..","dist","templates");(0,t.create)("create-mud",{templateRoot:i,defaultTemplate:"vanilla",defaultPackageManager:"pnpm",promptForDescription:!1,promptForAuthor:!1,promptForEmail:!1,promptForLicense:!1,promptForTemplate:!0,caveat:({answers:r,packageManager:a})=>`Done! Play in the MUD with \`cd ${r.name}\` and \`${a} run dev\``,extra:{"mud-version":{type:"input",describe:"The version of MUD packages to use, defaults to latest",default:e.version}}});
2
+ "use strict";var t=require("create-create-app"),s=require("path");var e={name:"create-mud",version:"2.0.0-next.8",description:"Create a new MUD project",license:"MIT",author:"Lattice <mud@lattice.xyz>",bin:"dist/cli.js",files:["dist"],scripts:{build:"pnpm run build:js","build:js":"tsup && ./scripts/copy-templates.sh",clean:"pnpm run clean:js","clean:js":"rimraf dist",dev:"tsup --watch",prepublishOnly:"npm run clean && npm run build",test:"pnpm run test:vanilla && pnpm run test:react && pnpm run test:phaser && pnpm run test:threejs","test:ci":"pnpm run test","test:phaser":"dist/cli.js test-project --template phaser && rimraf test-project","test:react":"dist/cli.js test-project --template react && rimraf test-project","test:threejs":"dist/cli.js test-project --template threejs && rimraf test-project","test:vanilla":"dist/cli.js test-project --template vanilla && rimraf test-project"},dependencies:{"create-create-app":"git+https://github.com/holic/create-create-app#74376c59b48a04aabbe94d9cacfe9cb1cecccd63"},devDependencies:{"@types/node":"^18.15.11",tsup:"^6.7.0"},publishConfig:{access:"public",registry:"https://registry.npmjs.org"},gitHead:"914a1e0ae4a573d685841ca2ea921435057deb8f"};var i=(0,s.resolve)(__dirname,"..","dist","templates");(0,t.create)("create-mud",{templateRoot:i,defaultTemplate:"vanilla",defaultPackageManager:"pnpm",promptForDescription:!1,promptForAuthor:!1,promptForEmail:!1,promptForLicense:!1,promptForTemplate:!0,caveat:({answers:r,packageManager:a})=>`Done! Play in the MUD with \`cd ${r.name}\` and \`${a} run dev\``,extra:{"mud-version":{type:"input",describe:"The version of MUD packages to use, defaults to latest",default:e.version}}});
@@ -1,3 +1,14 @@
1
+ /*
2
+ * Creates components for use by the client.
3
+ *
4
+ * By default it returns the components from setupNetwork.ts, those which are
5
+ * automatically inferred from the mud.config.ts table definitions.
6
+ *
7
+ * However, you can add or override components here as needed. This
8
+ * lets you add user defined components, which may or may not have
9
+ * an onchain component.
10
+ */
11
+
1
12
  import { SetupNetworkResult } from "./setupNetwork";
2
13
 
3
14
  export type ClientComponents = ReturnType<typeof createClientComponents>;
@@ -1,3 +1,14 @@
1
+ /*
2
+ * Creates components for use by the client.
3
+ *
4
+ * By default it returns the components from setupNetwork.ts, those which are
5
+ * automatically inferred from the mud.config.ts table definitions.
6
+ *
7
+ * However, you can add or override components here as needed. This
8
+ * lets you add user defined components, which may or may not have
9
+ * an onchain component.
10
+ */
11
+
1
12
  import { getComponentValue } from "@latticexyz/recs";
2
13
  import { ClientComponents } from "./createClientComponents";
3
14
  import { SetupNetworkResult } from "./setupNetwork";
@@ -6,10 +17,33 @@ import { singletonEntity } from "@latticexyz/store-sync/recs";
6
17
  export type SystemCalls = ReturnType<typeof createSystemCalls>;
7
18
 
8
19
  export function createSystemCalls(
20
+ /*
21
+ * The parameter list informs TypeScript that:
22
+ *
23
+ * - The first parameter is expected to be a
24
+ * SetupNetworkResult, as defined in setupNetwork.ts
25
+ *
26
+ * - Out of this parameter, we only care about two fields:
27
+ * - worldContract (which comes from createContract, see
28
+ * https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/phaser/packages/client/src/mud/setupNetwork.ts#L31).
29
+ * - waitForTransaction (which comes from syncToRecs, see
30
+ * https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/phaser/packages/client/src/mud/setupNetwork.ts#L39).
31
+ *
32
+ * - From the second parameter, which is a ClientComponent,
33
+ * we only care about Counter. This parameter comes to use
34
+ * through createClientComponents.ts, but it originates in
35
+ * syncToRecs (https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/phaser/packages/client/src/mud/setupNetwork.ts#L39).
36
+ */
9
37
  { worldContract, waitForTransaction }: SetupNetworkResult,
10
38
  { Counter }: ClientComponents
11
39
  ) {
12
40
  const increment = async () => {
41
+ /*
42
+ * Because IncrementSystem
43
+ * (https://mud.dev/tutorials/walkthrough/minimal-onchain#incrementsystemsol)
44
+ * is in the root namespace, `.increment` can be called directly
45
+ * on the World contract.
46
+ */
13
47
  const tx = await worldContract.write.increment();
14
48
  await waitForTransaction(tx);
15
49
  return getComponentValue(Counter, singletonEntity);
@@ -1,24 +1,80 @@
1
+ /*
2
+ * Network specific configuration for the client.
3
+ * By default connect to the anvil test network.
4
+ */
5
+
6
+ /*
7
+ * By default the template just creates a temporary wallet
8
+ * (called a burner wallet) and uses a faucet (on our test net)
9
+ * to get ETH for it.
10
+ *
11
+ * See https://mud.dev/tutorials/minimal/deploy#wallet-managed-address
12
+ * for how to use the user's own address instead.
13
+ */
1
14
  import { getBurnerPrivateKey } from "@latticexyz/common";
2
- import worldsJson from "contracts/worlds.json";
3
- import { supportedChains } from "./supportedChains";
4
15
 
5
- const worlds = worldsJson as Partial<Record<string, { address: string; blockNumber?: number }>>;
16
+ /*
17
+ * Import the addresses of the World, possibly on multiple chains,
18
+ * from packages/contracts/worlds.json. When the contracts package
19
+ * deploys a new `World`, it updates this file.
20
+ */
21
+ import worlds from "contracts/worlds.json";
22
+
23
+ /*
24
+ * The supported chains.
25
+ * By default, there are only two chains here:
26
+ *
27
+ * - mudFoundry, the chain running on anvil that pnpm dev
28
+ * starts by default. It is similar to the viem anvil chain
29
+ * (see https://viem.sh/docs/clients/test.html), but with the
30
+ * basefee set to zero to avoid transaction fees.
31
+ * - latticeTestnet, our public test network.
32
+ *
33
+ * See https://mud.dev/tutorials/minimal/deploy#run-the-user-interface
34
+ * for instructions on how to add networks.
35
+ */
36
+ import { supportedChains } from "./supportedChains";
6
37
 
7
38
  export async function getNetworkConfig() {
8
39
  const params = new URLSearchParams(window.location.search);
40
+
41
+ /*
42
+ * The chain ID is the first item available from this list:
43
+ * 1. chainId query parameter
44
+ * 2. chainid query parameter
45
+ * 3. The VITE_CHAIN_ID environment variable set when the
46
+ * vite dev server was started or client was built
47
+ * 4. The default, 31337 (anvil)
48
+ */
9
49
  const chainId = Number(params.get("chainId") || params.get("chainid") || import.meta.env.VITE_CHAIN_ID || 31337);
50
+
51
+ /*
52
+ * Find the chain (unless it isn't in the list of supported chains).
53
+ */
10
54
  const chainIndex = supportedChains.findIndex((c) => c.id === chainId);
11
55
  const chain = supportedChains[chainIndex];
12
56
  if (!chain) {
13
57
  throw new Error(`Chain ${chainId} not found`);
14
58
  }
15
59
 
60
+ /*
61
+ * Get the address of the World. If you want to use a
62
+ * different address than the one in worlds.json,
63
+ * provide it as worldAddress in the query string.
64
+ */
16
65
  const world = worlds[chain.id.toString()];
17
66
  const worldAddress = params.get("worldAddress") || world?.address;
18
67
  if (!worldAddress) {
19
68
  throw new Error(`No world address found for chain ${chainId}. Did you run \`mud deploy\`?`);
20
69
  }
21
70
 
71
+ /*
72
+ * MUD clients use events to synchronize the database, meaning
73
+ * they need to look as far back as when the World was started.
74
+ * The block number for the World start can be specified either
75
+ * on the URL (as initialBlockNumber) or in the worlds.json
76
+ * file. If neither has it, it starts at the first block, zero.
77
+ */
22
78
  const initialBlockNumber = params.has("initialBlockNumber")
23
79
  ? Number(params.get("initialBlockNumber"))
24
80
  : world?.blockNumber ?? 0n;
@@ -1,3 +1,8 @@
1
+ /*
2
+ * The MUD client code is built on top of viem
3
+ * (https://viem.sh/docs/getting-started.html).
4
+ * This line imports the functions we need from it.
5
+ */
1
6
  import { createPublicClient, fallback, webSocket, http, createWalletClient, Hex, parseEther, ClientConfig } from "viem";
2
7
  import { createFaucetService } from "@latticexyz/services/faucet";
3
8
  import { encodeEntity, syncToRecs } from "@latticexyz/store-sync/recs";
@@ -6,6 +11,15 @@ import { world } from "./world";
6
11
  import IWorldAbi from "contracts/abi/IWorld.sol/IWorld.abi.json";
7
12
  import { createBurnerAccount, createContract, transportObserver, ContractWrite } from "@latticexyz/common";
8
13
  import { Subject, share } from "rxjs";
14
+
15
+ /*
16
+ * Import our MUD config, which includes strong types for
17
+ * our tables and other config options. We use this to generate
18
+ * things like RECS components and get back strong types for them.
19
+ *
20
+ * See https://mud.dev/tutorials/walkthrough/minimal-onchain#mudconfigts
21
+ * for the source of this information.
22
+ */
9
23
  import mudConfig from "contracts/mud.config";
10
24
 
11
25
  export type SetupNetworkResult = Awaited<ReturnType<typeof setupNetwork>>;
@@ -13,6 +27,10 @@ export type SetupNetworkResult = Awaited<ReturnType<typeof setupNetwork>>;
13
27
  export async function setupNetwork() {
14
28
  const networkConfig = await getNetworkConfig();
15
29
 
30
+ /*
31
+ * Create a viem public (read only) client
32
+ * (https://viem.sh/docs/clients/public.html)
33
+ */
16
34
  const clientOptions = {
17
35
  chain: networkConfig.chain,
18
36
  transport: transportObserver(fallback([webSocket(), http()])),
@@ -21,13 +39,25 @@ export async function setupNetwork() {
21
39
 
22
40
  const publicClient = createPublicClient(clientOptions);
23
41
 
42
+ /*
43
+ * Create a temporary wallet and a viem client for it
44
+ * (see https://viem.sh/docs/clients/wallet.html).
45
+ */
24
46
  const burnerAccount = createBurnerAccount(networkConfig.privateKey as Hex);
25
47
  const burnerWalletClient = createWalletClient({
26
48
  ...clientOptions,
27
49
  account: burnerAccount,
28
50
  });
29
51
 
52
+ /*
53
+ * Create an observable for contract writes that we can
54
+ * pass into MUD dev tools for transaction observability.
55
+ */
30
56
  const write$ = new Subject<ContractWrite>();
57
+
58
+ /*
59
+ * Create an object for communicating with the deployed World.
60
+ */
31
61
  const worldContract = createContract({
32
62
  address: networkConfig.worldAddress as Hex,
33
63
  abi: IWorldAbi,
@@ -36,6 +66,12 @@ export async function setupNetwork() {
36
66
  onWrite: (write) => write$.next(write),
37
67
  });
38
68
 
69
+ /*
70
+ * Sync on-chain state into RECS and keeps our client in sync.
71
+ * Uses the MUD indexer if available, otherwise falls back
72
+ * to the viem publicClient to make RPC calls to fetch MUD
73
+ * events from the chain.
74
+ */
39
75
  const { components, latestBlock$, blockStorageOperations$, waitForTransaction } = await syncToRecs({
40
76
  world,
41
77
  config: mudConfig,
@@ -44,7 +80,11 @@ export async function setupNetwork() {
44
80
  startBlock: BigInt(networkConfig.initialBlockNumber),
45
81
  });
46
82
 
47
- // Request drip from faucet
83
+ /*
84
+ * If there is a faucet, request (test) ETH if you have
85
+ * less than 1 ETH. Repeat every 20 seconds to ensure you don't
86
+ * run out.
87
+ */
48
88
  if (networkConfig.faucetServiceUrl) {
49
89
  const address = burnerAccount.address;
50
90
  console.info("[Dev Faucet]: Player address -> ", address);
@@ -1,4 +1,19 @@
1
+ /*
2
+ * The supported chains.
3
+ * By default, there are only two chains here:
4
+ *
5
+ * - mudFoundry, the chain running on anvil that pnpm dev
6
+ * starts by default. It is similar to the viem anvil chain
7
+ * (see https://viem.sh/docs/clients/test.html), but with the
8
+ * basefee set to zero to avoid transaction fees.
9
+ * - latticeTestnet, our public test network.
10
+ *
11
+ */
12
+
1
13
  import { MUDChain, latticeTestnet, mudFoundry } from "@latticexyz/common/chains";
2
14
 
3
- // If you are deploying to chains other than anvil or Lattice testnet, add them here
15
+ /*
16
+ * See https://mud.dev/tutorials/minimal/deploy#run-the-user-interface
17
+ * for instructions on how to add networks.
18
+ */
4
19
  export const supportedChains: MUDChain[] = [mudFoundry, latticeTestnet];
@@ -0,0 +1,2 @@
1
+ declare const worlds: Partial<Record<string, { address: string; blockNumber?: number }>>;
2
+ export default worlds;
@@ -1,3 +1,14 @@
1
+ /*
2
+ * Creates components for use by the client.
3
+ *
4
+ * By default it returns the components from setupNetwork.ts, those which are
5
+ * automatically inferred from the mud.config.ts table definitions.
6
+ *
7
+ * However, you can add or override components here as needed. This
8
+ * lets you add user defined components, which may or may not have
9
+ * an onchain component.
10
+ */
11
+
1
12
  import { SetupNetworkResult } from "./setupNetwork";
2
13
 
3
14
  export type ClientComponents = ReturnType<typeof createClientComponents>;
@@ -1,3 +1,8 @@
1
+ /*
2
+ * Create the system calls that the client can use to ask
3
+ * for changes in the World state (using the System contracts).
4
+ */
5
+
1
6
  import { getComponentValue } from "@latticexyz/recs";
2
7
  import { ClientComponents } from "./createClientComponents";
3
8
  import { SetupNetworkResult } from "./setupNetwork";
@@ -6,10 +11,33 @@ import { singletonEntity } from "@latticexyz/store-sync/recs";
6
11
  export type SystemCalls = ReturnType<typeof createSystemCalls>;
7
12
 
8
13
  export function createSystemCalls(
14
+ /*
15
+ * The parameter list informs TypeScript that:
16
+ *
17
+ * - The first parameter is expected to be a
18
+ * SetupNetworkResult, as defined in setupNetwork.ts
19
+ *
20
+ * - Out of this parameter, we only care about two fields:
21
+ * - worldContract (which comes from createContract, see
22
+ * https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/react/packages/client/src/mud/setupNetwork.ts#L31).
23
+ * - waitForTransaction (which comes from syncToRecs, see
24
+ * https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/react/packages/client/src/mud/setupNetwork.ts#L39).
25
+ *
26
+ * - From the second parameter, which is a ClientComponent,
27
+ * we only care about Counter. This parameter comes to use
28
+ * through createClientComponents.ts, but it originates in
29
+ * syncToRecs (https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/react/packages/client/src/mud/setupNetwork.ts#L39).
30
+ */
9
31
  { worldContract, waitForTransaction }: SetupNetworkResult,
10
32
  { Counter }: ClientComponents
11
33
  ) {
12
34
  const increment = async () => {
35
+ /*
36
+ * Because IncrementSystem
37
+ * (https://mud.dev/tutorials/walkthrough/minimal-onchain#incrementsystemsol)
38
+ * is in the root namespace, `.increment` can be called directly
39
+ * on the World contract.
40
+ */
13
41
  const tx = await worldContract.write.increment();
14
42
  await waitForTransaction(tx);
15
43
  return getComponentValue(Counter, singletonEntity);
@@ -1,24 +1,81 @@
1
+ /*
2
+ * Network specific configuration for the client.
3
+ * By default connect to the anvil test network.
4
+ *
5
+ */
6
+
7
+ /*
8
+ * By default the template just creates a temporary wallet
9
+ * (called a burner wallet) and uses a faucet (on our test net)
10
+ * to get ETH for it.
11
+ *
12
+ * See https://mud.dev/tutorials/minimal/deploy#wallet-managed-address
13
+ * for how to use the user's own address instead.
14
+ */
1
15
  import { getBurnerPrivateKey } from "@latticexyz/common";
2
- import worldsJson from "contracts/worlds.json";
3
- import { supportedChains } from "./supportedChains";
4
16
 
5
- const worlds = worldsJson as Partial<Record<string, { address: string; blockNumber?: number }>>;
17
+ /*
18
+ * Import the addresses of the World, possibly on multiple chains,
19
+ * from packages/contracts/worlds.json. When the contracts package
20
+ * deploys a new `World`, it updates this file.
21
+ */
22
+ import worlds from "contracts/worlds.json";
23
+
24
+ /*
25
+ * The supported chains.
26
+ * By default, there are only two chains here:
27
+ *
28
+ * - mudFoundry, the chain running on anvil that pnpm dev
29
+ * starts by default. It is similar to the viem anvil chain
30
+ * (see https://viem.sh/docs/clients/test.html), but with the
31
+ * basefee set to zero to avoid transaction fees.
32
+ * - latticeTestnet, our public test network.
33
+ *
34
+ * See https://mud.dev/tutorials/minimal/deploy#run-the-user-interface
35
+ * for instructions on how to add networks.
36
+ */
37
+ import { supportedChains } from "./supportedChains";
6
38
 
7
39
  export async function getNetworkConfig() {
8
40
  const params = new URLSearchParams(window.location.search);
41
+
42
+ /*
43
+ * The chain ID is the first item available from this list:
44
+ * 1. chainId query parameter
45
+ * 2. chainid query parameter
46
+ * 3. The VITE_CHAIN_ID environment variable set when the
47
+ * vite dev server was started or client was built
48
+ * 4. The default, 31337 (anvil)
49
+ */
9
50
  const chainId = Number(params.get("chainId") || params.get("chainid") || import.meta.env.VITE_CHAIN_ID || 31337);
51
+
52
+ /*
53
+ * Find the chain (unless it isn't in the list of supported chains).
54
+ */
10
55
  const chainIndex = supportedChains.findIndex((c) => c.id === chainId);
11
56
  const chain = supportedChains[chainIndex];
12
57
  if (!chain) {
13
58
  throw new Error(`Chain ${chainId} not found`);
14
59
  }
15
60
 
61
+ /*
62
+ * Get the address of the World. If you want to use a
63
+ * different address than the one in worlds.json,
64
+ * provide it as worldAddress in the query string.
65
+ */
16
66
  const world = worlds[chain.id.toString()];
17
67
  const worldAddress = params.get("worldAddress") || world?.address;
18
68
  if (!worldAddress) {
19
69
  throw new Error(`No world address found for chain ${chainId}. Did you run \`mud deploy\`?`);
20
70
  }
21
71
 
72
+ /*
73
+ * MUD clients use events to synchronize the database, meaning
74
+ * they need to look as far back as when the World was started.
75
+ * The block number for the World start can be specified either
76
+ * on the URL (as initialBlockNumber) or in the worlds.json
77
+ * file. If neither has it, it starts at the first block, zero.
78
+ */
22
79
  const initialBlockNumber = params.has("initialBlockNumber")
23
80
  ? Number(params.get("initialBlockNumber"))
24
81
  : world?.blockNumber ?? 0n;
@@ -1,3 +1,7 @@
1
+ /*
2
+ * This file sets up all the definitions required for a MUD client.
3
+ */
4
+
1
5
  import { createClientComponents } from "./createClientComponents";
2
6
  import { createSystemCalls } from "./createSystemCalls";
3
7
  import { setupNetwork } from "./setupNetwork";
@@ -8,6 +12,7 @@ export async function setup() {
8
12
  const network = await setupNetwork();
9
13
  const components = createClientComponents(network);
10
14
  const systemCalls = createSystemCalls(network, components);
15
+
11
16
  return {
12
17
  network,
13
18
  components,
@@ -1,11 +1,27 @@
1
+ /*
2
+ * The MUD client code is built on top of viem
3
+ * (https://viem.sh/docs/getting-started.html).
4
+ * This line imports the functions we need from it.
5
+ */
1
6
  import { createPublicClient, fallback, webSocket, http, createWalletClient, Hex, parseEther, ClientConfig } from "viem";
2
7
  import { createFaucetService } from "@latticexyz/services/faucet";
3
8
  import { encodeEntity, syncToRecs } from "@latticexyz/store-sync/recs";
9
+
4
10
  import { getNetworkConfig } from "./getNetworkConfig";
5
11
  import { world } from "./world";
6
12
  import IWorldAbi from "contracts/abi/IWorld.sol/IWorld.abi.json";
7
13
  import { createBurnerAccount, createContract, transportObserver, ContractWrite } from "@latticexyz/common";
14
+
8
15
  import { Subject, share } from "rxjs";
16
+
17
+ /*
18
+ * Import our MUD config, which includes strong types for
19
+ * our tables and other config options. We use this to generate
20
+ * things like RECS components and get back strong types for them.
21
+ *
22
+ * See https://mud.dev/tutorials/walkthrough/minimal-onchain#mudconfigts
23
+ * for the source of this information.
24
+ */
9
25
  import mudConfig from "contracts/mud.config";
10
26
 
11
27
  export type SetupNetworkResult = Awaited<ReturnType<typeof setupNetwork>>;
@@ -13,6 +29,10 @@ export type SetupNetworkResult = Awaited<ReturnType<typeof setupNetwork>>;
13
29
  export async function setupNetwork() {
14
30
  const networkConfig = await getNetworkConfig();
15
31
 
32
+ /*
33
+ * Create a viem public (read only) client
34
+ * (https://viem.sh/docs/clients/public.html)
35
+ */
16
36
  const clientOptions = {
17
37
  chain: networkConfig.chain,
18
38
  transport: transportObserver(fallback([webSocket(), http()])),
@@ -21,13 +41,25 @@ export async function setupNetwork() {
21
41
 
22
42
  const publicClient = createPublicClient(clientOptions);
23
43
 
44
+ /*
45
+ * Create a temporary wallet and a viem client for it
46
+ * (see https://viem.sh/docs/clients/wallet.html).
47
+ */
24
48
  const burnerAccount = createBurnerAccount(networkConfig.privateKey as Hex);
25
49
  const burnerWalletClient = createWalletClient({
26
50
  ...clientOptions,
27
51
  account: burnerAccount,
28
52
  });
29
53
 
54
+ /*
55
+ * Create an observable for contract writes that we can
56
+ * pass into MUD dev tools for transaction observability.
57
+ */
30
58
  const write$ = new Subject<ContractWrite>();
59
+
60
+ /*
61
+ * Create an object for communicating with the deployed World.
62
+ */
31
63
  const worldContract = createContract({
32
64
  address: networkConfig.worldAddress as Hex,
33
65
  abi: IWorldAbi,
@@ -36,6 +68,12 @@ export async function setupNetwork() {
36
68
  onWrite: (write) => write$.next(write),
37
69
  });
38
70
 
71
+ /*
72
+ * Sync on-chain state into RECS and keeps our client in sync.
73
+ * Uses the MUD indexer if available, otherwise falls back
74
+ * to the viem publicClient to make RPC calls to fetch MUD
75
+ * events from the chain.
76
+ */
39
77
  const { components, latestBlock$, blockStorageOperations$, waitForTransaction } = await syncToRecs({
40
78
  world,
41
79
  config: mudConfig,
@@ -44,7 +82,11 @@ export async function setupNetwork() {
44
82
  startBlock: BigInt(networkConfig.initialBlockNumber),
45
83
  });
46
84
 
47
- // Request drip from faucet
85
+ /*
86
+ * If there is a faucet, request (test) ETH if you have
87
+ * less than 1 ETH. Repeat every 20 seconds to ensure you don't
88
+ * run out.
89
+ */
48
90
  if (networkConfig.faucetServiceUrl) {
49
91
  const address = burnerAccount.address;
50
92
  console.info("[Dev Faucet]: Player address -> ", address);
@@ -1,4 +1,20 @@
1
+ /*
2
+ * The supported chains.
3
+ * By default, there are only two chains here:
4
+ *
5
+ * - mudFoundry, the chain running on anvil that pnpm dev
6
+ * starts by default. It is similar to the viem anvil chain
7
+ * (see https://viem.sh/docs/clients/test.html), but with the
8
+ * basefee set to zero to avoid transaction fees.
9
+ * - latticeTestnet, our public test network.
10
+ *
11
+
12
+ */
13
+
1
14
  import { MUDChain, latticeTestnet, mudFoundry } from "@latticexyz/common/chains";
2
15
 
3
- // If you are deploying to chains other than anvil or Lattice testnet, add them here
16
+ /*
17
+ * See https://mud.dev/tutorials/minimal/deploy#run-the-user-interface
18
+ * for instructions on how to add networks.
19
+ */
4
20
  export const supportedChains: MUDChain[] = [mudFoundry, latticeTestnet];
@@ -0,0 +1,2 @@
1
+ declare const worlds: Partial<Record<string, { address: string; blockNumber?: number }>>;
2
+ export default worlds;
@@ -1,3 +1,14 @@
1
+ /*
2
+ * Creates components for use by the client.
3
+ *
4
+ * By default it returns the components from setupNetwork.ts, those which are
5
+ * automatically inferred from the mud.config.ts table definitions.
6
+ *
7
+ * However, you can add or override components here as needed. This
8
+ * lets you add user defined components, which may or may not have
9
+ * an onchain component.
10
+ */
11
+
1
12
  import { SetupNetworkResult } from "./setupNetwork";
2
13
 
3
14
  export type ClientComponents = ReturnType<typeof createClientComponents>;
@@ -1,3 +1,8 @@
1
+ /*
2
+ * Create the system calls that the client can use to ask
3
+ * for changes in the World state (using the System contracts).
4
+ */
5
+
1
6
  import { getComponentValue } from "@latticexyz/recs";
2
7
  import { ClientComponents } from "./createClientComponents";
3
8
  import { SetupNetworkResult } from "./setupNetwork";
@@ -5,10 +10,31 @@ import { SetupNetworkResult } from "./setupNetwork";
5
10
  export type SystemCalls = ReturnType<typeof createSystemCalls>;
6
11
 
7
12
  export function createSystemCalls(
13
+ /*
14
+ * The parameter list informs TypeScript that:
15
+ *
16
+ * - The first parameter is expected to be a
17
+ * SetupNetworkResult, as defined in setupNetwork.ts
18
+ *
19
+ * - Out of this parameter, we only care about two fields:
20
+ * - worldContract (which comes from createContract, see
21
+ * https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/threejs/packages/client/src/mud/setupNetwork.ts#L31).
22
+ * - waitForTransaction (which comes from syncToRecs, see
23
+ * https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/threejs/packages/client/src/mud/setupNetwork.ts#L39).
24
+ *
25
+ * - From the second parameter, which is a ClientComponent,
26
+ * we only care about Position. This parameter comes to use
27
+ * through createClientComponents.ts, but it originates in
28
+ * syncToRecs (https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/threejs/packages/client/src/mud/setupNetwork.ts#L39).
29
+ */
8
30
  { worldContract, waitForTransaction, playerEntity }: SetupNetworkResult,
9
31
  { Position }: ClientComponents
10
32
  ) {
11
33
  const moveTo = async (x: number, y: number, z: number) => {
34
+ /*
35
+ * Because MoveSystem is in the root namespace, .move can be called directly
36
+ * on the World contract.
37
+ */
12
38
  const tx = await worldContract.write.move([x, y, z]);
13
39
  await waitForTransaction(tx);
14
40
  };
@@ -1,24 +1,84 @@
1
+ /*
2
+ * Network specific configuration for the client.
3
+ * By default connect to the anvil test network.
4
+ *
5
+ */
6
+
7
+ /*
8
+ * By default the template just creates a temporary wallet
9
+ * (called a burner wallet) and uses a faucet (on our test net)
10
+ * to get ETH for it.
11
+ *
12
+ * See https://mud.dev/tutorials/minimal/deploy#wallet-managed-address
13
+ * for how to use the user's own address instead.
14
+ */
1
15
  import { getBurnerPrivateKey } from "@latticexyz/common";
2
- import worldsJson from "contracts/worlds.json";
3
- import { supportedChains } from "./supportedChains";
4
16
 
5
- const worlds = worldsJson as Partial<Record<string, { address: string; blockNumber?: number }>>;
17
+ /*
18
+ * Import the addresses of the World, possibly on multiple chains,
19
+ * from packages/contracts/worlds.json. When the contracts package
20
+ * deploys a new `World`, it updates this file.
21
+ */
22
+ import worlds from "contracts/worlds.json";
23
+
24
+ /*
25
+ * The supported chains.
26
+ * By default, there are only two chains here:
27
+ *
28
+ * - mudFoundry, the chain running on anvil that pnpm dev
29
+ * starts by default. It is similar to the viem anvil chain
30
+ * (see https://viem.sh/docs/clients/test.html), but with the
31
+ * basefee set to zero to avoid transaction fees.
32
+ * - latticeTestnet, our public test network.
33
+ *
34
+ * See https://mud.dev/tutorials/minimal/deploy#run-the-user-interface
35
+ * for instructions on how to add networks.
36
+ */
37
+ import { supportedChains } from "./supportedChains";
6
38
 
39
+ /*
40
+ * This is the function that does the actual work.
41
+ */
7
42
  export async function getNetworkConfig() {
8
43
  const params = new URLSearchParams(window.location.search);
44
+
45
+ /*
46
+ * The chain ID is the first item available from this list:
47
+ * 1. chainId query parameter
48
+ * 2. chainid query parameter
49
+ * 3. The VITE_CHAIN_ID environment variable set when the
50
+ * vite dev server was started or client was built
51
+ * 4. The default, 31337 (anvil)
52
+ */
9
53
  const chainId = Number(params.get("chainId") || params.get("chainid") || import.meta.env.VITE_CHAIN_ID || 31337);
54
+
55
+ /*
56
+ * Find the chain (unless it isn't in the list of supported chains).
57
+ */
10
58
  const chainIndex = supportedChains.findIndex((c) => c.id === chainId);
11
59
  const chain = supportedChains[chainIndex];
12
60
  if (!chain) {
13
61
  throw new Error(`Chain ${chainId} not found`);
14
62
  }
15
63
 
64
+ /*
65
+ * Get the address of the World. If you want to use a
66
+ * different address than the one in worlds.json,
67
+ * provide it as worldAddress in the query string.
68
+ */
16
69
  const world = worlds[chain.id.toString()];
17
70
  const worldAddress = params.get("worldAddress") || world?.address;
18
71
  if (!worldAddress) {
19
72
  throw new Error(`No world address found for chain ${chainId}. Did you run \`mud deploy\`?`);
20
73
  }
21
74
 
75
+ /*
76
+ * MUD clients use events to synchronize the database, meaning
77
+ * they need to look as far back as when the World was started.
78
+ * The block number for the World start can be specified either
79
+ * on the URL (as initialBlockNumber) or in the worlds.json
80
+ * file. If neither has it, it starts at the first block, zero.
81
+ */
22
82
  const initialBlockNumber = params.has("initialBlockNumber")
23
83
  ? Number(params.get("initialBlockNumber"))
24
84
  : world?.blockNumber ?? 0n;
@@ -1,3 +1,6 @@
1
+ /*
2
+ * This file sets up all the definitions required for a MUD client.
3
+ */
1
4
  import { createClientComponents } from "./createClientComponents";
2
5
  import { createSystemCalls } from "./createSystemCalls";
3
6
  import { setupNetwork } from "./setupNetwork";
@@ -1,3 +1,8 @@
1
+ /*
2
+ * The MUD client code is built on top of viem
3
+ * (https://viem.sh/docs/getting-started.html).
4
+ * This line imports the functions we need from it.
5
+ */
1
6
  import { createPublicClient, fallback, webSocket, http, createWalletClient, Hex, parseEther, ClientConfig } from "viem";
2
7
  import { createFaucetService } from "@latticexyz/services/faucet";
3
8
  import { encodeEntity, syncToRecs } from "@latticexyz/store-sync/recs";
@@ -6,6 +11,15 @@ import { world } from "./world";
6
11
  import IWorldAbi from "contracts/abi/IWorld.sol/IWorld.abi.json";
7
12
  import { createBurnerAccount, createContract, transportObserver, ContractWrite } from "@latticexyz/common";
8
13
  import { Subject, share } from "rxjs";
14
+
15
+ /*
16
+ * Import our MUD config, which includes strong types for
17
+ * our tables and other config options. We use this to generate
18
+ * things like RECS components and get back strong types for them.
19
+ *
20
+ * See https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/threejs/packages/contracts/mud.config.ts
21
+ * for the source of this information.
22
+ */
9
23
  import mudConfig from "contracts/mud.config";
10
24
 
11
25
  export type SetupNetworkResult = Awaited<ReturnType<typeof setupNetwork>>;
@@ -13,6 +27,10 @@ export type SetupNetworkResult = Awaited<ReturnType<typeof setupNetwork>>;
13
27
  export async function setupNetwork() {
14
28
  const networkConfig = await getNetworkConfig();
15
29
 
30
+ /*
31
+ * Create a viem public (read only) client
32
+ * (https://viem.sh/docs/clients/public.html)
33
+ */
16
34
  const clientOptions = {
17
35
  chain: networkConfig.chain,
18
36
  transport: transportObserver(fallback([webSocket(), http()])),
@@ -21,13 +39,25 @@ export async function setupNetwork() {
21
39
 
22
40
  const publicClient = createPublicClient(clientOptions);
23
41
 
42
+ /*
43
+ * Create a temporary wallet and a viem client for it
44
+ * (see https://viem.sh/docs/clients/wallet.html).
45
+ */
24
46
  const burnerAccount = createBurnerAccount(networkConfig.privateKey as Hex);
25
47
  const burnerWalletClient = createWalletClient({
26
48
  ...clientOptions,
27
49
  account: burnerAccount,
28
50
  });
29
51
 
52
+ /*
53
+ * Create an observable for contract writes that we can
54
+ * pass into MUD dev tools for transaction observability.
55
+ */
30
56
  const write$ = new Subject<ContractWrite>();
57
+
58
+ /*
59
+ * Create an object for communicating with the deployed World.
60
+ */
31
61
  const worldContract = createContract({
32
62
  address: networkConfig.worldAddress as Hex,
33
63
  abi: IWorldAbi,
@@ -36,6 +66,12 @@ export async function setupNetwork() {
36
66
  onWrite: (write) => write$.next(write),
37
67
  });
38
68
 
69
+ /*
70
+ * Sync on-chain state into RECS and keeps our client in sync.
71
+ * Uses the MUD indexer if available, otherwise falls back
72
+ * to the viem publicClient to make RPC calls to fetch MUD
73
+ * events from the chain.
74
+ */
39
75
  const { components, latestBlock$, blockStorageOperations$, waitForTransaction } = await syncToRecs({
40
76
  world,
41
77
  config: mudConfig,
@@ -44,7 +80,11 @@ export async function setupNetwork() {
44
80
  startBlock: BigInt(networkConfig.initialBlockNumber),
45
81
  });
46
82
 
47
- // Request drip from faucet
83
+ /*
84
+ * If there is a faucet, request (test) ETH if you have
85
+ * less than 1 ETH. Repeat every 20 seconds to ensure you don't
86
+ * run out.
87
+ */
48
88
  if (networkConfig.faucetServiceUrl) {
49
89
  const address = burnerAccount.address;
50
90
  console.info("[Dev Faucet]: Player address -> ", address);
@@ -1,4 +1,18 @@
1
+ /*
2
+ * The supported chains.
3
+ * By default, there are only two chains here:
4
+ *
5
+ * - mudFoundry, the chain running on anvil that pnpm dev
6
+ * starts by default. It is similar to the viem anvil chain
7
+ * (see https://viem.sh/docs/clients/test.html), but with the
8
+ * basefee set to zero to avoid transaction fees.
9
+ * - latticeTestnet, our public test network.
10
+ *
11
+ */
1
12
  import { MUDChain, latticeTestnet, mudFoundry } from "@latticexyz/common/chains";
2
13
 
3
- // If you are deploying to chains other than anvil or Lattice testnet, add them here
14
+ /*
15
+ * See https://mud.dev/tutorials/minimal/deploy#run-the-user-interface
16
+ * for instructions on how to add networks.
17
+ */
4
18
  export const supportedChains: MUDChain[] = [mudFoundry, latticeTestnet];
@@ -0,0 +1,2 @@
1
+ declare const worlds: Partial<Record<string, { address: string; blockNumber?: number }>>;
2
+ export default worlds;
@@ -1,3 +1,14 @@
1
+ /*
2
+ * Creates components for use by the client.
3
+ *
4
+ * By default it returns the components from setupNetwork.ts, those which are
5
+ * automatically inferred from the mud.config.ts table definitions.
6
+ *
7
+ * However, you can add or override components here as needed. This
8
+ * lets you add user defined components, which may or may not have
9
+ * an onchain component.
10
+ */
11
+
1
12
  import { SetupNetworkResult } from "./setupNetwork";
2
13
 
3
14
  export type ClientComponents = ReturnType<typeof createClientComponents>;
@@ -1,3 +1,8 @@
1
+ /*
2
+ * Create the system calls that the client can use to ask
3
+ * for changes in the World state (using the System contracts).
4
+ */
5
+
1
6
  import { getComponentValue } from "@latticexyz/recs";
2
7
  import { ClientComponents } from "./createClientComponents";
3
8
  import { SetupNetworkResult } from "./setupNetwork";
@@ -6,10 +11,34 @@ import { singletonEntity } from "@latticexyz/store-sync/recs";
6
11
  export type SystemCalls = ReturnType<typeof createSystemCalls>;
7
12
 
8
13
  export function createSystemCalls(
14
+ /*
15
+ * The parameter list informs TypeScript that:
16
+ *
17
+ * - The first parameter is expected to be a
18
+ * SetupNetworkResult, as defined in setupNetwork.ts
19
+ *
20
+ * - Out of this parameter, we only care about two fields:
21
+ * - worldContract (which comes from createContract, see
22
+ * https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/vanilla/packages/client/src/mud/setupNetwork.ts#L31).
23
+ * - waitForTransaction (which comes from syncToRecs, see
24
+ * https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/vanilla/packages/client/src/mud/setupNetwork.ts#L39).
25
+ *
26
+ * - From the second parameter, which is a ClientComponent,
27
+ * we only care about Counter. This parameter comes to use
28
+ * through createClientComponents.ts, but it originates in
29
+ * syncToRecs
30
+ (https://github.com/latticexyz/mud/blob/26dabb34321eedff7a43f3fcb46da4f3f5ba3708/templates/vanilla/packages/client/src/mud/setupNetwork.ts#L39).
31
+ */
9
32
  { worldContract, waitForTransaction }: SetupNetworkResult,
10
33
  { Counter }: ClientComponents
11
34
  ) {
12
35
  const increment = async () => {
36
+ /*
37
+ * Because IncrementSystem
38
+ * (https://mud.dev/tutorials/walkthrough/minimal-onchain#incrementsystemsol)
39
+ * is in the root namespace, `.increment` can be called directly
40
+ * on the World contract.
41
+ */
13
42
  const tx = await worldContract.write.increment();
14
43
  await waitForTransaction(tx);
15
44
  return getComponentValue(Counter, singletonEntity);
@@ -1,24 +1,82 @@
1
+ /*
2
+ * Network specific configuration for the client.
3
+ * By default connect to the anvil test network.
4
+ *
5
+ */
6
+
7
+ /*
8
+ * By default the template just creates a temporary wallet
9
+ * (called a burner wallet) and uses a faucet (on our test net)
10
+ * to get ETH for it.
11
+ *
12
+ * See https://mud.dev/tutorials/minimal/deploy#wallet-managed-address
13
+ * for how to use the user's own address instead.
14
+ */
1
15
  import { getBurnerPrivateKey } from "@latticexyz/common";
2
- import worldsJson from "contracts/worlds.json";
3
- import { supportedChains } from "./supportedChains";
4
16
 
5
- const worlds = worldsJson as Partial<Record<string, { address: string; blockNumber?: number }>>;
17
+ /*
18
+ * Import the addresses of the World, possibly on multiple chains,
19
+ * from packages/contracts/worlds.json. When the contracts package
20
+ * deploys a new `World`, it updates this file.
21
+ */
22
+ import worlds from "contracts/worlds.json";
23
+
24
+ /*
25
+ * The supported chains.
26
+ * By default, there are only two chains here:
27
+ *
28
+ * - mudFoundry, the chain running on anvil that pnpm dev
29
+ * starts by default. It is similar to the viem anvil chain
30
+ * (see https://viem.sh/docs/clients/test.html), but with the
31
+ * basefee set to zero to avoid transaction fees.
32
+ * - latticeTestnet, our public test network.
33
+ *
34
+ * See https://mud.dev/tutorials/minimal/deploy#run-the-user-interface
35
+ * for instructions on how to add networks.
36
+ */
37
+
38
+ import { supportedChains } from "./supportedChains";
6
39
 
7
40
  export async function getNetworkConfig() {
8
41
  const params = new URLSearchParams(window.location.search);
42
+
43
+ /*
44
+ * The chain ID is the first item available from this list:
45
+ * 1. chainId query parameter
46
+ * 2. chainid query parameter
47
+ * 3. The VITE_CHAIN_ID environment variable set when the
48
+ * vite dev server was started or client was built
49
+ * 4. The default, 31337 (anvil)
50
+ */
9
51
  const chainId = Number(params.get("chainId") || params.get("chainid") || import.meta.env.VITE_CHAIN_ID || 31337);
52
+
53
+ /*
54
+ * Find the chain (unless it isn't in the list of supported chains).
55
+ */
10
56
  const chainIndex = supportedChains.findIndex((c) => c.id === chainId);
11
57
  const chain = supportedChains[chainIndex];
12
58
  if (!chain) {
13
59
  throw new Error(`Chain ${chainId} not found`);
14
60
  }
15
61
 
62
+ /*
63
+ * Get the address of the World. If you want to use a
64
+ * different address than the one in worlds.json,
65
+ * provide it as worldAddress in the query string.
66
+ */
16
67
  const world = worlds[chain.id.toString()];
17
68
  const worldAddress = params.get("worldAddress") || world?.address;
18
69
  if (!worldAddress) {
19
70
  throw new Error(`No world address found for chain ${chainId}. Did you run \`mud deploy\`?`);
20
71
  }
21
72
 
73
+ /*
74
+ * MUD clients use events to synchronize the database, meaning
75
+ * they need to look as far back as when the World was started.
76
+ * The block number for the World start can be specified either
77
+ * on the URL (as initialBlockNumber) or in the worlds.json
78
+ * file. If neither has it, it starts at the first block, zero.
79
+ */
22
80
  const initialBlockNumber = params.has("initialBlockNumber")
23
81
  ? Number(params.get("initialBlockNumber"))
24
82
  : world?.blockNumber ?? 0n;
@@ -1,3 +1,7 @@
1
+ /*
2
+ * This file sets up all the definitions required for a MUD client.
3
+ */
4
+
1
5
  import { createClientComponents } from "./createClientComponents";
2
6
  import { createSystemCalls } from "./createSystemCalls";
3
7
  import { setupNetwork } from "./setupNetwork";
@@ -8,6 +12,7 @@ export async function setup() {
8
12
  const network = await setupNetwork();
9
13
  const components = createClientComponents(network);
10
14
  const systemCalls = createSystemCalls(network, components);
15
+
11
16
  return {
12
17
  network,
13
18
  components,
@@ -1,11 +1,27 @@
1
+ /*
2
+ * The MUD client code is built on top of viem
3
+ * (https://viem.sh/docs/getting-started.html).
4
+ * This line imports the functions we need from it.
5
+ */
1
6
  import { createPublicClient, fallback, webSocket, http, createWalletClient, Hex, parseEther, ClientConfig } from "viem";
2
7
  import { createFaucetService } from "@latticexyz/services/faucet";
3
8
  import { encodeEntity, syncToRecs } from "@latticexyz/store-sync/recs";
9
+
4
10
  import { getNetworkConfig } from "./getNetworkConfig";
5
11
  import { world } from "./world";
6
12
  import IWorldAbi from "contracts/abi/IWorld.sol/IWorld.abi.json";
7
13
  import { createBurnerAccount, createContract, transportObserver, ContractWrite } from "@latticexyz/common";
14
+
8
15
  import { Subject, share } from "rxjs";
16
+
17
+ /*
18
+ * Import our MUD config, which includes strong types for
19
+ * our tables and other config options. We use this to generate
20
+ * things like RECS components and get back strong types for them.
21
+ *
22
+ * See https://mud.dev/tutorials/walkthrough/minimal-onchain#mudconfigts
23
+ * for the source of this information.
24
+ */
9
25
  import mudConfig from "contracts/mud.config";
10
26
 
11
27
  export type SetupNetworkResult = Awaited<ReturnType<typeof setupNetwork>>;
@@ -13,6 +29,10 @@ export type SetupNetworkResult = Awaited<ReturnType<typeof setupNetwork>>;
13
29
  export async function setupNetwork() {
14
30
  const networkConfig = await getNetworkConfig();
15
31
 
32
+ /*
33
+ * Create a viem public (read only) client
34
+ * (https://viem.sh/docs/clients/public.html)
35
+ */
16
36
  const clientOptions = {
17
37
  chain: networkConfig.chain,
18
38
  transport: transportObserver(fallback([webSocket(), http()])),
@@ -21,13 +41,25 @@ export async function setupNetwork() {
21
41
 
22
42
  const publicClient = createPublicClient(clientOptions);
23
43
 
44
+ /*
45
+ * Create a temporary wallet and a viem client for it
46
+ * (see https://viem.sh/docs/clients/wallet.html).
47
+ */
24
48
  const burnerAccount = createBurnerAccount(networkConfig.privateKey as Hex);
25
49
  const burnerWalletClient = createWalletClient({
26
50
  ...clientOptions,
27
51
  account: burnerAccount,
28
52
  });
29
53
 
54
+ /*
55
+ * Create an observable for contract writes that we can
56
+ * pass into MUD dev tools for transaction observability.
57
+ */
30
58
  const write$ = new Subject<ContractWrite>();
59
+
60
+ /*
61
+ * Create an object for communicating with the deployed World.
62
+ */
31
63
  const worldContract = createContract({
32
64
  address: networkConfig.worldAddress as Hex,
33
65
  abi: IWorldAbi,
@@ -36,6 +68,12 @@ export async function setupNetwork() {
36
68
  onWrite: (write) => write$.next(write),
37
69
  });
38
70
 
71
+ /*
72
+ * Sync on-chain state into RECS and keeps our client in sync.
73
+ * Uses the MUD indexer if available, otherwise falls back
74
+ * to the viem publicClient to make RPC calls to fetch MUD
75
+ * events from the chain.
76
+ */
39
77
  const { components, latestBlock$, blockStorageOperations$, waitForTransaction } = await syncToRecs({
40
78
  world,
41
79
  config: mudConfig,
@@ -44,7 +82,11 @@ export async function setupNetwork() {
44
82
  startBlock: BigInt(networkConfig.initialBlockNumber),
45
83
  });
46
84
 
47
- // Request drip from faucet
85
+ /*
86
+ * If there is a faucet, request (test) ETH if you have
87
+ * less than 1 ETH. Repeat every 20 seconds to ensure you don't
88
+ * run out.
89
+ */
48
90
  if (networkConfig.faucetServiceUrl) {
49
91
  const address = burnerAccount.address;
50
92
  console.info("[Dev Faucet]: Player address -> ", address);
@@ -1,4 +1,19 @@
1
+ /*
2
+ * The supported chains.
3
+ * By default, there are only two chains here:
4
+ *
5
+ * - mudFoundry, the chain running on anvil that pnpm dev
6
+ * starts by default. It is similar to the viem anvil chain
7
+ * (see https://viem.sh/docs/clients/test.html), but with the
8
+ * basefee set to zero to avoid transaction fees.
9
+ * - latticeTestnet, our public test network.
10
+ *
11
+ */
12
+
1
13
  import { MUDChain, latticeTestnet, mudFoundry } from "@latticexyz/common/chains";
2
14
 
3
- // If you are deploying to chains other than anvil or Lattice testnet, add them here
15
+ /*
16
+ * See https://mud.dev/tutorials/minimal/deploy#run-the-user-interface
17
+ * for instructions on how to add networks.
18
+ */
4
19
  export const supportedChains: MUDChain[] = [mudFoundry, latticeTestnet];
@@ -0,0 +1,2 @@
1
+ declare const worlds: Partial<Record<string, { address: string; blockNumber?: number }>>;
2
+ export default worlds;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-mud",
3
- "version": "2.0.0-next.7",
3
+ "version": "2.0.0-next.8",
4
4
  "description": "Create a new MUD project",
5
5
  "license": "MIT",
6
6
  "author": "Lattice <mud@lattice.xyz>",