web3p / web3.php

A php interface for interacting with the Ethereum blockchain and ecosystem. Native ABI parsing and smart contract interactions.
MIT License
1.17k stars 555 forks source link

Error -> rlp: input string too long for common.Address, decoding into (types.LegacyTx).To #347

Open metawalletpsg opened 9 months ago

metawalletpsg commented 9 months ago

I am trying to interact with the mintNFT function of an ERC721 contract defined by me on the Mumbai network. I am having the error:

rlp: input string too long for common.Address, decoding into (types.LegacyTx).To

I've been trying to find the error in my code for days. But I'm not sure how I could interact with my function using the web3php library.

I have a nodeJS application that already interacts correctly with the mintNFT function of my contract on the mumba network.

Could someone give me some information about my error, how to fix it, or if you think I'm doing something wrong?


require './config.php';
require './vendor/autoload.php';

use Web3\Providers\HttpProvider;
use Web3\Contract;
use Web3\Web3;
use Web3\Utils;
use Web3p\EthereumTx\Transaction as EthereumTx;

// Asegura que las cadenas hexadecimales tengan longitud par
function ensureEvenLength($hexString) {
    $hexString = str_replace('0x', '', $hexString);
    if (strlen($hexString) % 2 != 0) {
        $hexString = '0' . $hexString;
    }
    return $hexString;
}

// Firma la transacción utilizando la clave privada
function signTransaction($transaction, $privateKey) {
    $tx = new EthereumTx($transaction);
    $tx->sign($privateKey);
    return '0x' . $tx->serialize();
}

// Datos Web3
$timeout = 30;
$rpcUrl = $endpointMumbai;
$provider = new HttpProvider($rpcUrl, $timeout);
$abi = $contractABI;
$contractAddress = $contractAddressMumbai;
$fromAddress = $ownerAddress;
$privateKey = $privateKeyWallet;

$web3 = new Web3($provider);

$contract = new Contract($provider, $abi);
$contract->at($contractAddress);

$recipient = $fromAddress;
$tokenName = 'Test php Mint';
$tokenURI = 'https://gateway.pinata.cloud/ipfs/Qma5ciw8u3XE2FcRfYU5HNChshWQJsifN93f1RdwvbUJkg';
$id_certificado = 'encrypted_data_001';

$transactionData = $contract->getData('mintNFT', $recipient, $tokenName, $tokenURI, $id_certificado);

// $recipientEncoded = Utils::toHex($recipient);
// $tokenNameEncoded = Utils::toHex($tokenName);
// $tokenURIEncoded = Utils::toHex($tokenURI);
// $idCertificadoEncoded = Utils::toHex($id_certificado);
// $transactionData = $recipientEncoded . $tokenNameEncoded . $tokenURIEncoded . $idCertificadoEncoded;

// Obtener nonce de manera asincrónica
$web3->eth->getTransactionCount($fromAddress, 'pending', function ($err, $nonce) use (
    $contract, 
    $contractAddress, 
    $fromAddress, 
    $transactionData, 
    $privateKey, 
    $web3, 
    $recipient, 
    $tokenName, 
    $tokenURI, 
    $id_certificado
    ) {
    if ($err !== null) {
        echo 'Error al obtener el nonce: ' . $err->getMessage();
        return;
    }

    echo 'contractAddress: ' . $contractAddress . PHP_EOL;
    echo 'fromAddress: ' . $fromAddress . PHP_EOL;
    echo 'privateKey: ' . $privateKey . PHP_EOL;
    echo 'recipient: ' . $recipient . PHP_EOL;
    echo 'tokenName: ' . $tokenName . PHP_EOL;
    echo 'tokenURI: ' . $tokenURI . PHP_EOL;
    echo 'id_certificado: ' . $id_certificado . PHP_EOL;
    echo 'nonce: ' . $nonce . PHP_EOL;
    echo 'transactionData: ';
    var_dump($transactionData);

    // Estimar el gas necesario para la transacción
    $contract->estimateGas('mintNFT', $recipient, $tokenName, $tokenURI, $id_certificado, ['from' => $fromAddress], function ($err, $gas) use ($nonce, $contractAddress, $fromAddress, $transactionData, $privateKey, $web3) {
        if ($err !== null) {
            echo 'Error al estimar el gas: ' . $err->getMessage();
            return;
        }

        // Convierte el valor estimado de gas a una cadena hexadecimal
        $gasValue = ensureEvenLength($gas->toString());
        $gasPrice = '0x9184e72a000';

        // Construir la transacción
        $transaction = [
            'nonce' => ensureEvenLength($nonce->toString()),
            'from' => $fromAddress,
            'to' => ensureEvenLength($contractAddress),
            'gas' => ensureEvenLength($gasValue),
            'gasPrice' => ensureEvenLength($gasPrice),
            'value' => ensureEvenLength('0x0'),
            'data' => ensureEvenLength($transactionData),
            'chainId' => ensureEvenLength('0x80001'),
        ];

        // Firmar y enviar la transacción
        $signedTransaction = signTransaction($transaction, $privateKey);
        $web3->eth->sendRawTransaction($signedTransaction, function ($err, $tx) {
            if ($err !== null) {
                echo 'Error al enviar la transacción: ' . $err->getMessage();
                return;
            }
            echo 'Transacción enviada con éxito. TX Hash: ' . $tx . PHP_EOL;
        });
    });
});

And this is my contract:

pragma solidity 0.8.18;

contract CERTOKEN is ERC721URIStorage, Ownable {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("CERTOKEN", "CRTKN"){}

    function mintNFT(address recipient, string memory tokenName, string memory tokenURI, string memory id_certificado) public onlyOwner returns (uint256) {
        _tokenIds.increment();
        uint256 newTokenId = _tokenIds.current();
        _mint(recipient, newTokenId);
        _setTokenName(newTokenId, tokenName);
        _setTokenURI(newTokenId, tokenURI);
        emit AdditionalData(newTokenId, id_certificado);
        return newTokenId;
    }

    function _setTokenName(uint256 tokenId, string memory name) internal virtual {
        require(_exists(tokenId), "ERC721URIStorage: name set of nonexistent token");
        bytes memory nameBytes = bytes(name);
        require(nameBytes.length > 0, "ERC721URIStorage: name must be non-empty");
        emit TokenNameSet(tokenId, name);
    }

    event TokenNameSet(uint256 tokenId, string name);
    event AdditionalData(uint256 tokenId, string id_certificado);

    function _burn(uint256 tokenId) internal override(ERC721URIStorage) {
        super._burn(tokenId);
    }

    function burnNFT(uint256 tokenId) public onlyOwner returns (uint256) {
        _burn(tokenId);
        return 0;
    }

    function transferNFT(address to, uint256 tokenId) public {
        require(_exists(tokenId), "CERTOKEN: Token does not exist");
        _transfer(ownerOf(tokenId), to, tokenId);
    }

}