_signTypedData method on ethers does not match with ERC712 solidity code - solidity

I've faced an ethers signature unmatched problem.
Everything is normal.
Already compared domainData, types, message variable in the js code with contract.
Below is the JS Code to generate signature and call contract.
const contractAddress = await contract.address;
domainData.chainId = 31337;
domainData.verifyingContract = contractAddress;
const signature = await signer._signTypedData(domainData, types, message);
const { r, s, v } = ethers.utils.splitSignature(signature);
const result = await contract.recoverAddressFromTypedData(
message,
v,
r,
s
);
expect(result).to.equal(signer.address);
Below is the solidity code which use "#openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"
function recoverAddressFromTypedData(
Bid memory bid,
uint8 v,
bytes32 r,
bytes32 s
) public view returns (address) {
bytes32 digest = _hashTypedDataV4(hashBid(bid));
address signer = ecrecover(digest, v, r, s);
return signer;
}
But I got following error on the last line of JS code.
AssertionError: expected '0x7Da34C07B95dB4A1c85fe4C5d313F4860E85e340' to equal '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
+ expected - actual
-0x7Da34C07B95dB4A1c85fe4C5d313F4860E85e340
+0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Is there anything wrong with my code?

I don't know if I have the same reason as you, in my case I had a struct member containing a string type which needed to be converted to bytes32.
contract MyContract is Ownable, AccessControl, EIP712 {
struct Action {
address initiator;
string name;
}
bytes32 public constant ACTION_TYPE_HASH = keccak256("Action(address initiator,string name)");
function _hashStruct(Action memory action) private pure returns (bytes32) {
// If your struct member has string type,
// you need to use keccak256(abi.encodePacked(string))
// convert it to bytes32
return keccak256(abi.encode(ACTION_TYPE_HASH, action.initiator, keccak256(abi.encodePacked(action.name))));
}
function _hashTypedDataV4(Action memory action) private view returns (bytes32) {
bytes32 structHash = _hashStruct(action);
return EIP712._hashTypedDataV4(structHash);
}
// more...
}

Related

CONTRACT_REVERT_EXECUTED Hedera Smart Contract

CONTRACT_REVERT_EXECUTED
Not sure what I'm doing wrong but I'm trying to call a function and it takes in one parameter and I made sure it was correct but it still reverts. This is hedera-hashgraph using HederaTokenService.
Smart Contract:
pragma solidity ^0.8.11;
import "./hip-206/HederaTokenService.sol";
import "./hip-206/HederaResponseCodes.sol";
contract Minting is HederaTokenService {
address tokenAddress;
bytes metadata;
string baseURI = "abc";
uint64 mintPrice;
function mintNonFungibleToken(uint64 _amount) external payable {
bytes[] memory nftMetadatas = generateBytesArrayForHTS(
baseURI,
_amount
);
(
int256 response,
uint64 newTotalSupply,
) = HederaTokenService.mintToken(tokenAddress, _amount, metadata);
if (response != HederaResponseCodes.SUCCESS) {
revert("Mint Failed");
}
}
// #dev Helper function which generates array of addresses required for HTSPrecompiled
function generateAddressArrayForHTS(address _address, uint256 _items)
internal
pure
returns (address[] memory _addresses)
{
_addresses = new address[](_items);
for (uint256 i = 0; i < _items; i++) {
_addresses[i] = _address;
}
}
// #dev Helper function which generates array required for metadata by HTSPrecompiled
function generateBytesArrayForHTS(bytes memory _bytes, uint256 _items)
internal
pure
returns (bytes[] memory _bytesArray)
{
_bytesArray = new bytes[](_items);
for (uint256 i = 0; i < _items; i++) {
_bytesArray[i] = _bytes;
}
}
Calling the transaction in js:
const contractMint = await new ContractExecuteTransaction()
.setContractId(contractId)
.setGas(3000000)
.setFunction(
"mintFungibleToken",
new ContractFunctionParameters().addUint64(1)
)
.setMaxTransactionFee(new Hbar(2));
Also note that a REVERT does usually contain useful information, you can navigate to hashscan.io to look up the response from your smart contract, for example
https://hashscan.io/testnet/transaction/1675427464.278782297?tid=0.0.1189-1675427451-309271560
shows a contract that reverted, the error message is 0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001b52656d697420746f6b656e20616c726561647920637265617465640000000000
with the error message starting with 0x08c379a, we know it's a string, so we can decode it
Hacky way:
Navigate to: https://www.rapidtables.com/convert/number/hex-to-ascii.html
Paste the above (remove the 0x)
Choose ASCII for character encoding
Press convert
Output: Ãy  Remit token already created
In Javascript
const {ethers} = require("ethers");
async function main() {
const error = "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001b52656d697420746f6b656e20616c726561647920637265617465640000000000";
const reason = ethers.utils.defaultAbiCoder.decode(
['string'],
ethers.utils.hexDataSlice(error, 4)
)
console.log(reason);
};
void main();
It looks like you're trying to call mintFungibleToken from JS, but the smart contract doesn't have a mintFungibleToken function; the smart contract function name is mintNonFungibleToken.

contracts/3_Ballot.sol:33:37: TypeError: Named argument does not match function declaration

from solidity:
contracts/3_Ballot.sol:33:37: TypeError: Named argument does not match function declaration.
Request memory newRequest = Request({
^ (Relevant source part starts here and spans across multiple lines).
I get this error every time. What should i do for the solve it?
pragma solidity ^0.4.17;
contract Campaign {
struct Request {
string description;
uint value;
address recipient;
bool complete;
}
Request[] public requests;
address public manager;
uint public minimumContirbution;
address[] public approvers;
modifier restricted() {
require (msg.sender == manager);
_;
}
function Campaign (uint minimum) public {
manager = msg.sender;
minimumContirbution = minimum;
}
function contribute () public payable {
require(msg.value > minimumContirbution);
approvers.push(msg.sender);
}
function createRequest(string description, uint value, address recipient) restricted public {
Request memory newRequest = Request({
description: description,
value: value,
restricted: restricted,
complete: false
});
requests.push(newRequest);
}
}
You can define the Request struct in this way and push it into requests array:
function createRequest(string description, uint value, address recipient) restricted public {
Request memory newRequest = Request(description, value, recipient, false);
requests.push(newRequest);
}
In this way, you can add the struct into your array and can retrieve with all parameters setted previously.
Because you're are using wrong argument(restricted) inside you Request type
try this:
Request memory newRequest = Request({
descritption: descritpion,
value: value,
recipient: recipient,
complete: false
});

Solidity struct arrar

I'm running into a problem with solidity with structures containing arrays, can you help me see what I'm missing?Any help would be greatly appreciated!
struct Info {
uint a;
uint256 b;
uint[] data;
}
mapping(address => Info) infos;
function set() public {
infos[msg.sender].a = 1;
infos[msg.sender].b = 2;
infos[msg.sender].data.push(3);
}
function get() public {
infos[msg.sender].a; //yes It is equal to 1
infos[msg.sender].b; //yes It is equal to 2
infos[msg.sender].data[0]; //The problem here is that anyone calling this function can read data[0]=3
}
I am a little confused as to what you require, but first solution I have provided modifies your Smart Contract such that mapping object infos and the getter function is both private (available only in the Contract defined).
contract test{
struct Info {
uint a;
uint b;
uint[] data;
}
mapping(address => Info) private infos;
function set() public {
infos[msg.sender].a = 1;
infos[msg.sender].b = 2;
infos[msg.sender].data.push(3);
}
function get() private view{
infos[msg.sender].a; //yes It is equal to 1
infos[msg.sender].b; //yes It is equal to 2
infos[msg.sender].data[0]; //The problem here is that anyone calling this function can read data[0]=3
} }
Second solution is to add something called 'require' in the getter function so that only the person who deploys the Smart Contract can view the array index. The constructor function assigns the person who deploys the contract as the 'owner'.
contract test{
struct Info {
uint a;
uint b;
uint[] data;
}
address owner;
constructor() {
owner = msg.sender;
}
mapping(address => Info) infos;
function set() public {
infos[msg.sender].a = 1;
infos[msg.sender].b = 2;
infos[msg.sender].data.push(3);
}
function get() public view{
infos[msg.sender].a; //yes It is equal to 1
infos[msg.sender].b; //yes It is equal to 2
require(owner == msg.sender, 'you cannot read this data, you are not the owner!');
infos[msg.sender].data[0]; //The problem here is that anyone calling this function can read data[0]=3
}
}
Let me know if I have misunderstood your question.

how to get correct address using ecrecover in tron

The code block of getting signer address via ecrecover in solidity contract code is working well with Ethereum but in TRON it is returning wrong address
My contract side code is
function validate(string memory strTest,uint8 v, bytes32 r, bytes32 s) public view returns(address){
bytes32 prefixedHash = keccak256(strTest);
return ecrecover(keccak256(prefixedHash),v,r,s);
// return ecrecover(prefixedHash,v,r,s):
}
and dapp side code is
msg = tronWeb.sha3("this is test string");
var signature = await tronWeb.trx.sign(msg);
var r=signature.substr(0,66);
var s= "0x" + signature.substr(66,64);
var v="0x" + signature.substr(signature.length-2);
retValue = await thisContractInstance.validate("this is test string",v,r,s).call();
but in both cases ( one case is commented in contract side code) getting wrong signer address in TRON shasta network
Are you trying to sign a string or sign transaction? #ashwin
I had the same kind of issues signing a string, and the below helped me out.
Tronweb uses different methods for signing transactions and signing strings.
1) For transactions you can refer this: https://github.com/TRON-US/tronweb/blob/master/src/lib/trx.js#L651,
2) Regarding signing string, it uses
ethers.utils.SigningKey.signDigest ()
of Ethereum: https://docs.ethers.io/ethers.js/html/api-advanced.html?highlight=signingkey#id8, note that the final v byte will always be nomalized for Solidity (either 27 or 28)
If you are trying to sign the msg as mentioned here,
var signature = await tronWeb.trx.sign(msg);
you can follow the second.
You could refer the article https://medium.com/#coredevs/verifying-elliptic-curve-digital-signature-with-tron-smart-contract-5d11347e7b5b.
This will be useful to accomplish signing the strings,
along with the above answer provided by #Aldo.
Happy coding.
Taken from here:
The smart contract code:
contract Verifier {
function recoverAddr(bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) returns (address) {
return ecrecover(msgHash, v, r, s);
}
function isSigned(address _addr, bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) returns (bool) {
return ecrecover(msgHash, v, r, s) == _addr;
}
}
The client code:
const ethers = tronWeb.utils.ethersUtils;
let contract = await tronWeb.contract().at(contract_address);
let signingKey = new ethers.SigningKey(tronWeb.defaultPrivateKey);
let message = "This is some message";
let messageBytes = ethers.toUtf8Bytes(message);
let messageDigest = ethers.keccak256(messageBytes);
let signature = signingKey.signDigest(messageDigest);
let hexAddress = await contract.recoverAddr(messageDigest, signature.v, signature.r, signature.s).call();
According to https://github.com/tronprotocol/tronweb/blob/1435436f83b910f19e9205998e348ea093732ce5/src/lib/trx.js#L629
tronWeb.trx.sign() does the following
Pass in 32 bytes of hash
The prefix "\x19TRON Signed Message:\n32" needs to be added first
Generate a new hash with the keccak256 algorithm
Signature (TronLink or private key)
Therefore, when using solidity's ecrecover, the hash of step 3 is passed in.
function getHash(hash) {
hash = hash.replace(/^0x/, '')
if (!tronWeb.utils.isHex(hash)) {
return
}
if (hash.length !== 64) {
return
}
const {
keccak256,
toUtf8Bytes
} = tronWeb.utils.ethersUtils
const hashArray = tronWeb.utils.code.hexStr2byteArray(hash)
const TRX_MESSAGE_PREFIX = toUtf8Bytes('\x19TRON Signed Message:\n32')
return keccak256([
...TRX_MESSAGE_PREFIX,
...hashArray
])
}

How to set default parameters to functions in Solidity

I came across below example from the Solidity Documentation and have similar code in my project and want to set default value to key parameter if the key is not passed from the caller
pragma solidity ^0.4.0;
contract C {
function f(uint key, uint value) public {
// ...
}
function g() public {
// named arguments
f({value: 2, key: 3});
}
}
My questions are -
Do Solidity language provides default parameters?
How to achieve the same if default parameters are not allowed then?
Appreciate the help?
Solidity does not support default parameters, but it is on their roadmap (see https://github.com/ethereum/solidity/issues/232). To work around this, just use function overloading:
pragma solidity ^0.4.0;
contract C {
function f(uint key, uint value) public {
// ...
}
function h(uint value) public {
f(123, value);
}
function g() public {
// named arguments
f({value: 2, key: 3});
}
function i() public {
h({value: 2});
}
}
Openzeppelin does a great job exemplifying how you can make "default" arguments. Check out their SafeMath Library.
In it, they have two sub (subtraction) contracts that are identical visibility and mutability wise- but a key difference:
function sub(
uint256 a,
uint256 b
)internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
The first one by default takes two arguments a & b (which will be subtracted). If a third argument is not given (the error statement) it will default to
SafeMath: subtraction overflow
If a third argument is given, it will replace that error statement.
Essentially:
pragma solidity >=0.6.0 <0.9.0;
contract C {
function f(unit value) public {
uint defaultVal = 5;
f(defaultVal, value);
function f(uint key, uint value) public {
// ...
}
function g() public {
// named arguments
f(2, 3);
}
}