mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Implement typechecked abi.encodeCall()
This commit is contained in:
@@ -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........";
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
contract C {
|
||||
function callMeMaybe(uint a, uint b, uint[] memory c) external {}
|
||||
|
||||
function abiEncodeSimple(uint x, uint y, uint z, uint[] memory a, uint[] memory b) public view {
|
||||
require(x == y);
|
||||
bytes memory b1 = abi.encodeCall(this.callMeMaybe, (x, z, a));
|
||||
bytes memory b2 = abi.encodeCall(this.callMeMaybe, (y, z, a));
|
||||
assert(b1.length == b2.length);
|
||||
|
||||
bytes memory b3 = abi.encodeCall(this.callMeMaybe, (y, z, b));
|
||||
assert(b1.length == b3.length); // should fail
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// SMTEngine: all
|
||||
// SMTIgnoreCex: yes
|
||||
// ----
|
||||
// Warning 6031: (233-249): Internal error: Expression undefined for SMT solver.
|
||||
// Warning 6031: (298-314): Internal error: Expression undefined for SMT solver.
|
||||
// Warning 6031: (398-414): Internal error: Expression undefined for SMT solver.
|
||||
// Warning 1218: (330-360): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (430-460): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 6328: (330-360): CHC: Assertion violation might happen here.
|
||||
// Warning 6328: (430-460): CHC: Assertion violation might happen here.
|
||||
// Warning 4661: (330-360): BMC: Assertion violation happens here.
|
||||
// Warning 4661: (430-460): BMC: Assertion violation happens here.
|
||||
@@ -0,0 +1,82 @@
|
||||
interface I {
|
||||
function fExternal(uint256 p, string memory t) external;
|
||||
}
|
||||
|
||||
library L {
|
||||
function fExternal(uint256 p, string memory t) external {}
|
||||
}
|
||||
|
||||
contract C {
|
||||
using L for uint256;
|
||||
|
||||
function f(int a) public {}
|
||||
function f2(int a, string memory b) public {}
|
||||
function f3(int a, int b) public {}
|
||||
function f4() public {}
|
||||
function fInternal(uint256 p, string memory t) internal {}
|
||||
|
||||
function failFunctionArgsWrongType() public returns(bytes memory) {
|
||||
return abi.encodeCall(this.f, ("test"));
|
||||
}
|
||||
function failFunctionArgsTooMany() public returns(bytes memory) {
|
||||
return abi.encodeCall(this.f, (1, 2));
|
||||
}
|
||||
function failFunctionArgsTooFew0() public returns(bytes memory) {
|
||||
return abi.encodeCall(this.f, ());
|
||||
}
|
||||
function failFunctionArgsTooFew1() public returns(bytes memory) {
|
||||
return abi.encodeCall(this.f);
|
||||
}
|
||||
function failFunctionPtrMissing() public returns(bytes memory) {
|
||||
return abi.encodeCall(1, this.f);
|
||||
}
|
||||
function failFunctionPtrWrongType() public returns(bytes memory) {
|
||||
return abi.encodeCall(abi.encodeCall, (1, 2, 3, "test"));
|
||||
}
|
||||
function failFunctionInternal() public returns(bytes memory) {
|
||||
return abi.encodeCall(fInternal, (1, "123"));
|
||||
}
|
||||
function failFunctionInternalFromVariable() public returns(bytes memory) {
|
||||
function(uint256, string memory) internal localFunctionPointer = fInternal;
|
||||
return abi.encodeCall(localFunctionPointer, (1, "123"));
|
||||
}
|
||||
function failFunctionArgsArrayLiteral() public returns(bytes memory) {
|
||||
return abi.encodeCall(this.f3, [1, 2]);
|
||||
}
|
||||
function failLibraryPointerCall() public returns (bytes memory) {
|
||||
return abi.encodeCall(L.fExternal, (1, "123"));
|
||||
}
|
||||
function failBoundLibraryPointerCall() public returns (bytes memory) {
|
||||
uint256 x = 1;
|
||||
return abi.encodeCall(x.fExternal, (1, "123"));
|
||||
}
|
||||
function failInterfacePointerCall() public returns (bytes memory) {
|
||||
return abi.encodeCall(I.fExternal, (1, "123"));
|
||||
}
|
||||
function successFunctionArgsIntLiteralTuple() public returns(bytes memory) {
|
||||
return abi.encodeCall(this.f, (1));
|
||||
}
|
||||
function successFunctionArgsIntLiteral() public returns(bytes memory) {
|
||||
return abi.encodeCall(this.f, 1);
|
||||
}
|
||||
function successFunctionArgsLiteralTuple() public returns(bytes memory) {
|
||||
return abi.encodeCall(this.f2, (1, "test"));
|
||||
}
|
||||
function successFunctionArgsEmptyTuple() public returns(bytes memory) {
|
||||
return abi.encodeCall(this.f4, ());
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 5407: (486-494): Cannot implicitly convert component at position 0 from "literal_string "test"" to "int256".
|
||||
// TypeError 7788: (576-606): Expected 1 instead of 2 components for the tuple parameter.
|
||||
// TypeError 7788: (687-713): Expected 1 instead of 0 components for the tuple parameter.
|
||||
// TypeError 6219: (794-816): Expected two arguments: a function pointer followed by a tuple.
|
||||
// TypeError 5511: (911-912): Expected first argument to be a function pointer, not "int_const 1".
|
||||
// TypeError 3509: (1018-1032): Function must be "public" or "external".
|
||||
// TypeError 3509: (1145-1154): Function must be "public" or "external". Did you forget to prefix "this."?
|
||||
// TypeError 3509: (1350-1370): Function must be "public" or "external".
|
||||
// TypeError 7515: (1469-1500): Expected a tuple with 2 components instead of a single non-tuple parameter.
|
||||
// TypeError 5407: (1493-1499): Cannot implicitly convert component at position 0 from "uint8[2]" to "int256".
|
||||
// TypeError 3509: (1596-1607): Function must be "public" or "external".
|
||||
// TypeError 3509: (1738-1749): Function must be "public" or "external".
|
||||
// TypeError 3509: (1860-1871): Function must be "public" or "external".
|
||||
@@ -0,0 +1,9 @@
|
||||
contract C {
|
||||
function f(int a, int b) public {}
|
||||
function failFunctionArgsIntLiteralNestedTuple() public returns(bytes memory) {
|
||||
return abi.encodeCall(this.f, ((1,2)));
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7788: (139-170): Expected 2 instead of 1 components for the tuple parameter.
|
||||
// TypeError 5407: (163-168): Cannot implicitly convert component at position 0 from "tuple(int_const 1,int_const 2)" to "int256".
|
||||
@@ -0,0 +1,8 @@
|
||||
contract C {
|
||||
function f(int a) public {}
|
||||
function failFunctionArgsIntLiteralTuple() public returns(bytes memory) {
|
||||
return abi.encodeCall(this.f, (1,));
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 8381: (149-153): Tuple component cannot be empty.
|
||||
Reference in New Issue
Block a user