Skip to main content

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, plus a helper for enforcing fees:
// Helper to enforce that the caller pays the Inco fee
function _requireFee() internal view {
    if (msg.value < inco.getFee()) revert InsufficientFees();
}

// Standard minting with plaintext amount (owner only)
function mint(uint256 mintAmount) public virtual onlyOwner {
    euint256 amount = e.asEuint256(mintAmount);
    balances[owner()] = e.add(balances[owner()], amount);
    e.allow(balances[owner()], address(this));
    e.allow(balances[owner()], owner());
    
    totalSupply = e.add(totalSupply, amount);
    e.reveal(totalSupply);
    emit Mint(owner(), mintAmount);
}

// Minting with encrypted amount (fee required)
function encryptedMint(
    bytes calldata encryptedAmount
) public payable virtual /*onlyOwner*/ {
    _requireFee();
    euint256 amount = e.newEuint256(encryptedAmount, msg.sender);
    e.allow(amount, address(this));
    if(euint256.unwrap(balances[msg.sender]) == bytes32(0)) {
        balances[msg.sender] = amount;
    } else {
        balances[msg.sender] = e.add(balances[msg.sender], amount);
    }
    e.allow(balances[msg.sender], address(this));
    e.allow(balances[msg.sender], owner());
    e.allow(balances[msg.sender], msg.sender);

    totalSupply = e.add(totalSupply, amount);
    e.reveal(totalSupply);
    emit EncryptedMint(msg.sender, amount);
}
The encryptedMint function accepts encrypted amounts for enhanced privacy and requires the caller to pay the Inco fee.

Transfer Functions

Two versions of transfer are available, with a fee required for the encrypted entrypoint:
// For EOAs using encrypted inputs
function transfer(
    address to,
    bytes calldata encryptedAmount
) public payable virtual returns (bool) {
    _requireFee();
    transfer(
        to,
        e.newEuint256(encryptedAmount, msg.sender)
    );
    return true;
}

// For contract interactions
function transfer(
    address to,
    euint256 amount
) public virtual returns (bool) {
    e.allow(amount, address(this));
    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 (encrypted amount, fee required)
function approve(
    address spender,
    bytes calldata encryptedAmount
) public payable virtual returns (bool) {
    _requireFee();
    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, amount);
    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, the encrypted entrypoint also requires a fee:
// TransferFrom for EOAs
function transferFrom(
    address from,
    address to,
    bytes calldata encryptedAmount
) public payable virtual returns (bool) {
    _requireFee();
    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) {
    e.allow(amount, address(this));
    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 total supply
function getTotalSupply() public view virtual returns (euint256) {
    return totalSupply;
}

// Get encrypted allowance
function allowance(
    address owner,
    address spender
) public view virtual returns (euint256) {
    return _allowance(owner, spender);
}

Next Steps

See how all these functions come together in the complete contract