Skip to content

Commit

Permalink
Merge branch 'main' into kumpis/show-transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
karooolis authored Aug 27, 2024
2 parents ebd419e + e583fc9 commit 5902737
Show file tree
Hide file tree
Showing 25 changed files with 338 additions and 178 deletions.
5 changes: 5 additions & 0 deletions .changeset/clean-worms-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@latticexyz/common": patch
---

Updated all custom Viem actions to properly call other actions via `getAction` so they can be composed.
4 changes: 2 additions & 2 deletions .changeset/real-waves-bathe.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
"@latticexyz/create-mud": patch
"create-mud": patch
---

Added `@latticexyz/explorer` and `@latticexyz/store-indexer` to all MUD templates. Updated default `worlds.json` config and world address.
New projects created with `pnpm create mud` now include the World Explorer and SQLite indexer running as additional services.
4 changes: 2 additions & 2 deletions .changeset/swift-rabbits-appear.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
"@latticexyz/explorer": minor
---

Initial release of the @latticexyz/explorer package. Explorer is a standalone tool designed to explore and manage worlds. This initial release supports local worlds, with plans to extend support to any world in the future.
Initial release of the `@latticexyz/explorer` package. World Explorer is a standalone tool designed to explore and manage worlds. This initial release supports local worlds, with plans to extend support to any world in the future.

Read more on how to get started or contribute in the [Explorer README](https://github.com/latticexyz/mud/blob/main/packages/explorer/README.md).
Read more on how to get started or contribute in the [World Explorer README](https://github.com/latticexyz/mud/blob/main/packages/explorer/README.md).
20 changes: 20 additions & 0 deletions .github/workflows/changeset.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Changeset

on:
pull_request:

jobs:
changeset:
name: Validate changeset
runs-on: depot-ubuntu-22.04-16
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Setup
uses: ./.github/actions/setup

- name: Changeset
run: pnpm changeset status --since origin/main
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"build": "turbo run build",
"changelog:generate": "bun scripts/changelog.ts",
"clean": "turbo run clean",
"dev": "TSUP_SKIP_DTS=true turbo run dev --concurrency 100",
"dev": "TSUP_SKIP_DTS=true turbo run dev --concurrency 100 --filter=!@latticexyz/explorer",
"dist-tag-rm": "pnpm recursive exec -- sh -c 'npm dist-tag rm $(cat package.json | jq -r \".name\") $TAG || true'",
"docs:generate:api": "bun scripts/render-api-docs.ts",
"foundryup": "curl -L https://foundry.paradigm.xyz | bash && bash ~/.foundry/bin/foundryup",
Expand Down
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"test:ci": "pnpm run test"
},
"dependencies": {
"@ark/util": "catalog:",
"@aws-sdk/client-kms": "^3.556.0",
"@latticexyz/abi-ts": "workspace:*",
"@latticexyz/common": "workspace:*",
Expand Down
20 changes: 10 additions & 10 deletions packages/cli/src/deploy/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Account, Address, Chain, Client, Hex, Transport } from "viem";
import { Account, Address, Chain, Client, Hex, Transport, stringToHex } from "viem";
import { ensureDeployer } from "./ensureDeployer";
import { deployWorld } from "./deployWorld";
import { ensureTables } from "./ensureTables";
Expand All @@ -15,7 +15,7 @@ import { ensureContractsDeployed } from "./ensureContractsDeployed";
import { randomBytes } from "crypto";
import { ensureWorldFactory } from "./ensureWorldFactory";
import { Table } from "@latticexyz/config";
import { ensureResourceLabels } from "./ensureResourceLabels";
import { ensureResourceTags } from "./ensureResourceTags";

type DeployOptions = {
client: Client<Transport, Chain | undefined, Account>;
Expand Down Expand Up @@ -90,14 +90,10 @@ export async function deploy({
throw new Error(`Unsupported World version: ${worldDeploy.worldVersion}`);
}

const resources = [
...tables.map((table) => ({ resourceId: table.tableId, label: table.label })),
...systems.map((system) => ({ resourceId: system.systemId, label: system.label })),
];
const namespaceTxs = await ensureNamespaceOwner({
client,
worldDeploy,
resourceIds: resources.map(({ resourceId }) => resourceId),
resourceIds: [...tables.map(({ tableId }) => tableId), ...systems.map(({ systemId }) => systemId)],
});

debug("waiting for all namespace registration transactions to confirm");
Expand Down Expand Up @@ -129,13 +125,17 @@ export async function deploy({
worldDeploy,
modules,
});
const labelTxs = await ensureResourceLabels({

const tableTags = tables.map(({ tableId: resourceId, label }) => ({ resourceId, tag: "label", value: label }));

const tagTxs = await ensureResourceTags({
client,
worldDeploy,
resources,
tags: tableTags,
valueToHex: stringToHex,
});

const txs = [...tableTxs, ...systemTxs, ...functionTxs, ...moduleTxs, ...labelTxs];
const txs = [...tableTxs, ...systemTxs, ...functionTxs, ...moduleTxs, ...tagTxs];

// wait for each tx separately/serially, because parallelizing results in RPC errors
debug("waiting for all transactions to confirm");
Expand Down
66 changes: 0 additions & 66 deletions packages/cli/src/deploy/ensureResourceLabels.ts

This file was deleted.

70 changes: 70 additions & 0 deletions packages/cli/src/deploy/ensureResourceTags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Hex, Client, Transport, Chain, Account, stringToHex, BaseError } from "viem";
import { WorldDeploy } from "./common";
import { debug } from "./debug";
import { hexToResource, writeContract } from "@latticexyz/common";
import { identity, isDefined } from "@latticexyz/common/utils";
import metadataConfig from "@latticexyz/world-module-metadata/mud.config";
import metadataAbi from "@latticexyz/world-module-metadata/out/IMetadataSystem.sol/IMetadataSystem.abi.json" assert { type: "json" };
import { getRecord } from "./getRecord";

export type ResourceTag<value> = {
resourceId: Hex;
tag: string;
value: value;
};

export async function ensureResourceTags<const value>({
client,
worldDeploy,
tags,
valueToHex = identity,
}: {
readonly client: Client<Transport, Chain | undefined, Account>;
readonly worldDeploy: WorldDeploy;
readonly tags: readonly ResourceTag<value>[];
} & (value extends Hex
? { readonly valueToHex?: (value: value) => Hex }
: { readonly valueToHex: (value: value) => Hex })): Promise<readonly Hex[]> {
const pendingTags = (
await Promise.all(
tags.map(async (tag) => {
const { value } = await getRecord({
client,
worldDeploy,
table: metadataConfig.tables.metadata__ResourceTag,
key: { resource: tag.resourceId, tag: stringToHex(tag.tag, { size: 32 }) },
});
if (value === valueToHex(tag.value)) return;
return tag;
}),
)
).filter(isDefined);

if (pendingTags.length === 0) return [];

debug("setting", pendingTags.length, "resource tags");
return (
await Promise.all(
pendingTags.map(async (tag) => {
const resource = hexToResource(tag.resourceId);
// TODO: move to resourceToDebugString
const resourceString = `${resource.type}:${resource.namespace}:${resource.name}`;
debug(`tagging ${resourceString} with ${tag.tag}: ${JSON.stringify(tag.value)}`);
try {
return await writeContract(client, {
chain: client.chain ?? null,
address: worldDeploy.address,
abi: metadataAbi,
// TODO: replace with batchCall (https://github.com/latticexyz/mud/issues/1645)
functionName: "metadata__setResourceTag",
args: [tag.resourceId, stringToHex(tag.tag, { size: 32 }), valueToHex(tag.value)],
});
} catch (error) {
debug(
`failed to set resource tag for ${resourceString}, skipping\n ${error instanceof BaseError ? error.shortMessage : error}`,
);
}
}),
)
).filter(isDefined);
}
46 changes: 46 additions & 0 deletions packages/cli/src/deploy/getRecord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
decodeValueArgs,
getKeySchema,
getKeyTuple,
getSchemaPrimitives,
getSchemaTypes,
getValueSchema,
} from "@latticexyz/protocol-parser/internal";
import { WorldDeploy, worldAbi } from "./common";
import { Client, Hex } from "viem";
import { readContract } from "viem/actions";
import { Table } from "@latticexyz/config";
import { mapObject } from "@latticexyz/common/utils";
import { show } from "@ark/util";

export async function getRecord<table extends Table>({
client,
worldDeploy,
table,
key,
}: {
readonly client: Client;
readonly worldDeploy: WorldDeploy;
readonly table: table;
readonly key: getSchemaPrimitives<getKeySchema<table>>;
}): Promise<show<getSchemaPrimitives<table["schema"]>>> {
const [staticData, encodedLengths, dynamicData] = (await readContract(client, {
blockNumber: worldDeploy.stateBlock,
address: worldDeploy.address,
abi: worldAbi,
functionName: "getRecord",
args: [table.tableId, getKeyTuple(table, key)],
// TODO: remove cast once https://github.com/wevm/viem/issues/2125 is resolved
// has something to do function overloads and TS having a hard time inferring which args to use
})) as [Hex, Hex, Hex];
const record = {
...key,
...decodeValueArgs(getSchemaTypes(getValueSchema(table)), {
staticData,
encodedLengths,
dynamicData,
}),
};
// return in schema order
return mapObject(table.schema, (value, key) => record[key as never]) as never;
}
8 changes: 4 additions & 4 deletions packages/cli/src/runDeploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ export async function runDeploy(opts: DeployOptions): Promise<WorldDeploy> {
});
const modules = await configToModules(config, outDir);

const tables = Object.values(config.namespaces)
.flatMap((namespace) => Object.values(namespace.tables))
.filter((table) => !table.deploy.disabled);

const account = await (async () => {
if (opts.kms) {
const keyId = process.env.AWS_KMS_KEY_ID;
Expand Down Expand Up @@ -129,10 +133,6 @@ export async function runDeploy(opts: DeployOptions): Promise<WorldDeploy> {

console.log("Deploying from", client.account.address);

const tables = Object.values(config.namespaces)
.flatMap((namespace) => Object.values(namespace.tables))
.filter((table) => !table.deploy.disabled);

const startTime = Date.now();
const worldDeploy = await deploy({
deployerAddress: opts.deployerAddress as Hex | undefined,
Expand Down
3 changes: 2 additions & 1 deletion packages/common/src/createFeeRef.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { EstimateFeesPerGasParameters, Client, EstimateFeesPerGasReturnType } from "viem";
import { estimateFeesPerGas } from "viem/actions";
import { getAction } from "viem/utils";

export type CreateFeeRefOptions = {
client: Client;
Expand All @@ -17,7 +18,7 @@ export async function createFeeRef({ client, args, refreshInterval }: CreateFeeR
const feeRef: FeeRef = { fees: {}, lastUpdatedTimestamp: 0 };

async function updateFees(): Promise<void> {
const fees = await estimateFeesPerGas(client, args);
const fees = await getAction(client, estimateFeesPerGas, "estimateFeesPerGas")(args);
feeRef.fees = fees;
feeRef.lastUpdatedTimestamp = Date.now();
}
Expand Down
3 changes: 2 additions & 1 deletion packages/common/src/createNonceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { debug as parentDebug } from "./debug";
import { getNonceManagerId } from "./getNonceManagerId";
import { getTransactionCount } from "viem/actions";
import PQueue from "p-queue";
import { getAction } from "viem/utils";

const debug = parentDebug.extend("createNonceManager");

Expand Down Expand Up @@ -66,7 +67,7 @@ export function createNonceManager({

async function resetNonce(): Promise<void> {
ref.noncePromise ??= (async (): Promise<void> => {
ref.nonce = await getTransactionCount(client, { address, blockTag });
ref.nonce = await getAction(client, getTransactionCount, "getTransactionCount")({ address, blockTag });
ref.noncePromise = null;
channel?.postMessage(JSON.stringify(ref.nonce));
debug("reset nonce to", ref.nonce);
Expand Down
4 changes: 3 additions & 1 deletion packages/common/src/getFeeRef.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { getChainId } from "viem/actions";
import { CreateFeeRefOptions, FeeRef, createFeeRef } from "./createFeeRef";
import { getAction } from "viem/utils";

const feeRefs = new Map<number, FeeRef>();

export async function getFeeRef(opts: CreateFeeRefOptions): Promise<FeeRef> {
const chainId = opts.args?.chain?.id ?? opts.client.chain?.id ?? (await getChainId(opts.client));
const chainId =
opts.args?.chain?.id ?? opts.client.chain?.id ?? (await getAction(opts.client, getChainId, "getChainId")({}));

const existingFeeRef = feeRefs.get(chainId);
if (existingFeeRef) {
Expand Down
3 changes: 2 additions & 1 deletion packages/common/src/getNonceManagerId.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BlockTag, Client, Hex, getAddress } from "viem";
import { getChainId } from "viem/actions";
import { getAction } from "viem/utils";

export async function getNonceManagerId({
client,
Expand All @@ -11,6 +12,6 @@ export async function getNonceManagerId({
blockTag: BlockTag;
}): Promise<string> {
// TODO: improve this so we don't have to call getChainId every time
const chainId = client.chain?.id ?? (await getChainId(client));
const chainId = client.chain?.id ?? (await getAction(client, getChainId, "getChainId")({}));
return `mud:createNonceManager:${chainId}:${getAddress(address)}:${blockTag}`;
}
3 changes: 2 additions & 1 deletion packages/common/src/sendTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { debug as parentDebug } from "./debug";
import { getNonceManager } from "./getNonceManager";
import { parseAccount } from "viem/accounts";
import { getFeeRef } from "./getFeeRef";
import { getAction } from "viem/utils";

const debug = parentDebug.extend("sendTransaction");

Expand Down Expand Up @@ -75,7 +76,7 @@ export async function sendTransaction<
...feeRef.fees,
};
debug("sending tx to", request.to, "with nonce", nonce);
return await viem_sendTransaction(client, params);
return await getAction(client, viem_sendTransaction, "sendTransaction")(params);
},
{
retries: 3,
Expand Down
Loading

0 comments on commit 5902737

Please sign in to comment.