Skip to content

Commit

Permalink
Add support for using libraries from root systems
Browse files Browse the repository at this point in the history
  • Loading branch information
vdrg committed Nov 22, 2024
1 parent 05ea70f commit 18987ea
Show file tree
Hide file tree
Showing 12 changed files with 620 additions and 35 deletions.
101 changes: 69 additions & 32 deletions packages/world/ts/node/render-solidity/renderSystemLibrary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function renderSystemLibrary(options: RenderSystemLibraryOptions) {
systemLabel,
resourceId,
functions,
errors,
errors: systemErrors,
worldImportPath,
storeImportPath,
} = options;
Expand All @@ -31,6 +31,10 @@ export function renderSystemLibrary(options: RenderSystemLibraryOptions) {
symbol: "IWorldCall",
path: `${worldImportPath}/IWorldKernel.sol`,
},
{
symbol: "SystemCall",
path: `${worldImportPath}/SystemCall.sol`,
},
{
symbol: "Systems",
path: `${worldImportPath}/codegen/tables/Systems.sol`,
Expand All @@ -45,6 +49,8 @@ export function renderSystemLibrary(options: RenderSystemLibraryOptions) {
},
];

const errors = [...systemErrors];

const camelCaseSystemLabel = systemLabel.charAt(0).toLowerCase() + systemLabel.slice(1);
const userTypeName = `${systemLabel}Type`;

Expand All @@ -62,6 +68,11 @@ export function renderSystemLibrary(options: RenderSystemLibraryOptions) {
address from;
}
struct RootCallWrapper {
ResourceId systemId;
address from;
}
/**
* @title ${libraryName}
* @author MUD (https://mud.dev) by Lattice (https://lattice.xyz)
Expand All @@ -74,10 +85,16 @@ export function renderSystemLibrary(options: RenderSystemLibraryOptions) {
${renderCallWrapperFunctions(functions, systemLabel)}
${renderRootCallWrapperFunctions(functions, systemLabel)}
function callFrom(${userTypeName} self, address from) internal pure returns (CallWrapper memory) {
return CallWrapper(self.toResourceId(), from);
}
function asRoot(${userTypeName} self) internal pure returns (RootCallWrapper memory) {
return RootCallWrapper(self.toResourceId(), address(0));
}
function toResourceId(${userTypeName} self) internal pure returns (ResourceId) {
return ResourceId.wrap(${userTypeName}.unwrap(self));
}
Expand All @@ -97,6 +114,7 @@ export function renderSystemLibrary(options: RenderSystemLibraryOptions) {
using ${libraryName} for ${userTypeName} global;
using ${libraryName} for CallWrapper global;
using ${libraryName} for RootCallWrapper global;
`;
}

Expand Down Expand Up @@ -125,71 +143,90 @@ function renderUserTypeFunction(contractFunction: ContractInterfaceFunction, use
${renderReturnParameters(returnParameters)}
`;

const functionBody = renderUserTypeFunctionBody(contractFunction);
const callWrapperArguments = parameters.map((param) => param.split(" ").slice(-1)[0]).join(", ");

return `
${functionSignature} {
${functionBody}
return CallWrapper(self.toResourceId(), address(0)).${name}(${callWrapperArguments});
}
`;
}

function renderUserTypeFunctionBody(contractFunction: ContractInterfaceFunction) {
const { name, parameters } = contractFunction;

const callWrapperArguments = parameters.map((param) => param.split(" ").slice(-1)[0]).join(", ");
return `
return CallWrapper(self.toResourceId(), address(0)).${name}(${callWrapperArguments});
`;
}

function renderCallWrapperFunctions(functions: ContractInterfaceFunction[], systemLabel: string) {
return renderList(functions, (contractFunction) => renderCallWrapperFunction(contractFunction, systemLabel));
}

function renderCallWrapperFunction(contractFunction: ContractInterfaceFunction, systemLabel: string) {
const { name, parameters, stateMutability, returnParameters } = contractFunction;

const allParameters = [`CallWrapper memory self`, ...parameters];
const functionArguments = [`CallWrapper memory self`, ...parameters];

const functionSignature = `
function ${name}(
${renderArguments(allParameters)}
${renderArguments(functionArguments)}
) internal
${stateMutability === "pure" ? "view" : stateMutability}
${renderReturnParameters(returnParameters)}
`;

const functionBody = renderCallWrapperFunctionBody(contractFunction, systemLabel);
const encodedSystemCall = renderEncodeSystemCall(systemLabel, name, parameters);

return `
${functionSignature} {
${functionBody}
}
`;
if (stateMutability === "") {
return `
${functionSignature} {
bytes memory systemCall = ${encodedSystemCall};
bytes memory result = self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall);
${renderAbiDecode(returnParameters)}
}
`;
} else {
return `
${functionSignature} {
bytes memory systemCall = ${encodedSystemCall};
bytes memory worldCall = self.from == address(0)
? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall))
: abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall));
(bool success, bytes memory returnData) = address(_world()).staticcall(worldCall);
if (!success) revertWithBytes(returnData);
bytes memory result = abi.decode(returnData, (bytes));
${renderAbiDecode(returnParameters)}
}
`;
}
}

function renderCallWrapperFunctionBody(contractFunction: ContractInterfaceFunction, systemLabel: string) {
function renderRootCallWrapperFunctions(functions: ContractInterfaceFunction[], systemLabel: string) {
return renderList(functions, (contractFunction) => renderRootCallWrapperFunction(contractFunction, systemLabel));
}

function renderRootCallWrapperFunction(contractFunction: ContractInterfaceFunction, systemLabel: string) {
const { name, parameters, stateMutability, returnParameters } = contractFunction;

const functionArguments = [`RootCallWrapper memory ${stateMutability === "" ? "self" : ""}`, ...parameters];

const functionSignature = `
function ${name}(
${renderArguments(functionArguments)}
) internal
${stateMutability === "view" ? "pure" : stateMutability}
${renderReturnParameters(returnParameters)}
`;

const encodedSystemCall = renderEncodeSystemCall(systemLabel, name, parameters);

if (stateMutability === "") {
return `
bytes memory systemCall = ${encodedSystemCall};
bytes memory result = self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall);
${renderAbiDecode(returnParameters)}
${functionSignature} {
bytes memory systemCall = ${encodedSystemCall};
bytes memory result = SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value);
${renderAbiDecode(returnParameters)}
}
`;
} else {
return `
bytes memory systemCall = ${encodedSystemCall};
bytes memory worldCall = self.from == address(0)
? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall))
: abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall));
(bool success, bytes memory returnData) = address(_world()).staticcall(worldCall);
if (!success) revertWithBytes(returnData);
bytes memory result = abi.decode(returnData, (bytes));
${renderAbiDecode(returnParameters)}
${functionSignature} {
revert("Static calls not implemented for root systems");
}
`;
}
}
Expand Down
4 changes: 3 additions & 1 deletion test/system-libraries/mud.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ export default defineWorld({
},
},
},

b: {},
root: {
namespace: "",
},
},
codegen: {
generateSystemLibraries: true,
Expand Down
13 changes: 13 additions & 0 deletions test/system-libraries/src/codegen/world/IRootSystem.sol

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion test/system-libraries/src/codegen/world/IWorld.sol

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions test/system-libraries/src/namespaces/root/RootSystem.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.28;

import { System } from "@latticexyz/world/src/System.sol";
import { aSystem } from "../a/codegen/libraries/ASystemLib.sol";

contract RootSystem is System {
function setValueInA(uint256 value) external {
aSystem.asRoot().setValue(value);
}
}
7 changes: 7 additions & 0 deletions test/system-libraries/src/namespaces/root/codegen/index.sol

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 18987ea

Please sign in to comment.