Skip to content

Commit

Permalink
Search for flyover txs
Browse files Browse the repository at this point in the history
  • Loading branch information
lserra-iov committed May 3, 2024
1 parent 6a080c2 commit b5484a1
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 9 deletions.
26 changes: 24 additions & 2 deletions src/__tests__/unit/tx-status.controller.unit.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {TxStatusController} from "../../controllers";
import {PeginStatusService, PegoutStatusService} from "../../services";
import {PeginStatusService, PegoutStatusService, RegisterFlyoverService} from "../../services";
import {createStubInstance, expect, StubbedInstanceWithSinonAccessor} from "@loopback/testlab";
import {BtcPeginStatus, PeginStatus, RskPeginStatus, Status, TxStatus, TxStatusType} from "../../models";
import {PeginStatus as RskPeginStatusEnum} from "../../models/rsk/pegin-status-data.model";
Expand All @@ -18,11 +18,13 @@ describe('Controller: Tx Status', () => {
let txStatusController: TxStatusController;
let peginStatusService: StubbedInstanceWithSinonAccessor<PeginStatusService>;
let pegoutStatusService: StubbedInstanceWithSinonAccessor<PegoutStatusService>;
let flyoverService: StubbedInstanceWithSinonAccessor<RegisterFlyoverService>;

function resetController() {
peginStatusService = createStubInstance(PeginStatusService);
pegoutStatusService = createStubInstance(PegoutStatusService);
txStatusController = new TxStatusController(peginStatusService, pegoutStatusService);
flyoverService = createStubInstance(RegisterFlyoverService);
txStatusController = new TxStatusController(peginStatusService, pegoutStatusService, flyoverService);
}
function getMockedPeginStatus(mockedTxId: string,status: Status): PeginStatus {
const btcPeginStatus = new BtcPeginStatus(mockedTxId);
Expand Down Expand Up @@ -189,5 +191,25 @@ describe('Controller: Tx Status', () => {
expect(pegoutStatusService.stubs.getPegoutStatusByRskTxHash.notCalled).to.be.true();
expect(status.type).to.be.eql(TxStatusType.INVALID_DATA);
});
it('should search for flyover transactions if there is no pegin or pegout status', async () => {
peginStatusService.stubs.getPeginSatusInfo.withArgs(testRskTxHash)
.resolves(getMockedPeginStatus(testRskTxHash, Status.ERROR_NOT_A_PEGIN));
pegoutStatusService.stubs.getPegoutStatusByRskTxHash.withArgs(testRskTxHash)
.resolves(getMockedPegoutStatus(testRskTxHash, PegoutStatus.NOT_FOUND));
flyoverService.stubs.getFlyoverStatus.withArgs(testRskTxHash)
.resolves({
status: 'COMPLETED',
type: 'pegout',
txHash: testRskTxHash,
date: +new Date(),
amount: 0.005,
fee: 0.00001,
});
const status = await txStatusController.getTxStatus(testRskTxHash);
expect(peginStatusService.stubs.getPeginSatusInfo.calledOnce).to.be.true();
expect(pegoutStatusService.stubs.getPegoutStatusByRskTxHash.calledOnce).to.be.true();
expect(flyoverService.stubs.getFlyoverStatus.calledOnce).to.be.true();
expect(status.type).to.be.eql(TxStatusType.FLYOVER_PEGOUT);
});
});
});
3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ export const ENVIRONMENT_DEVELOPMENT = 'development';
// transaction types
export const TX_TYPE_PEGIN = 'pegin';
export const TX_TYPE_PEGOUT = 'pegout';
// flyover status
export const FLYOVER_STATUS_PENDING = 'PENDING';
export const FLYOVER_STATUS_COMPLETED = 'COMPLETED';
46 changes: 39 additions & 7 deletions src/controllers/tx-status.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import {inject} from "@loopback/core";
import {PeginStatus, Status, TxStatus, TxStatusType} from '../models';
import {PeginStatusError} from "../models/pegin-status-error.model";
import {ServicesBindings} from "../dependency-injection-bindings";
import {PeginStatusService, PegoutStatusService} from "../services";
import {PeginStatusService, PegoutStatusService, RegisterFlyoverService} from "../services";
import {PegoutStatus} from "../models/rsk/pegout-status-data-model";
import { ensure0x, remove0x } from '../utils/hex-utils';
import { isValidTxId } from '../utils/tx-validator';
import {ensure0x, remove0x} from '../utils/hex-utils';
import {isValidTxId} from '../utils/tx-validator';
import {TX_TYPE_PEGIN, TX_TYPE_PEGOUT} from '../constants';


export class TxStatusController {
private logger: Logger;
Expand All @@ -16,7 +18,9 @@ export class TxStatusController {
@inject(ServicesBindings.PEGIN_STATUS_SERVICE)
protected peginStatusService: PeginStatusService,
@inject(ServicesBindings.PEGOUT_STATUS_SERVICE)
protected pegoutStatusService: PegoutStatusService
protected pegoutStatusService: PegoutStatusService,
@inject(ServicesBindings.REGISTER_FLYOVER_SERVICE)
protected registerFlyoverService: RegisterFlyoverService,
) {
this.logger = getLogger('TxStatusController');
}
Expand Down Expand Up @@ -75,13 +79,41 @@ export class TxStatusController {
});
return txStatus;
}
this.logger.warn(`[getTxStatus] a pegout for the provided tx id not found: ${txHash}`);
} catch (e) {
this.logger.warn(`[getTxStatus] Unexpected error while retrieving a pegout status: [${e}]`);
txStatus = new TxStatus({
type: TxStatusType.INVALID_DATA,
type: TxStatusType.UNEXPECTED_ERROR,
});
return txStatus;
}

try {
this.logger.debug(`[getTxStatus] trying to get a flyover status with txHash: ${txId}`);
const flyoverStatus = await this.registerFlyoverService.getFlyoverStatus(txId);
if (flyoverStatus) {
this.logger.debug(`[getTxStatus] Flyover status got for txId ${txId} - Status: ${flyoverStatus.status}`);
if (flyoverStatus.type === TX_TYPE_PEGIN) {
txStatus = new TxStatus({
type: TxStatusType.FLYOVER_PEGIN,
txDetails: flyoverStatus,
});
return txStatus;
}
if (flyoverStatus.type === TX_TYPE_PEGOUT) {
txStatus = new TxStatus({
type: TxStatusType.FLYOVER_PEGOUT,
txDetails: flyoverStatus,
});
return txStatus;
}
}
this.logger.warn(`[getTxStatus] no tx found for the provided tx id: ${txId}`);
txStatus = new TxStatus({
type: TxStatusType.INVALID_DATA, // no tx found
});
return txStatus;
} catch (e) {
this.logger.warn(`[getTxStatus] Unexpected error while retrieving a pegout status: [${e}]`);
this.logger.warn(`[getTxStatus] Unexpected error while retrieving a flyover status: [${e}]`);
txStatus = new TxStatus({
type: TxStatusType.UNEXPECTED_ERROR,
});
Expand Down
2 changes: 2 additions & 0 deletions src/models/tx-status.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export class TxStatus extends Model {
export enum TxStatusType {
PEGIN = 'PEGIN',
PEGOUT = 'PEGOUT',
FLYOVER_PEGIN = 'FLYOVER_PEGIN',
FLYOVER_PEGOUT = 'FLYOVER_PEGOUT',
INVALID_DATA = 'INVALID_DATA',
UNEXPECTED_ERROR = 'UNEXPECTED_ERROR',
}
22 changes: 22 additions & 0 deletions src/services/register-flyover.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {RegisterPayload} from '../models';
import {FlyoverStatusModel} from '../models/flyover-status.model';
import {MongoDbDataService} from './mongodb-data.service';
import { RskNodeService } from './rsk-node.service';
import * as constants from '../constants';

interface FlyoverStatusMongoModel extends mongoose.Document, FlyoverStatusModel {}

Expand Down Expand Up @@ -45,6 +46,27 @@ export class RegisterFlyoverService extends MongoDbDataService<FlyoverStatusMode
return filter;
}

async getFlyoverStatus(txHash: string): Promise<any> {
let status;
const flyoverTx = await this.getById(txHash);
if (!flyoverTx) return null;

const currentBlock = await this.rskNodeService.getBlockNumber();
if (flyoverTx.blockToBeFinished <= currentBlock) {
status = constants.FLYOVER_STATUS_COMPLETED;
} else {
status = constants.FLYOVER_STATUS_PENDING;
}

return {
txHash: flyoverTx.txHash,
date: flyoverTx.date,
type: flyoverTx.type,
amount: flyoverTx.amount,
fee: flyoverTx.fee,
status,
};
}

async register(payload: RegisterPayload): Promise<boolean> {
const currentBlock = await this.rskNodeService.getBlockNumber();
Expand Down

0 comments on commit b5484a1

Please sign in to comment.