Solidity.

Bài viết

Chia sẻ kiến thức của bạn.

Christian O'Connor.
May 26, 2023
Hỏi đáp Chuyên Gia

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
1
1
Chia sẻ
Bình luận
.
Sergey Ilin.
Jun 2 2023, 04:50

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`?

Christian O'Connor.
Jun 2 2023, 05:32

I was actually able to figure out the problem. I just answered it. Thanks for following up though!

Câu trả lời

1
Christian O'Connor.
Jun 2 2023, 05:28

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

0
Câu trả lời hay nhất
Bình luận
.

Bạn có biết câu trả lời không?

Hãy đăng nhập và chia sẻ nó.

Chúng tôi sử dụng cookie để đảm bảo bạn có trải nghiệm tốt nhất trên trang web của chúng tôi.
Thêm thông tin