Skip to content

Commit

Permalink
Merge pull request #80 from zama-ai/updates-mintable
Browse files Browse the repository at this point in the history
chore: updates mint functions
  • Loading branch information
PacificYield authored Dec 11, 2024
2 parents 631d8c0 + 9d65731 commit 9a60f83
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 52 deletions.
14 changes: 7 additions & 7 deletions contracts/token/ERC20/ConfidentialERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { TFHEErrors } from "../../utils/TFHEErrors.sol";
* The total supply is not encrypted.
*/
abstract contract ConfidentialERC20 is IConfidentialERC20, IERC20Errors, TFHEErrors {
/// @notice used as a placehoder in Approval and Transfer events to comply with the official EIP20
/// @notice Used as a placeholder in `Approval` & `Transfer` events to comply with the official EIP20.
uint256 internal constant _PLACEHOLDER = type(uint256).max;
/// @notice Total supply.
uint64 internal _totalSupply;
Expand All @@ -34,8 +34,8 @@ abstract contract ConfidentialERC20 is IConfidentialERC20, IERC20Errors, TFHEErr
mapping(address account => mapping(address spender => euint64 allowance)) internal _allowances;

/**
* @param name_ Name of the token.
* @param symbol_ Symbol.
* @param name_ Name of the token.
* @param symbol_ Symbol.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
Expand Down Expand Up @@ -75,7 +75,7 @@ abstract contract ConfidentialERC20 is IConfidentialERC20, IERC20Errors, TFHEErr
function transfer(address to, euint64 amount) public virtual returns (bool) {
_isSenderAllowedForAmount(amount);

/// Make sure the owner has enough tokens.
/// @dev Make sure the owner has enough tokens.
ebool canTransfer = TFHE.le(amount, _balances[msg.sender]);
_transfer(msg.sender, to, amount, canTransfer);
return true;
Expand Down Expand Up @@ -196,7 +196,7 @@ abstract contract ConfidentialERC20 is IConfidentialERC20, IERC20Errors, TFHEErr
revert ERC20InvalidReceiver(to);
}

/// Add to the balance of `to` and subract from the balance of `from`.
/// @dev Add to the balance of `to` and subtract from the balance of `from`.
euint64 transferValue = TFHE.select(isTransferable, amount, TFHE.asEuint64(0));
euint64 newBalanceTo = TFHE.add(_balances[to], transferValue);
_balances[to] = newBalanceTo;
Expand All @@ -210,9 +210,9 @@ abstract contract ConfidentialERC20 is IConfidentialERC20, IERC20Errors, TFHEErr

function _updateAllowance(address owner, address spender, euint64 amount) internal virtual returns (ebool) {
euint64 currentAllowance = _allowance(owner, spender);
/// Make sure sure the allowance suffices.
/// @dev Make sure sure the allowance suffices.
ebool allowedTransfer = TFHE.le(amount, currentAllowance);
/// Make sure the owner has enough tokens.
/// @dev Make sure the owner has enough tokens.
ebool canTransfer = TFHE.le(amount, _balances[owner]);
ebool isTransferable = TFHE.and(canTransfer, allowedTransfer);
_approve(owner, spender, TFHE.select(isTransferable, TFHE.sub(currentAllowance, amount), currentAllowance));
Expand Down
22 changes: 12 additions & 10 deletions contracts/token/ERC20/extensions/ConfidentialERC20Mintable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ abstract contract ConfidentialERC20Mintable is Ownable2Step, ConfidentialERC20 {
event Mint(address indexed to, uint64 amount);

/**
* @param name_ Name of the token.
* @param symbol_ Symbol.
* @param owner_ Owner address.
* @param name_ Name of the token.
* @param symbol_ Symbol.
* @param owner_ Owner address.
*/
constructor(
string memory name_,
Expand All @@ -29,14 +29,16 @@ abstract contract ConfidentialERC20Mintable is Ownable2Step, ConfidentialERC20 {
) Ownable(owner_) ConfidentialERC20(name_, symbol_) {}

/**
* @notice Mint tokens.
* @param amount Amount of tokens to mint.
* @notice Mint tokens.
* @param to Address to mint tokens to.
* @param amount Amount of tokens to mint.
*/
function mint(uint64 amount) public virtual onlyOwner {
_unsafeMint(msg.sender, amount);
/// @dev Since _totalSupply is not encrypted and _totalSupply >= balances[msg.sender],
/// the next line contains an overflow check for the encrypted operation above.
function mint(address to, uint64 amount) public virtual onlyOwner {
_unsafeMint(to, amount);
/// @dev Since _totalSupply is not encrypted and we ensure there is no underflow/overflow of encrypted balances
/// during transfers, making _totalSupply invariant during transfers, we know _totalSupply is greater than
/// all individual balances. Hence, the next line forbids any overflow to happen in the _unsafeMint above.
_totalSupply = _totalSupply + amount;
emit Mint(msg.sender, amount);
emit Mint(to, amount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ abstract contract ConfidentialERC20WithErrorsMintable is Ownable2Step, Confident
event Mint(address indexed to, uint64 amount);

/**
* @param name_ Name of the token.
* @param symbol_ Symbol.
* @param owner_ Owner address.
* @param name_ Name of the token.
* @param symbol_ Symbol.
* @param owner_ Owner address.
*/
constructor(
string memory name_,
Expand All @@ -29,14 +29,16 @@ abstract contract ConfidentialERC20WithErrorsMintable is Ownable2Step, Confident
) Ownable(owner_) ConfidentialERC20WithErrors(name_, symbol_) {}

/**
* @notice Mint tokens.
* @notice Mint tokens.
* @param to Address to mint tokens to.
* @param amount Amount of tokens to mint.
*/
function mint(uint64 amount) public virtual onlyOwner {
_unsafeMint(msg.sender, amount);
/// @dev Since _totalSupply is not encrypted and _totalSupply >= balances[msg.sender],
/// the next line contains an overflow check for the encrypted operation above.
function mint(address to, uint64 amount) public virtual onlyOwner {
_unsafeMint(to, amount);
/// @dev Since _totalSupply is not encrypted and we ensure there is no underflow/overflow of encrypted balances
/// during transfers, making _totalSupply invariant during transfers, we know _totalSupply is greater than
/// all individual balances. Hence, the next line forbids any overflow to happen in the _unsafeMint above.
_totalSupply = _totalSupply + amount;
emit Mint(msg.sender, amount);
emit Mint(to, amount);
}
}
23 changes: 11 additions & 12 deletions test/confidentialERC20/ConfidentialERC20.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe("ConfidentialERC20", function () {

it("should mint the contract", async function () {
const mintAmount = 1000;
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await expect(tx).to.emit(this.confidentialERC20, "Mint").withArgs(this.signers.alice, mintAmount);

expect(
Expand All @@ -48,7 +48,7 @@ describe("ConfidentialERC20", function () {
const mintAmount = 10_000;
const transferAmount = 1337;

let tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

const input = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand Down Expand Up @@ -82,7 +82,7 @@ describe("ConfidentialERC20", function () {
const mintAmount = 1000;
const transferAmount = 1337;

let tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

const input = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand Down Expand Up @@ -117,7 +117,7 @@ describe("ConfidentialERC20", function () {
const mintAmount = 10_000;
const transferAmount = 1337;

let tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

const inputAlice = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand Down Expand Up @@ -245,7 +245,7 @@ describe("ConfidentialERC20", function () {
it("should not be able to read the balance if not user after initialization", async function () {
// Mint is used to initialize the balanceOf(alice)
const amount = 10_000;
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(amount);
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, amount);
await tx.wait();

const balanceHandleAlice = await this.confidentialERC20.balanceOf(this.signers.alice);
Expand Down Expand Up @@ -274,7 +274,7 @@ describe("ConfidentialERC20", function () {
const NULL_ADDRESS = "0x0000000000000000000000000000000000000000";
const mintAmount = 100_000;
const transferAmount = 50_000;
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

const input = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand All @@ -293,7 +293,7 @@ describe("ConfidentialERC20", function () {
it("sender who is not allowed cannot transfer using a handle from another account", async function () {
const mintAmount = 100_000;
const transferAmount = 50_000;
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

const input = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand All @@ -319,7 +319,7 @@ describe("ConfidentialERC20", function () {
const mintAmount = 100_000;
const transferAmount = 50_000;

let tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

let input = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand Down Expand Up @@ -379,9 +379,8 @@ describe("ConfidentialERC20", function () {
});

it("ConfidentialERC20Mintable - only owner can mint", async function () {
await expect(this.confidentialERC20.connect(this.signers.bob).mint(1)).to.be.revertedWithCustomError(
this.confidentialERC20,
"OwnableUnauthorizedAccount",
);
await expect(
this.confidentialERC20.connect(this.signers.bob).mint(this.signers.bob, 1),
).to.be.revertedWithCustomError(this.confidentialERC20, "OwnableUnauthorizedAccount");
});
});
27 changes: 13 additions & 14 deletions test/confidentialERC20/ConfidentialERC20WithErrors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe("ConfidentialERC20WithErrors", function () {

it("should mint the contract", async function () {
const mintAmount = 1000;
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await expect(tx).to.emit(this.confidentialERC20, "Mint").withArgs(this.signers.alice, mintAmount);

expect(
Expand All @@ -50,7 +50,7 @@ describe("ConfidentialERC20WithErrors", function () {
const transferAmount = 1337;
const expectedTransferId = 0n;

let tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

const input = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand Down Expand Up @@ -107,7 +107,7 @@ describe("ConfidentialERC20WithErrors", function () {
const transferAmount = 1337;
const expectedTransferId = 0n;

let tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

const input = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand Down Expand Up @@ -152,7 +152,7 @@ describe("ConfidentialERC20WithErrors", function () {
const mintAmount = 10_000;
const transferAmount = 1337;

let tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

const inputAlice = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand Down Expand Up @@ -306,7 +306,7 @@ describe("ConfidentialERC20WithErrors", function () {
it("should not be able to read the balance if not user after initialization", async function () {
// Mint is used to initialize the balanceOf(alice)
const amount = 10_000;
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(amount);
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, amount);
await tx.wait();

const balanceHandleAlice = await this.confidentialERC20.balanceOf(this.signers.alice);
Expand Down Expand Up @@ -335,7 +335,7 @@ describe("ConfidentialERC20WithErrors", function () {
const NULL_ADDRESS = "0x0000000000000000000000000000000000000000";
const mintAmount = 100_000;
const transferAmount = 50_000;
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

const input = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand All @@ -355,7 +355,7 @@ describe("ConfidentialERC20WithErrors", function () {
const NULL_ADDRESS = "0x0000000000000000000000000000000000000000";
const mintAmount = 100_000;
const transferAmount = 50_000;
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
const tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

const input = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand All @@ -374,7 +374,7 @@ describe("ConfidentialERC20WithErrors", function () {
it("sender who is not allowed cannot transfer using a handle from another account", async function () {
const mintAmount = 100_000;
const transferAmount = 50_000;
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

const input = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand All @@ -400,7 +400,7 @@ describe("ConfidentialERC20WithErrors", function () {
const mintAmount = 100_000;
const transferAmount = 50_000;

let tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

let input = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand Down Expand Up @@ -440,7 +440,7 @@ describe("ConfidentialERC20WithErrors", function () {
const transferAmount = 1337;
const expectedTransferId = 0;

let tx = await this.confidentialERC20.connect(this.signers.alice).mint(mintAmount);
let tx = await this.confidentialERC20.connect(this.signers.alice).mint(this.signers.alice, mintAmount);
await tx.wait();

const input = this.instance.createEncryptedInput(this.confidentialERC20Address, this.signers.alice.address);
Expand Down Expand Up @@ -504,9 +504,8 @@ describe("ConfidentialERC20WithErrors", function () {
});

it("ConfidentialERC20WithErrorsMintable - only owner can mint", async function () {
await expect(this.confidentialERC20.connect(this.signers.bob).mint(1)).to.be.revertedWithCustomError(
this.confidentialERC20,
"OwnableUnauthorizedAccount",
);
await expect(
this.confidentialERC20.connect(this.signers.bob).mint(this.signers.bob.address, 1),
).to.be.revertedWithCustomError(this.confidentialERC20, "OwnableUnauthorizedAccount");
});
});

0 comments on commit 9a60f83

Please sign in to comment.