From 1eafa98a6f16995b30f34d2aa487f763e7d53685 Mon Sep 17 00:00:00 2001 From: Dereck Date: Thu, 2 Jul 2020 13:43:48 -0400 Subject: [PATCH] Add application-typescript to asset-transfer-basci (#221) Signed-off-by: Chongxin Luo --- .../application-typescript/.gitignore | 17 +++++ .../application-typescript/package.json | 59 ++++++++++++++++ .../application-typescript/src/enrollAdmin.ts | 56 +++++++++++++++ .../application-typescript/src/invoke.ts | 59 ++++++++++++++++ .../application-typescript/src/query.ts | 57 ++++++++++++++++ .../src/registerUser.ts | 68 +++++++++++++++++++ .../application-typescript/tsconfig.json | 16 +++++ .../application-typescript/tslint.json | 22 ++++++ 8 files changed, 354 insertions(+) create mode 100644 asset-transfer-basic/application-typescript/.gitignore create mode 100644 asset-transfer-basic/application-typescript/package.json create mode 100644 asset-transfer-basic/application-typescript/src/enrollAdmin.ts create mode 100644 asset-transfer-basic/application-typescript/src/invoke.ts create mode 100644 asset-transfer-basic/application-typescript/src/query.ts create mode 100644 asset-transfer-basic/application-typescript/src/registerUser.ts create mode 100644 asset-transfer-basic/application-typescript/tsconfig.json create mode 100644 asset-transfer-basic/application-typescript/tslint.json diff --git a/asset-transfer-basic/application-typescript/.gitignore b/asset-transfer-basic/application-typescript/.gitignore new file mode 100644 index 00000000..e610e389 --- /dev/null +++ b/asset-transfer-basic/application-typescript/.gitignore @@ -0,0 +1,17 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Coverage directory used by tools like istanbul +coverage + +# Dependency directories +node_modules/ +jspm_packages/ +package-lock.json + +# Compiled TypeScript files +dist + +wallet +!wallet/.gitkeep diff --git a/asset-transfer-basic/application-typescript/package.json b/asset-transfer-basic/application-typescript/package.json new file mode 100644 index 00000000..03546d28 --- /dev/null +++ b/asset-transfer-basic/application-typescript/package.json @@ -0,0 +1,59 @@ +{ + "name": "asset-transfer-basic", + "version": "1.0.0", + "description": "Asset-Transfer-Basic application implemented in TypeScript", + "engines": { + "node": ">=8", + "npm": ">=5" + }, + "scripts": { + "lint": "tslint -c tslint.json 'src/**/*.ts'", + "pretest": "npm run lint", + "test": "nyc mocha -r ts-node/register src/**/*.spec.ts", + "build": "tsc", + "build:watch": "tsc -w", + "prepublishOnly": "npm run build" + }, + "engineStrict": true, + "author": "Hyperledger", + "license": "Apache-2.0", + "dependencies": { + "fabric-ca-client": "^2.1.0", + "fabric-network": "^2.1.0" + }, + "devDependencies": { + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.5", + "@types/node": "^10.12.10", + "@types/sinon": "^5.0.7", + "@types/sinon-chai": "^3.2.1", + "chai": "^4.2.0", + "mocha": "^5.2.0", + "nyc": "^14.1.1", + "sinon": "^7.1.1", + "sinon-chai": "^3.3.0", + "ts-node": "^7.0.1", + "tslint": "^5.11.0", + "typescript": "^3.1.6" + }, + "nyc": { + "extension": [ + ".ts", + ".tsx" + ], + "exclude": [ + "coverage/**", + "dist/**" + ], + "reporter": [ + "text-summary", + "html" + ], + "all": true, + "check-coverage": true, + "statements": 100, + "branches": 100, + "functions": 100, + "lines": 100 + } +} diff --git a/asset-transfer-basic/application-typescript/src/enrollAdmin.ts b/asset-transfer-basic/application-typescript/src/enrollAdmin.ts new file mode 100644 index 00000000..43076c06 --- /dev/null +++ b/asset-transfer-basic/application-typescript/src/enrollAdmin.ts @@ -0,0 +1,56 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as FabricCAServices from 'fabric-ca-client'; +import { Wallets, X509Identity } from 'fabric-network'; +import * as fs from 'fs'; +import * as path from 'path'; + +async function main() { + try { + // load the network configuration + const ccpPath = path.resolve(__dirname, '..', '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json'); + const fileExists = fs.existsSync(ccpPath); + if (!fileExists) { + throw new Error(`no such file or directory: ${ccpPath}`); + } + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')); + + // Create a new CA client for interacting with the CA. + const caInfo = ccp.certificateAuthorities['ca.org1.example.com']; + const caTLSCACerts = caInfo.tlsCACerts.pem; + const ca = new FabricCAServices(caInfo.url, { trustedRoots: caTLSCACerts, verify: false }, caInfo.caName); + + // Create a new file system based wallet for managing identities. + const walletPath = path.join(path.resolve(__dirname, '..'), 'wallet'); + const wallet = await Wallets.newFileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + // Check to see if we've already enrolled the admin user. + const identity = await wallet.get('admin'); + if (identity) { + console.log('An identity for the admin user "admin" already exists in the wallet'); + return; + } + + // Enroll the admin user, and import the new identity into the wallet. + const enrollment = await ca.enroll({ enrollmentID: 'admin', enrollmentSecret: 'adminpw' }); + const x509Identity: X509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes(), + }, + mspId: 'Org1MSP', + type: 'X.509', + }; + await wallet.put('admin', x509Identity); + console.log('Successfully enrolled admin user "admin" and imported it into the wallet'); + + } catch (error) { + console.error(`Failed to enroll admin user "admin": ${error}`); + process.exit(1); + } +} + +main(); diff --git a/asset-transfer-basic/application-typescript/src/invoke.ts b/asset-transfer-basic/application-typescript/src/invoke.ts new file mode 100644 index 00000000..6f681567 --- /dev/null +++ b/asset-transfer-basic/application-typescript/src/invoke.ts @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Gateway, Wallets } from 'fabric-network'; +import * as path from 'path'; +import * as fs from 'fs'; + +async function main() { + try { + // load the network configuration + const ccpPath = path.resolve(__dirname, '..', '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json'); + const fileExists = fs.existsSync(ccpPath); + if (!fileExists) { + throw new Error(`no such file or directory: ${ccpPath}`); + } + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')); + + // Create a new file system based wallet for managing identities. + const walletPath = path.join(path.resolve(__dirname, '..'), 'wallet'); + const wallet = await Wallets.newFileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + // Check to see if we've already enrolled the user. + const identity = await wallet.get('appUser'); + if (!identity) { + console.log('An identity for the user "appUser" does not exist in the wallet'); + console.log('Run the registerUser.ts application before retrying'); + return; + } + + // Create a new gateway for connecting to our peer node. + const gateway = new Gateway(); + await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } }); + + // Get the network (channel) our contract is deployed to. + const network = await gateway.getNetwork('mychannel'); + + // Get the contract from the network. + const contract = network.getContract('basic'); + + // Submit the specified transaction. (several example transactions are listed below) + // createAsset creates an asset with ID asset1, color yellow, owner Dave, size 5 and appraizedValue of 130 requires 6 arguments. + // ex: ('createAsset', 'asset1', 'yellow', 'Dave', 5, 1300) + // transferAsset transfers an asset with ID asset1 to new owner Tom - requires 2 arguments. + // ex: ('transferAsset', 'asset1', 'Tom') + await contract.submitTransaction('createAsset', 'asset13', 'yellow', 'Tom', "5", "1300"); + console.log(`Transaction has been submitted`); + + // Disconnect from the gateway. + await gateway.disconnect(); + + } catch (error) { + console.error(`Failed to submit transaction: ${error}`); + process.exit(1); + } +} + +main(); diff --git a/asset-transfer-basic/application-typescript/src/query.ts b/asset-transfer-basic/application-typescript/src/query.ts new file mode 100644 index 00000000..aae2243f --- /dev/null +++ b/asset-transfer-basic/application-typescript/src/query.ts @@ -0,0 +1,57 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Gateway, Wallets } from 'fabric-network'; +import * as path from 'path'; +import * as fs from 'fs'; + + +async function main() { + try { + // load the network configuration + const ccpPath = path.resolve(__dirname, '..', '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json'); + const fileExists = fs.existsSync(ccpPath); + if (!fileExists) { + throw new Error(`no such file or directory: ${ccpPath}`); + } + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')); + + // Create a new file system based wallet for managing identities. + const walletPath = path.join(path.resolve(__dirname, '..'), 'wallet'); + const wallet = await Wallets.newFileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + // Check to see if we've already enrolled the user. + const identity = await wallet.get('appUser'); + if (!identity) { + console.log('An identity for the user "appUser" does not exist in the wallet'); + console.log('Run the registerUser.ts application before retrying'); + return; + } + + // Create a new gateway for connecting to our peer node. + const gateway = new Gateway(); + await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } }); + + // Get the network (channel) our contract is deployed to. + const network = await gateway.getNetwork('mychannel'); + + // Get the contract from the network. + const contract = network.getContract('basic'); + + // Evaluate the specified transaction. (several example transactions are listed below) + // getAsset returns an asset with given assetID asset4 - requires 1 argument. + // ex: ('getAsset', 'asset4') + // getAllAssets returns all assets in the world state - requires no arguments. + // ex: ('getAllAssets') + const result = await contract.evaluateTransaction('getAllAssets'); + console.log(`Transaction has been evaluated, result is: ${result.toString()}`); + + } catch (error) { + console.error(`Failed to evaluate transaction: ${error}`); + process.exit(1); + } +} + +main(); diff --git a/asset-transfer-basic/application-typescript/src/registerUser.ts b/asset-transfer-basic/application-typescript/src/registerUser.ts new file mode 100644 index 00000000..0b6b7a2c --- /dev/null +++ b/asset-transfer-basic/application-typescript/src/registerUser.ts @@ -0,0 +1,68 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Wallets, X509Identity } from 'fabric-network'; +import * as FabricCAServices from 'fabric-ca-client'; +import * as path from 'path'; +import * as fs from 'fs'; + +async function main() { + try { + // load the network configuration + const ccpPath = path.resolve(__dirname, '..', '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json'); + const fileExists = fs.existsSync(ccpPath); + if (!fileExists) { + throw new Error(`no such file or directory: ${ccpPath}`); + } + let ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')); + + // Create a new CA client for interacting with the CA. + const caURL = ccp.certificateAuthorities['ca.org1.example.com'].url; + const ca = new FabricCAServices(caURL); + + // Create a new file system based wallet for managing identities. + const walletPath = path.join(path.resolve(__dirname, '..'), 'wallet'); + const wallet = await Wallets.newFileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + // Check to see if we've already enrolled the user. + const userIdentity = await wallet.get('appUser'); + if (userIdentity) { + console.log('An identity for the user "appUser" already exists in the wallet'); + return; + } + + // Check to see if we've already enrolled the admin user. + const adminIdentity = await wallet.get('admin'); + if (!adminIdentity) { + console.log('An identity for the admin user "admin" does not exist in the wallet'); + console.log('Run the enrollAdmin.ts application before retrying'); + return; + } + + // build a user object for authenticating with the CA + const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type); + const adminUser = await provider.getUserContext(adminIdentity, 'admin'); + + // Register the user, enroll the user, and import the new identity into the wallet. + const secret = await ca.register({ affiliation: 'org1.department1', enrollmentID: 'appUser', role: 'client' }, adminUser); + const enrollment = await ca.enroll({ enrollmentID: 'appUser', enrollmentSecret: secret }); + const x509Identity: X509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes(), + }, + mspId: 'Org1MSP', + type: 'X.509', + }; + await wallet.put('appUser', x509Identity); + console.log('Successfully registered and enrolled admin user "appUser" and imported it into the wallet'); + + } catch (error) { + console.error(`Failed to register user "appUser": ${error}`); + process.exit(1); + } +} + +main(); diff --git a/asset-transfer-basic/application-typescript/tsconfig.json b/asset-transfer-basic/application-typescript/tsconfig.json new file mode 100644 index 00000000..8c96ea07 --- /dev/null +++ b/asset-transfer-basic/application-typescript/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "outDir": "dist", + "target": "es2017", + "moduleResolution": "node", + "module": "commonjs", + "declaration": true, + "sourceMap": true + }, + "include": [ + "./src/**/*" + ], + "exclude": [ + "./src/**/*.spec.ts" + ] +} diff --git a/asset-transfer-basic/application-typescript/tslint.json b/asset-transfer-basic/application-typescript/tslint.json new file mode 100644 index 00000000..e08fd0b8 --- /dev/null +++ b/asset-transfer-basic/application-typescript/tslint.json @@ -0,0 +1,22 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "indent": [true, "spaces", 4], + "linebreak-style": [true, "LF"], + "quotemark": [true, "single"], + "semicolon": [true, "always"], + "no-console": false, + "curly": true, + "triple-equals": true, + "no-string-throw": true, + "no-var-keyword": true, + "no-trailing-whitespace": true, + "object-literal-key-quotes": [true, "as-needed"], + "max-line-length": false + }, + "rulesDirectory": [] +}