Déplacez de la valeur. Déplacez des données. À vos conditions.
Une transaction ZooBC est une enveloppe signée qui contient un petit corps typé. L'enveloppe est identique pour tous les types ; le corps et quelques modificateurs facultatifs déterminent ce qui se passe réellement : un simple envoi, un transfert de jeton, un salaire à déblocage progressif, une transaction sous séquestre, un coup dans une application, un déclencheur planifié. Voici la carte complète.
01Anatomie d'une transaction
Tout est sérialisé en little-endian dans un seul tampon d'octets, puis signé. Les champs bleus constituent l'enveloppe (la même pour tous les types) ; le corps violet est ce qui change selon le type.
Une adresse de compte est constituée d'un type sur 4 octets (LE) + la clé publique : 00000000+32 o ed25519 pour ZBC, 04000000+ETH, 05000000+BTC, et ainsi de suite. Un destinataire absent est écrit avec le type vide 02000000. C'est dans la partie finale message qu'un simple envoi transporte son mémo : le corps d'un SendZBC ne contient que le montant ; le destinataire et le mémo se trouvent dans l'enveloppe.
02Signature
Le type de compte détermine à la fois le préfixe d'adresse et le schéma de signature. On signe l'enveloppe entière (sans le champ signature), précédée de l'étiquette de signature et du hash de genèse. Les trois schémas sont déterministes : un portefeuille de navigateur et le nœud s'accordent donc octet par octet.
ZooBC (ed25519) · type 00000000
// digest, then sign digest = SHA3_256("ZBC-TX" ‖ genesis_hash ‖ txBytes) sig = ed25519(digest, privkey) // 64 bytes
C'est aussi le schéma de Solana, Cardano, Tezos et Polkadot : même clé ed25519, mais préfixe d'adresse et encodage d'affichage différents.
Ethereum (secp256k1) · type 04000000
// recoverable ECDSA, low-s digest = keccak256(SHA3_256("ZBC-TX" ‖ genesis_hash ‖ txBytes)) r,s,v = secp256k1.sign(digest) sig = r ‖ s ‖ (v+27) // 65 bytes
MetaMask peut aussi envoyer son propre RLP signé ; le nœud retrouve l'expéditeur et le convertit en transfert ZBC.
Bitcoin (secp256k1) · type 05000000
// double-sha over the SHA3 payload digest = SHA256d(SHA3_256("ZBC-TX" ‖ genesis_hash ‖ txBytes)) sig = secp256k1.sign(digest) field = [len(2)] ‖ compressedPub(33) ‖ sig
Les frais, en bref
Les frais minimums dépendent de la taille : un taux de base × le coefficient de frais du réseau, plus une composante stockage/durée par octet. Lisez-les en direct depuis https://zoobc.network/api/v1/blockchain/fee-params ou calculez le prix exact d'une tx avec /estimate-fee, afin que le portefeuille ne soit jamais en désaccord avec le nœud, à l'unité atomique près. Le trop-perçu sur un envoi à frais précis est remboursé.
Le condensé lié à la chaîne (version de signature 2)
Depuis la v0.4.0 du nœud, le terme le plus interne est le même dans les trois schémas, car le nœud calcule ce condensé une seule fois et le transmet au schéma de signature choisi par le type de compte.
- "ZBC-TX" correspond à six octets ASCII sans terminateur : 5a 42 43 2d 54 58.
- genesis_hash correspond aux 32 octets bruts du bloc 0 de la chaîne pour laquelle on signe.
Lisez genesis_hash depuis GET /api/v1/node/info ; la même réponse contient signing_version: 2 et signing_tag: "ZBC-TX". Ne le codez jamais en dur : il change à chaque relance d'un réseau de test.
C'est l'intégration du hash de genèse dans le condensé qui rend une signature valide sur un seul et unique réseau : une transaction signée pour une chaîne de test ne peut donc pas être rejouée sur une autre. Signer le SHA3_256(txBytes) nu correspond à la version de signature 1, que le nœud refuse avec :
Invalid transaction signature: legacy unbound digest (signing v1); this chain requires signing v2
03Les trois types de monnaie
Les montants sont toujours exprimés en unités atomiques (1 ZBC = 100 000 000). La seule chose qui change d'une monnaie à l'autre est le champ token_id : la mécanique des mouvements est identique.
① ZBC natif
token_id = 0 partout. La monnaie du gas et des frais, des récompenses de bloc et du staking. Un SendZBC (type 1) est la voie simple.
② Jetons de genèse / de pont
Des actifs externes encapsulés, frappés à la genèse (ZBTC, ZETH, ZSOL…). Ce sont des jetons colorés ordinaires, avec un token_id fixe attribué dans la configuration de genèse : rien de particulier au niveau du protocole.
③ Jetons émis par les utilisateurs
N'importe qui peut en frapper un avec IssueToken (type 10) : symbole, offre, décimales, garantie en ZBC facultative. Son token_id dérive de la tx d'émission. Les mêmes TransferToken / MintToken / BurnToken s'appliquent.
Partout où un corps comporte un token_id (transfert, échange, mise d'application, paiement liquide, déblocage progressif…), passez 0 pour ZBC ou l'identifiant du jeton pour une monnaie colorée. Les jetons garantis peuvent même payer leurs propres frais (option fee_in_token), dont le prix est calculé d'après leur garantie en ZBC.
04Modificateurs : un paiement, de multiples formes
Au-delà des types de base, quatre surcouches de temporisation et de confiance modifient quand et si les fonds arrivent réellement. Ce sont elles qui donnent l'impression d'une surface aussi vaste.
Séquestre
Ajoutez une section de séquestre à l'enveloppe de n'importe quelle tx de valeur (approbateur · commission · délai · instruction). Les fonds sont retenus jusqu'à ce que l'approbateur désigné signe ApprovalEscrow (type 4) pour les libérer ou les rejeter, ou jusqu'à l'expiration du délai. Une transaction conditionnelle par-dessus n'importe quel transfert.
Liquide
LiquidPayment (type 6) : un paiement unique différé sur une période. Le destinataire reçoit le montant total à la fin de la période, ou une part au prorata si l'expéditeur l'interrompt plus tôt avec LiquidPaymentStop (type 262). Court terme (quelques heures), en ZBC ou en jeton.
Planifié / à déblocage progressif
ScheduledTransfer (type 29) : versement par tranches selon un calendrier, en déblocage progressif (fonds pré-bloqués) ou en salaire récurrent (prélevé à chaque période). Cliff, révocation, refus par le destinataire, réattribution. Long terme (de quelques semaines à plusieurs années). Les versements apparaissent comme des mouvements du registre, et non comme de nouvelles tx.
Déclencheur / arrêt
La minuterie légère : CreateTrigger (15) bloque un montant à verser à une hauteur future ; CancelTrigger (16) le rembourse. Pour arrêter les opérations longues : CancelSchedule (30) révocation/refus, LiquidPaymentStop (262).
Ils se combinent. Un salaire mensuel également placé sous séquestre, une attribution à déblocage progressif en jeton coloré : les primitives se composent. (La composition complète récurrent + séquestre figure sur la feuille de route ; toutes les briques sont déjà là.)
05Maintenir les objets de données en vie
Les objets sur la chaîne qui contiennent des données, les jeux de données (profils clé/valeur, chat, formulaires professionnels) et les jetons, paient un loyer pour subsister. « Ajouter des fonds à un objet » signifie recharger son financement de survie.
Jeux de données et fichiers → stockage prépayé
Vous écrivez des données avec SetupAccountDataset (type 3, une paire propriété → valeur) ou stockez un fichier avec DFSCreateFile (8). Chaque bloc facture un loyer de stockage sur le stockage prépayé de votre compte ; quand il est épuisé, l'objet est élagué. Rechargez-le avec AddPrepaidStorage (type 9) : le corps n'est qu'un montant, crédité directement sur votre solde de stockage prépayé. Plus de prépayé = une vie plus longue.
Jetons → financement de la persistance
Un jeton coloré paie lui aussi pour survivre. FinanceToken (type 14) prolonge l'horizon de persistance d'un jeton à partir des frais, ce qui allonge la durée pendant laquelle il reste actif avant que sa garantie inutilisée ne soit rendue à son créateur. Même principe, jeton par jeton.
06Catalogue complet des transactions
Tous les 50 types de transaction, avec la structure exacte de leur corps en little-endian. monnaie = prend en charge token_id · modifiable = accepte une section de séquestre · nouvelle chaîne = niveau consensus (livré avec un lancement de chaîne).