web3.eth.abi.encodeFunctionSignature is not working as expected - ethereum

I am using ERC165 in order to find out whether my contracts support an interface or not but I get really confusing behaviour form functionEncoding method of web3. Here is my interface
pragma solidity ^0.5.8;
interface ArrayExtraData {
function submitOfferArrayExtra(uint offerID, uint[] calldata extra) external returns (int status, uint offID);
function submitRequestArrayExtra(uint requestID, uint[] calldata extra) external returns (int status, uint reqID);
}
I expect to get 0x1ddeb71f as the interface selector which is essentially xor of function selectors but I get 0xe3bfed76.
And here is my js code:
let interfaceFunctions = [
'submitOfferArrayExtra(uint,uint[])',
'submitRequestArrayExtra(uint,uint[])'
]
let interfaceId = interfaceFunctions.
map(web3.eth.abi.encodeFunctionSignature).
map((x) => parseInt(x, 16)).
reduce((x, y) => x ^ y);
interfaceId = interfaceId > 0 ? interfaceId : 0xFFFFFFFF + interfaceId + 1;
interfaceId = '0x' + interfaceId.toString(16);

You have to be more specific about data types. for example, in this case, you must use uint256 instead of uint.

Related

Signature from array of tokenId's isn't verifying

The domain message is:
struct Offer{
address from;
address to;
uint256 nonce;
uint256[] tokenIds;
uint256 duration;
}
bytes32 constant EIP712DOMAIN_TYPEHASH = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
bytes32 constant OFFER_TYPEHASH = keccak256(
"Offer(address from,address to,uint256 nonce,uint256[] memory tokenIds,uint256 duration)"
);
function hash(Offer memory offer) public pure returns (bytes32) {
return keccak256(abi.encode(
OFFER_TYPEHASH,
offer.from,
offer.to,
offer.nonce,
keccak256(abi.encodePacked(offer.tokenIds)),
offer.duration
));
}
function verify(Offer memory offer, uint8 v, bytes32 r, bytes32 s) public view returns (bool) {
// Note: we need to use encodePacked here instead of encode.
bytes32 digest = keccak256(abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
hash(offer)
));
return ecrecover(digest, v, r, s) == ExpectedAddress;
}
I can't resolve issue with array when doing v4 signature.
If I removed tokenIds array from Offer struct, and OfferTypeHash, and also from hash func: everything works well as expected, I can verify signature via web3 and contract.
When I put tokenIds array to struct, I can't verify signature.
I googled and tried a lot of examples like:
I use this for hashing the offer:
keccak256(abi.encodePacked(array))
function hash(Offer memory offer) public pure returns (bytes32) {
return keccak256(abi.encode(
OFFER_TYPEHASH,
offer.from,
offer.to,
offer.nonce,
keccak256(abi.encodePacked(offer.tokenIds)),
offer.duration
));
}
keccak256(abi.encode(array))
keccak256(abi.encodePacked(array))
function hash(Offer memory offer) public pure returns (bytes32) {
return keccak256(abi.encode(
OFFER_TYPEHASH,
offer.from,
offer.to,
offer.nonce,
keccak256(abi.encode(offer.tokenIds)),
offer.duration
));
}
Even without Keccak:
function hash(Offer memory offer) public pure returns (bytes32) {
return keccak256(abi.encode(
OFFER_TYPEHASH,
offer.from,
offer.to,
offer.nonce,
keccak256(abi.encode(offer.tokenIds)),
offer.duration
));
}
I can't figure out: why keccak256(abi.encode is not doing the job?

Trying to convert address string to type address in Solidity

I am trying to convert address string to type address in solidity but when I am doing
function StringToBytes(string memory _str) public pure returns (bytes memory) {
return bytes(_str);
}
function StringToBytesLength(string memory _str) public pure returns (uint256) {
return bytes(_str).length;
}
The result of StringToBytes is giving me 42 which should ideally gives me 20. If I am trying the same thing in python i.e convert string to bytes , it is giving me 20 bytes which is the length of an ethereum address in bytes. I had found several solutions to convert address string to address type but none of them is working for solidity version 0.7.
Please help.
I want a solution but it is not optimal, I am looking for a solution which is lighter on gas fees, It is now consuming 77492.
function fromHexChar(uint8 c) public pure returns (uint8) {
if (bytes1(c) >= bytes1('0') && bytes1(c) <= bytes1('9')) {
return c - uint8(bytes1('0'));
}
if (bytes1(c) >= bytes1('a') && bytes1(c) <= bytes1('f')) {
return 10 + c - uint8(bytes1('a'));
}
if (bytes1(c) >= bytes1('A') && bytes1(c) <= bytes1('F')) {
return 10 + c - uint8(bytes1('A'));
}
return 0;
}
function hexStringToAddress(string calldata s) public pure returns (bytes memory) {
bytes memory ss = bytes(s);
require(ss.length%2 == 0); // length must be even
bytes memory r = new bytes(ss.length/2);
for (uint i=0; i<ss.length/2; ++i) {
r[i] = bytes1(fromHexChar(uint8(ss[2*i])) * 16 +
fromHexChar(uint8(ss[2*i+1])));
}
return r;
}
function toAddress(string calldata s) public pure returns (address) {
bytes memory _bytes = hexStringToAddress(s);
require(_bytes.length >= 1 + 20, "toAddress_outOfBounds");
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), 1)), 0x1000000000000000000000000)
}
return tempAddress;
}

How to encode tuple as input parameter to function using web3j

I am attempting to call a solidity function that looks something like the following:
function fillOrder(
Order memory order,
uint256 takerAssetFillAmount,
bytes memory signature
)
Using web3j I would create the function similar to below, however I'm not quite sure how to represent the order which is represented as a struct in Solidity.
List<Type> inputParams = Arrays.asList(???, new
Uint256(takerAssetFillAmount), new Bytes32(signture));
new Function("fillOrder", inputParams, Collections.emptyList());
Any pointers on how I should represent the struct?
Thanks.
You can wrap parameters with square brackets.
For example, let's say I have a contract:
contract Test {
struct Foo {
uint a;
string b;
address c;
}
function bar (Foo memory foo) public {
c = foo.c;
}
}
I can call bar function with web3.js like this:
contract.methods.foo([123, "123", "0xABC...."]).send({ from: '0x...' })
here is the contract address https://goerli.etherscan.io/address/0xd5999bf0ce31a1d9d6a6de2bf03feaff1913cee5#writeContract
in the write function , createSwapOrder is asking nested Tuple . here is the solidity code to show the structure of tuple :
struct Side {
address user;
bytes signedRequiredOutput;
ERC20Component[] erc20s;
ERC721Component[] erc721s;
ERC1155Component[] erc1155s;
}
struct ERC20Component {
uint256 amount;
address underlying;
// A signed approval transaction giving `amount` transfer rights
// of token `underlying` to address(this).
// bytes signedApproval;
}
struct ERC721Component {
uint256 tokenId;
address collection;
// A signed approval transaction giving `tokenId` tranfer rights
// of token `collection` to address(this).
// bytes signedApproval;
}
struct ERC1155Component {
uint256 tokenId;
uint256 amount;
address collection;
// A signed approval transaction giving `tokenId` tranfer rights
// of token `collection` to address(this).
// bytes signedApproval;
}
struct Order {
Side side0;
Side side1;
uint256 expiry;
bytes32 hashlock;
bytes32 preimage;
bool completed;
}
event OrderCreated(address indexed user, bytes32 orderId);
uint256 public totalOrders;
mapping(bytes32 => Order) public orders;
function createSwapOrder(
Side calldata side0,
bytes32 hashlock,
uint256 timelock
) public {
...
}
and in first args side0 is asking a nested tuple and this tuple formet should be like this
["0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","0x00",[["32","0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"]],[["32","0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"]],[["32","32","0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"]]],
i hope you can understand the structure how its provided !! and sure it working
Web3j offers such classes as StaticStruct and DynamicStruct where you define your struct object via primitives. Here is the sample from my project:
class Value: DynamicStruct {
private lateinit var offer: String
private lateinit var availableSince: BigInteger
private lateinit var availabilityEnd: BigInteger
private var isConsumed: Boolean = false
private lateinit var lockedUntil: BigInteger
constructor(
offer: String,
availableSince: BigInteger,
availabilityEnd: BigInteger,
isConsumed: Boolean,
lockedUntil: BigInteger
) : super(
Utf8String(offer), Uint256(availableSince),
Uint256(availabilityEnd), Bool(isConsumed),
Uint256(lockedUntil)
) {
this.offer = offer
this.availableSince = availableSince
this.availabilityEnd = availabilityEnd
this.isConsumed = isConsumed
this.lockedUntil = lockedUntil
}
constructor(
offer: Utf8String,
availableSince: Uint256,
availabilityEnd: Uint256,
isConsumed: Bool,
lockedUntil: Uint256
) : super(offer, availableSince, availabilityEnd, isConsumed, lockedUntil) {
this.offer = offer.value
this.availableSince = availableSince.value
this.availabilityEnd = availabilityEnd.value
this.isConsumed = isConsumed.value
this.lockedUntil = lockedUntil.value
}
}
Ideally you just need to pass this struct instance to you contract method as a parameter where contract is autogenerated over $web3j solidity generate -b /path/to/<smart-contract>.bin -a /path/to/<smart-contract>.abi -o /path/to/src/main/java -p com.your.organisation.name command.
However personally I faced with issue to make this console command working and have to implement required logic by my own. This is in the progress now.

How to push element in multiple dimension array at certain coordinate in solidity?

I have an array like this:
Animal[3][2][] animalArray.
After I have a new element like "dog", how to push it in the certain place at like
Animal[2][1][]?
I tried
animalArray[2][1].push(dog);
It always gives me the error.
Here below is the code with the problem:
pragma solidity ^0.4.0;
contract Zootest {
struct Zoo {
uint state;
Animal[][2][3] animalarray;
uint price;
}
struct Animal {
uint quantity;
address Address;
}
mapping (uint => Zoo) zoo;
function openZoo (uint index) {
Zoo memory newZoo = Zoo({
state: 1,
price: 0,
animalarray: new Animal[][2][3](0)
});
zoo[index] = newZoo;
}
function enterZoo (uint index, uint x, uint y, uint quantity) public {
Animal memory newAnimal = Animal({
Address:msg.sender,
quantity:quantity
});
zoo[index].price = zoo[index].price+msg.value;
zoo[index].animalarray[x][y].push(newAnimal);
}
}
Perhaps you meant to declare the array this way:
Animal[][2][3] animalArray;
From https://solidity.readthedocs.io/en/v0.4.24/types.html#arrays (my emphasis):
An array of fixed size k and element type T is written as T[k], an array of dynamic size as T[]. As an example, an array of 5 dynamic arrays of uint is uint[][5] (note that the notation is reversed when compared to some other languages). To access the second uint in the third dynamic array, you use x[2][1] (indices are zero-based and access works in the opposite way of the declaration, i.e. x[2] shaves off one level in the type from the right).

What is the best approach in Solidity for pagination (straightforward and based on some filter(s)) capabilities?

Let's suppose that we have following structures in Solidity contract :
struct EntityA {
string lessThen32ByteString1;
string moreThen32ByteString1;
string lessThen32ByteString2;
string moreThen32ByteString3;
bool flag;
uint var1;
uint var2;
uint var3;
uint var4;
ProposalStatus proposalStatus;}
// 100K entities EntityA[] public items;
We have now following implementation (with helper functions for string to byte32 conversion, splitting string to a few byte32 parts and so on) :
function getChunkOfPart1EntityADetails(uint filterAsUint, uint offset, uint limit) public constant
returns (bytes32[100] lessThen32ByteString1Arr, bytes32[100] moreThen32ByteString1PrefixArr, bytes32[100] moreThen32ByteString1SuffixArr) {
}
function getChunkOfPart2EntityADetails(uint filterAsUint, uint offset, uint limit) public constant
returns (bytes32[100] lessThen32ByteString2Arr, bytes32[100] moreThen32ByteString2PrefixArr, bytes32[100] moreThen32ByteString2SuffixArr) {
}
function getChunkOfPart3EntityADetails(uint filterAsUint, uint offset, uint limit) public constant
returns (bool[100] flagArr, uint[100] var1Arr, uint[100] var2Arr, uint[100] var3Arr, uint[100] var4Arr, ProposalStatus[100] proposalStatusArr,) {
}
Current implementation does not look good from design perspective, furthermore each additional filter support requires contract changes due to absence any query language support.
Use case example : retrieve 10 entities based on specified proposalStatus and offset 50 (6th page, page size is 10 entities (maybe 20, 50, 100))
I know I'm late but here you go. This will return an array of uints. You can then use this array on the client to resolve the id's in the getter for the array that stores your data.
struct Zombie {
//data
};
Zombie[] public zombies;
function paginateAllZombies(uint _resultsPerPage, uint _page) external view returns (uint[]) {
Zombie[] memory result = new Zombie[](_resultsPerPage);
for(uint i = _resultsPerPage * _page - _resultsPerPage; i < _resultsPerPage * _page; i++ ){
result[i] = i;
} //CONVERT TO SAFEMATH
return result;
}
So once you get this returned you can .map() the result in your client app and call zombies(uint _index).
If you need more details on this approach please check out cryptozombies.io
Not sure if this is the best approach though.
Hopefully in the future you can just do:
function paginateAllZombies(uint _resultsPerPage, uint _page) external view returns (Zombie[]) {
uint[] memory result = new uint[](_resultsPerPage);
for(uint i = _resultsPerPage * _page - _resultsPerPage; i < _resultsPerPage * _page; i++ ){
result[i] = zombies[i];
} //CONVERT TO SAFEMATH
return result;
}