Skip to main content

BITE API

This section provides detailed technical documentation for BITE’s APIs, both off-chain (TypeScript SDK) and on-chain (Solidity helpers).

Off-Chain API (bite-ts)

The @skalenetwork/bite TypeScript library provides methods for encrypting data before submitting to the blockchain.

new BITE(endpoint: string)

Creates a new BITE instance configured with a JSON-RPC endpoint. Parameters:
  • endpoint: string – The BITE URL provider (JSON-RPC endpoint)

bite.encryptTransaction(tx)

Encrypts a transaction using BLS threshold encryption. The encrypted transaction will have its to field set to the BITE magic address. Parameters:
  • tx: object – Transaction object with data and to fields as hex strings
Returns:
  • Promise<Transaction> – Encrypted transaction with modified data and to fields
Encryption Process:
  1. RLP encodes original data and to fields
  2. Encrypts encoded data using AES with randomly generated key
  3. Encrypts AES key using BLS threshold encryption
  4. Creates final payload: [EPOCH_ID, ENCRYPTED_BITE_DATA]
Committee Behavior:
  • Single Committee: AES key encrypted with current BLS public key
  • Dual Committee: During rotation, AES key encrypted twice (current + next committee keys)

BITE.encryptTransactionWithCommitteeInfo(tx, committees)

Static method that encrypts using provided committee info, avoiding internal RPC call. Parameters:
  • tx: object – Transaction with data and to fields
  • committees: Array – Committee info objects (from getCommitteesInfo)
Returns:
  • Promise<Transaction> – Encrypted transaction
Use Case: Offline/cached encryption when committee info is already known.

bite.encryptMessage(message)

Encrypts a raw hex-encoded message using BLS threshold encryption. Parameters:
  • message: string – Hex string to encrypt (with/without 0x prefix)
Returns:
  • Promise<string> – Encrypted hex string in RLP format with epoch and encryption data
Note: Encrypts raw data directly without transaction formatting.

bite.getDecryptedTransactionData(transactionHash)

Retrieves decrypted transaction data after consensus finality using bite_getDecryptedTransactionData JSON-RPC method. Parameters:
  • transactionHash: string – The transaction hash
Returns:
  • Promise<object> – JSON with data and to keys containing original decrypted fields

bite.getCommitteesInfo()

Fetches committee information using bite_getCommitteesInfo JSON-RPC method. Returns:
  • Promise<Array> – Array of 1-2 committee objects:
    • commonBLSPublicKey: string – 256-char hex (128-byte BLS public key)
    • epochId: number – Epoch identifier
Array Contents:
  • 1 element: Normal operation (single active committee)
  • 2 elements: Committee rotation period (scheduled for next 3 minutes)
Use Cases: Rotation monitoring, epoch tracking, key management

On-Chain API (bite-solidity)

The @skalenetwork/bite-solidity library provides Solidity helpers for creating Conditional Transactions (CTX) that request decryption from within smart contracts.

Installation

# npm
npm i @skalenetwork/bite-solidity

# forge
forge install skalenetwork/bite-solidity
echo "@skalenetwork/bite-solidity/=lib/bite-solidity/" >> remappings.txt
Compiler Requirements
  • Solidity version: >= 0.8.27
  • EVM version: istanbul or lower

Import

import { BITE } from "@skalenetwork/bite-solidity/BITE.sol";
import { IBiteSupplicant } from "@skalenetwork/bite-solidity/interfaces/IBiteSupplicant.sol";

BITE.submitCTX(address, gasLimit, encryptedArgs, plaintextArgs)

Creates a Conditional Transaction for decryption. Parameters:
  • address: CTX handler address (use BITE.SUBMIT_CTX_ADDRESS)
  • gasLimit: Gas for callback (in gas units, e.g., msg.value / tx.gasprice)
  • encryptedArgs: Array of encrypted bytes to decrypt
  • plaintextArgs: Array of unencrypted bytes to pass through
Returns: address – The CTX supplicant address that will call onDecrypt()

IBiteSupplicant.onDecrypt(decryptedArgs, plaintextArgs)

Callback that your contract must implement. Called by SKALE consensus with decrypted data. Parameters:
  • decryptedArgs: Array of decrypted byte arrays
  • plaintextArgs: Array of plaintext byte arrays (passed through)
Example:
pragma solidity >=0.8.27;

import { BITE } from "@skalenetwork/bite-solidity/BITE.sol";
import { IBiteSupplicant } from "@skalenetwork/bite-solidity/interfaces/IBiteSupplicant.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";

contract MyContract is IBiteSupplicant {
    using Address for address payable;

    address public ctxSender;

    function revealSecret(bytes calldata encrypted) external payable {
        bytes[] memory encryptedArgs = new bytes[](1);
        encryptedArgs[0] = encrypted;

        bytes[] memory plaintextArgs = new bytes[](0);

        ctxSender = BITE.submitCTX(
            BITE.SUBMIT_CTX_ADDRESS,
            msg.value / tx.gasprice,
            encryptedArgs,
            plaintextArgs
        );

        payable(ctxSender).sendValue(msg.value);
    }

    function onDecrypt(
        bytes[] calldata decryptedArgs,
        bytes[] calldata
    ) external override {
        require(msg.sender == ctxSender, "Unauthorized");
        // Handle decrypted data
    }
}

Transaction Structure

BITE Encrypted Transaction Format

BITE transactions modify standard Ethereum transaction structure:
interface BiteTransaction {
  to: string;      // Always set to BITE magic address
  data: string;    // Encrypted payload containing [EPOCH_ID, ENCRYPTED_DATA]
  from: string;    // Sender address (unchanged)
  value: string;    // ETH value (unchanged)
  gas: string;     // Gas limit (must be set manually)
  gasPrice: string; // Gas price (unchanged)
  nonce: number;    // Nonce (unchanged)
}

Encryption Payload Structure

The encrypted data field contains RLP-encoded array:
[EPOCH_ID, ENCRYPTED_BITE_DATA]
  • EPOCH_ID: Current committee epoch
  • ENCRYPTED_BITE_DATA: Contains the encrypted transaction data (AES-encrypted payload with BLS-encrypted AES key)
Important: Gas Limit Requirement When passing a transaction to bite.ts, you must set gasLimit manually. estimateGas does not return proper values for encrypted transactions. If gasLimit is omitted, bite.ts will automatically set it to 300000.

Common Use Cases

1. Private Token Transfers

// Encrypt ERC20 transfer
const transferData = iface.encodeFunctionData('transfer', [recipient, amount]);
const tx = {
  to: tokenAddress,
  data: transferData,
  gasLimit: 200000
};
const encryptedTx = await bite.encryptTransaction(tx);

2. Confidential Contract Interactions

// Encrypt any contract call
const callData = iface.encodeFunctionData('confidentialFunction', [secretParam]);
const tx = {
  to: contractAddress,
  data: callData,
  gasLimit: 300000
};
const encryptedTx = await bite.encryptTransaction(tx);

3. Raw Message Encryption

// Encrypt raw hex data directly
const message = '0x1234567890abcdef';
const encryptedMessage = await bite.encryptMessage(message);
console.log('Encrypted:', encryptedMessage);

4. Cached Committee Encryption

// Fetch committee info once, reuse for multiple transactions
const committees = await bite.getCommitteesInfo();

// Encrypt multiple transactions without additional RPC calls
const tx1 = await BITE.encryptTransactionWithCommitteeInfo(transaction1, committees);
const tx2 = await BITE.encryptTransactionWithCommitteeInfo(transaction2, committees);

5. Committee Rotation Monitoring

// Monitor for upcoming rotations
const committees = await bite.getCommitteesInfo();
if (committees.length === 2) {
  console.log('Rotation in progress');
  // Implement rotation-aware logic
}