See·two-phase async

Image Generation

Generate images

DALL-E and others. Returns content URI + content hash + dimensions.

0x0000000000000000000000000000000000000818Explorer
Two-phase async. eth_call validates encoding only. Real generation requires a consumer contract with onImageReady callback — paste the exported Solidity to your project.
click 'auto' (capability = 4)
What to generate
px
px
min escrow: 0.1000 RITUALyou have: RITUAL
Connect your wallet to submit a real transaction.
to: 0x0000000000000000000000000000000000000818chainId 1979 · two-phase
Output
Click Validate to encode the 21-field image request.
1024 × 1024 · FLUX.2-klein-4B
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {PrecompileConsumer} from "./utils/PrecompileConsumer.sol";

contract ImageMinter is PrecompileConsumer {
    address constant IMAGE = address(0x818);
    address constant ASYNC_DELIVERY = 0x5A16214fF555848411544b005f7Ac063742f39F6;

    struct StorageRef { string platform; string path; string credentials; }
    struct ModalInput {
        uint8 inputType; bytes data; string uri; bytes32 contentHash;
        uint32 param1; uint32 param2; bool encrypted;
    }
    struct OutputConfig {
        uint8 outputType; uint32 maxParam1; uint32 maxParam2; uint32 maxParam3;
        bool encryptOutput; uint16 numInferenceSteps; uint16 guidanceScaleX100;
        uint32 seed; uint8 fps; string negativePrompt;
    }

    event ImageRequested(bytes32 indexed jobId, address indexed sender);
    event ImageReady(bytes32 indexed jobId, string uri, uint32 width, uint32 height);

    mapping(bytes32 => address) public pending;

    function generate(address executor) external {
        ModalInput[] memory inputs = new ModalInput[](1);
        inputs[0] = ModalInput({
            inputType: 0,
            data: bytes("A mystical sigil glowing on a black obsidian altar, ember + violet light, hyperdetailed"),
            uri: "",
            contentHash: bytes32(0),
            param1: 0, param2: 0, encrypted: false
        });

        OutputConfig memory output = OutputConfig({
            outputType: 1,
            maxParam1: 1024, maxParam2: 1024, maxParam3: 0,
            encryptOutput: false,
            numInferenceSteps: 28,
            guidanceScaleX100: 750,
            seed: 1979,
            fps: 0,
            negativePrompt: "blurry, low quality, watermark"
        });

        StorageRef memory storage_ = StorageRef(
            "gcs",
            "images/sigil-playground",
            "GCS_CREDS"
        );

        bytes memory encoded = abi.encode(
            executor,
            new bytes[](0), uint256(300), new bytes[](0), bytes(""),
            uint64(5), uint64(400), "IMAGE_TASK_ID",
            address(this), this.onImageReady.selector,
            uint256(500000), uint256(1_000_000_000), uint256(100_000_000), uint256(0),
            "black-forest-labs/FLUX.2-klein-4B",
            inputs, output, storage_,
            new bytes[](0)
        );

        (bool ok,) = IMAGE.call(encoded);
        require(ok, "image precompile failed");

        bytes32 jobId = keccak256(abi.encodePacked(block.number, msg.sender));
        pending[jobId] = msg.sender;
        emit ImageRequested(jobId, msg.sender);
    }

    /// @notice AsyncDelivery callback after Phase 2 settles.
    function onImageReady(bytes32 jobId, bytes calldata result) external {
        require(msg.sender == ASYNC_DELIVERY, "unauth");
        (bool hasError, , string memory uri, , , , uint32 width, uint32 height, ) =
            abi.decode(result,
                (bool, bytes, string, bytes32, bool, uint32, uint32, uint32, string));
        require(!hasError, "image gen failed");
        emit ImageReady(jobId, uri, width, height);
        // Mint NFT, store URI, etc. — pending[jobId] knows the recipient
    }
}