Constructor
The constructor sets up the initial token configuration:
constructor() Ownable(msg.sender) {
_name = "Confidential USD";
_symbol = "cUSD";
}
Minting Tokens
There are two minting functions for different use cases:
// Standard minting with plaintext amount
function mint(uint256 mintedAmount) public virtual onlyOwner {
balances[owner()] = e.add(
balances[owner()],
e.asEuint256(mintedAmount)
);
e.allow(balances[owner()], address(this));
e.allow(balances[owner()], owner());
_totalSupply += mintedAmount;
emit Mint(owner(), mintedAmount);
}
// Minting with encrypted amount
function _mint(bytes calldata encryptedAmount) public virtual onlyOwner {
balances[msg.sender] = e.add(
balances[msg.sender],
e.newEuint256(encryptedAmount, msg.sender)
);
e.allow(balances[msg.sender], address(this));
e.allow(balances[msg.sender], owner());
e.allow(balances[msg.sender], msg.sender);
}
The _mint
function accepts encrypted amounts for enhanced privacy.
Transfer Functions
Two versions of transfer are available:
// For EOAs using encrypted inputs
function transfer(
address to,
bytes calldata encryptedAmount
) public virtual returns (bool) {
transfer(to, e.newEuint256(encryptedAmount, msg.sender));
return true;
}
// For contract interactions
function transfer(
address to,
euint256 amount
) public virtual returns (bool) {
ebool canTransfer = e.ge(balances[msg.sender], amount);
_transfer(msg.sender, to, amount, canTransfer);
return true;
}
Approval System
The approval system allows delegated spending:
// Approve for EOAs
function approve(
address spender,
bytes calldata encryptedAmount
) public virtual returns (bool) {
approve(spender, e.newEuint256(encryptedAmount, msg.sender));
return true;
}
// Approve for contracts
function approve(
address spender,
euint256 amount
) public virtual returns (bool) {
_approve(msg.sender, spender, amount);
emit Approval(msg.sender, spender);
return true;
}
// Internal approval logic
function _approve(
address owner,
address spender,
euint256 amount
) internal virtual {
allowances[owner][spender] = amount;
e.allow(amount, address(this));
e.allow(amount, owner);
e.allow(amount, spender);
}
TransferFrom Functions
For spending approved tokens:
// TransferFrom for EOAs
function transferFrom(
address from,
address to,
bytes calldata encryptedAmount
) public virtual returns (bool) {
transferFrom(from, to, e.newEuint256(encryptedAmount, msg.sender));
return true;
}
// TransferFrom for contracts
function transferFrom(
address from,
address to,
euint256 amount
) public virtual returns (bool) {
ebool isTransferable = _updateAllowance(from, msg.sender, amount);
_transfer(from, to, amount, isTransferable);
return true;
}
View Functions
Functions to check balances and allowances:
// Get encrypted balance
function balanceOf(address wallet) public view virtual returns (euint256) {
return balances[wallet];
}
// Get encrypted allowance
function allowance(
address owner,
address spender
) public view virtual returns (euint256) {
return _allowance(owner, spender);
}
Owner Functions
Special functions for the contract owner:
// Request balance decryption
function requestUserBalanceDecryption(
address user
) public onlyOwner returns (uint256) {
euint256 encryptedBalance = balances[user];
e.allow(encryptedBalance, address(this));
uint256 requestId = e.requestDecryption(
encryptedBalance,
this.onDecryptionCallback.selector,
""
);
requestIdToUserAddress[requestId] = user;
return requestId;
}
// Decryption callback
function onDecryptionCallback(
uint256 requestId,
bytes32 _decryptedAmount,
bytes memory data
) public returns (bool) {
address userAddress = requestIdToUserAddress[requestId];
emit UserBalanceDecrypted(userAddress, uint256(_decryptedAmount));
return true;
}
Next Steps
See how all these functions come together in the complete contract