Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/shy-poets-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@latticexyz/world": patch
---

Updated `callFrom` action to automatically translate `batchCall` to `batchCallFrom`.
Also fixed `encodeSystemCallFrom` and `encodeSystemCallsFrom` to return the right format for use with `batchCall` and `batchCallFrom` respectively.
35 changes: 25 additions & 10 deletions packages/world/ts/actions/callFrom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import {
type Account,
type Hex,
type WalletActions,
type Client,
type PublicActions,
type WriteContractParameters,
type EncodeFunctionDataParameters,
Client,
PublicActions,
} from "viem";
import { getAction, encodeFunctionData } from "viem/utils";
import { readContract, writeContract as viem_writeContract } from "viem/actions";
Expand All @@ -21,6 +22,7 @@ import {
encodeKey,
} from "@latticexyz/protocol-parser/internal";
import worldConfig from "../../mud.config";
import { worldCallAbi } from "../worldCallAbi";

type CallFromParameters = {
worldAddress: Hex;
Expand All @@ -46,7 +48,6 @@ export function callFrom(
client: Client<Transport, chain, account>,
) => Pick<WalletActions<chain, account>, "writeContract"> {
return (client) => ({
// Applies to: `client.writeContract`, `getContract(client, ...).write`
async writeContract(writeArgs) {
const _writeContract = getAction(client, viem_writeContract, "writeContract");

Expand All @@ -55,11 +56,28 @@ export function callFrom(
writeArgs.address !== params.worldAddress ||
writeArgs.functionName === "call" ||
writeArgs.functionName === "callFrom" ||
writeArgs.functionName === "batchCallFrom" ||
writeArgs.functionName === "callWithSignature"
) {
return _writeContract(writeArgs);
}

// Wrap system calls from `batchCall` with delegator for a `batchCallFrom`
// TODO: remove this specific workaround once https://github.com/latticexyz/mud/pull/3506 lands
if (writeArgs.functionName === "batchCall") {
const batchCallArgs = writeArgs as unknown as WriteContractParameters<worldCallAbi, "batchCall">;
const [systemCalls] = batchCallArgs.args;
if (!systemCalls.length) {
throw new Error("`batchCall` should have at least one system call.");
}

return _writeContract({
...batchCallArgs,
functionName: "batchCallFrom",
args: [systemCalls.map((systemCall) => ({ from: params.delegatorAddress, ...systemCall }))],
});
}

// Encode the World's calldata (which includes the World's function selector).
const worldCalldata = encodeFunctionData({
abi: writeArgs.abi,
Expand All @@ -81,15 +99,12 @@ export function callFrom(
// Use `readHex` instead of `slice` to prevent out-of-bounds errors with calldata that has no args.
const systemCalldata = concat([systemFunctionSelector, readHex(worldCalldata, 4)]);

// Construct args for `callFrom`.
const callFromArgs: typeof writeArgs = {
...writeArgs,
// Call `writeContract` with the new args.
return _writeContract({
...(writeArgs as unknown as WriteContractParameters<worldCallAbi, "callFrom">),
functionName: "callFrom",
args: [params.delegatorAddress, systemId, systemCalldata],
};

// Call `writeContract` with the new args.
return _writeContract(callFromArgs);
});
},
});
}
Expand Down
2 changes: 1 addition & 1 deletion packages/world/ts/encodeSystemCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ export function encodeSystemCall<abi extends Abi, functionName extends ContractF
abi,
functionName,
args,
} as unknown as EncodeFunctionDataParameters<abi, functionName>),
} as EncodeFunctionDataParameters<abi, functionName>),
];
}
2 changes: 1 addition & 1 deletion packages/world/ts/encodeSystemCallFrom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ export function encodeSystemCallFrom<abi extends Abi, functionName extends Contr
abi,
functionName,
args,
} as unknown as EncodeFunctionDataParameters<abi, functionName>),
} as EncodeFunctionDataParameters<abi, functionName>),
];
}
12 changes: 8 additions & 4 deletions packages/world/ts/encodeSystemCalls.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ describe("SystemCalls", () => {
).toMatchInlineSnapshot(`
[
[
"0x7379000000000000000000000000000000000000000000000000000000000000",
"0x40554c3a746200000000000000000000000000006d795461626c65000000000000000000000000000000000000000000943728592c20aed37a35c15235466f7a7cd00bd0",
{
"callData": "0x40554c3a746200000000000000000000000000006d795461626c65000000000000000000000000000000000000000000943728592c20aed37a35c15235466f7a7cd00bd0",
"systemId": "0x7379000000000000000000000000000000000000000000000000000000000000",
},
],
]
`);
Expand All @@ -47,8 +49,10 @@ describe("SystemCalls", () => {
).toMatchInlineSnapshot(`
[
[
"0x7379000000000000000000000000000000000000000000000000000000000000",
"0x0ba51f49746200000000000000000000000000006d795461626c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000046b6579310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046b6579310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066669656c6431000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066669656c64320000000000000000000000000000000000000000000000000000",
{
"callData": "0x0ba51f49746200000000000000000000000000006d795461626c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000046b6579310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046b6579310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000066669656c6431000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066669656c64320000000000000000000000000000000000000000000000000000",
"systemId": "0x7379000000000000000000000000000000000000000000000000000000000000",
},
],
]
`);
Expand Down
17 changes: 13 additions & 4 deletions packages/world/ts/encodeSystemCalls.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { Abi, type ContractFunctionName } from "viem";
import { SystemCall, encodeSystemCall } from "./encodeSystemCall";
import { Abi, EncodeFunctionDataParameters, encodeFunctionData, type ContractFunctionName } from "viem";
import { SystemCall } from "./encodeSystemCall";
import type { AbiParametersToPrimitiveTypes, ExtractAbiFunction } from "abitype";
import { worldCallAbi } from "./worldCallAbi";

/** Encode system calls to be passed as arguments into `World.batchCall` */
export function encodeSystemCalls<abi extends Abi, functionName extends ContractFunctionName<abi>>(
abi: abi,
systemCalls: readonly Omit<SystemCall<abi, functionName>, "abi">[],
): AbiParametersToPrimitiveTypes<ExtractAbiFunction<worldCallAbi, "call">["inputs"]>[] {
return systemCalls.map((systemCall) => encodeSystemCall({ ...systemCall, abi } as SystemCall<abi, functionName>));
): AbiParametersToPrimitiveTypes<ExtractAbiFunction<worldCallAbi, "batchCall">["inputs"]> {
return [
systemCalls.map(({ systemId, functionName, args }) => ({
systemId,
callData: encodeFunctionData<abi, functionName>({
abi,
functionName,
args,
} as EncodeFunctionDataParameters<abi, functionName>),
})),
];
}
20 changes: 14 additions & 6 deletions packages/world/ts/encodeSystemCallsFrom.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Abi, Address, type ContractFunctionName } from "viem";
import { SystemCallFrom, encodeSystemCallFrom } from "./encodeSystemCallFrom";
import { Abi, Address, EncodeFunctionDataParameters, encodeFunctionData, type ContractFunctionName } from "viem";
import { SystemCallFrom } from "./encodeSystemCallFrom";
import type { AbiParametersToPrimitiveTypes, ExtractAbiFunction } from "abitype";
import { worldCallAbi } from "./worldCallAbi";

Expand All @@ -8,8 +8,16 @@ export function encodeSystemCallsFrom<abi extends Abi, functionName extends Cont
abi: abi,
from: Address,
systemCalls: readonly Omit<SystemCallFrom<abi, functionName>, "abi" | "from">[],
): AbiParametersToPrimitiveTypes<ExtractAbiFunction<worldCallAbi, "callFrom">["inputs"]>[] {
return systemCalls.map((systemCall) =>
encodeSystemCallFrom({ ...systemCall, abi, from } as SystemCallFrom<abi, functionName>),
);
): AbiParametersToPrimitiveTypes<ExtractAbiFunction<worldCallAbi, "batchCallFrom">["inputs"]> {
return [
systemCalls.map(({ systemId, functionName, args }) => ({
from,
systemId,
callData: encodeFunctionData<abi, functionName>({
abi,
functionName,
args,
} as EncodeFunctionDataParameters<abi, functionName>),
})),
];
}
101 changes: 101 additions & 0 deletions packages/world/ts/worldCallAbi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,73 @@
// generating full TS files rather than DTS

export const worldCallAbi = [
{
type: "function",
name: "batchCall",
inputs: [
{
name: "systemCalls",
type: "tuple[]",
internalType: "struct SystemCallData[]",
components: [
{
name: "systemId",
type: "bytes32",
internalType: "ResourceId",
},
{
name: "callData",
type: "bytes",
internalType: "bytes",
},
],
},
],
outputs: [
{
name: "returnDatas",
type: "bytes[]",
internalType: "bytes[]",
},
],
stateMutability: "nonpayable",
},
{
type: "function",
name: "batchCallFrom",
inputs: [
{
name: "systemCalls",
type: "tuple[]",
internalType: "struct SystemCallFromData[]",
components: [
{
name: "from",
type: "address",
internalType: "address",
},
{
name: "systemId",
type: "bytes32",
internalType: "ResourceId",
},
{
name: "callData",
type: "bytes",
internalType: "bytes",
},
],
},
],
outputs: [
{
name: "returnDatas",
type: "bytes[]",
internalType: "bytes[]",
},
],
stateMutability: "nonpayable",
},
{
type: "function",
name: "call",
Expand Down Expand Up @@ -55,6 +122,40 @@ export const worldCallAbi = [
],
stateMutability: "payable",
},
{
type: "function",
name: "callWithSignature",
inputs: [
{
name: "signer",
type: "address",
internalType: "address",
},
{
name: "systemId",
type: "bytes32",
internalType: "ResourceId",
},
{
name: "callData",
type: "bytes",
internalType: "bytes",
},
{
name: "signature",
type: "bytes",
internalType: "bytes",
},
],
outputs: [
{
name: "",
type: "bytes",
internalType: "bytes",
},
],
stateMutability: "payable",
},
] as const;

export type worldCallAbi = typeof worldCallAbi;
Loading