forked from AmazingAng/WTF-Solidity
-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from AmazingAng/main
merge from current
- Loading branch information
Showing
126 changed files
with
6,053 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// SPDX-License-Identifier: MIT | ||
// By 0xAA | ||
pragma solidity ^0.8.0; | ||
|
||
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; | ||
|
||
contract EIP712Storage { | ||
using ECDSA for bytes32; | ||
|
||
bytes32 private constant EIP712DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); | ||
bytes32 private constant STORAGE_TYPEHASH = keccak256("Storage(address spender,uint256 number)"); | ||
bytes32 private DOMAIN_SEPARATOR; | ||
uint256 number; | ||
address owner; | ||
|
||
constructor(){ | ||
DOMAIN_SEPARATOR = keccak256(abi.encode( | ||
EIP712DOMAIN_TYPEHASH, // type hash | ||
keccak256(bytes("EIP712Storage")), // name | ||
keccak256(bytes("1")), // version | ||
block.chainid, // chain id | ||
address(this) // contract address | ||
)); | ||
owner = msg.sender; | ||
} | ||
|
||
/** | ||
* @dev Store value in variable | ||
*/ | ||
function permitStore(uint256 _num, bytes memory _signature) public { | ||
// Check the signature length, 65 is the length of standard r, s, v signatures | ||
require(_signature.length == 65, "invalid signature length"); | ||
bytes32 r; | ||
bytes32 s; | ||
uint8 v; | ||
// Currently, assembly (inline assembly) can only be used to obtain the values of r, s, and v from the signature. | ||
assembly { | ||
/* | ||
The first 32 bytes store the length of the signature (dynamic array storage rules) | ||
add(sig, 32) = pointer to sig + 32 | ||
Equivalent to skipping the first 32 bytes of signature | ||
mload(p) loads the next 32 bytes of data starting from memory address p | ||
*/ | ||
// 32 bytes after reading the length data | ||
r := mload(add(_signature, 0x20)) | ||
//32 bytes after reading | ||
s := mload(add(_signature, 0x40)) | ||
//Read the last byte | ||
v := byte(0, mload(add(_signature, 0x60))) | ||
} | ||
|
||
// Get signed message hash | ||
bytes32 digest = keccak256(abi.encodePacked( | ||
"\x19\x01", | ||
DOMAIN_SEPARATOR, | ||
keccak256(abi.encode(STORAGE_TYPEHASH, msg.sender, _num)) | ||
)); | ||
|
||
address signer = digest.recover(v, r, s); // Restore signer | ||
require(signer == owner, "EIP712Storage: Invalid signature"); // Check signature | ||
|
||
// Modify state variables | ||
number = _num; | ||
} | ||
|
||
/** | ||
* @dev Return value | ||
* @return value of 'number' | ||
*/ | ||
function retrieve() public view returns (uint256){ | ||
return number; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>EIP-712 Signature Example</title> | ||
</head> | ||
<body> | ||
<h1>EIP-712 Signature Example</h1> | ||
|
||
<label for="name">Name:</label> | ||
<input id="name" value="EIP712Storage"> | ||
<br> | ||
<label for="chainId">Chain ID:</label> | ||
<input id="chainId" value="1"> | ||
<br> | ||
<label for="contractAddress">Contract Address:</label> | ||
<input id="contractAddress" value="0xf8e81D47203A594245E36C48e151709F0C19fBe8"> | ||
<br> | ||
<label for="spender">Spender:</label> | ||
<input id="spender" value="0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"> | ||
<br> | ||
<label for="number">number:</label> | ||
<input id="number" value="100"> | ||
<br> | ||
<button id="connectButton">Connect MetaMask</button> | ||
<button id="signPermitButton" disabled>Sign Permit</button> | ||
<br> | ||
<pre id="signatureOutput"></pre> | ||
|
||
<h5>Wallet address: <span class="showAccount"></span></h5> | ||
<h5>ChainID: <span class="showChainID"></span></h5> | ||
<h5>ETH Balance: <span class="showETHBalance"></span></h5> | ||
<h5>Signature data: <span class="showSignature"></span></h5> | ||
|
||
<script type = "module"> | ||
import { ethers } from "https://cdnjs.cloudflare.com/ajax/libs/ethers/6.3.0/ethers.js"; const ethereumButton = document.querySelector('.connect'); | ||
const showAccount = document.querySelector('.showAccount'); | ||
const showChainID = document.querySelector('.showChainID'); | ||
const showETHBalance = document.querySelector('.showETHBalance'); | ||
const showSignature = document.querySelector('.showSignature'); | ||
const connectButton = document.getElementById("connectButton"); | ||
const signPermitButton = document.getElementById("signPermitButton"); | ||
|
||
let provider; | ||
let signer; | ||
|
||
async function connectMetaMask() { | ||
// Get provider | ||
const provider = new ethers.BrowserProvider(window.ethereum) | ||
|
||
//Read wallet address | ||
const accounts = await provider.send("eth_requestAccounts", []); | ||
const account = accounts[0] | ||
console.log(`Wallet address: ${account}`) | ||
showAccount.innerHTML = account; | ||
|
||
//Read chainid | ||
const { chainId } = await provider.getNetwork() | ||
console.log(`chainid: ${chainId}`) | ||
showChainID.innerHTML = chainId; | ||
|
||
//Read ETH balance | ||
const signer = await provider.getSigner() | ||
const balance = await provider.getBalance(signer.getAddress()); | ||
console.log(`Ethereum balance: ${ethers.formatUnits(balance)}`) | ||
showETHBalance.innerHTML = ethers.formatUnits(balance); | ||
signPermitButton.disabled = false; | ||
} | ||
|
||
async function signPermit() { | ||
const name = document.getElementById('name').value; | ||
const version = "1"; | ||
const chainId = parseInt(document.getElementById('chainId').value); | ||
const contractAddress = document.getElementById('contractAddress').value; | ||
const spender = document.getElementById('spender').value; | ||
const number = document.getElementById('number').value; | ||
const provider = new ethers.BrowserProvider(window.ethereum) | ||
const signer = await provider.getSigner() | ||
const owner = await signer.getAddress(); | ||
|
||
const domain = { | ||
name: name, | ||
version: version, | ||
chainId: chainId, | ||
verifyingContract: contractAddress, | ||
}; | ||
|
||
const types = { | ||
Storage: [ | ||
{ name: "spender", type: "address" }, | ||
{ name: "number", type: "uint256" }, | ||
], | ||
}; | ||
|
||
const message = { | ||
spender: spender, | ||
number: number, | ||
}; | ||
|
||
try { | ||
console.log(message) | ||
const signature = await signer.signTypedData(domain, types, message); | ||
console.log("Signature:", signature); | ||
showSignature.innerHTML = `${signature}`; | ||
} catch (error) { | ||
console.error("Error signing permit:", error); | ||
} | ||
} | ||
|
||
connectButton.addEventListener(`click`, connectMetaMask) | ||
signPermitButton.addEventListener(`click`, signPermit) | ||
</script> | ||
</body> | ||
</html> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.