diff --git a/src/subdomains/supporting/realunit/controllers/realunit.controller.ts b/src/subdomains/supporting/realunit/controllers/realunit.controller.ts index 597e5224b0..0461eb6a98 100644 --- a/src/subdomains/supporting/realunit/controllers/realunit.controller.ts +++ b/src/subdomains/supporting/realunit/controllers/realunit.controller.ts @@ -339,7 +339,7 @@ export class RealUnitController { @GetJwt() jwt: JwtPayload, @Body() dto: RealUnitEmailRegistrationDto, ): Promise { - const status = await this.realunitService.registerEmail(jwt.account, dto); + const status = await this.realunitService.registerEmail(jwt.account, jwt.address, dto); return { status }; } diff --git a/src/subdomains/supporting/realunit/dto/realunit-registration.dto.ts b/src/subdomains/supporting/realunit/dto/realunit-registration.dto.ts index 396cbe5a5b..5c2001755a 100644 --- a/src/subdomains/supporting/realunit/dto/realunit-registration.dto.ts +++ b/src/subdomains/supporting/realunit/dto/realunit-registration.dto.ts @@ -46,6 +46,12 @@ export class RealUnitEmailRegistrationDto { @IsLowercase() @Transform(Util.trim) email: string; + + @ApiProperty({ description: 'Ethereum wallet address (0x...)' }) + @IsNotEmpty() + @IsString() + @Matches(/^0x[a-fA-F0-9]{40}$/, { message: 'walletAddress must be a valid Ethereum address' }) + walletAddress: string; } export class RealUnitEmailRegistrationResponseDto { diff --git a/src/subdomains/supporting/realunit/realunit.service.ts b/src/subdomains/supporting/realunit/realunit.service.ts index 8f612174e1..807fa98a75 100644 --- a/src/subdomains/supporting/realunit/realunit.service.ts +++ b/src/subdomains/supporting/realunit/realunit.service.ts @@ -349,11 +349,26 @@ export class RealUnitService { return !success; } - async registerEmail(userDataId: number, dto: RealUnitEmailRegistrationDto): Promise { - const userData = await this.userDataService.getUserData(userDataId, { users: true }); + async registerEmail( + userDataId: number, + jwtAddress: string, + dto: RealUnitEmailRegistrationDto, + ): Promise { + const userData = await this.userDataService.getUserData(userDataId, { users: true, kycSteps: true }); if (!userData) throw new NotFoundException('User not found'); - if (!userData.mail) { + // Validate wallet address matches authenticated wallet + if (!Util.equalsIgnoreCase(dto.walletAddress, jwtAddress)) { + throw new BadRequestException('Wallet address does not match authenticated wallet'); + } + + const isNewEmail = !userData.mail || !Util.equalsIgnoreCase(dto.email, userData.mail); + + if (isNewEmail) { + if (userData.mail && this.hasRegistrationForWallet(userData, dto.walletAddress)) { + throw new BadRequestException('Not allowed to register a new email for this address'); + } + try { await this.userDataService.trySetUserMail(userData, dto.email); } catch (e) { @@ -364,8 +379,6 @@ export class RealUnitService { } throw e; } - } else if (!Util.equalsIgnoreCase(dto.email, userData.mail)) { - throw new BadRequestException('Email does not match verified email'); } if (userData.kycLevel < KycLevel.LEVEL_10) {