Aller au contenu

PD-52 — Plan d'implémentation

Story : PD-52 — Setup connexion Ethereum L2 (Polygon/Arbitrum) Epic : PD-187 — BLOCKCHAIN Date : 2026-02-12 Auteur : Claude (orchestrateur IA) Étape : 4 — Plan d'implémentation


1. Synthèse du périmètre

Objectif

Livrer une capacité de connexion Ethereum L2 (Polygon/Arbitrum) avec : - Connectivité RPC multi-provider avec failover automatique - Gestion de wallet avec signature secp256k1 (custody modes S1/S2/S3) - Émission et confirmation de transactions sur testnet - Endpoint d'observabilité /health/blockchain

Métriques de succès

  • 13 invariants à respecter
  • 13 critères d'acceptation à satisfaire
  • 14 codes d'erreur à implémenter
  • Couverture tests ≥ 80%

2. Architecture technique

2.1 Vue d'ensemble des modules

┌─────────────────────────────────────────────────────────────────────┐
│                        BlockchainModule                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐      │
│  │ RpcProviderSvc  │  │  CustodyService │  │ TransactionSvc  │      │
│  │                 │  │                 │  │                 │      │
│  │ - Polygon RPC   │  │ - S1 (HSM)      │  │ - Build TX      │      │
│  │ - Arbitrum RPC  │  │ - S2 (KMS)      │  │ - Sign TX       │      │
│  │ - Failover      │  │ - S3 (Hybrid)   │  │ - Send TX       │      │
│  │ - Health check  │  │ - Mode select   │  │ - Confirm TX    │      │
│  └────────┬────────┘  └────────┬────────┘  └────────┬────────┘      │
│           │                    │                    │                │
│           └────────────────────┼────────────────────┘                │
│                                │                                     │
│  ┌─────────────────┐  ┌───────┴───────┐  ┌─────────────────┐        │
│  │  WalletService  │  │ EthersAdapter │  │  HealthService  │        │
│  │                 │  │               │  │                 │        │
│  │ - Address       │  │ - JsonRpc     │  │ - /health/bc    │        │
│  │ - Sign EIP-191  │  │ - Contract    │  │ - Metrics       │        │
│  │ - Verify sig    │  │ - Utils       │  │ - Latency       │        │
│  └─────────────────┘  └───────────────┘  └─────────────────┘        │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

2.2 Dépendances externes

Dépendance Version Usage
ethers ^6.9.0 Librairie Web3 TypeScript
@nestjs/common ^10.x Framework applicatif
@nestjs/config ^3.x Configuration
@aws-sdk/client-kms ^3.x Custody mode S2
@hashicorp/vault-client ^1.x Custody mode S3

2.3 Structure des fichiers

src/modules/blockchain/
├── blockchain.module.ts           # Module NestJS
├── blockchain.config.ts           # Configuration (registerAs)
├── constants/
│   ├── chain-ids.ts               # Chain IDs testnet/mainnet
│   └── error-codes.ts             # 14 codes d'erreur
├── providers/
│   ├── rpc-provider.service.ts    # Gestion RPC + failover
│   ├── rpc-provider.interface.ts  # Types provider
│   └── rpc-health.service.ts      # Health check RPC
├── custody/
│   ├── custody.service.ts         # Orchestration custody modes
│   ├── custody.interface.ts       # Types custody
│   ├── strategies/
│   │   ├── s1-hsm.strategy.ts     # CloudHSM/PKCS#11
│   │   ├── s2-kms.strategy.ts     # AWS KMS
│   │   └── s3-hybrid.strategy.ts  # Hybrid HSM+Vault
│   └── custody.guard.ts           # Validation mode unique
├── wallet/
│   ├── wallet.service.ts          # Signature EIP-191
│   ├── wallet.interface.ts        # Types wallet
│   └── wallet.validator.ts        # Validation adresse
├── transaction/
│   ├── transaction.service.ts     # Build/Sign/Send/Confirm
│   ├── transaction.interface.ts   # Types TX
│   ├── gas-estimator.service.ts   # Estimation gas
│   └── confirmation.tracker.ts    # Suivi confirmations
├── health/
│   ├── blockchain-health.controller.ts  # GET /health/blockchain
│   └── blockchain-health.service.ts     # Métriques
├── validators/
│   ├── payload.validator.ts       # INV-52-08 : validation payload
│   └── chain-id.guard.ts          # INV-52-02 : testnet only
└── dto/
    ├── transaction.dto.ts         # DTO transaction
    └── health.dto.ts              # DTO health response

3. Décisions architecturales

DA-01 : Custody mode initial = S2 (AWS KMS)

Contexte : CloudHSM ne supporte pas nativement secp256k1 (courbe Ethereum).

Décision : Implémenter S2 (AWS KMS avec ECC_SECG_P256K1) pour la v1.

Justification : - AWS KMS supporte secp256k1 nativement - Simplification de l'intégration (SDK AWS) - Sécurité équivalente pour l'usage testnet - S1 (HSM) et S3 (hybrid) seront implémentés en parallèle mais S2 sera le mode par défaut

Alternative rejetée : S1 (HSM) nécessiterait un développement complexe pour la dérivation de clé.

Comportement des stubs S1/S3 (ECT-PLAN-01) : - Les stubs S1 et S3 DOIVENT retourner CUSTODY_MODE_INVALID lors de initialize() et validateCapability() - Cela garantit que le système refuse explicitement ces modes non implémentés - Les stubs respectent l'interface CustodyStrategy pour permettre les tests unitaires

DA-02 : Failover RPC synchrone avec retry

Contexte : SLA de 5 secondes pour bascule primaire → secondaire.

Décision : Implémentation synchrone avec timeout 2s + 1 retry avant failover.

Justification : - Timeout 2s conforme à spec (FN-52-06) - 1 retry tolère les erreurs transitoires - Switch secondaire immédiat après 2 échecs - Total < 5s garanti (2s timeout × 2 tentatives + switch ~100ms)

DA-03 : Pattern Strategy pour custody modes

Contexte : 3 modes de custody avec comportements distincts (S1/S2/S3).

Décision : Utiliser le pattern Strategy avec interface commune CustodyStrategy.

Justification : - Extensibilité : ajout de modes futurs simple - Testabilité : chaque stratégie testable indépendamment - Cohérence : INV-52-04 (un seul mode) garanti par le service orchestrateur

DA-04 : Validation payload défensive

Contexte : INV-52-08 interdit toute donnée non-hash dans les transactions.

Décision : Validation stricte du payload avec whitelist de formats acceptés.

Justification : - Seuls les payloads commençant par le préfixe keccak256("ProbatioVault:anchor:...) sont acceptés - Rejet immédiat avec PAYLOAD_VALIDATION_FAILED sinon - Défense en profondeur avant émission

DA-05 : Endpoint /health/blockchain JSON

Contexte : INV-52-10 requiert des métriques exposables.

Décision : Endpoint REST GET /health/blockchain retournant JSON.

DA-06 : Propagation uniforme des erreurs (ECT-PLAN-03)

Contexte : INV-52-11 requiert des erreurs déterministes et journalisables sans fuite de secret.

Décision : Tous les services DOIVENT utiliser BlockchainError avec les règles suivantes : - Chaque erreur utilise un code de BlockchainErrorCode (enum T-03) - Le champ context ne contient JAMAIS de secret (clé, token, seed, mnemonic) - Les erreurs sont loggées via le logger NestJS avec niveau error ou warn - Le format de log est : [BlockchainModule] {code}: {message} | context: {sanitized_context}

Implémentation : Chaque service (T-05, T-12, T-13, T-16, T-17) inclut un handler d'erreur uniforme.

DA-07 : Mesure de l'écart gas (ECT-PLAN-04)

Contexte : CA-52-05 requiert que l'écart entre gas estimé et consommé soit < 25%.

Décision : Le ConfirmationTracker (T-17) capture le gasUsed réel après confirmation et calcule l'écart.

Observable : TransactionResult.gasMetrics: { estimated: bigint, actual: bigint, deviationPercent: number }

DA-08 : Point d'observabilité SLA failover (ECT-PLAN-07)

Contexte : CA-52-07 requiert de démontrer que le failover < 5s.

Décision : Le RpcProviderService (T-05) horodate chaque événement de failover : - failoverStartedAt: Date — début de la séquence (premier timeout) - failoverCompletedAt: Date — fin de la séquence (switch effectué) - failoverDurationMs: number — durée totale calculée

Observable : Log structuré [RpcProvider] FAILOVER | network={polygon|arbitrum} | duration={ms}ms | from=primary | to=secondary

Format :

{
  "timestamp": "2026-02-12T19:30:00Z",
  "networks": {
    "polygon": {
      "status": "connected",
      "provider": "primary",
      "latencyMs": 45,
      "gasPriceGwei": 35.2,
      "walletBalance": "0.5",
      "blockNumber": 12345678
    },
    "arbitrum": {
      "status": "connected",
      "provider": "secondary",
      "latencyMs": 32,
      "gasPriceGwei": 0.1,
      "walletBalance": "0.3",
      "blockNumber": 87654321
    }
  },
  "custodyMode": "S2",
  "custodyStatus": "valid"
}


3bis. Préconditions d'environnement (ECT-PLAN-08/09)

Infrastructure requise avant implémentation

Composant Précondition Vérification
AWS KMS Clé ECC_SECG_P256K1 créée dans eu-west-3 aws kms describe-key --key-id $KMS_KEY_ID
IAM Permissions kms:Sign, kms:GetPublicKey aws iam simulate-principal-policy
RPC Alchemy API key valide avec accès Polygon Amoy + Arbitrum Sepolia Test eth_blockNumber
RPC Public Endpoints publics accessibles (fallback) Test eth_blockNumber
Vault (si S3) Moteur Transit activé, clé secp256k1 vault read transit/keys/ethereum
HSM (si S1) Slot PKCS#11 configuré, clé secp256k1 pkcs11-tool --list-objects

Wallet funding (testnet)

Réseau Wallet Solde minimum Faucet
Polygon Amoy $WALLET_ADDRESS 0.1 MATIC https://faucet.polygon.technology/
Arbitrum Sepolia $WALLET_ADDRESS 0.01 ETH https://www.alchemy.com/faucets/arbitrum-sepolia

Procédure de funding : 1. Récupérer l'adresse wallet via CustodyService.getStrategy().getAddress() 2. Demander des fonds sur les faucets listés 3. Vérifier le solde via eth_getBalance 4. Documenter les TX IDs de funding pour traçabilité

Checklist de readiness

# 1. Vérifier KMS
aws kms get-public-key --key-id $BLOCKCHAIN_KMS_KEY_ID --output text

# 2. Vérifier RPC Polygon
curl -X POST $BLOCKCHAIN_POLYGON_RPC_PRIMARY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

# 3. Vérifier RPC Arbitrum
curl -X POST $BLOCKCHAIN_ARBITRUM_RPC_PRIMARY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

# 4. Vérifier solde wallet (après funding)
curl -X POST $BLOCKCHAIN_POLYGON_RPC_PRIMARY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_getBalance","params":["'$WALLET_ADDRESS'","latest"],"id":1}'

Provisioning KMS et IAM (Terraform)

La clé KMS et le user IAM sont provisionnés automatiquement via Terraform dans ProbatioVault-infra.

Fichier : terraform/iam-blockchain-signer.tf

Ressources créées : - aws_kms_key.ethereum_signing — Clé ECC_SECG_P256K1 pour signature secp256k1 - aws_kms_alias.ethereum_signing — Alias probatiovault-eth-signing-{env} - aws_iam_user.blockchain_signer — User probatiovault-blockchain-signer - aws_iam_policy.blockchain_signer — Permissions minimales (kms:Sign, kms:GetPublicKey, kms:DescribeKey)

Déploiement :

# Via CI/CD (recommandé)
git push origin dev  # Pipeline terraform:apply:dev

# Manuel (debug)
cd ProbatioVault-infra/terraform
./scripts/terraform-with-vault.sh apply

Outputs à stocker dans Vault :

terraform output blockchain_kms_key_id              # ARN de la clé KMS
terraform output -raw blockchain_signer_access_key_id      # AWS Access Key ID
terraform output -raw blockchain_signer_secret_access_key  # AWS Secret Access Key

Mise à jour Vault :

curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
  --request POST \
  --data '{
    "data": {
      "BLOCKCHAIN_KMS_KEY_ID": "<ARN_FROM_OUTPUT>",
      "AWS_ACCESS_KEY_ID": "<ACCESS_KEY_FROM_OUTPUT>",
      "AWS_SECRET_ACCESS_KEY": "<SECRET_FROM_OUTPUT>",
      "BLOCKCHAIN_POLYGON_RPC_PRIMARY": "https://rpc-amoy.polygon.technology",
      "BLOCKCHAIN_POLYGON_RPC_SECONDARY": "https://polygon-amoy-bor-rpc.publicnode.com",
      "BLOCKCHAIN_ARBITRUM_RPC_PRIMARY": "https://sepolia-rollup.arbitrum.io/rpc",
      "BLOCKCHAIN_ARBITRUM_RPC_SECONDARY": "https://arbitrum-sepolia-rpc.publicnode.com",
      "BLOCKCHAIN_CUSTODY_MODE": "S2"
    }
  }' \
  "https://vault.dev.probatiovault.com/v1/kv/data/app/blockchain"


4. Séquençage des tâches

Phase 1 : Fondations (Tâches 1-4)

# Tâche Agent Dépendances Fichiers
T-01 Configuration module + constants developer - blockchain.module.ts, blockchain.config.ts, constants/*.ts
T-02 Interface et types developer T-01 */interfaces.ts, dto/.ts
T-03 Codes d'erreur developer T-01 constants/error-codes.ts
T-04 Chaîne IDs + guard testnet developer T-01 constants/chain-ids.ts, validators/chain-id.guard.ts

Phase 2 : RPC Provider (Tâches 5-7)

# Tâche Agent Dépendances Fichiers
T-05 RpcProviderService + failover developer T-01, T-03 providers/rpc-provider.service.ts
T-06 Health check RPC developer T-05 providers/rpc-health.service.ts
T-07 Tests unitaires RPC qa-unit T-05, T-06 tests/providers/*.spec.ts

Phase 3 : Custody (Tâches 8-12)

# Tâche Agent Dépendances Fichiers
T-08 Interface CustodyStrategy developer T-02 custody/custody.interface.ts
T-09 S2 KMS Strategy developer T-08 custody/strategies/s2-kms.strategy.ts
T-10 S1 HSM Strategy (stub → CUSTODY_MODE_INVALID) developer T-08 custody/strategies/s1-hsm.strategy.ts
T-11 S3 Hybrid Strategy (stub → CUSTODY_MODE_INVALID) developer T-08 custody/strategies/s3-hybrid.strategy.ts
T-12 CustodyService orchestrateur developer T-09, T-10, T-11 custody/custody.service.ts

Phase 4 : Wallet & Transaction (Tâches 13-17)

# Tâche Agent Dépendances Fichiers
T-13 WalletService (sign EIP-191) developer T-12 wallet/wallet.service.ts
T-14 PayloadValidator developer T-03 validators/payload.validator.ts
T-15 GasEstimatorService developer T-05 transaction/gas-estimator.service.ts
T-16 TransactionService developer T-13, T-14, T-15 transaction/transaction.service.ts
T-17 ConfirmationTracker developer T-05, T-16 transaction/confirmation.tracker.ts

Phase 5 : Health & Observability (Tâches 18-19)

# Tâche Agent Dépendances Fichiers
T-18 BlockchainHealthService developer T-05, T-12, T-13 health/blockchain-health.service.ts
T-19 BlockchainHealthController developer T-18 health/blockchain-health.controller.ts

Phase 6 : Tests & Intégration (Tâches 20-25)

# Tâche Agent Dépendances Fichiers
T-20 Tests unitaires custody qa-unit T-12 tests/custody/*.spec.ts
T-21 Tests unitaires wallet/tx qa-unit T-13, T-16, T-17 tests/wallet/.spec.ts, tests/transaction/.spec.ts
T-22 Tests intégration testnet (10/10 + SLA) qa-integration T-16, T-17 tests/integration/blockchain.e2e.spec.ts
T-23 Tests health endpoint qa-integration T-19 tests/health/*.spec.ts
T-24 Audit de secrets (gitleaks + logs) qa-security T-20, T-21 scripts/audit-secrets.sh, .gitleaks.toml
T-25 Rapport de couverture Jest/Istanbul qa-unit T-20, T-21 coverage/lcov-report/index.html

Détail T-22 : Tests intégration testnet (ECT-PLAN-06/07)

Test TC-NOM-01/02 : Connectivité 10/10 (CA-52-01, CA-52-02)

describe('Connectivity 10/10', () => {
  it.each(['polygon', 'arbitrum'])('should succeed 10 consecutive calls on %s', async (network) => {
    const results: number[] = [];
    for (let i = 0; i < 10; i++) {
      const blockNumber = await rpcService.call(network, 'eth_blockNumber');
      results.push(blockNumber);
    }
    expect(results).toHaveLength(10);
    expect(results.every(n => n > 0)).toBe(true);
    // Observable: logs contiennent 10 entrées successives
  });
});

Test TC-NOM-09 : Failover SLA < 5s (CA-52-07)

describe('Failover SLA', () => {
  it('should failover in less than 5 seconds', async () => {
    // Simuler timeout primaire
    mockPrimaryTimeout();

    const startTime = Date.now();
    const result = await rpcService.call('polygon', 'eth_blockNumber');
    const endTime = Date.now();

    const failoverDuration = endTime - startTime;
    expect(failoverDuration).toBeLessThan(5000);
    expect(rpcService.getActiveProvider('polygon')).toBe('secondary');
    // Observable: log FAILOVER avec duration
  });
});

Détail T-24 : Audit de secrets (ECT-PLAN-05)

Script scripts/audit-secrets.sh :

#!/bin/bash
set -e

echo "=== Audit de secrets PD-52 ==="

# 1. Scan gitleaks sur le code source
gitleaks detect --source . --config .gitleaks.toml --report-path gitleaks-report.json

# 2. Scan des logs applicatifs (patterns de clé privée)
grep -rn "0x[a-fA-F0-9]{64}" logs/ && echo "FAIL: Potential private key in logs" && exit 1

# 3. Scan des variables d'environnement
env | grep -E "PRIVATE_KEY|MNEMONIC|SEED" && echo "FAIL: Secret in env" && exit 1

# 4. Scan de l'historique git
git log --all --full-history -p | grep -E "0x[a-fA-F0-9]{64}" && echo "FAIL: Secret in git history" && exit 1

echo "=== Audit OK : aucun secret détecté ==="

Observable : Rapport gitleaks-report.json avec 0 finding.

Détail T-25 : Rapport de couverture (ECT-PLAN-15)

Commande : npm run test:cov

Artefact : coverage/lcov-report/index.html

Critère CA-52-12 : Couverture unitaire ≥ 80%

Vérification CI :

# .gitlab-ci.yml
test:coverage:
  script:
    - npm run test:cov
    - |
      COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
      if (( $(echo "$COVERAGE < 80" | bc -l) )); then
        echo "FAIL: Coverage $COVERAGE% < 80%"
        exit 1
      fi
  artifacts:
    paths:
      - coverage/


4bis. Diagrammes Mermaid

Graphe de dépendances des tâches

graph TD
    subgraph "Phase 1 — Fondations"
        T01["T-01<br/>blockchain.module.ts<br/>blockchain.config.ts"]
        T02["T-02<br/>Interfaces & DTOs"]
        T03["T-03<br/>Error codes"]
        T04["T-04<br/>Chain IDs + guard testnet"]
    end

    subgraph "Phase 2 — RPC Provider"
        T05["T-05<br/>RpcProviderService<br/>+ failover"]
        T06["T-06<br/>RPC Health check"]
        T07["T-07<br/>Tests unitaires RPC"]
    end

    subgraph "Phase 3 — Custody"
        T08["T-08<br/>CustodyStrategy<br/>interface"]
        T09["T-09<br/>S2 KMS Strategy"]
        T10["T-10<br/>S1 HSM Strategy<br/>(stub)"]
        T11["T-11<br/>S3 Hybrid Strategy<br/>(stub)"]
        T12["T-12<br/>CustodyService<br/>orchestrateur"]
    end

    subgraph "Phase 4 — Wallet & Transaction"
        T13["T-13<br/>WalletService<br/>(sign EIP-191)"]
        T14["T-14<br/>PayloadValidator"]
        T15["T-15<br/>GasEstimatorService"]
        T16["T-16<br/>TransactionService"]
        T17["T-17<br/>ConfirmationTracker"]
    end

    subgraph "Phase 5 — Health & Observability"
        T18["T-18<br/>BlockchainHealthService"]
        T19["T-19<br/>BlockchainHealthController"]
    end

    subgraph "Phase 6 — Tests & Intégration"
        T20["T-20<br/>Tests custody"]
        T21["T-21<br/>Tests wallet/tx"]
        T22["T-22<br/>Tests intégration<br/>testnet"]
        T23["T-23<br/>Tests health"]
        T24["T-24<br/>Audit secrets"]
        T25["T-25<br/>Rapport couverture"]
    end

    %% Phase 1 deps
    T01 --> T02
    T01 --> T03
    T01 --> T04

    %% Phase 2 deps
    T01 --> T05
    T03 --> T05
    T05 --> T06
    T05 --> T07
    T06 --> T07

    %% Phase 3 deps
    T02 --> T08
    T08 --> T09
    T08 --> T10
    T08 --> T11
    T09 --> T12
    T10 --> T12
    T11 --> T12

    %% Phase 4 deps
    T12 --> T13
    T03 --> T14
    T05 --> T15
    T13 --> T16
    T14 --> T16
    T15 --> T16
    T05 --> T17
    T16 --> T17

    %% Phase 5 deps
    T05 --> T18
    T12 --> T18
    T13 --> T18
    T18 --> T19

    %% Phase 6 deps
    T12 --> T20
    T13 --> T21
    T16 --> T21
    T17 --> T21
    T16 --> T22
    T17 --> T22
    T19 --> T23
    T20 --> T24
    T21 --> T24
    T20 --> T25
    T21 --> T25

Diagramme de séquence — Transaction avec failover RPC et custody S2

sequenceDiagram
    participant Client
    participant TxSvc as TransactionService
    participant PayloadVal as PayloadValidator
    participant GasEst as GasEstimatorService
    participant RpcSvc as RpcProviderService
    participant Custody as CustodyService
    participant KMS as S2 KMS Strategy
    participant Wallet as WalletService
    participant Tracker as ConfirmationTracker
    participant Health as BlockchainHealthService

    Client->>TxSvc: buildAndSend(payload, network)
    TxSvc->>PayloadVal: validate(payload)
    PayloadVal-->>TxSvc: OK (hash only, testnet)

    TxSvc->>GasEst: estimate(network)
    GasEst->>RpcSvc: call(eth_gasPrice)

    alt Primary RPC timeout (>2s)
        RpcSvc->>RpcSvc: retry (1x)
        RpcSvc->>RpcSvc: failover to secondary
        Note over RpcSvc: Log FAILOVER<br/>duration < 5s (DA-08)
    end

    RpcSvc-->>GasEst: gasPrice
    GasEst-->>TxSvc: estimatedGas

    TxSvc->>Custody: getStrategy()
    Custody-->>TxSvc: S2 (KMS)
    TxSvc->>KMS: sign(txData)
    KMS-->>TxSvc: signedTx

    TxSvc->>RpcSvc: sendTransaction(signedTx)
    RpcSvc-->>TxSvc: txHash

    TxSvc->>Tracker: track(txHash, network)
    loop Until confirmations >= threshold
        Tracker->>RpcSvc: getTransactionReceipt(txHash)
        RpcSvc-->>Tracker: receipt (confirmations)
    end
    Tracker-->>TxSvc: TransactionResult (gasMetrics)

    TxSvc-->>Client: TransactionResult

    Note over Health: Expose /health/blockchain<br/>RPC status + custody mode<br/>+ wallet balance + latency

5. Matrice de couverture

Invariants → Tâches

Invariant Tâches responsables
INV-52-01 (Polygon + Arbitrum) T-04, T-05
INV-52-02 (testnet only) T-04, T-14
INV-52-03 (pas de secret en clair) T-09, T-10, T-11, T-13
INV-52-04 (un seul custody mode) T-12
INV-52-05 (refus si mode indispo) T-12
INV-52-06 (primaire + secondaire) T-05
INV-52-07 (failover < 5s) T-05, T-06
INV-52-08 (hash only) T-14
INV-52-09 (seuil confirmations) T-17
INV-52-10 (/health/blockchain) T-18, T-19
INV-52-11 (erreurs déterministes) T-03, T-05, T-12, T-13, T-16, T-17 (propagation uniforme DA-06)
INV-52-12 (tests CI) T-20, T-21, T-22, T-23, T-24, T-25
INV-52-13 (seuil configurable) T-01, T-17

Cas d'erreur → Tâches

Code erreur Tâche responsable
RPC_PRIMARY_FAILED T-05
RPC_UNAVAILABLE T-05
CUSTODY_MODE_MISSING T-12
CUSTODY_MODE_INVALID T-12
SIGNATURE_VERIFICATION_FAILED T-13
INSUFFICIENT_FUNDS T-16
GAS_PRICE_CEILING_EXCEEDED T-15, T-16
TRANSACTION_REORG T-17
SECRET_LEAK_DETECTED T-20
CUSTODY_MODE_AMBIGUOUS T-12
CUSTODY_MODE_UNKNOWN T-12
RPC_INVALID_ENDPOINT T-05
MAINNET_FORBIDDEN T-04, T-14
PAYLOAD_VALIDATION_FAILED T-14

6. Risques techniques et mitigations

Risque Impact Mitigation
AWS KMS latence élevée pour signature Performance dégradée Cache de session KMS, parallélisation
Testnet RPC instable Tests flaky Mock pour tests unitaires, retry pour intégration
Complexity S1/S3 strategies Retard livraison S2 prioritaire, S1/S3 en stub
Gas estimation imprécise Transactions bloquées Marge +20%, fallback sur gasLimit fixe

7. Environnement de développement

Variables d'environnement requises

# RPC Providers
BLOCKCHAIN_POLYGON_RPC_PRIMARY=https://polygon-amoy.g.alchemy.com/v2/xxx
BLOCKCHAIN_POLYGON_RPC_SECONDARY=https://rpc-amoy.polygon.technology
BLOCKCHAIN_ARBITRUM_RPC_PRIMARY=https://arb-sepolia.g.alchemy.com/v2/xxx
BLOCKCHAIN_ARBITRUM_RPC_SECONDARY=https://sepolia-rollup.arbitrum.io/rpc

# Custody
BLOCKCHAIN_CUSTODY_MODE=S2
BLOCKCHAIN_KMS_KEY_ID=arn:aws:kms:eu-west-3:xxx:key/xxx

# Confirmations
BLOCKCHAIN_POLYGON_CONFIRMATIONS=5
BLOCKCHAIN_ARBITRUM_CONFIRMATIONS=1

# Timeouts
BLOCKCHAIN_RPC_TIMEOUT_MS=2000
BLOCKCHAIN_RPC_RETRY_COUNT=1

# Gas
BLOCKCHAIN_GAS_PRICE_CEILING_GWEI=100

Testnet Faucets

  • Polygon Amoy : https://faucet.polygon.technology/
  • Arbitrum Sepolia : https://www.alchemy.com/faucets/arbitrum-sepolia

8. Estimation effort

Phase Tâches Effort estimé
Phase 1 : Fondations T-01 à T-04 2h
Phase 2 : RPC Provider T-05 à T-07 3h
Phase 3 : Custody T-08 à T-12 4h
Phase 4 : Wallet & TX T-13 à T-17 4h
Phase 5 : Health T-18 à T-19 1h
Phase 6 : Tests & Audit T-20 à T-25 4h
Total 25 tâches ~18h

8bis. Notes de conception (ECT-PLAN-10/14)

MAINNET_FORBIDDEN : double vérification (défense en profondeur)

Le code d'erreur MAINNET_FORBIDDEN peut être émis depuis deux points : 1. chain-id.guard.ts (T-04) : Vérification au niveau configuration/module 2. payload.validator.ts (T-14) : Vérification avant émission de transaction

Ce chevauchement est intentionnel (défense en profondeur). La première barrière bloque au démarrage, la seconde bloque à l'exécution.

Métadonnées on-chain : risque de corrélation (ECT-PLAN-10)

Le payload de transaction type contient : keccak256("ProbatioVault:anchor:test:" || timestamp_unix)

Analyse : - Le préfixe ProbatioVault:anchor:test: est public et non identifiant - Le timestamp unix seul ne permet pas d'identifier un individu - La corrélation nécessiterait l'accès aux systèmes internes de ProbatioVault

Mitigation : Le timestamp est arrondi à la minute (pas à la milliseconde) pour réduire la précision de corrélation.


9. Prochaines étapes

  1. Gate 5 : Review plan d'implémentation (ChatGPT + confrontation)
  2. Étape 6 : Implémentation multi-agents
  3. Étape 7 : Acceptabilité (reviews + tests)
  4. Gate 8 : Closure

Références