On-chain Blocklock Encryption
This guide provides detailed instructions on how to implement your smart contract to request blocklock encryption using the blocklock-solidity library.
Overview
This guide demonstrates the implementation of the smart contract that uses the AbstractBlocklockReceiver
interface, which is mandatory for all contracts making blocklock encryption requests. The AbstractBlocklockReceiver
base smart contract contains functions for making conditional encryption requests depending on the form of payment for the request, direct funding or subscription:
- Direct funding:
_requestBlocklockPayInNative()
- Subscription:
_requestBlocklockWithSubscription()
Both functions return a requestId, which should be stored and can be used to verify the response when the decryption key is delivered through a callback from BlocklockSender
.
Walkthrough
Step-1. Create a Solidity Contract
First, create a Solidity smart contract that implements the AbstractBlocklockReceiver
interface to extend the blocklock encryption function:
pragma solidity ^0.8;
import {TypesLib} from "blocklock-solidity/src/libraries/TypesLib.sol";
import {AbstractBlocklockReceiver} from "blocklock-solidity/src/AbstractBlocklockReceiver.sol";
contract YourBlocklockReceiver is AbstractBlocklockReceiver {
……
constructor(address blocklockSender) AbstractBlocklockReceiver(blocklockSender) {}
……
}
The constructor takes the address of a deployed BlocklockSender(Proxy)
contract, which serves as the entry point for registering encrypted payloads and triggering blocklock decryption in the dcipher network.
Refer to the Networks page for a list of supported chains and their corresponding contract addresses.
Step-2. Implement the Blocklock Request
The abstract contract AbstractBlocklockReceiver
offers base functions for requesting blocklock decryption from the dcipher network with different payment options:
- Direct funding:
_requestBlocklockPayInNative()
- Subscription:
_requestBlocklockWithSubscription()
You can choose to implement one option based on your use case.
Option 1: Direct Funding
_requestBlocklockPayInNative()
is the internal function provided by the AbstractBlocklockReceiver
base contract. It allows you to register a new block-locked encryption request by sending native tokens directly, without relying on an active subscription from the dcipher network.
When calling _requestBlocklockPayInNative()
, we need to fund the request via msg.value
which should cover the estimated price for the request and decryption after the condition is met. It is recommended to add a buffer to account for fluctuations in network gas prices, thereby avoiding delays in processing the request.
Let's create a custom public wrapper function that registers a blocklock request and pays directly with native tokens by calling the internal _requestBlocklockPayInNative()
method:
// When calling this function, we need to attach enough native tokens for the blocklock request fee
function createBlocklockRequestWithDirectFunding(
uint32 callbackGasLimit,
bytes calldata condition,
TypesLib.Ciphertext calldata _encryptedValue
) external payable returns (uint256, uint256) {
// create blocklock request
(uint256 requestID, uint256 requestPrice) =
_requestBlocklockPayInNative(callbackGasLimit, condition, _encryptedValue);
// store request id
requestId = requestID;
// store Ciphertext
encryptedValue = _encryptedValue;
emit BlocklockRequestCreated(requestID, callbackGasLimit, requestPrice);
return (requestID, requestPrice);
}
Option 2: Subscription-based Request
The dcipher network also provides subscription-based funding for dApp builders to create and fund their customized YourBlocklockReceiver
contract with the dcipher network so that they can cover the blocklock request and decryption costs for their users. Learn more about Subscription-Based Funding.
1. Create a Subscription Account for Your Contract
The AbstractBlocklockReceiver
base contract already offers subscription-based functions which will be inherited by your YourBlocklockReceiver
contract. In this case, it is createSubscriptionAndFundNative()
as shown below:
function createSubscriptionAndFundNative() external payable onlyOwner {
subscriptionId = _subscribe();
blocklock.fundSubscriptionWithNative{value: msg.value}(subscriptionId);
}
After deploying your YourBlocklockReceiver
contract, you just need to call this function to create a subscription for your customized blocklock receiver contract with a certain amount of native tokens as payment.
Once the subscription is created, a subscriptionId
will be assigned and recorded in your contract, which is used to make subscription-funded requests. A subscriptionId can be shared with multiple decryption key receiver smart contracts.
2. Implement Your Function to Request Subscription-based Blocklock
_requestBlocklockWithSubscription()
is the internal function provided by the AbstractBlocklockReceiver
base contract to allow builders to create requests with a subscription account.
Let's create a custom public wrapper function that registers a subscription-based blocklock request by calling the internal _requestBlocklockWithSubscription()
method:
function createBlocklockRequestWithSubscription(
uint32 callbackGasLimit,
bytes calldata condition,
TypesLib.Ciphertext calldata _encryptedValue
) external returns (uint256) {
// create blocklock request
uint256 _requestId = _requestBlocklockWithSubscription(callbackGasLimit, condition, _encryptedValue);
// store request id
requestId = _requestId;
// store Ciphertext
encryptedValue = _encryptedValue;
return requestId;
}