Proposal preview
Use Deference from a contract
Request a Panel answer or a chat answer from a Sepolia contract through DeferenceIntake, and receive it on chain.
Proposal preview
DeferenceIntake runs on Sepolia and is not part of deference.si yet. While this deployment answers in example mode, the fulfiller charges a cost of 0, so the whole escrow goes back to the payer.
DeferenceIntake is the front door to Deference for other contracts. A payer escrows up to maxCost INFERENCE with a request; the Deference fulfiller serves it off chain and calls fulfill with the result, its attestation and the actual cost. The cost is activated as service credit for the Deference account that served the request, the rest goes back to the payer, and the payer's callback, if any, receives the result.
| Contract | Sepolia address |
|---|---|
| DeferenceIntake | 0x5c67d511EAE08d51C77185Be958aE55C7F46098b |
| INFERENCE (6 decimals) | 0x59e95fEde655A5E3e62067658e113A5292538193 |
| ContestJudge (Panel verifier) | 0xD55Db52c37B4eE31804F6F30f0f5e1B446615Fc7 |
Request
function request(bytes32 kind, bytes calldata body, Callback calldata callback, uint256 maxCost)
external
returns (bytes32 requestId);
struct Callback {
address target; // zero for no callback
bytes4 selector; // called as target.selector(bytes32 requestId, bytes result)
uint32 gasLimit; // exactly this much gas
}Approve maxCost INFERENCE to the intake first. Two kinds are enabled, each with a cap of 50 INFERENCE per request:
- panel@1bytes32
- A Panel verdict. The body is the JSON of the Panel request, for example
{"question":"Did team Blue win?","panel":{"members":[...],"answer_type":"bool"}}. A plain-text body is read as the question, put to a default panel of five labs. - chat@1bytes32
- One chat answer. The body is
{"prompt":"..."}, a chat completions body, or plain text.
A kind is the ASCII name right-padded to 32 bytes, bytes32("panel@1") in Solidity. The body is at most 16,384 bytes.
Result
fulfill emits Fulfilled(requestId, resultHash, cost, callbackOk) and, for a Panel, Attested(requestId, attestation).
resultis UTF-8 JSON. A Panel gives{"mode","kind","status","answer","agreed","size","quorum"}; a chat answer gives{"mode","kind","model","content"}.attestationisabi.encode(PanelAttestation.Attestation, bytes signature), with the on-chain request id as itsrequestId. Decode it and pass both parts toPanelAttestation.verifyto act on a verdict with the same checks as a direct Panel call.- The callback gets the result when it is at most 4,096 bytes, else empty bytes;
resultHashalways covers the full result. A reverting callback is recorded ascallbackOk = falseand never undoes the fulfilment.
Cancel
A request nobody fulfils can be cancelled by its payer once cancelAfter has passed, for a full refund:
INTAKE.cancel(requestId);Example consumer
contract AsksThePanel {
IDeferenceIntake public constant INTAKE = IDeferenceIntake(0x5c67d511EAE08d51C77185Be958aE55C7F46098b);
IERC20 public constant INFERENCE = IERC20(0x59e95fEde655A5E3e62067658e113A5292538193);
mapping(bytes32 requestId => bytes result) public results;
function ask(string calldata question) external returns (bytes32 requestId) {
uint256 maxCost = 1e6;
INFERENCE.approve(address(INTAKE), maxCost);
requestId = INTAKE.request(
bytes32("panel@1"),
bytes(string.concat('{"question":"', question, '"}')),
IDeferenceIntake.Callback(address(this), this.onResult.selector, 200_000),
maxCost
);
}
function onResult(bytes32 requestId, bytes calldata result) external {
require(msg.sender == address(INTAKE), "only the intake");
results[requestId] = result;
}
}The contract must hold the INFERENCE it escrows. The Oracle page lists recent requests and sends one from your wallet.