Skip to main content
import {euint256, ebool, eaddress, e} from "@inco/lightning/src/Lib.sol";
using e for *;

Case 1: the value comes from an offchain source

In the confidential transfer example, the first external method is meant to be called by an EOA / Smart account. It is using newEuint256 to convert the input value into a handle.
function transfer(
        address to,
        bytes memory valueInput
    ) external payable returns (ebool) {
        // Muliplied with one cause we consumed only one ciphertext i.e called `newEuint256` once
        require(msg.value >= inco.getFee() * 1, "Fee Not Paid");
        // This call needs the above fee otherwise it will fail
        euint256 value = valueInput.newEuint256(msg.sender);
        // stuff
    }
newEuint256 takes two arguments, the encrypted input value (in the form of bytes) and the address of the account doing the input (here msg.sender). This account should always be the one that created the input, it will be given decryption right over the handle. Passing another address than the user doing the input would be a malicious implementation. Similarly, newEaddress can be used to convert encrypted address inputs into handles:
function setAuthorizedAddress(
    bytes memory addressInput
) external payable {
    require(msg.value >= inco.getFee() * 1, "Fee Not Paid");
    eaddress authorizedAddr = addressInput.newEaddress(msg.sender);
    // stuff
}
newEaddress works identically to newEuint256 but creates an eaddress handle instead of an euint256 handle. It requires the same fee payment and follows the same security principles regarding the originating account. For boolean inputs, newEbool can be used to convert encrypted boolean inputs into handles:
function setFlag(
    bytes memory flagInput
) external payable {
    require(msg.value >= inco.getFee() * 1, "Fee Not Paid");
    ebool flag = flagInput.newEbool(msg.sender);
    // stuff
}
newEbool works identically to newEuint256 but creates an ebool handle instead of an euint256 handle. It requires the same fee payment and follows the same security principles regarding the originating account. valueInput has to be a ciphertext, meaning it has to be the value intended to be transferred, encrypted in a way that Inco can understand. To do this, you can use the encrypt method from the JavaScript SDK. If the bytes memory valueInput is malformed, Inco will fallback to the handle default value. The default value of euint256 is 0, and the default value of ebool is false.
Note: Consuming encrypted inputs on-chain requires paying an encryption fee per ciphertext (newEuint256). Ensure msg.value >= inco.getFee() × ciphertextCount, otherwise the call will revert.
After newEuint256 has been used, the resulting handle can be used immediately, there is no need for Inco to issue a confirmation to start using it in the contract logic. Inco will decrypt the corresponding ciphertext safely inside its TEE after the transaction has been included onchain. All operations onchain are performed virtually over identifiers, and reproduced over the actual values by Inco asynchronously. We call this model “symbolic execution”.
One could try to reuse the same ciphertext as another user to gain decryption access over it. Our JS SDK embeds context information in the ciphertext (originating account, chain, contract), and the value of the created handle will fallback to the default if it is used in another context.

Case 2 : the value comes from a variable

A known value can be turned into a handle using the asEuint256 method. This is sometimes called performing a “trivial encrypt” because the resulting handle will be of a known value. We can see it in the constructor of the token example:
constructor() {
    balanceOf[msg.sender] = uint256(1000 * 1e9).asEuint256();
}
Anyone can see that the initial value of balanceOf[msg.sender] is 1000 * 1e9, but after the deployer sends a few transfers, its balance will be unknown to the public. Similarly, known boolean values can be converted using asEbool:
constructor() {
    isActive = true.asEbool();
}