how to get correct address using ecrecover in tron - solidity

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
])
}

Related

How do I call diamondCut (EIP-2535) from another contract?

I'm trying to call execute the diamondCut function using another contract, but it keeps getting reverted, even though all the facet addresses and respective function selectors exist and are included in the call. I'm trying to do the following:
Remove 3 functions, each function is in a separate facet, using the cutSomeDiamonds function in this contract
The interfaces used are in https://github.com/mudgen/diamond-1-hardhat/tree/main/contracts/interfaces
contract ExecuteDiamondCuts {
address CONTRACT_ADDRESS = 0xblahblah; // dummy address
string[] functionsToRemove;
constructor() {
functionsToRemove.push("exampleFunctionA(address)");
functionsToRemove.push("exampleFunctionB(uint)");
functionsToRemove.push("exampleFunctionC()");
}
function cutSomeDiamonds() external {
IDiamondLoupe _loupe = IDiamondLoupe(CONTRACT_ADDRESS);
IDiamondCut.FacetCut[] memory _facetCuts = new IDiamondCut.FacetCut[](functionsToRemove.length);
for (uint i=0; i<functionsToRemove.length; i++) {
address facetWithFn = _loupe.facetAddress(bytes4(keccak256(bytes((functionsToRemove[i])))));
bytes4[] memory _fnSelectors = new bytes4[](1);
_fnSelectors[0] = bytes4(keccak256(bytes((functionsToRemove[i]))));
IDiamondCut.FacetCut memory _facetCut = IDiamondCut.FacetCut({
facetAddress: facetWithFn, // facet address
action: IDiamondCut.FacetCutAction.Remove, // action
functionSelectors: _fnSelectors // array of fn selectors
});
_facetCuts[i] = _facetCut;
}
(bool success,) = CONTRACT_ADDRESS.delegatecall(
abi.encodeWithSignature(
"diamondCut(FacetCut[],address,bytes)",
_facetCuts,
address(0),
"0x"
)
);
require(success);
}
}
Everything seems to work until require(success); which got reverted.

webjs execution reverting when calling deployed contract: var err = new Error('Returned error: ' + message)

I'm running the following javascript file and using web3js to call a smart contract (0xF3885ca057a42B10b6cb432B816FE11426a2E369) on Goerli:
const Web3 = require("web3");
// Loading the contract ABI
// (the results of a previous compilation step)
const fs = require("fs");
const { abi } = JSON.parse(fs.readFileSync("EtherSplitter.json"));
async function main() {
// Configuring the connection to an Ethereum node
const network = process.env.ETHEREUM_NETWORK;
const web3 = new Web3(
new Web3.providers.HttpProvider(
`https://${network}.infura.io/v3/${process.env.INFURA_PROJECT_ID}`
)
);
// Creating a signing account from a private key
const signer = web3.eth.accounts.privateKeyToAccount(
process.env.SIGNER_PRIVATE_KEY
);
web3.eth.accounts.wallet.add(signer);
// Creating a Contract instance
const contract = new web3.eth.Contract(
abi,
// Replace this with the address of your deployed contract
process.env.ETHERSPLITTER_CONTRACT
);
// Issuing a transaction that calls the splitEther method
const tx = contract.methods.splitEther(["0xdF8b511C3682b093736318A67Fcc2FEC6772D1a6","0x1E2eBeBB3348B1FeFC29239c20Df1c78668180Cc"]);
const receipt = await tx
.send({
from: signer.address,
value: 1e15, // IS THIS CORRECT? IF NOT, HOW DO I SPECIFY VALUE FOR SEND
gas: await tx.estimateGas(),
})
.once("transactionHash", (txhash) => {
console.log(`Mining transaction ...`);
console.log(`https://${network}.etherscan.io/tx/${txhash}`);
});
// The transaction is now on chain!
console.log(`Mined in block ${receipt.blockNumber}`);
}
require("dotenv").config();
main();
The smart contract is:
contract EtherSplitter {
function splitEther(address payable[] memory recipients) public payable {
uint fee = 10;
recipients[0].transfer(msg.value * fee / 100);
recipients[1].transfer(msg.value * (100 - fee) / 100);
}
receive() external payable {
}
}
Execution is reverting with the following error:
users/myusername/demo-eth-tx/node_modules/web3-core-helpers/lib/errors.js:28
var err = new Error('Returned error: ' + message);
I think I'm using send incorrectly, and incorrectly specifying the send value. How do I fix that?
Based on your code, seems like you mixed up some ether.js into your web3.js code coz in web3.js there when executing contract because in web3.js, function parameters doesn't need to be in an array like in ether.js
Try this
const tx = contract.methods.splitEther("0xdF8b511C3682b093736318A67Fcc2FEC6772D1a6","0x1E2eBeBB3348B1FeFC29239c20Df1c78668180Cc");

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.

Are the sign/recover function of web3js and solidity (not) interchangeable?

I'm trying to verify a signature created with web3js in Solidity, but do not get the correct signer.
In web3js:
var address = '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4'; // == msg.sender
var signature = web3.eth.accounts.sign(address, PRIVATE_KEY);
// check:
var signer = web3.eth.accounts.recover(signature.message, signature.signature);
console.log(signer); // == PUBLIC_KEY
In Solidity:
function verify(bytes memory signature) public view returns (address) {
bytes32 hash = keccak256(abi.encodePacked(msg.sender));
bytes32 messageHash = hash.toEthSignedMessageHash();
address signer = messageHash.recover(signature);
return signer; // != PUBLIC_KEY
}
signer in Solidity has different value than PUBLIC_KEY in web3js.
Tested by creating simple contract in Remix and calling verify() with signature from web3js.
Quick check I did was that
web3.utils.keccak256(address)
has same value as
keccak256(abi.encodePacked(msg.sender))
so address (= message signed) in web3js is same as msg.sender after hashing.

_signTypedData method on ethers does not match with ERC712 solidity code

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