Skip to content

Commit

Permalink
feat: define solowallet service
Browse files Browse the repository at this point in the history
  • Loading branch information
okjodom committed Nov 27, 2024
1 parent 5952d5d commit 963808e
Show file tree
Hide file tree
Showing 25 changed files with 384 additions and 13 deletions.
3 changes: 3 additions & 0 deletions apps/solowallet/.env.manual
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
NODE_ENV='development'
SOLOWALLET_GRPC_URL='0.0.0.0:4080'
DATABASE_URL=mongodb://bs:password@mongodb:27017
32 changes: 32 additions & 0 deletions apps/solowallet/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
FROM oven/bun:latest AS development

WORKDIR /usr/src/app

COPY package.json ./
COPY bun.lockb ./
COPY tsconfig.json tsconfig.json
COPY nest-cli.json nest-cli.json

COPY apps/solowallet apps/solowallet
COPY libs libs
COPY proto proto

RUN bun install
RUN bun build:solowallet

FROM oven/bun:latest AS production

ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}

WORKDIR /usr/src/app

COPY package.json ./
COPY bun.lockb ./

RUN bun install --production

COPY --from=development /usr/src/app/dist ./dist
COPY --from=development /usr/src/app/proto ./proto

CMD ["sh", "-c", "bun run dist/apps/solowallet/main.js"]
19 changes: 19 additions & 0 deletions apps/solowallet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# apps/solowallet

This app is a gRPC microservice for Bitsacco solo wallet.
The wallet full custodies ecash on behalf of individual members.
Members can withdraw at any time via lightning, or to fiat via integrated Bitsacco `swap` service.

## Dev

Run `bun dev solowallet` to launch the microservice in development mode.
Run `bun start` to launch this plus any other microservice and the REST api gateway in dev mode

## Docs

- See [solowallet.proto](https://github.com/bitsacco/os/blob/main/proto/solowallet.proto)
- With the microservice running, see supported gRPC methods with type reflection at http://localhost:4070

## Architecture

See [architecture.md](https://github.com/bitsacco/os/blob/main/docs/architecture.md)
2 changes: 2 additions & 0 deletions apps/solowallet/src/db/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './solowallet.repository';
export * from './solowallet.schema';
17 changes: 17 additions & 0 deletions apps/solowallet/src/db/solowallet.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { Injectable, Logger } from '@nestjs/common';
import { AbstractRepository } from '@bitsacco/common';
import { SolowalletDocument } from './solowallet.schema';

@Injectable()
export class SolowalletRepository extends AbstractRepository<SolowalletDocument> {
protected readonly logger = new Logger(SolowalletRepository.name);

constructor(
@InjectModel(SolowalletDocument.name)
reservationModel: Model<SolowalletDocument>,
) {
super(reservationModel);
}
}
14 changes: 14 additions & 0 deletions apps/solowallet/src/db/solowallet.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { AbstractDocument } from '@bitsacco/common';

@Schema({ versionKey: false })
export class SolowalletDocument extends AbstractDocument {
@Prop({ type: String, required: true })
userId: string;

@Prop({ type: Number, required: true })
quantity: number;
}

export const SolowalletSchema =
SchemaFactory.createForClass(SolowalletDocument);
33 changes: 33 additions & 0 deletions apps/solowallet/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { join } from 'path';
import { Logger } from 'nestjs-pino';
import { NestFactory } from '@nestjs/core';
import { ConfigService } from '@nestjs/config';
import { ReflectionService } from '@grpc/reflection';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { SolowalletModule } from './solowallet.module';

async function bootstrap() {
const app = await NestFactory.create(SolowalletModule);

const configService = app.get(ConfigService);

const solowallet_url = configService.getOrThrow<string>(
'SOLOWALLET_GRPC_URL',
);
const solowallet = app.connectMicroservice<MicroserviceOptions>({
transport: Transport.GRPC,
options: {
package: 'solowallet',
url: solowallet_url,
protoPath: join(__dirname, '../../../proto/solowallet.proto'),
onLoadPackageDefinition: (pkg, server) => {
new ReflectionService(pkg).addToServer(server);
},
},
});

// setup pino logging
app.useLogger(app.get(Logger));

await app.startAllMicroservices();
}
19 changes: 19 additions & 0 deletions apps/solowallet/src/solowallet.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { TestingModule } from '@nestjs/testing';
import { createTestingModuleWithValidation } from '@bitsacco/testing';
import { SolowalletController } from './solowallet.controller';
import { SolowalletService } from './solowallet.service';

describe('SolowalletController', () => {
let solowalletController: SolowalletController;
let solowalletService: SolowalletService;

beforeEach(async () => {
const app: TestingModule = await createTestingModuleWithValidation({
controllers: [SolowalletController],
providers: [SolowalletService],
});

solowalletController = app.get<SolowalletController>(SolowalletController);
solowalletService = app.get<SolowalletService>(SolowalletService);
});
});
16 changes: 16 additions & 0 deletions apps/solowallet/src/solowallet.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Controller, Get } from '@nestjs/common';
import { SolowalletService } from './solowallet.service';
import { GrpcMethod } from '@nestjs/microservices';
import { SolowalletServiceControllerMethods } from '@bitsacco/common';
import { DepositFundsRequestDto } from 'libs/common/src/dto/solowallet.dto';

@Controller()
@SolowalletServiceControllerMethods()
export class SolowalletController {
constructor(private readonly solowalletService: SolowalletService) {}

@GrpcMethod()
depositFunds(request: DepositFundsRequestDto): string {
return this.solowalletService.depositFunds(request);
}
}
32 changes: 32 additions & 0 deletions apps/solowallet/src/solowallet.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as Joi from 'joi';
import { Module } from '@nestjs/common';
import { DatabaseModule, LoggerModule } from '@bitsacco/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { SolowalletController } from './solowallet.controller';
import { SolowalletService } from './solowallet.service';
import {
SolowalletDocument,
SolowalletRepository,
SolowalletSchema,
} from './db';

@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
validationSchema: Joi.object({
NODE_ENV: Joi.string().required(),
SOLOWALLET_GRPC_URL: Joi.string().required(),
DATABASE_URL: Joi.string().required(),
}),
}),
DatabaseModule,
DatabaseModule.forFeature([
{ name: SolowalletDocument.name, schema: SolowalletSchema },
]),
LoggerModule,
],
controllers: [SolowalletController],
providers: [SolowalletService, ConfigService, SolowalletRepository],
})
export class SolowalletModule {}
18 changes: 18 additions & 0 deletions apps/solowallet/src/solowallet.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ConfigService } from '@nestjs/config';
import { Injectable, Logger } from '@nestjs/common';
import { DepositFundsRequestDto } from '@bitsacco/common';
import { SolowalletRepository } from './db';

@Injectable()
export class SolowalletService {
private readonly logger = new Logger(SolowalletService.name);

constructor(
private readonly wallet: SolowalletRepository,
private readonly configService: ConfigService,
) {
this.logger.log('SharesService created');
}

depositFunds({ userId, fiat_deposit }: DepositFundsRequestDto) {}
}
24 changes: 24 additions & 0 deletions apps/solowallet/test/app.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { SolowalletModule } from './../src/solowallet.module';

describe('SolowalletController (e2e)', () => {
let app: INestApplication;

beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [SolowalletModule],
}).compile();

app = moduleFixture.createNestApplication();
await app.init();
});

it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
});
});
9 changes: 9 additions & 0 deletions apps/solowallet/test/jest-e2e.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": ".",
"testEnvironment": "node",
"testRegex": ".e2e-spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
}
}
9 changes: 9 additions & 0 deletions apps/solowallet/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"declaration": false,
"outDir": "../../dist/apps/solowallet"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "test", "**/*spec.ts"]
}
1 change: 1 addition & 0 deletions libs/common/src/dto/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export * from './configure-nostr-relays.dto';
export * from './send-encrypted-nostr-dm.dto';
export * from './sms.dto';
export * from './shares.dto';
export * from './solowallet.dto';
18 changes: 18 additions & 0 deletions libs/common/src/dto/solowallet.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Type } from 'class-transformer';
import { IsNotEmpty, IsString, ValidateNested } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { CreateOnrampSwapDto } from './create-onramp-swap.dto';
import { DepositFundsRequest } from '../types';

export class DepositFundsRequestDto implements DepositFundsRequest {
@IsNotEmpty()
@IsString()
@Type(() => String)
@ApiProperty()
userId: string;

@ValidateNested()
@Type(() => CreateOnrampSwapDto)
@ApiProperty({ type: CreateOnrampSwapDto })
fiat_deposit?: CreateOnrampSwapDto;
}
1 change: 1 addition & 0 deletions libs/common/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './proto/swap';
export * from './proto/nostr';
export * from './proto/sms';
export * from './proto/shares';
export * from './proto/solowallet';
export * from './api';
export * from './validator';
export * from './fedimint';
12 changes: 12 additions & 0 deletions libs/common/src/types/proto/lightning.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 63 additions & 0 deletions libs/common/src/types/proto/solowallet.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 1 addition & 5 deletions libs/common/src/types/proto/swap.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 963808e

Please sign in to comment.