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);
Related
I'm trying to integrate Pricefeeds in the chain keepers to automate a sell order when the price goes under certain value.
Separately both work but when adding the Price feed function inside the checkUpkeep() it doesn't trigger the performUpkeep().
Does checkUpkeep() function can call the priceFeed function or is not even praepared for this?
how should I implement it then?
Here is the code:
function checkUpkeep(bytes memory /* checkData */) public view override returns (//,bytes memory value
bool upkeepNeeded,
bytes memory num
){
uint256 EthPrice = 0;
// uint256 i = 2;
EthPrice = getPrice();
num = abi.encodePacked(EthPrice);
if (EthPrice > 0){
upkeepNeeded = true;
}
return (upkeepNeeded, num);//, value
}
function performUpkeep(bytes calldata num) external override {//, bytes calldata value
(bool upkeepNeeded, ) = checkUpkeep("");
if (!upkeepNeeded) {
revert Order__UpkeepNotNeeded(
address(this).balance,
s_Wallets.length
);
}
//Byte conversion to uint
uint256 number;
number = abi.decode(num, (uint256));
// for(uint i=0;i<num.length;i++){
// number = number + uint(uint8(num[i]))*(2**(8*(num.length-(i+1))));
// }
s_nombre = number;
}
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);
}
}
This is what the error reads:
Gas estimation errored with the following message (see below). The
transaction execution will likely fail. Do you want to force sending?
Internal JSON-RPC error. { "message": "Returned error: project ID does
not have access to archive state", "code": -32000, "data": { "stack":
"Error: Returned error: project ID does not have access to archive
state\n at Object.ErrorResponse
(/usr/local/lib/node_modules/ganache-cli/build/ganache-core.node.cli.js:55:2110625)\n
at a
(/usr/local/lib/node_modules/ganache-cli/build/ganache-core.node.cli.js:55:2108932)\n
at
/usr/local/lib/node_modules/ganache-cli/build/ganache-core.node.cli.js:55:2093154\n
at runMicrotasks ()\n at processTicksAndRejections
(internal/process/task_queues.js:95:5)", "name": "Error" } }
I have made the settings for deployment on remix:
Injected Web 3
pragma solidity ^0.5.0;
pragma experimental ABIEncoderV2;
interface Structs {
struct Val {
uint256 value;
}
enum ActionType {
Deposit, // supply tokens
Withdraw, // borrow tokens
Transfer, // transfer balance between accounts
Buy, // buy an amount of some token (externally)
Sell, // sell an amount of some token (externally)
Trade, // trade tokens against another account
Liquidate, // liquidate an undercollateralized or expiring account
Vaporize, // use excess tokens to zero-out a completely negative account
Call // send arbitrary data to an address
}
enum AssetDenomination {
Wei // the amount is denominated in wei
}
enum AssetReference {
Delta // the amount is given as a delta from the current value
}
struct AssetAmount {
bool sign; // true if positive
AssetDenomination denomination;
AssetReference ref;
uint256 value;
}
struct ActionArgs {
ActionType actionType;
uint256 accountId;
AssetAmount amount;
uint256 primaryMarketId;
uint256 secondaryMarketId;
address otherAddress;
uint256 otherAccountId;
bytes data;
}
struct Info {
address owner; // The address that owns the account
uint256 number; // A nonce that allows a single address to control many accounts
}
struct Wei {
bool sign; // true if positive
uint256 value;
}
}
contract DyDxPool is Structs {
function getAccountWei(Info memory account, uint256 marketId) public view returns (Wei memory);
function operate(Info[] memory, ActionArgs[] memory) public;
}
/**
* #dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see `ERC20Detailed`.
*/
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
}
contract DyDxFlashLoan is Structs {
DyDxPool pool = DyDxPool(0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e);
address public WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
mapping(address => uint256) public currencies;
constructor() public {
currencies[WETH] = 1;
}
modifier onlyPool() {
require(
msg.sender == address(pool),
"FlashLoan: could be called by DyDx pool only"
);
_;
}
function tokenToMarketId(address token) public view returns (uint256) {
uint256 marketId = currencies[token];
require(marketId != 0, "FlashLoan: Unsupported token");
return marketId - 1;
}
// the DyDx will call `callFunction(address sender, Info memory accountInfo, bytes memory data) public` after during `operate` call
function flashloan(address token, uint256 amount, bytes memory data)
internal
{
IERC20(token).approve(address(pool), amount + 1);
Info[] memory infos = new Info[](1);
ActionArgs[] memory args = new ActionArgs[](3);
infos[0] = Info(address(this), 0);
AssetAmount memory wamt = AssetAmount(
false,
AssetDenomination.Wei,
AssetReference.Delta,
amount
);
ActionArgs memory withdraw;
withdraw.actionType = ActionType.Withdraw;
withdraw.accountId = 0;
withdraw.amount = wamt;
withdraw.primaryMarketId = tokenToMarketId(token);
withdraw.otherAddress = address(this);
args[0] = withdraw;
ActionArgs memory call;
call.actionType = ActionType.Call;
call.accountId = 0;
call.otherAddress = address(this);
call.data = data;
args[1] = call;
ActionArgs memory deposit;
AssetAmount memory damt = AssetAmount(
true,
AssetDenomination.Wei,
AssetReference.Delta,
amount + 1
);
deposit.actionType = ActionType.Deposit;
deposit.accountId = 0;
deposit.amount = damt;
deposit.primaryMarketId = tokenToMarketId(token);
deposit.otherAddress = address(this);
args[2] = deposit;
pool.operate(infos, args);
}
}
contract Flashloan is DyDxFlashLoan {
uint256 public loan;
constructor() public payable {
(bool success, ) = WETH.call.value(msg.value)("");
require(success, "fail to get weth");
}
function getFlashloan(address flashToken, uint256 flashAmount) external {
uint256 balanceBefore = IERC20(flashToken).balanceOf(address(this));
bytes memory data = abi.encode(flashToken, flashAmount, balanceBefore);
flashloan(flashToken, flashAmount, data); // execution goes to `callFunction`
}
function callFunction(
address, /* sender */
Info calldata, /* accountInfo */
bytes calldata data
) external onlyPool {
(address flashToken, uint256 flashAmount, uint256 balanceBefore) = abi
.decode(data, (address, uint256, uint256));
uint256 balanceAfter = IERC20(flashToken).balanceOf(address(this));
require(
balanceAfter - balanceBefore == flashAmount,
"contract did not get the loan"
);
loan = balanceAfter;
// Use the money here!
}
}
Trying to create a function to mint a specific set of ERC1155 tokens but for some reason when executing no tokens are minted. Code for mintSingle() works fine. I've tried multiple ways of constructing the dynamic array that's required as an input to the OpenZeppelin ERC1155 contract function _mintBatch(address to, uint256[] ids, uint256[] amounts, bytes data), but nothing is working. What am I doing wrong? Thank you.
contract ExampleProject is ERC1155 {
uint256 public constant ROWA = 0;
uint256 public constant ROWBA = 30;
constructor() public ERC1155("ipfs://Example/metadata/{id}.json") {
}
function mintRowA()
public
{
uint256[] memory a = new uint256[](2);
a[0] = ROWA;
a[1] = ROWBA;
uint256[] memory b = new uint256[](2);
b[0] = 1;
b[1] = 1;
_mintBatch(msg.sender, a, b, "" );
}
function mintSingle()
public
{
_mint(msg.sender, ROWBA, 1, "");
}
}
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