Publication
Partagez vos connaissances.
Solidity and ethers.js Compute Different Addresses from the Same Signature
This script:
const { ethers } = require('ethers');
async function recoverSigner(address, nonce, deadline, v, r, s) {
const domain = {
name: "RandomReachDebug5Local",
version: "1",
chainId: 31337,
verifyingContract: "0x8464135c8F25Da09e49BC8782676a84730C318bC",
};
const types = {
RequestRandomNFT: [
{ name: 'minter', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
};
const value = {
minter: address,
nonce: nonce,
deadline: deadline,
};
// Get the digest of the message
const digest = ethers.utils._TypedDataEncoder.hash(domain, types, value);
const sig = {
r: r,
s: s,
v: v,
};
if (sig.v < 27) {
sig.v += 27;
}
const signer = ethers.utils.recoverAddress(digest, sig);
return signer;
}
const address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266";
const nonce = "0";
const deadline = "1685162164";
const v = "28";
const r = "0xe0e4cc2f8b6bac3784f9feb3db4382291631d5f317d08a0b82305e5eb5ffc60a";
const s = "0x0416d521d12e26b8fc1f4bd566d5d67c5dffebe9564fe90db4f12c0a69b63d5e";
async function run() {
try {
const signer = await recoverSigner(address, nonce, deadline, v, r, s);
console.log(`The signer is: ${signer}`);
} catch (error) {
console.error(`Error in recovering signer: ${error}`);
}
}
run();
Produces this output: The signer is: 0x1AB26702A8068a247BD33a9555dfEf791d2BD68D
But this solidity contract:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
contract GetAddressFromSig is ERC721, EIP712 {
struct Request {
address minter;
uint256 nonce;
uint256 deadline;
}
bytes32 public constant REQUEST_TYPEHASH = keccak256("Request(address minter,uint256 nonce,uint256 deadline)");
// Initialize _DOMAIN_SEPARATOR directly with static values
bytes32 private immutable _DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes("RandomReachDebug5Local")), // static name
keccak256(bytes("1")), // static version
31337, // static chainId
0x8464135c8F25Da09e49BC8782676a84730C318bC // static verifyingContract
)
);
constructor(string memory name, string memory symbol) ERC721(name, symbol) EIP712(name, "1") {}
function domainSeparator() public view returns (bytes32) {
return _DOMAIN_SEPARATOR;
}
function recoverSigner(Request memory request, uint8 v, bytes32 r, bytes32 s) public view returns (address) {
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
_DOMAIN_SEPARATOR,
keccak256(
abi.encode(
REQUEST_TYPEHASH,
request.minter,
request.nonce,
request.deadline
)
)
)
);
// ECDSA.recover returns the address that is associated with the public key
// that was used to sign the given data, in this case, the digest.
return ECDSA.recover(digest, v, r, s);
}
}
Deployed with this script in hardhat:
import { ethers } from "hardhat";
const hre = require("hardhat");
const dotenv = require("dotenv");
dotenv.config();
async function main() {
const GetAddressFromSig = await hre.ethers.getContractFactory("GetAddressFromSig");
const gasPrice = await GetAddressFromSig.signer.getGasPrice();
console.log(`Current gas price: ${gasPrice}`);
const estimatedGas = await GetAddressFromSig.signer.estimateGas(
GetAddressFromSig.getDeployTransaction("RANDOM NFT 5", "RNFT5"),
);
console.log(`Estimated gas: ${estimatedGas}`);
const deploymentPrice = gasPrice.mul(estimatedGas);
const deployerBalance = await GetAddressFromSig.signer.getBalance();
console.log(`Deployer balance: ${ethers.utils.formatEther(deployerBalance)}`);
console.log(`Deployment price: ${ethers.utils.formatEther(deploymentPrice)}`);
const getAddressFromSig = await GetAddressFromSig.deploy("RANDOM NFT 5", "RNFT5");
await getAddressFromSig.deployed();
console.log("GetAddressFromSig deployed to:", getAddressFromSig.address);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
And ran with these commands in the hardhat console:
const Token = await ethers.getContractFactory("GetAddressFromSig");
const token = await Token.attach("0x8464135c8F25Da09e49BC8782676a84730C318bC");
const request = { minter: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", nonce: ethers.BigNumber.from("0"), deadline: ethers.BigNumber.from("1685162164") };
const v = 28
const r = "0xe0e4cc2f8b6bac3784f9feb3db4382291631d5f317d08a0b82305e5eb5ffc60a";
const s = "0x0416d521d12e26b8fc1f4bd566d5d67c5dffebe9564fe90db4f12c0a69b63d5e";
const signer = await token.recoverSigner(request, v, r, s);
console.log(`The signer is: ${signer}`);
Gives this output: The signer is: 0xeB7265f6625EaE66403a637c073E63ccf33b8Cdc
So why does the javascript calculate 0x1AB26702A8068a247BD33a9555dfEf791d2BD68D, while hardhat's solidity compiler calculates 0xeB7265f6625EaE66403a637c073E63ccf33b8Cdc?
- Smart Contract
- Solidity
Réponses
1I see one mismatch. REQUEST_TYPEHASH
uses the type name Request
. Type name in JavaScript when defining type is RequestRandomNFT
.
Also, you can try this alternative code for signing in JavaScript:
const value = {
minter: address,
nonce: nonce,
deadline: deadline,
};
const domainType = [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' }
];
const requestType = [
{ name: 'minter', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
];
const domainData = {
name: 'RandomReachDebug5Local',
version: '1',
chainId: 31337,
verifyingContract: '0x8464135c8F25Da09e49BC8782676a84730C318bC',
};
const dataToSign = JSON.stringify({
types: {
EIP712Domain: domainType,
Request: requestType,
},
domain: domainData,
primaryType: 'Request',
value,
});
const signature = await provider.send('eth_signTypedData_v4', [signerAddress, dataToSign]);
Connaissez-vous la réponse ?
Veuillez vous connecter et la partager.
Solidity is an object-oriented, high-level language for implementing smart contracts. It is a curly-bracket language designed to target the Ethereum Virtual Machine (EVM).
Gagne ta part de 1000 Sui
Gagne des points de réputation et obtiens des récompenses pour avoir aidé la communauté Sui à se développer.
- My ERC721 contract successfully deploys, but I can't verify the contract's source code with hardhat21
- Solidity and ethers.js Compute Different Addresses from the Same Signature21
- can't understand what are the locations(uint256)22
- How to reverse keccak256 in solidity22
- Clarification on Gas Refunds and Comparison Between "require" and "revert" in Smart Contracts21