WEB3DEV

Cover image for Como verificar uma mensagem assinada em Solidity
Dimitris Carvalho Calixto
Dimitris Carvalho Calixto

Posted on

Como verificar uma mensagem assinada em Solidity

Introdução

Este é um tutorial prático sobre como assinar uma mensagem usando a MetaMask e depois verificá-la na cadeia.

Aqui está uma demonstração: https://leon-do.github.io/ecrecover/

Assinatura

Sign Message

  async function signMessage() {

    if (!window.ethereum) return alert("Please Install Metamask");

    // conectar e obter conta metamask

    const accounts = await ethereum.request({ method: "eth_requestAccounts" });

    // mensagem a ser assinada

    const message = "hello";

    console.log({ message });

    // mensagem hash

    const hashedMessage = Web3.utils.sha3(message);

    console.log({ hashedMessage });

    // assinando mensagem hashed

    const signature = await ethereum.request({

    method: "personal_sign",

    params: [hashedMessage, accounts[0]],

    });

    console.log({ signature });

    // assinatura separada

    const r = signature.slice(0, 66);

    const s = "0x" + signature.slice(66, 130);

    const v = parseInt(signature.slice(130, 132), 16);

    console.log({ r, s, v });

  }

Enter fullscreen mode Exit fullscreen mode

Notas

  • Este código está usando o método personal_sign para evitar gastos com transações acidentais. Isto estará relacionado com o prefixo \x19Ethereum Signed Message:\n32 encontrado no contrato inteligente (abaixo).
  • Isto é a assinatura da mensagem codificada em hash.

Assinatura

Abaixo estão as informações necessárias para verificar uma assinatura. Use isto em seu contrato inteligente.


hashedMessage = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8

r = 0xb7cf302145348387b9e69fde82d8e634a0f8761e78da3bfa059efced97cbed0d

s = 0x2a66b69167cafe0ccfc726aec6ee393fea3cf0e4f3f9c394705e0f56d9bfe1c9

v = 28

Enter fullscreen mode Exit fullscreen mode

Contrato Inteligente

Criar o contrato Solidity


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract Verify {

    function VerifyMessage(bytes32 _hashedMessage, uint8 _v, bytes32 _r, bytes32 _s) public pure returns (address) {

        bytes memory prefix = "\x19Ethereum Signed Message:\n32";

        bytes32 prefixedHashMessage = keccak256(abi.encodePacked(prefix, _hashedMessage));

        address signer = ecrecover(prefixedHashMessage, _v, _r, _s);

        return signer;

    }

}

Enter fullscreen mode Exit fullscreen mode

Notas

  • Observe que o prefixo,\x19Ethereum Signed Message:\n32 é necessário para verificar uma mensagem assinada.
  • O prefixo é codificado em hash junto com a mensagem.
  • ecrecover deve retornar o endereço do signatário.

Verifique em Solidity

Insira a mensagem codificada em hash e a assinatura (r, s, v) para verificar o endereço.

Image

Caso de uso: Jogo da Unidade

  • O desenvolvedor do jogo cria um jogo, servidor e um contrato inteligente que emite prêmios se o jogador ganhar.
  • O jogador ganha e diz ao desenvolvedor do jogo que ganhou
  • O servidor do jogo fornece ao jogador uma assinatura (explicada acima) que permite que o usuário reivindique. Pense nisto como um cupom.
  • O jogador então interage com o contrato e apresenta a assinatura (cupom) para reivindicar seu prêmio.

Exemplo de contrato inteligente implantado pelo desenvolvedor de jogos:


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// desenvolvedor de jogos faz o contrato de implantação

contract Verify {

    // conta do desenvolvedor do jogo

    address public owner = 0xdD4c825203f97984e7867F11eeCc813A036089D1;

    // jogador reivindica preço

    function claimPrize(bytes32 _hashedMessage, uint8 _v, bytes32 _r, bytes32 _s) public view returns (bool) {

        bytes memory prefix = "\x19Ethereum Signed Message:\n32";

        bytes32 prefixedHashMessage = keccak256(abi.encodePacked(prefix, _hashedMessage));

        address signer = ecrecover(prefixedHashMessage, _v, _r, _s);

        // se a assinatura for assinada pelo proprietário

        if (signer == owner) {

            // dê ao jogador (msg.sender) um prêmio

            return true;

        }

        return false;

    }

}

Enter fullscreen mode Exit fullscreen mode

Depois de ganhar, o jogador recebe uma assinatura (cupom) do servidor do jogo para reivindicar seu prêmio

0xb7cf302145348387b9e69fde82d8e634a0f8761e78da3bfa059efced97cbed0d2a66b69167cafe0ccfc726aec6ee393fea3cf0e4f3f9c394705e0f56d9bfe1c91c

O jogador analisa a assinatura em Unity


string signature = "0xb7cf302145348387b9e69fde82d8e634a0f8761e78da3bfa059efced97cbed0d2a66b69167cafe0ccfc726aec6ee393fea3cf0e4f3f9c394705e0f56d9bfe1c91c";

string r = signature.Substring(0, 66);

string s = "0x" + signature.Substring(66, 64);

int v = int.Parse(signature.Substring(130, 2), System.Globalization.NumberStyles.HexNumber);

Enter fullscreen mode Exit fullscreen mode

O jogador pode então interagir com o contrato inteligente para reivindicar seu prêmio. Mais informações aqui.

Image

Conclusão

Tem mais perguntas? Entre em nosso discord - temos uma comunidade próspera ❤️🔥

off-topic-lounge para consultas gerais.

gaming-general para chat de desenvolvimento de jogos.

gaming-showcase para mostrar suas coisas.

Sobre ChainSafe

ChainSafe é líder em desenvolvimento de blockchains e soluções de infra-estrutura para web3. Estamos trabalhando para um futuro mais descentralizado, construindo implementações de clientes para Ethereum, Filecoin, Polkadot, e Mina. Também estamos mantendo a biblioteca web3.js, trabalhando em um SDK de jogos que conecta NFTs à Unidade, construindo uma aplicação de armazenamento distribuído em nuvem e iniciando uma ponte de múltiplas cadeias. Para saber mais, clique aqui.

Quer ajudar a construir os alicerces da web3? Junte-se a nós!

Tem alguma pergunta, comentário ou sugestão? Entre em nosso Discord e junte-se à conversa! Também estamos sempre à procura de pessoas talentosas. Confira nossas posições abertas e entre em contato ➡️➡️ [email protected]

Artigo escrito por Leon Do. A versão original pode ser encontrada aqui. Traduzido e adaptado por Dimitris Calixto.

Oldest comments (0)