DFlow - Guide d'intégration complet
Le guide définitif pour intégrer DFlow - un protocole de trading qui permet aux traders d'échanger de la valeur sur les marchés spot et de prédiction nativement sur Solana.
Qu'est-ce que DFlow ?
DFlow est une infrastructure de trading complète qui fournit :
- Applications de trading & Portefeuilles - Échanges de tokens avec routage intelligent et couverture de 99,9% des tokens
- Échanges & Agrégateurs - Accès à des milliards de volume routé mensuellement à travers les DEXes et les AMMs propriétaires
- Institutions financières & Market Makers - Couches d'exécution programmables avec CLPs et trades asynchrones
- Plateformes de marchés de prédiction - Infrastructure de découverte, pricing, routage et règlement
Capacités clés
| Fonctionnalité | Description |
|---|---|
| Couverture de tokens | 99,9% avec détection en millisecondes |
| Infrastructure | Distribution mondiale, optimisation du débit |
| Exécution | Algorithmes avancés avec routage JIT pour la meilleure exécution de prix |
| Marchés | Support du trading spot et des marchés de prédiction |
| Protection MEV | Protection sandwich améliorée avec bundles Jito |
Aperçu des API
DFlow fournit deux catégories principales d'API :
1. Swap API (Trading)
URL de base : https://quote-api.dflow.net
Pour exécuter des trades :
- Swaps impératifs - Contrôle total de la sélection du routage au moment de la signature
- Swaps déclaratifs - Swaps basés sur l'intention avec optimisation du routage différée
- Trade API - Interface unifiée pour le trading spot et les marchés de prédiction
- Order API - Génération de cotations et de transactions
2. Prediction Market Metadata API
URL de base : https://api.prod.dflow.net
Pour interroger les données des marchés de prédiction :
- Events API - Interroger les événements et les prédictions
- Markets API - Obtenir les détails du marché, les carnets d'ordres, les mints de résultat
- Trades API - Données historiques des trades
- Live Data API - Jalons et mises à jour en temps réel
- WebSocket - Mises à jour streaming du prix et du carnet d'ordres
Authentification
La plupart des endpoints nécessitent une clé API via l'en-tête x-api-key. Contactez hello@dflow.net pour obtenir les identifiants.
Démarrage rapide
Swap impératif (3 étapes)
import { Connection, Keypair, VersionedTransaction } from "@solana/web3.js";
const API_BASE = "https://quote-api.dflow.net";
const API_KEY = process.env.DFLOW_API_KEY; // Optionnel mais recommandé
// Adresses des tokens
const SOL = "So11111111111111111111111111111111111111112";
const USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
async function imperativeSwap(keypair: Keypair, connection: Connection) {
// Étape 1 : Obtenir une cotation
const quoteParams = new URLSearchParams({
inputMint: SOL,
outputMint: USDC,
amount: "1000000000", // 1 SOL
slippageBps: "50", // 0,5%
});
const quote = await fetch(`${API_BASE}/quote?${quoteParams}`, {
headers: API_KEY ? { "x-api-key": API_KEY } : {},
}).then(r => r.json());
// Étape 2 : Obtenir la transaction de swap
const swapResponse = await fetch(`${API_BASE}/swap`, {
method: "POST",
headers: {
"content-type": "application/json",
...(API_KEY && { "x-api-key": API_KEY }),
},
body: JSON.stringify({
userPublicKey: keypair.publicKey.toBase58(),
quoteResponse: quote,
dynamicComputeUnitLimit: true,
prioritizationFeeLamports: 150000,
}),
}).then(r => r.json());
// Étape 3 : Signer et envoyer
const tx = VersionedTransaction.deserialize(
Buffer.from(swapResponse.swapTransaction, "base64")
);
tx.sign([keypair]);
const signature = await connection.sendTransaction(tx);
await connection.confirmTransaction(signature);
return signature;
}
Trade API (Unifié - Recommandé)
L'API Trade fournit un endpoint unique qui gère l'exécution synchrone et asynchrone :
async function tradeTokens(keypair: Keypair, connection: Connection) {
// Étape 1 : Obtenir une commande (cotation + transaction en un seul appel)
const orderParams = new URLSearchParams({
inputMint: SOL,
outputMint: USDC,
amount: "1000000000",
slippageBps: "50",
userPublicKey: keypair.publicKey.toBase58(),
});
const order = await fetch(`${API_BASE}/order?${orderParams}`, {
headers: API_KEY ? { "x-api-key": API_KEY } : {},
}).then(r => r.json());
// Étape 2 : Signer et envoyer
const tx = VersionedTransaction.deserialize(
Buffer.from(order.transaction, "base64")
);
tx.sign([keypair]);
const signature = await connection.sendTransaction(tx);
// Étape 3 : Monitoring (basé sur le mode d'exécution)
if (order.executionMode === "async") {
// Interroger le statut de la commande pour les trades asynchrones
let status = "pending";
while (status !== "closed" && status !== "failed") {
await new Promise(r => setTimeout(r, 2000));
const statusRes = await fetch(
`${API_BASE}/order-status?signature=${signature}`,
{ headers: API_KEY ? { "x-api-key": API_KEY } : {} }
).then(r => r.json());
status = statusRes.status;
}
} else {
// Les trades synchrones se complètent de manière atomique
await connection.confirmTransaction(signature);
}
return signature;
}
Référence API
Endpoints Order API
GET /order
Retourne une cotation et optionnellement une transaction pour les trades spot ou des marchés de prédiction.
| Paramètre | Requis | Description |
|---|---|---|
inputMint |
Oui | Mint du token d'entrée en Base58 |
outputMint |
Oui | Mint du token de sortie en Base58 |
amount |
Oui | Montant en tant qu'entier mis à l'échelle (1 SOL = 1000000000) |
userPublicKey |
Non | Inclure pour recevoir une transaction signifiable |
slippageBps |
Non | Slippage maximal en points de base ou "auto" |
platformFeeBps |
Non | Frais de plateforme en points de base |
prioritizationFeeLamports |
Non | "auto", "medium", "high", "veryHigh", ou montant en lamports |
Réponse :
{
"outAmount": "150000000",
"minOutAmount": "149250000",
"priceImpactPct": "0.05",
"executionMode": "sync",
"transaction": "base64...",
"computeUnitLimit": 200000,
"lastValidBlockHeight": 123456789,
"routePlan": [...]
}
GET /order-status
Vérifier le statut des commandes asynchrones.
| Paramètre | Requis | Description |
|---|---|---|
signature |
Oui | Signature de la transaction en Base58 |
lastValidBlockHeight |
Non | Hauteur de bloc pour la vérification d'expiration |
Valeurs de statut :
pending- Commande soumise, en attente de traitementopen- Commande ouverte, en attente de remplissagependingClose- Remplie, transaction de fermeture en attenteclosed- Commande complétée avec succèsexpired- Transaction expirée avant d'être enregistréefailed- Exécution de la commande échouée
Endpoints Swap impératif
GET /quote
Obtenir une cotation pour un swap impératif.
| Paramètre | Requis | Description |
|---|---|---|
inputMint |
Oui | Mint d'entrée en Base58 |
outputMint |
Oui | Mint de sortie en Base58 |
amount |
Oui | Montant d'entrée (entier mis à l'échelle) |
slippageBps |
Non | Tolérance de slippage ou "auto" |
dexes |
Non | DEXes séparés par des virgules à inclure |
excludeDexes |
Non | DEXes séparés par des virgules à exclure |
onlyDirectRoutes |
Non | Routes à une seule jambe uniquement |
maxRouteLength |
Non | Nombre maximal de jambes de route |
forJitoBundle |
Non | Routes compatibles avec les bundles Jito |
platformFeeBps |
Non | Frais de plateforme en points de base |
POST /swap
Générer une transaction de swap à partir d'une cotation.
Corps de la requête :
{
"userPublicKey": "Base58...",
"quoteResponse": { /* from /quote */ },
"dynamicComputeUnitLimit": true,
"prioritizationFeeLamports": 150000,
"wrapAndUnwrapSol": true
}
Réponse :
{
"swapTransaction": "base64...",
"computeUnitLimit": 200000,
"lastValidBlockHeight": 123456789,
"prioritizationFeeLamports": 150000
}
POST /swap-instructions
Retourne les instructions individuelles au lieu d'une transaction complète (pour la construction de transactions personnalisées).
Endpoints Swap déclaratif
Les swaps déclaratifs utilisent l'exécution basée sur l'intention avec optimisation du routage différée.
GET /intent
Obtenir une cotation d'intention pour un swap déclaratif.
| Paramètre | Requis | Description |
|---|---|---|
inputMint |
Oui | Mint d'entrée en Base58 |
outputMint |
Oui | Mint de sortie en Base58 |
amount |
Oui | Montant d'entrée (entier mis à l'échelle) |
slippageBps |
Non | Tolérance de slippage |
userPublicKey |
Oui | Adresse du portefeuille de l'utilisateur |
POST /submit-intent
Soumettre une transaction d'intention signée pour exécution.
Corps de la requête :
{
"signedTransaction": "base64...",
"intentResponse": { /* from /intent */ }
}
Endpoints Token API
GET /tokens
Retourne une liste des mints de tokens supportés.
GET /tokens-with-decimals
Retourne les tokens avec les informations décimales pour la mise à l'échelle correcte des montants.
Endpoints Venue API
GET /venues
Retourne une liste des venues DEX supportées (Raydium, Orca, Phoenix, Lifinity, etc.).
Comparaison des modes de swap
| Fonctionnalité | Impératif | Déclaratif |
|---|---|---|
| Contrôle du routage | Contrôle total au moment de la signature | Optimisé à l'exécution |
| Latence | Plus élevée (deux appels API) | Plus basse (calcul différé) |
| Slippage | Fixé au moment de la cotation | Minimisé à l'exécution |
| Protection sandwich | Standard | Améliorée |
| Cas d'usage | Exigences de routage précises | Priorité à la meilleure exécution |
Quand utiliser l'impératif
- Besoin d'examiner le routage exact avant de signer
- Construction de carnets de commandes ou routage DEX spécifique
- Transactions multi-étapes complexes
- Besoin de chemins d'exécution déterministes
Quand utiliser le déclaratif
- Priorité à la meilleure exécution
- Exigences de slippage faible
- Simples échanges de tokens
- La protection MEV est importante
Modes d'exécution
Synchrone (Atomique)
- Exécution de transaction unique
- Règlement tout ou rien
- Flux de confirmation standard
- Utiliser
connection.confirmTransaction()
Asynchrone (Multi-transaction)
- Utilise les bundles Jito
- Flux de transaction Ouverture → Remplissage → Fermeture
- Interroger
/order-statuspour la complétion - Meilleur pour les routes complexes ou les marchés de prédiction
// Monitoring des commandes asynchrones
async function monitorAsyncOrder(signature: string) {
const statuses = ["pending", "open", "pendingClose"];
let currentStatus = "pending";
while (statuses.includes(currentStatus)) {
await new Promise(r => setTimeout(r, 2000));
const res = await fetch(
`${API_BASE}/order-status?signature=${signature}`,
{ headers: { "x-api-key": API_KEY } }
).then(r => r.json());
currentStatus = res.status;
if (currentStatus === "closed") {
return { success: true, fills: res.fills };
}
if (currentStatus === "failed" || currentStatus === "expired") {
return { success: false, status: currentStatus };
}
}
}
Marchés de prédiction
DFlow fournit une infrastructure pour le trading des tokens de résultat des marchés de prédiction.
Structure du marché
Series (Collection)
└── Event (Occurrence)
└── Market (Trade de résultat)
Cycle de vie du marché
- Initialized - Marché créé
- Active - Trading activé
- Inactive - Trading suspendu
- Closed - Pas de trading
- Determined - Résultat connu
- Finalized - Paiements disponibles
Trading des marchés de prédiction
// Utiliser l'API Trade avec les mints des tokens des marchés de prédiction
const order = await fetch(`${API_BASE}/order?${new URLSearchParams({
inputMint: USDC,
outputMint: OUTCOME_TOKEN_MINT, // Token du marché de prédiction
amount: "10000000", // 10 USDC
slippageBps: "100",
userPublicKey: keypair.publicKey.toBase58(),
predictionMarketSlippageBps: "200", // Slippage séparé pour PM
})}`, { headers: { "x-api-key": API_KEY } }).then(r => r.json());
Mints de tokens courants
| Token | Adresse du Mint |
|---|---|
| SOL (Wrapped) | So11111111111111111111111111111111111111112 |
| USDC | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| USDT | Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB |
| BONK | DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263 |
| JUP | JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN |
| WIF | EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm |
Frais de priorité
Configurer la priorité de la transaction :
// Option 1 : Auto (recommandé)
prioritizationFeeLamports: "auto"
// Option 2 : Niveau de priorité
prioritizationFeeLamports: {
priorityLevel: "high" // "medium", "high", "veryHigh"
}
// Option 3 : Montant exact
prioritizationFeeLamports: 150000
// Option 4 : Max avec ajustement automatique
prioritizationFeeLamports: {
autoMultiplier: 2,
maxLamports: 500000
}
Gestion des erreurs
async function safeSwap(params: SwapParams) {
try {
const quote = await getQuote(params);
if (!quote.routePlan?.length) {
throw new Error("No route found");
}
const swap = await getSwapTransaction(quote, params.userPublicKey);
const tx = deserializeTransaction(swap.swapTransaction);
tx.sign([params.keypair]);
const signature = await connection.sendTransaction(tx, {
skipPreflight: false,
maxRetries: 3,
});
return { success: true, signature };
} catch (error) {
if (error.message.includes("insufficient")) {
return { success: false, error: "Insufficient balance" };
}
if (error.message.includes("slippage")) {
return { success: false, error: "Slippage exceeded" };
}
return { success: false, error: error.message };
}
}
Frais de plateforme
Collecter les frais de plateforme sur les swaps :
const quote = await fetch(`${API_BASE}/quote?${new URLSearchParams({
inputMint: SOL,
outputMint: USDC,
amount: "1000000000",
platformFeeBps: "50", // Frais de 0,5%
platformFeeMode: "outputMint", // Collecter en token de sortie
})}`, { headers: { "x-api-key": API_KEY } }).then(r => r.json());
// Dans la requête de swap, spécifier le compte de frais
const swap = await fetch(`${API_BASE}/swap`, {
method: "POST",
headers: { "content-type": "application/json", "x-api-key": API_KEY },
body: JSON.stringify({
userPublicKey: user.toBase58(),
quoteResponse: quote,
feeAccount: platformFeeAccount.toBase58(), // Votre destinataire de frais
}),
}).then(r => r.json());
Intégration Jito
Pour la protection MEV et la soumission de bundles :
// Demander des routes compatibles Jito
const quote = await fetch(`${API_BASE}/quote?${new URLSearchParams({
inputMint: SOL,
outputMint: USDC,
amount: "1000000000",
forJitoBundle: "true",
})}`, { headers: { "x-api-key": API_KEY } }).then(r => r.json());
// Inclure la mitigation du sandwich Jito
const swap = await fetch(`${API_BASE}/swap`, {
method: "POST",
body: JSON.stringify({
userPublicKey: user.toBase58(),
quoteResponse: quote,
includeJitoSandwichMitigationAccount: true,
}),
}).then(r => r.json());
DFlow Swap Orchestrator
Le contrat DFlow Swap Orchestrator gère l'exécution des swaps déclaratifs :
Program ID: DF1ow3DqMj3HvTj8i8J9yM2hE9hCrLLXpdbaKZu4ZPnz
Prediction Market Metadata API
L'API de métadonnées des marchés de prédiction fournit un accès complet aux informations des marchés de prédiction.
URL de base : https://api.prod.dflow.net
Structure du marché
Series (Collection)
└── Event (Occurrence)
└── Market (Trade de résultat)
├── Yes Token (mint de résultat)
└── No Token (mint de résultat)
Events API
GET /api/v1/event/{ticker}
Retourne un événement unique par son ticker avec marchés imbriqués optionnels.
const METADATA_API = "https://api.prod.dflow.net";
// Obtenir les détails de l'événement
const event = await fetch(`${METADATA_API}/api/v1/event/TRUMP-2024`, {
headers: { "x-api-key": API_KEY }
}).then(r => r.json());
// La réponse inclut : ticker, title, status, markets, close_time, etc.
GET /api/v1/events
Retourne une liste paginée de tous les événements.
const events = await fetch(`${METADATA_API}/api/v1/events?limit=50&offset=0`, {
headers: { "x-api-key": API_KEY }
}).then(r => r.json());
GET /api/v1/event/{ticker}/forecast
Retourne les données historiques du percentile de prédiction.
GET /api/v1/event/{ticker}/candlesticks
Retourne les données en chandeliers de Kalshi.
Markets API
GET /api/v1/market/{ticker}
Retourne un marché unique par ticker.
const market = await fetch(`${METADATA_API}/api/v1/market/TRUMP-2024-WIN`, {
headers: { "x-api-key": API_KEY }
}).then(r => r.json());
// Réponse : ticker, yes_mint, no_mint, status, last_price, volume, etc.
GET /api/v1/market/by-mint/{mint_address}
Rechercher le marché par n'importe quel mint (ledger ou mints de résultat).
const market = await fetch(
`${METADATA_API}/api/v1/market/by-mint/${outcomeMint}`,
{ headers: { "x-api-key": API_KEY } }
).then(r => r.json());
POST /api/v1/markets/batch
Récupération par batch de plusieurs marchés (max 100).
const markets = await fetch(`${METADATA_API}/api/v1/markets/batch`, {
method: "POST",
headers: { "content-type": "application/json", "x-api-key": API_KEY },
body: JSON.stringify({
tickers: ["MARKET-1", "MARKET-2"],
mints: ["mint1...", "mint2..."]
})
}).then(r => r.json());
GET /api/v1/outcome_mints
Retourne tous les yes_mint et no_mint pubkeys de tous les marchés supportés.
// Obtenir tous les mints de résultat, filtrer optionnellement par heure de fermeture
const mints = await fetch(
`${METADATA_API}/api/v1/outcome_mints?min_close_timestamp=${Date.now()}`,
{ headers: { "x-api-key": API_KEY } }
).then(r => r.json());
POST /api/v1/filter_outcome_mints
Vérifier si les adresses sont des mints de résultat (max 200).
const filtered = await fetch(`${METADATA_API}/api/v1/filter_outcome_mints`, {
method: "POST",
headers: { "content-type": "application/json", "x-api-key": API_KEY },
body: JSON.stringify({ addresses: ["mint1...", "mint2..."] })
}).then(r => r.json());
Orderbook API
GET /api/v1/orderbook/{ticker}
Obtenir le carnet d'ordres par ticker du marché.
const orderbook = await fetch(
`${METADATA_API}/api/v1/orderbook/TRUMP-2024-WIN`,
{ headers: { "x-api-key": API_KEY } }
).then(r => r.json());
// Réponse : bids: [{price, quantity}], asks: [{price, quantity}]
GET /api/v1/orderbook/by-mint/{mint_address}
Obtenir le carnet d'ordres en utilisant la recherche par adresse mint.
Trades API
GET /api/v1/trades
Retourne l'historique des trades paginé avec filtrage.
const trades = await fetch(
`${METADATA_API}/api/v1/trades?ticker=TRUMP-2024-WIN&limit=100`,
{ headers: { "x-api-key": API_KEY } }
).then(r => r.json());
GET /api/v1/trades/by-mint/{mint_address}
Obtenir les trades en utilisant la recherche par adresse mint.
Live Data API
GET /api/v1/milestones/{ticker}
Données des jalons en temps réel de Kalshi.
const milestones = await fetch(
`${METADATA_API}/api/v1/milestones/TRUMP-2024`,
{ headers: { "x-api-key": API_KEY } }
).then(r => r.json());
Series & Categories
GET /api/v1/series
Retourne les templates de series pour les événements récurrents.
GET /api/v1/categories
Retourne les étiquettes de catégories pour le filtrage.
WebSocket Streaming
Se connecter pour les mises à jour en temps réel :
const ws = new WebSocket("wss://api.prod.dflow.net/ws");
ws.onopen = () => {
// S'abonner aux mises à jour du marché
ws.send(JSON.stringify({
action: "subscribe",
channel: "market",
ticker: "TRUMP-2024-WIN"
}));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
// Gérer : price_update, orderbook_update, trade, etc.
console.log("Update:", data);
};
Cycle de vie du marché
| Statut | Description |
|---|---|
initialized |
Marché créé |
active |
Trading activé |
inactive |
Trading suspendu |
closed |
Pas de trading |
determined |
Résultat connu |
finalized |
Paiements disponibles |
GitHub Tools & SDKs
DFlow fournit plusieurs outils open-source sur GitHub :
solana-agent-kit
Repository : DFlowProtocol/solana-agent-kit
Toolkit permettant aux agents IA de se connecter aux protocoles Solana :
// Utiliser avec des agents IA pour le trading automatisé
import { SolanaAgentKit } from "@dflow/solana-agent-kit";
const agent = new SolanaAgentKit({
rpcUrl: process.env.RPC_URL,
privateKey: process.env.PRIVATE_KEY,
});
// L'agent peut exécuter des swaps DFlow, interroger des marchés, etc.
clearpools
Repository : DFlowProtocol/clearpools
Orca Whirlpools avec support de segmentation de flux :
// Étend le protocole Orca avec le routage DFlow
import { ClearPools } from "@dflow/clearpools";
const pools = new ClearPools(connection);
await pools.initializePool(/* params */);
dflow-amm-interface
Repository : DFlowProtocol/dflow-amm-interface
Définitions de traits Rust pour l'implémentation AMM de DFlow. À utiliser lors de la construction d'AMMs personnalisés qui s'intègrent au routage DFlow.
Infrastructure Tools
- solana-accountsdb-plugin-bigtable - Plugin Geyser pour Bigtable
- solana-bigtable-connection - Bibliothèque de connexion Bigtable
- solana-bigtable-geyser-models - Modèles d'objets pour les données Geyser
Structure des skills
dflow/
├── SKILL.md # Ce fichier - guide d'intégration complet
├── resources/
│ ├── api-reference.md # Référence Swap API
│ ├── prediction-market-api.md # Référence Prediction Market Metadata API
│ ├── github-sdks.md # Documentation GitHub tools & SDKs
│ ├── token-mints.md # Adresses de tokens courants
│ └── error-codes.md # Guide de gestion des erreurs
├── examples/
│ ├── imperative-swaps/ # Exemples de swaps impératifs
│ ├── declarative-swaps/ # Exemples de swaps déclaratifs
│ ├── trade-api/ # Exemples Trade API unifié
│ └── prediction-markets/ # Exemples de marchés de prédiction
│ ├── query-markets.ts # Interroger les événements, marchés, carnet d'ordres
│ ├── trade-outcomes.ts # Trader les tokens de résultat
│ └── websocket-client.ts # Streaming de données en temps réel
├── templates/
│ ├── swap-client.ts # Démarrage du client swap
│ └── prediction-market-client.ts # Démarrage du client marché de prédiction
└── docs/
├── advanced-patterns.md # Intégrations complexes
└── troubleshooting.md # Problèmes courants
Directives
- Utiliser Trade API dans la plupart des cas - L'endpoint unifié gère la synchrone/asynchrone
- Toujours gérer les commandes asynchrones - Vérifier
executionModeet interroger le statut - Définir un slippage approprié - "auto" pour la commodité, personnalisé pour le contrôle
- Inclure les frais de priorité - Essentiel pour l'exécution fiable
- Gérer les erreurs avec grâce - Problèmes réseau, slippage, solde insuffisant
- Monitorer les limites de débit - Utiliser la clé API en production
- Tester sur devnet d'abord - DFlow supporte Solana devnet
Vérification
- Un véritable appel RPC/SDK a été émis (mainnet, devnet, ou validateur local) et la charge utile de réponse est capturée dans la transcription, jamais simplement paraphrasée
- Chaque transaction a été simulée (
simulateTransactionou équivalent) avant toute étape de signature/envoi ; les logs de simulation sont attachés - Pour toute transaction signée/envoyée, la signature résultante est enregistrée et confirmée en chaîne (statut retourné par
getSignatureStatusesou une URL d'explorateur) - Slippage, frais de priorité et limites de compute unit ont été définis explicitement avec des valeurs numériques concrètes, jamais laissés aux paramètres par défaut de la bibliothèque
- Les adresses de comptes, mints et IDs de programme utilisés dans l'exécution correspondent aux adresses DFlow documentées pour le cluster ciblé (pas de mélange mainnet/devnet)
- Le chemin d'erreur a été exercé au moins une fois (solde insuffisant, oracle obsolète, blockhash expiré, etc.) et la gestion des erreurs de l'agent a produit un message lisible