Contracts

Deploy it yourself.

Three contracts make the on-chain version of this market: the credit token, the order book that fills deepest discount first, and the staking rewards that create the supply sellers list. Sources and ABIs are below — copy them, or download and open in Remix.

Reference implementations, not audited. Compile with solc 0.8.24 or later, test on a testnet, and get an audit before real value. This app cannot sign a deploy transaction for you.

SpreadCredit

The credit token. 18 decimals, one unit of face value each, minted by the operator and burned when inference is spent.

Constructor

address operator_

Compile

solc 0.8.24 · evm paris · optimizer 200 runs

  1. 01Set the operator to the wallet your gateway signer controls (an EOA or a multisig).
  2. 02Mint credits to your treasury with mint(to, amount) — 1e18 per $1 of face value.
  3. 03Only the operator can mint or burn; transfer the role later with setOperator + acceptOperator.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/// @title SpreadCredit
/// @notice 1 CREDIT = 1 USD of inference. Minted by the operator, burned when spent.
/// @dev Plain ERC-20 with an operator role, no transfer tax, no hooks.
contract SpreadCredit {
    string public constant name = "Spread Credit";
    string public constant symbol = "CREDIT";
    uint8 public constant decimals = 18;

    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    address public operator;
    address public pendingOperator;

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event OperatorChanged(address indexed from, address indexed to);

    error NotOperator();
    error InsufficientBalance();
    error InsufficientAllowance();

    modifier onlyOperator() {
        if (msg.sender != operator) revert NotOperator();
        _;
    }

    constructor(address operator_) {
        operator = operator_;
        emit OperatorChanged(address(0), operator_);
    }

    function transfer(address to, uint256 value) external returns (bool) {
        _move(msg.sender, to, value);
        return true;
    }

    function approve(address spender, uint256 value) external returns (bool) {
        allowance[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
        return true;
    }

    function transferFrom(address from, address to, uint256 value) external returns (bool) {
        uint256 allowed = allowance[from][msg.sender];
        if (allowed != type(uint256).max) {
            if (allowed < value) revert InsufficientAllowance();
            allowance[from][msg.sender] = allowed - value;
        }
        _move(from, to, value);
        return true;
    }

    function mint(address to, uint256 value) external onlyOperator {
        totalSupply += value;
        balanceOf[to] += value;
        emit Transfer(address(0), to, value);
    }

    function burn(address from, uint256 value) external onlyOperator {
        uint256 balance = balanceOf[from];
        if (balance < value) revert InsufficientBalance();
        unchecked {
            balanceOf[from] = balance - value;
            totalSupply -= value;
        }
        emit Transfer(from, address(0), value);
    }

    function setOperator(address next) external onlyOperator {
        pendingOperator = next;
    }

    function acceptOperator() external {
        if (msg.sender != pendingOperator) revert NotOperator();
        emit OperatorChanged(operator, msg.sender);
        operator = msg.sender;
        pendingOperator = address(0);
    }

    function _move(address from, address to, uint256 value) private {
        uint256 balance = balanceOf[from];
        if (balance < value) revert InsufficientBalance();
        unchecked {
            balanceOf[from] = balance - value;
        }
        balanceOf[to] += value;
        emit Transfer(from, to, value);
    }
}

Deploy order

  1. 1. SpreadCredit — with your gateway operator wallet.
  2. 2. CreditsStaking — with the governance token and SpreadCredit addresses, then fund it.
  3. 3. CreditMarket — with SpreadCredit, the USDG address and your fee treasury.
  4. 4. Point SpreadCredit's operator at the gateway signer so serving inference burns credits, and mirror fills into this app's ledger so the UI stays accurate.