Skip to content

Show per-milestone receiver on multi-release milestone cards #65

@techrebelgit

Description

@techrebelgit

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:

receiver?: string;

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

  • ParsedMilestone includes optional receiver.
  • Multi-release milestone parsing extracts milestone-level receiver from contract storage.
  • Desktop milestone cards display receiver when available.
  • Mobile milestone cards display receiver when available.
  • Existing signer and approver display remains unchanged.
  • Single-release escrows are not negatively affected.
  • Multi-release escrows with different receivers per milestone clearly show each receiver.
  • Long receiver addresses do not break the milestone card layout.
  • No wallet connection or state-changing behavior is introduced.

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

  1. Load a known multi-release escrow where each milestone has a receiver.
  2. Confirm each milestone card shows the correct receiver.
  3. Test a multi-release escrow where milestones have different receivers.
  4. Confirm signer and approver still display correctly.
  5. Confirm single-release escrow rendering is unchanged.
  6. Test on desktop and mobile layouts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions