-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathAbstractBlocklockReceiver.sol
More file actions
192 lines (165 loc) · 10.7 KB
/
AbstractBlocklockReceiver.sol
File metadata and controls
192 lines (165 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import {IBlocklockReceiver} from "./interfaces/IBlocklockReceiver.sol";
import {IBlocklockSender, TypesLib} from "./interfaces/IBlocklockSender.sol";
import {ConfirmedOwner} from "./access/ConfirmedOwner.sol";
/// @title AbstractBlocklockReceiver contract
/// @author Randamu
/// @notice Base contract which blocklock decryption key receiver contracts must implement
/// @notice to receive decryption keys via callbacks to the receiveBlocklock function.
abstract contract AbstractBlocklockReceiver is IBlocklockReceiver, ConfirmedOwner {
/// @notice BlocklockSender contract for conditional encryption requests, subscription management and handling decryption keys
IBlocklockSender public blocklock;
/// @notice Event to log direct transfer of native tokens to the contract
event Received(address, uint256);
/// @notice Event to log deposits of native tokens
event Funded(address indexed sender, uint256 amount);
/// @notice Event to log withdrawals of native tokens
event Withdrawn(address indexed recipient, uint256 amount);
/// @notice Event logged when a new subscription id is set
event NewSubscriptionId(uint256 indexed subscriptionId);
/// @notice The subscription ID used for conditional encryption.
/// @dev Used in interactions with IBlocklockSender for subscription management, e.g.,
/// @dev funding and consumer contract address registration.
uint256 public subscriptionId;
/// @notice Ensures that the caller is the designated Blocklock contract.
/// @dev This modifier restricts access to the function it modifies to only the Blocklock contract.
/// If the caller is not the Blocklock contract, the transaction will revert with an error message.
/// @notice Reverts with the error message "Only blocklock contract can call" if the caller is not the Blocklock contract.
modifier onlyBlocklockContract() {
require(msg.sender == address(blocklock), "Only blocklock contract can call");
_;
}
constructor(address blocklockSender) ConfirmedOwner(msg.sender) {
blocklock = IBlocklockSender(blocklockSender);
}
/// @notice Receives a blocklock request and the associated decryption key.
/// @dev This function is only callable by a contract that is recognized as a valid "BlocklockContract".
/// Once the decryption key is received, it triggers the internal function `_onBlocklockReceived` to handle the processing.
/// @param requestId The unique identifier of the blocklock request.
/// @param decryptionKey The decryption key that will be used to decrypt the associated ciphertext.
/// @notice Emits an event or performs additional logic in `_onBlocklockReceived`.
function receiveBlocklock(uint256 requestId, bytes calldata decryptionKey) external virtual onlyBlocklockContract {
_onBlocklockReceived(requestId, decryptionKey);
}
/// @notice Sets the Randamu subscription ID used for conditional encryption oracle services.
/// @dev Only callable by the contract owner.
/// @param subId The new subscription ID to be set.
function setSubId(uint256 subId) external virtual onlyOwner {
subscriptionId = subId;
emit NewSubscriptionId(subId);
}
/// @notice Sets the address of the IBlocklockSender contract.
/// @dev Only the contract owner can call this function.
/// @param _blocklock The address of the deployed IBlocklockSender contract.
function setBlocklock(address _blocklock) external virtual onlyOwner {
require(_blocklock != address(0), "Cannot set zero address as sender");
blocklock = IBlocklockSender(_blocklock);
}
/// @notice Adds a list of consumer addresses to the Randamu subscription.
/// @dev Requires the subscription ID to be set before calling.
/// @param consumers An array of addresses to be added as authorized consumers.
function updateSubscription(address[] calldata consumers) external virtual onlyOwner {
require(subscriptionId != 0, "subID not set");
for (uint256 i = 0; i < consumers.length; i++) {
blocklock.addConsumer(subscriptionId, consumers[i]);
}
}
/// @notice Creates and funds a new Randamu subscription using native currency.
/// @dev Only callable by the contract owner. If a subscription already exists, it will not be recreated.
/// @dev The ETH value sent in the transaction (`msg.value`) will be used to fund the subscription.
function createSubscriptionAndFundNative() external payable virtual onlyOwner {
subscriptionId = _subscribe();
blocklock.fundSubscriptionWithNative{value: msg.value}(subscriptionId);
}
/// @notice Tops up the Randamu subscription using native currency (e.g., ETH).
/// @dev Requires a valid subscription ID to be set before calling.
/// @dev The amount to top up should be sent along with the transaction as `msg.value`.
function topUpSubscriptionNative() external payable virtual {
require(subscriptionId != 0, "sub not set");
blocklock.fundSubscriptionWithNative{value: msg.value}(subscriptionId);
}
/// @notice getBalance returns the native balance of the consumer contract.
/// @notice For direct funding requests, the contract needs to hold native tokens to
/// sufficient enough to cover the cost of the request.
function getBalance() public view returns (uint256) {
return address(this).balance;
}
function isInFlight(uint256 requestId) public view returns (bool) {
return blocklock.isInFlight(requestId);
}
function pendingRequestExists(uint256 subId) public view returns (bool) {
return blocklock.pendingRequestExists(subId);
}
/// @notice Requests a blocklock without a subscription and returns the request ID and request price.
/// @dev This function calls the `requestBlocklock` function from the `blocklock` contract, passing the required parameters such as
/// `callbackGasLimit`, `blockHeight`, and `ciphertext`.
/// @param callbackGasLimit The gas limit for the callback function to be executed after the blocklock request.
/// @param condition The condition for decryption of the Ciphertext.
/// The decryption key is sent back to the contract when the condition is met.
/// @param ciphertext The ciphertext to be used in the blocklock request.
/// @notice This function internally calls the `blocklock.requestBlocklock` function.
function _requestBlocklockPayInNative(
uint32 callbackGasLimit,
bytes memory condition,
TypesLib.Ciphertext calldata ciphertext
) internal virtual returns (uint256 requestId, uint256 requestPrice) {
requestPrice = blocklock.calculateRequestPriceNative(callbackGasLimit);
require(msg.value >= requestPrice, "Insufficient ETH");
requestId = blocklock.requestBlocklock{value: msg.value}(callbackGasLimit, condition, ciphertext);
}
/// @notice Requests a blocklock with a subscription and returns the request ID.
/// @dev This function calls the `requestBlocklockWithSubscription` function from the `blocklock` contract, passing the required parameters such as
/// `callbackGasLimit`, `subscriptionId`, `blockHeight`, and `ciphertext`.
/// @param callbackGasLimit The gas limit for the callback function to be executed after the blocklock request.
/// @param condition The condition for decryption of the Ciphertext.
/// The decryption key is sent back to the contract when the condition is met.
/// @param ciphertext The ciphertext to be used in the blocklock request.
/// @return requestId The unique identifier for the blocklock request.
/// @notice This function internally calls the `blocklock.requestBlocklockWithSubscription` function.
function _requestBlocklockWithSubscription(
uint32 callbackGasLimit,
bytes memory condition,
TypesLib.Ciphertext calldata ciphertext
) internal virtual returns (uint256 requestId) {
return blocklock.requestBlocklockWithSubscription(callbackGasLimit, subscriptionId, condition, ciphertext);
}
/// @notice Decrypts the provided ciphertext using the specified decryption key.
/// @dev This function calls the `decrypt` function from the `blocklock` contract to perform the decryption operation.
/// It requires that the `blocklock` contract implements decryption logic using the provided ciphertext and decryption key.
/// @param ciphertext The ciphertext that needs to be decrypted.
/// @param decryptionKey The decryption key to be used for decrypting the ciphertext.
/// @return The decrypted plaintext as a `bytes` array.
/// @notice This function internally calls the `blocklock.decrypt` function to perform the decryption.
function _decrypt(TypesLib.Ciphertext memory ciphertext, bytes calldata decryptionKey)
internal
view
returns (bytes memory)
{
return blocklock.decrypt(ciphertext, decryptionKey);
}
/// @notice Handles the reception of a blocklock with the provided decryption key.
/// @dev This function is meant to be overridden in derived contracts to define the specific logic
/// for processing a blocklock upon receipt of a decryption key.
/// @param _requestId The unique identifier of the blocklock request.
/// @param decryptionKey The decryption key that corresponds to the ciphertext in the blocklock request.
/// @notice This function does not implement any functionality itself but serves as a placeholder for derived contracts
/// to implement their specific logic when a blocklock is received.
/// @dev This function is marked as `internal` and `virtual`, meaning it can be overridden in a derived contract.
function _onBlocklockReceived(uint256 _requestId, bytes calldata decryptionKey) internal virtual;
/// @notice Creates a new Randamu subscription if none exists and registers this contract as a consumer.
/// @dev Internal helper that initializes the subscription only once.
/// @return subId The subscription ID that was created or already exists.
function _subscribe() internal virtual returns (uint256 subId) {
require(subscriptionId == 0, "SubscriptionId is not zero");
subId = blocklock.createSubscription();
blocklock.addConsumer(subId, address(this));
}
/// @notice Cancels an existing Randamu subscription if one exists.
/// @dev Internal helper that cancels the subscription.
/// @param to The recipient addresss that will receive the subscription balance.
function _cancelSubscription(address to) internal virtual {
require(subscriptionId != 0, "SubscriptionId is zero");
blocklock.cancelSubscription(subscriptionId, to);
}
}