Skip to content

Commit

Permalink
feat: abigen
Browse files Browse the repository at this point in the history
  • Loading branch information
yonadaaa committed May 21, 2024
1 parent f2b425e commit 0032e7b
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import type { CommandModule, InferredOptionTypes } from "yargs";
import { Hex, createWalletClient, http } from "viem";
import { getSystems } from "../deploy/getSystems";
import { getWorldDeploy } from "../deploy/getWorldDeploy";
import { interfacegen } from "@latticexyz/world/node";
import { abigen } from "@latticexyz/world/node";
import { getRpcUrl } from "@latticexyz/common/foundry";

const interfacegenOptions = {
const abigenOptions = {
worldAddress: { type: "string", required: true, desc: "Verify an existing World at the given address" },
profile: { type: "string", desc: "The foundry profile to use" },
rpc: {
Expand All @@ -14,24 +14,24 @@ const interfacegenOptions = {
},
} as const;

type Options = InferredOptionTypes<typeof interfacegenOptions>;
type Options = InferredOptionTypes<typeof abigenOptions>;

const commandModule: CommandModule<Options, Options> = {
command: "interfacegen",
command: "abigen",

describe: "Autogenerate interfaces for Systems and World based on RPC",

builder(yargs) {
return yargs.options(interfacegenOptions);
return yargs.options(abigenOptions);
},

async handler(args) {
await interfacegenHandler(args);
await abigenHandler(args);
process.exit(0);
},
};

export async function interfacegenHandler(opts: Options) {
export async function abigenHandler(opts: Options) {
const worldAddress = opts.worldAddress as Hex;
const profile = opts.profile ?? process.env.FOUNDRY_PROFILE;
const rpc = opts.rpc ?? (await getRpcUrl(profile));
Expand All @@ -45,7 +45,7 @@ export async function interfacegenHandler(opts: Options) {
const systems = await getSystems({ client, worldDeploy });

// generate new interfaces
await interfacegen(systems);
await abigen(systems);
}

export default commandModule;
4 changes: 2 additions & 2 deletions packages/cli/src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import test from "./test";
import trace from "./trace";
import devContracts from "./dev-contracts";
import verify from "./verify";
import interfacegen from "./interfacegen";
import abigen from "./abigen";

// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options
export const commands: CommandModule<any, any>[] = [
Expand All @@ -31,5 +31,5 @@ export const commands: CommandModule<any, any>[] = [
devContracts,
abiTs,
verify,
interfacegen,
abigen,
];
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { renderSystemInterface } from "./renderSystemInterface";
import { abigenInner } from "./abigenInner";
import { Abi, Address, Hex } from "viem";

type DeterministicContract = {
Expand Down Expand Up @@ -47,39 +47,6 @@ type DeployedSystem = Omit<System, "abi" | "prepareDeploy" | "deployedBytecodeSi
address: Address;
};

export async function interfacegen(systems: readonly DeployedSystem[]) {
for (const system of systems) {
const functions = system.functions.map((func) => {
const match = func.systemFunctionSignature.match(/^([a-zA-Z_]\w*)\((.*)\)$/);
if (!match) {
throw new Error("Invalid signature");
}

const name = match[1];
const argsString = match[2];

const parameters = argsString
.split(",")
.filter((arg) => arg.trim().length > 0)
.map((parameter, i) => (parameter[0] === "(" ? `${name}${i}Struct` : parameter));

return {
name,
parameters,
stateMutability: "",
returnParameters: [],
};
});

const systemInterfaceName = `I${system.name}`;
const output = renderSystemInterface({
name: systemInterfaceName,
functionPrefix: "",
functions,
errors: [],
imports: [],
});

console.log(output);
}
export function abigen(systems: readonly DeployedSystem[]) {
return systems.map((system) => abigenInner(system));
}
99 changes: 99 additions & 0 deletions packages/world/ts/node/render-solidity/abigenInner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Abi, AbiItem, Address, Hex } from "viem";

type DeterministicContract = {
readonly prepareDeploy: (
deployer: Address,
libraries: readonly Library[],
) => {
readonly address: Address;
readonly bytecode: Hex;
};
readonly deployedBytecodeSize: number;
readonly abi: Abi;
};

type Library = DeterministicContract & {
/**
* Path to library source file, e.g. `src/libraries/SomeLib.sol`
*/
path: string;
/**
* Library name, e.g. `SomeLib`
*/
name: string;
};

// map over each and decode signature
type WorldFunction = {
readonly signature: string;
readonly selector: Hex;
readonly systemId: Hex;
readonly systemFunctionSignature: string;
readonly systemFunctionSelector: Hex;
};

type System = DeterministicContract & {
readonly namespace: string;
readonly name: string;
readonly systemId: Hex;
readonly allowAll: boolean;
readonly allowedAddresses: readonly Hex[];
readonly allowedSystemIds: readonly Hex[];
readonly functions: readonly WorldFunction[];
};

type DeployedSystem = Omit<System, "abi" | "prepareDeploy" | "deployedBytecodeSize" | "allowedSystemIds"> & {
address: Address;
};

export function abigenInner(system: DeployedSystem): Abi {
const abi = system.functions.map((func) => {
const match = func.systemFunctionSignature.match(/^([a-zA-Z_]\w*)\((.*)\)$/);
if (!match) {
throw new Error("Invalid signature");
}

const name = match[1];
const argsString = match[2];

const args = argsString.split(",");

const item: AbiItem = {
type: "function",
name,
inputs: args.map((type, i) => {
const isTuple = type[0] === "(";
if (!isTuple) {
return {
name: "",
type,
internalType: type,
};
} else {
return {
name: "",
type: "tuple[]",
internalType: `${name}${i}Struct[]`,
components: type
.replace("(", "")
.replace(")", "")
.split(",")
.map((member, j) => ({
name: `value${j}`,
type: member,
internalType: member,
})),
};
}
}),
outputs: [],
stateMutability: "nonpayable",
};

console.log(argsString, item);

return item;
});

return abi;
}
2 changes: 1 addition & 1 deletion packages/world/ts/node/render-solidity/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ export * from "./renderSystemInterface";
export * from "./renderWorldInterface";
export * from "./types";
export * from "./worldgen";
export * from "./interfacegen";
export * from "./abigen";

0 comments on commit 0032e7b

Please sign in to comment.