📄Remix FHE Demo Local Deployment Tutorial- Deploying Contracts Using Remix

Let’s walk through the steps for deploying the provided CombinedContract.sol and Example.sol contracts using the Remix IDE. We’ll also explain some key components of the contracts to provide you with a better understanding of how they work.

Prerequisites

â€ĸ Make sure you have installed MetaMask and configured it to connect to your local test network, as described in Step 3: Deployment Configuration from earlier.

â€ĸ Open Remix IDE in your browser.

Step-by-Step Deployment in Remix

Open Remix and Create New Files

1. Open Remix IDE.

2. In the File Explorer (left panel), click on the + icon to create new files.

3. Create two new files named:

â€ĸ CombinedContract.sol

â€ĸ Example.sol

Copy and Paste Contract Code

1. CombinedContract.sol:

// Sources flattened with hardhat v2.22.7 https://hardhat.org

// SPDX-License-Identifier: MIT

// File contracts/Oracle/utils/Context.sol

// Original license: SPDX_License_Identifier: MIT
// Below codes are referred from @openzeppelin: [https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/]

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}


// File contracts/Oracle/access/Ownable.sol

// Original license: SPDX_License_Identifier: MIT
// Below codes are referred from @openzeppelin: [https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/]

pragma solidity ^0.8.0;

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}


// File contracts/Oracle/access/Ownable2Step.sol

// Original license: SPDX_License_Identifier: MIT
// Below codes are referred from @openzeppelin: [https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/]

pragma solidity ^0.8.0;

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
        _transferOwnership(sender);
    }
}


// File contracts/Oracle/Types.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity ^0.8.20;

type ebool is uint256;
type euint4 is uint256;
type euint8 is uint256;
type euint16 is uint256;
type euint32 is uint256;
type euint64 is uint256;
type eaddress is uint256;

type op is uint256;

struct CapsulatedValue {
    uint256 data;
    uint8 valueType;
}

struct Operation {
    uint8 opcode;
    uint256[] operands; // Indices of the operands within the request
    uint64 value; // Direct value if applicable
}

struct Request {
    address requester;
    Operation[] ops;
    uint256 opsCursor;
    address callbackAddr;
    bytes4 callbackFunc;
    bytes payload;
}

struct ReencryptRequest {
    address requester;
    CapsulatedValue target;
    bytes32 publicKey;
    bytes signature;
    address callbackAddr;
    bytes4 callbackFunc;
}

struct SaveCiphertextRequest {
    address requester;
    bytes ciphertext;
    uint8 ciphertextType;
    address callbackAddr;
    bytes4 callbackFunc;
}

library Opcode {
    // Encrypted_Op
    uint8 internal constant get_euint64 = 0;
    uint8 internal constant get_ebool = 1;
    uint8 internal constant rand_euint64 = 2;
    uint8 internal constant add_euint64_euint64 = 3;
    uint8 internal constant add_euint64_uint64 = 4;
    uint8 internal constant sub_euint64_euint64 = 5;
    uint8 internal constant sub_euint64_uint64 = 6;
    uint8 internal constant sub_uint64_euint64 = 7;

    uint8 internal constant mul = 8;
    uint8 internal constant div_euint64_euint64 = 9; // division
    uint8 internal constant div_euint64_uint64 = 10; // division
    uint8 internal constant div_uint64_euint64 = 11; // division
    uint8 internal constant and_euint64_euint64 = 12;
    uint8 internal constant and_euint64_uint64 = 13;
    uint8 internal constant and_uint64_euint64 = 14;
    uint8 internal constant or_euint64_euint64 = 15;
    uint8 internal constant or_euint64_uint64 = 16;
    uint8 internal constant or_uint64_euint64 = 17;
    uint8 internal constant xor_euint64_euint64 = 18;
    uint8 internal constant xor_euint64_uint64 = 19;
    uint8 internal constant xor_uint64_euint64 = 20;
    uint8 internal constant rem_euint64_euint64 = 21; // remainder
    uint8 internal constant rem_euint64_uint64 = 22; // remainder
    uint8 internal constant rem_uint64_euint64 = 23; // remainder

    // Encrypted Compare
    uint8 internal constant eq_euint64_euint64 = 24; // equal
    uint8 internal constant eq_euint64_uint64 = 25;
    uint8 internal constant eq_uint64_euint64 = 26;
    uint8 internal constant ne_euint64_euint64 = 27; // not equal
    uint8 internal constant ne_euint64_uint64 = 28;
    uint8 internal constant ne_uint64_euint64 = 29;
    uint8 internal constant ge_euint64_euint64 = 30; // greater or equal
    uint8 internal constant ge_euint64_uint64 = 31;
    uint8 internal constant ge_uint64_euint64 = 32;
    uint8 internal constant gt_euint64_euint64 = 33; // greater than
    uint8 internal constant gt_euint64_uint64 = 34;
    uint8 internal constant gt_uint64_euint64 = 35;
    uint8 internal constant le_euint64_euint64 = 36; // less or equal
    uint8 internal constant le_euint64_uint64 = 37;
    uint8 internal constant le_uint64_euint64 = 38;
    uint8 internal constant lt_euint64_euint64 = 39; // less than
    uint8 internal constant lt_euint64_uint64 = 40;
    uint8 internal constant lt_uint64_euint64 = 41;

    uint8 internal constant min = 42;
    uint8 internal constant max = 43;

    uint8 internal constant shl = 44; // shift left
    uint8 internal constant shr = 45; // shift right
    uint8 internal constant rotl = 46; // rotate left
    uint8 internal constant rotr = 47; // rotate right

    uint8 internal constant select = 48; // select(ebool, value1, value2)
    uint8 internal constant decrypt_ebool = 49;
    uint8 internal constant decrypt_euint64 = 50;
    uint8 internal constant decrypt_eaddress = 51;
    uint8 internal constant decrypt_ebool_async = 52;
    uint8 internal constant decrypt_euint64_async = 53;
    uint8 internal constant decrypt_eaddress_async = 54;

    uint8 internal constant min_euint64_uint64 = 55;
    uint8 internal constant max_euint64_uint64 = 56;

    uint8 internal constant rand_ebool = 57;
    uint8 internal constant get_eaddress = 58;

    uint8 internal constant eq = 59; // equal
    uint8 internal constant ne = 60; // not equal
}

library Types {
    uint8 internal constant T_BOOL = 1;
    uint8 internal constant T_UINT64 = T_BOOL + 1;
    uint8 internal constant T_ADDRESS = T_BOOL + 2;

    uint8 internal constant T_EBOOL = 128;
    uint8 internal constant T_EUINT64 = T_EBOOL + 1;
    uint8 internal constant T_EADDRESS = T_EBOOL + 2;
}


// File contracts/Oracle/CapsulatedValueResolver.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity ^0.8.20;

library CapsulatedValueResolver {
    function asCapsulatedValue(ebool eb) internal pure returns (CapsulatedValue memory) {
        return CapsulatedValue(ebool.unwrap(eb), Types.T_EBOOL);
    }

    function asCapsulatedValue(euint64 eu64) internal pure returns (CapsulatedValue memory) {
        return CapsulatedValue(euint64.unwrap(eu64), Types.T_EUINT64);
    }

    function asCapsulatedValue(eaddress eaddr) internal pure returns (CapsulatedValue memory) {
        return CapsulatedValue(eaddress.unwrap(eaddr), Types.T_EADDRESS);
    }
}


// File contracts/Oracle/constants/OracleAddresses.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity ^0.8.0;

address constant ORACLE_ADDR_OP_SEPOLIA = 0xf1F4540bff12e376184B9624822C782A012B3140;
address constant ORACLE_ADDR_HOLESKY = 0x5c84d4dBD316252DC79dac7534aEE7F91E29eFAE;


// File contracts/Oracle/ReencryptRequestBuilder.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity ^0.8.20;

library ReencryptRequestBuilder {
    function newReencryptRequest(
        address requester,
        CapsulatedValue memory target,
        bytes32 publicKey,
        bytes calldata signature,
        address callbackAddr,
        bytes4 callbackFunc
    ) internal pure returns (ReencryptRequest memory) {
        require(target.valueType != 0, "not initialized data");
        ReencryptRequest memory r = ReencryptRequest({
            requester: requester,
            target: target,
            publicKey: publicKey,
            signature: signature,
            callbackAddr: callbackAddr,
            callbackFunc: callbackFunc
        });
        return r;
    }
}


// File contracts/Oracle/RequestBuilder.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity ^0.8.20;

library RequestBuilder {
    function newRequest(
        address requester,
        uint256 opsLength,
        address callbackAddr,
        bytes4 callbackFunc,
        bytes memory payload
    ) internal pure returns (Request memory) {
        Operation[] memory ops = new Operation[](opsLength);
        Request memory r = Request({
            requester: requester,
            ops: ops,
            opsCursor: 0,
            callbackAddr: callbackAddr,
            callbackFunc: callbackFunc,
            payload: payload
        });
        return r;
    }

    function newRequest(
        address requester,
        uint256 opsLength,
        address callbackAddr,
        bytes4 callbackFunc
    ) internal pure returns (Request memory) {
        Operation[] memory ops = new Operation[](opsLength);
        Request memory r = Request({
            requester: requester,
            ops: ops,
            opsCursor: 0,
            callbackAddr: callbackAddr,
            callbackFunc: callbackFunc,
            payload: ""
        });
        return r;
    }

    // load an encrypted value into the execution context
    function getEbool(Request memory r, ebool input) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.get_ebool, operands: new uint256[](1), value: 0 });
        _op.operands[0] = ebool.unwrap(input);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    function getEaddress(Request memory r, eaddress input) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.get_eaddress, operands: new uint256[](1), value: 0 });
        _op.operands[0] = eaddress.unwrap(input);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    function getEuint64(Request memory r, euint64 input) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.get_euint64, operands: new uint256[](1), value: 0 });
        _op.operands[0] = euint64.unwrap(input);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // request a random euint64
    function rand(Request memory r) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.rand_euint64,
            operands: new uint256[](0), // Create an empty array
            value: 0
        });

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // add euint64 with euint64
    function add(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.add_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // add euint64 with uint64
    function add(Request memory r, op index, uint64 plaintextValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.add_euint64_uint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // sub euint64 with euint64
    function sub(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.sub_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // sub euint64 with uint64
    function sub(Request memory r, op index, uint64 plaintextValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.sub_euint64_uint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // sub uint64 with euint64
    function sub(Request memory r, uint64 plaintextValue, op index) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.sub_uint64_euint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // mul euint64 with euint64
    function mul(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.mul, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // mul euint64 with uint64
    function mul(Request memory r, op index, uint64 plaintextValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.mul, operands: new uint256[](1), value: plaintextValue });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // div euint64 with euint64
    function div(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.div_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // div euint64 with uint64
    function div(Request memory r, op index, uint64 plaintextValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.div_euint64_uint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // div uint64 with euint64
    function div(Request memory r, uint64 plaintextValue, op index) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.div_uint64_euint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // and euint64 with euint64
    function and(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.and_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // and euint64 with uint64
    function and(Request memory r, op index, uint64 plaintextValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.and_euint64_uint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // or euint64 with euint64
    function or(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.or_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // or euint64 with uint64
    function or(Request memory r, op index, uint64 plaintextValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.or_euint64_uint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // xor euint64 with euint64
    function xor(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.xor_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // xor euint64 with uint64
    function xor(Request memory r, op index, uint64 plaintextValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.xor_euint64_uint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // rem euint64 with euint64
    function rem(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.rem_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // rem euint64 with uint64
    function rem(Request memory r, op index, uint64 plaintextValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.rem_euint64_uint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // rem uint64 with euint64
    function rem(Request memory r, uint64 plaintextValue, op index) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.rem_uint64_euint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // eq euint64 with euint64
    function eq(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.eq_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // eq euint64 with uint64
    function eq(Request memory r, op leftIndex, uint64 rightValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.eq_euint64_uint64,
            operands: new uint256[](2),
            value: rightValue
        });
        _op.operands[0] = op.unwrap(leftIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // eq uint64 with euint64
    function eq(Request memory r, uint64 leftValue, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.eq_uint64_euint64,
            operands: new uint256[](2),
            value: leftValue
        });
        _op.operands[0] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // ne euint64 with euint64
    function ne(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.ne_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // ne euint64 with uint64
    function ne(Request memory r, op leftIndex, uint64 rightValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.ne_euint64_uint64,
            operands: new uint256[](2),
            value: rightValue
        });
        _op.operands[0] = op.unwrap(leftIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // ne uint64 with euint64
    function ne(Request memory r, uint64 leftValue, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.ne_uint64_euint64,
            operands: new uint256[](2),
            value: leftValue
        });
        _op.operands[0] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // ge euint64 with euint64
    function ge(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.ge_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // ge euint64 with uint64
    function ge(Request memory r, op leftIndex, uint64 rightValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.ge_euint64_uint64,
            operands: new uint256[](2),
            value: rightValue
        });
        _op.operands[0] = op.unwrap(leftIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // ge uint64 with euint64
    function ge(Request memory r, uint64 leftValue, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.ge_uint64_euint64,
            operands: new uint256[](2),
            value: leftValue
        });
        _op.operands[0] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // gt euint64 with euint64
    function gt(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.gt_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // gt euint64 with uint64
    function gt(Request memory r, op leftIndex, uint64 rightValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.gt_euint64_uint64,
            operands: new uint256[](2),
            value: rightValue
        });
        _op.operands[0] = op.unwrap(leftIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // gt uint64 with euint64
    function gt(Request memory r, uint64 leftValue, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.gt_uint64_euint64,
            operands: new uint256[](2),
            value: leftValue
        });
        _op.operands[0] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // le euint64 with euint64
    function le(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.le_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // le euint64 with uint64
    function le(Request memory r, op leftIndex, uint64 rightValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.le_euint64_uint64,
            operands: new uint256[](2),
            value: rightValue
        });
        _op.operands[0] = op.unwrap(leftIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // le uint64 with euint64
    function le(Request memory r, uint64 leftValue, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.le_uint64_euint64,
            operands: new uint256[](2),
            value: leftValue
        });
        _op.operands[0] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // lt euint64 with euint64
    function lt(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.lt_euint64_euint64, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // lt euint64 with uint64
    function lt(Request memory r, op leftIndex, uint64 rightValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.lt_euint64_uint64,
            operands: new uint256[](2),
            value: rightValue
        });
        _op.operands[0] = op.unwrap(leftIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // lt uint64 with euint64
    function lt(Request memory r, uint64 leftValue, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.lt_uint64_euint64,
            operands: new uint256[](2),
            value: leftValue
        });
        _op.operands[0] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // min euint64 with euint64
    function min(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.min, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // min euint64 with uint64
    function min(Request memory r, op leftIndex, uint64 plaintextValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.min_euint64_uint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(leftIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // min uint64 with euint64
    function min(Request memory r, uint64 plaintextValue, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.min_euint64_uint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // max euint64 with euint64
    function max(Request memory r, op leftIndex, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.max, operands: new uint256[](2), value: 0 });
        _op.operands[0] = op.unwrap(leftIndex);
        _op.operands[1] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // max euint64 with uint64
    function max(Request memory r, op leftIndex, uint64 plaintextValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.max_euint64_uint64,
            operands: new uint256[](2),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(leftIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // max uint64 with euint64
    function max(Request memory r, uint64 plaintextValue, op rightIndex) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({
            opcode: Opcode.max_euint64_uint64,
            operands: new uint256[](1),
            value: plaintextValue
        });
        _op.operands[0] = op.unwrap(rightIndex);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // shl euint64
    function shl(Request memory r, op index, uint64 shiftValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.shl, operands: new uint256[](1), value: shiftValue });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // shr euint64
    function shr(Request memory r, op index, uint64 shiftValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.shr, operands: new uint256[](1), value: shiftValue });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // rotl euint64
    function rotl(Request memory r, op index, uint64 rotateValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.rotl, operands: new uint256[](1), value: rotateValue });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // rotr euint64
    function rotr(Request memory r, op index, uint64 rotateValue) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.rotr, operands: new uint256[](1), value: rotateValue });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // select(ebool, value1, value2)
    function select(Request memory r, op eboolIndex, op value1Index, op value2Index) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.select, operands: new uint256[](3), value: 0 });
        _op.operands[0] = op.unwrap(eboolIndex);
        _op.operands[1] = op.unwrap(value1Index);
        _op.operands[2] = op.unwrap(value2Index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // decrypt euint64
    function decryptEuint64(Request memory r, op index) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.decrypt_euint64, operands: new uint256[](1), value: 0 });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // decrypt ebool
    function decryptEbool(Request memory r, op index) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.decrypt_ebool, operands: new uint256[](1), value: 0 });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // decrypt eaddress
    function decryptEaddress(Request memory r, op index) internal pure returns (op) {
        require(r.opsCursor < r.ops.length, "Operations array is full");
        Operation memory _op = Operation({ opcode: Opcode.decrypt_eaddress, operands: new uint256[](1), value: 0 });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // decrypt euint64 async
    function decryptEuint64Async(Request memory r, op index) internal pure returns (op) {
        require(r.opsCursor + 1 == r.ops.length, "Async Operation Need To Be The Latest.");
        Operation memory _op = Operation({
            opcode: Opcode.decrypt_euint64_async,
            operands: new uint256[](1),
            value: 0
        });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // decrypt ebool async
    function decryptEboolAsync(Request memory r, op index) internal pure returns (op) {
        require(r.opsCursor + 1 == r.ops.length, "Async Operation Need To Be The Latest.");
        Operation memory _op = Operation({ opcode: Opcode.decrypt_ebool_async, operands: new uint256[](1), value: 0 });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }

    // decrypt eaddress async
    function decryptEaddressAsync(Request memory r, op index) internal pure returns (op) {
        require(r.opsCursor + 1 == r.ops.length, "Async Operation Need To Be The Latest.");
        Operation memory _op = Operation({
            opcode: Opcode.decrypt_eaddress_async,
            operands: new uint256[](1),
            value: 0
        });
        _op.operands[0] = op.unwrap(index);

        r.ops[r.opsCursor] = _op;
        r.opsCursor += 1;

        return op.wrap(r.opsCursor - 1);
    }
}


// File contracts/Oracle/SaveCiphertextRequestBuilder.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity ^0.8.20;

library SaveCiphertextRequestBuilder {
    function newSaveCiphertextRequest(
        address requester,
        bytes calldata ciphertext,
        uint8 ciphertextType,
        address callbackAddr,
        bytes4 callbackFunc
    ) internal pure returns (SaveCiphertextRequest memory) {
        SaveCiphertextRequest memory r = SaveCiphertextRequest({
            requester: requester,
            ciphertext: ciphertext,
            ciphertextType: ciphertextType,
            callbackAddr: callbackAddr,
            callbackFunc: callbackFunc
        });
        return r;
    }
}


// File contracts/Oracle/Oracle.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity ^0.8.20;





Oracle constant oracleOpSepolia = Oracle(ORACLE_ADDR_OP_SEPOLIA);

contract Oracle is Ownable2Step {
    mapping(bytes32 => Request) requests;
    mapping(bytes32 => ReencryptRequest) reenc_requests;
    mapping(bytes32 => SaveCiphertextRequest) save_ciphertext_requests;

    event RequestSent(bytes32 indexed reqId, Request req);
    event RequestCallback(bytes32 indexed reqId, bool indexed success);

    event ReencryptSent(bytes32 indexed reqId, ReencryptRequest req);
    event ReencryptCallback(bytes32 indexed reqId, bool indexed success);

    event SaveCiphertextSent(bytes32 indexed reqId, SaveCiphertextRequest req);
    event SaveCiphertextCallback(bytes32 indexed reqId, bool indexed success);

    string public constant VERSION = "0.0.3-SNAPSHOT";

    uint256 private nonce;

    function send(Request memory req) external returns (bytes32) {
        bytes32 reqId = keccak256(abi.encodePacked(nonce++, req.requester, block.number));
        Request storage request = requests[reqId];
        request.requester = req.requester;
        request.opsCursor = req.opsCursor;
        request.callbackAddr = req.callbackAddr;
        request.callbackFunc = req.callbackFunc;
        request.payload = req.payload;
        Operation[] storage ops = request.ops;
        for (uint256 i; i < req.ops.length; i++) {
            ops.push(req.ops[i]);
        }
        emit RequestSent(reqId, request);
        return reqId;
    }

    function callback(bytes32 reqId, CapsulatedValue[] memory result) public onlyOwner {
        Request memory req = requests[reqId];
        (bool success, bytes memory bb) = req.callbackAddr.call(
            abi.encodeWithSelector(req.callbackFunc, reqId, result)
        );
        if (!success) {
            string memory err = abi.decode(bb, (string));
            revert(err);
        }
        emit RequestCallback(reqId, success);
    }

    function send(ReencryptRequest memory req) public returns (bytes32) {
        bytes32 reqId = keccak256(abi.encodePacked(nonce++, req.requester, block.number));
        reenc_requests[reqId] = req;
        emit ReencryptSent(reqId, req);
        return reqId;
    }

    function reencryptCallback(bytes32 reqId, bytes memory result) public onlyOwner {
        ReencryptRequest memory req = reenc_requests[reqId];
        (bool success, bytes memory bb) = req.callbackAddr.call(
            abi.encodeWithSelector(req.callbackFunc, reqId, result)
        );
        if (!success) {
            string memory err = abi.decode(bb, (string));
            revert(err);
        }
        emit ReencryptCallback(reqId, success);
    }

    function send(SaveCiphertextRequest memory req) public returns (bytes32) {
        bytes32 reqId = keccak256(abi.encodePacked(nonce++, req.requester, block.number));
        emit SaveCiphertextSent(reqId, req);
        delete req.ciphertext;
        save_ciphertext_requests[reqId] = req;
        return reqId;
    }

    function saveCiphertextCallback(bytes32 reqId, CapsulatedValue memory result) public onlyOwner {
        SaveCiphertextRequest memory req = save_ciphertext_requests[reqId];
        (bool success, bytes memory bb) = req.callbackAddr.call(
            abi.encodeWithSelector(req.callbackFunc, reqId, result)
        );
        if (!success) {
            string memory err = abi.decode(bb, (string));
            revert(err);
        }
        emit SaveCiphertextCallback(reqId, success);
    }
}


// File contracts/Oracle/ResponseResolver.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity ^0.8.20;

library ResponseResolver {
    function asBool(CapsulatedValue memory capsulatedValue) internal pure returns (bool) {
        require(capsulatedValue.valueType == Types.T_BOOL, "Invalid valueType for Bool");
        return (capsulatedValue.data % 2) == 1;
    }

    function asUint64(CapsulatedValue memory capsulatedValue) internal pure returns (uint64) {
        require(capsulatedValue.valueType == Types.T_UINT64, "Invalid valueType for Uint64");
        return uint64(capsulatedValue.data);
    }

    function asAddress(CapsulatedValue memory capsulatedValue) internal pure returns (address) {
        require(capsulatedValue.valueType == Types.T_ADDRESS, "Invalid valueType for address");
        return address(uint160(capsulatedValue.data));
    }

    function asEbool(CapsulatedValue memory capsulatedValue) internal pure returns (ebool) {
        require(capsulatedValue.valueType == Types.T_EBOOL, "Invalid valueType for Ebool");
        return ebool.wrap(capsulatedValue.data);
    }

    function asEuint64(CapsulatedValue memory capsulatedValue) internal pure returns (euint64) {
        require(capsulatedValue.valueType == Types.T_EUINT64, "Invalid valueType for Euint64");
        return euint64.wrap(capsulatedValue.data);
    }

    function asEaddress(CapsulatedValue memory capsulatedValue) internal pure returns (eaddress) {
        require(capsulatedValue.valueType == Types.T_EADDRESS, "Invalid valueType for Eaddress");
        return eaddress.wrap(capsulatedValue.data);
    }
}

2. Example.sol:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./CombinedContracts.sol";

contract Example {
    using RequestBuilder for Request;
    using ResponseResolver for CapsulatedValue;
    
    Oracle public immutable oracle;
    euint64 private target;
    
    event RequestSent(bytes32 indexed reqId);
    event TargetUpdated(uint256 newTarget);
    event DebugLog(string message);
    event DebugValue(string message, uint256 value);
    event ErrorLog(string message);
    
        constructor() payable {
        oracle = Oracle(payable(0x5FbDB2315678afecb367f032d93F642f64180aa3));
        emit DebugLog("Contract initialized");
        emit DebugValue("Oracle address", uint256(uint160(address(oracle))));
    }
    

    
    function createRandomTarget() public {
        emit DebugLog("Starting createRandomTarget");
        
        try this.createRandomTargetInternal() {
            emit DebugLog("createRandomTarget completed successfully");
        } catch Error(string memory reason) {
            emit ErrorLog(string(abi.encodePacked("Failed: ", reason)));
            revert(reason);
        } catch (bytes memory) {
            emit ErrorLog("Failed with low-level error");
            revert("Unknown error in createRandomTarget");
        }
    }
    
    function createRandomTargetInternal() public {
        emit DebugLog("Creating request");
        Request memory req = RequestBuilder.newRequest(
            msg.sender,
            2,
            address(this),
            this.randomTargetCallback.selector,
            abi.encode("random")
        );
        emit DebugLog("Request created");
        
        emit DebugLog("Generating random operation");
        op randOp = RequestBuilder.rand(req);
        emit DebugLog("Random operation generated");
        
        emit DebugLog("Setting up decrypt operation");
        RequestBuilder.decryptEuint64Async(req, randOp);
        emit DebugLog("Decrypt operation set");
        
        emit DebugLog("Sending request to oracle");
        bytes32 reqId = oracle.send(req);
        emit RequestSent(reqId);
        emit DebugValue("Request ID", uint256(reqId));
    }
    
    function randomTargetCallback(bytes32 /* reqId */, CapsulatedValue[] memory result) public {
        emit DebugLog("Callback received");
        
        require(msg.sender == address(oracle), "Only oracle can call this function");
        emit DebugValue("Caller address", uint256(uint160(msg.sender)));
        
        require(result.length > 0, "Empty result array");
        emit DebugValue("Result array length", result.length);
        
        uint64 randomValue = ResponseResolver.asUint64(result[0]);
        emit DebugValue("Random value", randomValue);
        
        target = euint64.wrap(uint256(randomValue));
        emit DebugValue("Target set", euint64.unwrap(target));
        
        emit TargetUpdated(euint64.unwrap(target));
        emit DebugLog("Callback completed");
    }
    
    function makeComputation(uint64 amount) public {
        emit DebugLog("Starting makeComputation");
        emit DebugValue("Input amount", amount);
        
        Request memory req = RequestBuilder.newRequest(
            msg.sender,
            4,
            address(this),
            this.computationCallback.selector,
            abi.encode(amount)
        );
        
        op targetOp = RequestBuilder.getEuint64(req, target);
        op amountOp = RequestBuilder.getEuint64(req, euint64.wrap(uint256(amount)));
        op addOp = RequestBuilder.add(req, targetOp, amountOp);
        RequestBuilder.decryptEuint64Async(req, addOp);
        
        bytes32 reqId = oracle.send(req);
        emit RequestSent(reqId);
        emit DebugValue("Computation request ID", uint256(reqId));
    }
    
    function computationCallback(bytes32 /* reqId */, CapsulatedValue[] memory result) public {
        emit DebugLog("Computation callback received");
        
        require(msg.sender == address(oracle), "Only oracle can call this function");
        require(result.length > 0, "Empty result array");
        
        uint64 computedValue = ResponseResolver.asUint64(result[0]);
        emit DebugValue("Computed value", computedValue);
        
        target = euint64.wrap(uint256(computedValue));
        emit TargetUpdated(euint64.unwrap(target));
        emit DebugLog("Computation callback completed");
    }
    
    function getTarget() public view returns (uint256) {
        return euint64.unwrap(target);
    }
} 

Compile the Contracts

1. Click on the Solidity Compiler tab (second icon from the top in the left toolbar).

2. Ensure the compiler version is set to 0.8.20 (or a compatible version with your code).

3. Click Compile CombinedContract.sol and Compile Example.sol.

â€ĸ If there are any warnings or errors, double-check the code and try compiling again.

â€ĸ Compilation warnings are common and often do not prevent deployment.

Deploy the Contracts Using Remix

1. Click on the Deploy & Run Transactions tab (third icon from the top in the left toolbar).

2. Set Environment:

â€ĸ Select Custom-External Http Provider

3. Deploy Example.sol:

â€ĸ Select Example.sol from the contract dropdown.

â€ĸ Click Deploy and waiting for depoly completion.

Last updated