@latticexyz/cli 2.0.0-main-257a0afc → 2.0.0-march-19-skystrife-playtest-f0a343b1
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-RZOPG5RM.js +27 -0
- package/dist/commands-RZOPG5RM.js.map +1 -0
- package/dist/mud.js +1 -1
- package/dist/mud.js.map +1 -1
- package/package.json +15 -17
- package/src/commands/deploy.ts +1 -1
- package/src/commands/dev-contracts.ts +1 -4
- package/src/commands/set-version.ts +1 -1
- package/src/commands/trace.ts +1 -1
- package/src/deploy/assertNamespaceOwner.ts +42 -0
- package/src/deploy/common.ts +2 -44
- package/src/deploy/configToTables.ts +3 -5
- package/src/deploy/create2/README.md +0 -4
- package/src/deploy/create2/deployment.json +1 -2
- package/src/deploy/deploy.ts +18 -43
- package/src/deploy/deployWorld.ts +4 -9
- package/src/deploy/ensureContract.ts +7 -12
- package/src/deploy/ensureContractsDeployed.ts +1 -9
- package/src/deploy/ensureDeployer.ts +22 -61
- package/src/deploy/ensureFunctions.ts +5 -5
- package/src/deploy/ensureModules.ts +10 -16
- package/src/deploy/ensureSystems.ts +83 -108
- package/src/deploy/ensureTables.ts +8 -7
- package/src/deploy/ensureWorldFactory.ts +37 -95
- package/src/deploy/getFunctions.ts +4 -4
- package/src/deploy/getResourceAccess.ts +2 -2
- package/src/deploy/getSystems.ts +7 -6
- package/src/deploy/getTables.ts +1 -1
- package/src/deploy/logsToWorldDeploy.ts +1 -1
- package/src/deploy/resolveConfig.ts +55 -52
- package/src/deploy/resourceLabel.ts +3 -0
- package/src/mud.ts +1 -1
- package/src/mudPackages.ts +1 -1
- package/src/runDeploy.ts +7 -34
- package/src/utils/{defaultModuleContracts.ts → modules/constants.ts} +0 -4
- package/src/utils/printMUD.ts +1 -1
- package/src/utils/{getContractData.ts → utils/getContractData.ts} +5 -11
- package/src/utils/{postDeploy.ts → utils/postDeploy.ts} +2 -2
- package/dist/commands-22M65L4E.js +0 -36
- package/dist/commands-22M65L4E.js.map +0 -1
- package/src/deploy/createPrepareDeploy.ts +0 -28
- package/src/deploy/ensureNamespaceOwner.ts +0 -71
- package/src/deploy/findLibraries.ts +0 -36
- package/src/deploy/orderByDependencies.ts +0 -12
- package/src/utils/findPlaceholders.ts +0 -27
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@latticexyz/cli",
|
3
|
-
"version": "2.0.0-
|
3
|
+
"version": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
4
4
|
"description": "Command line interface for mud",
|
5
5
|
"repository": {
|
6
6
|
"type": "git",
|
@@ -35,23 +35,22 @@
|
|
35
35
|
"path": "^0.12.7",
|
36
36
|
"rxjs": "7.5.5",
|
37
37
|
"throttle-debounce": "^5.0.0",
|
38
|
-
"
|
39
|
-
"
|
40
|
-
"viem": "2.7.12",
|
38
|
+
"typescript": "5.1.6",
|
39
|
+
"viem": "1.14.0",
|
41
40
|
"yargs": "^17.7.1",
|
42
41
|
"zod": "^3.21.4",
|
43
42
|
"zod-validation-error": "^1.3.0",
|
44
|
-
"@latticexyz/abi-ts": "2.0.0-
|
45
|
-
"@latticexyz/common": "2.0.0-
|
46
|
-
"@latticexyz/config": "2.0.0-
|
47
|
-
"@latticexyz/gas-report": "2.0.0-
|
48
|
-
"@latticexyz/protocol-parser": "2.0.0-
|
49
|
-
"@latticexyz/schema-type": "2.0.0-
|
50
|
-
"@latticexyz/services": "2.0.0-
|
51
|
-
"@latticexyz/store": "2.0.0-
|
52
|
-
"@latticexyz/utils": "2.0.0-
|
53
|
-
"@latticexyz/world": "2.0.0-
|
54
|
-
"@latticexyz/world-modules": "2.0.0-
|
43
|
+
"@latticexyz/abi-ts": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
44
|
+
"@latticexyz/common": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
45
|
+
"@latticexyz/config": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
46
|
+
"@latticexyz/gas-report": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
47
|
+
"@latticexyz/protocol-parser": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
48
|
+
"@latticexyz/schema-type": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
49
|
+
"@latticexyz/services": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
50
|
+
"@latticexyz/store": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
51
|
+
"@latticexyz/utils": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
52
|
+
"@latticexyz/world": "2.0.0-march-19-skystrife-playtest-f0a343b1",
|
53
|
+
"@latticexyz/world-modules": "2.0.0-march-19-skystrife-playtest-f0a343b1"
|
55
54
|
},
|
56
55
|
"devDependencies": {
|
57
56
|
"@types/debug": "^4.1.7",
|
@@ -60,13 +59,12 @@
|
|
60
59
|
"@types/node": "^18.15.11",
|
61
60
|
"@types/openurl": "^1.0.0",
|
62
61
|
"@types/throttle-debounce": "^5.0.0",
|
63
|
-
"@types/toposort": "^2.0.6",
|
64
62
|
"@types/yargs": "^17.0.10",
|
65
63
|
"ds-test": "https://github.com/dapphub/ds-test.git#e282159d5170298eb2455a6c05280ab5a73a4ef0",
|
66
64
|
"forge-std": "https://github.com/foundry-rs/forge-std.git#74cfb77e308dd188d2f58864aaf44963ae6b88b1",
|
67
65
|
"tsup": "^6.7.0",
|
68
66
|
"tsx": "^3.12.6",
|
69
|
-
"vitest": "0.
|
67
|
+
"vitest": "0.31.4"
|
70
68
|
},
|
71
69
|
"gitHead": "914a1e0ae4a573d685841ca2ea921435057deb8f",
|
72
70
|
"scripts": {
|
package/src/commands/deploy.ts
CHANGED
@@ -15,7 +15,7 @@ const commandModule: CommandModule<typeof deployOptions, DeployOptions> = {
|
|
15
15
|
// Wrap in try/catch, because yargs seems to swallow errors
|
16
16
|
try {
|
17
17
|
await runDeploy(opts);
|
18
|
-
} catch (error) {
|
18
|
+
} catch (error: any) {
|
19
19
|
logError(error);
|
20
20
|
process.exit(1);
|
21
21
|
}
|
@@ -83,15 +83,12 @@ const commandModule: CommandModule<typeof devOptions, InferredOptionTypes<typeof
|
|
83
83
|
...opts,
|
84
84
|
configPath,
|
85
85
|
rpc,
|
86
|
-
rpcBatch: false,
|
87
86
|
skipBuild: false,
|
88
87
|
printConfig: false,
|
89
88
|
profile: undefined,
|
90
89
|
saveDeployment: true,
|
91
|
-
deployerAddress: undefined,
|
92
90
|
worldAddress,
|
93
91
|
srcDir,
|
94
|
-
salt: "0x",
|
95
92
|
});
|
96
93
|
worldAddress = deploy.address;
|
97
94
|
// if there were changes while we were deploying, trigger it again
|
@@ -107,7 +104,7 @@ const commandModule: CommandModule<typeof devOptions, InferredOptionTypes<typeof
|
|
107
104
|
console.log(chalk.gray("\nWaiting for file changes…\n"));
|
108
105
|
}
|
109
106
|
}),
|
110
|
-
filter(isDefined)
|
107
|
+
filter(isDefined)
|
111
108
|
);
|
112
109
|
|
113
110
|
deploys$.subscribe();
|
@@ -45,7 +45,7 @@ const commandModule: CommandModule<Options, Options> = {
|
|
45
45
|
const mutuallyExclusiveOptions = ["mudVersion", "link", "tag", "commit", "restore"];
|
46
46
|
const numMutuallyExclusiveOptions = mutuallyExclusiveOptions.reduce(
|
47
47
|
(acc, opt) => (options[opt] ? acc + 1 : acc),
|
48
|
-
0
|
48
|
+
0
|
49
49
|
);
|
50
50
|
|
51
51
|
if (numMutuallyExclusiveOptions === 0) {
|
package/src/commands/trace.ts
CHANGED
@@ -63,7 +63,7 @@ const commandModule: CommandModule<Options, Options> = {
|
|
63
63
|
|
64
64
|
const resolvedConfig = resolveWorldConfig(
|
65
65
|
mudConfig,
|
66
|
-
existingContracts.map(({ basename }) => basename)
|
66
|
+
existingContracts.map(({ basename }) => basename)
|
67
67
|
);
|
68
68
|
|
69
69
|
// Get worldAddress either from args or from worldsFile
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { Account, Chain, Client, Hex, Transport, getAddress } from "viem";
|
2
|
+
import { WorldDeploy, worldTables } from "./common";
|
3
|
+
import { hexToResource, resourceToHex } from "@latticexyz/common";
|
4
|
+
import { getResourceIds } from "./getResourceIds";
|
5
|
+
import { getTableValue } from "./getTableValue";
|
6
|
+
|
7
|
+
export async function assertNamespaceOwner({
|
8
|
+
client,
|
9
|
+
worldDeploy,
|
10
|
+
resourceIds,
|
11
|
+
}: {
|
12
|
+
readonly client: Client<Transport, Chain | undefined, Account>;
|
13
|
+
readonly worldDeploy: WorldDeploy;
|
14
|
+
readonly resourceIds: readonly Hex[];
|
15
|
+
}): Promise<void> {
|
16
|
+
const desiredNamespaces = Array.from(new Set(resourceIds.map((resourceId) => hexToResource(resourceId).namespace)));
|
17
|
+
const existingResourceIds = await getResourceIds({ client, worldDeploy });
|
18
|
+
const existingNamespaces = Array.from(
|
19
|
+
new Set(existingResourceIds.map((resourceId) => hexToResource(resourceId).namespace))
|
20
|
+
);
|
21
|
+
|
22
|
+
const namespaces = desiredNamespaces.filter((namespace) => existingNamespaces.includes(namespace));
|
23
|
+
const namespaceOwners = await Promise.all(
|
24
|
+
namespaces.map(async (namespace) => {
|
25
|
+
const { owner } = await getTableValue({
|
26
|
+
client,
|
27
|
+
worldDeploy,
|
28
|
+
table: worldTables.world_NamespaceOwner,
|
29
|
+
key: { namespaceId: resourceToHex({ type: "namespace", namespace, name: "" }) },
|
30
|
+
});
|
31
|
+
return [namespace, owner];
|
32
|
+
})
|
33
|
+
);
|
34
|
+
|
35
|
+
const unauthorizedNamespaces = namespaceOwners
|
36
|
+
.filter(([, owner]) => getAddress(owner) !== getAddress(client.account.address))
|
37
|
+
.map(([namespace]) => namespace);
|
38
|
+
|
39
|
+
if (unauthorizedNamespaces.length) {
|
40
|
+
throw new Error(`You are attempting to deploy to namespaces you do not own: ${unauthorizedNamespaces.join(", ")}`);
|
41
|
+
}
|
42
|
+
}
|
package/src/deploy/common.ts
CHANGED
@@ -24,7 +24,6 @@ export const worldAbi = [...IBaseWorldAbi, ...IModuleAbi] as const;
|
|
24
24
|
export const supportedStoreVersions = ["1.0.0-unaudited"];
|
25
25
|
export const supportedWorldVersions = ["1.0.0-unaudited"];
|
26
26
|
|
27
|
-
// TODO: extend this to include factory+deployer address? so we can reuse the deployer for a world?
|
28
27
|
export type WorldDeploy = {
|
29
28
|
readonly address: Address;
|
30
29
|
readonly worldVersion: string;
|
@@ -47,62 +46,22 @@ export type WorldFunction = {
|
|
47
46
|
readonly systemFunctionSelector: Hex;
|
48
47
|
};
|
49
48
|
|
50
|
-
export type LibraryPlaceholder = {
|
51
|
-
/**
|
52
|
-
* Path to library source file, e.g. `src/libraries/SomeLib.sol`
|
53
|
-
*/
|
54
|
-
path: string;
|
55
|
-
/**
|
56
|
-
* Library name, e.g. `SomeLib`
|
57
|
-
*/
|
58
|
-
name: string;
|
59
|
-
/**
|
60
|
-
* Byte offset of placeholder in bytecode
|
61
|
-
*/
|
62
|
-
start: number;
|
63
|
-
/**
|
64
|
-
* Size of placeholder to replace in bytes
|
65
|
-
*/
|
66
|
-
length: number;
|
67
|
-
};
|
68
|
-
|
69
49
|
export type DeterministicContract = {
|
70
|
-
readonly
|
71
|
-
|
72
|
-
libraries: readonly Library[],
|
73
|
-
) => {
|
74
|
-
readonly address: Address;
|
75
|
-
readonly bytecode: Hex;
|
76
|
-
};
|
50
|
+
readonly address: Address;
|
51
|
+
readonly bytecode: Hex;
|
77
52
|
readonly deployedBytecodeSize: number;
|
78
53
|
readonly abi: Abi;
|
79
54
|
};
|
80
55
|
|
81
|
-
export type Library = DeterministicContract & {
|
82
|
-
/**
|
83
|
-
* Path to library source file, e.g. `src/libraries/SomeLib.sol`
|
84
|
-
*/
|
85
|
-
path: string;
|
86
|
-
/**
|
87
|
-
* Library name, e.g. `SomeLib`
|
88
|
-
*/
|
89
|
-
name: string;
|
90
|
-
};
|
91
|
-
|
92
56
|
export type System = DeterministicContract & {
|
93
57
|
readonly namespace: string;
|
94
58
|
readonly name: string;
|
95
59
|
readonly systemId: Hex;
|
96
60
|
readonly allowAll: boolean;
|
97
61
|
readonly allowedAddresses: readonly Hex[];
|
98
|
-
readonly allowedSystemIds: readonly Hex[];
|
99
62
|
readonly functions: readonly WorldFunction[];
|
100
63
|
};
|
101
64
|
|
102
|
-
export type DeployedSystem = Omit<System, "abi" | "prepareDeploy" | "deployedBytecodeSize" | "allowedSystemIds"> & {
|
103
|
-
address: Address;
|
104
|
-
};
|
105
|
-
|
106
65
|
export type Module = DeterministicContract & {
|
107
66
|
readonly name: string;
|
108
67
|
readonly installAsRoot: boolean;
|
@@ -114,5 +73,4 @@ export type Config<config extends ConfigInput> = {
|
|
114
73
|
readonly tables: Tables<config>;
|
115
74
|
readonly systems: readonly System[];
|
116
75
|
readonly modules: readonly Module[];
|
117
|
-
readonly libraries: readonly Library[];
|
118
76
|
};
|
@@ -14,12 +14,12 @@ type UserTypes<config extends StoreConfig = StoreConfig> = config["userTypes"];
|
|
14
14
|
|
15
15
|
export type TableKey<
|
16
16
|
config extends StoreConfig = StoreConfig,
|
17
|
-
table extends config["tables"][keyof config["tables"]] = config["tables"][keyof config["tables"]]
|
17
|
+
table extends config["tables"][keyof config["tables"]] = config["tables"][keyof config["tables"]]
|
18
18
|
> = `${config["namespace"]}_${table["name"]}`;
|
19
19
|
|
20
20
|
export type Table<
|
21
21
|
config extends StoreConfig = StoreConfig,
|
22
|
-
table extends config["tables"][keyof config["tables"]] = config["tables"][keyof config["tables"]]
|
22
|
+
table extends config["tables"][keyof config["tables"]] = config["tables"][keyof config["tables"]]
|
23
23
|
> = {
|
24
24
|
readonly namespace: config["namespace"];
|
25
25
|
readonly name: table["name"];
|
@@ -60,11 +60,9 @@ export function configToTables<config extends StoreConfig>(config: config): Tabl
|
|
60
60
|
namespace: config.namespace,
|
61
61
|
name: table.name,
|
62
62
|
}),
|
63
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
64
63
|
keySchema: resolveUserTypes(table.keySchema, userTypes) as any,
|
65
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
66
64
|
valueSchema: resolveUserTypes(table.valueSchema, userTypes) as any,
|
67
65
|
} satisfies Table<config, config["tables"][keyof config["tables"]]>,
|
68
|
-
])
|
66
|
+
])
|
69
67
|
) as Tables<config>;
|
70
68
|
}
|
@@ -6,8 +6,4 @@ cd deterministic-deployment-proxy
|
|
6
6
|
git checkout b3bb19c
|
7
7
|
npm install
|
8
8
|
npm run build
|
9
|
-
cd output
|
10
|
-
jq --arg bc "$(cat bytecode.txt)" '. + {bytecode: $bc}' deployment.json > deployment-with-bytecode.json
|
11
|
-
mv deployment-with-bytecode.json deployment.json
|
12
|
-
cp deployment.json ../path/to/this/dir
|
13
9
|
```
|
@@ -3,6 +3,5 @@
|
|
3
3
|
"gasLimit": 100000,
|
4
4
|
"signerAddress": "3fab184622dc19b6109349b94811493bf2a45362",
|
5
5
|
"transaction": "f8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222",
|
6
|
-
"address": "4e59b44847b379578588920ca78fbf26c0b4956c"
|
7
|
-
"bytecode": "604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"
|
6
|
+
"address": "4e59b44847b379578588920ca78fbf26c0b4956c"
|
8
7
|
}
|
package/src/deploy/deploy.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Account, Address, Chain, Client,
|
1
|
+
import { Account, Address, Chain, Client, Transport, getAddress } from "viem";
|
2
2
|
import { ensureDeployer } from "./ensureDeployer";
|
3
3
|
import { deployWorld } from "./deployWorld";
|
4
4
|
import { ensureTables } from "./ensureTables";
|
@@ -9,25 +9,17 @@ import { getWorldDeploy } from "./getWorldDeploy";
|
|
9
9
|
import { ensureFunctions } from "./ensureFunctions";
|
10
10
|
import { ensureModules } from "./ensureModules";
|
11
11
|
import { Table } from "./configToTables";
|
12
|
-
import {
|
12
|
+
import { assertNamespaceOwner } from "./assertNamespaceOwner";
|
13
13
|
import { debug } from "./debug";
|
14
|
-
import {
|
14
|
+
import { resourceLabel } from "./resourceLabel";
|
15
|
+
import { uniqueBy } from "@latticexyz/common/utils";
|
15
16
|
import { ensureContractsDeployed } from "./ensureContractsDeployed";
|
16
|
-
import {
|
17
|
-
import { ensureWorldFactory } from "./ensureWorldFactory";
|
17
|
+
import { coreModuleBytecode, worldFactoryBytecode, worldFactoryContracts } from "./ensureWorldFactory";
|
18
18
|
|
19
19
|
type DeployOptions<configInput extends ConfigInput> = {
|
20
20
|
client: Client<Transport, Chain | undefined, Account>;
|
21
21
|
config: Config<configInput>;
|
22
|
-
salt?: Hex;
|
23
22
|
worldAddress?: Address;
|
24
|
-
/**
|
25
|
-
* Address of determinstic deployment proxy: https://github.com/Arachnid/deterministic-deployment-proxy
|
26
|
-
* By default, we look for a deployment at 0x4e59b44847b379578588920ca78fbf26c0b4956c and, if not, deploy one.
|
27
|
-
* If the target chain does not support legacy transactions, we deploy the proxy bytecode anyway, but it will
|
28
|
-
* not have a deterministic address.
|
29
|
-
*/
|
30
|
-
deployerAddress?: Hex;
|
31
23
|
};
|
32
24
|
|
33
25
|
/**
|
@@ -39,33 +31,25 @@ type DeployOptions<configInput extends ConfigInput> = {
|
|
39
31
|
export async function deploy<configInput extends ConfigInput>({
|
40
32
|
client,
|
41
33
|
config,
|
42
|
-
salt,
|
43
34
|
worldAddress: existingWorldAddress,
|
44
|
-
deployerAddress: initialDeployerAddress,
|
45
35
|
}: DeployOptions<configInput>): Promise<WorldDeploy> {
|
46
36
|
const tables = Object.values(config.tables) as Table[];
|
37
|
+
const systems = Object.values(config.systems);
|
47
38
|
|
48
|
-
|
49
|
-
|
50
|
-
await ensureWorldFactory(client, deployerAddress);
|
39
|
+
await ensureDeployer(client);
|
51
40
|
|
52
41
|
// deploy all dependent contracts, because system registration, module install, etc. all expect these contracts to be callable.
|
53
42
|
await ensureContractsDeployed({
|
54
43
|
client,
|
55
|
-
deployerAddress,
|
56
44
|
contracts: [
|
57
|
-
...
|
58
|
-
|
59
|
-
|
60
|
-
label: `${library.path}:${library.name} library`,
|
61
|
-
})),
|
62
|
-
...config.systems.map((system) => ({
|
63
|
-
bytecode: system.prepareDeploy(deployerAddress, config.libraries).bytecode,
|
45
|
+
...worldFactoryContracts,
|
46
|
+
...uniqueBy(systems, (system) => getAddress(system.address)).map((system) => ({
|
47
|
+
bytecode: system.bytecode,
|
64
48
|
deployedBytecodeSize: system.deployedBytecodeSize,
|
65
|
-
label: `${
|
49
|
+
label: `${resourceLabel(system)} system`,
|
66
50
|
})),
|
67
|
-
...config.modules.map((mod) => ({
|
68
|
-
bytecode: mod.
|
51
|
+
...uniqueBy(config.modules, (mod) => getAddress(mod.address)).map((mod) => ({
|
52
|
+
bytecode: mod.bytecode,
|
69
53
|
deployedBytecodeSize: mod.deployedBytecodeSize,
|
70
54
|
label: `${mod.name} module`,
|
71
55
|
})),
|
@@ -74,7 +58,7 @@ export async function deploy<configInput extends ConfigInput>({
|
|
74
58
|
|
75
59
|
const worldDeploy = existingWorldAddress
|
76
60
|
? await getWorldDeploy(client, existingWorldAddress)
|
77
|
-
: await deployWorld(client
|
61
|
+
: await deployWorld(client);
|
78
62
|
|
79
63
|
if (!supportedStoreVersions.includes(worldDeploy.storeVersion)) {
|
80
64
|
throw new Error(`Unsupported Store version: ${worldDeploy.storeVersion}`);
|
@@ -83,17 +67,12 @@ export async function deploy<configInput extends ConfigInput>({
|
|
83
67
|
throw new Error(`Unsupported World version: ${worldDeploy.worldVersion}`);
|
84
68
|
}
|
85
69
|
|
86
|
-
|
70
|
+
await assertNamespaceOwner({
|
87
71
|
client,
|
88
72
|
worldDeploy,
|
89
|
-
resourceIds: [...tables.map((table) => table.tableId), ...
|
73
|
+
resourceIds: [...tables.map((table) => table.tableId), ...systems.map((system) => system.systemId)],
|
90
74
|
});
|
91
75
|
|
92
|
-
debug("waiting for all namespace registration transactions to confirm");
|
93
|
-
for (const tx of namespaceTxs) {
|
94
|
-
await waitForTransactionReceipt(client, { hash: tx });
|
95
|
-
}
|
96
|
-
|
97
76
|
const tableTxs = await ensureTables({
|
98
77
|
client,
|
99
78
|
worldDeploy,
|
@@ -101,20 +80,16 @@ export async function deploy<configInput extends ConfigInput>({
|
|
101
80
|
});
|
102
81
|
const systemTxs = await ensureSystems({
|
103
82
|
client,
|
104
|
-
deployerAddress,
|
105
|
-
libraries: config.libraries,
|
106
83
|
worldDeploy,
|
107
|
-
systems
|
84
|
+
systems,
|
108
85
|
});
|
109
86
|
const functionTxs = await ensureFunctions({
|
110
87
|
client,
|
111
88
|
worldDeploy,
|
112
|
-
functions:
|
89
|
+
functions: systems.flatMap((system) => system.functions),
|
113
90
|
});
|
114
91
|
const moduleTxs = await ensureModules({
|
115
92
|
client,
|
116
|
-
deployerAddress,
|
117
|
-
libraries: config.libraries,
|
118
93
|
worldDeploy,
|
119
94
|
modules: config.modules,
|
120
95
|
});
|
@@ -1,18 +1,14 @@
|
|
1
|
-
import { Account, Chain, Client,
|
1
|
+
import { Account, Chain, Client, Log, Transport } from "viem";
|
2
2
|
import { waitForTransactionReceipt } from "viem/actions";
|
3
|
-
import { ensureWorldFactory } from "./ensureWorldFactory";
|
3
|
+
import { ensureWorldFactory, worldFactory } from "./ensureWorldFactory";
|
4
4
|
import WorldFactoryAbi from "@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json" assert { type: "json" };
|
5
5
|
import { writeContract } from "@latticexyz/common";
|
6
6
|
import { debug } from "./debug";
|
7
7
|
import { logsToWorldDeploy } from "./logsToWorldDeploy";
|
8
8
|
import { WorldDeploy } from "./common";
|
9
9
|
|
10
|
-
export async function deployWorld(
|
11
|
-
client
|
12
|
-
deployerAddress: Hex,
|
13
|
-
salt: Hex,
|
14
|
-
): Promise<WorldDeploy> {
|
15
|
-
const worldFactory = await ensureWorldFactory(client, deployerAddress);
|
10
|
+
export async function deployWorld(client: Client<Transport, Chain | undefined, Account>): Promise<WorldDeploy> {
|
11
|
+
await ensureWorldFactory(client);
|
16
12
|
|
17
13
|
debug("deploying world");
|
18
14
|
const tx = await writeContract(client, {
|
@@ -20,7 +16,6 @@ export async function deployWorld(
|
|
20
16
|
address: worldFactory,
|
21
17
|
abi: WorldFactoryAbi,
|
22
18
|
functionName: "deployWorld",
|
23
|
-
args: [salt],
|
24
19
|
});
|
25
20
|
|
26
21
|
debug("waiting for world deploy");
|
@@ -1,5 +1,6 @@
|
|
1
|
-
import { Client, Transport, Chain, Account, concatHex, getCreate2Address, Hex } from "viem";
|
1
|
+
import { Client, Transport, Chain, Account, concatHex, getCreate2Address, Hex, size } from "viem";
|
2
2
|
import { getBytecode } from "viem/actions";
|
3
|
+
import { deployer } from "./ensureDeployer";
|
3
4
|
import { contractSizeLimit, salt } from "./common";
|
4
5
|
import { sendTransaction } from "@latticexyz/common";
|
5
6
|
import { debug } from "./debug";
|
@@ -14,19 +15,13 @@ export type Contract = {
|
|
14
15
|
|
15
16
|
export async function ensureContract({
|
16
17
|
client,
|
17
|
-
deployerAddress,
|
18
18
|
bytecode,
|
19
19
|
deployedBytecodeSize,
|
20
20
|
label = "contract",
|
21
21
|
}: {
|
22
22
|
readonly client: Client<Transport, Chain | undefined, Account>;
|
23
|
-
readonly deployerAddress: Hex;
|
24
23
|
} & Contract): Promise<readonly Hex[]> {
|
25
|
-
|
26
|
-
throw new Error(`Found unlinked public library in ${label} bytecode`);
|
27
|
-
}
|
28
|
-
|
29
|
-
const address = getCreate2Address({ from: deployerAddress, salt, bytecode });
|
24
|
+
const address = getCreate2Address({ from: deployer, salt, bytecode });
|
30
25
|
|
31
26
|
const contractCode = await getBytecode(client, { address, blockTag: "pending" });
|
32
27
|
if (contractCode) {
|
@@ -36,11 +31,11 @@ export async function ensureContract({
|
|
36
31
|
|
37
32
|
if (deployedBytecodeSize > contractSizeLimit) {
|
38
33
|
console.warn(
|
39
|
-
`\nBytecode for ${label} (${deployedBytecodeSize} bytes) is over the contract size limit (${contractSizeLimit} bytes). Run \`forge build --sizes\` for more info.\n
|
34
|
+
`\nBytecode for ${label} (${deployedBytecodeSize} bytes) is over the contract size limit (${contractSizeLimit} bytes). Run \`forge build --sizes\` for more info.\n`
|
40
35
|
);
|
41
36
|
} else if (deployedBytecodeSize > contractSizeLimit * 0.95) {
|
42
37
|
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
|
38
|
+
`\nBytecode for ${label} (${deployedBytecodeSize} bytes) is almost over the contract size limit (${contractSizeLimit} bytes). Run \`forge build --sizes\` for more info.\n`
|
44
39
|
);
|
45
40
|
}
|
46
41
|
|
@@ -50,7 +45,7 @@ export async function ensureContract({
|
|
50
45
|
() =>
|
51
46
|
sendTransaction(client, {
|
52
47
|
chain: client.chain ?? null,
|
53
|
-
to:
|
48
|
+
to: deployer,
|
54
49
|
data: concatHex([salt, bytecode]),
|
55
50
|
}),
|
56
51
|
{
|
@@ -60,7 +55,7 @@ export async function ensureContract({
|
|
60
55
|
debug(`failed to deploy ${label}, retrying in ${delay}ms...`);
|
61
56
|
await wait(delay);
|
62
57
|
},
|
63
|
-
}
|
58
|
+
}
|
64
59
|
),
|
65
60
|
];
|
66
61
|
}
|
@@ -2,23 +2,15 @@ import { Client, Transport, Chain, Account, Hex } from "viem";
|
|
2
2
|
import { waitForTransactionReceipt } from "viem/actions";
|
3
3
|
import { debug } from "./debug";
|
4
4
|
import { Contract, ensureContract } from "./ensureContract";
|
5
|
-
import { uniqueBy } from "@latticexyz/common/utils";
|
6
5
|
|
7
6
|
export async function ensureContractsDeployed({
|
8
7
|
client,
|
9
|
-
deployerAddress,
|
10
8
|
contracts,
|
11
9
|
}: {
|
12
10
|
readonly client: Client<Transport, Chain | undefined, Account>;
|
13
|
-
readonly deployerAddress: Hex;
|
14
11
|
readonly contracts: readonly Contract[];
|
15
12
|
}): Promise<readonly Hex[]> {
|
16
|
-
|
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();
|
13
|
+
const txs = (await Promise.all(contracts.map((contract) => ensureContract({ client, ...contract })))).flat();
|
22
14
|
|
23
15
|
if (txs.length) {
|
24
16
|
debug("waiting for contracts");
|
@@ -1,75 +1,36 @@
|
|
1
|
-
import { Account,
|
2
|
-
import {
|
1
|
+
import { Account, Chain, Client, Transport } from "viem";
|
2
|
+
import { getBytecode, sendRawTransaction, sendTransaction, waitForTransactionReceipt } from "viem/actions";
|
3
3
|
import deployment from "./create2/deployment.json";
|
4
4
|
import { debug } from "./debug";
|
5
5
|
|
6
|
-
const deployer = `0x${deployment.address}` as const;
|
7
|
-
const deployerBytecode = `0x${deployment.bytecode}` as const;
|
6
|
+
export const deployer = `0x${deployment.address}` as const;
|
8
7
|
|
9
|
-
export async function ensureDeployer(client: Client<Transport, Chain | undefined, Account>): Promise<
|
8
|
+
export async function ensureDeployer(client: Client<Transport, Chain | undefined, Account>): Promise<void> {
|
10
9
|
const bytecode = await getBytecode(client, { address: deployer });
|
11
10
|
if (bytecode) {
|
12
|
-
debug("found
|
13
|
-
|
14
|
-
console.warn(
|
15
|
-
`\n ⚠️ Bytecode for deployer at ${deployer} did not match the expected CREATE2 bytecode. You may have unexpected results.\n`,
|
16
|
-
);
|
17
|
-
}
|
18
|
-
return deployer;
|
11
|
+
debug("found create2 deployer at", deployer);
|
12
|
+
return;
|
19
13
|
}
|
20
14
|
|
21
|
-
//
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
const
|
29
|
-
if (
|
30
|
-
|
31
|
-
|
32
|
-
chain: client.chain ?? null,
|
33
|
-
to: `0x${deployment.signerAddress}`,
|
34
|
-
value: gasNeeded,
|
35
|
-
});
|
36
|
-
const gasReceipt = await waitForTransactionReceipt(client, { hash: gasTx });
|
37
|
-
if (gasReceipt.status !== "success") {
|
38
|
-
console.error("failed to send gas to deployer signer", gasReceipt);
|
39
|
-
throw new Error("failed to send gas to deployer signer");
|
40
|
-
}
|
15
|
+
// send gas to signer
|
16
|
+
debug("sending gas for create2 deployer to signer at", deployment.signerAddress);
|
17
|
+
const gasTx = await sendTransaction(client, {
|
18
|
+
chain: client.chain ?? null,
|
19
|
+
to: `0x${deployment.signerAddress}`,
|
20
|
+
value: BigInt(deployment.gasLimit) * BigInt(deployment.gasPrice),
|
21
|
+
});
|
22
|
+
const gasReceipt = await waitForTransactionReceipt(client, { hash: gasTx });
|
23
|
+
if (gasReceipt.status !== "success") {
|
24
|
+
console.error("failed to send gas to deployer signer", gasReceipt);
|
25
|
+
throw new Error("failed to send gas to deployer signer");
|
41
26
|
}
|
42
27
|
|
43
|
-
//
|
44
|
-
debug("deploying
|
45
|
-
const deployTx = await sendRawTransaction(client, { serializedTransaction: `0x${deployment.transaction}` })
|
46
|
-
(error) => {
|
47
|
-
// Do a regular contract create if the presigned transaction doesn't work due to replay protection
|
48
|
-
if (String(error).includes("only replay-protected (EIP-155) transactions allowed over RPC")) {
|
49
|
-
console.warn(
|
50
|
-
// eslint-disable-next-line max-len
|
51
|
-
`\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`,
|
52
|
-
);
|
53
|
-
debug("deploying CREATE2 deployer");
|
54
|
-
return sendTransaction(client, {
|
55
|
-
chain: client.chain ?? null,
|
56
|
-
data: deployerBytecode,
|
57
|
-
});
|
58
|
-
}
|
59
|
-
throw error;
|
60
|
-
},
|
61
|
-
);
|
62
|
-
|
28
|
+
// deploy the deployer
|
29
|
+
debug("deploying create2 deployer at", deployer);
|
30
|
+
const deployTx = await sendRawTransaction(client, { serializedTransaction: `0x${deployment.transaction}` });
|
63
31
|
const deployReceipt = await waitForTransactionReceipt(client, { hash: deployTx });
|
64
|
-
if (!deployReceipt.contractAddress) {
|
65
|
-
throw new Error("Deploy receipt did not have contract address, was the deployer not deployed?");
|
66
|
-
}
|
67
|
-
|
68
32
|
if (deployReceipt.contractAddress !== deployer) {
|
69
|
-
console.
|
70
|
-
|
71
|
-
);
|
33
|
+
console.error("unexpected contract address for deployer", deployReceipt);
|
34
|
+
throw new Error("unexpected contract address for deployer");
|
72
35
|
}
|
73
|
-
|
74
|
-
return deployReceipt.contractAddress;
|
75
36
|
}
|