Conversation
|
Advantage of using EIP-712 is that we can reuse some of existing alloy structures for it and it's also pretty much human readable and compact. However, it has some limitations
/// @param number forge-json: hex
/// @param inner forge-json: flatten
struct SomeStruct {
uint256 number;
AnotherStruct inner;
}However, all of this can be added in the future by just allowing more formats for |
|
Added cheatcode for serialization and Example output for project with 1 struct. In case of multiple structs and duplicating names, those are getting resolved correctly pragma solidity >=0.6.2 <0.9.0;
pragma experimental ABIEncoderV2;
import {Vm} from "forge-std/Vm.sol";
import {SomeStruct} from "src/SomeStruct.sol";
library JsonBindings {
Vm constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
string constant schema_SomeStruct = "SomeStruct(uint256 a,uint256 b)";
function serialize(SomeStruct memory value) internal pure returns (string memory) {
return vm.serializeJsonType(schema_SomeStruct, abi.encode(value));
}
function deserializeSomeStruct(string memory json) public pure returns (SomeStruct memory) {
return abi.decode(vm.parseJsonType(json, schema_SomeStruct), (SomeStruct));
}
function deserializeSomeStruct(string memory json, string memory path) public pure returns (SomeStruct memory) {
return abi.decode(vm.parseJsonType(json, path, schema_SomeStruct), (SomeStruct));
}
function deserializeSomeStructArray(string memory json, string memory path) public pure returns (SomeStruct[] memory) {
return abi.decode(vm.parseJsonTypeArray(json, path, schema_SomeStruct), (SomeStruct[]));
}
}
bindings are written to import "../utils/JsonBindings.sol";
import "forge-std/Test.sol";
struct SomeStruct {
uint256 a;
uint256 b;
}
contract SomeStructJsonTest is Test {
using JsonBindings for *;
function test() public {
SomeStruct memory s = SomeStruct(1, 2);
string memory json = s.serialize();
SomeStruct memory s2 = json.deserializeSomeStruct();
assertEq(keccak256(abi.encode(s)), keccak256(abi.encode(s2)));
}
}The command itself is pretty straightforward - just walk the AST and write the methods, the only non-trivial part is preprocessing which we need to obtain valid AST from solc even when bindings are outdated and would cause compiler to fail normally. We rely on solang parser for this. I think it might make sense to add more configuration for this, maybe even a config section. Currently for large codebases bindings file is ending up pretty large and there are also some issues with multi-version projects which I've addressed by only generating bindings for a single compiler input |
mattsse
left a comment
There was a problem hiding this comment.
nice, this is pretty cool!
still need to take a closer look but I believe this should work, and the helper commands should make this convenient to use.
if possible, we def want some forgetest! for this as well
mattsse
left a comment
There was a problem hiding this comment.
nice work!
only have a few questions/suggestions
|
Added config section: |
Motivation
closes #8326
Solution
Adds
parseJsonTypeset of cheatcodes which accepts stringified Solidity type as guidance for the parser, allowing to express complex types without the need to resort to parsing of them in multipleparseJson*calls.Example usage of such cheatcode:
For simpler creation of type strings for structs added
forge eip712 <path>command which creates EIP-712encodeTypestring for all structs in the given file.Example output:
This might also be useful for #4818 later
Will be working on serialization next