Understanding the core functionality of the confidential token
constructor() Ownable(msg.sender) { _name = "Confidential USD"; _symbol = "cUSD"; }
// 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); }
_mint
// 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; }
// 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 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; }
// 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); }
// 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; }
See how all these functions come together in the complete contract
Was this page helpful?