Skip to content

Commit f8998fd

Browse files
authored
Merge pull request #286 from ezedike-evan/feat/beneficiary-linked-withdrawal
feat(transactions): add beneficiary-linked withdrawal and destination…
2 parents 12ea8d5 + df78253 commit f8998fd

File tree

5 files changed

+138
-74
lines changed

5 files changed

+138
-74
lines changed

src/beneficiaries/beneficiaries.service.ts

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export class BeneficiariesService {
2020
userId: string,
2121
dto: CreateBeneficiaryDto,
2222
): Promise<Beneficiary> {
23-
// If this is set as default, unset all other defaults first
2423
if (dto.isDefault) {
2524
await this.beneficiaryRepository.update(
2625
{ userId, isDefault: true },
@@ -61,45 +60,7 @@ export class BeneficiariesService {
6160
return beneficiary;
6261
}
6362

64-
async updateBeneficiary(
65-
userId: string,
66-
id: string,
67-
dto: UpdateBeneficiaryDto,
68-
): Promise<Beneficiary> {
69-
const beneficiary = await this.getBeneficiaryById(userId, id);
70-
71-
Object.assign(beneficiary, dto);
72-
return this.beneficiaryRepository.save(beneficiary);
73-
}
74-
75-
async deleteBeneficiary(userId: string, id: string): Promise<void> {
76-
const beneficiary = await this.getBeneficiaryById(userId, id);
77-
await this.beneficiaryRepository.remove(beneficiary);
78-
}
79-
80-
async setDefault(userId: string, id: string): Promise<Beneficiary> {
81-
// Validate the beneficiary belongs to this user
82-
const beneficiary = await this.getBeneficiaryById(userId, id);
83-
84-
// Unset all current defaults for this user
85-
await this.beneficiaryRepository.update(
86-
{ userId, isDefault: true },
87-
{ isDefault: false },
88-
);
89-
90-
// Set new default
91-
beneficiary.isDefault = true;
92-
return this.beneficiaryRepository.save(beneficiary);
93-
}
94-
95-
/**
96-
* Used by the withdrawal flow — fetch wallet address from a saved beneficiary.
97-
*/
98-
async resolveWalletAddress(
99-
userId: string,
100-
beneficiaryId: string,
101-
): Promise<string> {
102-
const beneficiary = await this.getBeneficiaryById(userId, beneficiaryId);
103-
return beneficiary.walletAddress;
63+
async updateLastUsed(id: string): Promise<void> {
64+
await this.beneficiaryRepository.update(id, { lastUsedAt: new Date() });
10465
}
105-
}
66+
}

src/beneficiaries/entities/beneficiary.entity.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,12 @@ export class Beneficiary {
4545
@Column({ name: 'is_default', default: false })
4646
isDefault: boolean;
4747

48+
@Column({ name: 'last_used_at', type: 'timestamp', nullable: true })
49+
lastUsedAt: Date | null;
50+
4851
@CreateDateColumn({ name: 'created_at' })
4952
createdAt: Date;
5053

5154
@UpdateDateColumn({ name: 'updated_at' })
5255
updatedAt: Date;
53-
}
56+
}

src/transactions/dtos/transaction.dto.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,21 @@ export class CreateWithdrawalDto {
5555
@IsNotEmpty()
5656
currency: string;
5757

58-
@ApiProperty({
58+
@ApiPropertyOptional({
5959
example: 'GDQP2KPQGKIHYJGXNUIYOMHARUARCA7DJT5FO2FFOOUJ3UHMNGUAO7UP',
60-
description: 'Stellar destination address for the withdrawal',
60+
description:
61+
'Stellar destination address. Optional when beneficiaryId is provided — ' +
62+
'if both are given, beneficiaryId takes precedence.',
6163
})
6264
@IsString()
63-
@IsNotEmpty()
64-
destinationAddress: string;
65+
@IsOptional()
66+
destinationAddress?: string;
6567

6668
@ApiPropertyOptional({
6769
description:
68-
'ID of a saved beneficiary. If provided, walletAddress is pre-filled from it.',
69-
example: 'a1b2c3d4-...',
70+
'ID of a saved beneficiary. If provided, the beneficiary\'s walletAddress ' +
71+
'is used as the destination and lastUsedAt is updated on success.',
72+
example: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
7073
})
7174
@IsUUID()
7275
@IsOptional()
@@ -159,4 +162,4 @@ export class CreateSwapDto {
159162
@IsString()
160163
@IsNotEmpty()
161164
sourceAddress: string;
162-
}
165+
}

0 commit comments

Comments
 (0)