Skip to content

Commit

Permalink
fix: Fix
Browse files Browse the repository at this point in the history
  • Loading branch information
PacificYield committed Nov 29, 2024
1 parent 5f924c6 commit 77e4f80
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 91 deletions.
163 changes: 163 additions & 0 deletions contracts/token/ERC20/EncryptedERC20Wrapped.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.24;

import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import { EncryptedERC20 } from "./EncryptedERC20.sol";

import "fhevm/lib/TFHE.sol";
import "fhevm/gateway/GatewayCaller.sol";

/**
* @title EncryptedERC20Wrapped
* @notice This contract allows users to wrap/unwrap trustlessly
* ERC20 tokens to EncryptedERC20 tokens.
* @dev This implementation does not support tokens with rebase functions or
* tokens with a fee on transfer. All ERC20 tokens must have decimals
* inferior or equal to 18 decimals but superior or equal to 6 decimals.
*/
abstract contract EncryptedERC20Wrapped is EncryptedERC20, GatewayCaller {
using SafeERC20 for IERC20Metadata;

/// @notice Returns if user cannot transfer or mint.
error CannotTransferOrMint();

/// @notice Returned if the amount is greater than 2**64.
error AmountTooHigh();

/// @notice Emitted when token is unwrapped.
event Unwrap(address indexed to, uint64 amount);

/// @notice Emitted if unwrap fails.
event UnwrapFail(address account, uint64 amount);

/// @notice Emitted when token is wrapped.
event Wrap(address indexed to, uint64 amount);

/**
* @notice Keeps track of unwrap information.
* @param account Account that initiates the unwrap request.
* @param amount Amount to be unwrapped.
*/
struct UnwrapRequest {
address account;
uint64 amount;
}

/// @notice ERC20 token that is wrapped.
IERC20Metadata public immutable ERC20_TOKEN;

/// @notice Tracks whether the account can move funds.
mapping(address account => bool canMoveFunds) public isAccountRestricted;

/// @notice Tracks the unwrap request to a unique request id.
mapping(uint256 requestId => UnwrapRequest unwrapRequest) public unwrapRequests;

/**
* @notice Deposit/withdraw ERC20 tokens using encrypted ERC20 tokens.
* @param erc20_ Address of the ERC20 token to wrap/unwrap.
* @dev The name/symbol are autogenerated.
* For instance,
* "Wrapped Ether" --> "Encrypted Wrapped Ether"
* "WETH" --> "eWETH".
*/
constructor(
address erc20_
)
EncryptedERC20(
string(abi.encodePacked("Encrypted ", IERC20Metadata(erc20_).name())),
string(abi.encodePacked("e", IERC20Metadata(erc20_).symbol()))
)
{
ERC20_TOKEN = IERC20Metadata(erc20_);
}

/**
* @notice Unwrap EncryptedERC20 tokens to standard ERC20 tokens.
* @param amount Amount to unwrap.
*/
function unwrap(uint64 amount) public virtual {
_canTransferOrMint(msg.sender);

/// @dev Once this function is called, it becomes impossible for the sender to move any token.
isAccountRestricted[msg.sender] = true;
ebool canUnwrap = TFHE.le(amount, _balances[msg.sender]);

uint256[] memory cts = new uint256[](1);
cts[0] = Gateway.toUint256(canUnwrap);

uint256 requestId = Gateway.requestDecryption(
cts,
this.callbackUnwrap.selector,
0,
block.timestamp + 100,
false
);

unwrapRequests[requestId] = UnwrapRequest({ account: msg.sender, amount: amount });
}

/**
* @notice Wrap ERC20 tokens to an encrypted format.
* @param amount Amount to wrap.
*/
function wrap(uint256 amount) public virtual {
ERC20_TOKEN.safeTransferFrom(msg.sender, address(this), amount);

uint256 amountAdjusted = amount / (10 ** (ERC20_TOKEN.decimals() - decimals()));

if (amountAdjusted > type(uint64).max) {
revert AmountTooHigh();
}

uint64 amountUint64 = uint64(amountAdjusted);

_unsafeMint(msg.sender, TFHE.asEuint64(amountUint64));
_totalSupply += amountUint64;

emit Wrap(msg.sender, amountUint64);
}

/**
* @notice Callback function for the gateway.
* @param requestId Request id.
* @param canUnwrap Whether it can be unwrapped.
*/
function callbackUnwrap(uint256 requestId, bool canUnwrap) public virtual onlyGateway {
UnwrapRequest memory unwrapRequest = unwrapRequests[requestId];
delete unwrapRequests[requestId];

if (canUnwrap) {
_unsafeBurn(unwrapRequest.account, TFHE.asEuint64(unwrapRequest.amount));
_totalSupply -= unwrapRequest.amount;

/// @dev It does a supply adjustment.
uint256 amountUint256 = unwrapRequest.amount * (10 ** (ERC20_TOKEN.decimals() - decimals()));

ERC20_TOKEN.safeTransfer(unwrapRequest.account, amountUint256);

emit Unwrap(unwrapRequest.account, unwrapRequest.amount);
} else {
emit UnwrapFail(unwrapRequest.account, unwrapRequest.amount);
}

delete isAccountRestricted[unwrapRequest.account];
}

function _canTransferOrMint(address account) internal virtual {
if (isAccountRestricted[account]) {
revert CannotTransferOrMint();
}
}

function _transferNoEvent(
address from,
address to,
euint64 amount,
ebool isTransferable
) internal virtual override {
_canTransferOrMint(from);
super._transferNoEvent(from, to, amount, isTransferable);
}
}
89 changes: 0 additions & 89 deletions contracts/token/ERC20/EncryptedERC20Wrapper.sol

This file was deleted.

7 changes: 5 additions & 2 deletions contracts/token/ERC20/EncryptedWETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,14 @@ abstract contract EncryptedWETH is EncryptedERC20 {
* @notice Wrap ether to an encrypted format.
*/
function wrap() public payable virtual {
if (msg.value > type(uint64).max) {
uint256 amountAdjusted = msg.value / (10 ** (18 - decimals()));

if (amountAdjusted > type(uint64).max) {
revert AmountTooHigh();
}

uint64 amountUint64 = uint64(msg.value / (10 ** (18 - decimals())));
uint64 amountUint64 = uint64(amountAdjusted);

_balances[msg.sender] = TFHE.add(_balances[msg.sender], amountUint64);

TFHE.allowThis(_balances[msg.sender]);
Expand Down

0 comments on commit 77e4f80

Please sign in to comment.