Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(create-mud): use new sync packages #1214

Merged
merged 83 commits into from
Aug 9, 2023
Merged
Changes from 1 commit
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
6bc4dcd
migrate vanilla template to new sync stack
holic Jul 31, 2023
960300d
update types
holic Jul 31, 2023
9858d12
simplify
holic Jul 31, 2023
97f8a3c
migrate react client
holic Jul 31, 2023
8d7b706
migrate threejs
holic Jul 31, 2023
35c175c
migrate phaser template
holic Jul 31, 2023
5eb8bf1
update phaser example
holic Jul 31, 2023
b29a6fc
migrate example react
holic Jul 31, 2023
c6761eb
migrate example vanilla
holic Jul 31, 2023
fffdb10
start migrating e2e
holic Jul 31, 2023
d79c9d7
fix type
holic Jul 31, 2023
272cd6a
regen components
holic Aug 1, 2023
6cf4c1b
e2e wip
holic Aug 1, 2023
9f055af
fix node warning
holic Aug 1, 2023
07e9780
more wip
holic Aug 1, 2023
a5428f7
some e2e fixes
alvrs Aug 1, 2023
68f18ec
fix tests
holic Aug 2, 2023
9d9e5b4
removed unused method
holic Aug 2, 2023
3bf4eb8
make e2e tests work
holic Aug 2, 2023
0cb6cd9
bump timeout
holic Aug 2, 2023
7a150f6
disable that for now
holic Aug 2, 2023
0c34c1e
maybe fix tests
holic Aug 2, 2023
447c805
latestBlockNumberProcessed -> lastBlockNumberProcessed
holic Aug 2, 2023
89a711e
Merge remote-tracking branch 'origin/main' into holic/template-sync-s…
holic Aug 4, 2023
0db5373
update singleton entity
holic Aug 4, 2023
6bb33d8
attempt to override gas with custom transport and chain formatter
holic Aug 4, 2023
212c78c
nope, custom account doesn't work either
holic Aug 4, 2023
a0235f1
get zero fees working
holic Aug 4, 2023
08023c9
update templates etc
holic Aug 4, 2023
e46787c
bump es target
holic Aug 4, 2023
917c6d9
remove dupe keys after merge
holic Aug 4, 2023
490700f
Merge remote-tracking branch 'origin/main' into holic/template-sync-s…
holic Aug 4, 2023
f05eb13
Create tame-lemons-play.md
holic Aug 4, 2023
18b1476
a few more updates
holic Aug 4, 2023
c8b7cbd
Update tame-lemons-play.md
holic Aug 4, 2023
2b2a474
Update tame-lemons-play.md
holic Aug 4, 2023
8f5eff7
prettier
holic Aug 4, 2023
ba6f360
Update tame-lemons-play.md
holic Aug 7, 2023
f90031f
remove anvil.db before starting indexer
alvrs Aug 7, 2023
15c7ec3
Merge branch 'main' into holic/template-sync-stack
alvrs Aug 7, 2023
8a9a760
rework sqlite file handling
holic Aug 7, 2023
910eb24
rebuild recs components
holic Aug 7, 2023
a1d300f
fix start command
holic Aug 7, 2023
6840edb
I don't think this will help
holic Aug 7, 2023
3dceee3
console.log the indexer failures for playwright
holic Aug 7, 2023
eecfbad
move things around a bit
holic Aug 7, 2023
00b9b6c
log initial state
holic Aug 7, 2023
cb70bb8
this feels better
holic Aug 7, 2023
d463df2
Revert "log initial state"
holic Aug 7, 2023
eeb0a17
clean up
holic Aug 7, 2023
de05378
Update tame-lemons-play.md
holic Aug 7, 2023
39d160e
truncate instead of rm
alvrs Aug 7, 2023
08cbfb9
consolidate client config
holic Aug 7, 2023
2a44ceb
use anvil.js
holic Aug 7, 2023
81cb59e
don't use ws
holic Aug 7, 2023
f4defdb
get anvil.js working
holic Aug 8, 2023
7c1d06d
fix indexer shutdown
holic Aug 8, 2023
1b1e190
try our own exit tracking
holic Aug 8, 2023
05dc486
try an indexer instance per test
holic Aug 8, 2023
0666626
small bit of clean up
holic Aug 8, 2023
8d907e2
wip mud contract wrapper
holic Aug 8, 2023
063ea59
wip contract wrapper with nonce handling
holic Aug 8, 2023
2014146
add todo
holic Aug 8, 2023
9bb6c27
Merge remote-tracking branch 'origin/main' into holic/template-sync-s…
holic Aug 8, 2023
e89b317
clean up
holic Aug 8, 2023
891549a
throw on non-nonce issues
holic Aug 8, 2023
8a989d1
move getTableIds
holic Aug 9, 2023
cf7474c
simulate before write so we know when to increment nonce
holic Aug 9, 2023
397b8c7
deprecate/move TableId utils, replace with pure functions
holic Aug 9, 2023
945d75c
rename new utils
holic Aug 9, 2023
4f192b1
fix export
holic Aug 9, 2023
51a8017
missed an import
holic Aug 9, 2023
48ddd5a
Merge remote-tracking branch 'origin/main' into holic/template-sync-s…
holic Aug 9, 2023
8b9ede7
Merge remote-tracking branch 'origin/main' into holic/template-sync-s…
holic Aug 9, 2023
cf8aef2
revert changeset
holic Aug 9, 2023
0a810f5
update changeset
holic Aug 9, 2023
090b008
getContract -> createContract
holic Aug 9, 2023
051c510
move zero gas fee
holic Aug 9, 2023
2e270d1
move UnionOmit
holic Aug 9, 2023
f13d6d6
Merge remote-tracking branch 'origin/main' into holic/template-sync-s…
holic Aug 9, 2023
afe9613
don't need this anymore
holic Aug 9, 2023
575748e
Update .changeset/tame-lemons-play.md
holic Aug 9, 2023
d4984cc
Update tame-lemons-play.md
holic Aug 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
update phaser example
  • Loading branch information
holic committed Jul 31, 2023
commit 5eb8bf1db6813c95b29759ec29c4313e08b2915f
4 changes: 3 additions & 1 deletion examples/minimal/package.json
Original file line number Diff line number Diff line change
@@ -4,7 +4,9 @@
"scripts": {
"build": "pnpm recursive run build",
"clean": "pnpm recursive run clean",
"dev": "concurrently -n contracts,client -c cyan,magenta 'cd packages/contracts && pnpm run dev' 'cd packages/client-react && pnpm run dev'",
"dev": "concurrently -n contracts,client -c cyan,magenta 'pnpm run dev:contracts' 'pnpm run dev:client-react'",
"dev-with-phaser": "concurrently -n contracts,client -c cyan,magenta 'pnpm run dev:contracts' 'pnpm run dev:client-phaser'",
"dev-with-vanilla": "concurrently -n contracts,client -c cyan,magenta 'pnpm run dev:contracts' 'pnpm run dev:client-vanilla'",
"dev:client-phaser": "pnpm --filter 'client-phaser' run dev",
"dev:client-react": "pnpm --filter 'client-react' run dev",
"dev:client-vanilla": "pnpm --filter 'client-vanilla' run dev",
2 changes: 1 addition & 1 deletion examples/minimal/packages/client-phaser/package.json
Original file line number Diff line number Diff line change
@@ -13,14 +13,14 @@
"@ethersproject/providers": "^5.7.2",
"@improbable-eng/grpc-web": "^0.15.0",
"@latticexyz/common": "link:../../../../packages/common",
"@latticexyz/ecs-browser": "link:../../../../packages/ecs-browser",
"@latticexyz/network": "link:../../../../packages/network",
"@latticexyz/phaserx": "link:../../../../packages/phaserx",
"@latticexyz/react": "link:../../../../packages/react",
"@latticexyz/recs": "link:../../../../packages/recs",
"@latticexyz/schema-type": "link:../../../../packages/schema-type",
"@latticexyz/services": "link:../../../../packages/services",
"@latticexyz/std-client": "link:../../../../packages/std-client",
"@latticexyz/store-sync": "link:../../../../packages/store-sync",
"@latticexyz/utils": "link:../../../../packages/utils",
"@latticexyz/world": "link:../../../../packages/world",
"async-mutex": "^0.4.0",
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { getComponentValue } from "@latticexyz/recs";
import { awaitStreamValue } from "@latticexyz/utils";
import { ClientComponents } from "./createClientComponents";
import { SetupNetworkResult } from "./setupNetwork";

export type SystemCalls = ReturnType<typeof createSystemCalls>;

export function createSystemCalls(
{ worldSend, txReduced$, singletonEntity }: SetupNetworkResult,
{ worldContract, waitForTransaction, singletonEntity }: SetupNetworkResult,
{ CounterTable }: ClientComponents
) {
const increment = async () => {
const tx = await worldSend("increment", []);
await awaitStreamValue(txReduced$, (txHash) => txHash === tx.hash);
// TODO: fix anvil issue where accounts can't send txs unless max fee is specified or is funded
const tx = await worldContract.write.increment({ maxFeePerGas: 0n, maxPriorityFeePerGas: 0n });
await waitForTransaction(tx);
return getComponentValue(CounterTable, singletonEntity);
};

Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
import { SetupContractConfig, getBurnerWallet } from "@latticexyz/std-client";
import { getBurnerWallet } from "@latticexyz/std-client";
import worldsJson from "contracts/worlds.json";
import { supportedChains } from "./supportedChains";

const worlds = worldsJson as Partial<Record<string, { address: string; blockNumber?: number }>>;

type NetworkConfig = SetupContractConfig & {
privateKey: string;
faucetServiceUrl?: string;
snapSync?: boolean;
};

export async function getNetworkConfig(): Promise<NetworkConfig> {
export async function getNetworkConfig() {
const params = new URLSearchParams(window.location.search);

const chainId = Number(params.get("chainId") || import.meta.env.VITE_CHAIN_ID || 31337);
const chainId = Number(params.get("chainId") || params.get("chainid") || import.meta.env.VITE_CHAIN_ID || 31337);
const chainIndex = supportedChains.findIndex((c) => c.id === chainId);
const chain = supportedChains[chainIndex];
if (!chain) {
@@ -28,26 +21,14 @@ export async function getNetworkConfig(): Promise<NetworkConfig> {

const initialBlockNumber = params.has("initialBlockNumber")
? Number(params.get("initialBlockNumber"))
: world?.blockNumber ?? -1; // -1 will attempt to find the block number from RPC
: world?.blockNumber ?? 0n;

return {
clock: {
period: 1000,
initialTime: 0,
syncInterval: 5000,
},
provider: {
chainId,
jsonRpcUrl: params.get("rpc") ?? chain.rpcUrls.default.http[0],
wsRpcUrl: params.get("wsRpc") ?? chain.rpcUrls.default.webSocket?.[0],
},
privateKey: getBurnerWallet().value,
chainId,
modeUrl: params.get("mode") ?? chain.modeUrl,
chain,
faucetServiceUrl: params.get("faucet") ?? chain.faucetUrl,
worldAddress,
initialBlockNumber,
snapSync: params.get("snapSync") === "true",
disableCache: params.get("cache") === "false",
};
}
109 changes: 44 additions & 65 deletions examples/minimal/packages/client-phaser/src/mud/setupNetwork.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,53 @@
import { setupMUDV2Network } from "@latticexyz/std-client";
import { createFastTxExecutor, createFaucetService, getSnapSyncRecords } from "@latticexyz/network";
import { createPublicClient, fallback, webSocket, http, createWalletClient, getContract, Hex, parseEther } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { createFaucetService } from "@latticexyz/network";
import { encodeEntity, syncToRecs } from "@latticexyz/store-sync/recs";
import { getNetworkConfig } from "./getNetworkConfig";
import { defineContractComponents } from "./contractComponents";
import { world } from "./world";
import { Contract, Signer, utils } from "ethers";
import { JsonRpcProvider } from "@ethersproject/providers";
import { IWorld__factory } from "contracts/types/ethers-contracts/factories/IWorld__factory";
import { getTableIds } from "@latticexyz/utils";
import storeConfig from "contracts/mud.config";

export type SetupNetworkResult = Awaited<ReturnType<typeof setupNetwork>>;

export async function setupNetwork() {
const contractComponents = defineContractComponents(world);
const networkConfig = await getNetworkConfig();
const result = await setupMUDV2Network<typeof contractComponents, typeof storeConfig>({
networkConfig,

const publicClient = createPublicClient({
chain: networkConfig.chain,
transport: fallback([webSocket(), http()]),
pollingInterval: 1000,
});

const { components, singletonEntity, latestBlock$, blockStorageOperations$, waitForTransaction } = await syncToRecs({
world,
contractComponents,
syncThread: "main",
storeConfig,
worldAbi: IWorld__factory.abi,
config: storeConfig,
address: networkConfig.worldAddress as Hex,
publicClient,
components: contractComponents,
startBlock: BigInt(networkConfig.initialBlockNumber),
});

const burnerAccount = privateKeyToAccount(networkConfig.privateKey as Hex);
const burnerWalletClient = createWalletClient({
account: burnerAccount,
chain: networkConfig.chain,
transport: fallback([webSocket(), http()]),
pollingInterval: 1000,
});

// Request drip from faucet
const signer = result.network.signer.get();
if (networkConfig.faucetServiceUrl && signer) {
const address = await signer.getAddress();
if (networkConfig.faucetServiceUrl) {
const address = burnerAccount.address;
console.info("[Dev Faucet]: Player address -> ", address);

const faucet = createFaucetService(networkConfig.faucetServiceUrl);

const requestDrip = async () => {
const balance = await signer.getBalance();
const balance = await publicClient.getBalance({ address });
console.info(`[Dev Faucet]: Player balance -> ${balance}`);
const lowBalance = balance?.lte(utils.parseEther("1"));
const lowBalance = balance < parseEther("1");
if (lowBalance) {
console.info("[Dev Faucet]: Balance is low, dripping funds to player");
// Double drip
@@ -48,55 +61,21 @@ export async function setupNetwork() {
setInterval(requestDrip, 20000);
}

const provider = result.network.providers.get().json;
const signerOrProvider = signer ?? provider;
// Create a World contract instance
const worldContract = IWorld__factory.connect(networkConfig.worldAddress, signerOrProvider);

if (networkConfig.snapSync) {
const currentBlockNumber = await provider.getBlockNumber();
const tableRecords = await getSnapSyncRecords(
networkConfig.worldAddress,
getTableIds(storeConfig),
currentBlockNumber,
signerOrProvider
);

console.log(`Syncing ${tableRecords.length} records`);
result.startSync(tableRecords, currentBlockNumber);
} else {
result.startSync();
}

// Create a fast tx executor
const fastTxExecutor =
signer?.provider instanceof JsonRpcProvider
? await createFastTxExecutor(signer as Signer & { provider: JsonRpcProvider })
: null;

// TODO: infer this from fastTxExecute signature?
type BoundFastTxExecuteFn<C extends Contract> = <F extends keyof C>(
func: F,
args: Parameters<C[F]>,
options?: {
retryCount?: number;
}
) => Promise<ReturnType<C[F]>>;

function bindFastTxExecute<C extends Contract>(contract: C): BoundFastTxExecuteFn<C> {
return async function (...args) {
if (!fastTxExecutor) {
throw new Error("no signer");
}
const { tx } = await fastTxExecutor.fastTxExecute(contract, ...args);
return await tx;
};
}

return {
...result,
worldContract,
worldSend: bindFastTxExecute(worldContract),
fastTxExecutor,
world,
components,
singletonEntity,
playerEntity: encodeEntity({ address: "address" }, { address: burnerWalletClient.account.address }),
publicClient,
walletClient: burnerWalletClient,
latestBlock$,
blockStorageOperations$,
waitForTransaction,
worldContract: getContract({
address: networkConfig.worldAddress as Hex,
abi: IWorld__factory.abi,
publicClient,
walletClient: burnerWalletClient,
}),
};
}
40 changes: 0 additions & 40 deletions examples/minimal/packages/client-phaser/src/ui/ECSBrowser.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import React from "react";
import styled from "styled-components";
import { SyncState } from "@latticexyz/network";
import { LoadingBar } from "./LoadingBar";
import { BootScreen } from "./BootScreen";
import { useComponentValue } from "@latticexyz/react";
import { useMUD } from "../../store";
import { SyncStep } from "@latticexyz/store-sync/recs";

export const LoadingScreen = () => {
const {
networkLayer: {
components: { LoadingState },
components: { SyncProgress },
singletonEntity,
},
} = useMUD();

const loadingState = useComponentValue(LoadingState, singletonEntity, {
msg: "Connecting...",
const syncProgress = useComponentValue(SyncProgress, singletonEntity, {
message: "Connecting",
percentage: 0,
state: SyncState.CONNECTING,
step: SyncStep.INITIALIZE,
});

if (loadingState.state === SyncState.LIVE) {
if (syncProgress.step === SyncStep.LIVE) {
return null;
}

return (
<BootScreen>
{loadingState.msg}
{syncProgress.message}…
<LoadingContainer>
{Math.floor(loadingState.percentage)}%
<Loading percentage={loadingState.percentage} />
{Math.floor(syncProgress.percentage)}%
<Loading percentage={syncProgress.percentage} />
</LoadingContainer>
</BootScreen>
);
2 changes: 0 additions & 2 deletions examples/minimal/packages/client-phaser/src/ui/UIRoot.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from "react";
import { useStore } from "../store";
import { Controls } from "./Controls";
import { ECSBrowser } from "./ECSBrowser";
import { LoadingScreen } from "./LoadingScreen";
import { Wrapper } from "./Wrapper";
import { Title } from "./Title";
@@ -19,7 +18,6 @@ export const UIRoot = () => {
return (
<Wrapper>
<LoadingScreen />
<ECSBrowser />
<Controls />

<Title />
6 changes: 3 additions & 3 deletions examples/minimal/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.