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 });
}
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
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;
}
}
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.
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;
}
}
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);
O jogador pode então interagir com o contrato inteligente para reivindicar seu prêmio. Mais informações aqui.
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.
Latest comments (0)