feat(KI-14): SAFE execution flows — D1 SafeProposeClient + D2 attestation + D3 escrow + D4 farm ops #109
Merged
syntropicagent opened 2 weeks ago

KI-14 — SAFE Execution Flows (Phase D) — D1–D4

Iteration: v1.2 · Status: Draft — full Phase D scope implemented, one commit per workstream.

The security model (whole point of this work)

The server holds a delegate key that can only propose transactions via the SAFE Transaction Service API — it never signs as an owner, never executes. Humans confirm in the Safe app. Even a full delegate-key leak can only propose, never move funds. ATTESTER_PRIVATE_KEY is now propose-only (risk lower than today's direct-signing, per Wasabi's direction).

D1 — SafeProposeClient (services/treasury/propose.py)

  • EIP-712 safeTxHash computation, verified against a REAL executed transaction on the Core Team SAFE (Gnosis, nonce 6 → 0x776c65...). Domain separator uses abi.encode (address padded to 32 bytes), not encodePacked.
  • propose() signs the safeTxHash with the delegate key (raw ECDSA via unsafe_sign_hash, no EIP-191 prefix) and POSTs to the Transaction Service.
  • register_delegate(), list_delegates(), build_tx().
  • 7 tests incl. real on-chain vector.

D2 — Attestation via SAFE (services/attestation/safe_flow.py, Celo)

  • propose_attestation(): builds the EAS attest() call (EASClient.build_attest_call refactor — encode-only, no send), wraps in a Safe tx, proposes to the Core Team SAFE on Celo.
  • reconcile_attestation_executions(): polls the SAFE Transaction Service, marks requests executed once humans confirm.
  • Migration 355: attestation_request gains safe_tx_hash, proposal_status, safe_chain.
  • 3 tests (propose, reconcile executed, reconcile pending).

D3 — Escrow settlement via SAFE (services/credit_class/safe_settlement.py, Gnosis)

  • propose_settlement(): KokonutCreditToken transferFrom (seller→buyer + fee→treasury) proposed to the Core Team SAFE (2-of-3) — value moves now need human confirmation instead of raw DB updates.
  • Migration 356: order tables gain safe_settlement_tx_hash + settlement_status.
  • 3 tests (ABI encoding, default SAFE, farm op).

D4 — Farm treasury ops (services/treasury/ops.py)

  • propose_farm_op(): agent proposes payroll/inputs/expenses on a deployed farm SAFE; address/chain resolve from safe_account (Phase C) or explicit.
  • CLI: kokonut treasury ops-propose.
  • 4 tests.

Total: 17 new tests, all green (30 in treasury+attestation+settlement suite).

Chains (locked in KI-12 research)

  • D2 → Celo (Core Team SAFE, 1-of-3 — active, nonce 65)
  • D3 → Gnosis (Core Team SAFE, 2-of-3)
  • D4 → per farm SAFE (chain-agnostic)

Out of scope

  • Sepolia testnet validation before production chains (next step)
  • Removing the legacy direct-attestation path until the SAFE path is proven
  • Dedicated marketplace SAFE (currently reusing Core Team SAFE; noted)

Refs KI-14 · iteration v1.2

Commits were merged into target branch
  • feat(ki14): D1 — SafeProposeClient (propose-only, verified against real on-chain tx)
    - services/treasury/propose.py: SafeProposeClient with EIP-712 safeTxHash
      computation, verified against a REAL executed transaction on the Core Team
      SAFE (Gnosis, nonce 6 — safeTxHash 0x776c65...). Manual abi.encode
      approach (domain separator must use abi.encode, NOT encodePacked).
    - propose(): builds Safe tx, signs safeTxHash with delegate key via
      unsafe_sign_hash (raw ECDSA, no EIP-191 prefix), POSTs to SAFE Transaction
      Service API. Agent holds delegate key (propose-only); humans confirm.
    - register_delegate(), list_delegates(), build_tx() helpers.
    - tests/test_treasury_propose.py: 7 tests including the real on-chain vector,
      mocked HTTP propose, nonce/address determinism.
    - 20 treasury tests now green (13 existing + 7 new).
    
    Refs KI-14 · iteration v1.2
    2 weeks ago
    feat(ki14): D2 — propose EAS attestations via the Core Team SAFE (Celo)
    - services/attestation/safe_flow.py: propose_attestation() builds the EAS
      attest() call data, wraps it in a Safe tx, and proposes it to the Core
      Team SAFE on Celo (delegate key = propose-only). process_pending_requests_via_safe()
      batch entry point; reconcile_attestation_executions() polls the SAFE
      Transaction Service and marks requests executed once humans confirm.
    - services/attestation/eas_client.py: refactor attest() -> build_attest_call()
      (encode-only, no send) — the SAFE integration seam.
    - schemas/postgres/355: attestation_request gains safe_tx_hash, proposal_status,
      safe_chain (proposed→executed lifecycle).
    - tests/test_attestation_safe.py: 3 tests (propose, reconcile executed,
      reconcile pending) — mock EASClient/SafeProposeClient/SafeReadClient.
    
    Security: ATTESTER_PRIVATE_KEY becomes propose-only (delegate key). Even a
    full key leak can only propose, never execute — human confirmation on the
    SAFE (Celo 1-of-3) gates execution.
    
    Refs KI-14 · iteration v1.2
    2 weeks ago
    feat(ki14): D3 — marketplace escrow settlement via SAFE (Gnosis)
    - services/credit_class/safe_settlement.py: propose_settlement() builds a
      KokonutCreditToken transferFrom call (seller→buyer + fee→treasury) as a
      SAFE transaction and proposes it to the Core Team SAFE (2-of-3, Gnosis).
      propose_farm_op() shared helper for value moves.
    - schemas/postgres/356: credit_sell_order/credit_buy_order gain
      safe_settlement_tx_hash + settlement_status (pending→proposed→executed).
    - tests/test_safe_settlement.py: 3 tests (credit transfer ABI encoding,
      default SAFE, farm op proposal).
    
    Order book stays in DB (source of truth); value moves now require 2-of-3
    human confirmation via SAFE instead of raw DB updates.
    
    Refs KI-14 · iteration v1.2
    2 weeks ago
    feat(ki14): D4 — farm treasury ops (agent proposes, stewards confirm)
    - services/treasury/ops.py: propose_farm_op() — agent proposes payroll,
      inputs, expenses on a deployed farm SAFE. Address/chain resolve from the
      safe_account provisioning record (Phase C) or explicit params.
    - services/treasury/cli.py: kokonut treasury ops-propose command.
    - tests/test_treasury_ops.py: 4 tests (explicit address, DB resolve,
      unknown safe, decimal value).
    - docs/treasury.md: write-path section with D2/D3/D4 flows + security invariant.
    
    All 30 treasury + attestation + settlement tests pass, 7 CLI commands registered.
    
    Refs KI-14 · iteration v1.2
    2 weeks ago
  • fix(ki14): restore sys.modules in attestation_safe test (monkeypatch.setitem)
    The test was setting sys.modules entries directly to fake modules, which
    leaked into the rest of the test suite. When test_data_stream ran after
    my test, it imported the fake 'services.attestation.schemas' (returning
    1 field) instead of the real one (returning 9 fields), causing
    'assert 1 == 9' in CI. Fixed with monkeypatch.setitem which auto-restores
    the original sys.modules entry after the test.
    2 weeks ago
  • syntropicagent merged 2 weeks ago (merge commit: 48164002 )
1/1
Submitter syntropicagent
Target main
Source feat/ki14-safe-execution
Jobs
Merge Strategy
Create Merge Commit
Watchers (1)
Reference
pr KI-109
Please wait...
Connection lost or session expired, reload to recover
Page is in error, reload to recover