Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.1 Signing messages #7

Open
wants to merge 2 commits into
base: contract-calls
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .openzeppelin/goerli.json
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,22 @@
],
"storageDiff": []
}
},
"Verifier": {
"address": "0xB735f8730debFF357593dba17a7Fa3dD783b3DAe",
"constructorCode": "608060405234801561001057600080fd5b506105e7806100206000396000f3fe",
"bodyBytecodeHash": "cdcbeb651e8382f67e592daa834afb098964fcd557a81f930da622eb8eef0c64",
"localBytecodeHash": "52180514532af933f2e70d0473a69942db0b6637089152e6560d45ec6eeb3e58",
"deployedBytecodeHash": "52180514532af933f2e70d0473a69942db0b6637089152e6560d45ec6eeb3e58",
"types": {},
"storage": [],
"warnings": {
"hasConstructor": false,
"hasSelfDestruct": false,
"hasDelegateCall": false,
"hasInitialValuesInDeclarations": false,
"uninitializedBaseContracts": []
}
}
},
"solidityLibs": {},
Expand All @@ -307,6 +323,15 @@
"admin": "0x5c19BF66CC2c9386Cdf06d346F32F140A4559be9",
"kind": "Upgradeable"
}
],
"ledger-academy/Verifier": [
{
"address": "0xB0e0f956693eC1e990EB95C3a435B80548F7db1b",
"version": "1.0.0",
"implementation": "0xB735f8730debFF357593dba17a7Fa3dD783b3DAe",
"admin": "0x5c19BF66CC2c9386Cdf06d346F32F140A4559be9",
"kind": "Upgradeable"
}
]
},
"manifestVersion": "2.2",
Expand Down
3 changes: 2 additions & 1 deletion .openzeppelin/project.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"manifestVersion": "2.2",
"contracts": {
"ADIToken": "ADIToken"
"ADIToken": "ADIToken",
"Verifier": "Verifier"
},
"dependencies": {
"@openzeppelin/contracts-ethereum-package": "^3.0.0"
Expand Down
1 change: 1 addition & 0 deletions contracts/Verifier.json
23 changes: 23 additions & 0 deletions contracts/Verifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
pragma solidity ^0.6.0;

import "@openzeppelin/contracts-ethereum-package/contracts/cryptography/ECDSA.sol";

// https://www.codementor.io/@yosriady/signing-and-verifying-ethereum-signatures-vhe8ro3h6
// -> part of oz: https://docs.openzeppelin.com/contracts/3.x/api/cryptography#ECDSA-recover-bytes32-bytes-

contract Verifier {
function recoverAddr(
bytes32 msgHash,
bytes memory signature
) public pure returns (address) {
return ECDSA.recover(msgHash, signature);
}

function recoverAddrFromNonEthHash(
bytes32 msgHash,
bytes memory signature
) public pure returns (address) {
bytes32 ethHash = ECDSA.toEthSignedMessageHash(msgHash);
return recoverAddr(ethHash, signature);
}
}
9 changes: 8 additions & 1 deletion src/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import Web3 from "web3";
import ADIToken from "./contracts/ADIToken.json";
import TransferForm from "./TransferForm";
import _secrets from "../.secrets.json";
import SignForm from "./SignForm";
import VerifyForm from "./VerifyForm";

const Main: React.FC = () => {
const { account, library: web3 } = useWeb3React<Web3>();
Expand Down Expand Up @@ -36,7 +38,6 @@ const Main: React.FC = () => {
const readableAdiBalance = Web3.utils.fromWei(_adiBalance);
setADIBalance(readableAdiBalance);
}

})();
}, [web3]);

Expand All @@ -53,9 +54,15 @@ const Main: React.FC = () => {
<small>({_secrets.contractAddress})</small>
</p>
<p>to spare with others.</p>

<h2>Transfer ADI</h2>
{adiBalance && (
<TransferForm updateBalance={queryADIBalance}></TransferForm>
)}
<h2>Sign a message</h2>
<SignForm /> <br/>
<h2>Verify a message</h2>
<VerifyForm /> <br/>
</div>
);
};
Expand Down
37 changes: 37 additions & 0 deletions src/SignForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { useState } from "react";
import { useWeb3React } from "@web3-react/core";
import Web3 from "web3";

const SignForm = () => {
const { account, library: web3 } = useWeb3React<Web3>();
const [message, setMessage] = useState<string>("");

const [signature, setSignature] = useState<string>("");

async function signMessage() {
const signed = await web3.eth.personal.sign(message, account, "")
setSignature(signed);
}

return (
<div>
<label htmlFor="address">Message</label>
<input
type="text"
value={message}
onChange={(e) => setMessage(e.target.value)}
/>

<button disabled={!message} onClick={signMessage}>
Sign!
</button>
<br />
{signature &&
<small><b>Signature: {signature}</b></small>
}

</div>
);
};

export default SignForm;
104 changes: 104 additions & 0 deletions src/VerifyForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React, { useState } from "react";
import { useWeb3React } from "@web3-react/core";
import Web3 from "web3";
import VerifierABI from "./contracts/Verifier.json";

import _secrets from "../.secrets.json";

const VerifyForm = () => {
const { library: web3, account } = useWeb3React<Web3>();
const [message, setMessage] = useState<string>("");
const [signature, setSignature] = useState<string>("");
const [localVerificationResult, setLocalVerificationResult] = useState<string>("");
const [contractVerificationResult, setContractVerificationResult] = useState<string>("");
const [nonEthSignatureVerificationResult, setNonEthSignatureVerificationResult] = useState<string>("");

const contract = new web3.eth.Contract(
VerifierABI.abi,
_secrets.verifierContractAddress
);

// this will only work with messages that have been a hash by itself ;)
async function verifyNonEthSignatureOnContract() {
const nonEthMessageHash = web3.utils.sha3(message);
const recovered = await contract.methods.recoverAddrFromNonEthHash(
nonEthMessageHash,
signature
).call()

console.log(recovered);
setNonEthSignatureVerificationResult(recovered);
}

async function verifySignatureOnContract() {
const verifiableMessage = `\x19Ethereum Signed Message:\n${message.length}${message}`;
const verifiableMessageSha = web3.utils.sha3(verifiableMessage);

const recovered = await contract.methods.recoverAddr(
verifiableMessageSha,
signature
).call()

console.log(recovered);
setContractVerificationResult(recovered);
}

async function verifySignatureLocally() {
const recovered = await web3.eth.personal.ecRecover(message, signature);
console.log(recovered);
setLocalVerificationResult(web3.utils.toChecksumAddress(recovered));
}

async function verifySignature() {
verifySignatureLocally();
verifySignatureOnContract();
verifyNonEthSignatureOnContract();
}

function eqAccount(addr: string) {
return addr === account
}
return (
<div>
<label>Message</label>
<input
type="text"
value={message}
onChange={(e) => setMessage(e.target.value)}
/>

<label>Signature</label>
<input
type="text"
value={signature}
onChange={(e) => setSignature(e.target.value)}
/>

<button disabled={!message} onClick={verifySignature}>
Verify!
</button>

<br />

{ localVerificationResult &&
<small style={{color: eqAccount(localVerificationResult) ? 'green':'red'}}>
local verification: {localVerificationResult}
<br />
</small>
}
{ contractVerificationResult &&
<small style={{color: eqAccount(contractVerificationResult) ? 'green':'red'}}>
contract verification: {contractVerificationResult} <br />
</small>
}
{ nonEthSignatureVerificationResult &&
<small style={{color: eqAccount(nonEthSignatureVerificationResult) ? 'green':'red'}}>
non eth signed verification: {nonEthSignatureVerificationResult}
</small>
}

</div>
);
};

export default VerifyForm;
1 change: 1 addition & 0 deletions src/contracts/Verifier.json