@empereur-rouge/pms-sdk 0.3.8 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,118 +1,3 @@
1
- /**
2
- * PmsWallet - Wallet pour le réseau PMS.
3
- *
4
- * Supporte:
5
- * - Génération de wallet avec mnémonique 24 mots (BIP39)
6
- * - Import depuis clé privée
7
- * - Signature de messages
8
- * - Export de la phrase mnémonique
9
- *
10
- * @example
11
- * ```typescript
12
- * // Générer un nouveau wallet
13
- * const wallet = PmsWallet.generate();
14
- * console.log(wallet.mnemonic); // 24 mots
15
- *
16
- * // Restaurer depuis mnemonic
17
- * const wallet2 = PmsWallet.fromMnemonic("word1 word2 ...");
18
- *
19
- * // Signer un message
20
- * const sig = await wallet.sign(messageBytes);
21
- * ```
22
- */
23
- /**
24
- * Wallet PMS avec gestion des clés cryptographiques.
25
- */
26
- declare class PmsWallet {
27
- /** Clé privée secp256k1 (32 bytes) - pour signatures */
28
- private readonly _privateKey;
29
- /** Clé publique secp256k1 non compressée (65 bytes: 04 + x + y) */
30
- private readonly _publicKey;
31
- /** Clé privée X25519 (32 bytes) - pour chiffrement */
32
- private readonly _x25519PrivateKey;
33
- /** Clé publique X25519 (32 bytes) */
34
- private readonly _x25519PublicKey;
35
- /** Phrase mnémonique (24 mots) si générée/importée */
36
- private readonly _mnemonic?;
37
- /**
38
- * Constructeur privé - utiliser les méthodes statiques.
39
- */
40
- private constructor();
41
- /**
42
- * Génère un nouveau wallet avec une phrase de 24 mots.
43
- */
44
- static generate(): PmsWallet;
45
- /**
46
- * Crée un wallet à partir d'une phrase mnémonique (12, 15, 18, 21 ou 24 mots).
47
- * @throws Error si la phrase est invalide
48
- */
49
- static fromMnemonic(mnemonic: string): PmsWallet;
50
- /**
51
- * Crée un wallet à partir d'une clé privée hexadécimale.
52
- */
53
- static fromPrivateKey(privateKeyHex: string): PmsWallet;
54
- /**
55
- * Crée un wallet à partir d'une seed (32 bytes).
56
- */
57
- static fromSeed(seed: Uint8Array): PmsWallet;
58
- /**
59
- * Adresse du wallet (clé publique hex).
60
- * Format: "04" + 64 bytes hex = 130 caractères
61
- */
62
- get address(): string;
63
- /**
64
- * Clé publique en bytes.
65
- */
66
- get publicKey(): Uint8Array;
67
- /**
68
- * Clé publique en hex.
69
- */
70
- get publicKeyHex(): string;
71
- /**
72
- * Phrase mnémonique (si disponible).
73
- * @returns undefined si le wallet a été créé depuis une clé privée
74
- */
75
- get mnemonic(): string | undefined;
76
- /**
77
- * Clé publique X25519 en hex (pour chiffrement).
78
- * Utiliser cette clé comme destinataire pour encryptPayload().
79
- */
80
- get x25519PublicKeyHex(): string;
81
- /**
82
- * Clé privée X25519 en hex (pour déchiffrement).
83
- * ⚠️ Ne pas exposer cette clé publiquement !
84
- */
85
- get x25519PrivateKeyHex(): string;
86
- /**
87
- * Signe un message avec la clé privée.
88
- * @param message - Message à signer (sera hashé avec SHA256)
89
- * @returns Signature DER encodée en hex
90
- */
91
- sign(message: Uint8Array): string;
92
- /**
93
- * Signe un message déjà hashé.
94
- * @param hash - Hash 32 bytes du message
95
- * @returns Signature DER encodée en hex
96
- */
97
- signHash(hash: Uint8Array): string;
98
- /**
99
- * Exporte la clé privée en hex.
100
- * ⚠️ À utiliser avec précaution !
101
- */
102
- exportPrivateKey(): string;
103
- /**
104
- * Vérifie une signature.
105
- * @param message - Message original
106
- * @param signature - Signature DER hex
107
- * @param publicKeyHex - Clé publique hex du signataire
108
- */
109
- static verify(message: Uint8Array, signature: string, publicKeyHex: string): boolean;
110
- }
111
- /**
112
- * Vérifie si une phrase mnémonique est valide.
113
- */
114
- declare function isValidMnemonic(mnemonic: string): boolean;
115
-
116
1
  /**
117
2
  * Types TypeScript pour le SDK PMS.
118
3
  *
@@ -125,6 +10,27 @@ interface OutputRef {
125
10
  /** Index de l'output dans la transaction */
126
11
  index: number;
127
12
  }
13
+ /**
14
+ * Condition de déverrouillage d'un output (protocole 2.2, dag-pms v0.10.0).
15
+ *
16
+ * Sérialisation serde externally-tagged :
17
+ * - variant unit → string JSON `"PubKey"` ;
18
+ * - variants à données → `{ "MultiSig": {...} }` / `{ "HashLock": {...} }`.
19
+ *
20
+ * La condition est figée À LA CRÉATION de l'output. Au spend, le validateur
21
+ * lit la condition depuis l'UTXO STOCKÉ (jamais depuis les données du
22
+ * dépensier).
23
+ */
24
+ type SpendCondition = "PubKey" | {
25
+ MultiSig: {
26
+ m: number;
27
+ pubkeys: string[];
28
+ };
29
+ } | {
30
+ HashLock: {
31
+ hash_hex: string;
32
+ };
33
+ };
128
34
  /** Output de transaction (UTXO) */
129
35
  interface TxOutput {
130
36
  /** Adresse du destinataire */
@@ -133,6 +39,26 @@ interface TxOutput {
133
39
  amount: string;
134
40
  /** Asset ID (undefined/null = PMS natif, "edenite" = token custom) */
135
41
  asset_id?: string;
42
+ /**
43
+ * Time-lock natif (protocole 2.1) : timestamp UNIX **millisecondes**
44
+ * avant lequel l'output est indépensable. Absent = dépensable
45
+ * immédiatement. Entre dans le message signé quand présent.
46
+ */
47
+ locked_until?: number;
48
+ /**
49
+ * Condition de déverrouillage (protocole 2.2). Absent = PubKey simple
50
+ * (binding pubkey↔adresse classique). Pour MultiSig, `address` DOIT être
51
+ * l'adresse canonique de la policy — voir [`multisigAddress`].
52
+ */
53
+ spend_condition?: SpendCondition;
54
+ /**
55
+ * Timestamp de création de l'UTXO (UNIX ms), **assigné par le moteur**
56
+ * au persist — base du calcul de demurrage (protocole 2.5).
57
+ * NE JAMAIS poser ce champ côté client : toute valeur fournie est
58
+ * écrasée par le serveur, et le poser modifie inutilement le message
59
+ * signé. Présent en LECTURE seulement (GET /v1/wallet/{addr}/utxos).
60
+ */
61
+ created_at?: number;
136
62
  }
137
63
  /** UTXO complet avec sa référence */
138
64
  interface Utxo extends TxOutput {
@@ -144,12 +70,31 @@ interface TxInput {
144
70
  /** Référence à l'UTXO dépensé */
145
71
  out: OutputRef;
146
72
  }
73
+ /** Signature additionnelle d'un cosignataire MultiSig (protocole 2.2). */
74
+ interface Cosigner {
75
+ /** Clé publique hex (membre du set MultiSig) */
76
+ pubkey_hex: string;
77
+ /** Signature DER base64 du MÊME message canonique que l'unlock principal */
78
+ signature_b64: string;
79
+ }
147
80
  /** Unlock (signature pour un input) */
148
81
  interface Unlock {
149
82
  /** Clé publique hex */
150
83
  pubkey_hex: string;
151
84
  /** Signature base64 */
152
85
  signature_b64: string;
86
+ /**
87
+ * Cosignatures pour un input sous condition MultiSig : la paire
88
+ * principale compte comme première signature, les cosigners complètent
89
+ * jusqu'à M. Chaque signature porte sur le même message canonique.
90
+ * Les unlocks n'entrent PAS dans le message signé.
91
+ */
92
+ cosigners?: Cosigner[];
93
+ /**
94
+ * Préimage hex pour un input sous condition HashLock :
95
+ * `sha256(bytes(preimage_hex)) == hash_hex` de la condition.
96
+ */
97
+ preimage_hex?: string;
153
98
  }
154
99
  /** Transaction UTXO */
155
100
  interface TxUtxo {
@@ -168,8 +113,14 @@ type PayloadEnvelope = {
168
113
  } | {
169
114
  Encrypted: EncryptedPayload;
170
115
  };
171
- /** Payload en clair */
172
- type PlainPayload = {
116
+ /**
117
+ * Payload en clair.
118
+ *
119
+ * Sérialisation serde externally-tagged : variant unit → string JSON
120
+ * (`"Genesis"`), variant avec données → objet à clé unique
121
+ * (`{"TxUtxo": {...}}`).
122
+ */
123
+ type PlainPayload = "Genesis" | {
173
124
  Mint: MintPayload;
174
125
  } | {
175
126
  TxUtxo: TxUtxo;
@@ -312,8 +263,35 @@ interface TokenMetadata {
312
263
  creator: string;
313
264
  /** Clé publique autorisée à mint ce token */
314
265
  mint_authority: string;
266
+ /**
267
+ * Demurrage opt-in (protocole 2.5) : décote en basis points par JOUR
268
+ * PLEIN écoulé depuis `created_at` de chaque UTXO. Absent/0 = pas de
269
+ * demurrage. Voir [`effectiveValue`] pour le calcul côté client.
270
+ */
271
+ demurrage_bps_per_day?: number;
272
+ /**
273
+ * Mint collatéralisé (protocole 2.3 v2, dag-pms v0.11.0) : adresse de
274
+ * réserve sur le même ledger. Chaque mint exige
275
+ * `(circulation + minté) × collateral_ratio_bps / 10000` couvert par
276
+ * les UTXOs de réserve ENCORE time-lockés à cette adresse.
277
+ */
278
+ collateral_address?: string;
279
+ /** Asset du collatéral (absent = natif du ledger). */
280
+ collateral_asset_id?: string;
281
+ /** Ratio de couverture en bps (10000 = 1:1). Présent ssi collateral_address. */
282
+ collateral_ratio_bps?: number;
315
283
  }
316
- /** Mise à jour de configuration */
284
+ /**
285
+ * Mise à jour de configuration.
286
+ *
287
+ * Sérialisation serde externally-tagged côté moteur : chaque variant est un
288
+ * objet à clé unique (`{ "SetFeeRate": { "bps": 300 } }`). Les noms de
289
+ * variants sont en PascalCase, les champs en snake_case.
290
+ *
291
+ * Selon le sens du changement (durcissement vs assouplissement), le moteur
292
+ * applique la mise à jour instantanément (200) ou la place sous timelock de
293
+ * gouvernance (202) — voir [`PmsClient.setConfig`] / [`ConfigChangeResult`].
294
+ */
317
295
  type ConfigUpdate = {
318
296
  SetFeeRate: {
319
297
  bps: number;
@@ -334,7 +312,156 @@ type ConfigUpdate = {
334
312
  SetMintEnabled: {
335
313
  enabled: boolean;
336
314
  };
315
+ } | {
316
+ /**
317
+ * Couloir d'émission (plan §3, dag-pms v0.18.0). Tous les champs
318
+ * sont REQUIS et en basis points (sauf la durée d'epoch en
319
+ * secondes). Élargir le couloir (hausser le plafond / la cible) est
320
+ * un assouplissement → timelocké ; le resserrer est un durcissement
321
+ * → instantané.
322
+ */
323
+ SetEmissionCorridor: {
324
+ /** Plafond d'émission par epoch (bps). */
325
+ ceiling_bps: number;
326
+ /** Plancher d'émission par epoch (bps). */
327
+ floor_bps: number;
328
+ /** Cible d'émission par epoch (bps). */
329
+ target_bps: number;
330
+ /** Durée d'une epoch d'émission (secondes). */
331
+ epoch_duration_sec: number;
332
+ };
337
333
  };
334
+ /**
335
+ * Dernier snapshot de preuve de réserves ancré (protocole 2.6).
336
+ * `GET /v1/reserves/latest` — le bloc DAG `block_id` est la preuve signée
337
+ * Coordinator ; `state_root` = SHA-256 de l'état UTXO complet.
338
+ */
339
+ interface ReservesLatest {
340
+ /** ID du bloc ReserveSnapshot ancré dans le DAG */
341
+ block_id: string;
342
+ /** Racine d'état SHA-256 (64 hex chars) du set UTXO */
343
+ state_root: string;
344
+ /** Supply totale par asset : [asset_id | null (natif), montant] */
345
+ total_supply: Array<[string | null, string]>;
346
+ /** Nombre d'UTXOs couverts par le root */
347
+ utxo_count: number;
348
+ /** Horodatage du calcul (UNIX ms) */
349
+ computed_at_ms: number;
350
+ }
351
+ /**
352
+ * Palier de gouvernance d'une proposition.
353
+ *
354
+ * Casse en **minuscules** (`"operator" | "policy" | "constitution"`), cohérente
355
+ * entre requêtes et réponses depuis dag-pms v0.18.1 : le moteur accepte le
356
+ * `tier` en minuscules dans la REQUÊTE `propose` (en plus du PascalCase
357
+ * historique) et le renvoie toujours en minuscules dans les RÉPONSES (propose
358
+ * result, pending, history, blocks) via `GovernanceTier::as_str()`. Un `tier`
359
+ * reçu peut donc être comparé directement (`proposal.tier === "operator"`) sans
360
+ * normalisation de casse.
361
+ */
362
+ type GovernanceTier = "operator" | "policy" | "constitution";
363
+ /**
364
+ * Statut d'une proposition de gouvernance (forme renvoyée par les lectures
365
+ * publiques, en minuscules).
366
+ */
367
+ type GovernanceStatus = "pending" | "enacted" | "cancelled";
368
+ /**
369
+ * Proposition de gouvernance ancrée dans le DAG.
370
+ *
371
+ * Retournée par [`PmsClient.getGovernancePending`] et
372
+ * [`PmsClient.getGovernanceHistory`]. Le champ `update` est le `ConfigUpdate`
373
+ * brut (externally-tagged) que la proposition appliquera à son enactment.
374
+ */
375
+ interface GovernanceProposal {
376
+ /** Identifiant de la proposition (SHA-256 hex). */
377
+ proposal_id: string;
378
+ /** Palier de gouvernance. */
379
+ tier: GovernanceTier;
380
+ /** Statut courant. */
381
+ status: GovernanceStatus;
382
+ /** Raison libre fournie par le proposant (peut être vide). */
383
+ reason: string;
384
+ /** Horodatage de l'annonce (UNIX ms). */
385
+ announced_at_ms: number;
386
+ /** Horodatage à partir duquel l'enactment est autorisé (UNIX ms). */
387
+ enact_after_ms: number;
388
+ /** Mise à jour de config à appliquer. */
389
+ update: ConfigUpdate;
390
+ /** ID du bloc DAG de la proposition. */
391
+ proposal_block_id: string;
392
+ /** ID du bloc d'enactment (null tant que non-enacté). */
393
+ enact_block_id: string | null;
394
+ /** ID du bloc d'annulation (null tant que non-annulé). */
395
+ cancel_block_id: string | null;
396
+ }
397
+ /**
398
+ * Un bloc de gouvernance individuel du DAG (proposition, enactment, ou
399
+ * annulation), tel que retourné par [`PmsClient.getGovernanceBlocks`].
400
+ */
401
+ interface GovernanceBlock {
402
+ /** ID du bloc DAG. */
403
+ block_id: string;
404
+ /** Nature du bloc. */
405
+ kind: "proposal" | "enact" | "cancel";
406
+ /** Identifiant de la proposition à laquelle ce bloc se rattache. */
407
+ proposal_id: string;
408
+ /** Palier de gouvernance. */
409
+ tier: GovernanceTier;
410
+ /** Statut de la proposition au moment du snapshot. */
411
+ status: GovernanceStatus;
412
+ /** Mise à jour de config portée par la proposition. */
413
+ update: ConfigUpdate;
414
+ /** Raison libre. */
415
+ reason: string;
416
+ /** Horodatage de l'annonce (UNIX ms). */
417
+ announced_at_ms: number;
418
+ /** Horodatage d'enactment autorisé (UNIX ms). */
419
+ enact_after_ms: number;
420
+ }
421
+ /**
422
+ * Requête de proposition de gouvernance
423
+ * ([`PmsClient.proposeGovernance`]).
424
+ */
425
+ interface ProposeGovernanceRequest {
426
+ /** Mise à jour de config à proposer. */
427
+ update: ConfigUpdate;
428
+ /** Palier (minuscules — voir [`GovernanceTier`]). */
429
+ tier: GovernanceTier;
430
+ /** Raison libre (optionnelle, défaut côté moteur = chaîne vide). */
431
+ reason?: string;
432
+ }
433
+ /**
434
+ * Résultat de POST /admin/governance/propose.
435
+ *
436
+ * Le `tier` est renvoyé par le moteur en minuscules (voir [`GovernanceTier`]).
437
+ * La même casse est utilisée pour l'envoi de la requête.
438
+ */
439
+ interface ProposeResult {
440
+ /** Statut de l'appel (ex: "ok"). */
441
+ status: string;
442
+ /** Identifiant de la proposition créée (SHA-256 hex). */
443
+ proposal_id: string;
444
+ /** ID du bloc DAG de la proposition. */
445
+ block_id: string;
446
+ /** Palier assigné. */
447
+ tier: GovernanceTier;
448
+ /** Horodatage de l'annonce (UNIX ms). */
449
+ announced_at_ms: number;
450
+ /** Horodatage à partir duquel l'enactment est autorisé (UNIX ms). */
451
+ enact_after_ms: number;
452
+ }
453
+ /**
454
+ * Résultat d'un enactment ou d'une annulation de proposition
455
+ * (POST /admin/governance/enact/{id} et /cancel/{id}).
456
+ */
457
+ interface GovernanceActionResult {
458
+ /** Statut de l'appel (ex: "ok"). */
459
+ status: string;
460
+ /** Identifiant de la proposition concernée. */
461
+ proposal_id: string;
462
+ /** ID du bloc DAG d'enactment/annulation. */
463
+ block_id: string;
464
+ }
338
465
  /** Bloc du DAG */
339
466
  interface Block {
340
467
  /** ID unique du bloc (hash) */
@@ -440,13 +567,24 @@ interface UtxoDetail {
440
567
  interface PrepareTxResponse {
441
568
  /** Transaction non-signée (unlocks vide) */
442
569
  unsigned_tx: TxUtxo;
443
- /** Hash SHA256 du message à signer (hex) */
570
+ /** Hash SHA256 du message canonique à signer (hex) */
444
571
  tx_hash: string;
445
- /** Frais calculés */
572
+ /** Frais de gas PMS calculés */
446
573
  fee: string;
574
+ /** Frais de transfert smart contract ("0" si aucun contrat actif) */
575
+ transfer_fee: string;
447
576
  /** Détail des UTXOs sélectionnés */
448
577
  inputs_detail: UtxoDetail[];
449
578
  }
579
+ /** Réponse de POST /v1/wallet/tx/send */
580
+ interface SendTxResponse {
581
+ /** ID du bloc forgé et signé par le serveur (single-writer) */
582
+ id: string;
583
+ /** Statut: "inserted" (201) ou "duplicate" (409) */
584
+ status: string;
585
+ /** Alias de `id` pour compatibilité avec l'ancien SubmitResponse */
586
+ block_id: string;
587
+ }
450
588
  /** Réponse de getNft - informations complètes d'un NFT */
451
589
  interface NftResponse {
452
590
  /** Token ID du NFT */
@@ -518,11 +656,24 @@ interface PmsClientConfig {
518
656
  * Exemple: "pk_live_abc123..." ou "pk_test_xyz789..."
519
657
  */
520
658
  apiKey: string;
659
+ /**
660
+ * Jeton d'administration (optionnel).
661
+ *
662
+ * Requis UNIQUEMENT pour les méthodes admin (gouvernance propose/enact/
663
+ * cancel, [`PmsClient.setConfig`]). Envoyé dans l'en-tête
664
+ * `Authorization: Bearer <adminToken>`. Les lectures publiques (y compris
665
+ * de gouvernance) n'en ont PAS besoin. Si une méthode admin est appelée
666
+ * sans `adminToken`, le client lève une erreur explicite avant tout appel
667
+ * réseau.
668
+ *
669
+ * NE JAMAIS committer ce jeton ni l'exposer côté navigateur.
670
+ */
671
+ adminToken?: string;
521
672
  /** URLs des noeuds seeds (optionnel, pour racing et fallback) */
522
673
  seedNodes?: string[];
523
674
  /** ID du réseau (défaut: "pms-mainnet") */
524
675
  networkId?: string;
525
- /** Version du protocole (défaut: 1) */
676
+ /** Version du protocole P2P (défaut: 3 — dag-pms v0.10.0) */
526
677
  protocolVersion?: number;
527
678
  /** Timeout en ms (défaut: 30000) */
528
679
  timeout?: number;
@@ -654,6 +805,238 @@ interface RuntimeConfig {
654
805
  interface NodePublicConfig extends RuntimeConfig {
655
806
  fee_recipient: string;
656
807
  }
808
+ /**
809
+ * Résultat de POST /admin/config — union discriminée sur `applied`.
810
+ *
811
+ * Le moteur distingue deux issues selon le SENS de la mise à jour :
812
+ * - **durcissement** (tighten, ex: réduire un plafond, désactiver le mint) :
813
+ * appliqué INSTANTANÉMENT — HTTP 200, `status: "applied"`. → `applied: true`.
814
+ * - **assouplissement** (loosen, ex: hausser un plafond, réactiver le mint) :
815
+ * placé sous TIMELOCK de gouvernance, PAS encore appliqué — HTTP 202,
816
+ * `status: "proposed"`. → `applied: false`. Le changement s'auto-enacte
817
+ * quand le timelock expire, ou via [`PmsClient.enactProposal`].
818
+ *
819
+ * Le SDK NE traite JAMAIS un 202 comme un succès appliqué : inspectez
820
+ * `result.applied` avant de supposer que le changement est en vigueur.
821
+ */
822
+ type ConfigChangeResult = ConfigChangeApplied | ConfigChangeProposed;
823
+ /** Variante "appliqué instantanément" (HTTP 200). */
824
+ interface ConfigChangeApplied {
825
+ /** Discriminant : le changement est en vigueur. */
826
+ applied: true;
827
+ /** Statut moteur (toujours "applied" pour cette variante). */
828
+ status: "applied";
829
+ /** Mode lisible (ex: "instant (tighten)"). */
830
+ mode: string;
831
+ /** Description lisible de la mise à jour appliquée. */
832
+ updateApplied: string;
833
+ /** Palier de gouvernance déduit (minuscules côté moteur). */
834
+ tier: string;
835
+ /** Identifiant de la proposition implicite. */
836
+ proposalId: string;
837
+ /** ID du bloc DAG de proposition. */
838
+ proposalBlockId: string;
839
+ /** ID du bloc DAG d'enactment (immédiat). */
840
+ enactBlockId: string;
841
+ /** Config runtime résultante (null si lecture impossible côté moteur). */
842
+ config: RuntimeConfig | null;
843
+ }
844
+ /** Variante "proposé, timelocké" (HTTP 202). */
845
+ interface ConfigChangeProposed {
846
+ /** Discriminant : le changement n'est PAS encore en vigueur. */
847
+ applied: false;
848
+ /** Statut moteur (toujours "proposed" pour cette variante). */
849
+ status: "proposed";
850
+ /** Mode lisible (ex: "timelocked (loosen)"). */
851
+ mode: string;
852
+ /** Description lisible de la mise à jour proposée. */
853
+ update: string;
854
+ /** Palier de gouvernance déduit (minuscules côté moteur). */
855
+ tier: string;
856
+ /** Identifiant de la proposition créée. */
857
+ proposalId: string;
858
+ /** ID du bloc DAG de proposition. */
859
+ proposalBlockId: string;
860
+ /** Horodatage de l'annonce (UNIX ms). */
861
+ announcedAtMs: number;
862
+ /** Horodatage à partir duquel l'enactment est autorisé (UNIX ms). */
863
+ enactAfterMs: number;
864
+ /** Message explicatif du moteur. */
865
+ message: string;
866
+ }
867
+ /**
868
+ * Codes d'erreur numériques stables renvoyés par le moteur PMS.
869
+ *
870
+ * Le moteur renvoie ses erreurs au format JSON `{"code": NNNN, "message":
871
+ * "..."}`. Les clients DOIVENT brancher sur le `code` numérique (stable) et
872
+ * non sur le `message` (susceptible de changer de formulation).
873
+ *
874
+ * Tranches : `1xxx` auth/authz, `2xxx` validation requête, `3xxx`
875
+ * état/business, `4xxx` crypto/sécurité, `5xxx` ressource/quota, `9xxx`
876
+ * interne.
877
+ *
878
+ * Le code est exposé sur l'erreur levée via la propriété `code` (voir
879
+ * [`PmsError`]).
880
+ */
881
+ declare const ErrorCode: {
882
+ /** En-tête d'authentification manquant (admin requis). */
883
+ readonly MissingAuth: 1001;
884
+ /** Jeton d'authentification invalide. */
885
+ readonly InvalidAuth: 1002;
886
+ /**
887
+ * Proposition de gouvernance rejetée (timelock non écoulé, proposition
888
+ * non en attente, ou identifiant inconnu). HTTP 409.
889
+ */
890
+ readonly GovernanceRejected: 3071;
891
+ /** Émission native (mint) désactivée. HTTP 503. */
892
+ readonly MintDisabled: 5031;
893
+ /** Erreur interne générique (dette : handler non encore migré). */
894
+ readonly Internal: 9999;
895
+ };
896
+ /** Valeur numérique d'un code d'erreur ([`ErrorCode`]). */
897
+ type ErrorCodeValue = (typeof ErrorCode)[keyof typeof ErrorCode];
898
+
899
+ /**
900
+ * PmsWallet - Wallet pour le réseau PMS.
901
+ *
902
+ * Supporte:
903
+ * - Génération de wallet avec mnémonique 24 mots (BIP39)
904
+ * - Import depuis clé privée
905
+ * - Signature de messages
906
+ * - Export de la phrase mnémonique
907
+ *
908
+ * @example
909
+ * ```typescript
910
+ * // Générer un nouveau wallet
911
+ * const wallet = PmsWallet.generate();
912
+ * console.log(wallet.mnemonic); // 24 mots
913
+ *
914
+ * // Restaurer depuis mnemonic
915
+ * const wallet2 = PmsWallet.fromMnemonic("word1 word2 ...");
916
+ *
917
+ * // Signer un message
918
+ * const sig = await wallet.sign(messageBytes);
919
+ * ```
920
+ */
921
+
922
+ /**
923
+ * Wallet PMS avec gestion des clés cryptographiques.
924
+ */
925
+ declare class PmsWallet {
926
+ /** Clé privée secp256k1 (32 bytes) - pour signatures */
927
+ private readonly _privateKey;
928
+ /** Clé publique secp256k1 non compressée (65 bytes: 04 + x + y) */
929
+ private readonly _publicKey;
930
+ /** Clé privée X25519 (32 bytes) - pour chiffrement */
931
+ private readonly _x25519PrivateKey;
932
+ /** Clé publique X25519 (32 bytes) */
933
+ private readonly _x25519PublicKey;
934
+ /** Phrase mnémonique (24 mots) si générée/importée */
935
+ private readonly _mnemonic?;
936
+ /**
937
+ * Constructeur privé - utiliser les méthodes statiques.
938
+ */
939
+ private constructor();
940
+ /**
941
+ * Génère un nouveau wallet avec une phrase de 24 mots.
942
+ */
943
+ static generate(): PmsWallet;
944
+ /**
945
+ * Crée un wallet à partir d'une phrase mnémonique (12, 15, 18, 21 ou 24 mots).
946
+ * @throws Error si la phrase est invalide
947
+ */
948
+ static fromMnemonic(mnemonic: string): PmsWallet;
949
+ /**
950
+ * Crée un wallet à partir d'une clé privée hexadécimale.
951
+ */
952
+ static fromPrivateKey(privateKeyHex: string): PmsWallet;
953
+ /**
954
+ * Crée un wallet à partir d'une seed (32 bytes).
955
+ */
956
+ static fromSeed(seed: Uint8Array): PmsWallet;
957
+ /**
958
+ * Adresse du wallet (clé publique hex).
959
+ * Format: "04" + 64 bytes hex = 130 caractères
960
+ */
961
+ get address(): string;
962
+ /**
963
+ * Clé publique en bytes.
964
+ */
965
+ get publicKey(): Uint8Array;
966
+ /**
967
+ * Clé publique en hex.
968
+ */
969
+ get publicKeyHex(): string;
970
+ /**
971
+ * Phrase mnémonique (si disponible).
972
+ * @returns undefined si le wallet a été créé depuis une clé privée
973
+ */
974
+ get mnemonic(): string | undefined;
975
+ /**
976
+ * Clé publique X25519 en hex (pour chiffrement).
977
+ * Utiliser cette clé comme destinataire pour encryptPayload().
978
+ */
979
+ get x25519PublicKeyHex(): string;
980
+ /**
981
+ * Clé privée X25519 en hex (pour déchiffrement).
982
+ * ⚠️ Ne pas exposer cette clé publiquement !
983
+ */
984
+ get x25519PrivateKeyHex(): string;
985
+ /**
986
+ * Signe un message avec la clé privée.
987
+ * @param message - Message à signer (sera hashé avec SHA256)
988
+ * @returns Signature DER encodée en hex
989
+ */
990
+ sign(message: Uint8Array): string;
991
+ /**
992
+ * Signe un message déjà hashé.
993
+ * @param hash - Hash 32 bytes du message
994
+ * @returns Signature DER encodée en hex
995
+ */
996
+ signHash(hash: Uint8Array): string;
997
+ /**
998
+ * Exporte la clé privée en hex.
999
+ * ⚠️ À utiliser avec précaution !
1000
+ */
1001
+ exportPrivateKey(): string;
1002
+ /**
1003
+ * Vérifie une signature.
1004
+ * @param message - Message original
1005
+ * @param signature - Signature DER hex
1006
+ * @param publicKeyHex - Clé publique hex du signataire
1007
+ */
1008
+ static verify(message: Uint8Array, signature: string, publicKeyHex: string): boolean;
1009
+ }
1010
+ /**
1011
+ * Vérifie si une phrase mnémonique est valide.
1012
+ */
1013
+ declare function isValidMnemonic(mnemonic: string): boolean;
1014
+ /**
1015
+ * Construit l'`Unlock` d'un input pour les conditions de dépense du
1016
+ * protocole v0.10.0 (MultiSig / HashLock).
1017
+ *
1018
+ * - 1 signataire, pas d'options → unlock classique (PubKey / binding C-1).
1019
+ * - Plusieurs signataires (MultiSig M-of-N) : le premier devient la paire
1020
+ * principale, les suivants des `cosigners` — chacun signe le MÊME message
1021
+ * canonique (`txSigningMessage`). Le quorum compte les clés DISTINCTES
1022
+ * membres du set de la condition.
1023
+ * - `preimageHex` (HashLock) : révèle le secret tel que
1024
+ * `sha256(bytes(preimage)) == hash_hex` de la condition.
1025
+ *
1026
+ * @param signers - Wallets signataires (>= 1 ; ordre indifférent pour le quorum)
1027
+ * @param txHashHex - Hash hex retourné par `txSigningMessage(...)`
1028
+ * @param opts - `preimageHex` pour un input HashLock
1029
+ *
1030
+ * @example
1031
+ * ```typescript
1032
+ * const txHash = txSigningMessage(networkId, tx.inputs, tx.outputs, tx.fee);
1033
+ * // dépense d'un UTXO MultiSig 2-of-3 :
1034
+ * tx.unlocks = tx.inputs.map(() => makeUnlock([alice, carol], txHash));
1035
+ * ```
1036
+ */
1037
+ declare function makeUnlock(signers: PmsWallet[], txHashHex: string, opts?: {
1038
+ preimageHex?: string;
1039
+ }): Unlock;
657
1040
 
658
1041
  /**
659
1042
  * PmsClient - Client HTTP pour interagir avec un nœud PMS.
@@ -741,8 +1124,132 @@ declare class PmsClient {
741
1124
  getToken(assetId: string): Promise<TokenMetadata>;
742
1125
  /**
743
1126
  * Récupère les UTXOs d'une adresse.
1127
+ *
1128
+ * Depuis dag-pms v0.10.0, chaque UTXO expose aussi ses contraintes de
1129
+ * dépense : `locked_until` (time-lock), `spend_condition`
1130
+ * (MultiSig/HashLock) et `created_at` (base du demurrage). Utiliser
1131
+ * [`spendableUtxos`] pour exclure les UTXOs encore verrouillés avant
1132
+ * toute sélection de coins côté client.
744
1133
  */
745
1134
  getUtxos(address: string): Promise<Utxo[]>;
1135
+ /**
1136
+ * Dernier snapshot de preuve de réserves ancré (protocole 2.6,
1137
+ * `GET /v1/reserves/latest`). 404 si aucun snapshot n'a encore été ancré.
1138
+ */
1139
+ getLatestReserves(): Promise<ReservesLatest>;
1140
+ /**
1141
+ * Liste les propositions de gouvernance EN ATTENTE (statut `pending`).
1142
+ *
1143
+ * Lecture publique — aucun `adminToken` requis.
1144
+ *
1145
+ * @returns Le tableau des propositions en attente (vide si aucune).
1146
+ *
1147
+ * @example
1148
+ * ```typescript
1149
+ * const pending = await client.getGovernancePending();
1150
+ * for (const p of pending) {
1151
+ * console.log(`${p.proposal_id} enacts after ${new Date(p.enact_after_ms)}`);
1152
+ * }
1153
+ * ```
1154
+ */
1155
+ getGovernancePending(): Promise<GovernanceProposal[]>;
1156
+ /**
1157
+ * Liste les propositions de gouvernance TERMINÉES (enactées ou annulées).
1158
+ *
1159
+ * Lecture publique — aucun `adminToken` requis.
1160
+ *
1161
+ * @returns Le tableau de l'historique des propositions (vide si aucune).
1162
+ */
1163
+ getGovernanceHistory(): Promise<GovernanceProposal[]>;
1164
+ /**
1165
+ * Liste les blocs de gouvernance ancrés dans le DAG (un par proposition,
1166
+ * enactment, ou annulation).
1167
+ *
1168
+ * Lecture publique — aucun `adminToken` requis.
1169
+ *
1170
+ * @returns `{ count, blocks }` — le nombre et la liste des blocs.
1171
+ */
1172
+ getGovernanceBlocks(): Promise<{
1173
+ count: number;
1174
+ blocks: GovernanceBlock[];
1175
+ }>;
1176
+ /**
1177
+ * Soumet une proposition de gouvernance ancrée dans le DAG.
1178
+ *
1179
+ * Méthode ADMIN — requiert `adminToken` dans la config du client
1180
+ * (envoyé en `Authorization: Bearer <adminToken>`). Lève une erreur
1181
+ * explicite avant tout appel réseau si le jeton est absent.
1182
+ *
1183
+ * @param req.update - Mise à jour de config à proposer.
1184
+ * @param req.tier - Palier de gouvernance (minuscules, voir
1185
+ * [`GovernanceTier`]).
1186
+ * @param req.reason - Raison libre (optionnelle).
1187
+ * @returns `{ status, proposal_id, block_id, tier, announced_at_ms,
1188
+ * enact_after_ms }`.
1189
+ *
1190
+ * @example
1191
+ * ```typescript
1192
+ * const res = await client.proposeGovernance({
1193
+ * update: { SetEmissionCorridor: { ceiling_bps: 1500, floor_bps: 0, target_bps: 1000, epoch_duration_sec: 86400 } },
1194
+ * tier: "constitution",
1195
+ * reason: "raise emission ceiling for Q3",
1196
+ * });
1197
+ * console.log(res.proposal_id, "enacts after", new Date(res.enact_after_ms));
1198
+ * ```
1199
+ */
1200
+ proposeGovernance(req: ProposeGovernanceRequest): Promise<ProposeResult>;
1201
+ /**
1202
+ * Enacte une proposition de gouvernance dont le timelock est écoulé.
1203
+ *
1204
+ * Méthode ADMIN — requiert `adminToken`. Le moteur rejette (HTTP 409,
1205
+ * code [`ErrorCode.GovernanceRejected`] = 3071) si le timelock n'est pas
1206
+ * écoulé, si la proposition n'est pas en attente, ou si l'identifiant est
1207
+ * inconnu.
1208
+ *
1209
+ * @param proposalId - Identifiant de la proposition à enacter.
1210
+ * @param reason - Raison libre (optionnelle).
1211
+ * @returns `{ status, proposal_id, block_id }`.
1212
+ */
1213
+ enactProposal(proposalId: string, reason?: string): Promise<GovernanceActionResult>;
1214
+ /**
1215
+ * Annule une proposition de gouvernance en attente.
1216
+ *
1217
+ * Méthode ADMIN — requiert `adminToken`. Rejet HTTP 409 / code 3071 si la
1218
+ * proposition n'est pas en attente ou si l'identifiant est inconnu.
1219
+ *
1220
+ * @param proposalId - Identifiant de la proposition à annuler.
1221
+ * @param reason - Raison libre (optionnelle).
1222
+ * @returns `{ status, proposal_id, block_id }`.
1223
+ */
1224
+ cancelProposal(proposalId: string, reason?: string): Promise<GovernanceActionResult>;
1225
+ /**
1226
+ * Applique (ou propose) une mise à jour de configuration.
1227
+ *
1228
+ * Méthode ADMIN — requiert `adminToken`. Le moteur distingue DEUX issues
1229
+ * selon le sens du changement, et le SDK les EXPOSE explicitement via une
1230
+ * union discriminée sur `applied` — un 202 n'est JAMAIS traité comme un
1231
+ * succès appliqué :
1232
+ * - **HTTP 200** (durcissement) → `{ applied: true, ... }` : la mise à
1233
+ * jour est instantanément en vigueur.
1234
+ * - **HTTP 202** (assouplissement) → `{ applied: false, proposalId,
1235
+ * enactAfterMs, ... }` : la mise à jour est placée sous timelock de
1236
+ * gouvernance, PAS encore appliquée. Elle s'auto-enacte à l'expiration
1237
+ * du timelock, ou via [`enactProposal`].
1238
+ *
1239
+ * @param update - Mise à jour de config (envoyée brute, sans wrapper).
1240
+ * @returns Une [`ConfigChangeResult`] discriminée sur `applied`.
1241
+ *
1242
+ * @example
1243
+ * ```typescript
1244
+ * const r = await client.setConfig({ SetMintEnabled: { enabled: false } });
1245
+ * if (r.applied) {
1246
+ * console.log("appliqué instantanément:", r.updateApplied);
1247
+ * } else {
1248
+ * console.log("timelocké, enact après", new Date(r.enactAfterMs));
1249
+ * }
1250
+ * ```
1251
+ */
1252
+ setConfig(update: ConfigUpdate): Promise<ConfigChangeResult>;
746
1253
  /**
747
1254
  * Crée un nouveau wallet côté serveur (custodial).
748
1255
  * Le serveur génère le wallet et retourne toutes les clés + adresse Bech32.
@@ -957,18 +1464,45 @@ declare class PmsClient {
957
1464
  private refreshNodeList;
958
1465
  /**
959
1466
  * Envoie des tokens à une adresse.
960
- * Construit automatiquement la transaction, la signe et la soumet.
1467
+ *
1468
+ * Flux aligné sur dag-pms v0.9.0 (single-writer + vérification des
1469
+ * signatures de transaction par l'engine) :
1470
+ * 1. `POST /v1/tx/prepare` — le serveur sélectionne les UTXOs et calcule
1471
+ * les frais.
1472
+ * 2. Vérification défensive côté client : l'output destinataire demandé
1473
+ * existe bien, et le `tx_hash` retourné correspond au message canonique
1474
+ * recalculé localement (`txSigningMessage`). On ne signe JAMAIS un hash
1475
+ * opaque non vérifié.
1476
+ * 3. Le wallet signe la TRANSACTION (unlocks) — pas le bloc. C'est le
1477
+ * serveur qui forge et signe le bloc (single-writer enforcement).
1478
+ * 4. `POST /v1/wallet/tx/send` avec la TX signée + les clés X25519 des
1479
+ * destinataires pour le chiffrement du payload.
1480
+ *
1481
+ * @param params.to - Adresse destinataire (Bech32m de préférence)
1482
+ * @param params.amount - Montant décimal (ex: "10.0")
1483
+ * @param params.wallet - Wallet signataire (propriétaire des UTXOs)
1484
+ * @param params.assetId - Asset ID optionnel (undefined = PMS natif)
1485
+ * @returns `{id, status, block_id}` — id du bloc forgé par le serveur
961
1486
  */
962
1487
  send(params: {
963
1488
  to: string;
964
1489
  amount: string;
965
1490
  wallet: PmsWallet;
1491
+ assetId?: string;
966
1492
  memo?: string;
967
- }): Promise<SubmitResponse>;
1493
+ }): Promise<SendTxResponse>;
968
1494
  /**
969
1495
  * Transférer un NFT à un autre propriétaire.
970
1496
  * Prend en charge le re-chiffrement des métadonnées via le coordinateur.
971
1497
  *
1498
+ * @deprecated Cette méthode soumet un WireBlock signé par la clé
1499
+ * utilisateur via `/submit/block`. Depuis dag-pms v0.9.0, l'engine tourne
1500
+ * en mode **single-writer** : tout bloc signé par une clé non-coordinateur
1501
+ * est rejeté. Cette méthode ne fonctionne que sur un réseau SANS
1502
+ * single-writer enforcement. Utilisez les flux server-side
1503
+ * (`/v1/nft/transfer/prepare` + endpoints serveur) qui forgent et signent
1504
+ * le bloc côté coordinateur.
1505
+ *
972
1506
  * @param params - Paramètres du transfert
973
1507
  * @param params.tokenId - Identifiant du NFT
974
1508
  * @param params.to - Adresse du nouveau propriétaire
@@ -991,6 +1525,13 @@ declare class PmsClient {
991
1525
  * un remboursement est calculé selon la formule:
992
1526
  * `(weight * size * density) / 10000` PMS
993
1527
  *
1528
+ * @deprecated Cette méthode poste un WireBlock signé par la clé
1529
+ * utilisateur. Depuis dag-pms v0.9.0, l'engine tourne en mode
1530
+ * **single-writer** : tout bloc signé par une clé non-coordinateur est
1531
+ * rejeté. Cette méthode ne fonctionne que sur un réseau SANS single-writer
1532
+ * enforcement. Le flux supporté est le burn server-side
1533
+ * (`/v1/nft/burn-simple`), où le serveur forge et signe le bloc.
1534
+ *
994
1535
  * @param params - Paramètres du burn
995
1536
  * @param params.tokenId - Identifiant du NFT à brûler
996
1537
  * @param params.wallet - Wallet PMS du propriétaire (doit être l'owner actuel)
@@ -1015,6 +1556,13 @@ declare class PmsClient {
1015
1556
  /**
1016
1557
  * Brûle (détruit) plusieurs NFTs en une seule transaction.
1017
1558
  *
1559
+ * @deprecated Cette méthode poste un WireBlock signé par la clé
1560
+ * utilisateur. Depuis dag-pms v0.9.0, l'engine tourne en mode
1561
+ * **single-writer** : tout bloc signé par une clé non-coordinateur est
1562
+ * rejeté. Cette méthode ne fonctionne que sur un réseau SANS single-writer
1563
+ * enforcement. Le flux supporté est le burn server-side
1564
+ * (`/v1/nft/burn-simple`), où le serveur forge et signe le bloc.
1565
+ *
1018
1566
  * @param params - Paramètres du batch burn
1019
1567
  * @param params.tokenIds - Liste des Identifiants des NFTs à brûler
1020
1568
  * @param params.wallet - Wallet PMS du propriétaire
@@ -1049,15 +1597,101 @@ declare class PmsClient {
1049
1597
  * Utilise crypto.getRandomValues pour la sécurité cryptographique.
1050
1598
  */
1051
1599
  private generateRandomHex;
1600
+ /**
1601
+ * @internal
1602
+ * Garantit qu'un `adminToken` est configuré avant un appel admin.
1603
+ * Lève une erreur claire (sans appel réseau) sinon.
1604
+ */
1605
+ private requireAdminToken;
1606
+ /**
1607
+ * @internal
1608
+ * Effectue un appel admin authentifié (en-tête `Authorization: Bearer`).
1609
+ *
1610
+ * Les écritures admin ne sont PAS idempotentes — pas de retry automatique
1611
+ * (single-attempt via la branche non-idempotente de `fetchUrl`). L'auth est
1612
+ * injectée par appel (pas dans le bloc d'en-têtes partagé de `fetchOnce`)
1613
+ * pour éviter de fuiter le jeton admin vers des nœuds découverts/seeds lors
1614
+ * du racing — cf. `submitBlockRacing`. `method` ne sert qu'au libellé de
1615
+ * l'erreur "jeton manquant".
1616
+ */
1617
+ private fetchAdmin;
1618
+ /**
1619
+ * @internal
1620
+ * Variante d'appel admin qui expose le STATUT HTTP en plus du corps parsé.
1621
+ * Nécessaire pour [`setConfig`], qui doit distinguer 200 (applied) de 202
1622
+ * (proposed) — deux corps de réponse différents pour deux issues. Délègue à
1623
+ * la même primitive `fetchOnceWithStatus` que tous les autres appels, donc
1624
+ * hérite du merge de signal et du tagging d'abort sans duplication.
1625
+ */
1626
+ private fetchAdminWithStatus;
1627
+ /**
1628
+ * @internal
1629
+ * Vérifie la présence du jeton admin (sinon erreur claire, sans réseau) et
1630
+ * injecte l'en-tête `Authorization: Bearer <token>` dans un RequestInit.
1631
+ */
1632
+ private withAdminAuth;
1052
1633
  private fetch;
1053
1634
  /**
1054
1635
  * Single-attempt HTTP request. Throws a tagged error on transient conditions
1055
1636
  * (network failure, per-attempt abort, 5xx) so the retry loop can decide
1056
1637
  * whether to retry. 4xx and other non-2xx are thrown as fatal HttpError.
1638
+ *
1639
+ * Thin wrapper over `fetchOnceWithStatus` that discards the HTTP status —
1640
+ * every caller that only needs the parsed body goes through here.
1057
1641
  */
1058
1642
  private fetchOnce;
1643
+ /**
1644
+ * Single-attempt HTTP request returning BOTH the numeric HTTP status and the
1645
+ * parsed body. The shared fetch primitive: applies the default headers
1646
+ * (`Content-Type`, public `X-API-Key`), merges the caller's signal with the
1647
+ * per-attempt timeout, tags per-attempt aborts as `PerAttemptTimeoutError`
1648
+ * (so the retry loop can act on them), and constructs `HttpError` on non-2xx.
1649
+ *
1650
+ * NOTE: admin `Authorization: Bearer` is NOT injected here — it is added
1651
+ * per-admin-call by `withAdminAuth` so the admin token never leaks to
1652
+ * discovered/seed nodes during `submitBlockRacing`. Only the public,
1653
+ * scoped `X-API-Key` is broadcast.
1654
+ */
1655
+ private fetchOnceWithStatus;
1059
1656
  private fetchUrl;
1060
1657
  }
1658
+ /**
1659
+ * Error type for HTTP non-2xx responses.
1660
+ *
1661
+ * Carries the HTTP status + `Retry-After` header (for the retry loop) AND,
1662
+ * when the engine returns its stable `{"code": NNNN, "message": "..."}` JSON
1663
+ * body, the parsed numeric `code` and engine `message`. Consumers branch on
1664
+ * the stable numeric `code` (see {@link ErrorCode}) rather than the message
1665
+ * string:
1666
+ *
1667
+ * ```typescript
1668
+ * import { ErrorCode } from "@empereur-rouge/pms-sdk";
1669
+ * try {
1670
+ * await client.setConfig({ SetMintEnabled: { enabled: true } });
1671
+ * } catch (e) {
1672
+ * if ((e as any).code === ErrorCode.GovernanceRejected) { ... }
1673
+ * }
1674
+ * ```
1675
+ *
1676
+ * Backward compatible: `.message` keeps the original `HTTP <status> (...)`
1677
+ * format; `.code` is `undefined` when the body was not the `{code,message}`
1678
+ * shape (e.g. plaintext, legacy `{"error":"..."}`).
1679
+ */
1680
+ declare class HttpError extends Error {
1681
+ readonly status: number;
1682
+ readonly retryAfter: string | null;
1683
+ /** Raw response body text (may be empty). */
1684
+ readonly body: string;
1685
+ /** Stable numeric error code parsed from `{code,message}`, if present. */
1686
+ readonly code?: number;
1687
+ /** Engine-provided message from `{code,message}`, if present. */
1688
+ readonly engineMessage?: string;
1689
+ constructor(status: number, message: string, retryAfter: string | null, body?: string);
1690
+ }
1691
+
1692
+ /**
1693
+ * Utilitaires cryptographiques pour le SDK PMS.
1694
+ */
1061
1695
 
1062
1696
  /**
1063
1697
  * Convertit des bytes en hex.
@@ -1067,6 +1701,36 @@ declare function toHex(bytes: Uint8Array): string;
1067
1701
  * Convertit un hex en bytes.
1068
1702
  */
1069
1703
  declare function fromHex(hex: string): Uint8Array;
1704
+ /**
1705
+ * Message canonique de signature de transaction — DOIT matcher
1706
+ * `Transaction::signing_message` du Rust (dag-pms,
1707
+ * crates/pms-types-transaction/src/transaction.rs) :
1708
+ * `hex(SHA256(JSON({network_id, inputs, outputs, fee})))`
1709
+ * Ordre des clés et compacité identiques à serde_json.
1710
+ *
1711
+ * Le `network_id` est inclus dans le message pour empêcher le replay
1712
+ * cross-chain (une TX signée pour le testnet ne valide pas sur mainnet).
1713
+ *
1714
+ * Les inputs/outputs sont re-canonicalisés défensivement :
1715
+ * - `TxInput` → `{out: {txid, index}}` (ordre de clés serde).
1716
+ * - `TxOutput` → `{address, amount[, asset_id][, locked_until]
1717
+ * [, spend_condition][, created_at]}` — l'ORDRE des clés est celui de la
1718
+ * struct Rust et chaque clé optionnelle est OMISE quand undefined/null
1719
+ * (équivalent serde `skip_serializing_if`), jamais sérialisée à `null`.
1720
+ * `created_at` est système : ne le posez jamais côté client (géré ici
1721
+ * uniquement par fidélité de hash si un serveur l'echo).
1722
+ *
1723
+ * La signature côté wallet : `wallet.sign(encodeUtf8(msgHex))` —
1724
+ * `wallet.sign` fait SHA256(message) puis ECDSA, ce qui correspond
1725
+ * exactement au verify Rust (k256 hash la hex-string du message).
1726
+ *
1727
+ * @param networkId - Network ID de la chaîne cible (ex: "pms-testnet-v1")
1728
+ * @param inputs - Inputs de la transaction
1729
+ * @param outputs - Outputs de la transaction
1730
+ * @param fee - Frais (string décimale, ex: "0.1")
1731
+ * @returns Hash hex (64 chars) du message canonique
1732
+ */
1733
+ declare function txSigningMessage(networkId: string, inputs: TxInput[], outputs: TxOutput[], fee: string): string;
1070
1734
  /**
1071
1735
  * Parse un montant décimal en satoshis (8 décimales).
1072
1736
  */
@@ -1075,6 +1739,64 @@ declare function parseAmount(amount: string): bigint;
1075
1739
  * Formate des satoshis en montant décimal.
1076
1740
  */
1077
1741
  declare function formatAmount(sats: bigint): string;
1742
+ /** Millisecondes par jour — base du demurrage (protocole 2.5). */
1743
+ declare const DAY_MS = 86400000;
1744
+ /**
1745
+ * Dérive l'adresse multisig CANONIQUE d'une policy M-of-N (protocole 2.2).
1746
+ *
1747
+ * DOIT matcher `multisig_address` du Rust
1748
+ * (crates/pms-core/src/validations/conditions.rs) :
1749
+ * `"msig1" + hex(SHA256("pms-multisig-v1" || m || n || pk_1 || … || pk_n)[..20])`
1750
+ * où les pubkeys sont normalisées (trim, sans `0x`, lowercase) puis TRIÉES —
1751
+ * ordre et casse de déclaration indifférents.
1752
+ *
1753
+ * Tout output sous condition MultiSig DOIT porter cette adresse, sinon le
1754
+ * moteur rejette la création (`InvalidSpendCondition`).
1755
+ *
1756
+ * @param m - Quorum requis (1..=N)
1757
+ * @param pubkeys - Clés publiques secp256k1 hex des membres (N <= 16)
1758
+ */
1759
+ declare function multisigAddress(m: number, pubkeys: string[]): string;
1760
+ /**
1761
+ * Hash SHA-256 hex d'un préimage HashLock (protocole 2.2).
1762
+ * À poser dans `SpendCondition.HashLock.hash_hex` à la création de l'output ;
1763
+ * le dépensier fournira `hex(preimage)` dans `Unlock.preimage_hex`.
1764
+ *
1765
+ * @param preimage - Le secret, en bytes ou string UTF-8
1766
+ */
1767
+ declare function hashlockHash(preimage: Uint8Array | string): string;
1768
+ /**
1769
+ * Valeur effective d'un UTXO d'un asset à demurrage (protocole 2.5),
1770
+ * **plancher au satoshi** (8 décimales).
1771
+ *
1772
+ * Formule moteur (Rust `effective_value`, Decimal exact) :
1773
+ * `effective = amount − amount × bps × jours_pleins / 10_000` (plancher 0),
1774
+ * `jours_pleins = floor((now − created_at) / 24h)`.
1775
+ *
1776
+ * La conservation moteur est `sum(outputs) <= sum(effective_inputs)` :
1777
+ * arrondir VERS LE BAS au satoshi est donc toujours sûr (le résidu
1778
+ * sub-satoshi est brûlé avec la décote). Retourne le montant maximal
1779
+ * dépensable, en string décimale 8 dp.
1780
+ *
1781
+ * - `createdAtMs` undefined (UTXO pré-v0.10.0) → valeur nominale intacte.
1782
+ * - `bpsPerDay` 0/undefined → valeur nominale intacte.
1783
+ *
1784
+ * @param amount - Montant nominal (string décimale)
1785
+ * @param createdAtMs - `created_at` de l'UTXO (UNIX ms), tel que lu de l'API
1786
+ * @param nowMs - Horloge courante (UNIX ms)
1787
+ * @param bpsPerDay - `TokenMetadata.demurrage_bps_per_day` de l'asset
1788
+ */
1789
+ declare function effectiveValue(amount: string, createdAtMs: number | undefined, nowMs: number, bpsPerDay: number | undefined): string;
1790
+ /**
1791
+ * Filtre les UTXOs dépensables MAINTENANT : exclut ceux dont le time-lock
1792
+ * (`locked_until`, protocole 2.1) est encore dans le futur. Le moteur
1793
+ * rejetterait leur dépense (`OutputTimeLocked`) — à appliquer avant toute
1794
+ * sélection de coins côté client.
1795
+ *
1796
+ * @param utxos - UTXOs tels que retournés par `GET /v1/wallet/{addr}/utxos`
1797
+ * @param nowMs - Horloge courante (défaut: Date.now())
1798
+ */
1799
+ declare function spendableUtxos<T extends Utxo>(utxos: T[], nowMs?: number): T[];
1078
1800
 
1079
1801
  /**
1080
1802
  * Fonctions de chiffrement pour le SDK PMS.
@@ -1105,4 +1827,4 @@ declare function formatAmount(sats: bigint): string;
1105
1827
  */
1106
1828
  declare function decryptPayload(encrypted: EncryptedPayload, recipientPrivateKeyHex: string): string;
1107
1829
 
1108
- export { type ActivityDirection, type ActivityItem, type ActivityOptions, type ActivityResp, type ActivityType, type BalanceInfo, type Block, type BurnNftResponse, type CoordinatorInfoResponse, type CubeAttributes, type HistoryItem, type LedgerInfo, type ListLedgersOptions, type MintCubeResponse, type NftMetadata, type NftResponse, PmsClient, type PmsClientConfig, PmsWallet, type PrepareTxRequest, type PrepareTxResponse, type RuntimeConfig, type StreamActivityOptions, type SubmitResponse, type SupplyInfo, type TokenMetadata, type Utxo, type UtxoDetail, type WalletHistoryResp, type WalletResponse, decryptPayload, formatAmount, fromHex, isValidMnemonic, parseAmount, toHex };
1830
+ export { type ActivityDirection, type ActivityItem, type ActivityOptions, type ActivityResp, type ActivityType, type BalanceInfo, type Block, type BurnNftResponse, type ConfigChangeApplied, type ConfigChangeProposed, type ConfigChangeResult, type ConfigUpdate, type CoordinatorInfoResponse, type Cosigner, type CubeAttributes, DAY_MS, ErrorCode, type ErrorCodeValue, type GovernanceActionResult, type GovernanceBlock, type GovernanceProposal, type GovernanceStatus, type GovernanceTier, type HistoryItem, HttpError, type LedgerInfo, type ListLedgersOptions, type MintCubeResponse, type NftMetadata, type NftResponse, PmsClient, type PmsClientConfig, PmsWallet, type PrepareTxRequest, type PrepareTxResponse, type ProposeGovernanceRequest, type ProposeResult, type ReservesLatest, type RuntimeConfig, type SendTxResponse, type SpendCondition, type StreamActivityOptions, type SubmitResponse, type SupplyInfo, type TokenMetadata, type TxInput, type TxOutput, type TxUtxo, type Unlock, type Utxo, type UtxoDetail, type WalletHistoryResp, type WalletResponse, decryptPayload, effectiveValue, formatAmount, fromHex, hashlockHash, isValidMnemonic, makeUnlock, multisigAddress, parseAmount, spendableUtxos, toHex, txSigningMessage };