diff --git a/apps/api/src/swap/swap.controller.spec.ts b/apps/api/src/swap/swap.controller.spec.ts index 2f0a5b3..3df035d 100644 --- a/apps/api/src/swap/swap.controller.spec.ts +++ b/apps/api/src/swap/swap.controller.spec.ts @@ -71,7 +71,7 @@ describe('SwapController', () => { it('should call swapService.postOnrampTransaction', () => { const req = { quote: undefined, - ref: 'ref', + reference: 'ref', amountFiat: '100', source: { currency: Currency.KES, @@ -80,7 +80,7 @@ describe('SwapController', () => { }, }, target: { - invoice: { + payout: { invoice: 'lnbc1000u1p0j7j0pp5', }, }, @@ -115,11 +115,11 @@ describe('SwapController', () => { it('should call swapService.postOfframpTransaction', () => { const req = { quote: undefined, - ref: 'ref', + reference: 'ref', amountFiat: '100', target: { currency: SupportedCurrencies.KES, - destination: { + payout: { phone: '07000000000', }, }, diff --git a/apps/api/src/swap/swap.controller.ts b/apps/api/src/swap/swap.controller.ts index d351e92..6785eb3 100644 --- a/apps/api/src/swap/swap.controller.ts +++ b/apps/api/src/swap/swap.controller.ts @@ -77,13 +77,13 @@ export class SwapController { @ApiOperation({ summary: 'List onramp swaps' }) @ApiQuery({ name: 'page', - example: '?page=0', + example: '0', type: ListSwapsDto['page'], required: false, }) @ApiQuery({ name: 'size', - example: '?size=100', + example: '100', type: ListSwapsDto['size'], required: false, }) @@ -139,13 +139,13 @@ export class SwapController { @ApiOperation({ summary: 'List offramp swaps' }) @ApiQuery({ name: 'page', - example: '?page=0', + example: '0', type: ListSwapsDto['page'], required: false, }) @ApiQuery({ name: 'size', - example: '?size=100', + example: '100', type: ListSwapsDto['size'], required: false, }) diff --git a/apps/api/src/swap/swap.service.spec.ts b/apps/api/src/swap/swap.service.spec.ts index 57f7c36..deeacf8 100644 --- a/apps/api/src/swap/swap.service.spec.ts +++ b/apps/api/src/swap/swap.service.spec.ts @@ -147,7 +147,7 @@ describe('SwapService', () => { it('can initiate an onramp swap without a quote', () => { const swap = swapService.postOnrampTransaction({ quote: undefined, - ref: '1234', + reference: 'ref', amountFiat: '100', source: { currency: Currency.KES, @@ -167,7 +167,7 @@ describe('SwapService', () => { it('can initiate an onramp swap with a quote', () => { const swap = swapService.postOnrampTransaction({ - ref: '1234', + reference: 'ref', amountFiat: '100', source: { currency: Currency.KES, @@ -229,7 +229,7 @@ describe('SwapService', () => { it('can initiate an offramp swap without a quote', () => { const swap = swapService.postOfframpTransaction({ quote: undefined, - ref: '1234', + reference: 'ref', amountFiat: '100', target: { currency: Currency.KES, @@ -244,7 +244,7 @@ describe('SwapService', () => { it('can initiate an offramp swap with a quote', () => { const swap = swapService.postOfframpTransaction({ - ref: '1234', + reference: 'ref', amountFiat: '100', target: { currency: Currency.KES, diff --git a/apps/swap/src/fedimint/fedimint.service.ts b/apps/swap/src/fedimint/fedimint.service.ts index beb9a90..b193031 100644 --- a/apps/swap/src/fedimint/fedimint.service.ts +++ b/apps/swap/src/fedimint/fedimint.service.ts @@ -101,8 +101,7 @@ export class FedimintService { } async pay(invoice: string): Promise<{ operationId: string; fee: number }> { - this.logger.log('Paying invoice'); - this.logger.log('Invoice', invoice); + this.logger.log(`Paying Invoice : ${invoice}`); const { operationId, fee }: LightningPayResponse = await this.post< { paymentInfo: string } & WithFederationId & WithGatewayId, @@ -113,7 +112,7 @@ export class FedimintService { gatewayId: this.gatewayId, }); - this.logger.log('Paid Invoice : ', operationId); + this.logger.log(`Paid Invoice : ${invoice} : ${operationId}`); return { operationId, fee, diff --git a/apps/swap/src/swap.service.ts b/apps/swap/src/swap.service.ts index 3fa4ce4..4f6147f 100644 --- a/apps/swap/src/swap.service.ts +++ b/apps/swap/src/swap.service.ts @@ -139,7 +139,7 @@ export class SwapService { amountFiat, source, target, - ref, + reference, }: CreateOnrampSwapDto): Promise { const rate = await this.getRate(quote, { from: Currency.KES, @@ -152,7 +152,7 @@ export class SwapService { }); const swap = await this.onramp.create({ - reference: ref, + reference, state: SwapTransactionState.PENDING, lightning: target.payout.invoice, amountSats: amountSats.toFixed(2), @@ -163,7 +163,7 @@ export class SwapService { const mpesa = await this.intasendService.sendMpesaStkPush({ amount: Number(amountFiat), phone_number: source.origin.phone, - api_ref: ref, + api_ref: reference, }); const updatedSwap = await this.onramp.findOneAndUpdate( @@ -230,10 +230,10 @@ export class SwapService { } async createOfframpSwap({ - ref, quote, amountFiat, target, + reference, }: CreateOfframpSwapDto): Promise { const rate = await this.getRate(quote, { from: Currency.BTC, @@ -246,13 +246,13 @@ export class SwapService { }); const { invoice: lightning, operationId: id } = - await this.fedimintService.invoice(amountMsats, ref || 'offramp'); + await this.fedimintService.invoice(amountMsats, reference); const swap = await this.offramp.create({ rate, + reference, lightning, retryCount: 0, - reference: ref, phone: target.payout.phone, amountSats: amountSats.toFixed(2), state: SwapTransactionState.PENDING, @@ -399,7 +399,7 @@ export class SwapService { const mpesa = await this.intasendService.getMpesaTrackerFromPaymentUpdate(update); - const swap = await this.onramp.findOne({ + const swap = await this.offramp.findOne({ paymentTracker: update.file_id, }); @@ -423,9 +423,6 @@ export class SwapService { context, operationId, }: ReceivePaymentSuccessEvent) { - this.logger.log('Successfully received payment'); - this.logger.log(`Context : ${context}, OperationId: ${operationId}`); - const swap = await this.offramp.findOne({ _id: operationId }); const amount = Number(swap.amountSats) * Number(swap.rate); @@ -444,6 +441,10 @@ export class SwapService { state: SwapTransactionState.PROCESSING, }, ); + + this.logger.log( + `Received lightning payment for ${context} : ${operationId}`, + ); } @OnEvent(fedimint_receive_failure) @@ -451,8 +452,16 @@ export class SwapService { context, operationId, }: ReceivePaymentFailureEvent) { - this.logger.log('Failed to receive payment'); - this.logger.log(`Context : ${context}, OperationId: ${operationId}`); + this.logger.log( + `Failed to eceive lightning payment for ${context} : ${operationId}`, + ); + + await this.offramp.findOneAndUpdate( + { _id: operationId }, + { + state: SwapTransactionState.FAILED, + }, + ); } } diff --git a/libs/common/src/dto/create-offramp-swap.dto.ts b/libs/common/src/dto/create-offramp-swap.dto.ts index d0aa25d..5e21d98 100644 --- a/libs/common/src/dto/create-offramp-swap.dto.ts +++ b/libs/common/src/dto/create-offramp-swap.dto.ts @@ -6,6 +6,7 @@ import { Validate, IsEnum, IsDefined, + ValidateNested, } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; import { @@ -21,17 +22,21 @@ import { TransformToCurrency } from './transforms'; class OfframpSwapTargetDto implements OfframpSwapTarget { @IsEnum(Currency) - @ApiProperty({ enum: SupportedCurrencies, enumName: 'SupportedCurrencyType' }) @TransformToCurrency() + @ApiProperty({ enum: SupportedCurrencies, enumName: 'SupportedCurrencyType' }) currency: Currency; @IsDefined() + @ValidateNested() + @Type(() => MobileMoneyDto) @ApiProperty({ type: MobileMoneyDto }) payout: MobileMoneyDto; } export class CreateOfframpSwapDto implements OfframpSwapRequest { @IsOptional() + @ValidateNested() + @Type(() => QuoteDto) @ApiProperty({ type: QuoteDto }) quote: QuoteDto; @@ -39,7 +44,7 @@ export class CreateOfframpSwapDto implements OfframpSwapRequest { @IsString() @Type(() => String) @ApiProperty() - ref: string; + reference: string; @IsNotEmpty() @IsString() @@ -49,6 +54,8 @@ export class CreateOfframpSwapDto implements OfframpSwapRequest { amountFiat: string; @IsNotEmpty() + @ValidateNested() + @Type(() => OfframpSwapTargetDto) @ApiProperty({ type: OfframpSwapTargetDto }) target: OfframpSwapTargetDto; } diff --git a/libs/common/src/dto/create-onramp-swap.dto.ts b/libs/common/src/dto/create-onramp-swap.dto.ts index f06f4ec..b7624ef 100644 --- a/libs/common/src/dto/create-onramp-swap.dto.ts +++ b/libs/common/src/dto/create-onramp-swap.dto.ts @@ -53,7 +53,7 @@ export class CreateOnrampSwapDto implements OnrampSwapRequest { @IsString() @Type(() => String) @ApiProperty() - ref: string; + reference: string; @IsNotEmpty() @IsString() diff --git a/libs/common/src/dto/quote.dto.ts b/libs/common/src/dto/quote.dto.ts index e74a826..88bb8da 100644 --- a/libs/common/src/dto/quote.dto.ts +++ b/libs/common/src/dto/quote.dto.ts @@ -1,9 +1,15 @@ import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { IsBoolean, IsString } from 'class-validator'; export class QuoteDto { + @IsString() + @Type(() => String) @ApiProperty() id: string; + @IsBoolean() + @Type(() => Boolean) @ApiProperty() refreshIfExpired: boolean; } diff --git a/libs/common/src/types/proto/swap.ts b/libs/common/src/types/proto/swap.ts index ca2d05c..01573f1 100644 --- a/libs/common/src/types/proto/swap.ts +++ b/libs/common/src/types/proto/swap.ts @@ -88,7 +88,7 @@ export interface OnrampSwapRequest { */ quote?: Quote | undefined; /** Swap initiator reference to the account this transaction is associated with. */ - ref: string; + reference: string; /** * Amount to swap * Any transaction fees will be deducted from this amount @@ -118,6 +118,8 @@ export interface OfframpSwapRequest { * If not specified, the service will create a new quote for the swap */ quote?: Quote | undefined; + /** Swap initiator reference to the account this transaction is associated with. */ + reference: string; /** * Amount to swap * Any transaction fees will be deducted from this amount diff --git a/proto/swap.proto b/proto/swap.proto index 4d345f2..3de2472 100644 --- a/proto/swap.proto +++ b/proto/swap.proto @@ -84,7 +84,7 @@ message OnrampSwapRequest { optional Quote quote = 1; // Swap initiator reference to the account this transaction is associated with. - string ref = 2; + string reference = 2; // Amount to swap // Any transaction fees will be deducted from this amount @@ -117,12 +117,15 @@ message OfframpSwapRequest { // If not specified, the service will create a new quote for the swap optional Quote quote = 1; + // Swap initiator reference to the account this transaction is associated with. + string reference = 2; + // Amount to swap // Any transaction fees will be deducted from this amount - string amountFiat = 2; + string amountFiat = 3; // Target of the swap - OfframpSwapTarget target = 3; + OfframpSwapTarget target = 4; } message OfframpSwapTarget {