From b9a707d9d0851997137dfcc8bbe244a6db311639 Mon Sep 17 00:00:00 2001 From: Yukishige Nakajo Date: Tue, 11 Sep 2018 16:05:35 +0900 Subject: [PATCH 01/10] impl: Implement MasaPoint mock class. --- lib/masa.js | 47 ++++++++++++++++++++++++++++++++++++++--- lib/masa_coin.js | 28 +++++++++++++++++++++++++ lib/masa_point.js | 52 ++++++++++++++++++++++++++++++++++++++++++++++ lib/transaction.js | 37 +++++++++++++++++++++++++++++++++ lib/wallet.js | 4 ++++ package-lock.json | 38 +++++++++++++++++++++++++++++++++ package.json | 3 +++ test/masa.spec.js | 23 ++++++++++++++++++-- webpack.config.js | 11 +++++----- 9 files changed, 233 insertions(+), 10 deletions(-) create mode 100644 lib/masa_coin.js create mode 100644 lib/masa_point.js create mode 100644 lib/transaction.js create mode 100644 lib/wallet.js diff --git a/lib/masa.js b/lib/masa.js index 8a907c4..f2ee0d7 100644 --- a/lib/masa.js +++ b/lib/masa.js @@ -1,5 +1,46 @@ -function masa(provider) { - console.log('masa.js') +import MasaPoint from './masa_point' + +/** + * Masa system client library class. + */ +class Masa { + /** + * @constructor + */ + constructor() { + console.log('masa.js') + } + + /** + * Get the MasaPoint. + * @param address + * @return {MasaPoint} + */ + point(address) { + return new MasaPoint(address) + } + + /** + * Get the amount of valid points in a specific community of specific user. + * @param address + * @param communityId + * @return {number} + */ + getCommunityPoint(address, communityId) { + return MasaPoint.communityAmountOf(address, communityId) + } + + /** + * send feedback to to user. see {@link MasaPoint.feedback} + * @param to feedback receiver user address + * @param communityId the community regarding of feedback + * @param feelingsId + * @param msg + * @return {Transaction} + */ + feedback(to, communityId, feelingsId, msg) { + return MasaPoint.feedback(to, communityId, feelingsId, msg) + } } -export default masa +export default Masa diff --git a/lib/masa_coin.js b/lib/masa_coin.js new file mode 100644 index 0000000..06ebe0f --- /dev/null +++ b/lib/masa_coin.js @@ -0,0 +1,28 @@ +import Transaction from './transaction' + +/** + * MasaCoin managing class + */ +class MasaCoin { + /** + * Get the amount of coin. + * @returns {number} amount of coin. + */ + async amount() { + // TODO: implement + return 100 + } + + /** + * Send coin to other user. + * @param address receiver address + * @param amount sending amount + * @return Promise + */ + async transfer(address, amount) { + // TODO: implement + return Promise.resolve(new Transaction()) + } +} + +export default MasaCoin diff --git a/lib/masa_point.js b/lib/masa_point.js new file mode 100644 index 0000000..85aa413 --- /dev/null +++ b/lib/masa_point.js @@ -0,0 +1,52 @@ +import Transaction from './transaction' + +/** + * MasaPoint managing class + */ +class MasaPoint { + /** + * @constructor + * @param address the owner of masa point + */ + constructor(address) { + this.address = address + } + /** + * Get the amount of valid points. + * @returns {number} point of the user + */ + amountOf() { + // TODO: implement + return 500 + } + + /** + * Get the amount of valid points in a specific community. + * @param communityId community id + * @returns {number} point of the user in the community + */ + communityAmountOf(communityId) { + // TODO: implement + return 200 + } + + /** + * Create feedback (sined / unsigned) transaction. + * @param to feedback received user address + * @param communityId the community regarding of feedback + * @param feelingsId Gratitude: 1 / Empathy: 2 /Support: 3 + * @param msg reason for feelings + * @param signed [optional default false] return signed transaction if true. + * @returns {Transaction} + */ + feedback(to, communityId, feelingsId, msg, signed = false) { + // TODO: implement + return new Transaction() + } + + get [Symbol.toStringTag]() { + return 'MasaPoint' + } +} + +export default MasaPoint diff --git a/lib/transaction.js b/lib/transaction.js new file mode 100644 index 0000000..044d43f --- /dev/null +++ b/lib/transaction.js @@ -0,0 +1,37 @@ +/** + * Class for Provide convenience access to Ethereum Transaction. + */ +class Transaction { + /** + * sign this transaction + * @param privateKey + */ + signature(privateKey) { + // TODO: implement + } + + /** + * serialize to json format + * @return {JSON} json formatted transaction + */ + toJSON() { + // TODO: implement + return { + to: '', + nonce: 2, + gas: 0x01, + gasPrice: 20 * 10 ** 9, + data: '0x0000000001', + chainId: 4447, + v: '', + s: '', + r: '' + } + } + + get [Symbol.toStringTag]() { + return 'Transaction' + } +} + +export default Transaction diff --git a/lib/wallet.js b/lib/wallet.js new file mode 100644 index 0000000..d0909e6 --- /dev/null +++ b/lib/wallet.js @@ -0,0 +1,4 @@ +class Wallet { +} + +export default Wallet diff --git a/package-lock.json b/package-lock.json index 8bd7676..486cffd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -631,6 +631,17 @@ "regenerator-transform": "^0.13.3" } }, + "@babel/plugin-transform-runtime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.0.0.tgz", + "integrity": "sha512-yECRVxRu25Nsf6IY5v5XrXhcW9ZHomUQiq30VO8H7r3JYPcBJDTcxZmT+6v1O3QKKrDp1Wp40LinGbcd+jlp9A==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "resolve": "^1.8.1" + } + }, "@babel/plugin-transform-shorthand-properties": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0.tgz", @@ -689,6 +700,16 @@ "regexpu-core": "^4.1.3" } }, + "@babel/polyfill": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.0.0.tgz", + "integrity": "sha512-dnrMRkyyr74CRelJwvgnnSUDh2ge2NCTyHVwpOdvRMHtJUyxLtMAfhBN3s64pY41zdw0kgiLPh6S20eb1NcX6Q==", + "dev": true, + "requires": { + "core-js": "^2.5.7", + "regenerator-runtime": "^0.11.1" + } + }, "@babel/preset-env": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.0.0.tgz", @@ -738,6 +759,23 @@ "semver": "^5.3.0" } }, + "@babel/runtime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz", + "integrity": "sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.12.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", + "dev": true + } + } + }, "@babel/template": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0.tgz", diff --git a/package.json b/package.json index 9544477..5794040 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,10 @@ "author": "Chaintope Inc.", "devDependencies": { "@babel/core": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/polyfill": "^7.0.0", "@babel/preset-env": "^7.0.0", + "@babel/runtime": "^7.0.0", "babel-eslint": "^9.0.0", "babel-loader": "^8.0.2", "chai": "^4.1.2", diff --git a/test/masa.spec.js b/test/masa.spec.js index 2be41fc..0449374 100644 --- a/test/masa.spec.js +++ b/test/masa.spec.js @@ -1,9 +1,28 @@ -import masa from '../lib/masa' +import Masa from '../lib/masa' +import { expect } from 'chai' + var assert = require('assert') describe('masa.js', () => { it('should load', () => { - console.log(masa) + const masa = new Masa() assert(masa) }) + describe('masa point', () => { + let masaPoint + beforeEach(() => { + const masa = new Masa() + masaPoint = masa.point('0x1234567890abcdef1234') + }) + it('get masa point amount', () => { + expect(masaPoint.amountOf()).to.be.equal(500) + }) + it('get community masa point amount', () => { + expect(masaPoint.communityAmountOf(5)).to.be.equal(200) + }) + it('get feedback transaction', () => { + const transaction = masaPoint.feedback('0x1111111111aaaaaaaaaa', 5, 1, 'nice guy') + expect(transaction).to.be.a('transaction') + }) + }) }) diff --git a/webpack.config.js b/webpack.config.js index 0f67bb0..93fff84 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,7 +1,7 @@ -const path = require('path'); +const path = require('path') module.exports = { - entry: './index.js', + entry: ['./index.js'], mode: 'development', output: { filename: 'masa.js', @@ -13,12 +13,13 @@ module.exports = { test: /\.js$/, exclude: /node_modules/, use: { - loader: "babel-loader", + loader: 'babel-loader', options: { - presets: ['@babel/preset-env'] + presets: ['@babel/preset-env'], + plugins: ['@babel/transform-runtime'] } } } ] } -}; +} From ac13d3db96ff97430f0540de296f454ee3ac60b9 Mon Sep 17 00:00:00 2001 From: Yukishige Nakajo Date: Wed, 12 Sep 2018 09:26:45 +0900 Subject: [PATCH 02/10] add: Add Community class. --- lib/community.js | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 lib/community.js diff --git a/lib/community.js b/lib/community.js new file mode 100644 index 0000000..e102828 --- /dev/null +++ b/lib/community.js @@ -0,0 +1,10 @@ +/** + * Community managing class + */ +class Community { + get [Symbol.toStringTag]() { + return 'Community' + } +} + +export default Community From df782f4a7f99c3f0c0a6f4b03307b96c0eb18890 Mon Sep 17 00:00:00 2001 From: Yukishige Nakajo Date: Wed, 12 Sep 2018 17:17:51 +0900 Subject: [PATCH 03/10] impl: Implement Wallet. tweak webpack config and eslint config for test. --- .eslintrc.js | 6 +- lib/wallet.js | 44 ++++++++ package-lock.json | 268 +++++++++++++++++++++++++++++++++++++++----- package.json | 8 +- test/wallet.spec.js | 48 ++++++++ webpack.config.js | 3 + 6 files changed, 343 insertions(+), 34 deletions(-) create mode 100644 test/wallet.spec.js diff --git a/.eslintrc.js b/.eslintrc.js index fcb5589..0b9d0f5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,7 @@ module.exports = { parser: 'babel-eslint', extends: 'standard', - plugins: ['mocha'], + plugins: ['mocha', 'chai-friendly'], parserOptions: { 'ecmaVersion':2017 }, @@ -9,6 +9,8 @@ module.exports = { rules: { 'space-before-function-paren': ['error', 'never'], 'no-underscore-dangle': 0, - 'mocha/no-exclusive-tests': 'error' + 'mocha/no-exclusive-tests': 'error', + "no-unused-expressions": 0, + "chai-friendly/no-unused-expressions": 2 } } diff --git a/lib/wallet.js b/lib/wallet.js index d0909e6..04f4ccc 100644 --- a/lib/wallet.js +++ b/lib/wallet.js @@ -1,4 +1,48 @@ +import bip39 from 'bip39' +import hdkey from 'ethereumjs-wallet/hdkey' + +/** + * Masa Wallet class. + * Provide simple wallet functions. + * Usage: + * const mnemonic = Wallet.generateMnemonic() + * const wallet = new Wallet(mnemonic) + * const privateKey = wallet.privateKey // return Buffer + * const address = wallet.address // return string + */ class Wallet { + get HD_PATH() { + return "m/44'/60'/0'/0/0" + } + + /** + * generate mnemonic of master seed. + * @return {string} mnemonic + */ + static generateMnemonic() { + return bip39.generateMnemonic() + } + + /** + * create HDWallet from master seed mnemonic. + * @constructor + * @param mnemonic {string} + */ + constructor(mnemonic) { + if (!bip39.validateMnemonic(mnemonic)) { + throw new TypeError('invalid mnemonic!') + } + this.mnemonic = mnemonic + this._hdwallet = hdkey.fromMasterSeed(bip39.mnemonicToSeed(mnemonic)) + this._wallet = this._hdwallet.derivePath(this.HD_PATH).getWallet() + this.address = '0x' + this._wallet.getAddress().toString('hex') + this.privateKey = this._wallet.getPrivateKey() + this.publicKey = this._wallet.getPublicKey() + } + + get [Symbol.toStringTag]() { + return 'Wallet' + } } export default Wallet diff --git a/package-lock.json b/package-lock.json index 486cffd..3e6aa6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1123,6 +1123,11 @@ "acorn": "^5.0.3" } }, + "aes-js": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.1.tgz", + "integrity": "sha512-cEA0gBelItZZV7iBiL8ApCiNgc+gBWJJ4uoORhbu6vOqAJ0UL9wIlxr4RI7ij9SSVzy6AnPwiu37kVYiHCl3nw==" + }, "ajv": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz", @@ -1402,6 +1407,14 @@ } } }, + "base-x": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.4.tgz", + "integrity": "sha512-UYOadoSIkEI/VrRGSG6qp93rp2WdokiAiNYDfGW5qURAY8GiAQkvMbwNNSDYiVJopqv4gCna7xqf4rrNGp+5AA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", @@ -1420,6 +1433,31 @@ "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", "dev": true }, + "bindings": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz", + "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==" + }, + "bip39": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-2.5.0.tgz", + "integrity": "sha512-xwIx/8JKoT2+IPJpFEfXoWdYwP7UVAoUxxLNfGCfVowaJE7yg1Y5B1BVPqlUNsBq5/nGwmFkwRJ8xDW4sX8OdA==", + "requires": { + "create-hash": "^1.1.0", + "pbkdf2": "^3.0.9", + "randombytes": "^2.0.1", + "safe-buffer": "^5.0.1", + "unorm": "^1.3.3" + } + }, + "bip66": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", + "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "bluebird": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", @@ -1429,8 +1467,7 @@ "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, "brace-expansion": { "version": "1.1.11", @@ -1474,8 +1511,7 @@ "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, "browser-stdout": { "version": "1.3.1", @@ -1487,7 +1523,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, "requires": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -1565,6 +1600,24 @@ "node-releases": "^1.0.0-alpha.11" } }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "requires": { + "base-x": "^3.0.2" + } + }, + "bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "requires": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, "buffer": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", @@ -1585,8 +1638,7 @@ "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" }, "builtin-modules": { "version": "1.1.1", @@ -1742,7 +1794,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -1826,6 +1877,22 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "coinstring": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/coinstring/-/coinstring-2.3.0.tgz", + "integrity": "sha1-zbYzY6lhUCQEolr7gsLibV/2J6Q=", + "requires": { + "bs58": "^2.0.1", + "create-hash": "^1.1.1" + }, + "dependencies": { + "bs58": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-2.0.1.tgz", + "integrity": "sha1-VZCNWPGYKrogCPob7Y+RmYopv40=" + } + } + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -1960,7 +2027,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -1973,7 +2039,6 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -2205,6 +2270,16 @@ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true }, + "drbg.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", + "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", + "requires": { + "browserify-aes": "^1.0.6", + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4" + } + }, "duplexify": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", @@ -2227,7 +2302,6 @@ "version": "6.4.1", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", - "dev": true, "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -2440,6 +2514,12 @@ } } }, + "eslint-plugin-chai-friendly": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.4.1.tgz", + "integrity": "sha512-hkpLN7VVoGGsofZjUhcQ+sufC3FgqMJwD0DvAcRfxY1tVRyQyVsqpaKnToPHJQOrRo0FQ0fSEDwW2gr4rsNdGA==", + "dev": true + }, "eslint-plugin-es": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.3.1.tgz", @@ -2583,6 +2663,44 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, + "ethereumjs-util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "^0.1.3", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + }, + "ethereumjs-wallet": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-0.6.2.tgz", + "integrity": "sha512-DHEKPV9lYORM7dL8602dkb+AgdfzCYz2lxpdYQoD3OwG355LLDuivW9rGuLpDMCry/ORyBYV6n+QCo/71SwACg==", + "requires": { + "aes-js": "^3.1.1", + "bs58check": "^2.1.2", + "ethereumjs-util": "^5.2.0", + "hdkey": "^1.0.0", + "safe-buffer": "^5.1.2", + "scrypt.js": "^0.2.0", + "utf8": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, "events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", @@ -2593,7 +2711,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, "requires": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -3601,7 +3718,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -3611,12 +3727,21 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz", "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==", - "dev": true, "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" } }, + "hdkey": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hdkey/-/hdkey-1.1.0.tgz", + "integrity": "sha512-E7aU8pNlWUJbXGjTz/+lKf1LkMcA3hUrC5ZleeizrmLSd++kvf8mSOe3q8CmBDA9j4hdfXO5iY6hGiTUCOV2jQ==", + "requires": { + "coinstring": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", @@ -3627,7 +3752,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -3708,8 +3832,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "inquirer": { "version": "6.2.0", @@ -3927,6 +4050,11 @@ "is-extglob": "^2.1.1" } }, + "is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=" + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -4083,6 +4211,17 @@ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", "dev": true }, + "keccak": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-1.4.0.tgz", + "integrity": "sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw==", + "requires": { + "bindings": "^1.2.1", + "inherits": "^2.0.3", + "nan": "^2.2.1", + "safe-buffer": "^5.1.0" + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -4226,7 +4365,6 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", - "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -4291,14 +4429,12 @@ "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "minimatch": { "version": "3.0.4", @@ -4525,9 +4661,7 @@ "nan": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.0.tgz", - "integrity": "sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw==", - "dev": true, - "optional": true + "integrity": "sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw==" }, "nanomatch": { "version": "1.2.13", @@ -4918,7 +5052,6 @@ "version": "3.0.16", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz", "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==", - "dev": true, "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -5079,7 +5212,6 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", - "dev": true, "requires": { "safe-buffer": "^5.1.0" } @@ -5349,12 +5481,19 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" } }, + "rlp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.1.0.tgz", + "integrity": "sha512-93U7IKH5j7nmXFVg19MeNBGzQW5uXW1pmCuKY8veeKIhYTE32C2d0mOegfiIAfXcHOKJjjPlJisn8iHDF5AezA==", + "requires": { + "safe-buffer": "^5.1.1" + } + }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", @@ -5385,8 +5524,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -5413,6 +5551,46 @@ "ajv-keywords": "^3.1.0" } }, + "scrypt": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/scrypt/-/scrypt-6.0.3.tgz", + "integrity": "sha1-BOAUpWgrU/pQwtXM4WfXGcBthw0=", + "requires": { + "nan": "^2.0.8" + } + }, + "scrypt.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/scrypt.js/-/scrypt.js-0.2.0.tgz", + "integrity": "sha1-r40UZbcemZARC+38WTuUeeA6ito=", + "requires": { + "scrypt": "^6.0.2", + "scryptsy": "^1.2.1" + } + }, + "scryptsy": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-1.2.1.tgz", + "integrity": "sha1-oyJfpLJST4AnAHYeKFW987LZIWM=", + "requires": { + "pbkdf2": "^3.0.3" + } + }, + "secp256k1": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.5.2.tgz", + "integrity": "sha512-iin3kojdybY6NArd+UFsoTuapOF7bnJNf2UbcWXaY3z+E1sJDipl60vtzB5hbO/uquBu7z0fd4VC4Irp+xoFVQ==", + "requires": { + "bindings": "^1.2.1", + "bip66": "^1.1.3", + "bn.js": "^4.11.3", + "create-hash": "^1.1.2", + "drbg.js": "^1.0.1", + "elliptic": "^6.2.3", + "nan": "^2.2.1", + "safe-buffer": "^5.1.0" + } + }, "semver": { "version": "5.5.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", @@ -5470,7 +5648,6 @@ "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -5841,6 +6018,14 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, + "strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -6132,6 +6317,11 @@ "imurmurhash": "^0.1.4" } }, + "unorm": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.4.1.tgz", + "integrity": "sha1-NkIA1fE2RsqLzURJAnEzVhR5IwA=" + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -6217,6 +6407,11 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, + "utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" + }, "util": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", @@ -6242,6 +6437,11 @@ "object.getownpropertydescriptors": "^2.0.3" } }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, "v8-compile-cache": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz", @@ -6361,6 +6561,12 @@ } } }, + "webpack-node-externals": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-1.7.2.tgz", + "integrity": "sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg==", + "dev": true + }, "webpack-sources": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", diff --git a/package.json b/package.json index 5794040..fd664c3 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "chai": "^4.1.2", "eslint": "^5.5.0", "eslint-config-standard": "^12.0.0", + "eslint-plugin-chai-friendly": "^0.4.1", "eslint-plugin-import": "^2.14.0", "eslint-plugin-mocha": "^5.2.0", "eslint-plugin-node": "^7.0.1", @@ -29,6 +30,11 @@ "mocha": "^5.2.0", "mocha-webpack": "^2.0.0-beta.0", "webpack": "^4.17.1", - "webpack-cli": "^3.1.0" + "webpack-cli": "^3.1.0", + "webpack-node-externals": "^1.7.2" + }, + "dependencies": { + "bip39": "^2.5.0", + "ethereumjs-wallet": "^0.6.2" } } diff --git a/test/wallet.spec.js b/test/wallet.spec.js new file mode 100644 index 0000000..55a0db0 --- /dev/null +++ b/test/wallet.spec.js @@ -0,0 +1,48 @@ +import Wallet from '../lib/wallet' +import { expect } from 'chai' + +const GANACHE_MNEMONIC = 'special client interest guess wrist bring rack hockey tip divert three toe' +describe('wallet.js', () => { + it('should load', () => { + expect(Wallet).to.be.ok + }) + describe('initialize', function() { + it('generate mnemonic', () => { + const mnemonic = Wallet.generateMnemonic() + expect(mnemonic).to.be.a('string') + expect(mnemonic.split(' ')).to.have.lengthOf(12) + }) + it('create wallet', function() { + this.timeout(10000) + const wallet = new Wallet(GANACHE_MNEMONIC) + expect(wallet).to.be.ok + expect(wallet).to.be.a('wallet') + }) + it('failed. if specify undefined', () => { + expect(function() { + return new Wallet(undefined) + }).to.throw('invalid mnemonic!') + }) + it('failed. if specify empty string', () => { + expect(function() { + return new Wallet('') + }).to.throw('invalid mnemonic!') + }) + }) + describe('wallet functions', function() { + this.timeout(10000) + let wallet + before(function() { + wallet = new Wallet(GANACHE_MNEMONIC) + }) + it('check privateKey', () => { + expect(wallet.privateKey.toString('hex')).to.be.equal('4d8d0ece9fd220f7fb7f53f71e636ac377aa8bab4e5c8e601e515a625917134e') + }) + it('check publicKey', () => { + expect(wallet.publicKey.toString('hex')).to.be.equal('06d40dcd8748c724e20405eb837a6fc02eea32492dbea17b852ae1dba8500ba1193d843bb694f8d0fafab4007f213607a85297ebf505b2e9a1708b6d3af25553') + }) + it('check address', () => { + expect(wallet.address).to.be.equal('0xdaf8f49a3671082ed2ab0b67ecb7f0182faeab6c') + }) + }) +}) diff --git a/webpack.config.js b/webpack.config.js index 93fff84..220f91c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,6 +1,9 @@ const path = require('path') +const nodeExternals = require('webpack-node-externals') module.exports = { + target: 'node', + externals: [nodeExternals()], entry: ['./index.js'], mode: 'development', output: { From 00ef056a732b2db3fb572d7a8c48996a2a3a991e Mon Sep 17 00:00:00 2001 From: Yukishige Nakajo Date: Wed, 12 Sep 2018 20:09:21 +0900 Subject: [PATCH 04/10] impl: implement facade function of wallet generate / restore. --- lib/masa.js | 18 ++++++++++++++++++ test/masa.spec.js | 22 +++++++++++++++++++--- test/util.js | 5 +++++ test/wallet.spec.js | 5 ++++- 4 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 test/util.js diff --git a/lib/masa.js b/lib/masa.js index f2ee0d7..b33999b 100644 --- a/lib/masa.js +++ b/lib/masa.js @@ -1,4 +1,5 @@ import MasaPoint from './masa_point' +import Wallet from './wallet' /** * Masa system client library class. @@ -41,6 +42,23 @@ class Masa { feedback(to, communityId, feelingsId, msg) { return MasaPoint.feedback(to, communityId, feelingsId, msg) } + + /** + * generate Wallet with new master seed. + * @return {Wallet} + */ + generateNewWallet() { + return new Wallet(Wallet.generateMnemonic()) + } + + /** + * restore Wallet by exists mnemonic. + * @param mnemonic + * @return {Wallet} + */ + restoreWallet(mnemonic) { + return new Wallet(mnemonic) + } } export default Masa diff --git a/test/masa.spec.js b/test/masa.spec.js index 0449374..5b9d2d7 100644 --- a/test/masa.spec.js +++ b/test/masa.spec.js @@ -1,12 +1,11 @@ import Masa from '../lib/masa' import { expect } from 'chai' - -var assert = require('assert') +import { GANACHE_MNEMONIC } from './util' describe('masa.js', () => { it('should load', () => { const masa = new Masa() - assert(masa) + expect(masa).to.be.ok }) describe('masa point', () => { let masaPoint @@ -25,4 +24,21 @@ describe('masa.js', () => { expect(transaction).to.be.a('transaction') }) }) + describe('wallet functions', function() { + this.timeout(10000) + let masa + beforeEach(() => { + masa = new Masa() + }) + it('generate new wallet', () => { + const wallet = masa.generateNewWallet() + expect(wallet).to.be.ok + expect(wallet).to.be.a('wallet') + }) + it('restore wallet', () => { + const wallet = masa.restoreWallet(GANACHE_MNEMONIC) + expect(wallet).to.be.ok + expect(wallet).to.be.a('wallet') + }) + }) }) diff --git a/test/util.js b/test/util.js new file mode 100644 index 0000000..791aadd --- /dev/null +++ b/test/util.js @@ -0,0 +1,5 @@ +const GANACHE_MNEMONIC = 'special client interest guess wrist bring rack hockey tip divert three toe' + +export { + GANACHE_MNEMONIC +} diff --git a/test/wallet.spec.js b/test/wallet.spec.js index 55a0db0..ee5dea6 100644 --- a/test/wallet.spec.js +++ b/test/wallet.spec.js @@ -1,7 +1,7 @@ import Wallet from '../lib/wallet' import { expect } from 'chai' +import { GANACHE_MNEMONIC } from './util' -const GANACHE_MNEMONIC = 'special client interest guess wrist bring rack hockey tip divert three toe' describe('wallet.js', () => { it('should load', () => { expect(Wallet).to.be.ok @@ -35,6 +35,9 @@ describe('wallet.js', () => { before(function() { wallet = new Wallet(GANACHE_MNEMONIC) }) + it('check cat reget mnemonic', () => { + expect(wallet.mnemonic).to.be.equal(GANACHE_MNEMONIC) + }) it('check privateKey', () => { expect(wallet.privateKey.toString('hex')).to.be.equal('4d8d0ece9fd220f7fb7f53f71e636ac377aa8bab4e5c8e601e515a625917134e') }) From d0f08bfd60b36323ad48b6692d0c56b6dd0a1333 Mon Sep 17 00:00:00 2001 From: Yukishige Nakajo Date: Tue, 18 Sep 2018 15:13:06 +0900 Subject: [PATCH 05/10] change: Change as per review from @k_taniguchi san. As first step, I change Masa class to have only functions of explorer. --- lib/masa.js | 53 +++-------------------------------------------- lib/masa_coin.js | 6 +++--- lib/masa_point.js | 29 ++++++++++++++++++-------- test/masa.spec.js | 41 +++++++----------------------------- 4 files changed, 34 insertions(+), 95 deletions(-) diff --git a/lib/masa.js b/lib/masa.js index b33999b..0d6f78b 100644 --- a/lib/masa.js +++ b/lib/masa.js @@ -1,5 +1,4 @@ import MasaPoint from './masa_point' -import Wallet from './wallet' /** * Masa system client library class. @@ -10,55 +9,9 @@ class Masa { */ constructor() { console.log('masa.js') - } - - /** - * Get the MasaPoint. - * @param address - * @return {MasaPoint} - */ - point(address) { - return new MasaPoint(address) - } - - /** - * Get the amount of valid points in a specific community of specific user. - * @param address - * @param communityId - * @return {number} - */ - getCommunityPoint(address, communityId) { - return MasaPoint.communityAmountOf(address, communityId) - } - - /** - * send feedback to to user. see {@link MasaPoint.feedback} - * @param to feedback receiver user address - * @param communityId the community regarding of feedback - * @param feelingsId - * @param msg - * @return {Transaction} - */ - feedback(to, communityId, feelingsId, msg) { - return MasaPoint.feedback(to, communityId, feelingsId, msg) - } - - /** - * generate Wallet with new master seed. - * @return {Wallet} - */ - generateNewWallet() { - return new Wallet(Wallet.generateMnemonic()) - } - - /** - * restore Wallet by exists mnemonic. - * @param mnemonic - * @return {Wallet} - */ - restoreWallet(mnemonic) { - return new Wallet(mnemonic) + this.point = new MasaPoint() } } -export default Masa +const masa = new Masa() +export default masa diff --git a/lib/masa_coin.js b/lib/masa_coin.js index 06ebe0f..a97f841 100644 --- a/lib/masa_coin.js +++ b/lib/masa_coin.js @@ -17,11 +17,11 @@ class MasaCoin { * Send coin to other user. * @param address receiver address * @param amount sending amount - * @return Promise + * @return Transaction */ - async transfer(address, amount) { + transfer(address, amount) { // TODO: implement - return Promise.resolve(new Transaction()) + return new Transaction() } } diff --git a/lib/masa_point.js b/lib/masa_point.js index 85aa413..0ca073d 100644 --- a/lib/masa_point.js +++ b/lib/masa_point.js @@ -1,46 +1,57 @@ import Transaction from './transaction' /** - * MasaPoint managing class + * MasaPoint managing class. + * This class provide functions for access to MasaPoint Smart Contract on Ethereum. */ class MasaPoint { + /** * @constructor - * @param address the owner of masa point + * @param provider require for explorer functions + * @param wallet require for signed functions */ - constructor(address) { - this.address = address + constructor(provider, wallet) { + this.provider = provider + this.wallet = wallet } /** * Get the amount of valid points. + * @param address the owner of masa point * @returns {number} point of the user */ - amountOf() { + amountOf(address) { // TODO: implement + if (address === '0x6861766520636f696e20697300000000000000b8') { + return 200 + } return 500 } /** * Get the amount of valid points in a specific community. + * @param address the owner of masa point * @param communityId community id * @returns {number} point of the user in the community */ - communityAmountOf(communityId) { + communityAmountOf(address, communityId) { // TODO: implement return 200 } /** - * Create feedback (sined / unsigned) transaction. + * Create feedback raw transaction. * @param to feedback received user address * @param communityId the community regarding of feedback * @param feelingsId Gratitude: 1 / Empathy: 2 /Support: 3 * @param msg reason for feelings - * @param signed [optional default false] return signed transaction if true. * @returns {Transaction} */ - feedback(to, communityId, feelingsId, msg, signed = false) { + feedback(to, communityId, feelingsId, msg) { // TODO: implement + if (this.wallet === undefined) { + throw new TypeError('Wallet is NULL! need for sign.') + } return new Transaction() } diff --git a/test/masa.spec.js b/test/masa.spec.js index 5b9d2d7..4213c24 100644 --- a/test/masa.spec.js +++ b/test/masa.spec.js @@ -1,44 +1,19 @@ -import Masa from '../lib/masa' +import masa from '../lib/masa' import { expect } from 'chai' -import { GANACHE_MNEMONIC } from './util' describe('masa.js', () => { - it('should load', () => { - const masa = new Masa() - expect(masa).to.be.ok + describe('init', () => { + it('should load', () => { + expect(masa).to.be.ok + }) }) describe('masa point', () => { - let masaPoint - beforeEach(() => { - const masa = new Masa() - masaPoint = masa.point('0x1234567890abcdef1234') - }) it('get masa point amount', () => { - expect(masaPoint.amountOf()).to.be.equal(500) + expect(masa.point.amountOf('0xaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb')).to.be.equal(500) + expect(masa.point.amountOf('0x6861766520636f696e20697300000000000000b8')).to.be.equal(200) }) it('get community masa point amount', () => { - expect(masaPoint.communityAmountOf(5)).to.be.equal(200) - }) - it('get feedback transaction', () => { - const transaction = masaPoint.feedback('0x1111111111aaaaaaaaaa', 5, 1, 'nice guy') - expect(transaction).to.be.a('transaction') - }) - }) - describe('wallet functions', function() { - this.timeout(10000) - let masa - beforeEach(() => { - masa = new Masa() - }) - it('generate new wallet', () => { - const wallet = masa.generateNewWallet() - expect(wallet).to.be.ok - expect(wallet).to.be.a('wallet') - }) - it('restore wallet', () => { - const wallet = masa.restoreWallet(GANACHE_MNEMONIC) - expect(wallet).to.be.ok - expect(wallet).to.be.a('wallet') + expect(masa.point.communityAmountOf('0x6861766520636f696e20697300000000000000b8', 5)).to.be.equal(200) }) }) }) From 10863892e6c90030de13e2572d79e857369c9743 Mon Sep 17 00:00:00 2001 From: Yukishige Nakajo Date: Wed, 19 Sep 2018 10:50:30 +0900 Subject: [PATCH 06/10] change: Change to report error when call masa.point.feedback. --- lib/masa.js | 7 ++++++- test/masa.spec.js | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/masa.js b/lib/masa.js index 0d6f78b..7eacd34 100644 --- a/lib/masa.js +++ b/lib/masa.js @@ -9,7 +9,12 @@ class Masa { */ constructor() { console.log('masa.js') - this.point = new MasaPoint() + const provider = {} + this.point = new class extends MasaPoint { + feedback(to, communityId, feelingsId, msg) { + throw new TypeError('Not support function. Please use MasaTx.') + } + }(provider, null) } } diff --git a/test/masa.spec.js b/test/masa.spec.js index 4213c24..9bd3314 100644 --- a/test/masa.spec.js +++ b/test/masa.spec.js @@ -15,5 +15,10 @@ describe('masa.js', () => { it('get community masa point amount', () => { expect(masa.point.communityAmountOf('0x6861766520636f696e20697300000000000000b8', 5)).to.be.equal(200) }) + it('masa.point.feedback is not support.', () => { + expect(function() { + masa.point.feedback('0x6861766520636f696e20697300000000000000b8', 5, 1, '') + }).to.throw('Not support function. Please use MasaTx.') + }) }) }) From ad9c3c403329530307aec743c4305bca554c7a44 Mon Sep 17 00:00:00 2001 From: Yukishige Nakajo Date: Wed, 19 Sep 2018 12:07:23 +0900 Subject: [PATCH 07/10] impl: Implement for create transaction class as MasaTx. MasaTx class provide functions for create signed transaction. --- lib/masa_tx.js | 40 ++++++++++++++++++++++++++++++++++++++++ test/masa.spec.js | 2 +- test/masa_tx.spec.js | 23 +++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 lib/masa_tx.js create mode 100644 test/masa_tx.spec.js diff --git a/lib/masa_tx.js b/lib/masa_tx.js new file mode 100644 index 0000000..1e02654 --- /dev/null +++ b/lib/masa_tx.js @@ -0,0 +1,40 @@ +import Wallet from './wallet' +import MasaPoint from './masa_point' +import MasaCoin from './masa_coin' +import Community from './community' + +/** + * MasaTx class provide functions that create signed transaction. + * This class needs wallet for pick up private key. + * + * Usage: + * const masaTx = new MasaTx() // generate new wallet. + * or + * const masaTx = new MasaTx(mnemonic) // restore wallet from specify mnemonic + * + * masaTx.point.feedback(~~~~) // return signed transaction for Masa Point Feedback. + * masaTx.coin.transfer(~~~) // return signed transaction for Masa Coin Transfer. + * masaTx.community.create(~~~) // return signed transaction for Community creation. + */ +class MasaTx { + constructor(mnemonic = '') { + mnemonic = mnemonic === undefined || mnemonic === '' ? Wallet.generateMnemonic() : mnemonic + this.wallet = new Wallet(mnemonic) + this.point = new class extends MasaPoint { + amountOf(address) { + throw new TypeError('Not support function. Please use Masa.') + } + communityAmountOf(address, communityId) { + throw new TypeError('Not support function. Please use Masa.') + } + }(null, this.wallet) + this.coin = new class extends MasaCoin { + async amount() { + throw new TypeError('Not support function. Please use Masa.') + } + }(null, this.wallet) + this.community = new Community(null, this.wallet) + } +} + +export default MasaTx diff --git a/test/masa.spec.js b/test/masa.spec.js index 9bd3314..ba706fa 100644 --- a/test/masa.spec.js +++ b/test/masa.spec.js @@ -17,7 +17,7 @@ describe('masa.js', () => { }) it('masa.point.feedback is not support.', () => { expect(function() { - masa.point.feedback('0x6861766520636f696e20697300000000000000b8', 5, 1, '') + masa.point.feedback('0x6861766520636f696e20697300000000000000b8', 'Challenge Caravan', 1, '') }).to.throw('Not support function. Please use MasaTx.') }) }) diff --git a/test/masa_tx.spec.js b/test/masa_tx.spec.js new file mode 100644 index 0000000..8a6e852 --- /dev/null +++ b/test/masa_tx.spec.js @@ -0,0 +1,23 @@ +import { expect } from 'chai' +import MasaTx from '../lib/masa_tx' +import { GANACHE_MNEMONIC } from './util' + +describe('MasaTx', () => { + describe('init', () => { + it('should load', () => { + expect(MasaTx).to.be.ok + }) + it('create with generate Wallet', () => { + const masaTx = new MasaTx() + expect(masaTx).to.be.ok + expect(masaTx.wallet.mnemonic).to.be.a('string') + expect(masaTx.wallet.mnemonic).to.be.not.equal(GANACHE_MNEMONIC) + }) + it('create with restore Wallet', () => { + const masaTx = new MasaTx(GANACHE_MNEMONIC) + expect(masaTx).to.be.ok + expect(masaTx.wallet.mnemonic).to.be.a('string') + expect(masaTx.wallet.mnemonic).to.be.equal(GANACHE_MNEMONIC) + }) + }) +}) From 3e0c3d63f2439059d54b5f4bb05b7f62648fd3eb Mon Sep 17 00:00:00 2001 From: Yukishige Nakajo Date: Wed, 19 Sep 2018 14:29:14 +0900 Subject: [PATCH 08/10] impl: Implement MasaTx.point, MasaTx.coin, MasaTx.community functions. --- lib/community.js | 11 ++++++++++ lib/masa_coin.js | 5 +++-- lib/masa_tx.js | 2 +- test/masa_tx.spec.js | 52 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 65 insertions(+), 5 deletions(-) diff --git a/lib/community.js b/lib/community.js index e102828..6b0ed7f 100644 --- a/lib/community.js +++ b/lib/community.js @@ -1,7 +1,18 @@ +import Transaction from './transaction' + /** * Community managing class */ class Community { + /** + * create new Community. + * @param name (unique) as communityId. + * @return {Promise} + */ + async create(name) { + return new Transaction() + } + get [Symbol.toStringTag]() { return 'Community' } diff --git a/lib/masa_coin.js b/lib/masa_coin.js index a97f841..31bbfb7 100644 --- a/lib/masa_coin.js +++ b/lib/masa_coin.js @@ -5,10 +5,11 @@ import Transaction from './transaction' */ class MasaCoin { /** - * Get the amount of coin. + * Get the balance of coin. + * @param address to query the balance of. * @returns {number} amount of coin. */ - async amount() { + async balanceOf(address) { // TODO: implement return 100 } diff --git a/lib/masa_tx.js b/lib/masa_tx.js index 1e02654..aabb657 100644 --- a/lib/masa_tx.js +++ b/lib/masa_tx.js @@ -29,7 +29,7 @@ class MasaTx { } }(null, this.wallet) this.coin = new class extends MasaCoin { - async amount() { + async balanceOf() { throw new TypeError('Not support function. Please use Masa.') } }(null, this.wallet) diff --git a/test/masa_tx.spec.js b/test/masa_tx.spec.js index 8a6e852..d69c7a1 100644 --- a/test/masa_tx.spec.js +++ b/test/masa_tx.spec.js @@ -1,6 +1,6 @@ -import { expect } from 'chai' +import {expect} from 'chai' import MasaTx from '../lib/masa_tx' -import { GANACHE_MNEMONIC } from './util' +import {GANACHE_MNEMONIC} from './util' describe('MasaTx', () => { describe('init', () => { @@ -20,4 +20,52 @@ describe('MasaTx', () => { expect(masaTx.wallet.mnemonic).to.be.equal(GANACHE_MNEMONIC) }) }) + describe('masaPoint', () => { + let masaTx + beforeEach(() => { + masaTx = new MasaTx() + }) + it('create feedback transaction', async () => { + const feedbackTx = await masaTx.point.feedback('0xdaF8F49A3671082ED2ab0b67ecB7f0182fAEAb6C', 'Challenge Caravan', 1, '') + expect(feedbackTx).to.be.a('transaction') + }) + it('unsupport amountOf', () => { + expect(function () { + masaTx.point.amountOf('0x6861766520636f696e20697300000000000000b8') + }).to.throw('Not support function. Please use Masa.') + }) + it('unsupport communityAmountOf', () => { + expect(function () { + masaTx.point.communityAmountOf('0x6861766520636f696e20697300000000000000b8', 'chare cara') + }).to.throw('Not support function. Please use Masa.') + }) + }) + describe('masaCoin', () => { + let masaTx + beforeEach(() => { + masaTx = new MasaTx() + }) + it('create transfer transaction', async () => { + const transferTx = await masaTx.coin.transfer('0xdaF8F49A3671082ED2ab0b67ecB7f0182fAEAb6C', 100) + expect(transferTx).to.be.a('transaction') + }) + it('unsupport balanceOf', () => { + return masaTx.coin + .balanceOf('0xdaF8F49A3671082ED2ab0b67ecB7f0182fAEAb6C').then(balance => { + expect.fail('not happend error') + }).catch(e => { + expect(e.message).to.be.equal('Not support function. Please use Masa.') + }) + }) + }) + describe('community', () => { + let masaTx + beforeEach(() => { + masaTx = new MasaTx() + }) + it('create create transaction', async () => { + const createTx = await masaTx.community.create('SDGs') + expect(createTx).to.be.a('transaction') + }) + }) }) From 62dd44f8fd07fd536f41126ea7f3d73b09888a06 Mon Sep 17 00:00:00 2001 From: Yukishige Nakajo Date: Wed, 19 Sep 2018 14:53:24 +0900 Subject: [PATCH 09/10] impl: Implement masa.coin functions. integrate MasaCoin to Masa. --- lib/community.js | 3 +++ lib/masa.js | 6 ++++++ lib/masa_coin.js | 4 ++++ lib/masa_tx.js | 2 +- test/masa.spec.js | 15 +++++++++++++-- 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/community.js b/lib/community.js index 6b0ed7f..bbf47d5 100644 --- a/lib/community.js +++ b/lib/community.js @@ -4,6 +4,9 @@ import Transaction from './transaction' * Community managing class */ class Community { + constractor(wallet) { + this.wallet = wallet + } /** * create new Community. * @param name (unique) as communityId. diff --git a/lib/masa.js b/lib/masa.js index 7eacd34..1b0b722 100644 --- a/lib/masa.js +++ b/lib/masa.js @@ -1,4 +1,5 @@ import MasaPoint from './masa_point' +import MasaCoin from './masa_coin' /** * Masa system client library class. @@ -15,6 +16,11 @@ class Masa { throw new TypeError('Not support function. Please use MasaTx.') } }(provider, null) + this.coin = new class extends MasaCoin { + transfer(address) { + throw new TypeError('Not support function. Please use MasaTx.') + } + }(provider, null) } } diff --git a/lib/masa_coin.js b/lib/masa_coin.js index 31bbfb7..e7917c5 100644 --- a/lib/masa_coin.js +++ b/lib/masa_coin.js @@ -4,6 +4,10 @@ import Transaction from './transaction' * MasaCoin managing class */ class MasaCoin { + constructor(provider, wallet) { + this.provider = provider + this.wallet = wallet + } /** * Get the balance of coin. * @param address to query the balance of. diff --git a/lib/masa_tx.js b/lib/masa_tx.js index aabb657..e40f15b 100644 --- a/lib/masa_tx.js +++ b/lib/masa_tx.js @@ -33,7 +33,7 @@ class MasaTx { throw new TypeError('Not support function. Please use Masa.') } }(null, this.wallet) - this.community = new Community(null, this.wallet) + this.community = new Community(this.wallet) } } diff --git a/test/masa.spec.js b/test/masa.spec.js index ba706fa..a0e4e11 100644 --- a/test/masa.spec.js +++ b/test/masa.spec.js @@ -1,5 +1,5 @@ import masa from '../lib/masa' -import { expect } from 'chai' +import {expect} from 'chai' describe('masa.js', () => { describe('init', () => { @@ -16,9 +16,20 @@ describe('masa.js', () => { expect(masa.point.communityAmountOf('0x6861766520636f696e20697300000000000000b8', 5)).to.be.equal(200) }) it('masa.point.feedback is not support.', () => { - expect(function() { + expect(function () { masa.point.feedback('0x6861766520636f696e20697300000000000000b8', 'Challenge Caravan', 1, '') }).to.throw('Not support function. Please use MasaTx.') }) }) + describe('masa coin', () => { + it('balanceOf', async() => { + const balance = await masa.coin.balanceOf('0xdaF8F49A3671082ED2ab0b67ecB7f0182fAEAb6C') + return expect(balance).to.be.equal(100) + }) + it('unsupport transfer.', () => { + expect(function() { + masa.coin.transfer('0xdaF8F49A3671082ED2ab0b67ecB7f0182fAEAb6C', 20) + }).to.throw('Not support function. Please use MasaTx.') + }) + }) }) From 32945dcc861b79ea8bee692d65ce315d1cd4b7f0 Mon Sep 17 00:00:00 2001 From: Yukishige Nakajo Date: Wed, 19 Sep 2018 15:34:14 +0900 Subject: [PATCH 10/10] change: Change all function to async function. In future plan, MasaPoint, MasaCoin, Community are to be wrapper of web3.eth.contract. so that, these accessor method must be async process. --- lib/masa_coin.js | 6 +++--- lib/masa_point.js | 13 ++++++------- test/masa.spec.js | 14 +++++++------- test/masa_tx.spec.js | 14 +++++++------- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/lib/masa_coin.js b/lib/masa_coin.js index e7917c5..e957ec3 100644 --- a/lib/masa_coin.js +++ b/lib/masa_coin.js @@ -11,7 +11,7 @@ class MasaCoin { /** * Get the balance of coin. * @param address to query the balance of. - * @returns {number} amount of coin. + * @returns {Promise} amount of coin. */ async balanceOf(address) { // TODO: implement @@ -22,9 +22,9 @@ class MasaCoin { * Send coin to other user. * @param address receiver address * @param amount sending amount - * @return Transaction + * @return {Promise} */ - transfer(address, amount) { + async transfer(address, amount) { // TODO: implement return new Transaction() } diff --git a/lib/masa_point.js b/lib/masa_point.js index 0ca073d..a854018 100644 --- a/lib/masa_point.js +++ b/lib/masa_point.js @@ -5,7 +5,6 @@ import Transaction from './transaction' * This class provide functions for access to MasaPoint Smart Contract on Ethereum. */ class MasaPoint { - /** * @constructor * @param provider require for explorer functions @@ -18,9 +17,9 @@ class MasaPoint { /** * Get the amount of valid points. * @param address the owner of masa point - * @returns {number} point of the user + * @returns {Promise} point of the user */ - amountOf(address) { + async amountOf(address) { // TODO: implement if (address === '0x6861766520636f696e20697300000000000000b8') { return 200 @@ -32,9 +31,9 @@ class MasaPoint { * Get the amount of valid points in a specific community. * @param address the owner of masa point * @param communityId community id - * @returns {number} point of the user in the community + * @returns {Promise} point of the user in the community */ - communityAmountOf(address, communityId) { + async communityAmountOf(address, communityId) { // TODO: implement return 200 } @@ -45,9 +44,9 @@ class MasaPoint { * @param communityId the community regarding of feedback * @param feelingsId Gratitude: 1 / Empathy: 2 /Support: 3 * @param msg reason for feelings - * @returns {Transaction} + * @returns {Promise} */ - feedback(to, communityId, feelingsId, msg) { + async feedback(to, communityId, feelingsId, msg) { // TODO: implement if (this.wallet === undefined) { throw new TypeError('Wallet is NULL! need for sign.') diff --git a/test/masa.spec.js b/test/masa.spec.js index a0e4e11..c2ad5c2 100644 --- a/test/masa.spec.js +++ b/test/masa.spec.js @@ -1,5 +1,5 @@ import masa from '../lib/masa' -import {expect} from 'chai' +import { expect } from 'chai' describe('masa.js', () => { describe('init', () => { @@ -8,15 +8,15 @@ describe('masa.js', () => { }) }) describe('masa point', () => { - it('get masa point amount', () => { - expect(masa.point.amountOf('0xaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb')).to.be.equal(500) - expect(masa.point.amountOf('0x6861766520636f696e20697300000000000000b8')).to.be.equal(200) + it('get masa point amount', async() => { + expect(await masa.point.amountOf('0xaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb')).to.be.equal(500) + expect(await masa.point.amountOf('0x6861766520636f696e20697300000000000000b8')).to.be.equal(200) }) - it('get community masa point amount', () => { - expect(masa.point.communityAmountOf('0x6861766520636f696e20697300000000000000b8', 5)).to.be.equal(200) + it('get community masa point amount', async() => { + expect(await masa.point.communityAmountOf('0x6861766520636f696e20697300000000000000b8', 5)).to.be.equal(200) }) it('masa.point.feedback is not support.', () => { - expect(function () { + expect(function() { masa.point.feedback('0x6861766520636f696e20697300000000000000b8', 'Challenge Caravan', 1, '') }).to.throw('Not support function. Please use MasaTx.') }) diff --git a/test/masa_tx.spec.js b/test/masa_tx.spec.js index d69c7a1..dd7256e 100644 --- a/test/masa_tx.spec.js +++ b/test/masa_tx.spec.js @@ -1,6 +1,6 @@ -import {expect} from 'chai' +import { expect } from 'chai' import MasaTx from '../lib/masa_tx' -import {GANACHE_MNEMONIC} from './util' +import { GANACHE_MNEMONIC } from './util' describe('MasaTx', () => { describe('init', () => { @@ -25,17 +25,17 @@ describe('MasaTx', () => { beforeEach(() => { masaTx = new MasaTx() }) - it('create feedback transaction', async () => { + it('create feedback transaction', async() => { const feedbackTx = await masaTx.point.feedback('0xdaF8F49A3671082ED2ab0b67ecB7f0182fAEAb6C', 'Challenge Caravan', 1, '') expect(feedbackTx).to.be.a('transaction') }) it('unsupport amountOf', () => { - expect(function () { + expect(function() { masaTx.point.amountOf('0x6861766520636f696e20697300000000000000b8') }).to.throw('Not support function. Please use Masa.') }) it('unsupport communityAmountOf', () => { - expect(function () { + expect(function() { masaTx.point.communityAmountOf('0x6861766520636f696e20697300000000000000b8', 'chare cara') }).to.throw('Not support function. Please use Masa.') }) @@ -45,7 +45,7 @@ describe('MasaTx', () => { beforeEach(() => { masaTx = new MasaTx() }) - it('create transfer transaction', async () => { + it('create transfer transaction', async() => { const transferTx = await masaTx.coin.transfer('0xdaF8F49A3671082ED2ab0b67ecB7f0182fAEAb6C', 100) expect(transferTx).to.be.a('transaction') }) @@ -63,7 +63,7 @@ describe('MasaTx', () => { beforeEach(() => { masaTx = new MasaTx() }) - it('create create transaction', async () => { + it('create create transaction', async() => { const createTx = await masaTx.community.create('SDGs') expect(createTx).to.be.a('transaction') })