11import { Client , Transport , Chain , Account , Hex , BaseError } from "viem" ;
2- import { writeContract } from "@latticexyz/common" ;
2+ import { resourceToHex , writeContract } from "@latticexyz/common" ;
33import { Module , WorldDeploy , worldAbi } from "./common" ;
44import { debug } from "./debug" ;
55import { isDefined } from "@latticexyz/common/utils" ;
66import pRetry from "p-retry" ;
77import { LibraryMap } from "./getLibraryMap" ;
88import { ensureContractsDeployed } from "@latticexyz/common/internal" ;
9+ import { encodeSystemCalls } from "@latticexyz/world/internal" ;
10+ import { systemsConfig as worldSystemsConfig } from "@latticexyz/world/mud.config" ;
911
1012export async function ensureModules ( {
1113 client,
@@ -39,17 +41,55 @@ export async function ensureModules({
3941 pRetry (
4042 async ( ) => {
4143 try {
42- // append module's ABI so that we can decode any custom errors
43- const abi = [ ...worldAbi , ...mod . abi ] ;
4444 const moduleAddress = mod . prepareDeploy ( deployerAddress , libraryMap ) . address ;
45- // TODO: replace with batchCall (https://github.com/latticexyz/mud/issues/1645)
46- const params = mod . installAsRoot
47- ? ( { functionName : "installRootModule" , args : [ moduleAddress , mod . installData ] } as const )
48- : ( { functionName : "installModule" , args : [ moduleAddress , mod . installData ] } as const ) ;
45+
46+ // TODO: fix strong types for world ABI etc
47+ // TODO: add return types to get better type safety
48+ const params = ( ( ) => {
49+ if ( mod . installStrategy === "root" ) {
50+ return {
51+ functionName : "installRootModule" ,
52+ args : [ moduleAddress , mod . installData ] ,
53+ } as const ;
54+ }
55+
56+ if ( mod . installStrategy === "delegation" ) {
57+ return {
58+ functionName : "batchCall" ,
59+ args : encodeSystemCalls ( [
60+ {
61+ abi : registrationSystemAbi ,
62+ systemId : registrationSystemId ,
63+ functionName : "registerDelegation" ,
64+ args : [ moduleAddress , unlimitedDelegationControlId , "0x" ] ,
65+ } ,
66+ {
67+ abi : registrationSystemAbi ,
68+ systemId : registrationSystemId ,
69+ functionName : "installModule" ,
70+ args : [ moduleAddress , mod . installData ] ,
71+ } ,
72+ {
73+ abi : registrationSystemAbi ,
74+ systemId : registrationSystemId ,
75+ functionName : "unregisterDelegation" ,
76+ args : [ moduleAddress ] ,
77+ } ,
78+ ] ) ,
79+ } as const ;
80+ }
81+
82+ return {
83+ functionName : "installModule" ,
84+ args : [ moduleAddress , mod . installData ] ,
85+ } as const ;
86+ } ) ( ) ;
87+
4988 return await writeContract ( client , {
5089 chain : client . chain ?? null ,
5190 address : worldDeploy . address ,
52- abi,
91+ // append module's ABI so that we can decode any custom errors
92+ abi : [ ...worldAbi , ...mod . abi ] ,
5393 ...params ,
5494 } ) ;
5595 } catch ( error ) {
@@ -74,3 +114,67 @@ export async function ensureModules({
74114 )
75115 ) . filter ( isDefined ) ;
76116}
117+
118+ // TODO: export from world
119+ const unlimitedDelegationControlId = resourceToHex ( { type : "system" , namespace : "" , name : "unlimited" } ) ;
120+
121+ const registrationSystemId = worldSystemsConfig . systems . RegistrationSystem . systemId ;
122+
123+ // world/src/modules/init/RegistrationSystem.sol
124+ // TODO: import from world once we fix strongly typed JSON imports
125+ const registrationSystemAbi = [
126+ {
127+ type : "function" ,
128+ name : "installModule" ,
129+ inputs : [
130+ {
131+ name : "module" ,
132+ type : "address" ,
133+ internalType : "contract IModule" ,
134+ } ,
135+ {
136+ name : "encodedArgs" ,
137+ type : "bytes" ,
138+ internalType : "bytes" ,
139+ } ,
140+ ] ,
141+ outputs : [ ] ,
142+ stateMutability : "nonpayable" ,
143+ } ,
144+ {
145+ type : "function" ,
146+ name : "registerDelegation" ,
147+ inputs : [
148+ {
149+ name : "delegatee" ,
150+ type : "address" ,
151+ internalType : "address" ,
152+ } ,
153+ {
154+ name : "delegationControlId" ,
155+ type : "bytes32" ,
156+ internalType : "ResourceId" ,
157+ } ,
158+ {
159+ name : "initCallData" ,
160+ type : "bytes" ,
161+ internalType : "bytes" ,
162+ } ,
163+ ] ,
164+ outputs : [ ] ,
165+ stateMutability : "nonpayable" ,
166+ } ,
167+ {
168+ type : "function" ,
169+ name : "unregisterDelegation" ,
170+ inputs : [
171+ {
172+ name : "delegatee" ,
173+ type : "address" ,
174+ internalType : "address" ,
175+ } ,
176+ ] ,
177+ outputs : [ ] ,
178+ stateMutability : "nonpayable" ,
179+ } ,
180+ ] as const ;
0 commit comments