@latticexyz/cli 2.0.12-main-9be2bb86 → 2.0.12-main-96e7bf43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{commands-F37Q2ISZ.js → commands-265RZEHD.js} +17 -17
- package/dist/commands-265RZEHD.js.map +1 -0
- package/dist/mud.js +1 -1
- package/package.json +13 -11
- package/dist/commands-F37Q2ISZ.js.map +0 -1
- package/src/build.ts +0 -32
- package/src/commands/build.ts +0 -35
- package/src/commands/deploy.ts +0 -26
- package/src/commands/dev-contracts.ts +0 -118
- package/src/commands/devnode.ts +0 -42
- package/src/commands/hello.ts +0 -28
- package/src/commands/index.ts +0 -33
- package/src/commands/set-version.ts +0 -197
- package/src/commands/tablegen.ts +0 -34
- package/src/commands/test.ts +0 -65
- package/src/commands/trace.ts +0 -120
- package/src/commands/verify.ts +0 -100
- package/src/commands/worldgen.ts +0 -58
- package/src/common.ts +0 -1
- package/src/debug.ts +0 -10
- package/src/deploy/common.ts +0 -120
- package/src/deploy/configToModules.ts +0 -75
- package/src/deploy/configToTables.ts +0 -70
- package/src/deploy/create2/README.md +0 -13
- package/src/deploy/create2/deployment.json +0 -8
- package/src/deploy/createPrepareDeploy.ts +0 -28
- package/src/deploy/debug.ts +0 -10
- package/src/deploy/deploy.ts +0 -137
- package/src/deploy/deployWorld.ts +0 -38
- package/src/deploy/ensureContract.ts +0 -66
- package/src/deploy/ensureContractsDeployed.ts +0 -33
- package/src/deploy/ensureDeployer.ts +0 -69
- package/src/deploy/ensureFunctions.ts +0 -86
- package/src/deploy/ensureModules.ts +0 -81
- package/src/deploy/ensureNamespaceOwner.ts +0 -71
- package/src/deploy/ensureSystems.ts +0 -187
- package/src/deploy/ensureTables.ts +0 -64
- package/src/deploy/ensureWorldFactory.ts +0 -30
- package/src/deploy/findLibraries.ts +0 -36
- package/src/deploy/getDeployer.ts +0 -20
- package/src/deploy/getFunctions.ts +0 -64
- package/src/deploy/getResourceAccess.ts +0 -51
- package/src/deploy/getResourceIds.ts +0 -45
- package/src/deploy/getSystems.ts +0 -47
- package/src/deploy/getTableValue.ts +0 -31
- package/src/deploy/getTables.ts +0 -59
- package/src/deploy/getWorldContracts.ts +0 -79
- package/src/deploy/getWorldDeploy.ts +0 -39
- package/src/deploy/getWorldFactoryContracts.ts +0 -27
- package/src/deploy/getWorldProxyFactoryContracts.ts +0 -27
- package/src/deploy/logsToWorldDeploy.ts +0 -49
- package/src/deploy/orderByDependencies.ts +0 -12
- package/src/deploy/resolveConfig.ts +0 -104
- package/src/index.ts +0 -1
- package/src/modules.d.ts +0 -11
- package/src/mud.ts +0 -45
- package/src/mudPackages.ts +0 -24
- package/src/runDeploy.ts +0 -181
- package/src/utils/errors.ts +0 -29
- package/src/utils/findPlaceholders.ts +0 -27
- package/src/utils/getContractArtifact.ts +0 -80
- package/src/utils/getContractData.ts +0 -38
- package/src/utils/getExistingContracts.ts +0 -12
- package/src/utils/knownModuleArtifacts.ts +0 -8
- package/src/utils/postDeploy.ts +0 -42
- package/src/utils/printMUD.ts +0 -14
- package/src/verify/verifyContract.ts +0 -23
- package/src/verify.ts +0 -174
@@ -1,66 +0,0 @@
|
|
1
|
-
import { Client, Transport, Chain, Account, concatHex, getCreate2Address, Hex } from "viem";
|
2
|
-
import { getBytecode } from "viem/actions";
|
3
|
-
import { contractSizeLimit, salt } from "./common";
|
4
|
-
import { sendTransaction } from "@latticexyz/common";
|
5
|
-
import { debug } from "./debug";
|
6
|
-
import pRetry from "p-retry";
|
7
|
-
import { wait } from "@latticexyz/common/utils";
|
8
|
-
|
9
|
-
export type Contract = {
|
10
|
-
bytecode: Hex;
|
11
|
-
deployedBytecodeSize: number;
|
12
|
-
label?: string;
|
13
|
-
};
|
14
|
-
|
15
|
-
export async function ensureContract({
|
16
|
-
client,
|
17
|
-
deployerAddress,
|
18
|
-
bytecode,
|
19
|
-
deployedBytecodeSize,
|
20
|
-
label = "contract",
|
21
|
-
}: {
|
22
|
-
readonly client: Client<Transport, Chain | undefined, Account>;
|
23
|
-
readonly deployerAddress: Hex;
|
24
|
-
} & Contract): Promise<readonly Hex[]> {
|
25
|
-
if (bytecode.includes("__$")) {
|
26
|
-
throw new Error(`Found unlinked public library in ${label} bytecode`);
|
27
|
-
}
|
28
|
-
|
29
|
-
const address = getCreate2Address({ from: deployerAddress, salt, bytecode });
|
30
|
-
|
31
|
-
const contractCode = await getBytecode(client, { address, blockTag: "pending" });
|
32
|
-
if (contractCode) {
|
33
|
-
debug("found", label, "at", address);
|
34
|
-
return [];
|
35
|
-
}
|
36
|
-
|
37
|
-
if (deployedBytecodeSize > contractSizeLimit) {
|
38
|
-
console.warn(
|
39
|
-
`\nBytecode for ${label} (${deployedBytecodeSize} bytes) is over the contract size limit (${contractSizeLimit} bytes). Run \`forge build --sizes\` for more info.\n`,
|
40
|
-
);
|
41
|
-
} else if (deployedBytecodeSize > contractSizeLimit * 0.95) {
|
42
|
-
console.warn(
|
43
|
-
`\nBytecode for ${label} (${deployedBytecodeSize} bytes) is almost over the contract size limit (${contractSizeLimit} bytes). Run \`forge build --sizes\` for more info.\n`,
|
44
|
-
);
|
45
|
-
}
|
46
|
-
|
47
|
-
debug("deploying", label, "at", address);
|
48
|
-
return [
|
49
|
-
await pRetry(
|
50
|
-
() =>
|
51
|
-
sendTransaction(client, {
|
52
|
-
chain: client.chain ?? null,
|
53
|
-
to: deployerAddress,
|
54
|
-
data: concatHex([salt, bytecode]),
|
55
|
-
}),
|
56
|
-
{
|
57
|
-
retries: 3,
|
58
|
-
onFailedAttempt: async (error) => {
|
59
|
-
const delay = error.attemptNumber * 500;
|
60
|
-
debug(`failed to deploy ${label}, retrying in ${delay}ms...`);
|
61
|
-
await wait(delay);
|
62
|
-
},
|
63
|
-
},
|
64
|
-
),
|
65
|
-
];
|
66
|
-
}
|
@@ -1,33 +0,0 @@
|
|
1
|
-
import { Client, Transport, Chain, Account, Hex } from "viem";
|
2
|
-
import { waitForTransactionReceipt } from "viem/actions";
|
3
|
-
import { debug } from "./debug";
|
4
|
-
import { Contract, ensureContract } from "./ensureContract";
|
5
|
-
import { uniqueBy } from "@latticexyz/common/utils";
|
6
|
-
|
7
|
-
export async function ensureContractsDeployed({
|
8
|
-
client,
|
9
|
-
deployerAddress,
|
10
|
-
contracts,
|
11
|
-
}: {
|
12
|
-
readonly client: Client<Transport, Chain | undefined, Account>;
|
13
|
-
readonly deployerAddress: Hex;
|
14
|
-
readonly contracts: readonly Contract[];
|
15
|
-
}): Promise<readonly Hex[]> {
|
16
|
-
// Deployments assume a deterministic deployer, so we only need to deploy the unique bytecode
|
17
|
-
const uniqueContracts = uniqueBy(contracts, (contract) => contract.bytecode);
|
18
|
-
|
19
|
-
const txs = (
|
20
|
-
await Promise.all(uniqueContracts.map((contract) => ensureContract({ client, deployerAddress, ...contract })))
|
21
|
-
).flat();
|
22
|
-
|
23
|
-
if (txs.length) {
|
24
|
-
debug("waiting for contracts");
|
25
|
-
// wait for each tx separately/serially, because parallelizing results in RPC errors
|
26
|
-
for (const tx of txs) {
|
27
|
-
await waitForTransactionReceipt(client, { hash: tx });
|
28
|
-
// TODO: throw if there was a revert?
|
29
|
-
}
|
30
|
-
}
|
31
|
-
|
32
|
-
return txs;
|
33
|
-
}
|
@@ -1,69 +0,0 @@
|
|
1
|
-
import { Account, Address, Chain, Client, Transport } from "viem";
|
2
|
-
import { getBalance, sendRawTransaction, sendTransaction, waitForTransactionReceipt } from "viem/actions";
|
3
|
-
import deployment from "./create2/deployment.json";
|
4
|
-
import { debug } from "./debug";
|
5
|
-
import { getDeployer } from "./getDeployer";
|
6
|
-
|
7
|
-
const deployer = `0x${deployment.address}` as const;
|
8
|
-
|
9
|
-
export async function ensureDeployer(client: Client<Transport, Chain | undefined, Account>): Promise<Address> {
|
10
|
-
const existingDeployer = await getDeployer(client);
|
11
|
-
if (existingDeployer !== undefined) {
|
12
|
-
return existingDeployer;
|
13
|
-
}
|
14
|
-
|
15
|
-
// There's not really a way to simulate a pre-EIP-155 (no chain ID) transaction,
|
16
|
-
// so we have to attempt to create the deployer first and, if it fails, fall back
|
17
|
-
// to a regular deploy.
|
18
|
-
|
19
|
-
// Send gas to deployment signer
|
20
|
-
const gasRequired = BigInt(deployment.gasLimit) * BigInt(deployment.gasPrice);
|
21
|
-
const currentBalance = await getBalance(client, { address: `0x${deployment.signerAddress}` });
|
22
|
-
const gasNeeded = gasRequired - currentBalance;
|
23
|
-
if (gasNeeded > 0) {
|
24
|
-
debug("sending gas for CREATE2 deployer to signer at", deployment.signerAddress);
|
25
|
-
const gasTx = await sendTransaction(client, {
|
26
|
-
chain: client.chain ?? null,
|
27
|
-
to: `0x${deployment.signerAddress}`,
|
28
|
-
value: gasNeeded,
|
29
|
-
});
|
30
|
-
const gasReceipt = await waitForTransactionReceipt(client, { hash: gasTx });
|
31
|
-
if (gasReceipt.status !== "success") {
|
32
|
-
console.error("failed to send gas to deployer signer", gasReceipt);
|
33
|
-
throw new Error("failed to send gas to deployer signer");
|
34
|
-
}
|
35
|
-
}
|
36
|
-
|
37
|
-
// Deploy the deployer
|
38
|
-
debug("deploying CREATE2 deployer at", deployer);
|
39
|
-
const deployTx = await sendRawTransaction(client, { serializedTransaction: `0x${deployment.transaction}` }).catch(
|
40
|
-
(error) => {
|
41
|
-
// Do a regular contract create if the presigned transaction doesn't work due to replay protection
|
42
|
-
if (String(error).includes("only replay-protected (EIP-155) transactions allowed over RPC")) {
|
43
|
-
console.warn(
|
44
|
-
// eslint-disable-next-line max-len
|
45
|
-
`\n ⚠️ Your chain or RPC does not allow for non EIP-155 signed transactions, so your deploys will not be determinstic and contract addresses may change between deploys.\n\n We recommend running your chain's node with \`--rpc.allow-unprotected-txs\` to enable determinstic deployments.\n`,
|
46
|
-
);
|
47
|
-
debug("deploying CREATE2 deployer");
|
48
|
-
return sendTransaction(client, {
|
49
|
-
chain: client.chain ?? null,
|
50
|
-
data: `0x${deployment.creationCode}`,
|
51
|
-
});
|
52
|
-
}
|
53
|
-
throw error;
|
54
|
-
},
|
55
|
-
);
|
56
|
-
|
57
|
-
const deployReceipt = await waitForTransactionReceipt(client, { hash: deployTx });
|
58
|
-
if (!deployReceipt.contractAddress) {
|
59
|
-
throw new Error("Deploy receipt did not have contract address, was the deployer not deployed?");
|
60
|
-
}
|
61
|
-
|
62
|
-
if (deployReceipt.contractAddress !== deployer) {
|
63
|
-
console.warn(
|
64
|
-
`\n ⚠️ CREATE2 deployer created at ${deployReceipt.contractAddress} does not match the CREATE2 determinstic deployer we expected (${deployer})`,
|
65
|
-
);
|
66
|
-
}
|
67
|
-
|
68
|
-
return deployReceipt.contractAddress;
|
69
|
-
}
|
@@ -1,86 +0,0 @@
|
|
1
|
-
import { Client, Transport, Chain, Account, Hex } from "viem";
|
2
|
-
import { hexToResource, writeContract } from "@latticexyz/common";
|
3
|
-
import { WorldDeploy, WorldFunction, worldAbi } from "./common";
|
4
|
-
import { debug } from "./debug";
|
5
|
-
import { getFunctions } from "./getFunctions";
|
6
|
-
import pRetry from "p-retry";
|
7
|
-
import { wait } from "@latticexyz/common/utils";
|
8
|
-
|
9
|
-
export async function ensureFunctions({
|
10
|
-
client,
|
11
|
-
worldDeploy,
|
12
|
-
functions,
|
13
|
-
}: {
|
14
|
-
readonly client: Client<Transport, Chain | undefined, Account>;
|
15
|
-
readonly worldDeploy: WorldDeploy;
|
16
|
-
readonly functions: readonly WorldFunction[];
|
17
|
-
}): Promise<readonly Hex[]> {
|
18
|
-
const worldFunctions = await getFunctions({ client, worldDeploy });
|
19
|
-
const worldSelectorToFunction = Object.fromEntries(worldFunctions.map((func) => [func.selector, func]));
|
20
|
-
|
21
|
-
const toSkip = functions.filter((func) => worldSelectorToFunction[func.selector]);
|
22
|
-
const toAdd = functions.filter((func) => !toSkip.includes(func));
|
23
|
-
|
24
|
-
if (toSkip.length) {
|
25
|
-
debug("functions already registered:", toSkip.map((func) => func.signature).join(", "));
|
26
|
-
const wrongSystem = toSkip.filter((func) => func.systemId !== worldSelectorToFunction[func.selector]?.systemId);
|
27
|
-
if (wrongSystem.length) {
|
28
|
-
console.warn(
|
29
|
-
"found",
|
30
|
-
wrongSystem.length,
|
31
|
-
"functions already registered but pointing at a different system ID:",
|
32
|
-
wrongSystem.map((func) => func.signature).join(", "),
|
33
|
-
);
|
34
|
-
}
|
35
|
-
}
|
36
|
-
|
37
|
-
if (!toAdd.length) return [];
|
38
|
-
|
39
|
-
debug("registering functions:", toAdd.map((func) => func.signature).join(", "));
|
40
|
-
|
41
|
-
return Promise.all(
|
42
|
-
toAdd.map((func) => {
|
43
|
-
const { namespace } = hexToResource(func.systemId);
|
44
|
-
if (namespace === "") {
|
45
|
-
return pRetry(
|
46
|
-
() =>
|
47
|
-
writeContract(client, {
|
48
|
-
chain: client.chain ?? null,
|
49
|
-
address: worldDeploy.address,
|
50
|
-
abi: worldAbi,
|
51
|
-
// TODO: replace with batchCall (https://github.com/latticexyz/mud/issues/1645)
|
52
|
-
functionName: "registerRootFunctionSelector",
|
53
|
-
args: [func.systemId, func.systemFunctionSignature, func.systemFunctionSignature],
|
54
|
-
}),
|
55
|
-
{
|
56
|
-
retries: 3,
|
57
|
-
onFailedAttempt: async (error) => {
|
58
|
-
const delay = error.attemptNumber * 500;
|
59
|
-
debug(`failed to register function ${func.signature}, retrying in ${delay}ms...`);
|
60
|
-
await wait(delay);
|
61
|
-
},
|
62
|
-
},
|
63
|
-
);
|
64
|
-
}
|
65
|
-
return pRetry(
|
66
|
-
() =>
|
67
|
-
writeContract(client, {
|
68
|
-
chain: client.chain ?? null,
|
69
|
-
address: worldDeploy.address,
|
70
|
-
abi: worldAbi,
|
71
|
-
// TODO: replace with batchCall (https://github.com/latticexyz/mud/issues/1645)
|
72
|
-
functionName: "registerFunctionSelector",
|
73
|
-
args: [func.systemId, func.systemFunctionSignature],
|
74
|
-
}),
|
75
|
-
{
|
76
|
-
retries: 3,
|
77
|
-
onFailedAttempt: async (error) => {
|
78
|
-
const delay = error.attemptNumber * 500;
|
79
|
-
debug(`failed to register function ${func.signature}, retrying in ${delay}ms...`);
|
80
|
-
await wait(delay);
|
81
|
-
},
|
82
|
-
},
|
83
|
-
);
|
84
|
-
}),
|
85
|
-
);
|
86
|
-
}
|
@@ -1,81 +0,0 @@
|
|
1
|
-
import { Client, Transport, Chain, Account, Hex, BaseError } from "viem";
|
2
|
-
import { writeContract } from "@latticexyz/common";
|
3
|
-
import { Library, Module, WorldDeploy, worldAbi } from "./common";
|
4
|
-
import { debug } from "./debug";
|
5
|
-
import { isDefined, wait } from "@latticexyz/common/utils";
|
6
|
-
import pRetry from "p-retry";
|
7
|
-
import { ensureContractsDeployed } from "./ensureContractsDeployed";
|
8
|
-
|
9
|
-
export async function ensureModules({
|
10
|
-
client,
|
11
|
-
deployerAddress,
|
12
|
-
libraries,
|
13
|
-
worldDeploy,
|
14
|
-
modules,
|
15
|
-
}: {
|
16
|
-
readonly client: Client<Transport, Chain | undefined, Account>;
|
17
|
-
readonly deployerAddress: Hex;
|
18
|
-
readonly libraries: readonly Library[];
|
19
|
-
readonly worldDeploy: WorldDeploy;
|
20
|
-
readonly modules: readonly Module[];
|
21
|
-
}): Promise<readonly Hex[]> {
|
22
|
-
if (!modules.length) return [];
|
23
|
-
|
24
|
-
await ensureContractsDeployed({
|
25
|
-
client,
|
26
|
-
deployerAddress,
|
27
|
-
contracts: modules.map((mod) => ({
|
28
|
-
bytecode: mod.prepareDeploy(deployerAddress, libraries).bytecode,
|
29
|
-
deployedBytecodeSize: mod.deployedBytecodeSize,
|
30
|
-
label: `${mod.name} module`,
|
31
|
-
})),
|
32
|
-
});
|
33
|
-
|
34
|
-
debug("installing modules:", modules.map((mod) => mod.name).join(", "));
|
35
|
-
return (
|
36
|
-
await Promise.all(
|
37
|
-
modules.map((mod) =>
|
38
|
-
pRetry(
|
39
|
-
async () => {
|
40
|
-
try {
|
41
|
-
// append module's ABI so that we can decode any custom errors
|
42
|
-
const abi = [...worldAbi, ...mod.abi];
|
43
|
-
const moduleAddress = mod.prepareDeploy(deployerAddress, libraries).address;
|
44
|
-
return mod.installAsRoot
|
45
|
-
? await writeContract(client, {
|
46
|
-
chain: client.chain ?? null,
|
47
|
-
address: worldDeploy.address,
|
48
|
-
abi,
|
49
|
-
// TODO: replace with batchCall (https://github.com/latticexyz/mud/issues/1645)
|
50
|
-
functionName: "installRootModule",
|
51
|
-
args: [moduleAddress, mod.installData],
|
52
|
-
})
|
53
|
-
: await writeContract(client, {
|
54
|
-
chain: client.chain ?? null,
|
55
|
-
address: worldDeploy.address,
|
56
|
-
abi,
|
57
|
-
// TODO: replace with batchCall (https://github.com/latticexyz/mud/issues/1645)
|
58
|
-
functionName: "installModule",
|
59
|
-
args: [moduleAddress, mod.installData],
|
60
|
-
});
|
61
|
-
} catch (error) {
|
62
|
-
if (error instanceof BaseError && error.message.includes("Module_AlreadyInstalled")) {
|
63
|
-
debug(`module ${mod.name} already installed`);
|
64
|
-
return;
|
65
|
-
}
|
66
|
-
throw error;
|
67
|
-
}
|
68
|
-
},
|
69
|
-
{
|
70
|
-
retries: 3,
|
71
|
-
onFailedAttempt: async (error) => {
|
72
|
-
const delay = error.attemptNumber * 500;
|
73
|
-
debug(`failed to install module ${mod.name}, retrying in ${delay}ms...`);
|
74
|
-
await wait(delay);
|
75
|
-
},
|
76
|
-
},
|
77
|
-
),
|
78
|
-
),
|
79
|
-
)
|
80
|
-
).filter(isDefined);
|
81
|
-
}
|
@@ -1,71 +0,0 @@
|
|
1
|
-
import { Account, Chain, Client, Hex, Transport, getAddress } from "viem";
|
2
|
-
import { WorldDeploy, worldAbi, worldTables } from "./common";
|
3
|
-
import { hexToResource, resourceToHex, writeContract } from "@latticexyz/common";
|
4
|
-
import { getResourceIds } from "./getResourceIds";
|
5
|
-
import { getTableValue } from "./getTableValue";
|
6
|
-
import { debug } from "./debug";
|
7
|
-
|
8
|
-
export async function ensureNamespaceOwner({
|
9
|
-
client,
|
10
|
-
worldDeploy,
|
11
|
-
resourceIds,
|
12
|
-
}: {
|
13
|
-
readonly client: Client<Transport, Chain | undefined, Account>;
|
14
|
-
readonly worldDeploy: WorldDeploy;
|
15
|
-
readonly resourceIds: readonly Hex[];
|
16
|
-
}): Promise<readonly Hex[]> {
|
17
|
-
const desiredNamespaces = Array.from(new Set(resourceIds.map((resourceId) => hexToResource(resourceId).namespace)));
|
18
|
-
const existingResourceIds = await getResourceIds({ client, worldDeploy });
|
19
|
-
const existingNamespaces = new Set(existingResourceIds.map((resourceId) => hexToResource(resourceId).namespace));
|
20
|
-
if (existingNamespaces.size) {
|
21
|
-
debug(
|
22
|
-
"found",
|
23
|
-
existingNamespaces.size,
|
24
|
-
"existing namespaces:",
|
25
|
-
Array.from(existingNamespaces)
|
26
|
-
.map((namespace) => (namespace === "" ? "<root>" : namespace))
|
27
|
-
.join(", "),
|
28
|
-
);
|
29
|
-
}
|
30
|
-
|
31
|
-
// Assert ownership of existing namespaces
|
32
|
-
const existingDesiredNamespaces = desiredNamespaces.filter((namespace) => existingNamespaces.has(namespace));
|
33
|
-
const namespaceOwners = await Promise.all(
|
34
|
-
existingDesiredNamespaces.map(async (namespace) => {
|
35
|
-
const { owner } = await getTableValue({
|
36
|
-
client,
|
37
|
-
worldDeploy,
|
38
|
-
table: worldTables.world_NamespaceOwner,
|
39
|
-
key: { namespaceId: resourceToHex({ type: "namespace", namespace, name: "" }) },
|
40
|
-
});
|
41
|
-
return [namespace, owner];
|
42
|
-
}),
|
43
|
-
);
|
44
|
-
|
45
|
-
const unauthorizedNamespaces = namespaceOwners
|
46
|
-
.filter(([, owner]) => getAddress(owner) !== getAddress(client.account.address))
|
47
|
-
.map(([namespace]) => namespace);
|
48
|
-
|
49
|
-
if (unauthorizedNamespaces.length) {
|
50
|
-
throw new Error(`You are attempting to deploy to namespaces you do not own: ${unauthorizedNamespaces.join(", ")}`);
|
51
|
-
}
|
52
|
-
|
53
|
-
// Register missing namespaces
|
54
|
-
const missingNamespaces = desiredNamespaces.filter((namespace) => !existingNamespaces.has(namespace));
|
55
|
-
if (missingNamespaces.length > 0) {
|
56
|
-
debug("registering namespaces", Array.from(missingNamespaces).join(", "));
|
57
|
-
}
|
58
|
-
const registrationTxs = Promise.all(
|
59
|
-
missingNamespaces.map((namespace) =>
|
60
|
-
writeContract(client, {
|
61
|
-
chain: client.chain ?? null,
|
62
|
-
address: worldDeploy.address,
|
63
|
-
abi: worldAbi,
|
64
|
-
functionName: "registerNamespace",
|
65
|
-
args: [resourceToHex({ namespace, type: "namespace", name: "" })],
|
66
|
-
}),
|
67
|
-
),
|
68
|
-
);
|
69
|
-
|
70
|
-
return registrationTxs;
|
71
|
-
}
|
@@ -1,187 +0,0 @@
|
|
1
|
-
import { Client, Transport, Chain, Account, Hex, getAddress, Address } from "viem";
|
2
|
-
import { writeContract, resourceToLabel } from "@latticexyz/common";
|
3
|
-
import { Library, System, WorldDeploy, worldAbi } from "./common";
|
4
|
-
import { debug } from "./debug";
|
5
|
-
import { getSystems } from "./getSystems";
|
6
|
-
import { getResourceAccess } from "./getResourceAccess";
|
7
|
-
import { wait } from "@latticexyz/common/utils";
|
8
|
-
import pRetry from "p-retry";
|
9
|
-
import { ensureContractsDeployed } from "./ensureContractsDeployed";
|
10
|
-
|
11
|
-
// TODO: move each system registration+access to batch call to be atomic
|
12
|
-
|
13
|
-
export async function ensureSystems({
|
14
|
-
client,
|
15
|
-
deployerAddress,
|
16
|
-
libraries,
|
17
|
-
worldDeploy,
|
18
|
-
systems,
|
19
|
-
}: {
|
20
|
-
readonly client: Client<Transport, Chain | undefined, Account>;
|
21
|
-
readonly deployerAddress: Hex;
|
22
|
-
readonly libraries: readonly Library[];
|
23
|
-
readonly worldDeploy: WorldDeploy;
|
24
|
-
readonly systems: readonly System[];
|
25
|
-
}): Promise<readonly Hex[]> {
|
26
|
-
const [worldSystems, worldAccess] = await Promise.all([
|
27
|
-
getSystems({ client, worldDeploy }),
|
28
|
-
getResourceAccess({ client, worldDeploy }),
|
29
|
-
]);
|
30
|
-
|
31
|
-
// Register or replace systems
|
32
|
-
|
33
|
-
const existingSystems = systems.filter((system) =>
|
34
|
-
worldSystems.some(
|
35
|
-
(worldSystem) =>
|
36
|
-
worldSystem.systemId === system.systemId &&
|
37
|
-
getAddress(worldSystem.address) === getAddress(system.prepareDeploy(deployerAddress, libraries).address),
|
38
|
-
),
|
39
|
-
);
|
40
|
-
if (existingSystems.length) {
|
41
|
-
debug("existing systems", existingSystems.map(resourceToLabel).join(", "));
|
42
|
-
}
|
43
|
-
const existingSystemIds = existingSystems.map((system) => system.systemId);
|
44
|
-
|
45
|
-
const missingSystems = systems.filter((system) => !existingSystemIds.includes(system.systemId));
|
46
|
-
if (!missingSystems.length) return [];
|
47
|
-
|
48
|
-
const systemsToUpgrade = missingSystems.filter((system) =>
|
49
|
-
worldSystems.some(
|
50
|
-
(worldSystem) =>
|
51
|
-
worldSystem.systemId === system.systemId &&
|
52
|
-
getAddress(worldSystem.address) !== getAddress(system.prepareDeploy(deployerAddress, libraries).address),
|
53
|
-
),
|
54
|
-
);
|
55
|
-
if (systemsToUpgrade.length) {
|
56
|
-
debug("upgrading systems", systemsToUpgrade.map(resourceToLabel).join(", "));
|
57
|
-
}
|
58
|
-
|
59
|
-
const systemsToAdd = missingSystems.filter(
|
60
|
-
(system) => !worldSystems.some((worldSystem) => worldSystem.systemId === system.systemId),
|
61
|
-
);
|
62
|
-
if (systemsToAdd.length) {
|
63
|
-
debug("registering new systems", systemsToAdd.map(resourceToLabel).join(", "));
|
64
|
-
}
|
65
|
-
|
66
|
-
await ensureContractsDeployed({
|
67
|
-
client,
|
68
|
-
deployerAddress,
|
69
|
-
contracts: missingSystems.map((system) => ({
|
70
|
-
bytecode: system.prepareDeploy(deployerAddress, libraries).bytecode,
|
71
|
-
deployedBytecodeSize: system.deployedBytecodeSize,
|
72
|
-
label: `${resourceToLabel(system)} system`,
|
73
|
-
})),
|
74
|
-
});
|
75
|
-
|
76
|
-
const registerTxs = await Promise.all(
|
77
|
-
missingSystems.map((system) =>
|
78
|
-
pRetry(
|
79
|
-
() =>
|
80
|
-
writeContract(client, {
|
81
|
-
chain: client.chain ?? null,
|
82
|
-
address: worldDeploy.address,
|
83
|
-
abi: worldAbi,
|
84
|
-
// TODO: replace with batchCall (https://github.com/latticexyz/mud/issues/1645)
|
85
|
-
functionName: "registerSystem",
|
86
|
-
args: [system.systemId, system.prepareDeploy(deployerAddress, libraries).address, system.allowAll],
|
87
|
-
}),
|
88
|
-
{
|
89
|
-
retries: 3,
|
90
|
-
onFailedAttempt: async (error) => {
|
91
|
-
const delay = error.attemptNumber * 500;
|
92
|
-
debug(`failed to register system ${resourceToLabel(system)}, retrying in ${delay}ms...`);
|
93
|
-
await wait(delay);
|
94
|
-
},
|
95
|
-
},
|
96
|
-
),
|
97
|
-
),
|
98
|
-
);
|
99
|
-
|
100
|
-
// Adjust system access
|
101
|
-
|
102
|
-
const systemIds = systems.map((system) => system.systemId);
|
103
|
-
const currentAccess = worldAccess.filter(({ resourceId }) => systemIds.includes(resourceId));
|
104
|
-
const desiredAccess = [
|
105
|
-
...systems.flatMap((system) =>
|
106
|
-
system.allowedAddresses.map((address) => ({ resourceId: system.systemId, address })),
|
107
|
-
),
|
108
|
-
...systems.flatMap((system) =>
|
109
|
-
system.allowedSystemIds
|
110
|
-
.map((systemId) => ({
|
111
|
-
resourceId: system.systemId,
|
112
|
-
address:
|
113
|
-
worldSystems.find((s) => s.systemId === systemId)?.address ??
|
114
|
-
systems.find((s) => s.systemId === systemId)?.prepareDeploy(deployerAddress, libraries).address,
|
115
|
-
}))
|
116
|
-
.filter((access): access is typeof access & { address: Address } => access.address != null),
|
117
|
-
),
|
118
|
-
];
|
119
|
-
|
120
|
-
const accessToAdd = desiredAccess.filter(
|
121
|
-
(access) =>
|
122
|
-
!currentAccess.some(
|
123
|
-
({ resourceId, address }) =>
|
124
|
-
resourceId === access.resourceId && getAddress(address) === getAddress(access.address),
|
125
|
-
),
|
126
|
-
);
|
127
|
-
|
128
|
-
const accessToRemove = currentAccess.filter(
|
129
|
-
(access) =>
|
130
|
-
!desiredAccess.some(
|
131
|
-
({ resourceId, address }) =>
|
132
|
-
resourceId === access.resourceId && getAddress(address) === getAddress(access.address),
|
133
|
-
),
|
134
|
-
);
|
135
|
-
|
136
|
-
if (accessToRemove.length) {
|
137
|
-
debug("revoking", accessToRemove.length, "access grants");
|
138
|
-
}
|
139
|
-
if (accessToAdd.length) {
|
140
|
-
debug("adding", accessToAdd.length, "access grants");
|
141
|
-
}
|
142
|
-
|
143
|
-
const accessTxs = await Promise.all([
|
144
|
-
...accessToRemove.map((access) =>
|
145
|
-
pRetry(
|
146
|
-
() =>
|
147
|
-
writeContract(client, {
|
148
|
-
chain: client.chain ?? null,
|
149
|
-
address: worldDeploy.address,
|
150
|
-
abi: worldAbi,
|
151
|
-
functionName: "revokeAccess",
|
152
|
-
args: [access.resourceId, access.address],
|
153
|
-
}),
|
154
|
-
{
|
155
|
-
retries: 3,
|
156
|
-
onFailedAttempt: async (error) => {
|
157
|
-
const delay = error.attemptNumber * 500;
|
158
|
-
debug(`failed to revoke access, retrying in ${delay}ms...`);
|
159
|
-
await wait(delay);
|
160
|
-
},
|
161
|
-
},
|
162
|
-
),
|
163
|
-
),
|
164
|
-
...accessToAdd.map((access) =>
|
165
|
-
pRetry(
|
166
|
-
() =>
|
167
|
-
writeContract(client, {
|
168
|
-
chain: client.chain ?? null,
|
169
|
-
address: worldDeploy.address,
|
170
|
-
abi: worldAbi,
|
171
|
-
functionName: "grantAccess",
|
172
|
-
args: [access.resourceId, access.address],
|
173
|
-
}),
|
174
|
-
{
|
175
|
-
retries: 3,
|
176
|
-
onFailedAttempt: async (error) => {
|
177
|
-
const delay = error.attemptNumber * 500;
|
178
|
-
debug(`failed to grant access, retrying in ${delay}ms...`);
|
179
|
-
await wait(delay);
|
180
|
-
},
|
181
|
-
},
|
182
|
-
),
|
183
|
-
),
|
184
|
-
]);
|
185
|
-
|
186
|
-
return [...registerTxs, ...accessTxs];
|
187
|
-
}
|
@@ -1,64 +0,0 @@
|
|
1
|
-
import { Client, Transport, Chain, Account, Hex } from "viem";
|
2
|
-
import { Table } from "./configToTables";
|
3
|
-
import { resourceToLabel, writeContract } from "@latticexyz/common";
|
4
|
-
import { WorldDeploy, worldAbi } from "./common";
|
5
|
-
import { valueSchemaToFieldLayoutHex, keySchemaToHex, valueSchemaToHex } from "@latticexyz/protocol-parser/internal";
|
6
|
-
import { debug } from "./debug";
|
7
|
-
import { getTables } from "./getTables";
|
8
|
-
import pRetry from "p-retry";
|
9
|
-
import { wait } from "@latticexyz/common/utils";
|
10
|
-
|
11
|
-
export async function ensureTables({
|
12
|
-
client,
|
13
|
-
worldDeploy,
|
14
|
-
tables,
|
15
|
-
}: {
|
16
|
-
readonly client: Client<Transport, Chain | undefined, Account>;
|
17
|
-
readonly worldDeploy: WorldDeploy;
|
18
|
-
readonly tables: readonly Table[];
|
19
|
-
}): Promise<readonly Hex[]> {
|
20
|
-
const worldTables = await getTables({ client, worldDeploy });
|
21
|
-
const worldTableIds = worldTables.map((table) => table.tableId);
|
22
|
-
|
23
|
-
const existingTables = tables.filter((table) => worldTableIds.includes(table.tableId));
|
24
|
-
if (existingTables.length) {
|
25
|
-
debug("existing tables", existingTables.map(resourceToLabel).join(", "));
|
26
|
-
}
|
27
|
-
|
28
|
-
const missingTables = tables.filter((table) => !worldTableIds.includes(table.tableId));
|
29
|
-
if (missingTables.length) {
|
30
|
-
debug("registering tables", missingTables.map(resourceToLabel).join(", "));
|
31
|
-
return await Promise.all(
|
32
|
-
missingTables.map((table) =>
|
33
|
-
pRetry(
|
34
|
-
() =>
|
35
|
-
writeContract(client, {
|
36
|
-
chain: client.chain ?? null,
|
37
|
-
address: worldDeploy.address,
|
38
|
-
abi: worldAbi,
|
39
|
-
// TODO: replace with batchCall (https://github.com/latticexyz/mud/issues/1645)
|
40
|
-
functionName: "registerTable",
|
41
|
-
args: [
|
42
|
-
table.tableId,
|
43
|
-
valueSchemaToFieldLayoutHex(table.valueSchema),
|
44
|
-
keySchemaToHex(table.keySchema),
|
45
|
-
valueSchemaToHex(table.valueSchema),
|
46
|
-
Object.keys(table.keySchema),
|
47
|
-
Object.keys(table.valueSchema),
|
48
|
-
],
|
49
|
-
}),
|
50
|
-
{
|
51
|
-
retries: 3,
|
52
|
-
onFailedAttempt: async (error) => {
|
53
|
-
const delay = error.attemptNumber * 500;
|
54
|
-
debug(`failed to register table ${resourceToLabel(table)}, retrying in ${delay}ms...`);
|
55
|
-
await wait(delay);
|
56
|
-
},
|
57
|
-
},
|
58
|
-
),
|
59
|
-
),
|
60
|
-
);
|
61
|
-
}
|
62
|
-
|
63
|
-
return [];
|
64
|
-
}
|
@@ -1,30 +0,0 @@
|
|
1
|
-
import { Client, Transport, Chain, Account, Hex, Address } from "viem";
|
2
|
-
import { ensureContractsDeployed } from "./ensureContractsDeployed";
|
3
|
-
import { getWorldFactoryContracts } from "./getWorldFactoryContracts";
|
4
|
-
import { getWorldProxyFactoryContracts } from "./getWorldProxyFactoryContracts";
|
5
|
-
|
6
|
-
export async function ensureWorldFactory(
|
7
|
-
client: Client<Transport, Chain | undefined, Account>,
|
8
|
-
deployerAddress: Hex,
|
9
|
-
withWorldProxy?: boolean,
|
10
|
-
): Promise<Address> {
|
11
|
-
if (withWorldProxy) {
|
12
|
-
const contracts = getWorldProxyFactoryContracts(deployerAddress);
|
13
|
-
// We can deploy these contracts in parallel because they do not call each other at this point.
|
14
|
-
await ensureContractsDeployed({
|
15
|
-
client,
|
16
|
-
deployerAddress,
|
17
|
-
contracts: Object.values(contracts),
|
18
|
-
});
|
19
|
-
return contracts.WorldProxyFactory.address;
|
20
|
-
}
|
21
|
-
|
22
|
-
const contracts = getWorldFactoryContracts(deployerAddress);
|
23
|
-
// We can deploy these contracts in parallel because they do not call each other at this point.
|
24
|
-
await ensureContractsDeployed({
|
25
|
-
client,
|
26
|
-
deployerAddress,
|
27
|
-
contracts: Object.values(contracts),
|
28
|
-
});
|
29
|
-
return contracts.WorldFactory.address;
|
30
|
-
}
|