From 288bfaad5ed9ae15fc75944f501ac196a7c3ed39 Mon Sep 17 00:00:00 2001 From: Alisha-Reddy Date: Thu, 2 Oct 2025 02:20:43 +0530 Subject: [PATCH] fix: mock permit2 --- .../contracts/mocks/MockPermit2.sol | 24 +++++++ contract-hardhat/package.json | 1 + ...ding_restriction_manager_with_usdtiered.ts | 72 ++++++++++++++++++- contract-hardhat/yarn.lock | 15 +++- 4 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 contract-hardhat/contracts/mocks/MockPermit2.sol diff --git a/contract-hardhat/contracts/mocks/MockPermit2.sol b/contract-hardhat/contracts/mocks/MockPermit2.sol new file mode 100644 index 00000000..b36da05e --- /dev/null +++ b/contract-hardhat/contracts/mocks/MockPermit2.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.30; + +contract MockPermit2 { + // Minimal storage to simulate approvals + mapping(address => mapping(address => uint256)) public allowance; + + function permitTransferFrom( + address from, + address to, + uint256 amount + ) external { + // naive "transfer" simulation + require(allowance[from][msg.sender] >= amount, "Not permitted"); + allowance[from][msg.sender] -= amount; + } + + function approve( + address spender, + uint256 amount + ) external { + allowance[msg.sender][spender] = amount; + } +} diff --git a/contract-hardhat/package.json b/contract-hardhat/package.json index e6224fb6..abd1d802 100644 --- a/contract-hardhat/package.json +++ b/contract-hardhat/package.json @@ -55,6 +55,7 @@ "@graphprotocol/graph-ts": "^0.38.1", "@openzeppelin/contracts": "^5.3.0", "@openzeppelin/merkle-tree": "^1.0.8", + "@uniswap/permit2-sdk": "^1.4.0", "dotenv": "^17.0.1", "web3": "1.10.0" } diff --git a/contract-hardhat/test/a_trading_restriction_manager_with_usdtiered.ts b/contract-hardhat/test/a_trading_restriction_manager_with_usdtiered.ts index 817c90ef..35e528b1 100644 --- a/contract-hardhat/test/a_trading_restriction_manager_with_usdtiered.ts +++ b/contract-hardhat/test/a_trading_restriction_manager_with_usdtiered.ts @@ -9,6 +9,11 @@ import { deployERC20DividendAndVerifyed, deployGPMAndVerifyed, deployUSDTieredST import { initializeContracts } from "../scripts/polymath-deploy"; import { StandardMerkleTree } from "@openzeppelin/merkle-tree"; import { time } from "@nomicfoundation/hardhat-network-helpers"; +import { + PERMIT2_ADDRESS, + SignatureTransfer, + PermitTransferFrom, +} from "@uniswap/permit2-sdk"; const functionSignature = { name: "configure", @@ -219,6 +224,7 @@ describe("Trading restriction Manager", function() { // MockOracle USD prices let USDETH: bigint; // 500 USD/ETH let USDPOLY: bigint; // 0.25 USD/POLY + let mockPermit2: any; const DividendParameters = ["address"]; const checkpointKey = 4; @@ -251,6 +257,42 @@ describe("Trading restriction Manager", function() { return 0n; } + async function generatePermit2Data( + tokenAddress: string, + amountInWei: string, + spenderAddress: string, + signer: any, + chainId: number + ): Promise<{ permit: PermitTransferFrom; permitSignature: string }> { + const currentTime = Math.floor(Date.now() / 1000); + const deadline = currentTime + 3600; + const nonce = Math.floor(Math.random() * 1e15); + + const permit: PermitTransferFrom = { + permitted: { + token: tokenAddress, + amount: amountInWei, + }, + spender: spenderAddress, + nonce, + deadline, + }; + + const { domain, types, values } = SignatureTransfer.getPermitData( + permit, + PERMIT2_ADDRESS, + chainId + ); + + // ethers v6 signTypedData + const signature = await signer.signTypedData(domain, types, values); + + return { + permit, + permitSignature: signature, + }; + } + before(async () => { await initializeContracts(); @@ -306,6 +348,8 @@ describe("Trading restriction Manager", function() { GeneralTransferManager = await ethers.getContractFactory("GeneralTransferManager"); PolyTokenFaucetFactory = await ethers.getContractFactory("PolyTokenFaucet"); + const MockPermit2 = await ethers.getContractFactory("MockPermit2"); + mockPermit2 = await MockPermit2.deploy(); // Step 1: Deploy the general PM ecosystem @@ -678,8 +722,34 @@ describe("Trading restriction Manager", function() { const init_WalletPOLYBal = await I_PolyToken.balanceOf(account_issuer.address); const init_WalletDAIBal = await I_DaiToken.balanceOf(account_issuer.address); + const requiredAmount = ethers.parseEther("10"); + + const { permit, permitSignature } = await generatePermit2Data( + stoAddress, + requiredAmount.toString(), + token_owner.address, + account_investor1.address, + 31337 + ); + + expect(permit.permitted.token).to.eq(stoAddress); + expect(permit.permitted.amount).to.eq(requiredAmount.toString()); + expect(permit.spender).to.eq(token_owner.address); + expect(permitSignature).to.be.properHexString; + // Buy With DAI - const tx2 = await I_USDTieredSTO_Array[stoId].connect(account_investor1).buyWithUSD(account_investor1.address, investment_DAI, daiAddress, proof1, ltime, isAccredited1, InvestorClass.NonUS); + const tx2 = await I_USDTieredSTO_Array[stoId].connect(account_investor1).buyWithUSD( + null, + await mockPermit2.getAddress(), + account_investor1.address, + requiredAmount, + investment_DAI, + daiAddress, + proof1, + ltime, + isAccredited1, + InvestorClass.NonUS + ); const receipt2 = await tx2.wait(); const gasCost2 = receipt2.gasUsed * receipt2.gasPrice; console.log(`Gas buyWithUSD: ${receipt2.gasUsed}`); diff --git a/contract-hardhat/yarn.lock b/contract-hardhat/yarn.lock index b748876c..986c757b 100644 --- a/contract-hardhat/yarn.lock +++ b/contract-hardhat/yarn.lock @@ -1451,6 +1451,14 @@ dependencies: "@types/node" "*" +"@uniswap/permit2-sdk@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@uniswap/permit2-sdk/-/permit2-sdk-1.4.0.tgz#eafb48e89bd747b893a88d3cabd2422a81528b80" + integrity sha512-l/aGhfhB93M76vXs4eB8QNwhELE6bs66kh7F1cyobaPtINaVpMmlJv+j3KmHeHwAZIsh7QXyYzhDxs07u0Pe4Q== + dependencies: + ethers "^5.7.0" + tiny-invariant "^1.1.0" + "@whatwg-node/events@^0.0.3": version "0.0.3" resolved "https://registry.yarnpkg.com/@whatwg-node/events/-/events-0.0.3.tgz#13a65dd4f5893f55280f766e29ae48074927acad" @@ -3190,7 +3198,7 @@ ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereum ethereum-cryptography "^0.1.3" rlp "^2.2.4" -ethers@^5.7.2: +ethers@^5.7.0, ethers@^5.7.2: version "5.8.0" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.8.0.tgz#97858dc4d4c74afce83ea7562fe9493cedb4d377" integrity sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg== @@ -6765,6 +6773,11 @@ timeout-abort-controller@^2.0.0: native-abort-controller "^1.0.4" retimer "^3.0.0" +tiny-invariant@^1.1.0: + version "1.3.3" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" + integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== + tinyglobby@^0.2.6: version "0.2.14" resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d"