On-Chain Guide
Current contract interaction patterns for app integrations
All state changes are executed on-chain by the caller wallet.
Use API/helpers for discovery, then send contract transactions directly. The API also exposes authenticated /api/mm/*, /api/portfolio/*, and /api/strategies/* workflows, but direct contract interaction remains the canonical protocol path.
Core User Flows
| Flow | Contract | Function |
|---|---|---|
| Deposit collateral | DiffusalCollateralVault | depositToPortfolio(uint256 portfolioId, uint256 amount) |
| Withdraw collateral | DiffusalCollateralVault | withdrawFromPortfolio(uint256 portfolioId, uint256 amount) |
| Place signed order | DiffusalOptionsOrderBook | placeOrderWithSignature(...) |
| Place signed lazy-series | DiffusalOptionsOrderBook | placeOrderWithSeriesParamsWithSignature(...) |
| Cancel signed order | DiffusalOptionsOrderBook | cancelOrderWithSignature(bytes32 orderId, uint256 nonce, uint256 deadline, bytes signature) |
| Fill RFQ | DiffusalOptionsRFQ | fillRfqQuoteInPortfolio(...) |
| Create portfolio | DiffusalPortfolioManager | createPortfolio() |
Order Book Flow (Current)
- Build/find
seriesId. - Fetch pair tick precision (or derive from helper endpoint).
- Build
PlaceOrdertyped data or request it from the authenticated managed order placement endpoint. - Maker signs the typed data.
- Submit the signature on-chain via
placeOrderWithSignature(...). - Crossed orders are identified for execution.
- Settlement is finalized on-chain via
settleMatchByOrderId(makerOrderId, takerOrderId, fillAmount).
If the series may not exist yet, use placeOrderWithSeriesParamsWithSignature(...) instead so signature validation and lazy series creation happen in one transaction.
Direct registration via registerOrderInPortfolio(...) or registerOrderInPortfolioWithSeriesParams(...) still exists as a lower-level alternative, but it is not the recommended default flow for current integrations.
Key change vs legacy model:
- Placement and cancellation are signature-first, while settlement is order-ID based (stored order data), not full-signature payload settlement.
Canonical Signed Placement Example
The authenticated API can return the exact typed-data payload used by the order book.
Submit the unsigned request to /api/mm/orders/place, sign the returned typedData, then call placeOrderWithSignature(...).
{
"seriesId": "0x8f1c9d7b6a4e2f00112233445566778899aabbccddeeff001122334455667788",
"portfolioId": "0",
"isBuy": true,
"tick": "150",
"size": "1000000000000000000",
"expiry": "1762512000",
"nonce": "7",
"deadline": "1762512300"
}import { diffusalOptionsOrderBookAbi } from "@diffusal/contracts/deployment/abis";
const orderRequest = {
seriesId:
"0x8f1c9d7b6a4e2f00112233445566778899aabbccddeeff001122334455667788",
portfolioId: "0",
isBuy: true,
tick: "150",
size: "1000000000000000000",
expiry: "1762512000",
nonce: "7",
deadline: "1762512300",
};
const placementResponse = await fetch("/api/mm/orders/place", {
method: "POST",
headers: {
"content-type": "application/json",
authorization: `Bearer ${token}`,
},
body: JSON.stringify(orderRequest),
}).then((response) => response.json());
if (placementResponse.mode !== "typed_data") {
throw new Error("Expected typed_data mode");
}
const signature = await walletClient.signTypedData(placementResponse.typedData);
await walletClient.writeContract({
address: placementResponse.contractAddress,
abi: diffusalOptionsOrderBookAbi,
functionName: "placeOrderWithSignature",
args: [
placementResponse.typedData.message.seriesId,
placementResponse.typedData.message.portfolioId,
placementResponse.typedData.message.isBuy,
placementResponse.typedData.message.tick,
placementResponse.typedData.message.size,
placementResponse.typedData.message.expiry,
placementResponse.typedData.message.nonce,
placementResponse.typedData.message.deadline,
signature,
],
});typedData.message matches the live PlaceOrder schema exactly: seriesId, portfolioId, isBuy, tick, size, expiry, nonce, and deadline.
If you already have a signature, the same endpoint can return mode: "relay" with relay-ready calldata instead of a typedData payload.
If your order may create the series on first placement, use placeOrderWithSeriesParamsWithSignature(...) and include matching series parameters in the signed payload.
RFQ Flow (Current)
- Request a signed quote from
/api/rfq/request(the public timed RFQ auction endpoint). - The backend returns the winning signed EIP-712 quote, ready for contract submission.
- Optionally call authenticated
/api/rfq/fillif you want API-built calldata for the returned quote. - Submit the quote on-chain via
fillRfqQuoteInPortfolio(...). - Use
getQuoteStatus(...)for pre-flight checks when needed.
Portfolio Notes
- Portfolio
0is the default route used by most examples. - Users can create additional portfolios with
createPortfolio(). - Collateral movement between portfolios is done via
transferCollateralBetweenPortfolios(...).
Practical Integration Sequence
- Discover market/series via
/api/markets. - Prepare params via
/api/helperswhere useful. - Build or request the signed order payload when using the order book.
- Execute on-chain transaction from wallet.
- Track status and state via REST/WebSocket.