From ecdfce8aa047807665bc638aba67b5a441156798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joseph-Andr=C3=A9=20Turk?= Date: Thu, 15 Feb 2024 13:38:50 +0100 Subject: [PATCH] fixed typos --- contracts/EncryptedERC20.sol | 1 - contracts/UniswapV2Factory.sol | 10 +-- contracts/UniswapV2Pair.sol | 124 +++++++++++++++++++-------------- test/instance.ts | 22 +++--- 4 files changed, 87 insertions(+), 70 deletions(-) diff --git a/contracts/EncryptedERC20.sol b/contracts/EncryptedERC20.sol index 78343d6..d9184c8 100644 --- a/contracts/EncryptedERC20.sol +++ b/contracts/EncryptedERC20.sol @@ -151,4 +151,3 @@ contract EncryptedERC20 is Reencrypt, Ownable2Step { emit Transfer(from, to); } } - diff --git a/contracts/UniswapV2Factory.sol b/contracts/UniswapV2Factory.sol index 8e7189a..b6657d2 100644 --- a/contracts/UniswapV2Factory.sol +++ b/contracts/UniswapV2Factory.sol @@ -1,9 +1,10 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear + pragma solidity ^0.8.20; -import './UniswapV2Pair.sol'; +import "./UniswapV2Pair.sol"; contract UniswapV2Factory { - mapping(address => mapping(address => address)) public getPair; address[] public allPairs; @@ -20,12 +21,11 @@ contract UniswapV2Factory { require(token0 != address(0), "UniswapV2: ZERO_ADDRESS"); require(getPair[token0][token1] == address(0), "UniswapV2: PAIR_EXISTS"); // single check is sufficient bytes32 _salt = keccak256(abi.encodePacked(token0, token1)); - pair = address(new UniswapV2Pair{salt: _salt}()); + pair = address(new UniswapV2Pair{ salt: _salt }()); UniswapV2Pair(pair).initialize(token0, token1); getPair[token0][token1] = pair; getPair[token1][token0] = pair; // populate mapping in the reverse direction allPairs.push(pair); emit PairCreated(token0, token1, pair, allPairs.length); } - -} \ No newline at end of file +} diff --git a/contracts/UniswapV2Pair.sol b/contracts/UniswapV2Pair.sol index 9d8decf..6cbca6e 100644 --- a/contracts/UniswapV2Pair.sol +++ b/contracts/UniswapV2Pair.sol @@ -9,25 +9,25 @@ contract UniswapV2Pair is EncryptedERC20 { uint256 internal currentTradingEpoch; mapping(uint256 tradingEpoch => uint256 firstOrderBlock) internal firstBlockPerEpoch; // set to current block number for any first order (mint, burn or swap) in an epoch - + mapping(uint256 tradingEpoch => mapping(address user => euint32 mintedLiquidity)) internal pendingMints; - mapping(uint256 tradingEpoch => euint32 mintedTotalLiquidity) internal pendingTotalMints; - mapping(uint256 tradingEpoch => uint32 mintedTotalLiquidity) internal decryptedTotalMints; + mapping(uint256 tradingEpoch => euint32 mintedTotalLiquidity) internal pendingTotalMints; + mapping(uint256 tradingEpoch => uint32 mintedTotalLiquidity) internal decryptedTotalMints; mapping(uint256 tradingEpoch => mapping(address user => euint32 burnedLiquidity)) internal pendingBurns; - mapping(uint256 tradingEpoch => euint32 burnedTotalLiquidity) internal pendingTotalBurns; - mapping(uint256 tradingEpoch => uint32 burnedTotalLiquidity) internal decryptedTotalBurns; - mapping(uint256 tradingEpoch => uint32 totalToken0) internal totalToken0ClaimableBurn; - mapping(uint256 tradingEpoch => uint32 totalToken1) internal totalToken1ClaimableBurn; + mapping(uint256 tradingEpoch => euint32 burnedTotalLiquidity) internal pendingTotalBurns; + mapping(uint256 tradingEpoch => uint32 burnedTotalLiquidity) internal decryptedTotalBurns; + mapping(uint256 tradingEpoch => uint32 totalToken0) internal totalToken0ClaimableBurn; + mapping(uint256 tradingEpoch => uint32 totalToken1) internal totalToken1ClaimableBurn; mapping(uint256 tradingEpoch => mapping(address user => euint32 swappedToken0In)) internal pendingToken0In; - mapping(uint256 tradingEpoch => euint32 swappedTotalToken0In) internal pendingTotalToken0In; - mapping(uint256 tradingEpoch => uint32 swappedTotalToken0In) internal decryptedTotalToken0In; + mapping(uint256 tradingEpoch => euint32 swappedTotalToken0In) internal pendingTotalToken0In; + mapping(uint256 tradingEpoch => uint32 swappedTotalToken0In) internal decryptedTotalToken0In; mapping(uint256 tradingEpoch => mapping(address user => euint32 swappedToken1In)) internal pendingToken1In; - mapping(uint256 tradingEpoch => euint32 swappedTotalToken1In) internal pendingTotalToken1In; - mapping(uint256 tradingEpoch => uint32 swappedTotalToken1In) internal decryptedTotalToken1In; - mapping(uint256 tradingEpoch => uint32 totalToken0) internal totalToken0ClaimableSwap; - mapping(uint256 tradingEpoch => uint32 totalToken1) internal totalToken1ClaimableSwap; + mapping(uint256 tradingEpoch => euint32 swappedTotalToken1In) internal pendingTotalToken1In; + mapping(uint256 tradingEpoch => uint32 swappedTotalToken1In) internal decryptedTotalToken1In; + mapping(uint256 tradingEpoch => uint32 totalToken0) internal totalToken0ClaimableSwap; + mapping(uint256 tradingEpoch => uint32 totalToken1) internal totalToken1ClaimableSwap; address public factory; EncryptedERC20 public token0; @@ -105,18 +105,19 @@ contract UniswapV2Pair is EncryptedERC20 { } function mint(address to, euint32 amount0, euint32 amount1) internal returns (euint32 liquidity) { - if(firstBlockPerEpoch[currentTradingEpoch]==0){ + if (firstBlockPerEpoch[currentTradingEpoch] == 0) { firstBlockPerEpoch[currentTradingEpoch] = block.number; } reserve0PendingAdd += amount0; reserve1PendingAdd += amount1; - if (totalSupply() == 0) { // this condition is equivalent to currentTradingEpoch==0 (see batchSettlement logic) - liquidity = TFHE.shr(amount0,1)+TFHE.shr(amount1,1); + if (totalSupply() == 0) { + // this condition is equivalent to currentTradingEpoch==0 (see batchSettlement logic) + liquidity = TFHE.shr(amount0, 1) + TFHE.shr(amount1, 1); } else { - euint64 liquidity0 = TFHE.div(TFHE.mul(TFHE.asEuint64(amount0),uint64(_totalSupply)),uint64(_reserve0)); // to avoid overflows - euint64 liquidity1 = TFHE.div(TFHE.mul(TFHE.asEuint64(amount1),uint64(_totalSupply)),uint64(_reserve1)); // to avoid overflows + euint64 liquidity0 = TFHE.div(TFHE.mul(TFHE.asEuint64(amount0), uint64(_totalSupply)), uint64(_reserve0)); // to avoid overflows + euint64 liquidity1 = TFHE.div(TFHE.mul(TFHE.asEuint64(amount1), uint64(_totalSupply)), uint64(_reserve1)); // to avoid overflows liquidity = TFHE.asEuint32(TFHE.min(liquidity0, liquidity1)); // check this always fit in a euint32 from the logic of the contract } @@ -124,7 +125,6 @@ contract UniswapV2Pair is EncryptedERC20 { pendingTotalMints[currentTradingEpoch] += liquidity; } - // **** REMOVE LIQUIDITY **** function removeLiquidity( bytes calldata encryptedLiquidity, @@ -144,7 +144,7 @@ contract UniswapV2Pair is EncryptedERC20 { address tokenA, address tokenB, bytes calldata encryptedAmount0In, - bytes calldata encryptedAmount0In, + bytes calldata encryptedAmount1In, address to, uint deadline ) external ensure(deadline) { @@ -156,8 +156,8 @@ contract UniswapV2Pair is EncryptedERC20 { token1.transferFrom(msg.sender, address(this), amount1In); euint32 balance0After = token0.balanceOfMe(); euint32 balance1After = token1.balanceOfMe(); - euint32 sent0 = balance0After-balance0Before; - euint32 sent1 = balance1After-balance1Before; + euint32 sent0 = balance0After - balance0Before; + euint32 sent1 = balance1After - balance1Before; pendingToken0In[currentTradingEpoch][msg.sender] += sent0; pendingTotalToken0In[currentTradingEpoch] += sent0; pendingToken1In[currentTradingEpoch][msg.sender] += sent1; @@ -166,7 +166,7 @@ contract UniswapV2Pair is EncryptedERC20 { function claimMint(uint256 tradingEpoch, address user) external { require(tradingEpoch < currentTradingEpoch, "tradingEpoch is not settled yet"); - transfer(user,pendingMints[tradingEpoch][user]); + transfer(user, pendingMints[tradingEpoch][user]); pendingMints[tradingEpoch][user] = 0; } @@ -174,11 +174,15 @@ contract UniswapV2Pair is EncryptedERC20 { require(tradingEpoch < currentTradingEpoch, "tradingEpoch is not settled yet"); euint32 pendingBurn = pendingBurns[tradingEpoch][user]; uint32 decryptedTotalBurn = decryptedTotalBurns[tradingEpoch]; - require(decryptedTotalBurn!=0, "No liquidity was burnt during tradingEpoch"); + require(decryptedTotalBurn != 0, "No liquidity was burnt during tradingEpoch"); uint32 totalToken0 = totalToken0ClaimableBurn[tradingEpoch]; uint32 totalToken1 = totalToken1ClaimableBurn[tradingEpoch]; - euint32 token0Claimable = TFHE.asEuint32(TFHE.div(TFHE.mul(TFHE.asEuint64(pendingBurn),uint64(totalToken0)),uint64(decryptedTotalBurn))); // check this always fit in a euint32 - euint32 token1Claimable = TFHE.asEuint32(TFHE.div(TFHE.mul(TFHE.asEuint64(pendingBurn),uint64(totalToken1)),uint64(decryptedTotalBurn))); // check this always fit in a euint32 + euint32 token0Claimable = TFHE.asEuint32( + TFHE.div(TFHE.mul(TFHE.asEuint64(pendingBurn), uint64(totalToken0)), uint64(decryptedTotalBurn)) + ); // check this always fit in a euint32 + euint32 token1Claimable = TFHE.asEuint32( + TFHE.div(TFHE.mul(TFHE.asEuint64(pendingBurn), uint64(totalToken1)), uint64(decryptedTotalBurn)) + ); // check this always fit in a euint32 token0.transfer(user, token0Claimable); token1.transfer(user, token1Claimable); pendingBurns[tradingEpoch][user] = 0; @@ -186,10 +190,10 @@ contract UniswapV2Pair is EncryptedERC20 { function claimSwap(uint256 tradingEpoch, address user) external { require(tradingEpoch < currentTradingEpoch, "tradingEpoch is not settled yet"); - euint32 pendingToken0In = pendingToken0In[tradingEpoch][user]; - uint32 decryptedTotalToken0In = decryptedTotalToken0In[tradingEpoch]; - euint32 pendingToken1In = pendingToken1In[tradingEpoch][user]; - uint32 decryptedTotalToken1In = decryptedTotalToken1In[tradingEpoch]; + euint32 pending0In = pendingToken0In[tradingEpoch][user]; + uint32 totalToken0In = decryptedTotalToken0In[tradingEpoch]; + euint32 pending1In = pendingToken1In[tradingEpoch][user]; + uint32 totalToken1In = decryptedTotalToken1In[tradingEpoch]; uint32 totalToken0Out = totalToken0ClaimableSwap[tradingEpoch]; uint32 totalToken1Out = totalToken1ClaimableSwap[tradingEpoch]; @@ -197,21 +201,28 @@ contract UniswapV2Pair is EncryptedERC20 { euint32 amount0Out; euint32 amount1Out; - if(decryptedTotalToken1In!=0){ - amount0Out = TFHE.asEuint32(TFHE.div(TFHE.mul(TFHE.asEuint64(pendingToken1In),uint64(totalToken0Out)),uint64(decryptedTotalToken1In))); // check this always fit in a euint32 + if (totalToken1In != 0) { + amount0Out = TFHE.asEuint32( + TFHE.div(TFHE.mul(TFHE.asEuint64(pending1In), uint64(totalToken0Out)), uint64(totalToken1In)) + ); // check this always fit in a euint32 token0.transfer(user, amount0Out); } - if(decryptedTotalToken0In!=0){ - amount1Out = TFHE.asEuint32(TFHE.div(TFHE.mul(TFHE.asEuint64(pendingToken0In),uint64(totalToken1Out)),uint64(decryptedTotalToken0In))); // check this always fit in a euint32 + if (totalToken0In != 0) { + amount1Out = TFHE.asEuint32( + TFHE.div(TFHE.mul(TFHE.asEuint64(pending0In), uint64(totalToken1Out)), uint64(totalToken0In)) + ); // check this always fit in a euint32 token1.transfer(user, amount1Out); } - pendingToken0In[tradingEpoch][user]=0; - pendingToken1In[tradingEpoch][user]=0; + pendingToken0In[tradingEpoch][user] = 0; + pendingToken1In[tradingEpoch][user] = 0; } function batchSettlement() external { - require(firstBlockPerEpoch[currentTradingEpoch] - block.number >= MIN_DELAY_SETTLEMENT, "First order of current epoch is more recent than minimum delay"); + require( + firstBlockPerEpoch[currentTradingEpoch] - block.number >= MIN_DELAY_SETTLEMENT, + "First order of current epoch is more recent than minimum delay" + ); // update reserves after new liquidity deposits uint32 reserve0PendingAddDec = TFHE.decrypt(reserve0PendingAdd); @@ -224,9 +235,9 @@ contract UniswapV2Pair is EncryptedERC20 { // Liquidity Mints uint32 _mintedTotal = TFHE.decrypt(pendingTotalMints[currentTradingEpoch]); _mint(_mintedTotal); - if(currentTradingEpoch==0){ - require(_mintedTotal>=100, "Initial minted liquidity should be greater than 100"); - decryptedTotalMints[currentTradingEpoch] = _mintedTotal-100; // this is to lock forever 100 liquidity tokens inside the pool, so totalSupply of liquidity would remain above 100 to avoid security issues + if (currentTradingEpoch == 0) { + require(_mintedTotal >= 100, "Initial minted liquidity should be greater than 100"); + decryptedTotalMints[currentTradingEpoch] = _mintedTotal - 100; // this is to lock forever 100 liquidity tokens inside the pool, so totalSupply of liquidity would remain above 100 to avoid security issues } else { decryptedTotalMints[currentTradingEpoch] = _mintedTotal; } @@ -236,15 +247,22 @@ contract UniswapV2Pair is EncryptedERC20 { uint32 amount1In = TFHE.decrypt(pendingTotalToken1In[currentTradingEpoch]); decryptedTotalToken0In[currentTradingEpoch] = amount0In; decryptedTotalToken1In[currentTradingEpoch] = amount1In; - bool priceToken1Increasing = (uint64(decryptedTotalToken0In)*uint64(reserve1) > uint64(decryptedTotalToken1In)*uint64(reserve0)); - if(priceToken1Increasing){ // in this case, first sell all amount1In at current fixed token1 price to get amount0Out, then swap remaining (amount0In-amount0Out) to get amount1out_remaining according to AMM formula - uint32 amount0Out = uint32(uint64(amount1In)*uint64(reserve0)/uint64(reserve1)); - uint32 amount1Out = amount1In + reserve1 - (uint64(reserve1)*uint64(reserve0)/(uint64(reserve0)+uint64(amount0In)-uint64(amount0Out))); - amount1Out = uint32(99*uint64(amount1Out)/100); // 1% fee for liquidity providers - } else { // here we do the opposite, first sell token0 at current token0 price then swap remaining token1 according to AMM formula - uint32 amount1Out = uint32(uint64(amount0In)*uint64(reserve1)/uint64(reserve0)); - uint32 amount0Out = amount0In + reserve0 - (uint64(reserve0)*uint64(reserve1)/(uint64(reserve1)+uint64(amount1In)-uint64(amount1Out))); - amount0Out = uint32(99*uint64(amount0Out)/100); // 1% fee for liquidity providers + bool priceToken1Increasing = (uint64(decryptedTotalToken0In) * uint64(reserve1) > + uint64(decryptedTotalToken1In) * uint64(reserve0)); + if (priceToken1Increasing) { + // in this case, first sell all amount1In at current fixed token1 price to get amount0Out, then swap remaining (amount0In-amount0Out) to get amount1out_remaining according to AMM formula + uint32 amount0Out = uint32((uint64(amount1In) * uint64(reserve0)) / uint64(reserve1)); + uint32 amount1Out = amount1In + + reserve1 - + ((uint64(reserve1) * uint64(reserve0)) / (uint64(reserve0) + uint64(amount0In) - uint64(amount0Out))); + amount1Out = uint32((99 * uint64(amount1Out)) / 100); // 1% fee for liquidity providers + } else { + // here we do the opposite, first sell token0 at current token0 price then swap remaining token1 according to AMM formula + uint32 amount1Out = uint32((uint64(amount0In) * uint64(reserve1)) / uint64(reserve0)); + uint32 amount0Out = amount0In + + reserve0 - + ((uint64(reserve0) * uint64(reserve1)) / (uint64(reserve1) + uint64(amount1In) - uint64(amount1Out))); + amount0Out = uint32((99 * uint64(amount0Out)) / 100); // 1% fee for liquidity providers } totalToken0ClaimableSwap[currentTradingEpoch] = amount0Out; totalToken1ClaimableSwap[currentTradingEpoch] = amount1Out; @@ -254,8 +272,8 @@ contract UniswapV2Pair is EncryptedERC20 { // Liquidity Burns uint32 _burnedTotal = TFHE.decrypt(pendingTotalBurns[currentTradingEpoch]); decryptedTotalBurns[currentTradingEpoch] = _burnedTotal; - uint32 amount0Claimable = _burnedTotal*reserve0 / _totalSupply; - uint32 amount1Claimable = _burnedTotal*reserve1 / _totalSupply; + uint32 amount0Claimable = (_burnedTotal * reserve0) / _totalSupply; + uint32 amount1Claimable = (_burnedTotal * reserve1) / _totalSupply; totalToken0Claimable[currentTradingEpoch] = amount0Claimable; totalToken0Claimable[currentTradingEpoch] = amount1Claimable; reserve0 -= amount0Claimable; @@ -264,6 +282,6 @@ contract UniswapV2Pair is EncryptedERC20 { currentTradingEpoch++; - require(reserve0>0 && reserve1>0, "Reserves should stay positive"); + require(reserve0 > 0 && reserve1 > 0, "Reserves should stay positive"); } -} \ No newline at end of file +} diff --git a/test/instance.ts b/test/instance.ts index cbdc993..fccac88 100644 --- a/test/instance.ts +++ b/test/instance.ts @@ -1,11 +1,11 @@ -import { toBufferBE } from 'bigint-buffer'; -import { Signer } from 'ethers'; -import fhevmjs, { FhevmInstance } from 'fhevmjs'; -import { ethers as hethers } from 'hardhat'; +import { toBufferBE } from "bigint-buffer"; +import { Signer } from "ethers"; +import fhevmjs, { FhevmInstance } from "fhevmjs"; +import { ethers as hethers } from "hardhat"; -import { FHE_LIB_ADDRESS } from './generated'; -import type { Signers } from './signers'; -import { FhevmInstances } from './types'; +import { FHE_LIB_ADDRESS } from "./generated"; +import type { Signers } from "./signers"; +import { FhevmInstances } from "./types"; const HARDHAT_NETWORK = process.env.HARDHAT_NETWORK; @@ -43,9 +43,9 @@ export const createInstance = async (contractAddress: string, account: Signer, e const ret = await provider.call({ to: FHE_LIB_ADDRESS, // first four bytes of keccak256('fhePubKey(bytes1)') + 1 byte for library - data: '0xd9d47bb001', + data: "0xd9d47bb001", }); - const decoded = ethers.AbiCoder.defaultAbiCoder().decode(['bytes'], ret); + const decoded = ethers.AbiCoder.defaultAbiCoder().decode(["bytes"], ret); publicKey = decoded[0]; } catch (e) { publicKey = undefined; @@ -53,7 +53,7 @@ export const createInstance = async (contractAddress: string, account: Signer, e const instance = await fhevmjs.createInstance({ chainId, publicKey }); - if (HARDHAT_NETWORK === 'hardhat') { + if (HARDHAT_NETWORK === "hardhat") { instance.encrypt8 = createUintToUint8ArrayFunction(8); instance.encrypt16 = createUintToUint8ArrayFunction(16); instance.encrypt32 = createUintToUint8ArrayFunction(32); @@ -85,4 +85,4 @@ function createUintToUint8ArrayFunction(numBits: number) { const buffer = toBufferBE(BigInt(uint), numBytes); return buffer; }; -} \ No newline at end of file +}