Skip to content

BM-1466: Ec2/claim digest #1004

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 57 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
435e8c4
initial deployment
capossele May 21, 2025
4c36ef5
update commit
capossele May 21, 2025
d798851
use verifier rather than estop
capossele May 21, 2025
a1d3222
fix bytecode
capossele May 22, 2025
575d8b5
clean up
capossele May 22, 2025
1ebbc60
tmp
capossele May 22, 2025
924c53f
Merge remote-tracking branch 'origin/main' into angelo/base-deployment
capossele May 23, 2025
2e2156a
Merge remote-tracking branch 'origin/main' into angelo/base-deployment
capossele May 26, 2025
63d873a
fix cli
capossele May 26, 2025
da0cc55
fix comment
capossele May 26, 2025
661daa6
drop burn
capossele May 26, 2025
7cd90bb
add base deployment
capossele May 27, 2025
a672a0a
drop hp
capossele May 28, 2025
918934a
Merge remote-tracking branch 'origin/main' into angelo/base-deployment
capossele May 29, 2025
4a8b78e
add new staging deployments
capossele May 29, 2025
48822c6
tmp
capossele May 29, 2025
ebbccd1
Merge branch 'main' into angelo/claim-digest
capossele Jun 3, 2025
0985ba3
artifacts
capossele Jun 3, 2025
9b25d47
fmt
capossele Jun 3, 2025
e4dbfd4
use predicateType
capossele Jun 3, 2025
00f1078
clean up
capossele Jun 3, 2025
3c43edf
add no journal test
capossele Jun 3, 2025
25c7b42
Merge branch 'main' into angelo/claim-digest
ec2 Aug 4, 2025
7b905ef
Merge branch 'main' into angelo/claim-digest
ec2 Aug 11, 2025
27d0dc0
remove receipt verification from assessor-guest
ec2 Aug 11, 2025
41aa8b6
add CallbackData
ec2 Aug 11, 2025
9566b73
fix rust side
ec2 Aug 12, 2025
50167b3
forge fmt
ec2 Aug 12, 2025
fc6bd7f
fix rust tests
ec2 Aug 12, 2025
e2013f8
counter example with claim digest match predicate
ec2 Aug 12, 2025
eaa391f
remove image id from requirements and put it in the predicate data
ec2 Aug 12, 2025
0032fa2
still need to figure out how to get the image id from request in broker
ec2 Aug 12, 2025
c90f973
tests build, but not all pass
ec2 Aug 13, 2025
4ae5304
fix requirements type solidity signature
ec2 Aug 13, 2025
ea907a8
fix request builder
ec2 Aug 13, 2025
1937e1b
cargo tests pass
ec2 Aug 13, 2025
69abfb7
satisfy some compiler warnings
ec2 Aug 13, 2025
5df52a5
fix sol test
ec2 Aug 13, 2025
7864baa
Merge branch 'main' into ec2/claim-digest
ec2 Aug 13, 2025
ac3c914
fix more compiler warnings
ec2 Aug 13, 2025
3e0d070
debugging still
ec2 Aug 13, 2025
8d8a0c8
fix composition example
ec2 Aug 13, 2025
d3c9ace
fix smart-contract-requestor example
ec2 Aug 13, 2025
2ba252f
clippy
ec2 Aug 13, 2025
8833ded
fix deployment
ec2 Aug 13, 2025
e161dff
fix some naming
ec2 Aug 13, 2025
de0d3e2
composition
ec2 Aug 13, 2025
3b54725
remove some comments
ec2 Aug 13, 2025
7f2172e
fix boundless-cli test
ec2 Aug 13, 2025
04f6f99
do not push assumption receipts into the assessor in aggregator
ec2 Aug 13, 2025
0600765
fix comments
ec2 Aug 14, 2025
88b981b
Merge branch 'main' into ec2/claim-digest
ec2 Aug 14, 2025
d294e34
rename FulfillmentData to FulfillmentClaimData
ec2 Aug 14, 2025
dd44c54
Add callbacktype enum
ec2 Aug 14, 2025
d70bc72
fix test domain
ec2 Aug 14, 2025
de7225e
fix clippy
ec2 Aug 14, 2025
3778944
check claim digest if journal is available and not a claim digest match
ec2 Aug 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
"rust-analyzer.linkedProjects": [
"./Cargo.toml",
"./crates/distributor/Cargo.toml",
// "./crates/guest/assessor/assessor-guest/Cargo.toml",
"./crates/guest/assessor/assessor-guest/Cargo.toml",
// "./crates/guest/util/echo/Cargo.toml",
// "./crates/guest/util/identity/Cargo.toml",
// "./examples/counter/Cargo.toml",
"./examples/counter/Cargo.toml",
// "./examples/smart-contract-requestor/Cargo.toml",
// "./examples/counter-with-callback/Cargo.toml"
],
Expand Down
16 changes: 8 additions & 8 deletions contracts/deployment-test/Deploymnet.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {Input, InputType} from "../src/types/Input.sol";
import {Requirements} from "../src/types/Requirements.sol";
import {Offer} from "../src/types/Offer.sol";
import {ProofRequest} from "../src/types/ProofRequest.sol";
import {Predicate, PredicateType} from "../src/types/Predicate.sol";
import {PredicateLibrary} from "../src/types/Predicate.sol";
import {RequestId, RequestIdLibrary} from "../src/types/RequestId.sol";
import {RequestLock} from "../src/types/RequestLock.sol";

Expand Down Expand Up @@ -105,7 +105,10 @@ contract DeploymentTest is Test {
function testRouterIsDeployed() external view {
require(address(verifier) != address(0), "no verifier (router) address is set");
require(keccak256(address(verifier).code) != keccak256(bytes("")), "verifier code is empty");
require(address(verifier) == address(BoundlessMarket(address(boundlessMarket)).VERIFIER()), "verifier address does not match boundless market");
require(
address(verifier) == address(BoundlessMarket(address(boundlessMarket)).VERIFIER()),
"verifier address does not match boundless market"
);
}

function testSetVerifierIsDeployed() external view {
Expand Down Expand Up @@ -191,9 +194,7 @@ contract DeploymentTest is Test {
vm.expectEmit(true, true, true, false);
emit IBoundlessMarket.ProofDelivered(request.id, address(testProver), result.fills[0]);

boundlessMarket.priceAndFulfill(
requests, clientSignatures, result.fills, result.assessorReceipt
);
boundlessMarket.priceAndFulfill(requests, clientSignatures, result.fills, result.assessorReceipt);
Fulfillment memory fill = result.fills[0];
assertTrue(boundlessMarket.requestIsFulfilled(fill.id), "Request should have fulfilled status");
}
Expand Down Expand Up @@ -230,8 +231,7 @@ contract Client {

function defaultRequirements() public pure returns (Requirements memory) {
return Requirements({
imageId: bytes32(APP_IMAGE_ID),
predicate: Predicate({predicateType: PredicateType.PrefixMatch, data: hex"53797374"}),
predicate: PredicateLibrary.createPrefixMatchPredicate(bytes32(APP_IMAGE_ID), hex"53797374"),
callback: Callback({gasLimit: 0, addr: address(0)}),
selector: bytes4(0)
});
Expand All @@ -257,4 +257,4 @@ contract Client {
(uint8 v, bytes32 r, bytes32 s) = VM.sign(wallet, structDigest);
return abi.encodePacked(r, s, v);
}
}
}
77 changes: 39 additions & 38 deletions contracts/snapshots/BoundlessMarketBasicTest.json
Original file line number Diff line number Diff line change
@@ -1,42 +1,43 @@
{
"ERC20 approve: required for depositStake": "45966",
"bytecode size implementation": "24381",
"bytecode size implementation": "24341",
"bytecode size proxy": "89",
"deposit: first ever deposit": "50920",
"deposit: second deposit": "33820",
"depositStake: 1 HP (tops up market account)": "59400",
"depositStake: full (drains testProver account)": "49800",
"depositStakeWithPermit: 1 HP (tops up market account)": "72272",
"depositStakeWithPermit: full (drains testProver account)": "72262",
"fulfill: a batch of 8": "402078",
"fulfill: a locked request": "90511",
"fulfill: a locked request (locked via prover signature)": "90511",
"fulfill: a locked request with 10kB journal": "427539",
"fulfill: another prover fulfills without payment": "85473",
"fulfill: fulfilled by the locked prover for payment (request already fulfilled by another prover)": "80772",
"fulfillAndWithdraw: a batch of 8": "414256",
"fulfillAndWithdraw: a locked request": "102689",
"lockinRequest: base case": "146877",
"lockinRequest: with prover signature": "156522",
"priceAndFulfill: a single request": "108760",
"priceAndFulfill: a single request (smart contract signature)": "118938",
"priceAndFulfill: a single request (with selector)": "111059",
"priceAndFulfill: a single request that was not locked": "108760",
"priceAndFulfill: a single request that was not locked fulfilled by prover not in allow-list": "108760",
"priceAndFulfill: fulfill already fulfilled was locked request": "102475",
"slash: base case": "100967",
"slash: fulfilled request after lock deadline": "80532",
"submitRequest: with maxPrice ether": "51904",
"submitRequest: without ether": "45061",
"submitRootAndFulfill: a batch of 2 requests": "168676",
"submitRootAndFulfill: a locked request": "124555",
"submitRootAndFulfill: a locked request (locked via prover signature)": "124555",
"submitRootAndFulfillAndWithdraw: a locked request": "136476",
"submitRootAndPriceAndFulfill: a single request": "141098",
"submitRootAndPriceAndFulfill: a single request that was not locked": "141110",
"submitRootAndPriceAndFulfill: a single request that was not locked fulfilled by prover not in allow-list": "141110",
"withdraw: 1 ether": "40314",
"withdraw: full balance": "40326",
"withdrawStake: 1 HP balance": "68743",
"withdrawStake: full balance": "51739"
"deposit: first ever deposit": "50876",
"deposit: second deposit": "33776",
"depositStake: 1 HP (tops up market account)": "59378",
"depositStake: full (drains testProver account)": "49778",
"depositStakeWithPermit: 1 HP (tops up market account)": "72236",
"depositStakeWithPermit: full (drains testProver account)": "72227",
"fulfill (no journal): a batch of 8": "385299",
"fulfill: a batch of 8": "438335",
"fulfill: a locked request": "95167",
"fulfill: a locked request (locked via prover signature)": "95167",
"fulfill: a locked request with 10kB journal": "432569",
"fulfill: another prover fulfills without payment": "90165",
"fulfill: fulfilled by the locked prover for payment (request already fulfilled by another prover)": "84071",
"fulfillAndWithdraw: a batch of 8": "451307",
"fulfillAndWithdraw: a locked request": "108139",
"lockinRequest: base case": "147332",
"lockinRequest: with prover signature": "157039",
"priceAndFulfill: a single request": "113970",
"priceAndFulfill: a single request (smart contract signature)": "124159",
"priceAndFulfill: a single request (with selector)": "116270",
"priceAndFulfill: a single request that was not locked": "113934",
"priceAndFulfill: a single request that was not locked fulfilled by prover not in allow-list": "113934",
"priceAndFulfill: fulfill already fulfilled was locked request": "106280",
"slash: base case": "100898",
"slash: fulfilled request after lock deadline": "80465",
"submitRequest: with maxPrice ether": "52227",
"submitRequest: without ether": "45384",
"submitRootAndFulfill: a batch of 2 requests": "177800",
"submitRootAndFulfill: a locked request": "129534",
"submitRootAndFulfill: a locked request (locked via prover signature)": "129534",
"submitRootAndFulfillAndWithdraw: a locked request": "141954",
"submitRootAndPriceAndFulfill: a single request": "146462",
"submitRootAndPriceAndFulfill: a single request that was not locked": "146426",
"submitRootAndPriceAndFulfill: a single request that was not locked fulfilled by prover not in allow-list": "146426",
"withdraw: 1 ether": "40331",
"withdraw: full balance": "40343",
"withdrawStake: 1 HP balance": "68755",
"withdrawStake: full balance": "51751"
}
40 changes: 20 additions & 20 deletions contracts/snapshots/BoundlessMarketBench.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
{
"fulfill (with callback): batch of 001": "132142",
"fulfill (with callback): batch of 002": "218443",
"fulfill (with callback): batch of 004": "392147",
"fulfill (with callback): batch of 008": "739579",
"fulfill (with callback): batch of 016": "1272464",
"fulfill (with callback): batch of 032": "2373148",
"fulfill (with selector): batch of 001": "92745",
"fulfill (with selector): batch of 002": "139726",
"fulfill (with selector): batch of 004": "236258",
"fulfill (with selector): batch of 008": "420231",
"fulfill (with selector): batch of 016": "790425",
"fulfill (with selector): batch of 032": "1558877",
"fulfill: batch of 001": "90487",
"fulfill: batch of 002": "135232",
"fulfill: batch of 004": "227181",
"fulfill: batch of 008": "402117",
"fulfill: batch of 016": "754179",
"fulfill: batch of 032": "1485129",
"fulfill: batch of 064": "3014348",
"fulfill: batch of 128": "6255291"
"fulfill (with callback): batch of 001": "136946",
"fulfill (with callback): batch of 002": "227879",
"fulfill (with callback): batch of 004": "410896",
"fulfill (with callback): batch of 008": "776960",
"fulfill (with callback): batch of 016": "1346098",
"fulfill (with callback): batch of 032": "2522586",
"fulfill (with selector): batch of 001": "97441",
"fulfill (with selector): batch of 002": "148905",
"fulfill (with selector): batch of 004": "254383",
"fulfill (with selector): batch of 008": "456439",
"fulfill (with selector): batch of 016": "862953",
"fulfill (with selector): batch of 032": "1704151",
"fulfill: batch of 001": "95191",
"fulfill: batch of 002": "144387",
"fulfill: batch of 004": "245394",
"fulfill: batch of 008": "438338",
"fulfill: batch of 016": "826511",
"fulfill: batch of 032": "1630160",
"fulfill: batch of 064": "3306156",
"fulfill: batch of 128": "6849269"
}
44 changes: 37 additions & 7 deletions contracts/src/BoundlessMarket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ import {Account} from "./types/Account.sol";
import {AssessorJournal} from "./types/AssessorJournal.sol";
import {AssessorCallback} from "./types/AssessorCallback.sol";
import {AssessorCommitment} from "./types/AssessorCommitment.sol";
import {CallbackData} from "./types/CallbackData.sol";
import {Fulfillment} from "./types/Fulfillment.sol";
import {AssessorReceipt} from "./types/AssessorReceipt.sol";
import {PredicateType} from "./types/Predicate.sol";
import {ProofRequest} from "./types/ProofRequest.sol";
import {LockRequest, LockRequestLibrary} from "./types/LockRequest.sol";
import {RequestId} from "./types/RequestId.sol";
Expand Down Expand Up @@ -239,6 +241,7 @@ contract BoundlessMarket is
}
bytes32[] memory leaves = new bytes32[](fills.length);
bool[] memory hasSelector = new bool[](fills.length);
PredicateType[] memory predicateTypes = new PredicateType[](fills.length);

// Check the selector constraints.
// NOTE: The assessor guest adds non-zero selector values to the list.
Expand All @@ -255,16 +258,16 @@ contract BoundlessMarket is
// Verify the application receipts.
for (uint256 i = 0; i < fills.length; i++) {
Fulfillment calldata fill = fills[i];
predicateTypes[i] = fill.predicateType;

bytes32 claimDigest = ReceiptClaimLib.ok(fill.imageId, sha256(fill.journal)).digest();
leaves[i] = AssessorCommitment(i, fill.id, fill.requestDigest, claimDigest).eip712Digest();
leaves[i] = AssessorCommitment(i, fill.id, fill.requestDigest, fill.claimDigest).eip712Digest();

// If the requestor did not specify a selector, we verify with DEFAULT_MAX_GAS_FOR_VERIFY gas limit.
// This ensures that by default, client receive proofs that can be verified cheaply as part of their applications.
if (!hasSelector[i]) {
VERIFIER.verifyIntegrity{gas: DEFAULT_MAX_GAS_FOR_VERIFY}(Receipt(fill.seal, claimDigest));
VERIFIER.verifyIntegrity{gas: DEFAULT_MAX_GAS_FOR_VERIFY}(Receipt(fill.seal, fill.claimDigest));
} else {
VERIFIER.verifyIntegrity(Receipt(fill.seal, claimDigest));
VERIFIER.verifyIntegrity(Receipt(fill.seal, fill.claimDigest));
}
}

Expand All @@ -278,6 +281,7 @@ contract BoundlessMarket is
root: batchRoot,
callbacks: assessorReceipt.callbacks,
selectors: assessorReceipt.selectors,
predicateTypes: predicateTypes,
prover: assessorReceipt.prover
})
)
Expand Down Expand Up @@ -333,13 +337,39 @@ contract BoundlessMarket is
}

uint256 callbackIndexPlusOne = fillToCallbackIndexPlusOne[i];
if (callbackIndexPlusOne > 0) {
AssessorCallback calldata callback = assessorReceipt.callbacks[callbackIndexPlusOne - 1];
_executeCallback(fill.id, callback.addr, callback.gasLimit, fill.imageId, fill.journal, fill.seal);

// We do not support callbacks for claim digest matches because we cant authenticate the journal.
if (fill.predicateType != PredicateType.ClaimDigestMatch) {
// In the case this is a not a claim digest match, we need to authenticate the journal, since we actually have it
(bytes32 imageId, bytes calldata journal) = _decodeCallbackData(fill.callbackData);
bytes32 calculatedClaimDigest = ReceiptClaimLib.ok(imageId, sha256(journal)).digest();
if (fill.claimDigest != calculatedClaimDigest) {
revert ClaimDigestMismatch(fill.claimDigest, calculatedClaimDigest);
}

if (callbackIndexPlusOne > 0) {
AssessorCallback calldata callback = assessorReceipt.callbacks[callbackIndexPlusOne - 1];
_executeCallback(fill.id, callback.addr, callback.gasLimit, imageId, journal, fill.seal);
}
Comment on lines -336 to +353
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By placing the callback data into the AssessorCallback, we can mostly eliminate the new validation here, and simply decode and execute the callback (reverting if decode fails). If we directly embed the CallbackData into AssessorCallback, we can avoid the extra decode step as well.

}
}
}

function _decodeCallbackData(bytes calldata data) internal pure returns (bytes32 imageId, bytes calldata journal) {
assembly {
// Extract imageId (first 32 bytes after length)
imageId := calldataload(add(data.offset, 0x20))

// Extract journal offset and create calldata slice
let journalOffset := calldataload(add(data.offset, 0x40))
let journalPtr := add(data.offset, add(0x20, journalOffset))
let journalLength := calldataload(journalPtr)

journal.offset := add(journalPtr, 0x20)
journal.length := journalLength
}
}

/// @inheritdoc IBoundlessMarket
function priceAndFulfillAndWithdraw(
ProofRequest[] calldata requests,
Expand Down
4 changes: 4 additions & 0 deletions contracts/src/IBoundlessMarket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ interface IBoundlessMarket {
/// @dev selector efc954a6
error BatchSizeExceedsLimit(uint256 batchSize, uint256 limit);

/// @notice Error when a journal is provided but does not match the claim digest
/// TODO(ec2): selector
error ClaimDigestMismatch(bytes32 expected, bytes32 calculated);

/// @notice Check if the given request has been locked (i.e. accepted) by a prover.
/// @dev When a request is locked, only the prover it is locked to can be paid to fulfill the job.
/// @param requestId The ID of the request.
Expand Down
4 changes: 4 additions & 0 deletions contracts/src/types/AssessorCallback.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
// as found in the LICENSE-BSL file.
pragma solidity ^0.8.20;

import {CallbackType} from "./CallbackType.sol";

struct AssessorCallback {
/// @notice The index of the fill in the request
uint16 index;
/// @notice The address of the contract to call back
address addr;
/// @notice Maximum gas to use for the callback
uint96 gasLimit;
/// @notice The type of callback
CallbackType callbackType;
Comment on lines +16 to +17
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of just the callback type, we should encode the full callback data here, and ensure it is committed in the assessor journal. This both allows us to skip the recomputation of the receipt claim onchain when we go to send the callback, because it will now be part of what the assessor constructs, and allows for more flexibility in the future in how we evolve the system.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to my comments below, I am kind of thinking we should just embed the imageId and journal directly here to simplify. https://github.com/boundless-xyz/boundless/pull/1004/files#r2277886432

}
3 changes: 3 additions & 0 deletions contracts/src/types/AssessorJournal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
pragma solidity ^0.8.20;

import {AssessorCallback} from "./AssessorCallback.sol";
import {PredicateType} from "./Predicate.sol";
import {Selector} from "./Selector.sol";

/// @title Assessor Journal Struct
Expand All @@ -17,6 +18,8 @@ struct AssessorJournal {
/// @notice The (optional) selectors for the requests committed by the assessor.
/// @dev This is used to verify the fulfillment of the request against its selector's seal.
Selector[] selectors;
/// @notice The list of `PredicateType` for each request.
PredicateType[] predicateTypes;
Comment on lines +21 to +22
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this.

Also, if we do this should be in AssessorCommitment instead. The reason the callbacks and selectors are outside this Merkle tree of AssessorCommitment objects is that most of them will be empty and so it takes up less space to do it this way.

/// @notice Root of the Merkle tree committing to the set of proven claims.
/// @dev In the case of a batch of size one, this may simply be the eip712Digest of the `AssessorCommitment`.
bytes32 root;
Expand Down
8 changes: 6 additions & 2 deletions contracts/src/types/Callback.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,27 @@ pragma solidity ^0.8.24;

using CallbackLibrary for Callback global;

import {CallbackType} from "./CallbackType.sol";

/// @title Callback Struct and Library
/// @notice Represents a callback configuration for proof delivery
struct Callback {
/// @notice The address of the contract to call back
address addr;
/// @notice Maximum gas to use for the callback
uint96 gasLimit;
/// @notice The type of callback
CallbackType callbackType;
Comment on lines +18 to +19
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we maybe not support multiple callback types? I am leaning towards saying that we should not, or least not support multiple callback types right now. Maybe this will be requested in the future, but its unclear what the receiver experience would look like and I'm inclined to think we probably won't support it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another way to keep the option open for multiple callback types would be to add a version number to the start of the encoded CallbackData. So if we increment the version in the future, we could provide a new function for decoding it.

But we don't necessarily need to do that even: because the first 32 bytes are a hash, we can use a special value of bytes32(uint256(1)) to indicate that this is the new version in the future. This is more ugly, but it can be the plan of record in the eventuality that we do want to support multiple types of callbacks in the future.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option for forward compatibility is that we can increment the entire request version, and accordingly create any need code paths we need, switching on that. We have reserved bits in the request ID that can be used for this.

}

library CallbackLibrary {
string constant CALLBACK_TYPE = "Callback(address addr,uint96 gasLimit)";
string constant CALLBACK_TYPE = "Callback(address addr,uint96 gasLimit,uint8 callbackType)";
bytes32 constant CALLBACK_TYPEHASH = keccak256(bytes(CALLBACK_TYPE));

/// @notice Computes the EIP-712 digest for the given callback
/// @param callback The callback to compute the digest for
/// @return The EIP-712 digest of the callback
function eip712Digest(Callback memory callback) internal pure returns (bytes32) {
return keccak256(abi.encode(CALLBACK_TYPEHASH, callback.addr, callback.gasLimit));
return keccak256(abi.encode(CALLBACK_TYPEHASH, callback.addr, callback.gasLimit, callback.callbackType));
}
}
19 changes: 19 additions & 0 deletions contracts/src/types/CallbackData.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2025 RISC Zero, Inc.
//
// Use of this source code is governed by the Business Source License
// as found in the LICENSE-BSL file.
pragma solidity ^0.8.24;

using CallbackDataLibrary for CallbackData global;

/// @title Callback Struct and Library
/// @notice Represents a callback configuration for proof delivery
struct CallbackData {
/// @notice Image ID of the guest that was verifiably executed to satisfy the request.
bytes32 imageId;
/// @notice Journal committed by the guest program execution.
/// @dev The journal is checked to satisfy the predicate specified on the request's requirements.
bytes journal;
}

library CallbackDataLibrary {}
10 changes: 10 additions & 0 deletions contracts/src/types/CallbackType.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2025 RISC Zero, Inc.
//
// Use of this source code is governed by the Business Source License
// as found in the LICENSE-BSL file.
pragma solidity ^0.8.20;

enum CallbackType {
None,
JournalRequired
}
Loading
Loading