├── .env.template ├── .gitattributes ├── .gitignore ├── .nvmrc ├── LICENSE ├── README.md ├── box-img-lg.png ├── box-img-sm.png ├── contracts ├── ConvertLib.sol ├── MetaCoin.sol └── Migrations.sol ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── nest-cli.json ├── package-lock.json ├── package.json ├── src ├── app.module.ts ├── common │ └── validation │ │ ├── is-address.pipe.ts │ │ └── is-not-empty-string.pipe.ts ├── connection │ ├── connection.module.ts │ └── connection.service.ts ├── main.ts └── metacoin │ ├── dto │ └── signed-transfer.dto.ts │ ├── metacoin.controller.ts │ ├── metacoin.module.ts │ └── metacoin.service.ts ├── test ├── TestMetaCoin.sol ├── jest-e2e.json └── metacoin.js ├── truffle-box.json ├── truffle-config.js ├── tsconfig.build.json └── tsconfig.json /.env.template: -------------------------------------------------------------------------------- 1 | APP_HOST= 2 | APP_PORT= 3 | 4 | METACOIN_ADDRESS= -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | build/ 107 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v18.12.0 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Truffle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
4 | 5 | # Truffle-NestJS-Box 6 | To Be Used as Truffle Box Creating API Endpoints for 7 | Ethereum Blockchain. 8 | 9 | We use personalised blockchain for Ethereum BlockChain 10 | Development. This personalised blockchain is made in the 11 | GanacheCLI. 12 | 13 | The Smart Contract Written in solidity language 14 | is deployed on this Ethereum Blockchain. Smart Contract is 15 | Immutable hence, once deployed it can't be changed. 16 | 17 | A truffle box to serve as the foundation of any Truffle and Nest.js dApp. 18 | 19 | **Pre-Requisites** 20 | 1. [nvm](https://github.com/nvm-sh/nvm#installing-and-updating) 21 | 2. [npx](https://www.npmjs.com/package/npx#install) 22 | 23 | **Installation** 24 | 1. Set correct Node.js version. 25 | ``` 26 | nvm use 27 | ``` 28 | 29 | 2. Install necessary dependencies. 30 | ``` 31 | npm clean-install 32 | ``` 33 | 34 | 3. Run the ganache-cli. 35 | ``` 36 | npx ganache 37 | ``` 38 | 39 | 4. Now these contracts need to be compiled and deployed on the Blockchain. For this, run `npx truffle migrate` inside project root directory. 40 | 5. You can see that a new `/build` folder has been created in the root directory which contains the compiled contracts. 41 | 6. Create `.env` file in root directory and pass to `METACOIN_ADDRESS` address of created contract from blockchain network. (You have `.env.template` as a sample) 42 | 7. To run the Node server `npm start`. 43 | 8. Server will be available on `http://${APP_HOST}:${APP_PORT}/`. 44 | 45 | **Collaborators** 46 | 1. [Illia Khvost](https://github.com/ikhvost) 47 | 2. [Bohdan Titov](https://github.com/titovb) 48 | 2. [Philip Schulz-Klingauf](https://github.com/pschulzk) 49 | -------------------------------------------------------------------------------- /box-img-lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikhvost/truffle-nest-box/23ee8f1692e8c4c9fdb3d59096bc627440fabe23/box-img-lg.png -------------------------------------------------------------------------------- /box-img-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikhvost/truffle-nest-box/23ee8f1692e8c4c9fdb3d59096bc627440fabe23/box-img-sm.png -------------------------------------------------------------------------------- /contracts/ConvertLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.25 <0.7.0; 3 | 4 | library ConvertLib{ 5 | function convert(uint amount,uint conversionRate) public pure returns (uint convertedAmount) 6 | { 7 | return amount * conversionRate; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /contracts/MetaCoin.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.25 <0.7.0; 3 | 4 | import "./ConvertLib.sol"; 5 | 6 | // This is just a simple example of a coin-like contract. 7 | // It is not standards compatible and cannot be expected to talk to other 8 | // coin/token contracts. If you want to create a standards-compliant 9 | // token, see: https://github.com/ConsenSys/Tokens. Cheers! 10 | 11 | contract MetaCoin { 12 | mapping (address => uint) balances; 13 | 14 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 15 | 16 | constructor() public { 17 | balances[tx.origin] = 10000; 18 | } 19 | 20 | function sendCoin(address receiver, uint amount) public returns(bool sufficient) { 21 | if (balances[msg.sender] < amount) return false; 22 | balances[msg.sender] -= amount; 23 | balances[receiver] += amount; 24 | emit Transfer(msg.sender, receiver, amount); 25 | return true; 26 | } 27 | 28 | function getBalanceInEth(address addr) public view returns(uint){ 29 | return ConvertLib.convert(getBalance(addr),2); 30 | } 31 | 32 | function getBalance(address addr) public view returns(uint) { 33 | return balances[addr]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.25 <0.7.0; 3 | 4 | contract Migrations { 5 | address public owner; 6 | uint public last_completed_migration; 7 | 8 | modifier restricted() { 9 | if (msg.sender == owner) _; 10 | } 11 | 12 | constructor() public { 13 | owner = msg.sender; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | const ConvertLib = artifacts.require("ConvertLib"); 2 | const MetaCoin = artifacts.require("MetaCoin"); 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(ConvertLib); 6 | deployer.link(ConvertLib, MetaCoin); 7 | deployer.deploy(MetaCoin); 8 | }; 9 | -------------------------------------------------------------------------------- /nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src" 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "truffle-nest-box", 3 | "version": "0.0.1", 4 | "description": "This box comes with everything you need to get started with Nest.js and Truffle", 5 | "keywords": [ 6 | "nestjs", 7 | "truffle", 8 | "ethers", 9 | "typescript" 10 | ], 11 | "author": "ikhvost & titovb", 12 | "license": "MIT", 13 | "scripts": { 14 | "prebuild": "rimraf dist", 15 | "build": "nest build", 16 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 17 | "start": "nest start", 18 | "start:dev": "nest start --watch", 19 | "start:debug": "nest start --debug --watch", 20 | "start:prod": "node dist/main", 21 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 22 | "test": "jest", 23 | "test:watch": "jest --watch", 24 | "test:cov": "jest --coverage", 25 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 26 | "test:e2e": "jest --config ./test/jest-e2e.json" 27 | }, 28 | "dependencies": { 29 | "@nestjs/cli": "^9.5.0", 30 | "@nestjs/common": "^9.4.1", 31 | "@nestjs/config": "^2.3.2", 32 | "@nestjs/core": "^9.4.1", 33 | "@nestjs/platform-express": "^9.4.1", 34 | "@nestjs/swagger": "^6.3.0", 35 | "class-transformer": "^0.5.1", 36 | "class-validator": "0.14.0", 37 | "ethers": "^6.3.0", 38 | "reflect-metadata": "^0.1.13", 39 | "rimraf": "^4.4.1", 40 | "rxjs": "^7.8.1" 41 | }, 42 | "jest": { 43 | "moduleFileExtensions": [ 44 | "js", 45 | "json", 46 | "ts" 47 | ], 48 | "rootDir": "src", 49 | "testRegex": ".spec.ts$", 50 | "transform": { 51 | "^.+\\.(t|j)s$": "ts-jest" 52 | }, 53 | "coverageDirectory": "../coverage", 54 | "testEnvironment": "node" 55 | }, 56 | "devDependencies": { 57 | "@nestjs/schematics": "^9.2.0", 58 | "@nestjs/testing": "^9.4.1", 59 | "@types/express": "^4.17.17", 60 | "@types/express-serve-static-core": "^4.17.35", 61 | "@types/jest": "^29.5.1", 62 | "@types/node": "^20.2.1", 63 | "@types/supertest": "^2.0.12", 64 | "@typescript-eslint/eslint-plugin": "^5.59.6", 65 | "@typescript-eslint/parser": "^5.59.6", 66 | "eslint": "^8.40.0", 67 | "eslint-config-prettier": "^8.8.0", 68 | "eslint-plugin-import": "^2.27.5", 69 | "ganache": "^7.8.0", 70 | "jest": "^29.5.0", 71 | "prettier": "^2.8.8", 72 | "supertest": "^6.3.3", 73 | "truffle": "^5.9.0", 74 | "ts-jest": "^29.1.0", 75 | "ts-loader": "^9.4.2", 76 | "ts-node": "^10.9.1", 77 | "tsconfig-paths": "^4.2.0", 78 | "typescript": "^5.0.4" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MetacoinModule } from './metacoin/metacoin.module'; 3 | import { ConnectionModule } from './connection/connection.module'; 4 | import { ConfigModule } from '@nestjs/config'; 5 | 6 | @Module({ 7 | imports: [ 8 | MetacoinModule, 9 | ConnectionModule, 10 | ConfigModule.forRoot({ 11 | envFilePath: '.env', 12 | expandVariables: true 13 | }) 14 | ] 15 | }) 16 | export class AppModule {} 17 | -------------------------------------------------------------------------------- /src/common/validation/is-address.pipe.ts: -------------------------------------------------------------------------------- 1 | import { ArgumentMetadata, BadRequestException, PipeTransform } from '@nestjs/common'; 2 | import { ethers } from 'ethers'; 3 | 4 | export class IsAddressPipe implements PipeTransform { 5 | transform(value: string, metadata: ArgumentMetadata): string { 6 | if (!ethers.isAddress(value)) throw new BadRequestException(`'${metadata.data}' ${metadata.type} should be an address`); 7 | return value; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/common/validation/is-not-empty-string.pipe.ts: -------------------------------------------------------------------------------- 1 | import { isNotEmpty, isString, registerDecorator, ValidationArguments, ValidationOptions } from 'class-validator'; 2 | 3 | export function IsNotEmptyString(validationOptions?: ValidationOptions) { 4 | return (object: unknown, propertyName: string) => { 5 | registerDecorator({ 6 | name: 'isNotEmptyString', 7 | target: object.constructor, 8 | propertyName, 9 | options: validationOptions, 10 | validator: { 11 | validate: (value: any): boolean => isString(value) && isNotEmpty(value.trim()), 12 | defaultMessage: (validationArguments?: ValidationArguments): string => `${validationArguments.property} should be not an empty string` 13 | } 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/connection/connection.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConnectionService } from './connection.service'; 3 | 4 | @Module({ 5 | providers: [ConnectionService], 6 | exports: [ConnectionService] 7 | }) 8 | export class ConnectionModule {} 9 | -------------------------------------------------------------------------------- /src/connection/connection.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { ethers, Contract, InterfaceAbi } from 'ethers'; 3 | 4 | @Injectable() 5 | export class ConnectionService { 6 | private provider = new ethers.JsonRpcProvider(); 7 | 8 | launchToContract(contractAddress: string, contractAbi: InterfaceAbi): Contract { 9 | return new Contract(contractAddress, contractAbi, this.provider); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { ValidationPipe } from '@nestjs/common'; 2 | import { ConfigService } from '@nestjs/config'; 3 | import { NestFactory } from '@nestjs/core'; 4 | import { AppModule } from './app.module'; 5 | import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; 6 | 7 | async function bootstrap() { 8 | const app = await NestFactory.create(AppModule); 9 | app.useGlobalPipes(new ValidationPipe()); 10 | 11 | // SWAGGER SETUP 12 | const swaggerConfig = new DocumentBuilder() 13 | .setTitle('Truffle-NestJS-Box') 14 | .setDescription('API description') 15 | .setVersion('1.0') 16 | .build(); 17 | const document = SwaggerModule.createDocument(app, swaggerConfig); 18 | SwaggerModule.setup('api', app, document); 19 | 20 | const config = app.get