Skip to content

Commit 5efc17d

Browse files
authored
Merge pull request #70 from ChainSafe/fix/autobot-topup
fix: for autobot topups
2 parents 72149ca + 093fa23 commit 5efc17d

1 file changed

Lines changed: 19 additions & 38 deletions

File tree

src/canton_mcp_server/canton_billing.py

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -863,47 +863,27 @@ async def get_or_create_charge_manager() -> str:
863863

864864
logger.info("Looking for existing ChargeManager contract...")
865865

866-
# Query for existing ChargeManager
867-
template_id = f"{BILLING_PACKAGE_ID}:MCP.Billing:ChargeManager"
868-
869866
try:
870-
# Get current ledger offset
871-
offset = await get_ledger_offset()
872-
873-
data = await _make_ledger_request(
874-
"POST",
875-
"/v2/state/active-contracts",
876-
{
877-
"filter": {
878-
"filtersByParty": {
879-
CANTON_PROVIDER_PARTY: {
880-
"filters": [{
881-
"templateFilter": {
882-
"templateId": template_id
883-
}
884-
}]
885-
}
886-
}
887-
},
888-
"activeAtOffset": offset
889-
}
867+
# Query for existing ChargeManager via the paginated /v2/updates helper.
868+
# ChargeManager was intended to be a singleton, but historical deploys
869+
# with cold in-memory caches created multiple copies over time — on
870+
# mainnet the provider party now has >200 of them, which crossed the
871+
# /v2/state/active-contracts 200-element hard cap and surfaced as
872+
# "413 JSON_API_MAXIMUM_LIST_ELEMENTS_NUMBER_REACHED" inside
873+
# /billing/credit top-up failures. The paginated helper scans via
874+
# /v2/updates (no cap) and short-circuits on the first active match.
875+
def _extract_charge_manager(contract_id: str, _payload: dict, _created_at: str) -> Optional[str]:
876+
return contract_id or None
877+
878+
found = await _query_active_contracts_via_updates(
879+
template_suffix=":MCP.Billing:ChargeManager",
880+
party=CANTON_PROVIDER_PARTY,
881+
extract=_extract_charge_manager,
882+
stop_when=lambda _cid: True, # return as soon as any active one is seen
890883
)
891884

892-
# Handle different response formats (list or dict with activeContracts)
893-
contracts = data if isinstance(data, list) else data.get("activeContracts", [])
894-
895-
if contracts:
896-
# Handle different response formats
897-
first = contracts[0]
898-
contract_id = (
899-
first.get("contractId") or
900-
first.get("createdEvent", {}).get("contractId") or
901-
first.get("contractEntry", {}).get("activeContract", {}).get("createdEvent", {}).get("contractId") or
902-
first.get("contractEntry", {}).get("JsActiveContract", {}).get("createdEvent", {}).get("contractId")
903-
)
904-
if not contract_id:
905-
logger.error(f"Cannot find contractId in response: {first}")
906-
raise LedgerError("No contractId found in ChargeManager query response")
885+
if found:
886+
contract_id = found[0]
907887
logger.info(f"Found existing ChargeManager: {contract_id}")
908888
_charge_manager_cache = {
909889
"contract_id": contract_id,
@@ -913,6 +893,7 @@ async def get_or_create_charge_manager() -> str:
913893

914894
# No ChargeManager exists, create one using submit-and-wait-for-transaction
915895
logger.info("Creating new ChargeManager contract...")
896+
template_id = f"{BILLING_PACKAGE_ID}:MCP.Billing:ChargeManager"
916897

917898
create_data = await _make_ledger_request(
918899
"POST",

0 commit comments

Comments
 (0)