diff --git a/contracts/ConfidentialERC20/ConfidentialERC20.sol b/contracts/ConfidentialERC20/ConfidentialERC20.sol index 22bc767..d654a11 100644 --- a/contracts/ConfidentialERC20/ConfidentialERC20.sol +++ b/contracts/ConfidentialERC20/ConfidentialERC20.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; import { IConfidentialERC20 } from "./Interfaces/IConfidentialERC20.sol"; import { IERC20Metadata } from "./Utils/IERC20Metadata.sol"; @@ -228,7 +228,7 @@ abstract contract ConfidentialERC20 is Ownable, IConfidentialERC20, IERC20Metada } _balances[account] = TFHE.add(_balances[account], value); TFHE.allow(_balances[account], address(this)); - TFHE.allow(_balances[account], msg.sender); + TFHE.allow(_balances[account], account); _totalSupply += value; } diff --git a/contracts/ConfidentialERC20/ConfidentialToken.sol b/contracts/ConfidentialERC20/ConfidentialToken.sol index 52bcad8..dd99434 100644 --- a/contracts/ConfidentialERC20/ConfidentialToken.sol +++ b/contracts/ConfidentialERC20/ConfidentialToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; import "./ConfidentialERC20.sol"; import "fhevm/lib/TFHE.sol"; diff --git a/contracts/ConfidentialERC20/Interfaces/IConfidentialERC20.sol b/contracts/ConfidentialERC20/Interfaces/IConfidentialERC20.sol index 31bca2d..b0807f7 100644 --- a/contracts/ConfidentialERC20/Interfaces/IConfidentialERC20.sol +++ b/contracts/ConfidentialERC20/Interfaces/IConfidentialERC20.sol @@ -2,7 +2,7 @@ // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) import "fhevm/lib/TFHE.sol"; -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; /** * @dev Interface of the ERC-20 standard as defined in the ERC. diff --git a/contracts/ConfidentialERC20/Utils/Context.sol b/contracts/ConfidentialERC20/Utils/Context.sol index e110234..416dae4 100644 --- a/contracts/ConfidentialERC20/Utils/Context.sol +++ b/contracts/ConfidentialERC20/Utils/Context.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; /** * @dev Provides information about the current execution context, including the diff --git a/contracts/ConfidentialERC20/Utils/IERC20Metadata.sol b/contracts/ConfidentialERC20/Utils/IERC20Metadata.sol index 7ac255f..7860ad5 100644 --- a/contracts/ConfidentialERC20/Utils/IERC20Metadata.sol +++ b/contracts/ConfidentialERC20/Utils/IERC20Metadata.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; import { IConfidentialERC20 } from "../Interfaces/IConfidentialERC20.sol"; diff --git a/contracts/ConfidentialERC20/Utils/IERC6093.sol b/contracts/ConfidentialERC20/Utils/IERC6093.sol index 2358037..e7672ca 100644 --- a/contracts/ConfidentialERC20/Utils/IERC6093.sol +++ b/contracts/ConfidentialERC20/Utils/IERC6093.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; /** * @dev Standard ERC-20 Errors diff --git a/contracts/ConfidentialERC20Wrapper.sol b/contracts/ConfidentialERC20Wrapper.sol index 096764d..1c94e25 100644 --- a/contracts/ConfidentialERC20Wrapper.sol +++ b/contracts/ConfidentialERC20Wrapper.sol @@ -6,10 +6,16 @@ import "fhevm/gateway/GatewayCaller.sol"; import { ConfidentialToken } from "./ConfidentialERC20/ConfidentialToken.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +interface IERC20extended is IERC20 { + function decimals() external view returns (uint8); +} contract ConfidentialERC20Wrapper is ConfidentialToken { + using SafeERC20 for IERC20; IERC20 public baseERC20; mapping(address => bool) public unwrapDisabled; + uint8 private _decimals; event Wrap(address indexed account, uint64 amount); event Unwrap(address indexed account, uint64 amount); event Burn(address indexed account, uint64 amount); @@ -17,14 +23,22 @@ contract ConfidentialERC20Wrapper is ConfidentialToken { error UnwrapNotAllowed(address account); constructor(address _baseERC20) ConfidentialToken("Wrapped cERC20", "wcERC20") { + uint8 baseERCdecimals = IERC20extended(_baseERC20).decimals(); + require(baseERCdecimals <= 6, "Base ERC20 token must have 6 or less decimals"); baseERC20 = IERC20(_baseERC20); + _decimals = baseERCdecimals; + // set the wrapper decimals to be the same as the base token + } + + function decimals() public view override returns (uint8) { + return _decimals; } function wrap(uint64 amount) external { uint256 _amount = uint256(amount); uint256 allowance = baseERC20.allowance(msg.sender, address(this)); require(allowance >= _amount, "Not enough allowance"); - baseERC20.transferFrom(msg.sender, address(this), _amount); + baseERC20.safeTransferFrom(msg.sender, address(this), _amount); _mint(msg.sender, uint64(amount)); emit Wrap(msg.sender, amount); } @@ -47,7 +61,7 @@ contract ConfidentialERC20Wrapper is ConfidentialToken { } // Call base ERC20 transfer and emit Unwrap event - baseERC20.transfer(account, amount); + baseERC20.safeTransfer(account, amount); emit Unwrap(account, amount); // Continue with the burn logic diff --git a/contracts/ERC20.sol b/contracts/ERC20.sol index 4d7502c..7b1de7f 100644 --- a/contracts/ERC20.sol +++ b/contracts/ERC20.sol @@ -8,4 +8,7 @@ contract MyToken is ERC20 { constructor() ERC20("MyToken", "MTK") { _mint(msg.sender, 1000); } + function decimals() public pure override returns (uint8) { + return 6; + } } diff --git a/test/ConfidentialERC20Tests/ConfidentialERC20.ts b/test/ConfidentialERC20Tests/ConfidentialERC20.ts index 2bddf2d..4d03c4f 100644 --- a/test/ConfidentialERC20Tests/ConfidentialERC20.ts +++ b/test/ConfidentialERC20Tests/ConfidentialERC20.ts @@ -43,7 +43,32 @@ describe("Confidential ERC20 tests", function () { const totalSupply = await this.erc20.totalSupply(); expect(totalSupply).to.equal(1000); }); + it("should mint to bob", async function () { + const transaction = await this.erc20.mint(this.signers.bob, 1000); + await transaction.wait(); + + //Reencrypt Bob's balance + const balanceHandleBob = await this.erc20.balanceOf(this.signers.bob); + const { publicKey: publicKeyBob, privateKey: privateKeyBob } = this.instances.bob.generateKeypair(); + const eip712 = this.instances.bob.createEIP712(publicKeyBob, this.contractAddress); + const signatureBob = await this.signers.bob.signTypedData( + eip712.domain, + { Reencrypt: eip712.types.Reencrypt }, + eip712.message, + ); + const balanceBob = await this.instances.bob.reencrypt( + balanceHandleBob, + privateKeyBob, + publicKeyBob, + signatureBob.replace("0x", ""), + this.contractAddress, + this.signers.bob.address, + ); + expect(balanceBob).to.equal(1000); + const totalSupply = await this.erc20.totalSupply(); + expect(totalSupply).to.equal(1000); + }); it("should transfer tokens between two users", async function () { const transaction = await this.erc20.mint(this.signers.alice, 10000); const t1 = await transaction.wait();