Context
In multi-release escrows, the receiver can exist at the milestone level rather than only at the escrow/global role level.
The Escrow Viewer currently displays milestone-level information such as amount, status, release/dispute/resolved flags, signer, and approver, but it does not display the receiver for each milestone.
This is important because in multi-release escrows, each milestone may route funds to a different receiver. The Viewer should make that explicit for transparency and auditability.
Problem
Users viewing a multi-release escrow cannot see the receiver address for each milestone on the milestone card.
This creates ambiguity around where funds will be released for each milestone.
Objective
Add the receiver address to each multi-release milestone card when the receiver exists at the milestone level.
Current Implementation Notes
The current normalized milestone type is defined in:
src/mappers/escrow-mapper.ts
Current ParsedMilestone includes:
export interface ParsedMilestone {
id: number;
title: string;
description: string;
status: string;
approved: boolean;
amount?: string;
release_flag?: boolean;
dispute_flag?: boolean;
resolved_flag?: boolean;
signer?: string;
approver?: string;
}
It does not include receiver.
The current milestone extraction already reads milestone-level addresses for:
signer: getAddr(milestoneMap, "signer"),
approver: getAddr(milestoneMap, "approver"),
Add receiver extraction from the milestone map.
The current shared milestone card accepts:
signer?: string;
approver?: string;
and displays those at the bottom of the card.
Scope of Work
1. Add receiver to normalized milestone type
Update:
src/mappers/escrow-mapper.ts
Add:
To ParsedMilestone.
2. Extract milestone-level receiver
In extractMilestones(), when handling multi-release milestones, extract the receiver address from the milestone map.
Suggested baseline:
receiver: getAddr(milestoneMap, "receiver"),
If the updated contract uses a different field name, support the actual field as well. Possible names to verify against raw contract storage:
receiver
receiver_address
recipient
recipient_address
Do not guess blindly. Inspect a real multi-release escrow from the current contract schema and document the actual field name in the PR.
3. Pass receiver into milestone cards
Update both desktop and mobile render paths:
src/components/escrow/desktop-view.tsx
src/components/escrow/tab-view.tsx
Pass:
receiver={milestone.receiver}
To MilestoneCard.
4. Display receiver in the milestone card
Update:
src/components/shared/milestone-card.tsx
Add a receiver?: string prop.
Display it together with signer and approver, for example:
Receiver: G...
Signer: G...
Approver: G...
Receiver should be visible when present.
5. Address formatting and copy behavior
Receiver may be a full Stellar address. Ensure it is readable and does not break card layout.
Preferred behavior:
- Show a truncated address in the UI if the card would overflow.
- Keep enough information for users to identify the address.
- If an existing copy/address component is available, reuse it.
- If no copy pattern exists in milestone cards, do not over-scope; display receiver safely first.
Non-Goals
- Do not change escrow state.
- Do not add wallet connection.
- Do not modify release logic.
- Do not change smart contract behavior.
- Do not add new dependencies.
- Do not redesign the entire milestone card.
- Do not remove the global receiver role display.
Acceptance Criteria
Suggested Files
src/mappers/escrow-mapper.ts
src/components/shared/milestone-card.tsx
src/components/escrow/desktop-view.tsx
src/components/escrow/tab-view.tsx
Potentially related if PDF export should include the same receiver data later:
src/utils/escrowExport.ts
Do not update the PDF in this issue unless the implementation naturally requires it. A separate issue can cover PDF receiver reporting.
Security / Product Notes
- Viewer remains read-only.
- Receiver visibility is important because it shows where milestone funds are routed.
- This supports Trustless Work’s transparency promise for multi-release escrows.
- This is especially important for grants, bounties, crowdfunding, and multi-party milestone flows.
Recommended Validation
- Load a known multi-release escrow where each milestone has a receiver.
- Confirm each milestone card shows the correct receiver.
- Test a multi-release escrow where milestones have different receivers.
- Confirm signer and approver still display correctly.
- Confirm single-release escrow rendering is unchanged.
- Test on desktop and mobile layouts.
Context
In multi-release escrows, the receiver can exist at the milestone level rather than only at the escrow/global role level.
The Escrow Viewer currently displays milestone-level information such as amount, status, release/dispute/resolved flags, signer, and approver, but it does not display the receiver for each milestone.
This is important because in multi-release escrows, each milestone may route funds to a different receiver. The Viewer should make that explicit for transparency and auditability.
Problem
Users viewing a multi-release escrow cannot see the receiver address for each milestone on the milestone card.
This creates ambiguity around where funds will be released for each milestone.
Objective
Add the receiver address to each multi-release milestone card when the receiver exists at the milestone level.
Current Implementation Notes
The current normalized milestone type is defined in:
Current
ParsedMilestoneincludes:It does not include
receiver.The current milestone extraction already reads milestone-level addresses for:
Add receiver extraction from the milestone map.
The current shared milestone card accepts:
and displays those at the bottom of the card.
Scope of Work
1. Add
receiverto normalized milestone typeUpdate:
Add:
To
ParsedMilestone.2. Extract milestone-level receiver
In
extractMilestones(), when handling multi-release milestones, extract the receiver address from the milestone map.Suggested baseline:
If the updated contract uses a different field name, support the actual field as well. Possible names to verify against raw contract storage:
Do not guess blindly. Inspect a real multi-release escrow from the current contract schema and document the actual field name in the PR.
3. Pass receiver into milestone cards
Update both desktop and mobile render paths:
Pass:
To
MilestoneCard.4. Display receiver in the milestone card
Update:
Add a
receiver?: stringprop.Display it together with signer and approver, for example:
Receiver should be visible when present.
5. Address formatting and copy behavior
Receiver may be a full Stellar address. Ensure it is readable and does not break card layout.
Preferred behavior:
Non-Goals
Acceptance Criteria
ParsedMilestoneincludes optionalreceiver.Suggested Files
Potentially related if PDF export should include the same receiver data later:
Do not update the PDF in this issue unless the implementation naturally requires it. A separate issue can cover PDF receiver reporting.
Security / Product Notes
Recommended Validation