Bài viết
Chia sẻ kiến thức của bạn.
Tại sao Solidity tạo ra một địa chỉ khác với một khóa riêng tư hơn ether.js?
Tôi có chức năng này trong hợp đồng vững chắc của tôi:
function requestRandomNFT(
address minter,
uint256 nonce,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s,
uint256 randomUint256
) external payable {
require(block.timestamp <= deadline, "Request has expired");
require(nonce == _nonces[minter].current(), "Nonce does not match expected value");
bytes32 structHash = keccak256(
abi.encode(
_REQUEST_RANDOM_NFT_TYPEHASH,
keccak256(
abi.encode(
minter,
nonce,
deadline
)
)
)
);
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, v, r, s);
emit Verified(signer, nonce, minter, r, s, v, signer);
console.log("below this is signer");
console.log(signer);
console.log("below this is aithorizedAccount");
console.log(authorizedAccount);
require(signer == authorizedAccount, ERR_INVALID_SIGNER);
bytes32 requestId = keccak256(abi.encodePacked(signer, nonce));
_nonces[minter].increment();
emit RequestedRandom(requestId);
// Auto mint NFT
mintNFT(minter, requestId, randomUint256);
}
I used import "hardhat/console.sol";
to write logs to the console.
This is my minting code:
import { ethers } from 'ethers';
import { useAccount } from "wagmi";
import { useContractWrite, useWaitForTransaction, usePrepareContractWrite } from 'wagmi';
import RandomReachDebug5Local from "../app/contracts/RandomReachDebug5Local.json";
import { useState, useEffect, useCallback } from 'react';
import { parseGwei } from 'viem'
// Function to get a signature for the random NFT request
async function signRandomNFTRequest(account, nonce, deadline) {
const privateKey = "0x REST OF MY PRIVATE KEY";
const wallet = new ethers.Wallet(privateKey);
const domain = {
name: "RandomReachDebug5Local",
version: "1",
chainId: 31337, // chainId for local node (Ganache or Hardhat)
verifyingContract: "0x8464135c8F25Da09e49BC8782676a84730C318bC", // replace with your contract address
};
const types = {
RequestRandomNFT: [
{ name: 'minter', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
};
const value = {
minter: account,
nonce: nonce,
deadline: deadline,
};
const signature = await wallet._signTypedData(domain, types, value);
const sig = ethers.utils.splitSignature(signature);
console.log("Signature: ", sig);
return sig;
}
export function useMintNFT() {
const { address: connectedAddrs, provider } = useAccount();
const [contract, setContract] = useState(null);
const [sigData, setSigData] = useState(null);
const [args, setArgs] = useState([]);
const [fetchNonceError, setFetchNonceError] = useState(null);
const randomReachDebug5Address = "0x8464135c8F25Da09e49BC8782676a84730C318bC"; // replace with your contract address
// Instantiate the contract
const initializeContract = useCallback(async () => {
if (window.ethereum && randomReachDebug5Address) {
console.log("initContract is running");
// If you use MetaMask
// const provider = new ethers.providers.Web3Provider(window.ethereum);
// If you use a local node (e.g., Ganache)
const provider = new ethers.providers.JsonRpcProvider('http://localhost:8545');
const balance = await provider.getBalance(connectedAddrs);
console.log("Balance: ", ethers.utils.formatEther(balance));
const contractInstance = new ethers.Contract(randomReachDebug5Address, RandomReachDebug5Local.abi, provider.getSigner());
console.log(`contract is set here: ${contractInstance}`);
if (!sigData) {
setContract(contractInstance);
try {
const nonce = await contractInstance.nonces(connectedAddrs);
console.log("Nonce fetched: ", nonce);
const deadline = Math.floor(Date.now() / 1000) + 120; // 2 minutes from now
const sig = await signRandomNFTRequest(connectedAddrs, nonce, deadline);
setSigData(sig);
const randomUint256 = ethers.utils.hexlify(ethers.BigNumber.from(ethers.utils.randomBytes(32))); // generating random uint256
const argsInUseEffect = [connectedAddrs, nonce.toString(), deadline, sig.v, sig.r, sig.s, randomUint256];
console.log("Args in use effect: ", argsInUseEffect);
setArgs(argsInUseEffect);
} catch (error) {
console.error("Error fetching nonce: ", error);
setFetchNonceError(error);
}
}
console.log(`sig is here: ${sigData}`);
console.log(`args is here: ${args}`);
}
}, [args, connectedAddrs, randomReachDebug5Address, setContract]);
useEffect(() => {
initializeContract();
}, [initializeContract]);
console.log(`args outside of use effect ${args}`);
const { config, prepareError, isPrepareError } = usePrepareContractWrite({
address: randomReachDebug5Address,
abi: RandomReachDebug5Local.abi,
functionName: 'requestRandomNFT',
args: args,
value: '10000000000000000', // This is 0.01 Ether represented in Wei
gas: 300000n, // Set your desired gas limit here
gasPrice: parseGwei('50'),
});
console.log(`this is config: ${config}`);
const { data, error, isError, write } = useContractWrite(config || {});
console.log(`this is the error ${error} and this is the error bool ${isError}`);
const { isLoading, isSuccess } = useWaitForTransaction({hash: data?.hash});
const mintNFT = () => {
if (sigData) {
console.log('Minting...');
write?.();
} else {
console.error('sigData is not defined.');
}
};
return {
mintNFT,
isLoading,
isSuccess,
isError,
error,
data,
write,
isPrepareError,
prepareError,
fetchNonceError
};
}
So here's the weird thing... When I ran the minting code within a next.js app, I got this in my console for the hardhat node:
console.log:
below this is signer
0x2d0b2215d4e00807a6982877a9762ef41541ecef
below this is aithorizedAccount
0x1ab26702a8068a247bd33a9555dfef791d2bd68d
But the private key I used gives me the address 0x1AB26702A8068a247BD33a9555dfEf791d2BD68D when I test it in javascript with ethers.js, but solidity gives me 0x2d0b2215d4e00807a6982877a9762ef41541ecef ???
I used this script with const privateKey = "0x REST OF MY PRIVATE KEY":
const ethers = require('ethers');
function getAddressFromPrivateKey(privateKey) {
const wallet = new ethers.Wallet(privateKey);
return wallet.address;
}
const privateKey = "0x REST OF MY PRIVATE KEY";
console.log(getAddressFromPrivateKey(privateKey)); // This should log your expected address
Mã này cho tôi 0x1AB26702A8068A247BD33A9555DFEF791D2BD68D, nhưng mã rắn của tôi cho tôi 0x2d0b2215d4e00807a6982877a9762ef41541ecef. Điều đó chẳng có ý nghĩa gì cả. Tại sao chuyện này lại xảy ra?
- Smart Contract
- Solidity
Bằng cách nhìn vào mã, tôi không thấy bất kỳ vấn đề nào. Bạn có thể chia sẻ giá trị cho`_REQUEST_RANDOM_NFT_TYPEHASH`?
I was actually able to figure out the problem. I just answered it. Thanks for following up though!
Câu trả lời
1The problem was 1 little naming inconsistency. It took me a really a long time to figure it out.
This is types
in my minting code:
const types = {
Request: [
{ name: 'minter', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
};
I didn't display _REQUEST_RANDOM_NFT_TYPEHASH
in the smart contract, but it looks like this:
bytes32 internal constant REQUEST_TYPEHASH = keccak256(bytes("RequestRandom(address minter,uint256 nonce,uint256 deadline)"));
Notice in _REQUEST_RANDOM_NFT_TYPEHASH, the first word is RequestRandom
, and in types
(within the minting code), the first word is Request
. That word needs to be the same. I made them both Request
and the addresses matched.
Bạn có biết câu trả lời không?
Hãy đăng nhập và chia sẻ nó.
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).
- My ERC721 contract successfully deploys, but I can't verify the contract's source code with hardhat21
- Solidity và ethers.js Tính toán các địa chỉ khác nhau từ cùng một chữ ký21
- không thể hiểu các vị trí là gì (uint256)22
- Làm thế nào để đảo ngược keccak256 trong độ rắn22
- Làm rõ về hoàn tiền gas và so sánh giữa “yêu cầu” và “hoàn lại” trong hợp đồng thông minh21