Files
zeekay 2a145d1976 Update @luxfhe packages to latest versions
- @luxfhe/wasm: ^0.2.0
- @luxfhe/kms: ^0.2.0
- @luxfhe/relayer-sdk: ^0.6.0
- @luxfhe/mock-contracts: ^0.6.0
- Remove deprecated Zama dependencies
2026-01-02 10:49:14 -08:00

119 lines
4.0 KiB
Solidity

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.25;
import { IERC20, IERC20Metadata, ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IFHERC20, FHERC20 } from "./FHERC20.sol";
import { euint128, FHE } from "@luxfi/contracts/fhe/FHE.sol";
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import { ConfidentialClaim } from "./ConfidentialClaim.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract ConfidentialERC20 is FHERC20, Ownable, ConfidentialClaim {
using EnumerableSet for EnumerableSet.UintSet;
using SafeERC20 for IERC20;
IERC20 private immutable _erc20;
string private _symbol;
event EncryptedERC20(address indexed from, address indexed to, uint128 value);
event DecryptedERC20(address indexed from, address indexed to, uint128 value);
event ClaimedDecryptedERC20(address indexed from, address indexed to, uint128 value);
event SymbolUpdated(string symbol);
/**
* @dev The erc20 token couldn't be wrapped.
*/
error FHERC20InvalidErc20(address token);
/**
* @dev The recipient is the zero address.
*/
error InvalidRecipient();
constructor(
IERC20 erc20_,
string memory symbolOverride_
)
Ownable(msg.sender)
FHERC20(
string.concat("Confidential ", IERC20Metadata(address(erc20_)).name()),
bytes(symbolOverride_).length == 0
? string.concat("e", IERC20Metadata(address(erc20_)).symbol())
: symbolOverride_,
IERC20Metadata(address(erc20_)).decimals()
)
{
try IFHERC20(address(erc20_)).isFherc20() returns (bool isFherc20) {
if (isFherc20) {
revert FHERC20InvalidErc20(address(erc20_));
}
} catch {
// Not an FHERC20, continue
}
_erc20 = erc20_;
_symbol = bytes(symbolOverride_).length == 0
? string.concat("e", IERC20Metadata(address(erc20_)).symbol())
: symbolOverride_;
}
function symbol() public view override returns (string memory) {
return _symbol;
}
function updateSymbol(string memory updatedSymbol) public onlyOwner {
_symbol = updatedSymbol;
emit SymbolUpdated(updatedSymbol);
}
/**
* @dev Returns the address of the erc20 ERC-20 token that is being encrypted wrapped.
*/
function erc20() public view returns (IERC20) {
return _erc20;
}
function encrypt(address to, uint128 value) public {
if (to == address(0)) to = msg.sender;
_erc20.safeTransferFrom(msg.sender, address(this), value);
_mint(to, value);
emit EncryptedERC20(msg.sender, to, value);
}
function decrypt(address to, uint128 value) public {
if (to == address(0)) to = msg.sender;
euint128 burned = _burn(msg.sender, value);
FHE.decrypt(burned);
_createClaim(to, value, burned);
emit DecryptedERC20(msg.sender, to, value);
}
/**
* @notice Claim a decrypted amount of the underlying ERC20
* @param ctHash The ctHash of the burned amount
*/
function claimDecrypted(uint256 ctHash) public {
Claim memory claim = _handleClaim(ctHash);
// Send the ERC20 to the recipient
_erc20.safeTransfer(claim.to, claim.decryptedAmount);
emit ClaimedDecryptedERC20(msg.sender, claim.to, claim.decryptedAmount);
}
/**
* @notice Claim all decrypted amounts of the underlying ERC20
*/
function claimAllDecrypted() public {
Claim[] memory claims = _handleClaimAll();
for (uint256 i = 0; i < claims.length; i++) {
_erc20.safeTransfer(claims[i].to, claims[i].decryptedAmount);
emit ClaimedDecryptedERC20(msg.sender, claims[i].to, claims[i].decryptedAmount);
}
}
}