feat(v2): wire fee-config publish into machine + super-config triggers (#39 3/3)
Three trigger points wire fee_transport.publish_fee_config into the satmachineadmin API endpoints per the #39 spec. All three soft-fail on transport errors — the underlying CRUD operation (machine create / update / super-config save) succeeds even when the publish couldn't reach the relay or the signer, and the operator can re-trigger by editing again. views_api.py: - api_create_machine — publishes always after create, even when operator fees default to 0/0 (the resulting super-only payload is what unblocks the ATM past its `awaiting-fees` maintenance gate). Reads super_config singleton; if absent (m001 should have inserted it, so this is an impossible state), skips the publish to avoid crashing create. - api_update_machine — publishes only when either operator_cash_*_fee_fraction is in the patch payload. Skip on name/location/wallet_id/is_active/fiat_code edits since those don't affect the fee model the ATM enforces (avoids unnecessary relay churn). - api_update_super_config — publishes to every active machine when either super fraction changes. Per-machine: that machine's operator_user_id is the signer (machines owned by different operators sign with different keys); each soft-fail is independent. Skip if only super_fee_wallet_id changed (no fee-model impact). Tests (9 cases, all green): - 3 create-machine triggers: default 0/0 operator fees still publishes super-only payload, nonzero operator fees publish full payload, None super_config short-circuits without crashing - 4 update-machine triggers: publishes on cash_in change, publishes on cash_out change, skips on name-only, skips on is_active-only - 2 super-config triggers: publishes per-active-machine signed by each machine's operator on fraction change, skips entirely on wallet-id-only change (with an assertion that list_all_active_machines is never called, proving the short-circuit path) 191/191 tests green. Layer 2 (#39) complete; ready for joint smoke once bitspire fixes the three deploy gaps from coord-log §2026-06-01T18:30Z (`relay.aiolabs.dev` default, `VITE_LNBITS_HTTP_URL` dead echo, operator-fees subscriber not running in maintenance state). Refs: aiolabs/satmachineadmin#37 (parent), #39 (closes Layer 2), aiolabs/lamassu-next#57 (Layer 3 consumer — blocked on bitspire-side gaps). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
12f39226f0
commit
794d7e5395
2 changed files with 424 additions and 0 deletions
33
views_api.py
33
views_api.py
|
|
@ -22,6 +22,7 @@ from .cassette_transport import (
|
|||
SignerUnavailable,
|
||||
publish_to_atm,
|
||||
)
|
||||
from .fee_transport import publish_fee_config
|
||||
from .crud import (
|
||||
append_settlement_note,
|
||||
count_completed_legs_for_settlement,
|
||||
|
|
@ -264,6 +265,12 @@ async def api_create_machine(
|
|||
data.operator_cash_out_fee_fraction,
|
||||
)
|
||||
machine = await create_machine(user.id, data)
|
||||
# Layer 2 (#39): publish initial fee config to the ATM so it can
|
||||
# unblock past its `awaiting-fees` maintenance gate. Soft-fails on
|
||||
# transport errors — machine creation has already succeeded.
|
||||
super_config = await get_super_config()
|
||||
if super_config is not None:
|
||||
await publish_fee_config(machine, super_config, user.id)
|
||||
return machine
|
||||
|
||||
|
||||
|
|
@ -319,6 +326,18 @@ async def api_update_machine(
|
|||
updated = await update_machine(machine_id, data)
|
||||
if updated is None:
|
||||
raise HTTPException(HTTPStatus.NOT_FOUND, "Machine not found")
|
||||
# Layer 2 (#39): if either operator fee fraction changed, publish a
|
||||
# fresh kind-30078 to the ATM so it picks up the new total. Skip
|
||||
# otherwise — name/location/wallet_id/is_active edits don't change
|
||||
# the fee model the ATM enforces.
|
||||
fees_changed = (
|
||||
data.operator_cash_in_fee_fraction is not None
|
||||
or data.operator_cash_out_fee_fraction is not None
|
||||
)
|
||||
if fees_changed:
|
||||
super_config = await get_super_config()
|
||||
if super_config is not None:
|
||||
await publish_fee_config(updated, super_config, user.id)
|
||||
return updated
|
||||
|
||||
|
||||
|
|
@ -939,6 +958,20 @@ async def api_update_super_config(
|
|||
raise HTTPException(
|
||||
HTTPStatus.INTERNAL_SERVER_ERROR, "Failed to update super config"
|
||||
)
|
||||
# Layer 2 (#39): a super-fee change ripples to every active machine
|
||||
# since each machine's total = super + machine.operator. Republish
|
||||
# per-machine with that machine's operator as the signer.
|
||||
# Soft-fails per machine independently; partial success is acceptable
|
||||
# (the operator whose publish failed can re-trigger via a machine
|
||||
# edit). Skip if neither directional fraction was touched in this
|
||||
# update (e.g. caller only changed super_fee_wallet_id).
|
||||
super_fractions_changed = (
|
||||
data.super_cash_in_fee_fraction is not None
|
||||
or data.super_cash_out_fee_fraction is not None
|
||||
)
|
||||
if super_fractions_changed:
|
||||
for machine in await list_all_active_machines():
|
||||
await publish_fee_config(machine, config, machine.operator_user_id)
|
||||
return config
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue