Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import "lib"
import "messages"
import "types"

/// @notice Generic message interceptor deployed per async operation.
/// Waits for messages from whitelisted `forwardFrom` addresses, then forwards them
/// to the owner pool with the original context attached for finalization.
contract ContextExecutor {
author: "SmartContract Chainlink Limited SEZC"
version: "0.1.0"
Expand Down
11 changes: 6 additions & 5 deletions contracts/contracts/ccip/executors/context_executor/lib.tolk
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ import "../../../lib/utils"
import "types"
import "messages"

struct ContextExecutor<T> {
data: ContextExecutor_Data<T>;
}

/// @notice Handles incoming messages: Set/Ask are control messages from owner,
/// all other messages from `forwardFrom` addresses are forwarded to owner.
fun ContextExecutor<T>.onInternalMessage(
mutate self,
in: ContextExecutor_InMessageForward,
Expand Down Expand Up @@ -62,14 +60,17 @@ fun ContextExecutor<T>.onInternalMessage(
}
else => {
if (self._isForwardSender(in.senderAddress)) {
val forwardFrom = self.data.forwardFrom;
self.data.forwardFrom = [];

val reply = createMessage({
bounce: BounceMode.NoBounce,
value: 0,
dest: self.data.owner,
body: ContextExecutor_ForwardNotification<T> {
id: self.data.id,
context: self.data.context,
forwardFrom: self.data.forwardFrom,
forwardFrom,
message: in.toCell(),
},
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
// SPDX-License-Identifier: BUSL-1.1
import "types"

/// @notice Sets the context and forwardFrom whitelist on an existing ContextExecutor.
/// Only callable by the owner.
struct (0x44e61eec) ContextExecutor_Set<T> {
queryId: uint64;
context: Cell<T>;
forwardFrom: array<address>;
}

/// @notice Queries or updates the ContextExecutor state.
/// When `done=true`, the executor self-destructs after replying.
struct (0xcad4d1d0) ContextExecutor_Ask {
queryId: uint64;

// Per request context
forwardPayload: cell;
forwardPayload: cell?;

// Close the context executor after this request is processed.
done: bool;
}

/// @notice Union of all incoming messages the ContextExecutor accepts.
type ContextExecutor_InMessage<T> =
| ContextExecutor_Set<T>
| ContextExecutor_Ask;
Expand All @@ -29,12 +34,15 @@ struct (0x93e5bbc5) ContextExecutor_Reply<T> {
forwardFrom: array<address>;

// Per request context
forwardPayload: cell;
forwardPayload: cell?;

// Whether the context executor was closed.
done: bool;
}

/// @notice Forwarded notification sent to the owner pool when a message arrives
/// from a whitelisted `forwardFrom` address. Carries the original context and message.
/// @dev After forwarding, `forwardFrom` is cleared so the executor only forwards once.
struct (0x55b412b9) ContextExecutor_ForwardNotification<T> {
// Notice: no queryId here, because it's not a reply to a specific request

Expand All @@ -46,6 +54,7 @@ struct (0x55b412b9) ContextExecutor_ForwardNotification<T> {
message: Cell<ContextExecutor_InMessageForward>;
}

/// @notice Union of all outgoing messages the ContextExecutor can send.
type ContextExecutor_OutMessage<T> =
| ContextExecutor_Reply<T>
| ContextExecutor_ForwardNotification<T>;
38 changes: 36 additions & 2 deletions contracts/contracts/ccip/executors/context_executor/types.tolk
Original file line number Diff line number Diff line change
@@ -1,12 +1,45 @@
// SPDX-License-Identifier: BUSL-1.1

/// @notice Runtime data stored by each ContextExecutor instance.
/// A pool deploys one executor per async operation with deterministic address.
struct ContextExecutor_Data<C> {
id: uint64; // 64bit addr space for a unique identity, for more use context C
/// 64bit addr space for a unique identity, for more use context C
id: uint64;
/// Address of the owning pool contract (only owner receives forwarded messages).
owner: address;
/// Arbitrary context cell encoding operation-specific data for the owner to consume.
context: Cell<C>;
/// Whitelist of addresses whose messages will be forwarded to the owner.
forwardFrom: array<address>;
}

/// @notice Wrapper providing load/store helpers for ContextExecutor instances.
struct ContextExecutor<T> {
data: ContextExecutor_Data<T>;
}

fun ContextExecutor<T>.getAddress(
code: cell,
id: uint64,
owner: address,
context: Cell<T>,
forwardFrom: array<address>,
): AutoDeployAddress {
return AutoDeployAddress {
stateInit: ContractState {
code,
data: ContextExecutor_Data<T> {
id,
owner,
context,
forwardFrom,
}.toCell(),
},
};
}

/// @notice Forwarded message info passed from ContextExecutor to the owner pool.
/// Contains the original message metadata plus the message body cell.
struct ContextExecutor_InMessageForward {
senderAddress: address // an internal address from which the message arrived
valueCoins: coins // ton amount attached to an incoming message
Expand All @@ -21,7 +54,8 @@ const ContextExecutor_FACILITY_NAME = "link.chain.ton.lib.executor.ContextExecut
const ContextExecutor_FACILITY_ID = ContextExecutor_FACILITY_NAME.crc32() % 640 + 10;
const ContextExecutor_ERROR_CODE = ContextExecutor_FACILITY_ID * 100;

/// Error codes used by the ContextExecutor contract.
/// @notice Error codes used by the ContextExecutor contract.
/// Facility ID: 260 (based on FACILITY_NAME CRC32).
enum ContextExecutor_Error {
/// Thrown when a function is called by an address that is not the owner of the contract.
OnlyCallableByOwner = ContextExecutor_ERROR_CODE
Expand Down
Loading
Loading