FaRl Language
FaRl (Financial accounting Rule Language) est le langage de script embarqué dans Corren. Conçu pour exprimer les flux financiers clairement, avec sécurité, et validation à la compilation. Chaque script est atomique — si une instruction échoue, rien n'est committé.
Installation
Nécessite Go 1.16+. Buildez depuis les sources :
# Cloner le dépôt git clone https://github.com/amezianechayer/corren cd corren # Builder go build -o corren . sudo mv corren /usr/local/bin/ # Vérifier corren --help
Quick Start
# Terminal 1 — démarrer le serveur corren server start # Terminal 2 — exécuter un script cat > script.farl << EOF transfer [DZD.2 10000] ( from @world to @banque:reserve ) EOF corren run quickstart script.farl 200 {"ok":true} # Vérifier le solde curl http://localhost:3068/quickstart/accounts/@banque:reserve
Configuration
corren config init
Génère le fichier de config à ~/.corren/corren.yaml :
server:
http:
bind_address: 127.0.0.1:3068
storage:
driver: sqlite # sqlite | postgres
dir: ~/.corren/data
sqlite:
db_name: corren
postgres:
conn_string: postgresql://localhost/postgres
CLI Reference
| Commande | Description |
|---|---|
corren server start | Démarre le serveur HTTP sur l'adresse configurée |
corren run <ledger> <file> | Compile et exécute un script FaRl contre un ledger |
corren config init | Crée le fichier de config par défaut |
corren storage init | Initialise le schéma de la base de données |
Vue d'ensemble FaRl
Un script FaRl est une séquence d'instructions séparées par des sauts de ligne. Chaque instruction déplace de l'argent, affiche une valeur, ou définit des métadonnées. L'ensemble du script s'exécute comme une transaction atomique unique.
Types
| Type | Syntaxe | Exemples | Description |
|---|---|---|---|
account | @name | @alice, @users:001 | Adresse de compte. Commence par @. Namespacé avec : |
monetary | [ASSET amount] | [DZD.2 5000], [COIN 100] | Un montant spécifique d'un actif |
asset | ASSET | DZD, COIN, CREDIT | Identifiant d'actif — majuscules uniquement |
portion | N/D ou N% | 85/100, 15% | Fraction entre 0 et 1 exclusive |
number | N | 42, 100 | Entier non signé |
string | "..." | "seller" | Chaîne littérale. Utilisée dans les clés de metadata |
Syntaxe monétaire
# Avec précision — [ASSET.decimals montant] [DZD.2 5000] # Dinar algérien, 2 décimales [EUR.2 10000] # Euro, 2 décimales [USD.2 10000] # Dollar US, 2 décimales [TND.3 5000] # Dinar tunisien, 3 décimales # Sans précision — [ASSET montant] [COIN 100] # Token COIN, pas de décimales # Transférer tout le solde [DZD.2 *] # tout le solde DZD.2
Variables
Les variables sont déclarées en haut du script avant toute instruction. Elles sont injectées sous forme de JSON lors de l'exécution via l'API.
# Déclaration simple var $name: type # Depuis les métadonnées var $name: type = meta($account, "key")
Format JSON des variables
| Type | Format JSON | Exemple |
|---|---|---|
account | string | "@alice" |
monetary | object | {"asset":"DZD.2","amount":5000} |
asset | string | "DZD.2" |
portion | string | "15%" ou "3/20" |
number | integer | 42 |
string | string | "hello" |
transfer
L'instruction transfer déplace un montant monétaire d'une source vers une destination.
transfer <monetary | monetaryAll> ( from <source> to <destination> )
from et to peuvent être dans n'importe quel ordre. Corren suit les changements de solde dans le script — un transfer peut dépenser des fonds reçus par un transfer précédent dans le même script, même si le solde initial en base était 0.Sources
Compte unique
from @alice from $vendeur # variable
Cascade ordonnée
Draine chaque source dans l'ordre jusqu'à atteindre le montant cible :
from { @wallet:ameziane # drainé en premier @credit:ameziane # puis ceci @world # fallback illimité }
Source capée (max)
max [DZD.2 1000] from @alice # Combinable avec cascade from { max [DZD.2 500] from @alice @bob }
Allotment source
from { 60% from @alice 35.5% from @bob 4.5% from @charlie }
Destinations
Compte unique
to @bob to $vendeur # variable
Allotment destination
to { 85/100 to @vendeur:yanis 10/100 to @plateforme:frais 5/100 to @taxes }
Avec remaining
to { 10% to @plateforme 5% to @taxes remaining to @vendeur # reçoit 85% }
Portion dynamique (variable)
var $commission: portion to { $commission to @plateforme remaining to @vendeur }
Règles d'allotment
| Règle | Valide | Invalide |
|---|---|---|
| Portions fixes doivent sommer à 100% (sans remaining) | 50% + 50% | 50% + 30% |
Un seul remaining par allotment | 20% + remaining | remaining + remaining |
| Avec remaining, portions fixes < 100% | 80% + remaining | 100% + remaining |
| Portions variables nécessitent un remaining | $p + remaining | $p + 50% |
@world
@world est un compte intégré spécial représentant la création de monnaie. Il émet des fonds illimités sans vérification de solde — comme une banque centrale.
# ✅ Émettre un montant fixe transfer [DZD.2 10000] ( from @world to @banque:reserve ) # ✅ Fallback dans une cascade from { @wallet @world } # ❌ Impossible de transférer tout depuis @world transfer [DZD.2 *] ( from @world to @bob ) # ❌ Impossible d'utiliser @world dans allotment source from { 50% from @world 50% from @alice }
Metadata (lecture)
Les variables peuvent être résolues depuis les métadonnées de compte à l'exécution via meta(account, "key") :
var $sale: account var $seller: account = meta($sale, "seller") var $commission: portion = meta($seller, "commission_rate") transfer [DZD.2 1000] ( from $sale to { $commission to @plateforme remaining to $seller } )
set metadata
Métadonnées de transaction
# Clé unique set transaction metadata "reference" = "PAY-2026-001" set transaction metadata "amount_dzd" = 5000 # Forme bloc set transaction metadata { "reference" = "PAY-2026-001" "channel" = "mobile" "region" = "alger" }
Métadonnées de compte
set account metadata of @vendeur:yanis key "commission_rate" = 10/100 set account metadata of @vendeur:yanis key "tier" = "gold"
print & fail
print 42 print 10 + 5 - 2 print @alice # Abort immédiat — rollback tout fail
Exemple — Marketplace split
transfer [DZD.2 5000] ( from @client:ameziane to @courses:0587:paiement ) transfer [DZD.2 5000] ( from @courses:0587:paiement to { 90/100 to @chauffeur:yanis 10/100 to @plateforme:frais } ) set transaction metadata "reference" = "COURSE-0587"
Exemple — Source cascade
transfer [DZD.2 3000] ( from { @wallet:ameziane # balance: 1000 → utilisé first @credit:ameziane # balance: 2000 → utilisé next @world # fallback illimité } to @commande:0089 ) # Résultat : 1000 wallet + 2000 credit = 3000
Exemple — Commission dynamique
var $sale: account var $seller: account = meta($sale, "seller") var $rate: portion = meta($seller, "commission_rate") transfer [DZD.2 10000] ( from $sale to { $rate to @plateforme:commission remaining to $seller } )
Exemple — Allotment source
transfer [DZD.2 1000] ( from { 60% from @alice # contribue 600 35% from @bob # contribue 350 5% from @charlie # contribue 50 } to @destinataire )
Exemple — Set metadata
# Définir le taux de commission d'un vendeur set account metadata of @vendeur:yanis key "commission_rate" = 12/100 # Utiliser dans un transfer var $seller: account var $rate: portion = meta($seller, "commission_rate") transfer [DZD.2 5000] ( from @world to { $rate to @plateforme remaining to $seller } )
HTTP API — Exécuter un script
curl -X POST http://localhost:3068/quickstart/script \
-H "Content-Type: application/json" \
-d '{
"plain": "transfer [DZD.2 1000] (\n from @world\n to @alice\n)",
"vars": {}
}'| Champ | Type | Requis | Description |
|---|---|---|---|
plain | string | requis | Le contenu du script FaRl |
vars | object | optionnel | Valeurs des variables comme JSON |
HTTP API — Transactions
| Méthode | Endpoint | Description |
|---|---|---|
| GET | /:ledger/transactions | Lister toutes les transactions. Params: after, account |
| POST | /:ledger/transactions | Créer une transaction manuelle avec des postings explicites |
HTTP API — Accounts
| Méthode | Endpoint | Description |
|---|---|---|
| GET | /:ledger/accounts | Lister tous les comptes. Params: after |
| GET | /:ledger/accounts/:address | Obtenir le solde et infos d'un compte spécifique |