Invalid implicit conversion from address payable to bytes memory requested. This function requires a single bytes argument - ethereum

function setBasicDetails(string memory _registrationNo,
string memory _farmerName,
string memory _farmAddress,
string memory _exporterName,
string memory _importerName
) public onlyAuthCaller returns(address) {
uint tmpData = uint(keccak256(msg.sender));
address batchNo = address(tmpData);
basicDetailsData.registrationNo = _registrationNo;
basicDetailsData.farmerName = _farmerName;
basicDetailsData.farmAddress = _farmAddress;
basicDetailsData.exporterName = _exporterName;
basicDetailsData.importerName = _importerName;
batchBasicDetails[batchNo] = basicDetailsData;
nextAction[batchNo] = 'FARM_INSPECTION';
return batchNo;
}
this is my solidity function code and i have error here's code
uint tmpData = uint(keccak256(msg.sender));
address batchNo = address(tmpData);
error msg:Invalid type for argument in function call. Invalid implicit conversion from address payable to bytes memory requested. This function requires a single bytes argument. Use abi.encodePacked(...) to obtain the pre-0.5.0 behaviour or abi.encode(...) to use ABI encoding.

If that is the only error in your code ()
keccak256(msg.sender)
keccak256 will return 32 bytes hash. but the address is 20 bytes. so instead of uint you should be using uint160
uint tmpData = uint160(keccak256(msg.sender))

Related

Solidity how to validate calldata decodes to a paticular struct

I have an interface in solidity which looks like so, I would like my call to revert if the calldata passed isn't of a specific type
// Resolver interface
interface IResolver {
// Pass payment info as calldata only the manager should have the right to update it
function resolve(uint256 amount, ResolverOptions calldata resolverOptions) external returns (uint256);
// Reverts if the calldata passes is not a proper struct
function validateAdditionalCalldata(bytes calldata additionalCalldata) external view;
}
I've created a class to implement this here:
struct fooResolverOptions {
address[] fooAddresses;
uint256[] fooAmounts;
}
contract FooResolver is IResolver {
// Validate the additional calldata passed to the resolver contract
function validateAdditionalCalldata(bytes calldata additionalCalldata) view external {
// Convert the additional calldata to bytes memory
bytes memory additionalCalldataMemory = additionalCalldata;
// Decode the additional calldata as a FooResolverOptions struct
FooResolverOptions memory fooOptions;
bool success = abi.decode(additionalCalldataMemory, fooOptions);
// Check if the decode was successful
require(success, "Invalid additional calldata");
}
}
None of the Way's I've tried to decode work:
bool success = abi.decode(additionalCalldataMemory, fooOptions);
this way claims there is no return value from decode.
FooResolverOptions memory fooOptions;
abi.decode(additionalCalldata, fooOptions);
This way claims it wants a tuple of types. How do I decode a struct data, and validate it succeeded?
Solidity currently (v0.8) doesn't support dynamic arguments in abi.decode(), so you'll need to write logic that validates against predefined set of types.
bytes calldata additionalCalldata in your example is an array of bytes, so abi.decode(additionalCalldataMemory, <types>); tries to decode the binary to whatever <types> you pass. If the input fits the type length, it will simply decode the value to the type.
Example where the value fits into both bool and address types, so both operations succeed:
function validateAdditionalCalldata() pure external returns (bool, address) {
bytes memory additionalCalldataMemory = hex"0000000000000000000000000000000000000000000000000000000000000001";
bool decoded1 = abi.decode(additionalCalldataMemory, (bool));
address decoded2 = abi.decode(additionalCalldataMemory, (address));
return (decoded1, decoded2);
}
When the value doesn't fit the type, it throws an exception. Uncaught exception effectively reverts the transaction or the call. However, you can use try / catch to catch the exception.
pragma solidity ^0.8;
contract FooResolver {
function validateAdditionalCalldata() external view returns (bool, address) {
// does not fit `bool` but still fits `address`
bytes memory additionalCalldataMemory = hex"0000000000000000000000000000000000000000000000000000000000000002";
bool decoded1;
try this.decodeToBool(additionalCalldataMemory) returns (bool decodedValue) {
decoded1 = decodedValue;
} catch {
decoded1 = false;
}
address decoded2 = abi.decode(additionalCalldataMemory, (address));
return (decoded1, decoded2);
}
// workaround - try/catch can be currently (v0.8) used on external function calls - but not on native function calls
function decodeToBool(bytes memory data) external pure returns (bool) {
return abi.decode(data, (bool));
}
}

Solidity: How to type cast string memory to address and uint type?

I get the following errors when trying to type cast string memory to address and uint type.
TypeError: Explicit type conversion not allowed from "string memory" to "address".
TypeError: Explicit type conversion not allowed from "string memory" to "uint256".
Below is the solidity code.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Test {
struct allowedTokenDetails {
address admin;
uint256 price;
uint256 balance;
address rewardToken;
uint256 timestampAdded;
uint256 timestampLastUpdated;
}
mapping(address => allowedTokenDetails) public allowedTokensData;
function setAllowedTokensData(address _token, string[][] memory _data) public {
for (uint256 dataIndex = 0; dataIndex < _data.length; dataIndex++) {
string memory dataKey = _data[dataIndex][0];
string memory dataValue = _data[dataIndex][1];
if (keccak256(abi.encodePacked(dataKey)) == keccak256(abi.encodePacked("admin"))) allowedTokensData[_token].admin = address(dataValue);
if (keccak256(abi.encodePacked(dataKey)) == keccak256(abi.encodePacked("price"))) allowedTokensData[_token].price = uint256(dataValue);
if (keccak256(abi.encodePacked(dataKey)) == keccak256(abi.encodePacked("balance"))) allowedTokensData[_token].balance = uint256(dataValue);
if (keccak256(abi.encodePacked(dataKey)) == keccak256(abi.encodePacked("rewardToken"))) allowedTokensData[_token].rewardToken = address(dataValue);
allowedTokensData[_token].timestampLastUpdated = block.timestamp;
}
}
}
Is there a solution to this?
Instead of validating the input with a set of if statements and typecasting each value based on the function logic, you can already pass the input data in expected types in a prepared struct:
struct inputData {
address admin;
uint256 price;
uint256 balance;
address rewardToken;
}
function setAllowedTokensData(address _token, inputData[] memory _data) public {
for (uint256 dataIndex = 0; dataIndex < _data.length; dataIndex++) {
allowedTokensData[_token] = allowedTokenDetails(
_data[dataIndex].admin,
_data[dataIndex].price,
_data[dataIndex].balance,
_data[dataIndex].rewardToken,
0, // `timestampAdded` not set in your snippet
block.timestamp
);
}
}

Why does this code throw a (ambiguous) internal compiler error?

This function produces the following error (compiled by hardhat)
Solidity 0.8.7
contract TestContract {
function slice(string calldata source, uint from, uint to) public pure returns(string memory) {
bytes calldata b = (bytes(source));
uint len = b.length;
require(to < len && to>=from, "indexes out of bounds");
string memory retval = string(b[from:to]);
return retval;
}
}
The error I get is Compiling 1 file with 0.8.7 InternalCompilerError: Internal compiler error (/Users/distiller/project/libsolidity/codegen/CompilerUtils.cpp:1116) Error HH600: Compilation failed
I'm not sure about how you convert bytes to string, but the error might come from string(b[from:to]);. You can reference the byteToString function provided here https://ethereum.stackexchange.com/questions/29295/how-to-convert-a-bytes-to-string-in-solidity.

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.

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;
}