Implement typechecked abi.encodeCall()

This commit is contained in:
Marenz
2021-12-16 17:35:58 +01:00
parent 6363ff31db
commit 7a96953e78
21 changed files with 538 additions and 26 deletions
@@ -0,0 +1,51 @@
pragma abicoder v2;
contract C {
type UnsignedNumber is uint256;
enum Enum { First, Second, Third }
struct Struct {
UnsignedNumber[] dynamicArray;
uint256 justAnInt;
string name;
bytes someBytes;
Enum theEnum;
}
function callMeMaybe(Struct calldata _data, int256 _intVal, string memory _nameVal) external pure {
assert(_data.dynamicArray.length == 3);
assert(UnsignedNumber.unwrap(_data.dynamicArray[0]) == 0);
assert(UnsignedNumber.unwrap(_data.dynamicArray[1]) == 1);
assert(UnsignedNumber.unwrap(_data.dynamicArray[2]) == 2);
assert(_data.justAnInt == 6);
assert(keccak256(bytes(_data.name)) == keccak256("StructName"));
assert(keccak256(_data.someBytes) == keccak256(bytes("1234")));
assert(_data.theEnum == Enum.Second);
assert(_intVal == 5);
assert(keccak256(bytes(_nameVal)) == keccak256("TestName"));
}
function callExternal() public returns (bool) {
Struct memory structToSend;
structToSend.dynamicArray = new UnsignedNumber[](3);
structToSend.dynamicArray[0] = UnsignedNumber.wrap(0);
structToSend.dynamicArray[1] = UnsignedNumber.wrap(1);
structToSend.dynamicArray[2] = UnsignedNumber.wrap(2);
structToSend.justAnInt = 6;
structToSend.name = "StructName";
structToSend.someBytes = bytes("1234");
structToSend.theEnum = Enum.Second;
(bool success,) = address(this).call(abi.encodeCall(this.callMeMaybe, (
structToSend,
5,
"TestName"
)));
return success;
}
}
// ====
// compileViaYul: also
// ----
// callExternal() -> true
@@ -0,0 +1,63 @@
pragma abicoder v2;
contract C {
bool sideEffectRan = false;
function(uint256, string memory) external fPointer;
function fExternal(uint256 p, string memory t) external {}
string xstor;
function getExternalFunctionPointer() public returns (function(uint256, string memory) external) {
sideEffectRan = true;
return this.fExternal;
}
function fSignatureFromLiteral() public pure returns (bytes memory) {
return abi.encodeWithSignature("fExternal(uint256,string)", 1, "123");
}
function fSignatureFromLiteralCall() public view returns (bytes memory) {
return abi.encodeCall(this.fExternal, (1, "123"));
}
function fSignatureFromMemory() public pure returns (bytes memory) {
string memory x = "fExternal(uint256,string)";
return abi.encodeWithSignature(x, 1, "123");
}
function fSignatureFromMemoryCall() public view returns (bytes memory) {
return abi.encodeCall(this.fExternal, (1,"123"));
}
function fSignatureFromMemorys() public returns (bytes memory) {
xstor = "fExternal(uint256,string)";
return abi.encodeWithSignature(xstor, 1, "123");
}
function fPointerCall() public returns(bytes memory) {
fPointer = this.fExternal;
return abi.encodeCall(fPointer, (1, "123"));
}
function fLocalPointerCall() public returns(bytes memory) {
function(uint256, string memory) external localFunctionPointer = this.fExternal;
return abi.encodeCall(localFunctionPointer, (1, "123"));
}
function fReturnedFunctionPointer() public returns (bytes memory) {
return abi.encodeCall(getExternalFunctionPointer(), (1, "123"));
}
function assertConsistentSelectors() public {
assert(keccak256(fSignatureFromLiteral()) == keccak256(fSignatureFromLiteralCall()));
assert(keccak256(fSignatureFromMemory()) == keccak256(fSignatureFromMemoryCall()));
assert(keccak256(fSignatureFromMemoryCall()) == keccak256(fSignatureFromMemorys()));
assert(keccak256(fPointerCall()) == keccak256(fSignatureFromLiteral()));
assert(keccak256(fLocalPointerCall()) == keccak256(fSignatureFromLiteral()));
assert(keccak256(fReturnedFunctionPointer()) == keccak256(fSignatureFromLiteral()));
}
}
// ====
// compileViaYul: also
// ----
// assertConsistentSelectors() ->
// fSignatureFromLiteral() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fSignatureFromLiteralCall() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fSignatureFromMemory() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fSignatureFromMemoryCall() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fSignatureFromMemorys() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fPointerCall() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fLocalPointerCall() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fReturnedFunctionPointer() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
@@ -0,0 +1,28 @@
pragma abicoder v2;
contract D {
function something() external pure {}
}
contract C {
function something() external pure {}
function test() external returns (bytes4) {
function() external[2] memory x;
x[0] = this.something;
x[1] = (new D()).something;
function() external f = x[1];
bytes memory a = abi.encodeCall(x[0], ());
bytes memory b = abi.encodeCall(x[1], ());
bytes memory c = abi.encodeCall(f, ());
assert(a.length == 4 && b.length == 4 && c.length == 4);
assert(bytes4(a) == bytes4(b));
assert(bytes4(a) == bytes4(c));
assert(bytes4(a) == f.selector);
return bytes4(a);
}
}
// ====
// compileViaYul: also
// ----
// test() -> 0xa7a0d53700000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,48 @@
pragma abicoder v2;
contract C {
bool sideEffectRan = false;
function fNoArgs() external {}
function fArray(uint[] memory x) external {}
function fUint(uint x, uint y) external returns (uint a, uint b) {}
function fSignatureFromLiteralNoArgs() public pure returns (bytes memory) {
return abi.encodeWithSignature("fNoArgs()");
}
function fPointerNoArgs() public view returns (bytes memory) {
return abi.encodeCall(this.fNoArgs, ());
}
function fSignatureFromLiteralArray() public pure returns (bytes memory) {
uint[] memory x;
return abi.encodeWithSignature("fArray(uint256[])", x);
}
function fPointerArray() public view returns (bytes memory) {
uint[] memory x;
return abi.encodeCall(this.fArray, x);
}
function fSignatureFromLiteralUint() public pure returns (bytes memory) {
return abi.encodeWithSignature("fUint(uint256,uint256)", 12, 13);
}
function fPointerUint() public view returns (bytes memory) {
return abi.encodeCall(this.fUint, (12,13));
}
function assertConsistentSelectors() public view {
assert(keccak256(fSignatureFromLiteralNoArgs()) == keccak256(fPointerNoArgs()));
assert(keccak256(fSignatureFromLiteralArray()) == keccak256(fPointerArray()));
assert(keccak256(fSignatureFromLiteralUint()) == keccak256(fPointerUint()));
}
}
// ====
// compileViaYul: also
// ----
// assertConsistentSelectors() ->
// fSignatureFromLiteralNoArgs() -> 0x20, 0x04, 12200448252684243758085936796735499259670113115893304444050964496075123064832
// fPointerNoArgs() -> 0x20, 4, 12200448252684243758085936796735499259670113115893304444050964496075123064832
// fSignatureFromLiteralArray() -> 0x20, 0x44, 4612216551196396486909126966576324289294165774260092952932219511233230929920, 862718293348820473429344482784628181556388621521298319395315527974912, 0
// fPointerArray() -> 0x20, 0x44, 4612216551196396486909126966576324289294165774260092952932219511233230929920, 862718293348820473429344482784628181556388621521298319395315527974912, 0
// fPointerUint() -> 0x20, 0x44, 30372892641494467502622535050667754357470287521126424526399600764424271429632, 323519360005807677536004181044235568083645733070486869773243322990592, 350479306672958317330671196131255198757282877493027442254346933239808
// fSignatureFromLiteralUint() -> 0x20, 0x44, 30372892641494467502622535050667754357470287521126424526399600764424271429632, 323519360005807677536004181044235568083645733070486869773243322990592, 350479306672958317330671196131255198757282877493027442254346933239808
@@ -26,7 +26,6 @@ contract C {
}
struct S { uint a; string b; uint16 c; }
function f4() public pure returns (bytes memory) {
bytes4 x = 0x12345678;
S memory s;
s.a = 0x1234567;
s.b = "Lorem ipsum dolor sit ethereum........";