├── .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 |

2 | Logo 3 |

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(ConfigService); 21 | await app.listen(config.get('APP_PORT'), config.get('APP_HOST')); 22 | } 23 | bootstrap(); 24 | -------------------------------------------------------------------------------- /src/metacoin/dto/signed-transfer.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsNotEmptyString } from "../../common/validation/is-not-empty-string.pipe"; 2 | 3 | export class SignedTransferDto { 4 | @IsNotEmptyString() 5 | tx: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/metacoin/metacoin.controller.ts: -------------------------------------------------------------------------------- 1 | import { Body, Controller, Get, Param, Post, Query } from '@nestjs/common'; 2 | import { MetacoinService } from './metacoin.service'; 3 | import { IsAddressPipe } from '../common/validation/is-address.pipe'; 4 | import { SignedTransferDto } from './dto/signed-transfer.dto'; 5 | 6 | @Controller('metacoin') 7 | export class MetacoinController { 8 | constructor(private readonly metacoinService: MetacoinService) { } 9 | 10 | @Get('balance/:address') 11 | getBalance(@Param('address', IsAddressPipe) address: string, 12 | @Query('eth') eth?: boolean): Promise { 13 | return this.metacoinService.getBalance(address, eth); 14 | } 15 | 16 | @Post('send-coin') 17 | sendCoin(@Body() signedTransfer: SignedTransferDto): Promise { 18 | return this.metacoinService.sendSignedTransaction(signedTransfer.tx); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/metacoin/metacoin.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigModule } from '@nestjs/config'; 3 | import { ConnectionModule } from '../connection/connection.module'; 4 | import { MetacoinController } from './metacoin.controller'; 5 | import { MetacoinService } from './metacoin.service'; 6 | 7 | @Module({ 8 | imports: [ 9 | ConnectionModule, 10 | ConfigModule 11 | ], 12 | controllers: [MetacoinController], 13 | providers: [MetacoinService] 14 | }) 15 | export class MetacoinModule {} 16 | -------------------------------------------------------------------------------- /src/metacoin/metacoin.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { Contract } from 'ethers'; 3 | import { ConfigService } from '@nestjs/config'; 4 | import { ConnectionService } from '../connection/connection.service'; 5 | import * as MetaCoin from '../../build/contracts/MetaCoin.json'; 6 | 7 | @Injectable() 8 | export class MetacoinService { 9 | private metacoinContract: Contract; 10 | 11 | constructor(private readonly connectionService: ConnectionService, 12 | private readonly configService: ConfigService) { 13 | this.metacoinContract = this.getMetacoinContract(); 14 | } 15 | 16 | async getBalance(account: string, eth?: boolean): Promise { 17 | try { 18 | const balance = eth ? 19 | await this.metacoinContract.getBalanceInEth(account) : 20 | await this.metacoinContract.getBalance(account); 21 | return balance.toString(); 22 | } catch (error) { 23 | throw new Error('Unable to check account balance'); 24 | } 25 | } 26 | 27 | sendSignedTransaction(tx: string): Promise { 28 | return this.metacoinContract.sendTransaction(tx) 29 | .catch(() => { 30 | throw new Error('Unable to send signed transaction'); 31 | }); 32 | } 33 | 34 | private getMetacoinContract(): Contract { 35 | try { 36 | const metacoinAddress = this.configService.get('METACOIN_ADDRESS'); 37 | const metacoinAbi = MetaCoin.abi; 38 | return this.connectionService.launchToContract(metacoinAddress, metacoinAbi); 39 | } catch (error) { 40 | throw new Error('Unable to connect to MetaCoin contract'); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/TestMetaCoin.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.25 <0.7.0; 2 | 3 | import "truffle/Assert.sol"; 4 | import "truffle/DeployedAddresses.sol"; 5 | import "../contracts/MetaCoin.sol"; 6 | 7 | contract TestMetaCoin { 8 | 9 | function testInitialBalanceUsingDeployedContract() public { 10 | MetaCoin meta = MetaCoin(DeployedAddresses.MetaCoin()); 11 | 12 | uint expected = 10000; 13 | 14 | Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially"); 15 | } 16 | 17 | function testInitialBalanceWithNewMetaCoin() public { 18 | MetaCoin meta = new MetaCoin(); 19 | 20 | uint expected = 10000; 21 | 22 | Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/metacoin.js: -------------------------------------------------------------------------------- 1 | const MetaCoin = artifacts.require("MetaCoin"); 2 | 3 | contract('MetaCoin', (accounts) => { 4 | it('should put 10000 MetaCoin in the first account', async () => { 5 | const metaCoinInstance = await MetaCoin.deployed(); 6 | const balance = await metaCoinInstance.getBalance.call(accounts[0]); 7 | 8 | assert.equal(balance.valueOf(), 10000, "10000 wasn't in the first account"); 9 | }); 10 | it('should call a function that depends on a linked library', async () => { 11 | const metaCoinInstance = await MetaCoin.deployed(); 12 | const metaCoinBalance = (await metaCoinInstance.getBalance.call(accounts[0])).toNumber(); 13 | const metaCoinEthBalance = (await metaCoinInstance.getBalanceInEth.call(accounts[0])).toNumber(); 14 | 15 | assert.equal(metaCoinEthBalance, 2 * metaCoinBalance, 'Library function returned unexpected function, linkage may be broken'); 16 | }); 17 | it('should send coin correctly', async () => { 18 | const metaCoinInstance = await MetaCoin.deployed(); 19 | 20 | // Setup 2 accounts. 21 | const accountOne = accounts[0]; 22 | const accountTwo = accounts[1]; 23 | 24 | // Get initial balances of first and second account. 25 | const accountOneStartingBalance = (await metaCoinInstance.getBalance.call(accountOne)).toNumber(); 26 | const accountTwoStartingBalance = (await metaCoinInstance.getBalance.call(accountTwo)).toNumber(); 27 | 28 | // Make transaction from first account to second. 29 | const amount = 10; 30 | await metaCoinInstance.sendCoin(accountTwo, amount, { from: accountOne }); 31 | 32 | // Get balances of first and second account after the transactions. 33 | const accountOneEndingBalance = (await metaCoinInstance.getBalance.call(accountOne)).toNumber(); 34 | const accountTwoEndingBalance = (await metaCoinInstance.getBalance.call(accountTwo)).toNumber(); 35 | 36 | 37 | assert.equal(accountOneEndingBalance, accountOneStartingBalance - amount, "Amount wasn't correctly taken from the sender"); 38 | assert.equal(accountTwoEndingBalance, accountTwoStartingBalance + amount, "Amount wasn't correctly sent to the receiver"); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /truffle-box.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": [ 3 | "README.md", 4 | "box-img-lg", 5 | "box-img-sm" 6 | ], 7 | "commands": { 8 | "Compile": "truffle compile", 9 | "Migrate": "truffle migrate", 10 | "Test contracts": "truffle test", 11 | "Test API": "npm test", 12 | "Build server": "npm run build", 13 | "Run in live mode": "npm run start:dev", 14 | "Run using dist": "npm run start:prod" 15 | }, 16 | "hooks": { 17 | "post-unpack": "npm install" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // Uncommenting the defaults below 3 | // provides for an easier quick-start with Ganache. 4 | // You can also follow this format for other networks; 5 | // see 6 | // for more details on how to specify configuration options! 7 | 8 | networks: { 9 | development: { 10 | host: "127.0.0.1", 11 | port: 8545, 12 | network_id: "*" 13 | }, 14 | }, 15 | compilers: { 16 | solc: { 17 | version: "0.6.12" 18 | } 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "moduleResolution": "node", 5 | "declaration": true, 6 | "removeComments": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "allowSyntheticDefaultImports": true, 10 | "target": "es2017", 11 | "skipLibCheck": true, 12 | "sourceMap": true, 13 | "outDir": "./dist", 14 | "baseUrl": "./", 15 | "incremental": true, 16 | "resolveJsonModule": true 17 | } 18 | } 19 | --------------------------------------------------------------------------------