Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/escrow/escrow.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FundEscrowDto } from './dto/fund-escrow.dto';
import { ReleaseEscrowDto } from './dto/release-escrow.dto';
import { SplitReleaseDto } from './dto/split-release.dto';
import { toPublicEscrow } from './escrow-response.mapper';
import { toPublicPayments } from './payment-response.mapper';
import { Idempotent } from '../common/idempotency/idempotent.decorator';

@ApiTags('escrow')
Expand Down Expand Up @@ -37,8 +38,10 @@ export class EscrowController {

@Idempotent('escrow.splitRelease')
@Post(':id/split-release')
splitRelease(@Param('id') id: string, @Body() dto: SplitReleaseDto) {
return this.escrowService.splitRelease(id, dto.recipients);
async splitRelease(@Param('id') id: string, @Body() dto: SplitReleaseDto) {
return toPublicPayments(
await this.escrowService.splitRelease(id, dto.recipients),
);
}

@Idempotent('escrow.refund')
Expand Down
52 changes: 52 additions & 0 deletions src/escrow/payment-response.mapper.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Payment } from '../common/entities';
import { AssetType, PaymentStatus } from '../common/enums';
import { toPublicPayment, toPublicPayments } from './payment-response.mapper';

function makePayment(overrides: Partial<Payment> = {}): Payment {
return {
id: 'pay_1',
escrow: null as unknown as Payment['escrow'],
escrowId: 'esc_1',
recipient: null,
recipientId: 'user_1',
recipientAddress: 'GRECIPIENT',
amount: '50.0000000',
asset: AssetType.USDC,
splitPercentage: '50.00',
status: PaymentStatus.PENDING,
txHash: null,
createdAt: new Date(),
updatedAt: new Date(),
...overrides,
};
}

describe('toPublicPayment', () => {
it('preserves every field unchanged', () => {
const payment = makePayment();

const publicPayment = toPublicPayment(payment);

expect(publicPayment).toMatchObject({
id: 'pay_1',
escrowId: 'esc_1',
recipientId: 'user_1',
amount: '50.0000000',
status: PaymentStatus.PENDING,
});
});
});

describe('toPublicPayments', () => {
it('maps every payment in the array', () => {
const payments = [
makePayment({ id: 'pay_1' }),
makePayment({ id: 'pay_2' }),
];

const publicPayments = toPublicPayments(payments);

expect(publicPayments).toHaveLength(2);
expect(publicPayments.map((p) => p.id)).toEqual(['pay_1', 'pay_2']);
});
});
18 changes: 18 additions & 0 deletions src/escrow/payment-response.mapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Payment } from '../common/entities';

export type PublicPayment = Payment;

/**
* Thin passthrough today — Payment doesn't carry anything as sensitive as
* Escrow.metadata yet. Exists so splitRelease follows the same
* controller-boundary mapping pattern as every other escrow endpoint
* (see toPublicEscrow), so a future internal-only field added to Payment
* has somewhere to be stripped instead of leaking by default.
*/
export function toPublicPayment(payment: Payment): PublicPayment {
return payment;
}

export function toPublicPayments(payments: Payment[]): PublicPayment[] {
return payments.map(toPublicPayment);
}