Comprendre l’architecture du XRP Ledger et son consensus UNL
Manipuler des comptes et transactions XRP via xrpl-py
Explorer les trust lines, offers et le DEX integre
Decouvrir les payment channels pour les micropaiements
Comprendre les Hooks comme equivalent smart contract du XRPL
Prerequis
Python 3.10+ avec xrpl-py (kernel Jupyter smartcontracts : environnement ou xrpl-py est installe)
Connexion internet (acces au Testnet XRP)
Environnement : ce notebook utilise le kernel smartcontracts et l’API asyncio de xrpl-py (AsyncJsonRpcClient, await), seule compatible avec la boucle evenementielle de Jupyter. Le client synchrone JsonRpcClient declenche asyncio.run() cannot be called from a running event loop dans un notebook.
Duree estimee : 50 minutes
1. Introduction au protocole Ripple et au XRP Ledger
Historique
Le XRP Ledger (XRPL) a ete concu en 2012 par Jed McCaleb, Arthur Britto et David Schwartz, avec pour objectif principal de faciliter les paiements transfrontaliers rapides et peu couteux. Contrairement a Bitcoin (2009) et Ethereum (2015), le XRPL n’utilise pas de Proof-of-Work ni de Proof-of-Stake : il repose sur un mécanisme de consensus unique base sur une Unique Node List (UNL).
Consensus UNL vs Proof-of-Work
Propriete
Bitcoin (PoW)
Ethereum (PoS)
XRP Ledger (UNL)
Temps de confirmation
~10 min
~12 sec
3-5 sec
Cout de transaction
Variable, souvent eleve
Variable (gas)
~0.00001 XRP
Consommation energetique
Très elevee
Moderee
Negligeable
Finalite
Probabiliste
Probabiliste
Déterministe
Decentralisation
Milliers de mineurs
Milliers de validateurs
~150 validateurs UNL
Le consensus UNL fonctionne par accord iteratif : chaque validateur maintient une liste de validateurs de confiance (la UNL). Un ledger est valide quand 80% ou plus des validateurs de la UNL s’accordent sur le même ensemble de transactions.
Concepts cles du XRPL
Concept
Description
Account
Adresse avec reserve de base (actuellement 10 XRP)
Trust Line
Lien bilateral pour detenir des IOU (devises personnalisees)
Offer
Ordre d’achat/vente sur le DEX integre au protocole
Payment Channel
Canal off-chain pour micropaiements en XRP
Escrow
Verrouillage conditionnel de XRP (time-lock, crypto-condition)
Hook
Programme WASM execute lors d’une transaction (smart contract)
# Comparaison des architectures blockchainarchitectures = {"Bitcoin (2009)": {"Consensus": "Proof-of-Work (SHA-256)","Langage SC": "Bitcoin Script (limite)","TPS": "~7","Finalite": "~60 min (6 confirmations)", },"Ethereum (2015)": {"Consensus": "Proof-of-Stake (Casper)","Langage SC": "Solidity / Vyper (Turing-complet)","TPS": "~15-30","Finalite": "~15 min (64 slots)", },"XRP Ledger (2012)": {"Consensus": "UNL (Unique Node List)","Langage SC": "Hooks (WASM) + primitives natives","TPS": "~1500","Finalite": "3-5 sec (deterministe)", },}print("COMPARAISON DES ARCHITECTURES BLOCKCHAIN")print("="*65)for chain, props in architectures.items():print(f"\n{chain}")print("-"*40)for key, val in props.items():print(f" {key:20s} : {val}")
Le XRPL se distingue par son approche pragmatique : plutot que de chercher la decentralisation maximale, il optimise pour la vitesse et le cout des paiements. Les fonctionnalites de smart contracts (trust lines, offers, escrows) sont natives au protocole plutot qu’executees dans une machine virtuelle generique.
Cette approche a des avantages (performance, fiabilite) et des inconvenients (flexibilite limitee comparee a Ethereum).
2. Installation et connexion au Testnet
La bibliotheque xrpl-py est le SDK Python officiel pour interagir avec le XRP Ledger. Le Testnet est un reseau de test gratuit ou l’on peut obtenir des XRP fictifs via un faucet (robinet) pour experimenter sans risque.
# Verification de l'installation de xrpl-pytry:import xrplfrom xrpl.asyncio.clients import AsyncJsonRpcClientfrom xrpl.asyncio.wallet import generate_faucet_walletfrom xrpl.asyncio.transaction import submit_and_waitfrom xrpl.models.requests import AccountInfo, Ledgerfrom importlib.metadata import version as pkg_versionimport sysprint(f"xrpl-py version : {pkg_version('xrpl-py')}")print(f"Python : {sys.version.split()[0]}")print("Installation OK - API asyncio chargee (compatible boucle Jupyter)")exceptImportError:print("xrpl-py n'est pas installe dans le kernel smartcontracts.")print("Installation : pip install xrpl-py")print("Les cellules suivantes ne fonctionneront pas sans cette bibliotheque.")
xrpl-py version : 4.5.0
Python : 3.13.3
Installation OK - API asyncio chargee (compatible boucle Jupyter)
Connexion au testnet XRP Ledger via un client JSON-RPC pour interagir avec le réseau de test.
# Connexion au Testnet XRP - API asyncio nativeimport xrplfrom xrpl.asyncio.clients import AsyncJsonRpcClientfrom xrpl.models.requests import LedgerTESTNET_URL ="https://s.altnet.rippletest.net:51234"# AsyncJsonRpcClient s'integre a la boucle evenementielle de Jupyter :# chaque appel est un simple `await`, sans asyncio.run() interdit.client = AsyncJsonRpcClient(TESTNET_URL)response =await client.request(Ledger(ledger_index="validated"))ledger_index = response.result.get("ledger_index", "inconnu")close_time = response.result.get("ledger", {}).get("close_time_human", "inconnu")print("Connexion au Testnet XRP reussie")print(f" URL : {TESTNET_URL}")print(f" Ledger valide : #{ledger_index}")print(f" Heure : {close_time}")
Connexion au Testnet XRP reussie
URL : https://s.altnet.rippletest.net:51234
Ledger valide : #20235788
Heure : 2026-Aug-26 12:42:52.000000000 UTC
Interpretation : connexion au Testnet XRP
Resultat obtenu : la lecture du dernier ledger valide reussit en direct - le numero de ledger et son horodatage ci-dessus viennent du reseau Testnet au moment de l’execution.
Le piege asyncio de xrpl-py : le client synchrone JsonRpcClient encapsule chaque requete dans asyncio.run(), ce qui leve asyncio.run() cannot be called from a running event loop sous Jupyter (le notebook possede deja sa boucle). Le notebook bascule alors entierement en mode simule sans erreur visible - un defaut silencieux typique. La solution n’est pas de contourner (threads, nest_asyncio) mais d’utiliser l’API officielle asynchrone : AsyncJsonRpcClient + await client.request(...), native dans xrpl-py.
Information
Exemple
Source
ledger_index
Numero entier
Compteur sequentiel des ledgers
close_time_human
Date et heure
Horodatage de fermeture du ledger
URL Testnet
s.altnet.rippletest.net
Point d’acces au reseau de test
Note technique : Le XRPL utilise un modele JSON-RPC (et WebSocket) plutot que REST. Chaque appel au client envoie une requete JSON structuree et recoit une reponse JSON.”
Création d’un wallet de test via le faucet du testnet XRP pour obtenir des fonds de développement.
# Creation de wallets de test via le faucet - sans jamais exposer la seedfrom xrpl.asyncio.wallet import generate_faucet_walletfrom xrpl.models.requests import AccountInfoprint("Demande de XRP au faucet Testnet (10-20 s par wallet)...\n")# debug=False est indispensable : debug=True imprimerait la seed dans les outputs.wallet_1 =await generate_faucet_wallet(client, debug=False)wallet_2 =await generate_faucet_wallet(client, debug=False)print("WALLET 1 (Alice)")print(f" Adresse classique : {wallet_1.address}")print(f" Cle publique : {wallet_1.public_key[:32]}...")print(" Seed : jamais affichee (secret de signature)")print()print("WALLET 2 (Bob)")print(f" Adresse classique : {wallet_2.address}")print(f" Cle publique : {wallet_2.public_key[:32]}...")print(" Seed : jamais affichee (secret de signature)")print()# Consulter les soldes reelsfor label, w in (("Alice", wallet_1), ("Bob", wallet_2)): acct_info =await client.request(AccountInfo( account=w.address, ledger_index="validated")) balance_drops =int(acct_info.result["account_data"]["Balance"])print(f"Solde {label} : {balance_drops /1_000_000:.6f} XRP ({balance_drops:,} drops)")print(" (1 XRP = 1,000,000 drops)")
Demande de XRP au faucet Testnet (10-20 s par wallet)...
WALLET 1 (Alice)
Adresse classique : rsV9uq1DVWrHWbx66jhkeyxa5jKfgmErg9
Cle publique : ED4BCB4D0E298410ECB3E4D6FC7A3EC5...
Seed : jamais affichee (secret de signature)
WALLET 2 (Bob)
Adresse classique : rnAwyYV3R7CShvr4hVuBwHSurRbtWpzRSX
Cle publique : ED7DCA1B2D6E2A4DDABFF6E64524E308...
Seed : jamais affichee (secret de signature)
Solde Alice : 100.000000 XRP (100,000,000 drops)
Solde Bob : 100.000000 XRP (100,000,000 drops)
(1 XRP = 1,000,000 drops)
Interpretation : creation de wallets et reserves
Resultat obtenu : deux wallets finances par le faucet, avec soldes verifies en direct. La seed existe en memoire (elle signe les transactions des cellules suivantes) mais n’est jamais imprimee ni persistee : exposer la seed d’un wallet - meme de test - dans un output committe revient a publier sa cle privee.
Element
Format
Utilite
Adresse
r... (25-35 caracteres)
Identifiant public du compte
Cle publique
Hex (64 octets)
Verification des signatures
Seed
s... (cle privee)
Signature des transactions - secret, jamais affichee
Points cles : - La reserve de base est un mecanisme anti-spam : chaque objet supplementaire (trust line, offer, channel) consomme de la reserve - 1 XRP = 1 000 000 drops. Le XRPL utilise les drops comme unite atomique dans toutes les operations - Regle de securite : la seed ne quitte jamais la memoire du process. En production, elle vit dans un wallet hardware ou un gestionnaire de secrets.
Le faucet Testnet distribue des XRP gratuits pour les tests. Chaque compte XRP necessite une reserve de base (actuellement 10 XRP sur le mainnet) pour exister. Cette reserve empeche la creation massive de comptes spam.
Anatomie d’une adresse XRP : - Commence par r (Base58Check, similaire a Bitcoin) - 25-34 caractères - Derivee de la cle publique Ed25519 ou secp256k1
3. Transactions XRP
Le XRPL supporte nativement plusieurs types de transactions, sans avoir besoin de smart contracts :
Type
Description
Payment
Transfert de XRP ou d’IOU
TrustSet
Etablir une trust line (autoriser un IOU)
OfferCreate
Placer un ordre sur le DEX integre
OfferCancel
Annuler un ordre DEX
EscrowCreate
Verrouiller des XRP conditionnellement
PaymentChannelCreate
Ouvrir un canal de micropaiement
Chaque transaction est signee par la cle privee de l’expediteur et validee par le consensus en 3-5 secondes.
# Envoi d'un paiement XRP - transaction Testnet reellefrom xrpl.asyncio.transaction import submit_and_wait as submit_and_wait_asyncfrom xrpl.models.transactions import Paymentfrom xrpl.utils import xrp_to_drops# Paiement de 25 XRP d'Alice vers Bobpayment_tx = Payment( account=wallet_1.address, destination=wallet_2.address, amount=xrp_to_drops(25), # 25 XRP en drops)print("ENVOI DE PAIEMENT XRP")print("="*60)print(f"De : {wallet_1.address}")print(f"Vers : {wallet_2.address}")print(f"Montant : 25 XRP ({xrp_to_drops(25)} drops)")print("\nSoumission en cours...")response =await submit_and_wait_async(payment_tx, client, wallet_1)result = response.resulttx_hash = result.get("hash", "inconnu")status = result.get("meta", {}).get("TransactionResult", "inconnu")# Frais reels, mesures par difference de solde avant/apres paiement :# le solde d'Alice ne baisse que du montant envoye + des frais.acct_after =await client.request(AccountInfo( account=wallet_1.address, ledger_index="validated"))balance_after =int(acct_after.result["account_data"]["Balance"])fee_drops =100_000_000-25_000_000- balance_afterprint(f"\nResultat :")print(f" Hash : {tx_hash}")print(f" Statut : {status}")print(f" Frais : {fee_drops} drops ({fee_drops /1_000_000:.6f} XRP), mesures par solde avant/apres")print(f" Solde Alice : 100.000000 -> {balance_after /1_000_000:.6f} XRP")print(f" Ledger : {result.get('ledger_index', 'inconnu')}")if status =="tesSUCCESS":print("\n-> Transaction validee par le consensus Testnet en quelques secondes")else:print(f"\n-> Resultat inattendu : {status}")
ENVOI DE PAIEMENT XRP
============================================================
De : rsV9uq1DVWrHWbx66jhkeyxa5jKfgmErg9
Vers : rnAwyYV3R7CShvr4hVuBwHSurRbtWpzRSX
Montant : 25 XRP (25000000 drops)
Soumission en cours...
Resultat :
Hash : 4E1FF3141312183FC34E8C9284B109A6653705CD0CE9C4571A8E65DED4A0D4A9
Statut : tesSUCCESS
Frais : 10 drops (0.000010 XRP), mesures par solde avant/apres
Solde Alice : 100.000000 -> 74.999990 XRP
Ledger : 20235798
-> Transaction validee par le consensus Testnet en quelques secondes
Interpretation : transaction de paiement XRP
Resultat obtenu : transaction validee en direct sur le Testnet - le hash ci-dessus est verifiable dans l’explorateur (testnet.xrpl.org), le code tesSUCCESS et le numero de ledger sont ceux du reseau au moment de l’execution.
Champ
Valeur typique
Signification
hash
64 caracteres hex
Identifiant unique de la transaction
TransactionResult
tesSUCCESS
Code de resultat (tes = Transaction Engine Success)
Fee
~12 drops (~0.000012 XRP)
Frais de transaction
ledger_index
Numero du ledger
Bloc dans lequel la tx est incluse
Points cles : - Le code tesSUCCESS signifie une validation reussie. Le prefixe tes est un des prefixes de codes du XRPL (tec, tef, tel, tem pour les differents types d’echec) - Les frais sont fixes et ne dependent pas de la congestion du reseau - a contraster avec le gas d’Ethereum - La finalite est deterministe : 3-5 secondes, pas de reorganisation possible comme sur Ethereum
Création d’une Trust Line pour accepter un IOU (dette émise) d’un autre compte sur le XRP Ledger.
# Creation d'une Trust Line pour un IOU (devise personnalisee) - transaction reellefrom xrpl.models.transactions import TrustSetfrom xrpl.models.amounts import IssuedCurrencyAmount# Bob autorise Alice a emettre jusqu'a 1000 EUR (IOU)trust_set_tx = TrustSet( account=wallet_2.address, limit_amount=IssuedCurrencyAmount( currency="EUR", issuer=wallet_1.address, value="1000", ),)print("CREATION D'UNE TRUST LINE")print("="*60)print("Bob autorise Alice a emettre jusqu'a 1000 EUR")print(f" Compte : {wallet_2.address} (Bob)")print(f" Emetteur : {wallet_1.address} (Alice)")print(f" Devise : EUR")print(f" Limite : 1000")print("\nSoumission en cours...")response =await submit_and_wait_async(trust_set_tx, client, wallet_2)status = response.result.get("meta", {}).get("TransactionResult", "inconnu")print(f" Hash : {response.result.get('hash', 'inconnu')}")print(f" Statut : {status}")if status =="tesSUCCESS":print("\n-> Trust line creee sur le ledger. Bob peut maintenant recevoir des EUR d'Alice.")print(" Les trust lines sont la base du systeme de credit du XRPL.")
CREATION D'UNE TRUST LINE
============================================================
Bob autorise Alice a emettre jusqu'a 1000 EUR
Compte : rnAwyYV3R7CShvr4hVuBwHSurRbtWpzRSX (Bob)
Emetteur : rsV9uq1DVWrHWbx66jhkeyxa5jKfgmErg9 (Alice)
Devise : EUR
Limite : 1000
Soumission en cours...
Hash : 96C839AB3EF1CE83A25591F6DAEC7DCF601307EDAF3914414F39C467B4A62FEF
Statut : tesSUCCESS
-> Trust line creee sur le ledger. Bob peut maintenant recevoir des EUR d'Alice.
Les trust lines sont la base du systeme de credit du XRPL.
Interpretation : Trust Lines et systeme de credit
Resultat obtenu : la Trust Line de Bob vers Alice (limite 1000 EUR) est reellement inscrite au ledger - le hash et le statut tesSUCCESS ci-dessus proviennent de la transaction Testnet validee.
Propriete
Valeur
Role
Compte
Bob
Celui qui accorde sa confiance
Emetteur
Alice
Celui qui peut emettre l’IOU
Devise
EUR
Code devise ISO 4217 (ou libre)
Limite
1000
Plafond de confiance de Bob
Points cles : - Sans Trust Line, il est impossible de recevoir un IOU d’un emetteur donne - La limite protege Bob : Alice ne peut pas lui envoyer plus de 1000 EUR sans son consentement - Les Trust Lines sont bilaterales : Bob autorise Alice, mais Alice doit aussi autoriser Bob pour un flux bidirectionnel - Ce mecanisme remplace les smart contracts ERC-20 d’Ethereum : pas de code a deployer pour creer un token
Création d’un Offer sur le DEX intégré du XRP Ledger pour échanger des devises de manière décentralisée.
# Creation d'un Offer sur le DEX integre - transaction reellefrom xrpl.models.transactions import OfferCreate# Alice propose de vendre 50 XRP contre 45 EURoffer_tx = OfferCreate( account=wallet_1.address, taker_pays=xrp_to_drops(50), # Ce que l'acheteur paie : 50 XRP taker_gets=IssuedCurrencyAmount( # Ce que l'acheteur recoit : 45 EUR currency="EUR", issuer=wallet_1.address, value="45", ),)print("CREATION D'UN OFFER (DEX INTEGRE)")print("="*60)print("Le XRPL possede un DEX (Decentralized Exchange) natif.")print("Pas besoin de smart contract comme Uniswap sur Ethereum.\n")print("Alice propose :")print(" Vend : 45 EUR (IOU)")print(" Recoit: 50 XRP")print(" Taux : 1 EUR = 1.11 XRP\n")print("Soumission en cours...")response =await submit_and_wait_async(offer_tx, client, wallet_1)status = response.result.get("meta", {}).get("TransactionResult", "inconnu")print(f" Hash : {response.result.get('hash', 'inconnu')}")print(f" Statut : {status}")if status =="tesSUCCESS":print("\n-> Offer placee sur le carnet d'ordres du XRPL")print(" Elle sera executee automatiquement si un offer correspondant apparait.")
CREATION D'UN OFFER (DEX INTEGRE)
============================================================
Le XRPL possede un DEX (Decentralized Exchange) natif.
Pas besoin de smart contract comme Uniswap sur Ethereum.
Alice propose :
Vend : 45 EUR (IOU)
Recoit: 50 XRP
Taux : 1 EUR = 1.11 XRP
Soumission en cours...
Hash : B5F36C3F9BC240F4D0DF063059CD91AD62C404A7AF84A58472CCC275A5E793B6
Statut : tesSUCCESS
-> Offer placee sur le carnet d'ordres du XRPL
Elle sera executee automatiquement si un offer correspondant apparait.
Interpretation : DEX integre au protocole
Resultat obtenu : l’offre de vente de 45 EUR contre 50 XRP est reellement placee sur le carnet d’ordres Testnet (hash et tesSUCCESS ci-dessus). Comme aucun ordre correspondant n’existe, elle reste en attente - c’est le comportement attendu d’un carnet d’ordres.
Element
Valeur
Explication
taker_pays
50 XRP
Ce que l’acheteur paie
taker_gets
45 EUR (IOU)
Ce que l’acheteur recoit
Taux implicite
1 EUR = 1.11 XRP
Ratio taker_pays / taker_gets
Matching
Automatique
Le protocole execute si un offer inverse existe
Note technique : L’auto-bridging est une fonctionnalite unique du XRPL. Si Alice veut vendre des EUR contre des USD et qu’un chemin optimal passe par XRP, le protocole effectue automatiquement la conversion EUR -> XRP -> USD sans intervention de l’utilisateur.
Les trois types de transactions ci-dessus illustrent la philosophie du XRPL : les fonctionnalites financieres sont integrees au protocole, pas ajoutees via des smart contracts.
Fonctionnalite
Ethereum
XRP Ledger
Transfert de tokens
Smart contract ERC-20
Trust line + Payment natif
Echange decentralise
Uniswap (smart contract)
DEX natif (OfferCreate)
Depot conditionnel
Smart contract Escrow
EscrowCreate natif
Micropaiements
State channels (complexe)
PaymentChannel natif
Avantage : fiabilite, performance, cout minimal. Inconvenient : impossible d’inventer de nouvelles primitives sans modifier le protocole (avant l’arrivee des Hooks, cf. section 5).
3b. Exercice : Analyseur de transactions XRP
Objectif
Implementez une fonction analyze_xrp_transaction qui analyse une transaction XRP brute (sous forme de dictionnaire) et en extrait les informations cles : type de transaction, parties impliquees, montants et frais.
Contexte
Chaque transaction XRP contient des champs standards (Account, Fee, Sequence) et des champs spécifiques au type (Amount, Destination pour un paiement, LimitAmount pour une trust line, etc.). Un analyseur doit extraire et formater ces informations de maniere lisible.
Indice :
Utilisez des if/elif sur le champ TransactionType pour distinguer les types
Pour un Payment, les champs cles sont Account, Destination, Amount, Fee
Pour un TrustSet, le champ est LimitAmount avec les sous-champs currency, issuer, value
Retournez un dictionnaire structure avec un resume human-readable
def analyze_xrp_transaction(tx):"""Analyser une transaction XRP et extraire un resume lisible.TODO etudiant : implementez l'analyse pour les types suivants : - Payment : extraire Account, Destination, Amount, Fee - TrustSet : extraire Account, LimitAmount (currency, issuer, value) - OfferCreate : extraire Account, TakerPays, TakerGets Args: tx: dictionnaire representant une transaction XRP brute (contient au minimum 'TransactionType', 'Account', 'Fee') Returns: dict avec les cles 'type', 'summary', 'fee_drops', 'details' """# TODO etudiant : implementez l'analysereturn {"type": None, "summary": None, "fee_drops": None, "details": {}}# Test avec des transactions simuleessample_payment = {"TransactionType": "Payment","Account": "rAlice...","Destination": "rBob...","Amount": "25000000", # 25 XRP en drops"Fee": "12","Sequence": 1,}sample_trustset = {"TransactionType": "TrustSet","Account": "rBob...","LimitAmount": {"currency": "EUR", "issuer": "rAlice...", "value": "1000"},"Fee": "12","Sequence": 2,}print("Exercice a completer : implementez analyze_xrp_transaction")print(f" Transaction test 1 : {sample_payment['TransactionType']}")print(f" Transaction test 2 : {sample_trustset['TransactionType']}")
Exercice a completer : implementez analyze_xrp_transaction
Transaction test 1 : Payment
Transaction test 2 : TrustSet
4. Payment Channels (micropaiements)
Les Payment Channels permettent des flux de micropaiements off-chain entre deux parties, avec un reglement final on-chain.
Principe
1. Alice ouvre un canal : verrouille 100 XRP on-chain
2. Alice envoie des "claims" signes a Bob (off-chain, instantane)
- Claim 1 : Bob peut reclamer 1 XRP
- Claim 2 : Bob peut reclamer 2 XRP (remplace claim 1)
- Claim 3 : Bob peut reclamer 3 XRP (remplace claim 2)
- ...
3. Bob soumet le dernier claim on-chain pour recevoir ses XRP
4. Le canal est ferme, Alice recupere le reste
Cas d’usage : streaming de paiements (payer a la seconde pour un service), microtransactions (IoT, API pay-per-call), et tout scénario ou les frais de transaction on-chain seraient prohibitifs.
# Demonstration conceptuelle des Payment Channels# (La creation reelle necessite un canal ouvert sur le ledger)import hashlibimport jsonimport timeprint("PAYMENT CHANNEL - SIMULATION CONCEPTUELLE")print("="*60)# Etape 1 : Ouverture du canalchannel_params = {"source": "rAlice...","destination": "rBob...","amount_xrp": 100,"settle_delay_seconds": 3600, # 1 heure pour contester}print("1. OUVERTURE DU CANAL")print(f" Source : {channel_params['source']}")print(f" Destination : {channel_params['destination']}")print(f" Reserve : {channel_params['amount_xrp']} XRP")print(f" Delai : {channel_params['settle_delay_seconds']}s")print()# Etape 2 : Flux de claims off-chainprint("2. FLUX DE CLAIMS OFF-CHAIN")print("-"*40)cumulative_amount =0claims = []for i inrange(1, 11): cumulative_amount +=0.5# 0.5 XRP par increment claim = {"channel_id": "ABC123...","amount_drops": int(cumulative_amount *1_000_000),"signature": hashlib.sha256(f"claim:{cumulative_amount}".encode() ).hexdigest()[:16] +"...", } claims.append(claim)print(f" Claim {i:2d} : {cumulative_amount:.1f} XRP"f" (sig: {claim['signature'][:12]}...)")print()# Etape 3 : Reglement finallast_claim = claims[-1]remaining = channel_params["amount_xrp"] - cumulative_amountprint("3. REGLEMENT FINAL ON-CHAIN")print(f" Bob soumet le dernier claim : {cumulative_amount:.1f} XRP")print(f" Bob recoit : {cumulative_amount:.1f} XRP")print(f" Alice recupere le reste : {remaining:.1f} XRP")print(f" Total = {cumulative_amount + remaining:.1f} XRP (integre)")print()print("-> 10 transferts realises pour le cout d'1 seule transaction on-chain")print("-> Latence quasi-nulle pour les claims off-chain")
PAYMENT CHANNEL - SIMULATION CONCEPTUELLE
============================================================
1. OUVERTURE DU CANAL
Source : rAlice...
Destination : rBob...
Reserve : 100 XRP
Delai : 3600s
2. FLUX DE CLAIMS OFF-CHAIN
----------------------------------------
Claim 1 : 0.5 XRP (sig: 32ba101f6d7d...)
Claim 2 : 1.0 XRP (sig: 1e3baf0a3b58...)
Claim 3 : 1.5 XRP (sig: 9957d0d4212a...)
Claim 4 : 2.0 XRP (sig: 5d96607fa8ea...)
Claim 5 : 2.5 XRP (sig: 8f86e267d0ab...)
Claim 6 : 3.0 XRP (sig: 5cd139a825bc...)
Claim 7 : 3.5 XRP (sig: 1ab175b5374d...)
Claim 8 : 4.0 XRP (sig: 44e2386e70cf...)
Claim 9 : 4.5 XRP (sig: b0d46f517113...)
Claim 10 : 5.0 XRP (sig: b5d920a7f36a...)
3. REGLEMENT FINAL ON-CHAIN
Bob soumet le dernier claim : 5.0 XRP
Bob recoit : 5.0 XRP
Alice recupere le reste : 95.0 XRP
Total = 100.0 XRP (integre)
-> 10 transferts realises pour le cout d'1 seule transaction on-chain
-> Latence quasi-nulle pour les claims off-chain
Interpretation : simulation d’un Payment Channel
Résultat obtenu : 10 claims cumulatifs sont generes off-chain, passant de 0.5 a 5.0 XRP. Seul le dernier claim sera soumis on-chain.
Étape
Action
On-chain ?
Cout
Ouverture du canal
Verrouillage de 100 XRP
Oui
1 transaction
Claims 1 a 10
Envoi de 0.5 XRP chacun
Non
0
Reglement final
Soumission du dernier claim
Oui
1 transaction
Points cles : - Le rapport cout/transfert est de 2 transactions pour 10 paiements, soit un cout effectif de ~0.0000024 XRP par paiement : 2 transactions x 12 drops = 24 drops = 0.000024 XRP au total, reparti sur 10 paiements (vs 0.000012 XRP par paiement, soit 10 x 12 drops = 0.00012 XRP au total, si chaque paiement etait on-chain) - L’avantage principal n’est pas le cout mais la latence : les claims off-chain sont instantanes - L’integrite est garantie : 5.0 + 95.0 = 100.0 XRP (conservation parfaite)
Ouverture réelle d’un Payment Channel sur le testnet XRP via la transaction PaymentChannelCreate.
# Ouverture d'un Payment Channel reelle - transaction Testnetfrom xrpl.models.transactions import PaymentChannelCreate# Ouverture d'un canal de 20 XRPchannel_tx = PaymentChannelCreate( account=wallet_1.address, destination=wallet_2.address, amount=xrp_to_drops(20), settle_delay=3600, # 1 heure de delai de reglement public_key=wallet_1.public_key,)print("OUVERTURE D'UN PAYMENT CHANNEL REEL")print("="*60)print(f" De : {wallet_1.address}")print(f" Vers : {wallet_2.address}")print(f" Reserve : 20 XRP")print(f" Delai : 3600 secondes\n")print("Soumission en cours...")response =await submit_and_wait_async(channel_tx, client, wallet_1)status = response.result.get("meta", {}).get("TransactionResult", "inconnu")print(f" Hash : {response.result.get('hash', 'inconnu')}")print(f" Statut : {status}")if status =="tesSUCCESS":# Extraire le channel ID des metadonnees meta = response.result.get("meta", {}) affected = meta.get("AffectedNodes", []) channel_id =Nonefor node in affected: created = node.get("CreatedNode", {})if created.get("LedgerEntryType") =="PayChannel": channel_id = created.get("LedgerIndex")breakif channel_id:print(f" Channel ID : {channel_id}")print("\n-> Canal ouvert sur le ledger. Les claims off-chain peuvent commencer.")
OUVERTURE D'UN PAYMENT CHANNEL REEL
============================================================
De : rsV9uq1DVWrHWbx66jhkeyxa5jKfgmErg9
Vers : rnAwyYV3R7CShvr4hVuBwHSurRbtWpzRSX
Reserve : 20 XRP
Delai : 3600 secondes
Soumission en cours...
Hash : 561A526FB4B1B0E5CCB956CB6E5F560B117A43D7776AD4D5F0AAA4528FD392F4
Statut : tesSUCCESS
Channel ID : 8F9AACFF78829EA1552E00458707AB983C85039027B27B16492CF573287A1419
-> Canal ouvert sur le ledger. Les claims off-chain peuvent commencer.
Interpretation : ouverture d’un Payment Channel reel
Resultat obtenu : le canal est reellement ouvert sur le Testnet - le channel_id ci-dessus est l’identifiant du ledger entry PayChannel cree par la transaction (extrait des AffectedNodes de la reponse validee).
Parametre
Valeur
Signification
amount
20 XRP
Reserve bloquee on-chain
settle_delay
3600s
Delai de contestation apres fermeture
public_key
cle Alice
Authentification des claims
Note technique : Le settle_delay est crucial pour la securite. Si Alice veut fermer le canal, elle doit attendre 3600 secondes pendant lesquelles Bob peut soumettre son dernier claim. Cela empeche Alice de fermer le canal brutalement avant que Bob n’ait recu ses fonds.
Les Payment Channels du XRPL sont une solution native aux micropaiements :
Aspect
On-chain classique
Payment Channel
Cout par transfert
~0.000012 XRP
0 (off-chain)
Latence
3-5 secondes
Instantane
Debit
~1500 TPS
Illimite (off-chain)
Securite
Consensus complet
Signature cryptographique
Bob est protege car il peut soumettre le dernier claim a tout moment. Alice est protegee par le delai de reglement (settle_delay) qui empeche Bob de reclamer des fonds après la fermeture.
4b. Exercice : Validateur de claims pour Payment Channel
Objectif
Implementez une fonction validate_claim_chain qui valide une sequence de claims off-chain pour un Payment Channel. La fonction doit verifier l’integrite de la chaîne de claims : montants strictement croissants et signatures valides.
Contexte
Dans un Payment Channel, Bob recoit une serie de claims signes par Alice. Chaque claim remplace le précédent : seul le dernier compte. Bob doit pouvoir verifier que les claims sont valides (montant croissant, signature correcte) avant de soumettre le dernier on-chain.
Indice :
Parcourez la liste de claims et verifiez que chaque montant est > au précédent
Verifiez que chaque signature correspond au montant (hash SHA-256 du montant)
Retournez le montant total valide (dernier claim) et le nombre de claims valides
Utilisez hashlib.sha256 pour verifier les signatures simulees
import hashlibdef generate_claim(channel_id, cumulative_drops, sender_key):"""Generer un claim simule (fourni, ne pas modifier).""" msg =f"{channel_id}:{cumulative_drops}" sig = hashlib.sha256((msg + sender_key).encode()).hexdigest()[:16]return {"channel_id": channel_id, "amount_drops": cumulative_drops, "signature": sig}def validate_claim_chain(claims, channel_id, sender_key, max_channel_amount):"""Valider une chaine de claims pour un Payment Channel.TODO etudiant : implementez les verifications : 1. Les montants sont strictement croissants 2. Chaque signature correspond a SHA-256(channel_id:amount + sender_key)[:16] 3. Le dernier montant ne depasse pas max_channel_amount 4. Tous les channel_id correspondent Args: claims: liste de dictionnaires (channel_id, amount_drops, signature) channel_id: identifiant attendu du canal sender_key: cle de l'emetteur pour la verification de signature max_channel_amount: montant maximal du canal (en drops) Returns: dict avec 'valid', 'last_valid_amount', 'num_validated', 'errors' """# TODO etudiant : implementez la validationreturn {"valid": False, "last_valid_amount": 0, "num_validated": 0, "errors": []}# Generation de claims de testtest_channel_id ="ABC123..."test_sender_key ="alice_secret_key"test_claims = [ generate_claim(test_channel_id, 500_000, test_sender_key), # 0.5 XRP generate_claim(test_channel_id, 1_000_000, test_sender_key), # 1.0 XRP generate_claim(test_channel_id, 1_500_000, test_sender_key), # 1.5 XRP generate_claim(test_channel_id, 2_000_000, test_sender_key), # 2.0 XRP]print("Exercice a completer : implementez validate_claim_chain")print(f" Canal : {test_channel_id}")print(f" Claims : {len(test_claims)} claims generes")print(f" Montant max: 5.0 XRP (5_000_000 drops)")
Les Hooks sont l’equivalent des smart contracts pour le XRP Ledger. Introduits via l’amendement Hooks (en cours de deploiement), ils permettent d’attacher une logique programmable aux comptes du XRPL.
Architecture des Hooks
Propriete
Ethereum Smart Contract
XRP Hook
Langage
Solidity / Vyper
C (compile en WASM)
Exécution
EVM
WebAssembly (WASM)
Declenchement
Appel explicite
Automatique (pre/post transaction)
Stockage
Storage slots (256 bits)
Hook State (32 bytes key-value)
Limites
Gas limit
Instruction count
Declenchement
Un Hook est declenche automatiquement lorsqu’une transaction implique le compte auquel il est attache :
#include "hookapi.h"// Hook qui limite les paiements sortants a 100 XRP maximumint64_t hook(uint32_t reserved){// Lire le montant de la transactionint64_t amount = otxn_amount();// Limite de 100 XRP (en drops)int64_t limit =100000000;// 100 * 1,000,000 dropsif(amount > limit){// Rejeter la transaction rollback(SBUF("Payment exceeds 100 XRP limit"),1);}// Accepter la transaction accept(SBUF("Payment approved"),0);return0;}
API Hook principale
Fonction
Description
hook()
Point d’entree pour les transactions sortantes
cbak()
Callback pour les transactions entrantes
accept()
Approuver la transaction
rollback()
Rejeter la transaction
otxn_amount()
Montant de la transaction courante
otxn_field()
Lire un champ de la transaction
state_set()
Ecrire dans le stockage du Hook
state()
Lire le stockage du Hook
emit()
Emettre une transaction depuis le Hook
Note : Les Hooks sont en cours de deploiement sur le mainnet XRPL. Ils sont disponibles sur le testnet Hooks (hooks-testnet-v3.xrpl-labs.com). La compilation C -> WASM necessite un toolchain spécifique (wasmcc).
# Les Hooks ne sont pas encore deployables via xrpl-py standard.# Voici une representation structurelle d'un Hook.print("ANATOMIE D'UN HOOK XRPL")print("="*60)hook_example = {"nom": "Limite de paiement sortant","description": "Rejette tout paiement sortant > 100 XRP","langage": "C -> WebAssembly (WASM)","declenchement": "Automatique sur chaque transaction sortante","fonctions": {"hook()": "Verifie le montant, accept/rollback","cbak()": "Non utilise (transactions entrantes)", },"etat_stocke": {"limite": "100 XRP (modifiable par le proprietaire)","compteur_rejets": "Nombre de transactions rejetees", },"taille_wasm": "~2 Ko","cout_installation": "~2 XRP (reserve d'objet)",}for key, val in hook_example.items():ifisinstance(val, dict):print(f"\n{key} :")for k, v in val.items():print(f" {k:25s} : {v}")else:print(f"{key:25s} : {val}")print()print("Cycle de vie d'un Hook :")print(" 1. Ecriture en C avec hookapi.h")print(" 2. Compilation en WASM (wasmcc)")print(" 3. Installation via SetHook transaction")print(" 4. Declenchement automatique a chaque transaction")print(" 5. Desinstallation via SetHook (wasm vide)")
ANATOMIE D'UN HOOK XRPL
============================================================
nom : Limite de paiement sortant
description : Rejette tout paiement sortant > 100 XRP
langage : C -> WebAssembly (WASM)
declenchement : Automatique sur chaque transaction sortante
fonctions :
hook() : Verifie le montant, accept/rollback
cbak() : Non utilise (transactions entrantes)
etat_stocke :
limite : 100 XRP (modifiable par le proprietaire)
compteur_rejets : Nombre de transactions rejetees
taille_wasm : ~2 Ko
cout_installation : ~2 XRP (reserve d'objet)
Cycle de vie d'un Hook :
1. Ecriture en C avec hookapi.h
2. Compilation en WASM (wasmcc)
3. Installation via SetHook transaction
4. Declenchement automatique a chaque transaction
5. Desinstallation via SetHook (wasm vide)
Interpretation : anatomie d’un Hook
Résultat obtenu : Le Hook affiche une structure complete avec fonctions hook() et cbak(), un etat persistant et un cycle de vie en 5 étapes.
Composant
Rôle
Equivalent Ethereum
hook()
Intercepte les transactions sortantes
Fallback function
cbak()
Intercepte les transactions entrantes
Event listener
Hook State
Stockage key-value (32 bytes)
Contract storage
accept() / rollback()
Valide ou rejette la transaction
revert() / return
Points cles : - Le Hook est compile en WASM (~2 Ko), ce qui le rend déterministe et rapide a executer - Le cout d’installation (~2 XRP) est une reserve, pas un frais perdu - Contrairement a un smart contract Ethereum, un Hook n’a pas d’adresse propre : il est attache au compte existant
Comparaison : Hooks vs Smart Contracts Ethereum
Aspect
Smart Contract Ethereum
Hook XRPL
Deploiement
Adresse propre
Attache a un compte existant
Appel
Explicite (tx vers le contrat)
Implicite (toute tx du compte)
Turing-complet
Oui
Non (pas de boucles infinies)
Composabilite
Appels inter-contrats
Limitee (emit)
Maturite
Production depuis 2015
En cours de deploiement
Les Hooks ne remplacent pas les smart contracts Ethereum pour les cas d’usage complexes (DeFi avancee, NFT), mais ils couvrent efficacement les scénarios lies aux paiements : limites, compliance, routage automatique.
6. Exercice : scénario de paiement cross-currency
Implementez un scénario complet de paiement cross-currency sur le XRPL Testnet :
Créer 3 wallets (Alice, Bob, Gateway)
Gateway etablit des trust lines pour EUR et USD
Alice et Bob etablissent des trust lines vers Gateway
Gateway emet des EUR a Alice et des USD a Bob
Alice paie Bob en EUR, qui arrive en USD (via le DEX)
Ce scénario illustre le cas d’usage principal du XRPL : le paiement transfrontalier avec conversion automatique de devises.
Transition : de la théorie a la pratique
Les sections précédentes ont couvert les mécanismes fondamentaux du XRPL : consensus UNL, transactions natives, trust lines, DEX, payment channels et Hooks. L’exercice suivant combine plusieurs de ces primitives dans un scénario realiste de paiement transfrontalier, cas d’usage historique du protocole Ripple.
# Exercice : Paiement cross-currency via trust lines et DEXimport xrplfrom xrpl.asyncio.clients import AsyncJsonRpcClientfrom xrpl.asyncio.wallet import generate_faucet_walletfrom xrpl.asyncio.transaction import submit_and_waitfrom xrpl.models.transactions import TrustSet, Payment, OfferCreatefrom xrpl.models.amounts import IssuedCurrencyAmountfrom xrpl.utils import xrp_to_drops# API asyncio : dans ce kernel Jupyter, chaque appel reseau se fait avec `await`.def cross_currency_scenario(client):"""Scenario complet de paiement cross-currency. Etapes : 1. Creer 3 wallets via le faucet (Alice, Bob, Gateway) 2. Gateway cree des trust lines EUR et USD 3. Alice etablit une trust line EUR vers Gateway 4. Bob etablit une trust line USD vers Gateway 5. Gateway emet 500 EUR a Alice (Payment IOU) 6. Gateway emet 500 USD a Bob (Payment IOU) 7. Creer un offer EUR/USD sur le DEX pour etablir un taux 8. Alice envoie 100 EUR a Bob, qui arrive en ~110 USD (utiliser SendMax et DeliverMin pour le cross-currency) 9. Afficher les soldes finaux de tous les comptes Returns: dict: Soldes finaux de chaque participant """# TODO : Implementer le scenario completpass# TODO: Completez cet exerciceprint("Exercice a completer")
Exercice a completer
Indice : paiement cross-currency
Pour realiser ce scénario, vous aurez besoin des transactions suivantes dans l’ordre :
generate_faucet_wallet() pour créer les 3 wallets
TrustSet pour etablir les trust lines EUR et USD vers Gateway
Payment avec IssuedCurrencyAmount pour emettre les IOU
OfferCreate pour créer un taux de change EUR/USD sur le DEX
Payment avec SendMax et DeliverMin pour le paiement cross-currency
Consultez la documentation xrpl.models.transactions pour les paramètres exacts de chaque transaction.
7. Resume
Fonctionnalite
Mécanisme XRPL
Equivalent Ethereum
Consensus
UNL (3-5 sec, déterministe)
PoS Casper (~12 sec)
Tokens
Trust Lines natives
Smart contract ERC-20
DEX
Order book integre au protocole
Uniswap/smart contract
Micropaiements
Payment Channels natifs
State channels (complexe)
Smart Contracts
Hooks (C/WASM)
Solidity/EVM
Escrow
Natif (time-lock, conditions)
Smart contract Escrow
Frais
~0.000012 XRP (~$0.00001)
Variable (gas, congestion)
Points cles
Le XRPL est optimise pour les paiements : rapide, peu couteux, déterministe
Les fonctionnalites financieres sont natives au protocole, pas dans des smart contracts
Les trust lines permettent la creation de tokens (IOU) sans deployer de code
Le DEX integre offre un echange decentralise sans intermediaire logiciel
Les Hooks (C/WASM) ajoutent la programmabilite manquante au XRPL
Le consensus UNL sacrifie un peu de decentralisation pour la performance
Ce notebook a permis de decouvrir l’ecosysteme Ripple/XRP, une blockchain concue pour les paiements transfrontaliers rapides et peu couteux. Nous avons explore le consensus UNL (3-5 secondes, finalite déterministe), manipule les comptes et transactions via xrpl-py, et compris les mécanismes natifs des trust lines (système de credit IOU), du DEX integre (carnet d’ordres on-chain avec auto-bridging) et des payment channels (micropaiements off-chain instantanes). Les Hooks, equivalents des smart contracts en C/WASM, completent l’architecture en ajoutant la programmabilite manquante.
La philosophie du XRPL contraste avec celle d’Ethereum : les primitives financieres sont integrees au protocole plutot qu’implementees dans des smart contracts. Ce choix architectural privilegie la performance (1500 TPS, frais negligeables) au depens de la flexibilite (impossible de créer de nouvelles primitives sans modifier le protocole). Les Hooks representent un compromis evolutif, permettant une logique programmable attachee aux comptes tout en conservant le modèle déterministe du XRPL.
Le prochain notebook explore le modèle UTXO et le langage Script de Bitcoin, une approche encore plus minimaliste ou les smart contracts se limitent a des conditions de depense sur une pile, sans aucune machine virtuelle. Cette progression illustre le spectre complet entre computation expressive et verification déterministe : SC-20-Bitcoin-Scripting-Python.