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
- 01Set the operator to the wallet your gateway signer controls (an EOA or a multisig).
- 02Mint credits to your treasury with mint(to, amount) — 1e18 per $1 of face value.
- 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. SpreadCredit — with your gateway operator wallet.
- 2. CreditsStaking — with the governance token and SpreadCredit addresses, then fund it.
- 3. CreditMarket — with SpreadCredit, the USDG address and your fee treasury.
- 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.