Skip to main content

On-chain Blocklock Decryption

This guide provides detailed instructions on how to implement callback functions to handle the reception of a blocklock decryption key in your smart contract.

Overview

When implementing the AbstractBlocklockReceiver interface, your smart contract must override the _onBlocklockReceived function. This function is automatically called by the dcipher network when the block height condition is met, providing your contract with the decryption key. The base smart contract provides two key functions for handling decryption:

  • Receive Callback: _onBlocklockReceived(uint256 requestId, bytes decryptionKey)
  • Decrypt Data: _decrypt(TypesLib.Ciphertext ciphertext, bytes decryptionKey)

Walkthrough

Step-1. Override the Callback Function

First, implement the _onBlocklockReceived function in your smart contract to handle the decryption key when it arrives:

function _onBlocklockReceived(
uint256 _requestId,
bytes calldata decryptionKey
) internal override {
// Verify this is the request we're waiting for
require(requestId == _requestId, "Invalid request ID");

// Store the decryption key if needed
// Or proceed directly with decryption
}

Step-2. Implement the Decryption Logic

The AbstractBlocklockReceiver provides the internal _decrypt function to decrypt your data. When implementing decryption, you must use the same data type that was encrypted initially in your blocklock request. Here are examples of common data types:

Option 1: Decrypt a uint256 Value

function _onBlocklockReceived(
uint256 _requestId,
bytes calldata decryptionKey
) internal override {
require(requestId == _requestId, "Invalid request ID");

// Decrypt the stored ciphertext
bytes memory decryptedData = _decrypt(encryptedValue, decryptionKey);

// Decode the uint256 value
uint256 value = abi.decode(decryptedData, (uint256));

// Use the decrypted value
// Example: store it in a state variable
decryptedAmount = value;
}

Option 2: Decrypt a string

function _onBlocklockReceived(
uint256 _requestId,
bytes calldata decryptionKey
) internal override {
require(requestId == _requestId, "Invalid request ID");

// Decrypt the stored ciphertext
bytes memory decryptedData = _decrypt(encryptedValue, decryptionKey);

// Decode the address
string value = abi.decode(decryptedData, (string));

// Use the decrypted address
// Example: store it in a state variable
decryptedAddress = value;
}

Option 3: Decrypt a struct

// Define your struct
struct UserData {
address userAddress;
uint256 amount;
string metadata;
}

function _onBlocklockReceived(
uint256 _requestId,
bytes calldata decryptionKey
) internal override {
require(requestId == _requestId, "Invalid request ID");

// Decrypt the stored ciphertext
bytes memory decryptedData = _decrypt(encryptedValue, decryptionKey);

// Decode the struct
UserData memory userData = abi.decode(decryptedData, (UserData));
}

Best Practices

  1. Always verify the requestId to ensure you're processing the correct decryption key
  2. Handle decryption errors gracefully using try-catch when possible
  3. Emit events for important state changes and decryption results