DLC Oracle
Magnolia provides oracle infrastructure for Bitcoin-backed loans using Discreet Log Contracts. We attest to loan conditions. We are not a lender.
TL;DR
Magnolia acts as a DLC oracle for Bitcoin-collateralized lending. When you register a loan with us, we:
- Generate oracle announcements for funding and maturity events
- Monitor on-chain activity and price feeds
- Attest to outcomes (repaid, liquidated, etc.)
- Enable trustless settlement of your DLC
Ready to integrate? Email us [email protected].
A Brief History of DLCs
In 2017, Tadge Dryja (co-author of the Lightning Network whitepaper) published a paper that would quietly reshape what's possible on Bitcoin.
The problem was simple: Bitcoin's scripting language is intentionally limited. You can't encode complex financial contracts in a single transaction the way Ethereum does. This was by design — simplicity means security — but it left Bitcoiners without native smart contract capabilities.
Dryja's insight was elegant: instead of cramming contract logic into one transaction, spread it across multiple pre-signed transactions. An oracle commits to attesting a future event. Parties construct transactions for every possible outcome, locked by the oracle's future attestation. When the event occurs, the oracle publishes a signature that unlocks exactly one transaction.
The original construction required Schnorr signatures, which Bitcoin didn't have yet. But the community adapted. Using ECDSA adaptor signatures, developers built working DLC implementations years before Taproot activated.
The road so far:
| Year | Milestone |
|---|---|
| 2017 | Tadge Dryja publishes the DLC whitepaper |
| 2020 | Multiple compatible implementations emerge (Suredbits, Crypto Garage, Atomic Finance) |
| 2020 | DLC specification standardizes interoperability |
| 2021 | Taproot activates, enabling native Schnorr DLCs |
| 2024 | DLCs power production lending, derivatives, and prediction markets |
| 2026 | Magnolia launches first public DLC Oracle |
Today, DLCs enable trustless financial contracts on Bitcoin — derivatives, options, loans — without custodians, without wrapping, without leaving the Bitcoin network.
For a non-technical introduction, we recommend Atomic Finance's excellent A Layperson's Guide to Discreet Log Contracts.
What is a DLC Oracle?
A DLC oracle is a trusted third party that commits to reporting real-world events. The oracle doesn't custody funds or know the contract terms, it just attests to outcomes.
Here's why it's a big deal: the oracle can't cheat without detection. If an oracle signs contradictory outcomes, it leaks its private key. This creates a strong incentive for honest reporting.
Magnolia operates as a DLC oracle specialized for Bitcoin-backed loans. We:
- Commit to monitoring specific loan conditions
- Watch for funding transactions, repayments, and price movements
- Attest to outcomes when conditions are met
- Provide cryptographic proofs that settle DLCs trustlessly
We are infrastructure. We are not a lender. We don't custody funds or make lending decisions. We simply report what happened.
How DLCs Enable Trustless Bitcoin Loans
The Trust Problem
Traditional Bitcoin-collateralized loans have a trust problem:
┌──────────────────────────────────────────────────────────────────────────────────────────────┐
│ TRADITIONAL BITCOIN LOAN │
├──────────────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ │
│ Borrower ─────────────────► Custodian ◄───────────────── Lender │
│ │ │ │ │
│ │ "Trust me" │ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ Sends BTC Holds collateral Sends USD │
│ │
│ │
│ Problems: │
│ • Custodian can rug │
│ • Custodian can be hacked │
│ • Custodian can be seized │
│ • Single point of failure │
│ │
│ │
└────────────────────────────────────────────── ────────────────────────────────────────────────┘
The borrower's Bitcoin sits in someone else's custody. If that custodian disappears, gets hacked, or faces regulatory action — the collateral is at risk.
The DLC Solution
DLCs eliminate the custodian:
┌──────────────────────────────────────────────────────────────────────────────────────────────┐
│ DLC-BASED LOAN │
├──────────────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ │
│ ┌───────────────────────────┐ │
│ │ DLC │ │
│ │ │ │
│ Borrower ◄─────────►│ Pre-signed │◄──────────► Lender │
│ │ transactions │ │
│ │ for ALL outcomes │ │
│ │ │ │
│ └─────────────┬─────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────┐ │
│ │ Oracle │ │
│ │ (Magnolia) │ │
│ │ │ │
│ │ Attests to: │ │
│ │ • Repayment │ │
│ │ • Price drops │ │
│ │ • Time expiry │ │
│ └───────────────────────────┘ │
│ │ │
│ ▼ │
│ Correct payout │
│ executed trustlessly │
│ │
│ │
│ Benefits: │
│ • No custodian holds the Bitcoin │
│ • Contract terms enforced by math │
│ • Oracle can't steal funds (only attest) │
│ • Fraud is cryptographically detectable │
│ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────────┘
The borrower and lender construct a DLC together. They pre-sign transactions for every possible outcome: repayment, liquidation by price, liquidation by time. The Bitcoin collateral is locked in a 2-of-2 multisig that neither party can spend alone.
When Magnolia attests to an outcome, that attestation unlocks exactly one pre-signed transaction. The correct party receives the funds. No trust required.
The Two-Event Model
Magnolia uses a two-event model for loan monitoring:
LOAN LIFECYCLE
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ FUNDING EVENT │ │ MATURITY EVENT │
│ │ │ │
│ loan-funded-{hash} │───── success ───►│ loan-matured-{hash} │
│ │ │ │
│ Monitors: │ │ Monitors: │
│ • USDC transfer │ │ • Repayment │
│ to loan address │ │ • BTC price │
│ │ │ • Time │
│ Outcomes: │ │ │
│ ┌───────────────────┐ │ │ Outcomes: │
│ │ paid │ │ │ ┌───────────────────┐ │
│ │ not-paid │ │ │ │ repaid │ │
│ └───────────────────┘ │ │ │ liquidated-by- │ │
│ │ │ │ price-threshold │ │
└───────────────┬─────────────────┘ │ │ liquidated-by- │ │
│ │ │ maturation-date │ │
│ not-paid │ │ not-paid │ │
│ │ └───────────────────┘ │
▼ │ │
┌─────────────┐ └─────────────────────────────────┘
│ LOAN │
│ CANCELLED │
└─────────────┘
Funding Event
The funding event tracks whether the loan was funded before the deadline.
Event ID generation:
const crypto = require('crypto');
// Event ID is derived from loan parameters
const eventHash = crypto
.createHash('sha256')
.update(`loan-funded//${loanAddress}//${loanAmount}`)
.digest('hex');
const fundingEventId = `loan-funded-${eventHash}`;
// Example: loan-funded-7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069
What we monitor:
- USDC transfers to the specified loan address
- Transaction confirmations
- Funding deadline (
fundingDatetimeUTC)
Possible outcomes:
| Outcome | Condition |
|---|---|
paid | Correct USDC amount received at loan address before deadline |
not-paid | Funding deadline passed without valid funding transaction |
If the funding event attests not-paid, the maturity event is also automatically attested as not-paid — the loan never started.
Maturity Event
The maturity event tracks how the loan concludes.
Event ID generation:
const crypto = require('crypto');
// Event ID is derived from repayment parameters
const eventHash = crypto
.createHash('sha256')
.update(`loan-matured//${repayAddress}//${repayAmount}`)
.digest('hex');
const maturityEventId = `loan-matured-${eventHash}`;
// Example: loan-matured-3e23e8160039594a33894f6564e1b1348bbd7a0088d42c4acb73eeaed59c009d
What we monitor:
- USDC balance at the repay address
- BTC/USD price (median from 5 exchanges)
- Current time vs. maturity date (
maturityDatetimeUTC)
Possible outcomes:
| Outcome | Condition |
|---|---|
repaid | Full repayment amount received at repay address |
liquidated-by-price-threshold | BTC price dropped below the loan's price threshold |
liquidated-by-maturation-date | Maturity date reached without repayment |
not-paid | Loan was never funded (inherited from funding event) |
Liquidation Conditions
When multiple conditions are met simultaneously, we use a priority system:
| Priority | Outcome | Trigger |
|---|---|---|
| 1 (highest) | repaid | Full repayment received at repay address |
| 2 | liquidated-by-price-threshold | BTC price < loan's priceLiquidationThreshold |
| 3 (lowest) | liquidated-by-maturation-date | Current time >= maturityDatetimeUTC |
Why this order?
Repayment is always checked first. If the borrower repaid, they repaid — regardless of what the price did or whether the maturity date passed.
Price liquidation takes precedence over time because it represents an active risk condition. If the collateral value dropped below the safety threshold, that's a more urgent trigger than simply running out of time.
Price Oracle
We compute the median BTC/USD price from 5 major cryptocurrency exchanges.
The median (not average) provides resistance to manipulation — a single exchange reporting an anomalous price won't affect the outcome.
Price event format:
- Event ID:
BTCUSD-{YYYY-MM-DD}(e.g.,BTCUSD-2025-01-07) - Value: 10-digit decimal representation (price in cents)
- Attestation timing: Attested the day after the event date
For details on our specific data sources, contact us at [email protected].
Integration Flow
Here's the complete flow from loan registration to settlement:
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Lender │ │ Magnolia API │ │Magnolia Oracle│
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
│ 1. POST /loan │ │
│ { │ │
│ loanAddress, │ │
│ loanAmount, │ │
│ repayAddress, │ │
│ repayAmount, │ │
│ fundingDatetimeUTC, │ │
│ maturityDatetimeUTC, │ │
│ priceLiquidationThreshold │ │
│ } │ │
│───────────────────────────────────►│ │
│ │ │
│ │ 2. Generate event hashes │
│ │ and announcements │
│ │ │
│ 3. Response: │ │
│ { │ │
│ fundingEventId, │ │
│ maturityEventId, │ │
│ announcements: [...] │ │
│ } │ │
│◄───────────────────────────────────│ │
│ │ │
│ │ 4. Register monitoring │
│ │───────────────────────────────────►│
│ │ │
╔═══════════════════════════════════════════════════════════════════════════════════════════╗
║ LENDER CONSTRUCTS DLC WITH BORROWER USING ANNOUNCEMENTS ║
║ (off-chain, using @node-dlc or similar library) ║
╚═══════════════════════════════════════════════════════════════════════════════════════════╝
│ │ │
│ │ 5. Watch for funding tx │
│ │ ┌─────────────────────┤
│ │ │ Monitor USDC │
│ │ │ transfers to │
│ │ │ loanAddress │
│ │ └─────────────────────┤
│ │ │
│ │ 6. Funding detected │
│ │◄───────────────────────────────────│
│ │ attestation: "paid" │
│ │ │
│ 7. GET /oracle/events │ │
│ Event funded-* has attestation │ │
│◄───────────────────────────────────│ │
│ │ │
│ │ 8. Continuous monitoring │
│ │ ┌─────────────────────┤
│ │ │ • Repayment │
│ │ │ • BTC price │
│ │ │ • Time │
│ │ └─────────────────────┤
│ │ │
│ │ 9. Condition met │
│ │◄───────────────────────────────────│
│ │ attestation: "repaid" | │
│ │ "liquidated-by-*" │
│ │ │
│ 10. GET /oracle/events │ │
│ Event matured-* has attested │ │
│◄───────────────────────────────────│ │
│ │ │
╔═══════════════════════════════════════════════════════════════════════════════════════════╗
║ DLC SETTLES: Attestation unlocks the correct pre-signed transaction. ║
║ Funds go to the appropriate party. ║
╚════════════════════════════════════════════════ ═══════════════════════════════════════════╝
│ │ │
Using the Announcements
When you register a loan, you receive oracle announcements. These are the cryptographic commitments you need to construct a DLC with your counterparty.
What's in an Announcement?
// Example response from POST /loan
{
"id": "loan_abc123",
"oracleFundingEventId": "loan-funded-7f83b1657ff1fc53...",
"oracleMaturityEventId": "loan-matured-3e23e8160039594a...",
"fundingAnnouncement": {
"announcementSerialized": "fdd824...", // Hex-encoded OracleAnnouncement
"oraclePublicKey": "02abc123...",
"eventDescriptor": {
"outcomes": ["paid", "not-paid"]
},
"maturityEpoch": 1704067200
},
"maturityAnnouncement": {
"announcementSerialized": "fdd824...",
"oraclePublicKey": "02abc123...",
"eventDescriptor": {
"outcomes": [
"repaid",
"liquidated-by-price-threshold",
"liquidated-by-maturation-date",
"not-paid"
]
},
"maturityEpoch": 1706745600
}
}
What Each Field Means
| Field | Description |
|---|---|
announcementSerialized | The full announcement, hex-encoded. Pass this to your DLC library. |
oraclePublicKey | Magnolia's oracle public key. Verify attestations against this. |
eventDescriptor | The possible outcomes. Your DLC must have a CET for each. |
maturityEpoch | Unix timestamp when the oracle can attest. |
Using with @node-dlc
import { OracleAnnouncement } from '@node-dlc/messaging';
// Parse the announcement from the API response
const announcementHex = loanResponse.fundingAnnouncement.announcementSerialized;
const announcement = OracleAnnouncement.deserialize(
Buffer.from(announcementHex, 'hex')
);
// The announcement contains:
// - Oracle's public key (for verifying attestations)
// - R-values (nonces) for each outcome
// - Event descriptor (possible outcomes)
// - Maturity epoch
console.log('Oracle public key:', announcement.oraclePublicKey.toString('hex'));
console.log('Outcomes:', announcement.oracleEvent.eventDescriptor.outcomes);
console.log('Maturity:', new Date(announcement.oracleEvent.eventMaturityEpoch * 1000));
// Use this announcement to construct CETs (Contract Execution Transactions)
// for each possible outcome with your counterparty (the borrower)
What an Attestation Proves
When Magnolia attests to an outcome, the attestation cryptographically proves:
- The oracle committed to this event — The attestation references the original announcement
- This specific outcome occurred — The signed outcome string (e.g., "repaid")
- The oracle can't equivocate — Signing a different outcome would leak the private key
import { OracleAttestation } from '@node-dlc/messaging';
// Fetch the oracle event to check for attestation
const BASE_URL = process.env.BASE_URL || 'https://api.sandbox.magfi.dev';
const API_KEY = process.env.MAGNOLIA_API_KEY;
const eventId = 'loan-matured-3e23e8160039594a...';
const response = await fetch(`${BASE_URL}/oracle/events/${eventId}`, {
headers: { 'X-API-Key': API_KEY }
});
const event = await response.json();
if (event.attestationSerialized) {
// The event has been attested!
const attestation = OracleAttestation.deserialize(
Buffer.from(event.attestationSerialized, 'hex')
);
console.log('Outcome:', attestation.outcomes); // e.g., ["repaid"]
console.log('Signatures:', attestation.signatures); // Schnorr signatures
// Use this attestation to:
// 1. Decrypt the adaptor signature on the correct CET
// 2. Broadcast the CET to settle the DLC
// 3. The correct party receives the funds trustlessly
} else {
console.log('Event not yet attested. Monitoring in progress...');
}
Testing in Sandbox
The sandbox environment lets you test liquidation scenarios without real funds.
Triggering Events Manually
Use the sandbox trigger endpoint to simulate oracle behavior:
# Set sandbox environment
export BASE_URL="https://api.sandbox.magfi.dev"
export API_KEY="magfi_YOUR_SANDBOX_API_KEY"
# Trigger the oracle job to process pending events
curl "$BASE_URL/loan/__sandbox/trigger" \
-X POST \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json"
Testing Liquidation Scenarios
1. Test Price Liquidation
# Register a loan with a HIGH price threshold (easy to trigger)
curl "$BASE_URL/loan" \
-X POST \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"loanAddress": "0x1234...",
"loanAmount": 100000,
"repayAddress": "0x5678...",
"repayAmount": 105000,
"fundingDatetimeUTC": "2025-01-15T00:00:00Z",
"maturityDatetimeUTC": "2025-04-15T00:00:00Z",
"priceLiquidationThreshold": 200000
}'
# Fund the loan (simulate USDC transfer in sandbox)
# Then trigger the oracle job
curl "$BASE_URL/loan/__sandbox/trigger" \
-X POST \
-H "X-API-Key: $API_KEY"
# Check the maturity event - should show "liquidated-by-price-threshold"
# if current BTC price < 200000
2. Test Time Liquidation
# Register a loan with a maturity date in the past
curl "$BASE_URL/loan" \
-X POST \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"loanAddress": "0x1234...",
"loanAmount": 100000,
"repayAddress": "0x5678...",
"repayAmount": 105000,
"fundingDatetimeUTC": "2024-01-01T00:00:00Z",
"maturityDatetimeUTC": "2024-12-01T00:00:00Z",
"priceLiquidationThreshold": 10000
}'
# Trigger the oracle job
curl "$BASE_URL/loan/__sandbox/trigger" \
-X POST \
-H "X-API-Key: $API_KEY"
# Check the maturity event - should show "liquidated-by-maturation-date"
3. Test Repayment
# Register a loan normally
# Fund the loan
# Send the repayment amount to the repay address (simulated in sandbox)
# Trigger the oracle job
curl "$BASE_URL/loan/__sandbox/trigger" \
-X POST \
-H "X-API-Key: $API_KEY"
# Check the maturity event - should show "repaid"
See Trigger Oracle Loan Sandbox Event for full endpoint documentation.
API Reference
| Endpoint | Description |
|---|---|
| Register a new loan | Register loan details, receive announcements |
| Get existing loan | Check loan status and attestations |
| Update an existing loan | Modify loan parameters |
| List oracle events | View all oracle events and their status |
| Trigger oracle loan sandbox event | Manually trigger oracle processing (sandbox only) |
Further Reading
DLC Fundamentals
- Discreet Log Contracts (Tadge Dryja, 2017) — The original whitepaper that started it all
- A Layperson's Guide to DLCs (Atomic Finance) — Excellent non-technical introduction
- DLC Specification — The interoperability specification
Bitcoin Optech Coverage
- Discreet Log Contracts — Ongoing news and updates
- Adaptor Signatures — The cryptographic primitive enabling DLCs
- Schnorr Signatures — Foundation for modern DLCs
Libraries
Contact
Questions about integration? Reach out at [email protected].