Skip to content

Commit

Permalink
fixed typos
Browse files Browse the repository at this point in the history
  • Loading branch information
jatZama committed Feb 15, 2024
1 parent b2134ee commit ecdfce8
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 70 deletions.
1 change: 0 additions & 1 deletion contracts/EncryptedERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,3 @@ contract EncryptedERC20 is Reencrypt, Ownable2Step {
emit Transfer(from, to);
}
}

10 changes: 5 additions & 5 deletions contracts/UniswapV2Factory.sol
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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);
}

}
}
124 changes: 71 additions & 53 deletions contracts/UniswapV2Pair.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -105,26 +105,26 @@ 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
}

pendingMints[currentTradingEpoch][to] += liquidity;
pendingTotalMints[currentTradingEpoch] += liquidity;
}


// **** REMOVE LIQUIDITY ****
function removeLiquidity(
bytes calldata encryptedLiquidity,
Expand All @@ -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) {
Expand All @@ -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;
Expand All @@ -166,52 +166,63 @@ 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;
}

function claimBurn(uint256 tradingEpoch, address user) external {
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;
}

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];

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);
Expand All @@ -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;
}
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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");
}
}
}
22 changes: 11 additions & 11 deletions test/instance.ts
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -43,17 +43,17 @@ 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;
}

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);
Expand Down Expand Up @@ -85,4 +85,4 @@ function createUintToUint8ArrayFunction(numBits: number) {
const buffer = toBufferBE(BigInt(uint), numBytes);
return buffer;
};
}
}

0 comments on commit ecdfce8

Please sign in to comment.