Skip to content

Instantly share code, notes, and snippets.

@shobhitic
Last active May 3, 2024 03:27
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save shobhitic/c16b647562e7995d788e2e1bd5818267 to your computer and use it in GitHub Desktop.
Save shobhitic/c16b647562e7995d788e2e1bd5818267 to your computer and use it in GitHub Desktop.
ERC20 Permit OpenZeppelin Tutorial - https://www.youtube.com/watch?v=lFKcga4Y6Ys
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ERC20 Permit</title>
<script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/web3modal@1.9.9/dist/index.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@walletconnect/web3-provider@1.8.0/dist/umd/index.min.js"></script>
<script src="https://bundle.run/buffer@6.0.3"></script>
</head>
<body>
<script type="text/javascript">
window.Buffer = buffer.Buffer // getting this from buffer module for frontend.
const domainName = "MyToken" // put your token name
const domainVersion = "1" // leave this to "1"
const chainId = 1 // this is for the chain's ID. value is 1 for remix
const contractAddress = "0xd9145CCE52D386f254917e481eB44e9943F39138" // Put the address here from remix
var account = null;
const domain = {
name: domainName,
version: domainVersion,
verifyingContract: contractAddress,
chainId
}
const domainType = [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
]
const connect = async () => {
// This helps connect webpage to wallet.
const providerOptions = {
walletconnect: {
package: WalletConnectProvider.default, // required
options: {
rpc: {
1: "https://cloudflare-eth.com",
137: "https://polygon-rpc.com",
// ...
},
}
}
};
const Web3Modal = window.Web3Modal.default;
const web3Modal = new Web3Modal({
network: "mainnet", // optional
cacheProvider: false, // optional
providerOptions, // required
theme: "dark"
});
const provider = await web3Modal.connect();
window.web3 = new Web3(provider);
var accounts = await web3.eth.getAccounts();
account = accounts[0];
}
const splitSig = (sig) => {
// splits the signature to r, s, and v values.
const pureSig = sig.replace("0x", "")
const r = new Buffer(pureSig.substring(0, 64), 'hex')
const s = new Buffer(pureSig.substring(64, 128), 'hex')
const v = new Buffer((parseInt(pureSig.substring(128, 130), 16)).toString());
return {
r, s, v
}
}
const signTyped = (dataToSign) => {
// call this method to sign EIP 712 data
return new Promise((resolve, reject) => {
web3.currentProvider.sendAsync({
method: "eth_signTypedData_v4",
params: [account, dataToSign],
from: account
}, (err, result) => {
if (err) return reject(err);
resolve(result.result)
})
})
}
async function createPermit(spender, value, nonce, deadline) {
const permit = { owner: account, spender, value, nonce, deadline }
const Permit = [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
]
const dataToSign = JSON.stringify({
types: {
EIP712Domain: domainType,
Permit: Permit
},
domain: domain,
primaryType: "Permit",
message: permit
});
const signature = await signTyped(dataToSign)
const split = splitSig(signature)
return {
...split, signature
}
}
async function main() {
await connect()
const permit = await createPermit("0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", 1000, 1, 2661766724)
console.log(`r: 0x${permit.r.toString('hex')}, s: 0x${permit.s.toString('hex')}, v: ${permit.v}, sig: ${permit.signature}`)
}
</script>
</body>
</html>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts@4.7.3/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts@4.7.3/token/ERC20/extensions/draft-ERC20Permit.sol";
contract MyToken is ERC20, ERC20Permit {
constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {}
function mint(address to, uint256 value) external {
_mint(to, value);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment