From a41d4fa2f1a8a5ebb360aa35965abfce129a0667 Mon Sep 17 00:00:00 2001 From: Faran Ahmad Date: Fri, 23 Feb 2024 13:02:26 +0000 Subject: [PATCH 1/6] token contract --- contracts/OurToken.sol | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 contracts/OurToken.sol diff --git a/contracts/OurToken.sol b/contracts/OurToken.sol new file mode 100644 index 0000000..9d65c9d --- /dev/null +++ b/contracts/OurToken.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract OurToken is ERC20, ERC20Permit { + constructor() ERC20("OurToken", "OT") ERC20Permit("OurToken") {} + + function mint(address _to, uint _amount) external { + _mint(_to, _amount); + } +} From bb3aca4336cdf1732383e845feb10bfced2a8195 Mon Sep 17 00:00:00 2001 From: Faran Ahmad Date: Fri, 23 Feb 2024 13:04:06 +0000 Subject: [PATCH 2/6] vault contract --- contracts/Vault.sol | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 contracts/Vault.sol diff --git a/contracts/Vault.sol b/contracts/Vault.sol new file mode 100644 index 0000000..325ab55 --- /dev/null +++ b/contracts/Vault.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "./IERC20Permit.sol"; + +contract Vault { + IERC20Permit public immutable token; + + constructor(address _token) { + token = IERC20Permit(_token); + } + + // transfer funds by executing transaction + function deposit(uint amount) external { + token.transferFrom(msg.sender, address(this), amount); + } + + // transfer funds by using digital signature + function depositWithPermit( + uint amount, + uint deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external { + token.permit(msg.sender, address(this), amount, deadline, v, r, s); + token.transferFrom(msg.sender, address(this), amount); + } +} From 57faf4aa5dd809e567805814d1a0069f2bb45361 Mon Sep 17 00:00:00 2001 From: Faran Ahmad Date: Fri, 23 Feb 2024 13:04:33 +0000 Subject: [PATCH 3/6] permit contract --- contracts/IERC20Permit.sol | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 contracts/IERC20Permit.sol diff --git a/contracts/IERC20Permit.sol b/contracts/IERC20Permit.sol new file mode 100644 index 0000000..cab592b --- /dev/null +++ b/contracts/IERC20Permit.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +interface IERC20Permit { + function totalSupply() external view returns (uint); + + function balanceOf(address account) external view returns (uint); + + function transfer(address recipient, uint amount) external returns (bool); + + function allowance( + address owner, + address spender + ) external view returns (uint); + + function approve(address spender, uint amount) external returns (bool); + + function transferFrom( + address sender, + address recipient, + uint amount + ) external returns (bool); + + function permit( + address owner, + address spender, + uint value, + uint deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + event Transfer(address indexed from, address indexed to, uint value); + event Approval(address indexed owner, address indexed spender, uint value); +} From 0cf317af6a21c4f36e9a54d114074920f7f96c03 Mon Sep 17 00:00:00 2001 From: Faran Ahmad Date: Fri, 23 Feb 2024 13:05:07 +0000 Subject: [PATCH 4/6] test case for permt --- test/erc20-permit.js | 90 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 test/erc20-permit.js diff --git a/test/erc20-permit.js b/test/erc20-permit.js new file mode 100644 index 0000000..ef7c5b2 --- /dev/null +++ b/test/erc20-permit.js @@ -0,0 +1,90 @@ +const { expect } = require("chai"); +const { ethers } = require("hardhat"); + +async function getPermitSignature(signer, token, spender, value, deadline) { + const [nonce, name, version, chainId] = await Promise.all([ + token.nonces(signer.address), + token.name(), + "1", + 31337, + ]); + + return ethers.Signature.from( + await signer.signTypedData( + { + name, + version, + chainId, + verifyingContract: token.target, + }, + { + Permit: [ + { + name: "owner", + type: "address", + }, + { + name: "spender", + type: "address", + }, + { + name: "value", + type: "uint256", + }, + { + name: "nonce", + type: "uint256", + }, + { + name: "deadline", + type: "uint256", + }, + ], + }, + { + owner: signer.address, + spender, + value, + nonce, + deadline, + } + ) + ); +} + +describe("ERC20Permit", function () { + it("ERC20 permit", async function () { + const accounts = await ethers.getSigners(1); + const signer = accounts[0]; + + const OurToken = await ethers.getContractFactory("OurToken"); + const ourToken = await OurToken.deploy(); + await ourToken.waitForDeployment(); + + // assign the token contract address to vault contract + + const Vault = await ethers.getContractFactory("Vault"); + const vault = await Vault.deploy(ourToken.target); + await vault.waitForDeployment(); + + // amount of tokens to be minted + const amount = 1000; + // call mint function + await ourToken.mint(signer.address, amount); + + const deadline = ethers.MaxUint256; + + const { v, r, s } = await getPermitSignature( + signer, + ourToken, + vault.target, + amount, + deadline + ); + + await vault.depositWithPermit(amount, deadline, v, r, s); + + // test cases + expect(await ourToken.balanceOf(vault.target)).to.equal(amount); + }); +}); From 8faa3fbc89b822818b4dfdea517c66d6a47858cf Mon Sep 17 00:00:00 2001 From: Faran Ahmad Date: Fri, 23 Feb 2024 13:05:42 +0000 Subject: [PATCH 5/6] changes to config --- hardhat.config.js | 7 +++++++ package-lock.json | 7 +++++++ package.json | 1 + 3 files changed, 15 insertions(+) diff --git a/hardhat.config.js b/hardhat.config.js index 8ba99bc..5e82d93 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -2,5 +2,12 @@ require("@nomicfoundation/hardhat-toolbox"); /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { + defaultNetwork: "hardhat", + networks: { + localhost: { + url: "http://127.0.0.1:8545", + chainId: 31337, + }, + }, solidity: "0.8.24", }; diff --git a/package-lock.json b/package-lock.json index 4def613..5bf165f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ }, "devDependencies": { "@nomicfoundation/hardhat-toolbox": "^4.0.0", + "@openzeppelin/contracts": "^5.0.1", "hardhat": "^2.20.1" } }, @@ -1753,6 +1754,12 @@ "node": ">= 10" } }, + "node_modules/@openzeppelin/contracts": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.1.tgz", + "integrity": "sha512-yQJaT5HDp9hYOOp4jTYxMsR02gdFZFXhewX5HW9Jo4fsqSVqqyIO/xTHdWDaKX5a3pv1txmf076Lziz+sO7L1w==", + "dev": true + }, "node_modules/@scure/base": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz", diff --git a/package.json b/package.json index 8067ae8..097c62e 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "license": "ISC", "devDependencies": { "@nomicfoundation/hardhat-toolbox": "^4.0.0", + "@openzeppelin/contracts": "^5.0.1", "hardhat": "^2.20.1" }, "dependencies": { From 466f32ce765bed6d810f3adc40d403a2f75168c8 Mon Sep 17 00:00:00 2001 From: Faran Ahmad Date: Fri, 23 Feb 2024 13:06:57 +0000 Subject: [PATCH 6/6] version --- contracts/VerifySignature.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/VerifySignature.sol b/contracts/VerifySignature.sol index 5cf1771..cff711c 100644 --- a/contracts/VerifySignature.sol +++ b/contracts/VerifySignature.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8; +pragma solidity ^0.8.24; contract VerifySignature { function getMessageHash(