MilestonesService.resolveIssue() distributes a milestone's budget by repeatedly calling EscrowService.releasePartial() against one Escrow row that was fund()-ed once for the milestone's full budget and stays LOCKED across many partial releases (one per resolved issue).
The real mergefi-milestones contract (MergeFi/contracts, contracts/milestones/src/lib.rs) models this completely differently: create_milestone() opens a budget pool, allocate(milestone_id, issue_id, amount) reserves a slice of the unallocated remainder for one specific issue_id (admin-only, rejects over-allocation), and release_issue(milestone_id, issue_id, recipients) pays out that specific issue's already-reserved slice. There is no "partially release from a locked escrow" primitive at all — resolveIssue's even-split-of-remainingBudget-across-openIssues logic, and its single ever-LOCKED Escrow row, don't correspond to anything the real contract exposes. Making milestones work against the real contract needs MilestonesService to track per-issue allocations (mirroring allocate/release_issue) rather than one shared escrow drained via repeated partial releases — a data-model change in this service, not just an argument-encoding fix in SorobanClientService.
MilestonesService.resolveIssue()distributes a milestone's budget by repeatedly callingEscrowService.releasePartial()against oneEscrowrow that wasfund()-ed once for the milestone's fullbudgetand staysLOCKEDacross many partial releases (one per resolved issue).The real
mergefi-milestonescontract (MergeFi/contracts,contracts/milestones/src/lib.rs) models this completely differently:create_milestone()opens a budget pool,allocate(milestone_id, issue_id, amount)reserves a slice of the unallocated remainder for one specificissue_id(admin-only, rejects over-allocation), andrelease_issue(milestone_id, issue_id, recipients)pays out that specific issue's already-reserved slice. There is no "partially release from a locked escrow" primitive at all —resolveIssue's even-split-of-remainingBudget-across-openIssueslogic, and its single ever-LOCKEDEscrowrow, don't correspond to anything the real contract exposes. Making milestones work against the real contract needsMilestonesServiceto track per-issue allocations (mirroringallocate/release_issue) rather than one shared escrow drained via repeated partial releases — a data-model change in this service, not just an argument-encoding fix inSorobanClientService.