@latticexyz/cli 2.0.0-next.11 → 2.0.0-next.13
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/chunk-22IIKR4S.js +4 -0
- package/dist/chunk-22IIKR4S.js.map +1 -0
- package/dist/commands-AAHOIIJW.js +23 -0
- package/dist/commands-AAHOIIJW.js.map +1 -0
- package/dist/errors-XGN6V2Y3.js +2 -0
- package/dist/errors-XGN6V2Y3.js.map +1 -0
- package/dist/index.js +0 -1
- package/dist/mud.js +1 -18
- package/dist/mud.js.map +1 -1
- package/package.json +16 -12
- package/src/commands/deploy.ts +7 -30
- package/src/commands/dev-contracts.ts +74 -138
- package/src/commands/test.ts +30 -36
- package/src/commands/trace.ts +7 -5
- package/src/debug.ts +3 -0
- package/src/deploy/assertNamespaceOwner.ts +42 -0
- package/src/deploy/common.ts +72 -0
- package/src/deploy/configToTables.ts +68 -0
- package/src/deploy/create2/README.md +9 -0
- package/src/deploy/create2/deployment.json +7 -0
- package/src/deploy/debug.ts +3 -0
- package/src/deploy/deploy.ts +108 -0
- package/src/deploy/deployWorld.ts +33 -0
- package/src/deploy/ensureContract.ts +49 -0
- package/src/deploy/ensureContractsDeployed.ts +25 -0
- package/src/deploy/ensureDeployer.ts +36 -0
- package/src/deploy/ensureFunctions.ts +86 -0
- package/src/deploy/ensureModules.ts +72 -0
- package/src/deploy/ensureSystems.ts +161 -0
- package/src/deploy/ensureTables.ts +65 -0
- package/src/deploy/ensureWorldFactory.ts +34 -0
- package/src/deploy/getFunctions.ts +58 -0
- package/src/deploy/getResourceAccess.ts +51 -0
- package/src/deploy/getResourceIds.ts +31 -0
- package/src/deploy/getSystems.ts +48 -0
- package/src/deploy/getTableValue.ts +30 -0
- package/src/deploy/getTables.ts +59 -0
- package/src/deploy/getWorldDeploy.ts +39 -0
- package/src/deploy/logsToWorldDeploy.ts +49 -0
- package/src/deploy/resolveConfig.ts +154 -0
- package/src/deploy/resourceLabel.ts +3 -0
- package/src/index.ts +1 -1
- package/src/mud.ts +37 -31
- package/src/runDeploy.ts +128 -0
- package/src/utils/modules/constants.ts +1 -2
- package/src/utils/utils/getContractData.ts +2 -5
- package/dist/chunk-TW3YGZ4D.js +0 -11
- package/dist/chunk-TW3YGZ4D.js.map +0 -1
- package/src/utils/deploy.ts +0 -254
- package/src/utils/deployHandler.ts +0 -93
- package/src/utils/modules/getInstallModuleCallData.ts +0 -27
- package/src/utils/modules/getUserModules.ts +0 -5
- package/src/utils/modules/types.ts +0 -14
- package/src/utils/systems/getGrantAccessCallData.ts +0 -29
- package/src/utils/systems/getRegisterFunctionSelectorsCallData.ts +0 -57
- package/src/utils/systems/getRegisterSystemCallData.ts +0 -17
- package/src/utils/systems/types.ts +0 -9
- package/src/utils/systems/utils.ts +0 -42
- package/src/utils/tables/getRegisterTableCallData.ts +0 -49
- package/src/utils/tables/getTableIds.ts +0 -18
- package/src/utils/tables/types.ts +0 -12
- package/src/utils/utils/confirmNonce.ts +0 -24
- package/src/utils/utils/deployContract.ts +0 -33
- package/src/utils/utils/fastTxExecute.ts +0 -56
- package/src/utils/utils/getChainId.ts +0 -10
- package/src/utils/utils/setInternalFeePerGas.ts +0 -49
- package/src/utils/utils/types.ts +0 -21
- package/src/utils/world.ts +0 -28
@@ -0,0 +1,59 @@
|
|
1
|
+
import { Client, parseAbiItem, decodeAbiParameters, parseAbiParameters } from "viem";
|
2
|
+
import { Table } from "./configToTables";
|
3
|
+
import { hexToResource } from "@latticexyz/common";
|
4
|
+
import { WorldDeploy, storeTables } from "./common";
|
5
|
+
import { debug } from "./debug";
|
6
|
+
import { storeSetRecordEvent } from "@latticexyz/store";
|
7
|
+
import { getLogs } from "viem/actions";
|
8
|
+
import { KeySchema, ValueSchema, decodeKey, decodeValueArgs, hexToSchema } from "@latticexyz/protocol-parser";
|
9
|
+
|
10
|
+
export async function getTables({
|
11
|
+
client,
|
12
|
+
worldDeploy,
|
13
|
+
}: {
|
14
|
+
readonly client: Client;
|
15
|
+
readonly worldDeploy: WorldDeploy;
|
16
|
+
}): Promise<readonly Table[]> {
|
17
|
+
// This assumes we only use `Tables._set(...)`, which is true as of this writing.
|
18
|
+
// TODO: PR to viem's getLogs to accept topics array so we can filter on all store events and quickly recreate this table's current state
|
19
|
+
// TODO: consider moving this to a batched getRecord for Tables table
|
20
|
+
|
21
|
+
debug("looking up tables for", worldDeploy.address);
|
22
|
+
const logs = await getLogs(client, {
|
23
|
+
strict: true,
|
24
|
+
// this may fail for certain RPC providers with block range limits
|
25
|
+
// if so, could potentially use our fetchLogs helper (which does pagination)
|
26
|
+
fromBlock: worldDeploy.deployBlock,
|
27
|
+
toBlock: worldDeploy.stateBlock,
|
28
|
+
address: worldDeploy.address,
|
29
|
+
event: parseAbiItem(storeSetRecordEvent),
|
30
|
+
args: { tableId: storeTables.store_Tables.tableId },
|
31
|
+
});
|
32
|
+
|
33
|
+
// TODO: combine with store-sync logToTable and export from somewhere
|
34
|
+
const tables = logs.map((log) => {
|
35
|
+
const { tableId } = decodeKey(storeTables.store_Tables.keySchema, log.args.keyTuple);
|
36
|
+
const { namespace, name } = hexToResource(tableId);
|
37
|
+
const value = decodeValueArgs(storeTables.store_Tables.valueSchema, log.args);
|
38
|
+
|
39
|
+
// TODO: migrate to better helper
|
40
|
+
const keySchemaFields = hexToSchema(value.keySchema);
|
41
|
+
const valueSchemaFields = hexToSchema(value.valueSchema);
|
42
|
+
const keyNames = decodeAbiParameters(parseAbiParameters("string[]"), value.abiEncodedKeyNames)[0];
|
43
|
+
const fieldNames = decodeAbiParameters(parseAbiParameters("string[]"), value.abiEncodedFieldNames)[0];
|
44
|
+
|
45
|
+
const valueAbiTypes = [...valueSchemaFields.staticFields, ...valueSchemaFields.dynamicFields];
|
46
|
+
|
47
|
+
const keySchema = Object.fromEntries(
|
48
|
+
keySchemaFields.staticFields.map((abiType, i) => [keyNames[i], abiType])
|
49
|
+
) as KeySchema;
|
50
|
+
const valueSchema = Object.fromEntries(valueAbiTypes.map((abiType, i) => [fieldNames[i], abiType])) as ValueSchema;
|
51
|
+
|
52
|
+
return { namespace, name, tableId, keySchema, valueSchema } as const;
|
53
|
+
});
|
54
|
+
// TODO: filter/detect duplicates?
|
55
|
+
|
56
|
+
debug("found", tables.length, "tables for", worldDeploy.address);
|
57
|
+
|
58
|
+
return tables;
|
59
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { Client, Address, getAddress, parseAbi } from "viem";
|
2
|
+
import { getBlockNumber, getLogs } from "viem/actions";
|
3
|
+
import { WorldDeploy, worldDeployEvents } from "./common";
|
4
|
+
import { debug } from "./debug";
|
5
|
+
import { logsToWorldDeploy } from "./logsToWorldDeploy";
|
6
|
+
|
7
|
+
const deploys = new Map<Address, WorldDeploy>();
|
8
|
+
|
9
|
+
export async function getWorldDeploy(client: Client, worldAddress: Address): Promise<WorldDeploy> {
|
10
|
+
const address = getAddress(worldAddress);
|
11
|
+
|
12
|
+
let deploy = deploys.get(address);
|
13
|
+
if (deploy != null) {
|
14
|
+
return deploy;
|
15
|
+
}
|
16
|
+
|
17
|
+
debug("looking up world deploy for", address);
|
18
|
+
|
19
|
+
const stateBlock = await getBlockNumber(client);
|
20
|
+
const logs = await getLogs(client, {
|
21
|
+
strict: true,
|
22
|
+
address,
|
23
|
+
events: parseAbi(worldDeployEvents),
|
24
|
+
// this may fail for certain RPC providers with block range limits
|
25
|
+
// if so, could potentially use our fetchLogs helper (which does pagination)
|
26
|
+
fromBlock: "earliest",
|
27
|
+
toBlock: stateBlock,
|
28
|
+
});
|
29
|
+
|
30
|
+
deploy = {
|
31
|
+
...logsToWorldDeploy(logs),
|
32
|
+
stateBlock,
|
33
|
+
};
|
34
|
+
deploys.set(address, deploy);
|
35
|
+
|
36
|
+
debug("found world deploy for", address, "at block", deploy.deployBlock);
|
37
|
+
|
38
|
+
return deploy;
|
39
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import { AbiEventSignatureNotFoundError, Log, decodeEventLog, hexToString, parseAbi, trim } from "viem";
|
2
|
+
import { WorldDeploy, worldDeployEvents } from "./common";
|
3
|
+
import { isDefined } from "@latticexyz/common/utils";
|
4
|
+
|
5
|
+
export function logsToWorldDeploy(logs: readonly Log<bigint, number, false>[]): Omit<WorldDeploy, "stateBlock"> {
|
6
|
+
const deployLogs = logs
|
7
|
+
.map((log) => {
|
8
|
+
try {
|
9
|
+
return {
|
10
|
+
...log,
|
11
|
+
...decodeEventLog({
|
12
|
+
strict: true,
|
13
|
+
abi: parseAbi(worldDeployEvents),
|
14
|
+
topics: log.topics,
|
15
|
+
data: log.data,
|
16
|
+
}),
|
17
|
+
};
|
18
|
+
} catch (error: unknown) {
|
19
|
+
if (error instanceof AbiEventSignatureNotFoundError) {
|
20
|
+
return;
|
21
|
+
}
|
22
|
+
throw error;
|
23
|
+
}
|
24
|
+
})
|
25
|
+
.filter(isDefined);
|
26
|
+
|
27
|
+
// TODO: should this test for/validate that only one of each of these events is present? and that the address/block number don't change between each?
|
28
|
+
const { address, deployBlock, worldVersion, storeVersion } = deployLogs.reduce<Partial<WorldDeploy>>(
|
29
|
+
(deploy, log) => ({
|
30
|
+
...deploy,
|
31
|
+
address: log.address,
|
32
|
+
deployBlock: log.blockNumber,
|
33
|
+
...(log.eventName === "HelloWorld"
|
34
|
+
? { worldVersion: hexToString(trim(log.args.worldVersion, { dir: "right" })) }
|
35
|
+
: null),
|
36
|
+
...(log.eventName === "HelloStore"
|
37
|
+
? { storeVersion: hexToString(trim(log.args.storeVersion, { dir: "right" })) }
|
38
|
+
: null),
|
39
|
+
}),
|
40
|
+
{}
|
41
|
+
);
|
42
|
+
|
43
|
+
if (address == null) throw new Error("could not find world address");
|
44
|
+
if (deployBlock == null) throw new Error("could not find world deploy block number");
|
45
|
+
if (worldVersion == null) throw new Error("could not find world version");
|
46
|
+
if (storeVersion == null) throw new Error("could not find store version");
|
47
|
+
|
48
|
+
return { address, deployBlock, worldVersion, storeVersion };
|
49
|
+
}
|
@@ -0,0 +1,154 @@
|
|
1
|
+
import { resolveWorldConfig } from "@latticexyz/world";
|
2
|
+
import { Config, ConfigInput, WorldFunction, salt } from "./common";
|
3
|
+
import { resourceToHex, hexToResource } from "@latticexyz/common";
|
4
|
+
import { resolveWithContext } from "@latticexyz/config";
|
5
|
+
import { encodeField } from "@latticexyz/protocol-parser";
|
6
|
+
import { SchemaAbiType, SchemaAbiTypeToPrimitiveType } from "@latticexyz/schema-type";
|
7
|
+
import {
|
8
|
+
getFunctionSelector,
|
9
|
+
Hex,
|
10
|
+
getCreate2Address,
|
11
|
+
getAddress,
|
12
|
+
hexToBytes,
|
13
|
+
Abi,
|
14
|
+
bytesToHex,
|
15
|
+
getFunctionSignature,
|
16
|
+
} from "viem";
|
17
|
+
import { getExistingContracts } from "../utils/getExistingContracts";
|
18
|
+
import { defaultModuleContracts } from "../utils/modules/constants";
|
19
|
+
import { getContractData } from "../utils/utils/getContractData";
|
20
|
+
import { configToTables } from "./configToTables";
|
21
|
+
import { deployer } from "./ensureDeployer";
|
22
|
+
import { resourceLabel } from "./resourceLabel";
|
23
|
+
|
24
|
+
// TODO: this should be replaced by https://github.com/latticexyz/mud/issues/1668
|
25
|
+
|
26
|
+
export function resolveConfig<config extends ConfigInput>({
|
27
|
+
config,
|
28
|
+
forgeSourceDir,
|
29
|
+
forgeOutDir,
|
30
|
+
}: {
|
31
|
+
config: config;
|
32
|
+
forgeSourceDir: string;
|
33
|
+
forgeOutDir: string;
|
34
|
+
}): Config<config> {
|
35
|
+
const tables = configToTables(config);
|
36
|
+
|
37
|
+
// TODO: should the config parser/loader help with resolving systems?
|
38
|
+
const contractNames = getExistingContracts(forgeSourceDir).map(({ basename }) => basename);
|
39
|
+
const resolvedConfig = resolveWorldConfig(config, contractNames);
|
40
|
+
const baseSystemContractData = getContractData("System", forgeOutDir);
|
41
|
+
const baseSystemFunctions = baseSystemContractData.abi
|
42
|
+
.filter((item): item is typeof item & { type: "function" } => item.type === "function")
|
43
|
+
.map(getFunctionSignature);
|
44
|
+
|
45
|
+
const systems = Object.entries(resolvedConfig.systems).map(([systemName, system]) => {
|
46
|
+
const namespace = config.namespace;
|
47
|
+
const name = system.name;
|
48
|
+
const systemId = resourceToHex({ type: "system", namespace, name });
|
49
|
+
const contractData = getContractData(systemName, forgeOutDir);
|
50
|
+
|
51
|
+
const systemFunctions = contractData.abi
|
52
|
+
.filter((item): item is typeof item & { type: "function" } => item.type === "function")
|
53
|
+
.map(getFunctionSignature)
|
54
|
+
.filter((sig) => !baseSystemFunctions.includes(sig))
|
55
|
+
.map((sig): WorldFunction => {
|
56
|
+
// TODO: figure out how to not duplicate contract behavior (https://github.com/latticexyz/mud/issues/1708)
|
57
|
+
const worldSignature = namespace === "" ? sig : `${namespace}_${name}_${sig}`;
|
58
|
+
return {
|
59
|
+
signature: worldSignature,
|
60
|
+
selector: getFunctionSelector(worldSignature),
|
61
|
+
systemId,
|
62
|
+
systemFunctionSignature: sig,
|
63
|
+
systemFunctionSelector: getFunctionSelector(sig),
|
64
|
+
};
|
65
|
+
});
|
66
|
+
|
67
|
+
return {
|
68
|
+
namespace,
|
69
|
+
name,
|
70
|
+
systemId,
|
71
|
+
allowAll: system.openAccess,
|
72
|
+
allowedAddresses: system.accessListAddresses as Hex[],
|
73
|
+
allowedSystemIds: system.accessListSystems.map((name) =>
|
74
|
+
resourceToHex({ type: "system", namespace, name: resolvedConfig.systems[name].name })
|
75
|
+
),
|
76
|
+
address: getCreate2Address({ from: deployer, bytecode: contractData.bytecode, salt }),
|
77
|
+
bytecode: contractData.bytecode,
|
78
|
+
abi: contractData.abi,
|
79
|
+
functions: systemFunctions,
|
80
|
+
};
|
81
|
+
});
|
82
|
+
|
83
|
+
// resolve allowedSystemIds
|
84
|
+
// TODO: resolve this at deploy time so we can allow for arbitrary system IDs registered in the world as the source-of-truth rather than config
|
85
|
+
const systemsWithAccess = systems.map(({ allowedAddresses, allowedSystemIds, ...system }) => {
|
86
|
+
const allowedSystemAddresses = allowedSystemIds.map((systemId) => {
|
87
|
+
const targetSystem = systems.find((s) => s.systemId === systemId);
|
88
|
+
if (!targetSystem) {
|
89
|
+
throw new Error(
|
90
|
+
`System ${resourceLabel(system)} wanted access to ${resourceLabel(
|
91
|
+
hexToResource(systemId)
|
92
|
+
)}, but it wasn't found in the config.`
|
93
|
+
);
|
94
|
+
}
|
95
|
+
return targetSystem.address;
|
96
|
+
});
|
97
|
+
return {
|
98
|
+
...system,
|
99
|
+
allowedAddresses: Array.from(
|
100
|
+
new Set([...allowedAddresses, ...allowedSystemAddresses].map((addr) => getAddress(addr)))
|
101
|
+
),
|
102
|
+
};
|
103
|
+
});
|
104
|
+
|
105
|
+
// ugh (https://github.com/latticexyz/mud/issues/1668)
|
106
|
+
const resolveContext = {
|
107
|
+
tableIds: Object.fromEntries(
|
108
|
+
Object.entries(config.tables).map(([tableName, table]) => [
|
109
|
+
tableName,
|
110
|
+
hexToBytes(
|
111
|
+
resourceToHex({
|
112
|
+
type: table.offchainOnly ? "offchainTable" : "table",
|
113
|
+
namespace: config.namespace,
|
114
|
+
name: table.name,
|
115
|
+
})
|
116
|
+
),
|
117
|
+
])
|
118
|
+
),
|
119
|
+
};
|
120
|
+
|
121
|
+
const defaultModules = defaultModuleContracts.map((mod) => ({
|
122
|
+
name: mod.name,
|
123
|
+
bytecode: (typeof mod.bytecode === "string" ? mod.bytecode : mod.bytecode.object) as Hex,
|
124
|
+
abi: mod.abi as Abi,
|
125
|
+
}));
|
126
|
+
|
127
|
+
const modules = config.modules.map((mod) => {
|
128
|
+
const contractData =
|
129
|
+
defaultModules.find((defaultMod) => defaultMod.name === mod.name) ?? getContractData(mod.name, forgeOutDir);
|
130
|
+
const installArgs = mod.args
|
131
|
+
.map((arg) => resolveWithContext(arg, resolveContext))
|
132
|
+
.map((arg) => {
|
133
|
+
const value = arg.value instanceof Uint8Array ? bytesToHex(arg.value) : arg.value;
|
134
|
+
return encodeField(arg.type as SchemaAbiType, value as SchemaAbiTypeToPrimitiveType<SchemaAbiType>);
|
135
|
+
});
|
136
|
+
if (installArgs.length > 1) {
|
137
|
+
throw new Error(`${mod.name} module should only have 0-1 args, but had ${installArgs.length} args.`);
|
138
|
+
}
|
139
|
+
return {
|
140
|
+
name: mod.name,
|
141
|
+
installAsRoot: mod.root,
|
142
|
+
installData: installArgs.length === 0 ? "0x" : installArgs[0],
|
143
|
+
address: getCreate2Address({ from: deployer, bytecode: contractData.bytecode, salt }),
|
144
|
+
bytecode: contractData.bytecode,
|
145
|
+
abi: contractData.abi,
|
146
|
+
};
|
147
|
+
});
|
148
|
+
|
149
|
+
return {
|
150
|
+
tables,
|
151
|
+
systems: systemsWithAccess,
|
152
|
+
modules,
|
153
|
+
};
|
154
|
+
}
|
package/src/index.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
// nothing to export
|
package/src/mud.ts
CHANGED
@@ -1,39 +1,45 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
2
|
|
3
|
-
import yargs from "yargs";
|
4
|
-
import { hideBin } from "yargs/helpers";
|
5
|
-
import { commands } from "./commands";
|
6
|
-
import { logError } from "./utils/errors";
|
7
|
-
|
8
3
|
// Load .env file into process.env
|
9
4
|
import * as dotenv from "dotenv";
|
10
|
-
import chalk from "chalk";
|
11
5
|
dotenv.config();
|
12
6
|
|
13
|
-
|
14
|
-
//
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
//
|
31
|
-
|
32
|
-
|
7
|
+
async function run() {
|
8
|
+
// Import everything else async so they can pick up env vars in .env
|
9
|
+
const { default: yargs } = await import("yargs");
|
10
|
+
const { default: chalk } = await import("chalk");
|
11
|
+
const { hideBin } = await import("yargs/helpers");
|
12
|
+
const { logError } = await import("./utils/errors");
|
13
|
+
const { commands } = await import("./commands");
|
14
|
+
|
15
|
+
yargs(hideBin(process.argv))
|
16
|
+
// Explicit name to display in help (by default it's the entry file, which may not be "mud" for e.g. ts-node)
|
17
|
+
.scriptName("mud")
|
18
|
+
// Use the commands directory to scaffold
|
19
|
+
// command array overload isn't typed, see https://github.com/yargs/yargs/blob/main/docs/advanced.md#esm-hierarchy
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
21
|
+
.command(commands as any)
|
22
|
+
// Enable strict mode.
|
23
|
+
.strict()
|
24
|
+
// Custom error handler
|
25
|
+
.fail((msg, err) => {
|
26
|
+
console.error(chalk.red(msg));
|
27
|
+
if (msg.includes("Missing required argument")) {
|
28
|
+
console.log(
|
29
|
+
chalk.yellow(`Run 'pnpm mud ${process.argv[2]} --help' for a list of available and required arguments.`)
|
30
|
+
);
|
31
|
+
}
|
33
32
|
console.log("");
|
34
|
-
|
33
|
+
// Even though `.fail` type says we should get an `Error`, this can sometimes be undefined
|
34
|
+
if (err != null) {
|
35
|
+
logError(err);
|
36
|
+
console.log("");
|
37
|
+
}
|
38
|
+
|
39
|
+
process.exit(1);
|
40
|
+
})
|
41
|
+
// Useful aliases.
|
42
|
+
.alias({ h: "help" }).argv;
|
43
|
+
}
|
35
44
|
|
36
|
-
|
37
|
-
})
|
38
|
-
// Useful aliases.
|
39
|
-
.alias({ h: "help" }).argv;
|
45
|
+
run();
|
package/src/runDeploy.ts
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
import path from "node:path";
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
3
|
+
import { InferredOptionTypes, Options } from "yargs";
|
4
|
+
import { deploy } from "./deploy/deploy";
|
5
|
+
import { createWalletClient, http, Hex } from "viem";
|
6
|
+
import { privateKeyToAccount } from "viem/accounts";
|
7
|
+
import { loadConfig } from "@latticexyz/config/node";
|
8
|
+
import { StoreConfig } from "@latticexyz/store";
|
9
|
+
import { WorldConfig } from "@latticexyz/world";
|
10
|
+
import { forge, getOutDirectory, getRemappings, getRpcUrl, getSrcDirectory } from "@latticexyz/common/foundry";
|
11
|
+
import chalk from "chalk";
|
12
|
+
import { execa } from "execa";
|
13
|
+
import { MUDError } from "@latticexyz/common/errors";
|
14
|
+
import { resolveConfig } from "./deploy/resolveConfig";
|
15
|
+
import { getChainId } from "viem/actions";
|
16
|
+
import { postDeploy } from "./utils/utils/postDeploy";
|
17
|
+
import { WorldDeploy } from "./deploy/common";
|
18
|
+
import { tablegen } from "@latticexyz/store/codegen";
|
19
|
+
import { worldgen } from "@latticexyz/world/node";
|
20
|
+
import { getExistingContracts } from "./utils/getExistingContracts";
|
21
|
+
|
22
|
+
export const deployOptions = {
|
23
|
+
configPath: { type: "string", desc: "Path to the config file" },
|
24
|
+
printConfig: { type: "boolean", desc: "Print the resolved config" },
|
25
|
+
profile: { type: "string", desc: "The foundry profile to use" },
|
26
|
+
saveDeployment: { type: "boolean", desc: "Save the deployment info to a file", default: true },
|
27
|
+
rpc: { type: "string", desc: "The RPC URL to use. Defaults to the RPC url from the local foundry.toml" },
|
28
|
+
worldAddress: { type: "string", desc: "Deploy to an existing World at the given address" },
|
29
|
+
srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." },
|
30
|
+
skipBuild: { type: "boolean", desc: "Skip rebuilding the contracts before deploying" },
|
31
|
+
alwaysRunPostDeploy: {
|
32
|
+
type: "boolean",
|
33
|
+
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.",
|
34
|
+
},
|
35
|
+
} as const satisfies Record<string, Options>;
|
36
|
+
|
37
|
+
export type DeployOptions = InferredOptionTypes<typeof deployOptions>;
|
38
|
+
|
39
|
+
/**
|
40
|
+
* Given some CLI arguments, finds and resolves a MUD config, foundry profile, and runs a deploy.
|
41
|
+
* This is used by the deploy, test, and dev-contracts CLI commands.
|
42
|
+
*/
|
43
|
+
export async function runDeploy(opts: DeployOptions): Promise<WorldDeploy> {
|
44
|
+
const profile = opts.profile ?? process.env.FOUNDRY_PROFILE;
|
45
|
+
|
46
|
+
const config = (await loadConfig(opts.configPath)) as StoreConfig & WorldConfig;
|
47
|
+
if (opts.printConfig) {
|
48
|
+
console.log(chalk.green("\nResolved config:\n"), JSON.stringify(config, null, 2));
|
49
|
+
}
|
50
|
+
|
51
|
+
const srcDir = opts.srcDir ?? (await getSrcDirectory(profile));
|
52
|
+
const outDir = await getOutDirectory(profile);
|
53
|
+
const remappings = await getRemappings();
|
54
|
+
|
55
|
+
const rpc = opts.rpc ?? (await getRpcUrl(profile));
|
56
|
+
console.log(
|
57
|
+
chalk.bgBlue(
|
58
|
+
chalk.whiteBright(`\n Deploying MUD contracts${profile ? " with profile " + profile : ""} to RPC ${rpc} \n`)
|
59
|
+
)
|
60
|
+
);
|
61
|
+
|
62
|
+
// Run build
|
63
|
+
if (!opts.skipBuild) {
|
64
|
+
const outPath = path.join(srcDir, config.codegenDirectory);
|
65
|
+
await Promise.all([tablegen(config, outPath, remappings), worldgen(config, getExistingContracts(srcDir), outPath)]);
|
66
|
+
await forge(["build"], { profile });
|
67
|
+
await execa("mud", ["abi-ts"], { stdio: "inherit" });
|
68
|
+
}
|
69
|
+
|
70
|
+
const privateKey = process.env.PRIVATE_KEY as Hex;
|
71
|
+
if (!privateKey) {
|
72
|
+
throw new MUDError(
|
73
|
+
`Missing PRIVATE_KEY environment variable.
|
74
|
+
Run 'echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" > .env'
|
75
|
+
in your contracts directory to use the default anvil private key.`
|
76
|
+
);
|
77
|
+
}
|
78
|
+
|
79
|
+
const resolvedConfig = resolveConfig({ config, forgeSourceDir: srcDir, forgeOutDir: outDir });
|
80
|
+
|
81
|
+
const client = createWalletClient({
|
82
|
+
transport: http(rpc),
|
83
|
+
account: privateKeyToAccount(privateKey),
|
84
|
+
});
|
85
|
+
console.log("Deploying from", client.account.address);
|
86
|
+
|
87
|
+
const startTime = Date.now();
|
88
|
+
const worldDeploy = await deploy({
|
89
|
+
worldAddress: opts.worldAddress as Hex | undefined,
|
90
|
+
client,
|
91
|
+
config: resolvedConfig,
|
92
|
+
});
|
93
|
+
if (opts.worldAddress == null || opts.alwaysRunPostDeploy) {
|
94
|
+
await postDeploy(config.postDeployScript, worldDeploy.address, rpc, profile);
|
95
|
+
}
|
96
|
+
console.log(chalk.green("Deployment completed in", (Date.now() - startTime) / 1000, "seconds"));
|
97
|
+
|
98
|
+
const deploymentInfo = {
|
99
|
+
worldAddress: worldDeploy.address,
|
100
|
+
blockNumber: Number(worldDeploy.deployBlock),
|
101
|
+
};
|
102
|
+
|
103
|
+
if (opts.saveDeployment) {
|
104
|
+
const chainId = await getChainId(client);
|
105
|
+
const deploysDir = path.join(config.deploysDirectory, chainId.toString());
|
106
|
+
mkdirSync(deploysDir, { recursive: true });
|
107
|
+
writeFileSync(path.join(deploysDir, "latest.json"), JSON.stringify(deploymentInfo, null, 2));
|
108
|
+
writeFileSync(path.join(deploysDir, Date.now() + ".json"), JSON.stringify(deploymentInfo, null, 2));
|
109
|
+
|
110
|
+
const localChains = [1337, 31337];
|
111
|
+
const deploys = existsSync(config.worldsFile) ? JSON.parse(readFileSync(config.worldsFile, "utf-8")) : {};
|
112
|
+
deploys[chainId] = {
|
113
|
+
address: deploymentInfo.worldAddress,
|
114
|
+
// We expect the worlds file to be committed and since local deployments are often
|
115
|
+
// a consistent address but different block number, we'll ignore the block number.
|
116
|
+
blockNumber: localChains.includes(chainId) ? undefined : deploymentInfo.blockNumber,
|
117
|
+
};
|
118
|
+
writeFileSync(config.worldsFile, JSON.stringify(deploys, null, 2));
|
119
|
+
|
120
|
+
console.log(
|
121
|
+
chalk.bgGreen(chalk.whiteBright(`\n Deployment result (written to ${config.worldsFile} and ${deploysDir}): \n`))
|
122
|
+
);
|
123
|
+
}
|
124
|
+
|
125
|
+
console.log(deploymentInfo);
|
126
|
+
|
127
|
+
return worldDeploy;
|
128
|
+
}
|
@@ -1,10 +1,9 @@
|
|
1
1
|
import KeysWithValueModuleData from "@latticexyz/world-modules/out/KeysWithValueModule.sol/KeysWithValueModule.json" assert { type: "json" };
|
2
2
|
import KeysInTableModuleData from "@latticexyz/world-modules/out/KeysInTableModule.sol/KeysInTableModule.json" assert { type: "json" };
|
3
3
|
import UniqueEntityModuleData from "@latticexyz/world-modules/out/UniqueEntityModule.sol/UniqueEntityModule.json" assert { type: "json" };
|
4
|
-
import { ContractCode } from "../utils/types";
|
5
4
|
|
6
5
|
// These modules are always deployed
|
7
|
-
export const defaultModuleContracts
|
6
|
+
export const defaultModuleContracts = [
|
8
7
|
{
|
9
8
|
name: "KeysWithValueModule",
|
10
9
|
abi: KeysWithValueModuleData.abi,
|
@@ -1,16 +1,13 @@
|
|
1
1
|
import { readFileSync } from "fs";
|
2
2
|
import path from "path";
|
3
|
-
import { Fragment } from "ethers/lib/utils.js";
|
4
3
|
import { MUDError } from "@latticexyz/common/errors";
|
4
|
+
import { Abi, Hex } from "viem";
|
5
5
|
|
6
6
|
/**
|
7
7
|
* Load the contract's abi and bytecode from the file system
|
8
8
|
* @param contractName: Name of the contract to load
|
9
9
|
*/
|
10
|
-
export function getContractData(
|
11
|
-
contractName: string,
|
12
|
-
forgeOutDirectory: string
|
13
|
-
): { bytecode: string; abi: Fragment[] } {
|
10
|
+
export function getContractData(contractName: string, forgeOutDirectory: string): { bytecode: Hex; abi: Abi } {
|
14
11
|
let data: any;
|
15
12
|
const contractDataPath = path.join(forgeOutDirectory, contractName + ".sol", contractName + ".json");
|
16
13
|
try {
|
package/dist/chunk-TW3YGZ4D.js
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
import S from"chalk";import $ from"path";import{MUDError as it}from"@latticexyz/common/errors";import{loadConfig as ct}from"@latticexyz/config/node";import u from"chalk";import ze from"path";import{ethers as A}from"ethers";import{getOutDirectory as Qe,cast as Xe,getSrcDirectory as Ze,getRemappings as et}from"@latticexyz/common/foundry";import{resolveWorldConfig as tt}from"@latticexyz/world";import Fe from"chalk";import Ie from"@latticexyz/world/out/World.sol/World.json"assert{type:"json"};import Me from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import G from"chalk";import{ethers as Pe}from"ethers";import{MUDError as U}from"@latticexyz/common/errors";async function I(e){let{signer:t,nonce:r,maxPriorityFeePerGas:o,maxFeePerGas:n,debug:a,gasPrice:l,confirmations:p,contract:m}=e;try{let i=new Pe.ContractFactory(m.abi,m.bytecode,t);console.log(G.gray(`executing deployment of ${m.name} with nonce ${r}`));let g=i.deploy({nonce:r,maxPriorityFeePerGas:o,maxFeePerGas:n,gasPrice:l}).then(s=>p?s:s.deployed()),{address:f}=await g;return console.log(G.green("Deployed",m.name,"to",f)),f}catch(i){throw a&&console.error(i),i?.message.includes("invalid bytecode")?new U(`Error deploying ${m.name}: invalid bytecode. Note that linking of public libraries is not supported yet, make sure none of your libraries use "external" functions.`):i?.message.includes("CreateContractLimit")?new U(`Error deploying ${m.name}: CreateContractLimit exceeded.`):i}}import{readFileSync as Se}from"fs";import Te from"path";import{MUDError as N}from"@latticexyz/common/errors";function w(e,t){let r,o=Te.join(t,e+".sol",e+".json");try{r=JSON.parse(Se(o,"utf8"))}catch{throw new N(`Error reading file at ${o}`)}let n=r?.bytecode?.object;if(!n)throw new N(`No bytecode found in ${o}`);let a=r?.abi;if(!a)throw new N(`No ABI found in ${o}`);return{abi:a,bytecode:n}}async function K(e){console.log(Fe.blue("Deploying World"));let t=e.worldContractName?{name:"World",...w(e.worldContractName,e.forgeOutDirectory)}:{abi:Me,bytecode:Ie.bytecode,name:"World"};return I({...e,nonce:e.nonce,contract:t})}import ot from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import ce from"@latticexyz/world/out/CoreModule.sol/CoreModule.json"assert{type:"json"};import L from"@latticexyz/world-modules/out/KeysWithValueModule.sol/KeysWithValueModule.json"assert{type:"json"};import H from"@latticexyz/world-modules/out/KeysInTableModule.sol/KeysInTableModule.json"assert{type:"json"};import J from"@latticexyz/world-modules/out/UniqueEntityModule.sol/UniqueEntityModule.json"assert{type:"json"};var R=[{name:"KeysWithValueModule",abi:L.abi,bytecode:L.bytecode},{name:"KeysInTableModule",abi:H.abi,bytecode:H.bytecode},{name:"UniqueEntityModule",abi:J.abi,bytecode:J.bytecode}];import{defaultAbiCoder as ve}from"ethers/lib/utils.js";import{resolveWithContext as Ne}from"@latticexyz/config";async function _(e,t,r){let o=await e[t.name];if(!o)throw new Error(`Module ${t.name} not found`);let n=t.args.map(p=>Ne(p,{tableIds:r})),a=n.map(p=>p.value),l=n.map(p=>p.type);return{func:t.root?"installRootModule":"installModule",args:[o,ve.encode(l,a)]}}function q(e,t){return t.filter(r=>!e.some(o=>o.name===r.name))}import{resourceIdToHex as Re}from"@latticexyz/common";async function Y(e){let{systems:t,namespace:r,systemContracts:o}=e,n=[];for(let{name:a,accessListAddresses:l,accessListSystems:p}of t)l.map(async m=>n.push(V(a,r,m))),p.map(async m=>n.push(V(a,r,await o[m])));return n}function V(e,t,r){return{func:"grantAccess",args:[Re({type:"system",namespace:t,name:e}),r]}}import{resourceIdToHex as X}from"@latticexyz/common";import{ethers as k}from"ethers";function O(e,t){let{abi:r}=w(e,t);return r.filter(o=>["fallback","function"].includes(o.type)).map(o=>`${o.name}${Q(o.inputs)}`)}function z(e){return ke(e)}function Q(e){return`(${e.map(r=>{let o=r.type.match(/tuple(.*)/);return o?Q(r.components)+o[1]:r.type})})`}function ke(e){return k.utils.hexDataSlice(k.utils.keccak256(k.utils.toUtf8Bytes(e)),0,4)}function Z(e){let t=[],{systemContractName:r,namespace:o,forgeOutDirectory:n,system:a}=e;if(a.registerFunctionSelectors){let l=O("System",n),p=O(r,n).filter(i=>r==="System"||!l.includes(i)),m=o==="";for(let i of p)t.push(Oe({namespace:o,name:a.name,systemFunctionSignature:i,isRoot:m}))}return t}function Oe(e){let{namespace:t,name:r,systemFunctionSignature:o,isRoot:n}=e;if(n){let a=z(o);return{func:"registerRootFunctionSelector",args:[X({type:"system",namespace:t,name:r}),o,a]}}else return{func:"registerFunctionSelector",args:[X({type:"system",namespace:t,name:r}),o]}}import{resourceIdToHex as je}from"@latticexyz/common";async function ee(e){let{namespace:t,systemContracts:r,systemKey:o,system:n}=e,a=await r[o];return{func:"registerSystem",args:[je({type:"system",namespace:t,name:n.name}),a,n.openAccess]}}import{encodeSchema as te,getStaticByteLength as Ae}from"@latticexyz/schema-type/deprecated";import{resolveAbiOrUserType as oe}from"@latticexyz/store/codegen";import{resourceIdToHex as $e}from"@latticexyz/common";import{fieldLayoutToHex as We}from"@latticexyz/protocol-parser";import{loadAndExtractUserTypes as Ee}from"@latticexyz/common/codegen";function re(e,t,r,o){let{name:n,valueSchema:a,keySchema:l}=e;if(!n)throw Error("Table missing name");let p=Ee(t.userTypes,r,o),m=Object.values(a).map(s=>{let{schemaType:d}=oe(s,t,p);return d}),i=m.map(s=>Ae(s)),g={staticFieldLengths:i.filter(s=>s>0),numDynamicFields:i.filter(s=>s===0).length},f=Object.values(l).map(s=>{let{schemaType:d}=oe(s,t,p);return d});return{func:"registerTable",args:[$e({type:e.offchainOnly?"offchainTable":"table",namespace:t.namespace,name:n}),We(g),te(f),te(m),Object.keys(l),Object.keys(a)]}}import{resourceIdToHex as Be}from"@latticexyz/common";import{hexToBytes as Ge}from"viem";function ne(e){let t={};for(let[r,{name:o,offchainOnly:n}]of Object.entries(e.tables))t[r]=Ge(Be({type:n?"offchainTable":"table",namespace:e.namespace,name:o}));return t}import Ue from"chalk";import{MUDError as Ke}from"@latticexyz/common/errors";async function ae(e,t,r){let o=await e.getTransactionCount(),n=0,a=100;for(;o!==t&&n<a;)console.log(Ue.gray(`Waiting for transactions to be included before executing postDeployScript (local nonce: ${t}, remote nonce: ${o}, retry number ${n}/${a})`)),await new Promise(l=>setTimeout(l,r)),n++,o=await e.getTransactionCount();if(o!==t)throw new Ke("Remote nonce doesn't match local nonce, indicating that not all deploy transactions were included.")}import Le from"chalk";import{MUDError as He}from"@latticexyz/common/errors";async function h(e){let{func:t,args:r,contract:o,signer:n,nonce:a,maxPriorityFeePerGas:l,maxFeePerGas:p,gasPrice:m,confirmations:i=1,debug:g}=e,f=`${t}(${r.map(s=>`'${s}'`).join(",")})`;try{let s=o.connect(n),d=await s.estimateGas[t].apply(null,r);return console.log(Le.gray(`executing transaction: ${f} with nonce ${a}`)),s[t].apply(null,[...r,{gasLimit:d,nonce:a,maxPriorityFeePerGas:l,maxFeePerGas:p,gasPrice:m}]).then(D=>i===0?D:D.wait(i))}catch(s){throw g&&console.error(s),new He(`Gas estimation error for ${f}: ${s?.reason}`)}}import{existsSync as Je}from"fs";import _e from"path";import qe from"chalk";import{getScriptDirectory as Ve,forge as Ye}from"@latticexyz/common/foundry";async function se(e,t,r,o){let n=_e.join(await Ve(),e+".s.sol");Je(n)?(console.log(qe.blue(`Executing post deploy script at ${n}`)),await Ye(["script",e,"--sig","run(address)",t,"--broadcast","--rpc-url",r,"-vvv"],{profile:o})):console.log(`No script at ${n}, skipping post deploy hook`)}import{MUDError as j}from"@latticexyz/common/errors";async function ie(e,t){let r=await e.provider.getFeeData(),o,n,a;if(r.lastBaseFeePerGas){if(!r.lastBaseFeePerGas.eq(0)&&(await e.getBalance()).eq(0))throw new j(`Attempting to deploy to a chain with non-zero base fee with an account that has no balance.
|
2
|
-
If you're deploying to the Lattice testnet, you can fund your account by running 'pnpm mud faucet --address ${await e.getAddress()}'`);o=r.lastBaseFeePerGas.eq(0)?0:Math.floor(15e8*t),n=r.lastBaseFeePerGas.mul(2).add(o)}else if(r.gasPrice){if(!r.gasPrice.eq(0)&&(await e.getBalance()).eq(0))throw new j("Attempting to deploy to a chain with non-zero gas price with an account that has no balance.");a=r.gasPrice}else throw new j("Can not fetch fee data from RPC");return{maxPriorityFeePerGas:o,maxFeePerGas:n,gasPrice:a}}import{resourceIdToHex as rt}from"@latticexyz/common";async function le(e,t,r){let o=Date.now(),{profile:n,rpc:a,privateKey:l,priorityFeeMultiplier:p,debug:m,worldAddress:i,disableTxWait:g,pollInterval:f}=r,s=tt(e,t),d=await Qe(n),D=await et(n),T=ze.join(await Ze(n),e.codegenDirectory),E=new A.providers.StaticJsonRpcProvider(a);E.pollingInterval=f;let P=new A.Wallet(l,E);console.log("Deploying from",P.address);let y=await P.getTransactionCount();console.log("Initial nonce",y);let C={...await ie(P,p),signer:P,debug:!!m,disableTxWait:g,confirmations:g?0:1},B=Number(await Xe(["block-number","--rpc-url",a],{profile:n}));console.log("Start deployment at block",B);let de=i?Promise.resolve(i):K({...C,nonce:y++,worldContractName:e.worldContractName,forgeOutDirectory:d}),ue=q(R,e.modules),ge=Object.keys(ue).map(c=>{let{abi:b,bytecode:v}=w(c,d);return{name:c,abi:b,bytecode:v}}),ye=Object.keys(s.systems).map(c=>{let{abi:b,bytecode:v}=w(c,d);return{name:c,abi:b,bytecode:v}}),F=[{name:"CoreModule",abi:ce.abi,bytecode:ce.bytecode},...R,...ge,...ye].reduce((c,b)=>(c[b.name]=I({...C,nonce:y++,contract:b}),c),{}),M=await de,x=new A.Contract(M,ot);i||(console.log(u.blue("Installing CoreModule")),await h({...C,nonce:y++,contract:x,func:"initialize",args:[await F.CoreModule]}),console.log(u.green("Installed CoreModule"))),e.namespace&&(console.log(u.blue("Registering Namespace")),await h({...C,nonce:y++,contract:x,func:"registerNamespace",args:[rt({type:"namespace",namespace:e.namespace,name:""})]}),console.log(u.green("Namespace registered")));let be=ne(e),Ce=Object.values(e.tables).map(c=>re(c,e,T,D));console.log(u.blue("Registering tables")),await Promise.all(Ce.map(c=>h({...C,nonce:y++,contract:x,...c}))),console.log(u.green("Tables registered")),console.log(u.blue("Registering Systems and Functions"));let we=await Promise.all(Object.entries(s.systems).map(([c,b])=>ee({systemContracts:F,systemKey:c,system:b,namespace:e.namespace}))),he=Object.entries(s.systems).flatMap(([c,b])=>Z({systemContractName:c,system:b,namespace:e.namespace,forgeOutDirectory:d}));await Promise.all([...we,...he].map(c=>h({...C,nonce:y++,contract:x,...c}))),console.log(u.green("Systems and Functions registered"));let De=await Y({systems:Object.values(s.systems),systemContracts:F,namespace:e.namespace});console.log(u.blue("Granting Access")),await Promise.all(De.map(c=>h({...C,nonce:y++,contract:x,...c}))),console.log(u.green("Access granted"));let xe=await Promise.all(e.modules.map(c=>_(F,c,be)));return console.log(u.blue("Installing User Modules")),await Promise.all(xe.map(c=>h({...C,nonce:y++,contract:x,...c}))),console.log(u.green("User Modules Installed")),await ae(P,y,f),await se(e.postDeployScript,M,a,n),console.log(u.green("Deployment completed in",(Date.now()-o)/1e3,"seconds")),{worldAddress:M,blockNumber:B}}import{forge as fe,getRpcUrl as lt,getSrcDirectory as mt}from"@latticexyz/common/foundry";import{existsSync as pt,mkdirSync as ft,readFileSync as dt,writeFileSync as W}from"fs";import nt from"glob";import{basename as at}from"path";function me(e){return nt.sync(`${e}/**/*.sol`).map(t=>({path:t,basename:at(t,".sol")}))}import{execa as ut}from"execa";import{ethers as st}from"ethers";async function pe(e){let{result:t}=await st.utils.fetchJson(e,'{ "id": 42, "jsonrpc": "2.0", "method": "eth_chainId", "params": [ ] }');return Number(t)}async function nr(e){e.profile??=process.env.FOUNDRY_PROFILE;let{configPath:t,printConfig:r,profile:o,clean:n,skipBuild:a}=e,l=e.rpc??await lt(o);console.log(S.bgBlue(S.whiteBright(`
|
3
|
-
Deploying MUD contracts${o?" with profile "+o:""} to RPC ${l}
|
4
|
-
`))),n&&await fe(["clean"],{profile:o}),a||(await fe(["build","--skip","test","script"],{profile:o}),await ut("mud",["abi-ts"],{stdio:"inherit"}));let p=e?.srcDir??await mt(),m=me(p).map(({basename:s})=>s),i=await ct(t);r&&console.log(S.green(`
|
5
|
-
Resolved config:
|
6
|
-
`),JSON.stringify(i,null,2));let g=process.env.PRIVATE_KEY;if(!g)throw new it(`Missing PRIVATE_KEY environment variable.
|
7
|
-
Run 'echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" > .env'
|
8
|
-
in your contracts directory to use the default anvil private key.`);let f=await le(i,m,{...e,rpc:l,privateKey:g});if(e.saveDeployment){let s=await pe(l),d=$.join(i.deploysDirectory,s.toString());ft(d,{recursive:!0}),W($.join(d,"latest.json"),JSON.stringify(f,null,2)),W($.join(d,Date.now()+".json"),JSON.stringify(f,null,2));let D=[1337,31337],T=pt(i.worldsFile)?JSON.parse(dt(i.worldsFile,"utf-8")):{};T[s]={address:f.worldAddress,blockNumber:D.includes(s)?void 0:f.blockNumber},W(i.worldsFile,JSON.stringify(T,null,2)),console.log(S.bgGreen(S.whiteBright(`
|
9
|
-
Deployment result (written to ${i.worldsFile} and ${d}):
|
10
|
-
`)))}return console.log(f),f}export{me as a,pe as b,nr as c};
|
11
|
-
//# sourceMappingURL=chunk-TW3YGZ4D.js.map
|