How extract return data from call - solidity

I'm writing raw EVM op-codes, and want to return result data
contract Test {
address public addr;
bytes public sourceCode;
function deploy() private returns (address pointer) {
bytes memory code = abi.encodePacked(
hex"60003560805260206080f3"
);
sourceCode = code;
assembly {
pointer := create(0, add(code, 32), mload(code))
}
addr = pointer;
return pointer;
}
function win() public returns (bool, bytes memory, uint) {
address a = deploy();
(bool sent, bytes memory data) = address(this).call(abi.encodeWithSignature("func()"));
uint returnValue = abi.decode(data, (uint));
return (sent, data, returnValue);
}
This bytecode corresponds next opcodes:
PUSH1 0x00
CALLDATALOAD
PUSH1 0x80
MSTORE
PUSH1 0x20
PUSH1 0x80
RETURN
I validate this opcodes on this site
This opcodes take first byte from calldata, placed it into memory and returns this memory as result.
In remix if I call function win it returns true and 0x0, but in EVM Playground it returns expected result (first byte from calldata)
My question is: what I'm doing wrong? How can I fix my opcode to return result correctly?
No, I can't just write normal solidity code, because I have strong limitation on code size

Related

Authenticating Solidity params and signatures within smart contract

I'm trying to build a sort-of meta-transaction architecture where an admin can trustlessly submit someone else's transaction with validated data. Basic Solidity and JS code below. I'm missing a piece somewhere as the signature verification fails, but not sure where
...
Basic contract version:
contract Account {
struct User {
string username;
}
function createAccount(
address _signer,
User _user,
uint256 _nonce,
bytes memory _signature
) {
bytes32 messageHash = keccak256(abi.encode(_user, _nonce));
bytes32 signedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash));
require(recoverSigner(signedHash, _signature) == _signer);
...
}
function recoverSigner(
bytes32 _ethSignedMessageHash,
bytes memory _signature
) public pure returns (address) {
(bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);
return ecrecover(_ethSignedMessageHash, v, r, s);
}
function splitSignature(bytes memory sig)
public
pure
returns (
bytes32 r,
bytes32 s,
uint8 v
)
{
require(sig.length == 65, "invalid signature length");
assembly {
/*
First 32 bytes stores the length of the signature
add(sig, 32) = pointer of sig + 32
effectively, skips first 32 bytes of signature
mload(p) loads next 32 bytes starting at the memory address p into memory
*/
// first 32 bytes, after the length prefix
r := mload(add(sig, 32))
// second 32 bytes
s := mload(add(sig, 64))
// final byte (first byte of the next 32 bytes)
v := byte(0, mload(add(sig, 96)))
}
// implicitly return (r, s, v)
}
}
Basic JS script:
const userEncoded = ethers.utils.AbiCoder.prototype.encode(
['string'],
['abc']
);
const nonce = 1;
const hashedMessage = ethers.utils.keccak256(userEncoded, nonce);
const signedMessage = await user1.signMessage(hashedMessage);
await account.connect(admin).createAccount(user1.address, { username: 'abc' }), nonce, signedMessage);

Failed to call solidity function with array argument

I'm trying to execute contract's function use abi encode and call function, but I'm getting an error. Don't know how to resolve this issue.
pragma solidity >=0.8.0;
contract AbiTest {
event A(uint);
event Out(bytes);
function test() public {
bytes4 func = bytes4(keccak256("callMe(uint[])"));
uint[] memory arr = new uint[](3);
arr[0] = 3;
arr[1] = 4;
(bool res, bytes memory data) = address(this).call(abi.encode(func, arr));
emit Out(data);
require(res);
}
function callMe(uint[] memory array) public {
emit A(array[0]);
emit A(array[1]);
}
}
This solution works well, if arguments sizes are known at compile time, but with dynamic sizes this doesn't work.
How can I resolve it?
I think this solution should work just fine. This is compatible with dynamic array lengths.
function test() public {
uint[] memory arr = new uint[](2);
arr[0] = 3;
arr[1] = 4;
(bool success, ) = address(this).call
(
abi.encodeWithSignature(
"callMe(uint[])",
arr
)
);
}
Need to use abi.encodePacked see Solidity doc instead of abi.encode because second one don't compress items and therefore uses 32 bytes for the function name.
pragma solidity >=0.8.0;
contract Abi2Test {
function getByte() public returns (bytes memory) {
bytes4 func = bytes4(keccak256("callMe(uint256[])"));
return abi.encode(func);
}
function getByte2() public returns (bytes memory) {
bytes4 func = bytes4(keccak256("callMe(uint256[])"));
return abi.encodePacked(func);
}
}
getByte output: 0x6600981c00000000000000000000000000000000000000000000000000000000
getByte2 output: 0x6600981c
Therefore, when you use encode with function signature additionally will be allocated 28 bytes and EVM can't correctly parse passed value.
So, to correctly call function with abi.encode and abi.encodePacked you need to pack arguments with encode at the first, and at the second group function's signature with encoded bytes.
pragma solidity >=0.8.0;
contract Abi2Test {
event A(uint256);
event Out(bytes);
event Out1(bytes);
function test() public {
bytes4 func = bytes4(keccak256("callMe(uint256[])"));
uint256[] memory arr = new uint256[](3);
arr[0] = 3;
arr[1] = 4;
(bool res, bytes memory data) = address(this).call(abi.encodePacked(func, abi.encode(arr)));
emit Out(data);
require(res);
}
function callMe(uint256[] memory array) public {
emit A(array.length);
emit Out1(msg.data);
}
}

What type of input should I give to this function?

struct khatian{
uint64 khatianiId;
bytes32 plotHash;
uint16 percentOwn;
bytes32 buyFrom;
bytes32[] sellTo;
uint16[] sellPercentage;
uint[] ownerArray;
uint16[] perOwnerPercentage;
bool isExist;
}
function addKhatianFromOld(uint64 _khatianiId, bytes32 _plotHash, uint16 _percentOwn, bytes32 _buyFrom, uint[] _user, uint16[] _percentage) public{
require(msg.sender == contarctOwner, "Sender is not authorized");
require(plotMapping[_plotHash].isExist == true, "Plot doesn't exist");
bytes32 khatianHash = keccak256(abi.encodePacked(_khatianiId, _plotHash));
require(khatianMapping[khatianHash].isExist != true, "Khatian already exists");
require(khatianMapping[_buyFrom].isExist, "previous Khatian doesn't exist");
require(khatianMapping[_buyFrom].percentOwn >= _percentOwn, "Not enough land to sell");
for(uint j = 0; j< _user.length; j++){
require(userMapping[_user[j]].isExist == true, "User's NID doesn't exist");
}
This are my code snippet. I getting this error
''Error: expected array value (argument=null, value="1", code=INVALID_ARGUMENT, version=abi/5.5.0)''
What type of data should I give input here? specially in bytes32_buyFrom, uint[] _user, uint16[] _percentage?
I tried to give address and other string as input
Add memory / calldata keyword after declaring uint[] just like this uint[] memory _user and uint16[] memory _percentage let me know if it works
First of all, you must change the signature method adding the where memorized the data passed in input. In detail, you can consider that adding in memory the arrays.
Insomuch, change your method signature method in this way:
function addKhatianFromOld(uint64 _khatianiId, bytes32 _plotHash, uint16 _percentOwn, bytes32 _buyFrom, uint[] memory _user, uint16[] memory _percentage) public{
// your logic
}
To reply about your question:
In bytes32 parameter, in this function, you must give a format bytes32 from a string. You can see my answer to this thread for convert string to bytes32;
In uint[] array parameter, you must filled it with integer number starting from a maximum range value: 115792089237316195423570985008687907853269984665640564039457584007913129639935
(2**256);
In uint16[] array parameter, you must filled it with integer number starting from a maximum range value:
65536
(2**16)
In following attach an example of request with vainput

I want to find the substring (index 0 to 13) of bytes32 data and convert it into uint256 data

I am stuck in solidity code. I want substring of below data and convert it to uint256 data
bytes32 hmacSha256 = 0xf83bf40815929b2448b230d51fa2eaa5b8ccffd87691db7e62bf817b2cbb56ad;
I want first 13 chars of above hmacSha256 data i.e. 'f83bf40815929' and its uint256 ie. 4366982094870825.
I tried a number of things but to failure.
Code and tried code is below:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
/**
* #title Storage
* #dev Store & retrieve value in a variable
*/
contract TestContract {
function getsubstring1() public pure returns (string memory, uint256, string memory) {
bytes32 hmacSha256 = 0xf83bf40815929b2448b230d51fa2eaa5b8ccffd87691db7e62bf817b2cbb56ad;
bytes memory tempH = bytes(abi.encodePacked(hmacSha256));
uint256 uintHash = uint256(hmacSha256);
//I want below values as result.
// _hs is first 13 chars of hmacSha256.
//neither i could derive the _hs and nor _h from _hs.
string memory _hs = '0xf83bf40815929';
uint256 _h = 0xf83bf40815929;
//What I tried
//bytes13 _hs1 = bytes13(hmacSha256);
//but its returning 0xf83bf40815929b2448b230d51f which is double the length of expected value 0xf83bf40815929
//string memory _hs1 = substring(string(abi.encodePacked(hmacSha256)), 0, 13);
//above code is throwing error:Failed to decode output: null: invalid codepoint at offset 0; bad codepoint prefix
// bytes memory _hs2 = tempH[0:13] ;
//above giving error that its for bytes calldata dynamic array
//uint256 _h1 = uint256(bytes(abi.encodePacked(_hs)));
return (_hs, _h, _hs1);
}
function substring(string memory str, uint startIndex, uint endIndex) public pure returns (string memory) {
bytes memory strBytes = bytes(str);
bytes memory result = new bytes(endIndex-startIndex);
for(uint i = startIndex; i < endIndex; i++) {
result[i-startIndex] = strBytes[i];
}
return string(result);
}
}
You need to perform few typecasts and bitwise operatations, see the code comments.
Code:
pragma solidity ^0.8;
contract TestContract {
function getsubstring() external pure returns (bytes7, uint256) {
bytes32 hmacSha256 = 0xf83bf40815929b2448b230d51fa2eaa5b8ccffd87691db7e62bf817b2cbb56ad;
bytes7 first7Bytes = bytes7(hmacSha256); // get the first 7 bytes (14 hex characters): 0xf83bf40815929b
bytes7 thirteenHexCharacters = first7Bytes >> 4; // move 4 bytes (1 hex character) to the right: 0x0f83bf40815929
bytes32 castBytes = bytes32(thirteenHexCharacters); // cast the bytes7 to bytes32 so that we can cast it to integer later
bytes32 castBytesMoved = castBytes >> 200; // move 200 bytes (50 hex characters) to the right: 0x000000000000000000000000000000000000000000000000000f83bf40815929
uint256 integerValue = uint256(castBytesMoved); // cast the bytes32 to uint256
return (thirteenHexCharacters, integerValue);
}
}
Returned values:
bytes7: 0x0f83bf40815929
uint256: 4366982094870825

solidity ERC20 transferFrom gives no error but does not execute

I have a Solidity code that aims to Exchange BUSD with myToken (both ERC20) which calls a BUSD.transferFrom() and a myToken.transfer(), but despite the core executes with no errors only myToken is transferred.
The account is approved and has enough balance.
Can you please point the error?
bytes4 private constant SELECTOR_TRANSFER = bytes4(keccak256(bytes('transfer(address,uint256)')));
bytes4 private constant SELECTOR_TRANSFERFROM = bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
function _myTokenTransfer(uint256 amount) private {
_safeTransfer(myToken_addr, _msgSender(), amount);
}
function _busdTransfer(uint256 amount) private {
_safeTransferFrom(busd_addr, _msgSender(), address(this), amount);
}
function _safeTransferFrom(address token, address from, address to, uint value) private {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR_TRANSFERFROM, from , to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'myTokenPrivateSale: TRANSFERFROM_FAILED');
}
function _safeTransfer(address token, address to, uint value) private {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR_TRANSFER, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'myTokenPrivateSale: TRANSFER_FAILED');
}
}
Your busd_addr is unset (i.e. 0x0).
When the _safeTransferFrom() function gets executed, it sends an internal transaction to the 0x0 address. The transaction doesn't revert (there's no contract that would throw an exception on the 0x0 address) and doesn't return any data (again, no contract that would return any data).
(bool success, bytes memory data)
// `success` is true because it didn't revert
// `data` is 0x00, the default value
The validation then passes as if it were sucessful.
require(success && (data.length == 0 || ...));
// `success` is true
// `data.length` is 0, so the rest of the OR condition is ignored
I see that you executed the setBUSD() function. But this function doesn't set the busd_addr value, that is used in the _safeTransferFrom() function. (It only sets the busd and busd_set.)
There's currently no way to set the busd_addr value in your code. So you'll need to make the proper changes in your code - set busd_addr value in the setBUSD() function, and then redeploy your contract.