From f0ca0e6dd5c095b0db4f0ef80ae151b00cdbc966 Mon Sep 17 00:00:00 2001 From: "ducnv1911@gmail.com" Date: Fri, 18 Mar 2022 10:49:50 +0700 Subject: [PATCH 1/3] Change transaction status when reject user greater than threshold --- .../impls/multisig-transaction.service.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/services/impls/multisig-transaction.service.ts b/src/services/impls/multisig-transaction.service.ts index 89f779e0..936f4dbd 100644 --- a/src/services/impls/multisig-transaction.service.ts +++ b/src/services/impls/multisig-transaction.service.ts @@ -24,6 +24,7 @@ import { IGeneralRepository, IMultisigConfirmRepository, IMultisigTransactionsRepository, + IMultisigWalletOwnerRepository, IMultisigWalletRepository, } from 'src/repositories'; import { ConfirmTransactionRequest } from 'src/dtos/requests'; @@ -44,6 +45,8 @@ export class MultisigTransactionService private chainRepos: IGeneralRepository, @Inject(REPOSITORY_INTERFACE.IMULTISIG_WALLET_REPOSITORY) private safeRepos: IMultisigWalletRepository, + @Inject(REPOSITORY_INTERFACE.IMULTISIG_WALLET_OWNER_REPOSITORY) + private safeOwnerRepo: IMultisigWalletOwnerRepository, ) { super(multisigTransactionRepos); this._logger.log( @@ -181,6 +184,24 @@ export class MultisigTransactionService MULTISIG_CONFIRM_STATUS.REJECT, ); + let rejectConfirms = await this.multisigConfirmRepos.findByCondition({ + multisigTransactionId: request.transactionId, + status: MULTISIG_CONFIRM_STATUS.REJECT, + }); + + let safeOwner = await this.safeOwnerRepo.findByCondition({ + safeId: transaction.safeId + }); + + let safe = await this.safeRepos.findOne({ + where: { id: transaction.safeId }, + }); + + if (safeOwner.length - rejectConfirms.length < safe.threshold) { + transaction.status = TRANSACTION_STATUS.CANCELLED; + await this.multisigTransactionRepos.update(transaction); + } + return res.return(ErrorMap.SUCCESSFUL); } catch (error) { return ResponseDto.responseError(MultisigTransactionService.name, error); From 81ff7ea27e8c6e0db3bf5faa983556b070d76846 Mon Sep 17 00:00:00 2001 From: "ducnv1911@gmail.com" Date: Fri, 18 Mar 2022 16:11:07 +0700 Subject: [PATCH 2/3] Validate input param --- .../confirm-multisig-wallet.request.ts | 2 ++ .../connect-multisig-wallet.request.ts | 4 ++++ .../create-multisig-wallet.request.ts | 6 ++++++ .../delete-multisig-wallet.request.ts | 1 + .../multisig-wallet/get-safe-by-owner.request.ts | 3 ++- .../transaction/confirm-transaction.request.ts | 6 ++++++ .../transaction/create-transaction.request.ts | 12 ++++++++++++ .../transaction/get-all-transactions.request.ts | 5 +++++ .../transaction/reject-transaction.request.ts | 4 ++++ .../requests/transaction/send-transaction.request.ts | 4 ++++ 10 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/dtos/requests/multisig-wallet/confirm-multisig-wallet.request.ts b/src/dtos/requests/multisig-wallet/confirm-multisig-wallet.request.ts index 0f075747..e2961bc7 100644 --- a/src/dtos/requests/multisig-wallet/confirm-multisig-wallet.request.ts +++ b/src/dtos/requests/multisig-wallet/confirm-multisig-wallet.request.ts @@ -2,9 +2,11 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsString } from 'class-validator'; export class ConfirmMultisigWalletRequest { + @IsString() @ApiProperty() myAddress: string; + @IsString() @ApiProperty() myPubkey: string; } diff --git a/src/dtos/requests/multisig-wallet/connect-multisig-wallet.request.ts b/src/dtos/requests/multisig-wallet/connect-multisig-wallet.request.ts index 76d1da0b..9abe5e2c 100644 --- a/src/dtos/requests/multisig-wallet/connect-multisig-wallet.request.ts +++ b/src/dtos/requests/multisig-wallet/connect-multisig-wallet.request.ts @@ -1,12 +1,16 @@ import { ApiProperty } from '@nestjs/swagger'; +import { IsString } from 'class-validator'; export class ConnectMultisigWalletRequest { + @IsString() @ApiProperty() owner_address: string; + @IsString() @ApiProperty() chainId: string; + @IsString() @ApiProperty() safe_address: string; } \ No newline at end of file diff --git a/src/dtos/requests/multisig-wallet/create-multisig-wallet.request.ts b/src/dtos/requests/multisig-wallet/create-multisig-wallet.request.ts index dfc3dec2..85b654ff 100644 --- a/src/dtos/requests/multisig-wallet/create-multisig-wallet.request.ts +++ b/src/dtos/requests/multisig-wallet/create-multisig-wallet.request.ts @@ -1,18 +1,24 @@ import { ApiProperty } from '@nestjs/swagger'; +import { IsNumber, IsString } from 'class-validator'; export class CreateMultisigWalletRequest { + @IsString() @ApiProperty() creatorAddress: string; + @IsString() @ApiProperty() creatorPubkey: string; + @IsString() @ApiProperty({ type: [String] }) otherOwnersAddress: string[]; + @IsNumber() @ApiProperty() threshold: number; + @IsNumber() @ApiProperty() internalChainId: number; } diff --git a/src/dtos/requests/multisig-wallet/delete-multisig-wallet.request.ts b/src/dtos/requests/multisig-wallet/delete-multisig-wallet.request.ts index 19ed8559..ec62eff9 100644 --- a/src/dtos/requests/multisig-wallet/delete-multisig-wallet.request.ts +++ b/src/dtos/requests/multisig-wallet/delete-multisig-wallet.request.ts @@ -2,6 +2,7 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsString } from 'class-validator'; export class DeleteMultisigWalletRequest { + @IsString() @ApiProperty() myAddress: string; } diff --git a/src/dtos/requests/multisig-wallet/get-safe-by-owner.request.ts b/src/dtos/requests/multisig-wallet/get-safe-by-owner.request.ts index f1a86d41..bb5874be 100644 --- a/src/dtos/requests/multisig-wallet/get-safe-by-owner.request.ts +++ b/src/dtos/requests/multisig-wallet/get-safe-by-owner.request.ts @@ -1,7 +1,8 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty } from 'class-validator'; +import { IsNotEmpty, IsNumber } from 'class-validator'; export class GetSafesByOwnerAddressQuery { + @IsNumber() @ApiProperty() internalChainId: number; } diff --git a/src/dtos/requests/transaction/confirm-transaction.request.ts b/src/dtos/requests/transaction/confirm-transaction.request.ts index c41f8b15..74d48c10 100644 --- a/src/dtos/requests/transaction/confirm-transaction.request.ts +++ b/src/dtos/requests/transaction/confirm-transaction.request.ts @@ -1,30 +1,36 @@ import { ApiProperty } from '@nestjs/swagger'; +import { IsNumber, IsString } from 'class-validator'; export class ConfirmTransactionRequest { + @IsString() @ApiProperty({ description: 'Owner address', example: 'aura1l5k37zpxp3ukty282kn6r7kf8rqh7cve0ggq2w' }) fromAddress: string; + @IsNumber() @ApiProperty({ description: 'Offchain Transaction Id', example: 14 }) transactionId: number; + @IsString() @ApiProperty({ description: 'Owner sign transaction via wallet then get bodyBytes', example: 'CosBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmsKK2F1cmExNnVyaHBuM3hqY2phMGZydjc1MHR5M3c2MnFkOHNraHQ3ZTN0bGgSK2F1cmExbDVrMzd6cHhwM3VrdHkyODJrbjZyN2tmOHJxaDdjdmUwZ2dxMncaDwoFdWF1cmESBjEwMDAwMBIWVXNlIHlvdXIgdG9rZW5zIHdpc2VseQ==' }) bodyBytes: string; + @IsString() @ApiProperty({ description: 'Owner sign transaction via wallet then get transaction', example: 'd20oaWycg+cT7kWAK/rhoM8zBzHbPhAr4J3ZoTbnLyIXNB4tHuVqrBRae5Qs2mh3FAezZHx2WE1/auQYudZQyw==' }) signature: string; + @IsNumber() @ApiProperty({ description: 'Offline Chain Id', example: 4 diff --git a/src/dtos/requests/transaction/create-transaction.request.ts b/src/dtos/requests/transaction/create-transaction.request.ts index f3061d05..0285e212 100644 --- a/src/dtos/requests/transaction/create-transaction.request.ts +++ b/src/dtos/requests/transaction/create-transaction.request.ts @@ -1,54 +1,66 @@ import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsNumber, IsString } from 'class-validator'; export class CreateTransactionRequest { + @IsString() + @IsNotEmpty() @ApiProperty({ description: 'Address of safe', example: 'aura1328x7tacz28w96zl4j50qnfg4gqjdd56wqd3ke' }) from: string; + @IsString() + @IsNotEmpty() @ApiProperty({ description: 'Address of receiver', example: 'aura136v0nmlv0saryev8wqz89w80edzdu3quzm0ve9' }) to: string; + @IsNumber() @ApiProperty({ description: 'Transaction amount', example: 3000000 }) amount: number; + @IsNumber() @ApiProperty({ description: 'Transaction fee', example: 0.01 }) fee: number; + @IsNumber() @ApiProperty({ description: 'Transaction gas limit', example: 100000 }) gasLimit: number; + @IsNumber() @ApiProperty({ description: 'Offline Chain Id', example: 4 }) internalChainId: number; + @IsString() @ApiProperty({ description: 'Owner who create transaction must sign transaction via wallet first. Then get bodyBytes of result.', example: 'CogBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmgKK2F1cmExMzJha3g5OTg5Y2FueHV6a2ZqbnJneHd5Y2NmY210ZnpobWZscW0SK2F1cmExdHVlaDRodnJmbmZ3c3VobDMyd21sbWV2NjU2bmhxc2t2cTd0N3QaDAoFdWF1cmESAzIwMBIA' }) bodyBytes: string; + @IsString() @ApiProperty({ description: 'Owner who create transaction must sign transaction via wallet first. Then get signature of result.', example: 'Dj8pEXMADBGCjaRSAQwT1/7s+6fRrf985UZL2ujo0YMe+M2VEqYLERkc5tsrg8HAWuqzKVq5CV6a7KcOSgjNtw==' }) signature: string; + @IsString() @ApiProperty({ description: 'Address of owner who create transaction', example: 'aura13t8ej6yvje8n9zl7hcvj8ks24tp5qvdsgfhnjx' diff --git a/src/dtos/requests/transaction/get-all-transactions.request.ts b/src/dtos/requests/transaction/get-all-transactions.request.ts index 62b0b6a2..53150473 100644 --- a/src/dtos/requests/transaction/get-all-transactions.request.ts +++ b/src/dtos/requests/transaction/get-all-transactions.request.ts @@ -1,21 +1,26 @@ import { ApiProperty } from "@nestjs/swagger"; +import { IsBoolean, IsNumber, IsString } from "class-validator"; export class GetAllTransactionsRequest { + @IsString() @ApiProperty({ example: 'aura16urhpn3xjcja0frv750ty3w62qd8skht7e3tlh' }) safeAddress: string; + @IsBoolean() @ApiProperty({ example: true }) isHistory: boolean; + @IsNumber() @ApiProperty({ example: 10 }) pageSize: number; + @IsNumber() @ApiProperty({ example: 1 }) diff --git a/src/dtos/requests/transaction/reject-transaction.request.ts b/src/dtos/requests/transaction/reject-transaction.request.ts index e82b910f..2f8f1106 100644 --- a/src/dtos/requests/transaction/reject-transaction.request.ts +++ b/src/dtos/requests/transaction/reject-transaction.request.ts @@ -1,18 +1,22 @@ import { ApiProperty } from '@nestjs/swagger'; +import { IsNumber, IsString } from 'class-validator'; export class RejectTransactionRequest { + @IsString() @ApiProperty({ description: 'Owner Address', example: 'aura1l5k37zpxp3ukty282kn6r7kf8rqh7cve0ggq2w' }) fromAddress: string; + @IsNumber() @ApiProperty({ description: 'Offchain Transaction Id', example: 14 }) transactionId: number; + @IsNumber() @ApiProperty({ description: 'Offchain Chain Id', example: 4 diff --git a/src/dtos/requests/transaction/send-transaction.request.ts b/src/dtos/requests/transaction/send-transaction.request.ts index 297bcb87..609ec2ba 100644 --- a/src/dtos/requests/transaction/send-transaction.request.ts +++ b/src/dtos/requests/transaction/send-transaction.request.ts @@ -1,18 +1,22 @@ import { ApiProperty } from '@nestjs/swagger'; +import { IsNumber, IsString } from 'class-validator'; export class SendTransactionRequest { + @IsNumber() @ApiProperty({ description: 'Offchain Transaction Id', example: 14 }) transactionId: number; + @IsNumber() @ApiProperty({ description: 'Offchain Chain Id', example: 4 }) internalChainId: number; + @IsString() @ApiProperty({ description: 'Owner who broadcast transaction', example: 'aura1l5k37zpxp3ukty282kn6r7kf8rqh7cve0ggq2w' From 9b7953a22ccb08eb5d32c85fa75e172bb483ec8f Mon Sep 17 00:00:00 2001 From: "ducnv1911@gmail.com" Date: Fri, 18 Mar 2022 16:29:36 +0700 Subject: [PATCH 3/3] Change source check Vulnerabilities --- README.md | 2 +- .../responses/general/get-account-onchain.response.ts | 5 +++++ src/dtos/responses/general/network-list.response.ts | 8 ++++++++ .../multisig-transaction/multisig-signature.response.ts | 7 +++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e5a8d350..88daebcb 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/aura-nw/multisig-api/issues) [![codecov](https://img.shields.io/codecov/c/gh/aura-nw/multisig-api/dev?style=flat-square&token=FNWOTPBIRX)](https://codecov.io/gh/aura-nw/multisig-api) -[![Known Vulnerabilities](https://snyk.io/test/github/aura-nw/multisig-api/badge.svg)](https://snyk.io/test/github/aura-nw/multisig-api/) +[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=aura-nw_multisig-api&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=aura-nw_multisig-api) [![Maintainability](https://api.codeclimate.com/v1/badges/670351cb6c558dc7d9c2/maintainability)](https://codeclimate.com/github/aura-nw/multisig-api/maintainability) # Overview diff --git a/src/dtos/responses/general/get-account-onchain.response.ts b/src/dtos/responses/general/get-account-onchain.response.ts index 5387387b..5fb09cdd 100644 --- a/src/dtos/responses/general/get-account-onchain.response.ts +++ b/src/dtos/responses/general/get-account-onchain.response.ts @@ -1,12 +1,15 @@ import { Pubkey } from "@cosmjs/amino"; import { ApiProperty } from "@nestjs/swagger"; +import { IsNumber, IsString } from "class-validator"; export class GetAccountOnchainResponse { + @IsString() @ApiProperty({ example: 'aura1r2gv6rx0fxdmepu8gd2gmn5j8cjetkqrw836x5' }) address: string; + @IsString() @ApiProperty({ example: { type: 'tendermint/PubKeyMultisigThreshold', @@ -23,11 +26,13 @@ export class GetAccountOnchainResponse { }) pubkey: Pubkey; + @IsNumber() @ApiProperty({ example: 39 }) accountNumber: number; + @IsNumber() @ApiProperty({ example: 13 }) diff --git a/src/dtos/responses/general/network-list.response.ts b/src/dtos/responses/general/network-list.response.ts index 62066890..003bd5a5 100644 --- a/src/dtos/responses/general/network-list.response.ts +++ b/src/dtos/responses/general/network-list.response.ts @@ -1,36 +1,44 @@ import { ApiProperty } from "@nestjs/swagger"; +import { IsNumber, IsString } from "class-validator"; export class NetworkListResponse { + @IsNumber() @ApiProperty({ example: 13 }) id: number; + @IsString() @ApiProperty({ example: 'Aura Testnet' }) name: string; + @IsString() @ApiProperty({ example: 'https://rpc-testnet.aura.network' }) rest: string; + @IsString() @ApiProperty({ example: 'https://tendermint-testnet.aura.network' }) rpc: string; + @IsString() @ApiProperty({ example: 'aura-testnet' }) chainId: string; + @IsString() @ApiProperty({ example: 'uaura' }) denom: string; + @IsString() @ApiProperty({ example: 'aura' }) diff --git a/src/dtos/responses/multisig-transaction/multisig-signature.response.ts b/src/dtos/responses/multisig-transaction/multisig-signature.response.ts index 5c265d49..34a2add2 100644 --- a/src/dtos/responses/multisig-transaction/multisig-signature.response.ts +++ b/src/dtos/responses/multisig-transaction/multisig-signature.response.ts @@ -1,31 +1,38 @@ import { ApiProperty } from "@nestjs/swagger"; +import { IsDate, IsNumber, IsString } from "class-validator"; export class MultisigSignatureResponse { + @IsNumber() @ApiProperty({ example: 1 }) id: number; + @IsDate() @ApiProperty({ example: '2022-02-24T09:44:52.935Z' }) createdAt: Date; + @IsDate() @ApiProperty({ example: '2022-02-24T09:44:52.935Z' }) updatedAt: Date; + @IsString() @ApiProperty({ example: 'aura15f6wn3nymdnhnh5ddlqletuptjag09tryrtpq5' }) ownerAddress: string; + @IsString() @ApiProperty({ example: 'IIo33eqegxuCl/Nx9p0Bfhlvz1y+Qr1ZVeJHQVRX2e4EW0sotraMTUyEAb3pNbQ8cgkiwIimFf73yUapGoLnmw==' }) signature: string; + @IsString() @ApiProperty({ example: 'CONFIRM' })