├── libs
├── version.json
├── config.js
├── extensionHandler.js
├── http.js
├── Utils.js
├── pay.js
├── appHandler.js
└── qrcode.js
├── doc
├── flow_chart.png
├── flow_chart.plantuml
├── NebPay介绍.md
└── NebPay_Introduction.md
├── .npmignore
├── .jshintrc
├── .gitignore
├── package.json
├── gulpfile.js
├── nebpay.js
├── README.md
├── LICENSE
├── examples
└── example.html
└── dist
└── nebPay.min.js
/libs/version.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.4"
3 | }
--------------------------------------------------------------------------------
/doc/flow_chart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nebulasio/nebPay.js/HEAD/doc/flow_chart.png
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | example/js
2 | node_modules
3 | test
4 | .gitignore
5 | .editorconfig
6 | .travis.yml
7 | .npmignore
8 | component.json
9 | testling.html
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esversion": 6,
3 | "browserify": true,
4 | "bitwise": true,
5 | "camelcase": true,
6 | "eqeqeq": true,
7 | "freeze": true,
8 | "funcscope": false,
9 | "maxcomplexity": 5, /* our target is 3! */
10 | "maxdepth": 3,
11 | "maxerr": 50,
12 | /*"maxlen": 80*/ /*this should be our goal*/
13 | /*"maxparams": 3,*/
14 | "nonew": true,
15 | "unused": true,
16 | "undef": true,
17 | "predef": [
18 | "console"
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile ~/.gitignore_global
6 |
7 | *.swp
8 | /coverage
9 | /tmp
10 | */**/*un~
11 | *un~
12 | .DS_Store
13 | */**/.DS_Store
14 | example/js
15 | node_modules
16 | documentation
17 | bower_components
18 | npm-debug.log
19 | /bower
20 | .npm/
21 | packages/
22 |
23 | .idea/
--------------------------------------------------------------------------------
/doc/flow_chart.plantuml:
--------------------------------------------------------------------------------
1 | @startuml
2 | participant "Dapp\n(NebPay)" as NebPay
3 | participant "Wallet App" as App
4 | participant Server as server
5 | participant "Nebulas\nBlockChain" as chain
6 |
7 | NebPay -> App: serialNumber = nebpay.pay( )
8 | App -> chain: send transaction
9 | App <- chain: return TxHash
10 | App -> server: save (serialNumber, TxHash) to server
11 | ...
12 | |||
13 | NebPay --> server: queryPayInfo(serialNumber,options)
14 | server --> chain: get tx receipt by TxHash
15 | server <-- chain: return tx receipt data
16 | NebPay <-- server: \t\t\t\t\t\t\t return PayInfo
17 | @enduml
--------------------------------------------------------------------------------
/libs/config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var mainnetUrl = "https://pay.nebulas.io/api/mainnet/pay";
4 | var testnetUrl = "https://pay.nebulas.io/api/pay";
5 |
6 | var payUrl = function(debug) {
7 | debug = debug || false;
8 | if (debug) {
9 | return testnetUrl;
10 | } else {
11 | return mainnetUrl;
12 | }
13 | };
14 |
15 | var nanoScheme = function(debug) {
16 | debug = debug || false;
17 | if (debug) {
18 | return "openapp.NASnano.testnet";
19 | } else {
20 | return "openapp.NASnano";
21 | }
22 | };
23 |
24 | module.exports = {
25 | payUrl: payUrl,
26 | nanoScheme: nanoScheme,
27 | mainnetUrl: mainnetUrl,
28 | testnetUrl: testnetUrl
29 | };
--------------------------------------------------------------------------------
/libs/extensionHandler.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var callbackMap = {};
4 |
5 | var openExtension = function (params) {
6 |
7 | if(params.listener){
8 | callbackMap[params.serialNumber] = params.listener;
9 | }
10 | //params.callback = undefined; //postMessage can't contains a function attr
11 | params.listener = undefined; //postMessage can't contains a function attr
12 |
13 | window.postMessage({
14 | "src" : "nebPay",
15 | "logo" : "nebulas", //to distinguish from other messages
16 | "params" : params
17 | },"*");
18 |
19 | };
20 |
21 | window.addEventListener('message', function(resp) {
22 |
23 | // console.log("nebpay: received resp.data: " + JSON.stringify(resp.data));
24 | if(resp.data.src !== "content")
25 | return;
26 |
27 | var key = resp.data.serialNumber;
28 | var callback = callbackMap[key];
29 | if(typeof callback === "function"){
30 | callback(key, resp.data.resp);
31 | }
32 |
33 | //delete callbackMap[key];
34 |
35 | });
36 |
37 |
38 | module.exports = openExtension;
39 |
--------------------------------------------------------------------------------
/libs/http.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var get = function(url, body) {
4 | var obj = {
5 | url: url,
6 | method: "GET",
7 | body: body
8 | };
9 | return request(obj);
10 | };
11 |
12 | var post = function (url, body) {
13 | var obj = {
14 | url: url,
15 | method: "POST",
16 | body: body
17 | };
18 | return request(obj);
19 | };
20 | var request = function(obj) {
21 | return new Promise(function(resolve, reject) {
22 | var xhr = new XMLHttpRequest();
23 | xhr.open(obj.method || "GET", obj.url);
24 | if (obj.headers) {
25 | Object.keys(obj.headers).forEach(function(key) {
26 | xhr.setRequestHeader(key, obj.headers[key]);
27 | });
28 | }
29 | xhr.onload = function() {
30 | if (xhr.status >= 200 && xhr.status < 300) {
31 | resolve(xhr.response);
32 | } else {
33 | reject(xhr.statusText);
34 | }
35 | };
36 | xhr.onerror = function() { return reject(xhr.statusText); };
37 | xhr.send(obj.body);
38 | });
39 | };
40 |
41 | module.exports = {
42 | get: get,
43 | post: post,
44 | request: request
45 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nebpay.js",
3 | "version": "0.2.4",
4 | "copyright": "Copyright © 2017-2020 Nebulas.io",
5 | "description": "Nebulas JavaScript PAY SDK",
6 | "main": "nebpay.js",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/nebulasio/nebPay.js"
10 | },
11 | "scripts": {
12 | "npm-build": "parcel build ./nebpay.js",
13 | "build": "gulp",
14 | "watch": "gulp watch",
15 | "lint": "jshint *.js lib",
16 | "test": "mocha; jshint *.js lib"
17 | },
18 | "author": "nebulas",
19 | "license": "LGPL-3.0",
20 | "keywords": [
21 | "neb",
22 | "javascript",
23 | "pay",
24 | "nebpay"
25 | ],
26 | "directories": {
27 | "lib": "./libs"
28 | },
29 | "dependencies": {
30 | "axios": "^0.18.0",
31 | "bs58": "^4.0.1",
32 | "uuid": "^3.0.1",
33 | "promise": "^8.0.1",
34 | "ripemd160": "^2.0.1",
35 | "qrcode": "^1.4.4",
36 | "extend": ">=3.0.2",
37 | "bignumber.js": "^5.0.0"
38 | },
39 | "devDependencies": {
40 | "assert": "*",
41 | "babelify": "^10.0.0",
42 | "browserify": ">=16.5.0",
43 | "chai": "^4.2.0",
44 | "coveralls": "^3.0.9",
45 | "del": ">=5.1.0",
46 | "exorcist": "^1.0.1",
47 | "gulp": ">=4.0.2",
48 | "gulp-jshint": ">=2.1.0",
49 | "gulp-notify": ">=3.2.0",
50 | "gulp-plumber": "^1.2.1",
51 | "gulp-rename": ">=2.0.0",
52 | "gulp-replace": "^1.0.0",
53 | "gulp-uglify": ">=3.0.2",
54 | "gulp-jsdoc3": "^2.0.0",
55 | "jshint": ">=2.11.0",
56 | "mocha": ">=7.1.0",
57 | "vinyl-buffer": "^1.0.1",
58 | "vinyl-source-stream": "^2.0.0",
59 | "parcel-bundler": "^1.12.4"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/libs/Utils.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var isChrome = function() {
4 | if (typeof window !== "undefined") {
5 | var userAgent = navigator.userAgent.toLowerCase();
6 | if (userAgent.match(/chrome\/([\d\.]+)/)) {
7 | return true;
8 | }
9 | }
10 | return false;
11 | };
12 |
13 | var isExtInstalled = function() {
14 | return (typeof(NasExtWallet) !== 'undefined');
15 | };
16 |
17 | var isMobile = function() {
18 | var userAgent = navigator.userAgent.toLowerCase();
19 | if (userAgent.indexOf("mobile") > -1) {
20 | return true;
21 | }
22 | return false;
23 | };
24 |
25 | var isNano = function() {
26 | var userAgent = navigator.userAgent.toLowerCase();
27 | if (userAgent.indexOf("nasnanoapp") > -1) {
28 | return true;
29 | }
30 | return false;
31 | };
32 |
33 | var isWechat = function () {
34 | var userAgent = navigator.userAgent.toLowerCase();
35 | if (userAgent.indexOf("micromessenger") > -1) {
36 | return true;
37 | }
38 | return false;
39 | };
40 |
41 | var randomCode = function (len) {
42 | var d,
43 | e,
44 | b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
45 | c = "";
46 | for (d = 0; len > d; d += 1){
47 | e = Math.random() * b.length;
48 | e = Math.floor(e);
49 | c += b.charAt(e);
50 | }
51 | return c;
52 | };
53 |
54 | var addCssRule = function() {
55 | function createStyleSheet() {
56 | var style = document.createElement('style');
57 | style.type = 'text/css';
58 | document.head.appendChild(style);
59 | return style.sheet;
60 | }
61 |
62 | var sheet = createStyleSheet();
63 |
64 | return function(selector, rules, index) {
65 | index = index || 0;
66 | sheet.insertRule(selector + "{" + rules + "}", index);
67 | };
68 | }();
69 |
70 | module.exports = {
71 | isExtInstalled: isExtInstalled,
72 | isChrome: isChrome,
73 | isMobile: isMobile,
74 | isNano: isNano,
75 | isWechat: isWechat,
76 | randomCode: randomCode,
77 | addCssRule: addCssRule
78 | };
79 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | 'use strict';
4 | var version = require('./libs/version.json');
5 | var path = require('path');
6 |
7 | var del = require('del');
8 | const { src, dest, watch, series } = require('gulp');
9 | var browserify = require('browserify');
10 | var jshint = require('gulp-jshint');
11 | var uglify = require('gulp-uglify');
12 | var rename = require('gulp-rename');
13 | var plumber = require('gulp-plumber');
14 | var notify = require('gulp-notify');
15 | var source = require('vinyl-source-stream');
16 | // var exorcist = require('exorcist');
17 | // var streamify = require('gulp-streamify');
18 | var replace = require('gulp-replace');
19 | var babelify = require('babelify');
20 | var buffer = require('vinyl-buffer');
21 | var jsdoc = require("gulp-jsdoc3");
22 | var pkg = require("./package.json");
23 |
24 | var DEST = path.join(__dirname, 'dist/');
25 | var dst = 'nebPay';
26 | var documentationDst = path.join(__dirname, 'docs/');
27 |
28 | // Error / Success Handling
29 | var onError = function(err) {
30 | notify.onError({
31 | title: "Error: " + err.plugin,
32 | subtitle: "<%= file.relative %>",
33 | message: "<%= error.message %>",
34 | sound: "Beep",
35 | })(err);
36 | console.log(err.toString())
37 | this.emit('end');
38 | }
39 |
40 | function onSuccess(msg) {
41 | return {
42 | message: msg + " Complete! ",
43 | onLast: true
44 | }
45 | }
46 |
47 | function notifyFunc(msg) {
48 | return gulp.src('.', { read: false })
49 | .pipe(notify(onSuccess(msg)))
50 | }
51 |
52 | var browserifyOptions = {
53 | debug: true,
54 | insert_global_vars: false, // jshint ignore:line
55 | detectGlobals: false,
56 | bundleExternal: true
57 | };
58 |
59 | function gversion(){
60 | return src(['./package.json'])
61 | .pipe(replace(/\"version\"\: \"([\.0-9]*)\"/, '"version": "'+ version.version + '"'))
62 | .pipe(dest('./'));
63 | }
64 |
65 | function lint(){
66 | return src(['./nebpay.js', './libs/*.js'])
67 | .pipe(jshint())
68 | .pipe(jshint.reporter('default'));
69 | }
70 |
71 | function clean(cb) {
72 | del([ DEST ]).then(cb.bind(null, null));
73 | }
74 |
75 | function nebpay() {
76 | return browserify()
77 | .require('./nebpay.js', {expose: 'nebpay'})
78 | .transform(babelify)
79 | .bundle()
80 | .pipe(plumber({ errorHandler: onError }))
81 | // .pipe(exorcist(path.join( DEST, nebulasDst + '.js.map')))
82 | .pipe(source('nebPay.js'))
83 | .pipe(buffer())
84 | .pipe(rename(dst + '.js'))
85 | .pipe(dest(DEST))
86 | .pipe(uglify())
87 | .pipe(rename(dst + '.min.js'))
88 | .pipe(dest(DEST));
89 | }
90 |
91 | function gwatch() {
92 | watch(['./libs/*.js'], ['lint', 'build']);
93 | }
94 |
95 | exports.watch = gwatch
96 | exports.default = series(gversion, lint, clean, nebpay)
97 |
--------------------------------------------------------------------------------
/libs/pay.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var BigNumber = require("bignumber.js");
4 |
5 | var Utils = require("./Utils");
6 | var QRCode = require("./qrcode");
7 |
8 | var openExtension = require("./extensionHandler");
9 | var openApp = require("./appHandler");
10 | var config = require("./config");
11 |
12 | var Pay = function (appKey, appSecret) {
13 | // TODO: currently not use
14 | this.appKey = appKey;
15 | this.appSecret = appSecret;
16 | };
17 | var TransactionMaxGasPrice = "1000000000000";
18 | var TransactionMaxGas = "50000000000";
19 |
20 | Pay.prototype = {
21 | /*jshint maxcomplexity:6 */
22 | submit: function (currency, to, value, payload, options) {
23 | options.serialNumber = Utils.randomCode(32);
24 | value = value || "0";
25 | var amount = new BigNumber(value).times("1000000000000000000");//10^18
26 |
27 | var gasLimitBN, gasPriceBN;
28 | if(!!options.gasLimit) {
29 | gasLimitBN = new BigNumber(options.gasLimit); //check validity of gasPrice & gasLimit
30 | if (gasLimitBN.lt(0)) throw new Error("gas limit should not be minus");
31 | if (gasLimitBN.gt(TransactionMaxGas)) throw new Error("gas limit should smaller than " + TransactionMaxGas);
32 | if (!gasLimitBN.isInteger()) throw new Error("gas limit should be integer");
33 | }
34 |
35 | if(!!options.gasPrice) {
36 | gasPriceBN = new BigNumber(options.gasPrice);
37 | if (gasPriceBN.lt(0)) throw new Error("gas price should not be minus");
38 | if (gasPriceBN.gt(TransactionMaxGasPrice)) throw new Error("gas price should smaller than " + TransactionMaxGasPrice);
39 | if (!gasPriceBN.isInteger()) throw new Error("gas price should be integer");
40 | }
41 |
42 | var params = {
43 | serialNumber: options.serialNumber,
44 | goods:options.goods,
45 | pay: {
46 | currency: currency,
47 | to: to,
48 | value: amount.toString(10),
49 | payload: payload,
50 | gasLimit: !!gasLimitBN ? gasLimitBN.toString(10) : undefined,
51 | gasPrice: !!gasPriceBN ? gasPriceBN.toString(10) : undefined
52 | },
53 | callback: options.callback || config.payUrl(options.debug),
54 | listener: options.listener,
55 | nrc20: options.nrc20
56 | };
57 |
58 | if (Utils.isChrome() && !Utils.isMobile() && options.extension.openExtension) {
59 | if(Utils.isExtInstalled())
60 | openExtension(params);
61 | else {
62 | //window.alert("NasExtWallet is not installed.");
63 | if (window.confirm('NasExtWallet is not installed. Click "ok" to install it.'))
64 | {
65 | window.open('https://chrome.google.com/webstore/detail/nasextwallet/gehjkhmhclgnkkhpfamakecfgakkfkco');
66 | }
67 | }
68 | }
69 |
70 | var appParams = {
71 | category: "jump",
72 | des: "confirmTransfer",
73 | pageParams: params
74 | };
75 |
76 | if (Utils.isMobile()) {
77 | openApp(appParams, options);
78 | }
79 |
80 | if (options.qrcode.showQRCode && !Utils.isNano()) {
81 | QRCode.showQRCode(JSON.stringify(appParams), options);
82 | }
83 |
84 | return options.serialNumber;
85 | }
86 | };
87 |
88 | module.exports = Pay;
--------------------------------------------------------------------------------
/libs/appHandler.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var config = require("./config");
4 | var Utils = require("./Utils");
5 |
6 | function openApp(appParams, options) {
7 | var url = config.nanoScheme(options.debug);
8 | url = url + "://virtual?params=" + JSON.stringify(appParams);
9 | window.location.href = url;
10 | // var ifr = document.createElement('iframe');
11 | // ifr.src = url;
12 | // ifr.style.display='none';
13 |
14 | //if (!Utils.isNano() && options.mobile.showInstallTip) {
15 | checkOpen(function(opened) {
16 | if (!opened) {
17 | //showNanoInstallTip(options);
18 | alertNanoInstall();
19 | }
20 | });
21 | //}
22 |
23 | // document.body.appendChild(ifr);
24 | // setTimeout(function() {
25 | // document.body.removeChild(ifr);
26 | // }, 2000);
27 | }
28 |
29 | function alertNanoInstall(){
30 | if (window.confirm('NasNano is not installed. Click "ok" to install it.'))
31 | {
32 | //window.open("https://nano.nebulas.io/"); //usually pop-up window is blocked
33 | window.location.href='https://nano.nebulas.io/';
34 | }
35 | }
36 |
37 | //check app open
38 | function checkOpen(cb){
39 | var _clickTime = +(new Date());
40 | function check(elsTime) {
41 | if ( elsTime > 3000 || document.hidden || document.webkitHidden) {
42 | cb(1);
43 | } else {
44 | cb(0);
45 | }
46 | }
47 |
48 | //Start the timer running at an interval of 20ms
49 | // and check whether the cumulative consumption time exceeds 3000ms
50 | var _count = 0, intHandle;
51 | intHandle = setInterval(function(){
52 | _count++;
53 | var elsTime = +(new Date()) - _clickTime;
54 | if (_count>=100 || elsTime > 3000 ) {
55 | clearInterval(intHandle);
56 | check(elsTime);
57 | }
58 | }, 20);
59 | }
60 |
61 | function showNanoInstallTip(options) {
62 | var installBtn = document.createElement("BUTTON");
63 | installBtn.className = "install";
64 | installBtn.innerHTML = options.mobile.installTip || "INSTALL NASNano/下载星云钱包";
65 | /*jshint multistr: true */
66 | var style = ("text-align: center;\
67 | background-color: #000;\
68 | color: #fff;\
69 | border-radius: 20px;\
70 | width: 80%;\
71 | height: 40px;\
72 | position: absolute;\
73 | left: 50%;\
74 | top: 50%;\
75 | transform: translate(-50%,-50%);");
76 | Utils.addCssRule(".install", style);
77 |
78 | var background = document.createElement("div");
79 | background.className = "install-background";
80 | style = "position: fixed;\
81 | bottom:0;\
82 | z-index:1000;\
83 | height:40px;\
84 | width:100%;\
85 | background-color: rgba(0, 0, 0, 0);";
86 | Utils.addCssRule(".install-background", style);
87 | background.appendChild(installBtn);
88 |
89 | var bodys = document.getElementsByTagName("body");
90 | var body = bodys[0];
91 | body.appendChild(background);
92 |
93 | installBtn.onclick = function () {
94 | body.removeChild(background);
95 | background = null;
96 | //window.location.href = "https://nano.nebulas.io/";
97 | window.open("https://nano.nebulas.io/");
98 | };
99 | }
100 |
101 | module.exports = openApp;
--------------------------------------------------------------------------------
/libs/qrcode.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var QRCode = require('qrcode');
4 | var Utils = require("./Utils");
5 |
6 | var createDeaultQRContainer = function(options) {
7 | var canvas = document.createElement("canvas");
8 | canvas.className = "qrcode";
9 | /*jshint multistr: true */
10 | var canvasStyle = "//box-shadow: 2px 2px 12px lightgray;";
11 | Utils.addCssRule(".qrcode", canvasStyle);
12 |
13 | var qrcontainer = document.createElement("div");
14 | qrcontainer.className = "qrcode-container";
15 | var style = ("text-align: center;\
16 | //background-color: #fff0;\
17 | background-color: white;\
18 | //border-radius: 20px;\
19 | width: min-content; //300px;\
20 | height: min-content; //300px;\
21 | position: absolute;\
22 | left: 50%;\
23 | top: 50%;\
24 | transform: translate(-50%,-50%);");
25 | Utils.addCssRule(".qrcode-container", style);
26 | qrcontainer.appendChild(canvas);
27 |
28 | var newLine = document.createElement('br');
29 | qrcontainer.appendChild(newLine);
30 |
31 | var textInfo = document.createElement('label');
32 | textInfo.innerHTML = 'Please use NasNano to scan this QR-Code.';
33 | textInfo.className = "qrcode-text";
34 | style = "background-color: white;\
35 | width: 300px";
36 | Utils.addCssRule(".qrcode-text", style);
37 | qrcontainer.appendChild(textInfo);
38 |
39 | newLine = document.createElement('br');
40 | qrcontainer.appendChild(newLine);
41 |
42 | var completeBtn = document.createElement("BUTTON");
43 | completeBtn.className = "complete";
44 | completeBtn.innerHTML = options.qrcode.completeTip || "COMPLETE/完成支付";
45 | style = "background-color: #000;\
46 | border-radius: 4px;\
47 | width: 295px; // 300px;\
48 | height: 40px;\
49 | // padding: 20px;\
50 | margin-top: 20px;\
51 | color: #fff;\
52 | ";
53 | Utils.addCssRule(".complete", style);
54 | qrcontainer.appendChild(completeBtn);
55 |
56 | newLine = document.createElement('br');
57 | qrcontainer.appendChild(newLine);
58 |
59 | var cancelBtn = document.createElement("BUTTON");
60 | cancelBtn.className = "cancel";
61 | cancelBtn.innerHTML = options.qrcode.cancelTip || "CANCEL/取消支付";
62 | style = "background-color: #666;\
63 | border-radius: 4px;\
64 | width: 295px; // 300px;\
65 | height: 40px;\
66 | // padding: 20px;\
67 | margin-top: 10px;\
68 | margin-bottom: 20px;\
69 | color: #fff;\
70 | ";
71 | Utils.addCssRule(".cancel", style);
72 | qrcontainer.appendChild(cancelBtn);
73 |
74 | var background = document.createElement("div");
75 | background.className = "qrcode-background";
76 | style = "position:absolute;\
77 | left:0;\
78 | top:0;\
79 | z-index:100;\
80 | height:100%;\
81 | width:100%;\
82 | background-color: rgba(0, 0, 0, 0.4);";
83 | Utils.addCssRule(".qrcode-background", style);
84 | background.appendChild(qrcontainer);
85 |
86 | var bodys = document.getElementsByTagName("body");
87 | var body = bodys[0];
88 | body.appendChild(background);
89 |
90 | qrcontainer.onclick = function(){ //if clicked on qr-container, qr-code should not be removed
91 | event.cancelBubble = true;
92 | };
93 | background.onclick = function () {
94 | // if (background !== null) { //change: qrcode should be cancelled when click background
95 | // body.removeChild(background);
96 | // dismiss(false, options);
97 | // }
98 | };
99 | cancelBtn.onclick = function () {
100 | body.removeChild(background);
101 | background = null;
102 | dismiss(false, options);
103 | };
104 | completeBtn.onclick = function () {
105 | body.removeChild(background);
106 | background = null;
107 | dismiss(true, options);
108 | };
109 |
110 | return canvas;
111 | };
112 |
113 | var dismiss = function(complete, options) {
114 | if (typeof options.listener !== "undefined") {
115 | options.listener(options.serialNumber, complete);
116 | }
117 | };
118 |
119 | var showQRCode = function (content, options) {
120 | if (typeof window === "undefined") {
121 | return;
122 | }
123 | var container = options.qrcode.container;
124 | if (typeof container === "undefined") {
125 | container = createDeaultQRContainer(options);
126 | }
127 | QRCode.toCanvas(container, content, function (error) {
128 | if (error) {
129 | console.error(error);
130 | }
131 | });
132 | };
133 |
134 | module.exports = {
135 | showQRCode: showQRCode
136 | };
137 |
--------------------------------------------------------------------------------
/nebpay.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var extend = require("extend");
4 | var http = require("./libs/http");
5 | var config = require("./libs/config");
6 | var Pay = require("./libs/pay");
7 |
8 | var BigNumber = require("bignumber.js");
9 |
10 | var NAS = "NAS";
11 |
12 | var NebPay = function(appKey, appSecret) {
13 | this._pay = new Pay(appKey, appSecret);
14 | };
15 |
16 | NebPay.config = config;
17 |
18 | var defaultOptions = function() {
19 | return {
20 | goods: {
21 | name: "",
22 | desc: "",
23 | orderId: "",
24 | ext: ""
25 | },
26 | qrcode: {
27 | showQRCode: false,
28 | completeTip: undefined, // string of complete payment tip
29 | cancelTip: undefined, // string of cancel payment tip
30 | container: undefined
31 | },
32 | extension: {
33 | openExtension: true //set if need show extension payment mode
34 | },
35 |
36 | mobile: {
37 | showInstallTip: true,
38 | installTip: undefined // string of install NASNano tip
39 | },
40 |
41 | // callback is the return url after payment
42 | //callback: config.payUrl,
43 | callback: undefined,
44 |
45 | //listener:specify a listener function to handle payment feedback message(only valid for browser extension)
46 | listener: undefined,
47 |
48 | // if use nrc20pay ,should input nrc20 params like address, name, symbol, decimals
49 | nrc20: undefined,
50 |
51 | // if debug mode, should open testnet nano and reset the callback
52 | debug: false,
53 |
54 | gasPrice: 20000000000,
55 | gasLimit: 2000000
56 | };
57 | };
58 |
59 | NebPay.prototype = {
60 | pay: function(to, value, options) {
61 | var payload = {
62 | type: "binary"
63 | };
64 | options = extend(defaultOptions(), options);
65 | return this._pay.submit(NAS, to, value, payload, options);
66 | },
67 | nrc20pay: function(currency, to, value, options) {
68 | if (options.nrc20 && options.nrc20.decimals > 0) {
69 | value = value || "0";
70 | value = new BigNumber(value).times(new BigNumber(10).pow(options.nrc20.decimals)).toString(10);
71 | }
72 | var address = "";
73 | if (options.nrc20 && options.nrc20.address) {
74 | address = options.nrc20.address;
75 | }
76 |
77 | var args = [to, value];
78 | var payload = {
79 | type: "call",
80 | function: "transfer",
81 | args: JSON.stringify(args)
82 | };
83 | options = extend(defaultOptions(), options);
84 | return this._pay.submit(currency, address, "0", payload, options);
85 | },
86 | deploy: function(source, sourceType, args, options) {
87 | var payload = {
88 | type: "deploy",
89 | source: source,
90 | sourceType: sourceType,
91 | args: args
92 | };
93 | options = extend(defaultOptions(), options);
94 | return this._pay.submit(NAS, "", "0", payload, options);
95 | },
96 | call: function(to, value, func, args, options) {
97 | var payload = {
98 | type: "call",
99 | function: func,
100 | args: args
101 | };
102 | options = extend(defaultOptions(), options);
103 | return this._pay.submit(NAS, to, value, payload, options);
104 | },
105 | simulateCall: function(to, value, func, args, options) {
106 | //this API will not be supported in the future
107 | var payload = {
108 | type: "simulateCall",
109 | function: func,
110 | args: args
111 | };
112 | options = extend(defaultOptions(), options);
113 | options.qrcode.showQRCode = false;
114 | options.mobile.showInstallTip = false;
115 | options.extension.openExtension = true;
116 |
117 | return this._pay.submit(NAS, to, value, payload, options);
118 | },
119 | queryPayInfo: function(serialNumber, options) {
120 | options = extend(defaultOptions(), options);
121 | var url = options.callback || config.payUrl(options.debug);
122 | url = url + "/query?payId=" + serialNumber;
123 | return http.get(url);
124 | }
125 | };
126 |
127 | module.exports = NebPay;
128 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nebPay
2 |
3 | [](https://www.jsdelivr.com/package/npm/nebpay.js)
4 |
5 | [](https://nodei.co/npm/nebpay.js/)
6 |
7 | This is the Nebulas payment JavaScript API. Users can use it in browser on both PC and mobile. Users can do NAS payment through [Chrome extension](https://chrome.google.com/webstore/detail/nasextwallet/gehjkhmhclgnkkhpfamakecfgakkfkco) and [iOS/Android wallet]((https://nano.nebulas.io/)) with it. [nebPay](https://github.com/nebulasio/nebPay)
8 |
9 |
10 | ## Install && Package
11 |
12 | Use `npm` to install dependencies:
13 |
14 | ```
15 | npm install
16 | ```
17 |
18 | **Notice:The official version of the package in NPMJS is `nebpay.js`, not `nebpay` and etc.**
19 |
20 |
21 | Use `gulp` to package the nebPay:
22 |
23 | ```
24 | gulp
25 | ```
26 |
27 | Now we can check the newly created files in `/dist`
28 |
29 | Here you should see a bunch of js files.
30 |
31 | * `nebPay.js`: Used in browser side. Including outside dependency.
32 |
33 | ###### CDN Support
34 | Nebpay has been released to [NPM](https://www.npmjs.com/package/nebpay.js), and developers can use the following code through [CDN](https://www.jsdelivr.com/package/npm/nebpay.js) addition.
35 |
36 | ```html
37 |
38 | ```
39 |
40 | ## Usage
41 |
42 | `nebPay.js` is a useful library for Nebulas DApp developers. It provides rich underlying support in web's DApp. It implements the payment functions.
43 |
44 | For the usage of nebPay please refer to this example:
45 |
46 | * [example](examples/example.html)
47 |
48 | ### Wallet support
49 |
50 | #### iOS/Android wallet
51 | Nebpay supports evoking mobile wallets, allowing users to pay via their phones. **Mobile payment is safe and convenient. We recommend you to pay by mobile wallet.**
52 |
53 | * [Nas Nano](https://nano.nebulas.io/)
54 |
55 | ***
56 | *Tips*:NAS Nano also provides a test version of the wallet for the Testnet, which only supports the use of the wallet in the Testnet for developers to test.
57 |
58 | - [iOS for Testnet(itms-services://?action=download-manifest&url=https://testnet.nebulas.io/static/wallet/ios/NASnano.plist)](itms-services://?action=download-manifest&url=https://testnet.nebulas.io/static/wallet/ios/NASnano.plist)
59 | - [Android for Testnet](https://testnet.nebulas.io/static/wallet/android/nas-nano-Testnet-v1.2.2.apk)
60 |
61 | ***
62 |
63 | #### Chrome extension wallet
64 |
65 | An implementation of chrome extension contributed by community is:
66 |
67 | * [NasExtWallet](https://chrome.google.com/webstore/detail/nasextwallet/gehjkhmhclgnkkhpfamakecfgakkfkco)
68 |
69 | The parameter [`options.callback`](/doc/NebPay_Introduction.md#options) is used for querying transaction result. And it's mainnet by default if you don't specify it.
70 |
71 | * to select mainnet: `callback : NebPay.config.mainnetUrl` (default value)
72 | * to select testnet: `callback : NebPay.config.testnetUrl`
73 |
74 | ## Documentation
75 |
76 | All NebPay SDK documents are in `doc` folder.
77 |
78 | * [doc](/doc)
79 |
80 | And also there is a blog tutorial:
81 |
82 | * [How to use NebPay in your DApp](https://medium.com/nebulasio/how-to-use-nebpay-in-your-dapp-8e785e560fbb)
83 | * [如何在 DApp 中使用 NebPay SDK](https://blog.csdn.net/ycyzyp/article/details/80261142)
84 |
85 | ## The process of a transaction using NebPay
86 | 
87 |
88 | ## Wiki
89 |
90 | Please check our [Wiki](https://github.com/nebulasio/wiki) to learn more about Nebulas.
91 |
92 | ## Contribution
93 |
94 | We are very glad that you are considering to help Nebulas Team or go-nebulas project, including but not limited to source code, documents or others.
95 |
96 | If you'd like to contribute, please fork, fix, commit and send a pull request for the maintainers to review and merge into the main code base. If you wish to submit more complex changes though, please check up with the core devs first on our [slack channel](http://nebulasio.herokuapp.com) to ensure those changes are in line with the general philosophy of the project and/or get some early feedback which can make both your efforts much lighter as well as our review and merge procedures quick and simple.
97 |
98 | Please refer to our [contribution guideline](https://github.com/nebulasio/wiki/blob/master/contribute.md) for more information.
99 |
100 | Thanks.
101 |
102 | ## License
103 |
104 | The go-nebulas project is licensed under the [GNU Lesser General Public License Version 3.0 (“LGPL v3”)](https://www.gnu.org/licenses/lgpl-3.0.en.html).
105 |
106 | For the more information about licensing, please refer to [Licensing](https://github.com/nebulasio/wiki/blob/master/licensing.md) page.
107 |
108 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/doc/NebPay介绍.md:
--------------------------------------------------------------------------------
1 | ## NebPay SDK
2 |
3 | ### 简介
4 |
5 | NebPay SDK 为不同平台的交易提供了统一的支付接口,开发者在Dapp页面中使用NebPay API可以通过浏览器插件钱包、手机app钱包等实现交易支付和合约调用。
6 |
7 | ### 接口介绍
8 |
9 | 目前NebPay 提供了以下接口:
10 |
11 | | 接口 | 简介 |
12 | | :---------------------------- | :----------------------------------------- |
13 | | [pay](#pay) | 用于账户间的NAS转账 |
14 | | [nrc20pay](#nrc20pay) | 用于NRC20代币的转账,仅接口实现,app不支持 |
15 | | [deploy](#deploy) | 用于部署智能合约,仅接口实现 |
16 | | [call](#call) | 用于调用智能合约 |
17 | | [queryPayInfo](#querypayinfo) | 用于查询支付结果 |
18 |
19 | 以上接口中,前四个api对应于[SendTransaction](https://github.com/nebulasio/wiki/blob/master/rpc_admin.md#sendtransaction)接口,细化了`SendTransaction`的使用场景。simulateCall 对应于RPC [Call](https://github.com/nebulasio/wiki/blob/master/rpc.md#call)接口,只用于和浏览器扩展的交互,移动端钱包app不支持该接口。
20 |
21 |
22 | ### 使用说明
23 | 在开发Dapp时,如果要使用NebPay SDK来处理交易, 需要将`nebPay.js`插入到Dapp页面中, 然后就可以使用NebPay模块来发送交易了。
24 |
25 |
26 | Dapp中使用NebPay的例子, 可参考`examples/example.html`.
27 |
28 | ```html
29 |
30 |
53 | ```
54 |
55 | #### 接口&参数说明
56 |
57 | ##### options
58 |
59 | 所有支付接口都有一个`options`参数,该参数的详细介绍如下:
60 |
61 | ```js
62 | var options = {
63 | gasLimit: "2000000", //可以自定义gasLimit和gasPrice
64 | gasPrice: "20000000000",
65 |
66 | goods: { //Dapp端对当前交易商品的描述信息,app暂时不展示
67 | name: "", //商品名称
68 | desc: "", //描述信息
69 | orderId: "", //订单ID
70 | ext: "" //扩展字段
71 | },
72 | qrcode: {
73 | showQRCode: false, //是否显示二维码信息,可以使用NasNano扫码支付
74 | container: undefined, //指定显示二维码的canvas容器,不指定则生成一个默认canvas
75 | completeTip: undefined, // 完成支付按钮文字提示
76 | cancelTip: undefined // 取消支付按钮文字提示
77 | },
78 | extension: {
79 | openExtension: true //是否支持插件调用
80 | },
81 |
82 | // callback 是记录交易返回信息的交易查询服务器地址,
83 | // 目前我们提供了主网和测试网交易查询服务器, 查询频率不能超过20次/分钟
84 | //callback: NebPay.config.mainnetUrl, //主网
85 | callback: NebPay.config.testnetUrl, //测试网
86 |
87 | // listener: 指定一个listener函数来处理交易返回信息(仅用于浏览器插件,App钱包不支持listener)
88 | listener: undefined,
89 | // if use nrc20pay ,should input nrc20 params like name, address, symbol, decimals
90 | nrc20: undefined,
91 |
92 | // 是否为测试模式,在测试模式下,将打开测试版Nano钱包和切换请求连接
93 | debug: false
94 | };
95 | ```
96 |
97 | 为了应对不同的应用场景,开发者可以通过配置`options`参数来选择使用浏览器插件或者NasNano钱包来完成支付。 这里要用到的参数是 `qrcode.showQRCode` 和 `extension.openExtension`。
98 | 这两个参数的效果如下:
99 | * 参数`showQRCode`决定是否显示二维码信息。不论是PC端还是移动端, 当`showQRCode = true`, 页面上都会弹出二维码信息。
100 | * 参数`openExtension`决定是否使用浏览器插件支付。如果设置`openExtension = true`, 则会尝试通过浏览器插件来完成支付;此时如果插件未安装, 则会通过alert提醒用户安装插件。 在移动端, `openExtension` 参数无效。
101 | * 如果是在移动端发起交易,NebPay都会尝试跳转NasNano完成支付,如果未安装NasNano则会出现下载提醒。
102 |
103 | ***
104 |
105 | ##### pay
106 | 发起普通交易支付,指定转账地址和金额。
107 |
108 | ```
109 | pay(to, value, options)
110 | ```
111 |
112 | ###### 参数说明:
113 |
114 | - `to` 转账目的地址
115 |
116 | - `value` 转账数额,单位为nas。(wei是Nas的最小单位,1 Nas = 1e18 wei)
117 |
118 | - `options` 参见[options](#options)
119 |
120 | ###### 返回值
121 |
122 | - `serialNumber` 交易流水号,用于查询交易信息
123 |
124 | ***
125 |
126 | ##### nrc20pay
127 |
128 | 发起星云代币交易支付,指定交易代币名称,转账地址和金额。
129 |
130 | ```
131 | nrc20pay(currency, to, value, options)
132 | ```
133 |
134 | ###### 参数说明:
135 |
136 | - `currency` NRC20代币符号, 即代币简称, 等同于options.nrc20.symbol
137 |
138 | - `to` 转账目的地址,该地址为nebulas钱包地址
139 |
140 | - `value` 转账数额,单位为 NRC20 token
141 |
142 | - `options` 必须指定代币的小数点位数和代币合约地址,另外可指定代币名称、符号。
143 |
144 | ```js
145 | options = {
146 | //nrc20参数介绍
147 | nrc20: {
148 | address: "", //NRC20 代币的合约地址
149 | decimals: 0, //代币小数点位数, 决定了代币的最小单位
150 | name: "", //代币全称, 比如 "Nebulas Token"
151 | symbol: "" //代币简称, 比如 "NAS", "EOS"
152 | }
153 | }
154 | ```
155 | ###### 返回值
156 |
157 | - `serialNumber` 交易流水号,用于查询交易信息
158 |
159 | ***
160 |
161 | ##### deploy
162 |
163 | 发起部署合约交易,指定合约代码,合约代码类型和参数。**【当前版本暂不支持】**
164 |
165 | ```
166 | deploy(source, sourceType, args, options)
167 | ```
168 |
169 | ###### 参数说明:
170 |
171 | - `source` 合约源代码
172 |
173 | - `sourceType` 合约代码类型
174 |
175 | - `args` 合约的初始化函数参数,初始化函数无参数则留空,参数格式为参数数组的JSON字符串,比如`["arg"]` , `["arg1","arg2"]`。
176 |
177 | - `options` 参见[options](#options)
178 |
179 | ###### 返回值
180 |
181 | - `serialNumber` 交易流水号,用于查询交易信息
182 |
183 | ***
184 |
185 | ##### call
186 |
187 | 发起合约调用交易,指定合约地址,金额,方法名和参数。
188 |
189 | ```
190 | call(to, value, func, args, options)
191 | ```
192 |
193 | ###### 参数说明:
194 |
195 | - `to` 合约地址
196 |
197 | - `value` 转账数额,单位为nas。注意value是向合约地址转账,如果合约没有相关的转出函数,则转入的Nas将无法转出。
198 |
199 | - `func` 要调用的合约函数名
200 |
201 | - `args` 调用的函数参数,格式为参数数组的JSON字符串,比如`["arg"]` , `["arg1","arg2"]`。
202 |
203 | - `options` 参见[options](#options)
204 |
205 | ###### 返回值
206 |
207 | - `serialNumber` 交易流水号,用于查询交易信息
208 |
209 | ***
210 |
211 | ##### queryPayInfo
212 | 查询交易信息。
213 |
214 | ```
215 | queryPayInfo(serialNumber,options)
216 | ```
217 |
218 | ###### 参数说明:
219 |
220 | - `serialNumber` 交易序列号,使用上面介绍的接口发送交易后会返回该交易的序列号,是一个32字节随机数。钱包App会将交易结果会上传到交易查询服务器,Dapp端用 `queryPayInfo(serialNumber)` 来查询交易结果信息。
221 | - `options` 对于`queryPayInfo`接口, options 主要用来指定交易查询服务器.
222 |
223 | ###### 返回值:
224 | `queryPayInfo`会返回一个`Promise`对象.
225 |
226 | ```js
227 | var options = {callback: NebPay.config.testnetUrl} //指定查询服务器
228 | nebPay.queryPayInfo(serialNumber, options)
229 | .then(function (resp) {
230 | console.log(resp);
231 | })
232 | .catch(function (err) {
233 | console.log(err);
234 | });
235 | ```
236 | **注意:** 我们提供的查询服务器有查询频率限制, 不得超过20次/分钟, 所以查询周期在 5-10s为宜.
237 |
238 | #### 交易返回信息的处理
239 | 跳转钱包APP发送交易时,钱包App无法直接返回消息给Dapp页面,所以App会将交易信息发送到一个交易查询服务器。
240 | Dapp端需要记录发送交易时返回的序列号`serialNumber`,然后使用`queryPayInfo`接口去查询该交易的序列号以获取交易信息.
241 |
242 | 浏览器插件则相对灵活一些, 它可以直接发送消息给页面。使用浏览器插件发送交易时,浏览器插件可以直接返回交易结果给Dapp页面。
243 | 所以除了可以通过`serialNumber`查询交易结果,Dapp端也可以指定一个`listener(serialNumber, result)`函数来接收并处理交易返回信息。
244 |
245 | **注意:** NebPay并不直接决定交易发送到什么网络(主网/测试网/本地网络), 只是把交易信息发给插件或手机App, 由后者决定使用哪个网络。
246 | NebPay 指定的 callback 是交易查询服务器地址, callback只是告诉钱包App将发送交易后的(serialNumber,txHash)注册到哪个服务器以供查询, 并不能决定交易发送到主网还是测试网。
247 |
248 | #### 交易返回信息
249 |
250 | `queryPayInfo` 查询到的交易返回信息为JSON字符串, 反序列化得到的js 对象。其格式为如下所示。
251 | Dapp页面应该判断`code === 0`, 然后判断`data.status === 1`以确保交易被打包上链。
252 |
253 | ```json
254 | //查询失败
255 | {
256 | "code": 1,
257 | "data": {},
258 | "msg": "payId ZBTSkk74dB4tPJI9J8FDFMu270h7yaut get transaction error"
259 | },
260 | //查询成功
261 | {
262 | "code": 0,
263 | "data": {
264 | "data": null,
265 | "contractAddress": "",
266 | "type": "binary",
267 | "nonce": 136,
268 | "gasLimit": "30000",
269 | "gasUsed": "20000",
270 | "chainId": 1001,
271 | "from": "n1JmhE82GNjdZPNZr6dgUuSfzy2WRwmD9zy",
272 | "to": "n1JmhE82GNjdZPNZr6dgUuSfzy2WRwmD9zy",
273 | "value": "1000000000000000000",
274 | "hash": "f9549a5c01f50f372607b9fd29bf15d483246578f6cc7008d6e2a537920802e6",
275 | "gasPrice": "1000000",
276 | "status": 1,
277 | "timestamp": 1525508076
278 | },
279 | "msg": "success"
280 | }
281 | ```
282 |
283 | 对于浏览器插件,如果指定了`listener`函数,发送交易后如果有返回信息,则会调用`listener`来处理,返回的信息如下:
284 |
285 | **注意:** Listener函数需要有两个参数`function listener(serialNumber, result)`
286 | ```json
287 | //用户拒绝交易, 这会返回错误信息(字符串)
288 | "Error: Transaction rejected by user
289 |
290 | //成功发送交易,
291 | {
292 | "txhash": "a333288574df47b411ca43ed656e16c99c0af98fa3ab14647ce1ad66b45d43f1",
293 | "contract_address": ""
294 | }
295 | ```
296 |
297 | ###使用NebPay的交易处理流程如下:
298 |
299 | 
300 |
301 | ### NebPay 的使用效果示例
302 | 这里有个使用nebPay的例子可以参考: [SuperDictionary](https://yupnano.github.io/SuperDictionary/) ,[GitHub链接](https://github.com/15010159959/super-dictionary)
303 |
304 | SuperDictionary 的使用过程可参见以下视频:
305 |
306 | Youtube:
307 | - [Nebulas Dapp Using NebPay SDK on PC](https://youtu.be/FSFZqoUIT8A)
308 | - [Nebulas Dapp Using NebPay SDK on mobile](https://youtu.be/Cjlo9KKwlNE)
309 |
310 | 国内视频:
311 | - [[星云链]如何在Dapp中使用NebPay SDK ](https://www.bilibili.com/video/av23217213/)
312 |
313 | ### 提示
314 | 在开发Dapp页面时,如果不想使用NebPay,或者需要处理交易之外的其他消息,则可以使用[neb.js](https://github.com/nebulasio/neb.js)直接访问星云链。
315 |
--------------------------------------------------------------------------------
/examples/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
156 |
166 |
167 |
168 | Demo page for Nebpay
169 | Options
170 |
171 |
172 |
173 |
174 |
179 |
180 |
181 |
182 |
Other settings for options:
183 |
198 |
199 |
200 |
201 | Nebpay API
202 |
203 |
204 |
Normal
205 |
206 |
210 |
211 |
212 |
value(nas):
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
NRC20
224 |
225 |
226 |
currency:
227 |
228 |
229 |
230 |
234 |
235 |
236 |
value(nas):
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
Call
246 |
247 |
251 |
252 |
253 |
value(nas):
254 |
255 |
256 |
257 |
function:
258 |
259 |
260 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
Simulate Call (only supported by extension)
271 |
272 |
276 |
277 |
278 |
value(nas):
279 |
280 |
281 |
282 |
function:
283 |
284 |
285 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
pay result queried from server with serialNumber,
296 | you need to click the refresh button th check if the tx result is uploaded to server
297 |
298 |
299 |
300 |
pay result listened directly from extension:
301 |
302 |
303 |
304 |
305 |
306 |
--------------------------------------------------------------------------------
/doc/NebPay_Introduction.md:
--------------------------------------------------------------------------------
1 | ## Introduction of NebPay SDK
2 |
3 | ### Overview
4 | NebPay SDK provides a unified payment interface for transactions on different platforms. While using NebPay in your Dapp page, you can send transaction throw desktop browser extension and mobile wallet App.
5 |
6 | ### API introduction
7 |
8 | The APIs provided by NebPay SDK are as flows:
9 |
10 | | API | Introduction |
11 | | :---------------------------- | :---------------------------------- |
12 | | [pay](#pay) | Ordinary transactions between users |
13 | | [nrc20pay](#nrc20pay) | NRC20 token transactions |
14 | | [deploy](#deploy) | Deploy a smart contract |
15 | | [call](#call) | Call a smart contract function |
16 | | [queryPayInfo](#querypayinfo) | query a transaction result |
17 |
18 | The first four APIs above are correspond to [SendTransaction](https://github.com/nebulasio/wiki/blob/master/rpc_admin.md#sendtransaction) API, and just refined the usage scenario of `SendTransaction`.
19 | simulateCall is correspond to [Call](https://github.com/nebulasio/wiki/blob/master/rpc.md#call) API, which is only used for interactions with browser extension, and is not supported by mobile wallet App.
20 |
21 |
22 | ### How to use NebPay
23 | While developing your Dapp, if you want to use NebPay SDK to handle transaction, you need to include `nebPay.js` into your Dapp page. And then you can use NebPay module to send transactions.
24 |
25 | When users using your Dapp whit desktop browsers (chrome), NebPay will call the browser plugin to process the transaction. And when your Dapp is used on mobile phone, NebPay will jump to the wallet App to process the transaction.
26 |
27 | Here is an example of using NebPay in you Dapp. Please refer to `examples/example.html` for more information.
28 |
29 | ```html
30 |
31 |
52 | ```
53 |
54 | #### Introduction of API & Parameters
55 |
56 | ##### options
57 |
58 | NebPay payment APIs has a common parameter `options`. And here is a detailed introduction of it.
59 |
60 | ```js
61 | var options = {
62 | gasLimit: "2000000", //you can customize the gasLimit and gasPrice
63 | gasPrice: "20000000000",
64 |
65 | goods: { //Description of this commodity being traded
66 | name: "", //name of commodity
67 | desc: "", //description
68 | orderId: "", //order ID
69 | ext: "" //extended field
70 | },
71 | qrcode: {
72 | showQRCode: false, //Whether to display QR code information
73 | container: undefined, //Specifies the canvas container that displays the QR code.
74 | completeTip: undefined, // string of complete payment tip
75 | cancelTip: undefined // string of cancel payment tip
76 | },
77 | extension: {
78 | openExtension: true //set if need show extension payment mode
79 | },
80 | mobile: {
81 | showInstallTip: true,
82 | installTip: undefined // string of install NASNano tip
83 | },
84 |
85 | // callback is the server address that records tx results (the results is uploaded by wallet App)
86 | // we provided tx results query server for testnet and mainnet, and there is a limits to the query frequency.(should less than 20 times per minute)
87 | //callback: NebPay.config.mainnetUrl, //tx result query server for mainnet
88 | callback: NebPay.config.testnetUrl, //tx result query server for testnet
89 |
90 | // listener: specify a listener function to handle payment feedback message(just used by browser extension, App wallet doesn't support listener)
91 | listener: undefined,
92 |
93 | // if use nrc20pay API, you need to specify nrc20 params like name, address, symbol, decimals
94 | nrc20: undefined,
95 |
96 | // if debug mode, should open testnet nano and reset the callback
97 | debug: false
98 | };
99 | ```
100 | In order to deal with different application scenarios, developers can choose to use the browser plugin or NasNano wallet to complete the payment by configuring the `options` parameter.
101 |
102 | The parameters to be used here are `qrcode.showQRCode` and `extension.openExtension`.
103 | The effect of these two parameters is as follows:
104 | * The parameter `showQRCode` determines whether to display the QR code information. Whether it is PC or mobile, when `showQRCode = true`, the QR code information will pop up on the page.
105 | * The parameter `openExtension` determines whether to open the browser plugin. If `openExtension = true`, NebPay will try to complete the transaction through the browser plugin. And if the plugin is not installed, an alert info will be prompted to tell the user to install the plugin. On the mobile side, the `openExtension` parameter is neglected.
106 | * If NebPay is used on the mobile side, it will try to jump to NasNano to complete the payment. If NasNano is not installed, a download reminder will appear.
107 |
108 | ***
109 |
110 | ##### pay
111 |
112 | pay(to, value, options)
113 |
114 | ###### parameters:
115 |
116 | - `to` Destination address of this transfer
117 |
118 | - `value` Transfer amount in nas.
119 |
120 | - `options` Refer to [options](#options)
121 |
122 | ###### return
123 |
124 | - `serialNumber` transaction's serival number, used for query transaction info.
125 |
126 | ***
127 |
128 | ##### nrc20pay
129 |
130 | **[Currently not support for mobile wallet app]**
131 |
132 | ```
133 | nrc20pay(currency, to, value, options)
134 | ```
135 |
136 | ###### parameters:
137 |
138 | - `currency` symbol of NRC20 Token,
139 |
140 | - `to` Destination address, which is a Nebulas wallet address
141 |
142 | - `value` Transfer amount, The unit is this NRC20 token.
143 |
144 | - `options` decimals and Token SmartContract address is required, while Token name and symbol is optional。
145 |
146 | ```js
147 | options = {
148 | //nrc20 parameter
149 | nrc20: {
150 | address: "", //contract address of nrc20
151 | decimals: 0, //
152 | name: "", //Token full name, such as "Nebulas Token"
153 | symbol: "" //Token symbol, such as "NAS","EOS". it's the same with "currency"
154 | }
155 | }
156 | ```
157 |
158 | ###### return
159 |
160 | - `serialNumber` transaction's serival number, used for query transaction info.
161 |
162 | ***
163 |
164 | ##### deploy
165 |
166 | **[Currently not support for mobile wallet app]**
167 |
168 | ```
169 | deploy(source, sourceType, args, options)
170 | ```
171 |
172 | ###### parameters:
173 |
174 | - `source` source code of smart contract
175 |
176 | - `sourceType` source type of smart contract
177 |
178 | - `args` initialization parameters of the SmartContract. parameters are in the form of JSON string of the parameters array, such as`["arg"]` , `["arg1","arg2"]`.
179 |
180 | - `options` Refer to [options](#options)
181 |
182 | ###### return
183 |
184 | - `serialNumber` transaction's serival number, used for query transaction info.
185 |
186 | ***
187 |
188 | ##### call
189 |
190 | call(to, value, func, args, options)
191 |
192 | ###### parameters:
193 |
194 | - `to` address of smart contract
195 |
196 | - `value` Transfer amount in nas. Note that the value is transferred to the contract address. If the contract does not have an associated transfer out function, the transferred Nas could not be reached any more.
197 |
198 | - `func` the function name that will be called
199 |
200 | `args` arguments, in the form of a JSON string of arguments array, such as `["arg"]`, `["arg1","arg2"]`.
201 |
202 | `options` Refer to `options` parameter description
203 |
204 | ###### return
205 |
206 | - `serialNumber` transaction's serival number, used for query transaction info.
207 |
208 | ***
209 |
210 | ##### queryPayInfo
211 |
212 | ```
213 | queryPayInfo(serialNumber, options)
214 | ```
215 |
216 | ###### parameters:
217 |
218 | - `serialNumber` SerialNumber of this transaction, it's a random number of 32 bytes. After sending a transaction with the interface described above, a serial number of the transaction will be returned. Wallet App will uploaded the tx result to a tx query server, and you can use `queryPayInfo(serialNumber)` to query the tx result.
219 | - `options` which specifies the query server to query results.
220 |
221 | ###### return
222 | The return value of `queryPayInfo` is a `Promise` object. You can handle the result as follows:
223 |
224 | ```js
225 | var options = {callback: NebPay.config.testnetUrl}
226 | nebPay.queryPayInfo(serialNumber, options)
227 | .then(function (resp) {
228 | console.log(resp);
229 | })
230 | .catch(function (err) {
231 | console.log(err);
232 | });
233 | ```
234 | **Note:** The query server we provided has limitations on the query frequency, which is 20 times per minute. We suggest that you should set the query period to 5~10s.
235 |
236 | #### Dealing with transaction results
237 |
238 | When using wallet App to send tx, wallet App can't return tx result back to Dapp page directly. Hence wallet App will send the tx result to a server. The Dapp side need to record the SerialNumber of a tx, and then use `queryPayInfo` to query the tx result from this server.
239 |
240 | Browser plugins are relatively flexible, it can send messages directly to the page.
241 | When using a browser extension to send tx, the extension can send back tx result directly.
242 | Hence except querying result with `serialNumber`, you can also just specify a `listener(serialNumber, result)` function to handle tx result.
243 |
244 | #### Transaction result message
245 |
246 | The tx result queried by `queryPayInfo` is a JSON string, the format of this JSON is as follows.
247 | You should check `code === 0`, and `data.status === 1` to make sure the transaction is packed on chain.
248 | ```json
249 | //query failed
250 | {
251 | "code": 1,
252 | "data": {},
253 | "msg": "payId ZBTSkk74dB4tPJI9J8FDFMu270h7yaut get transaction error"
254 | },
255 | //query succeed
256 | {
257 | "code": 0,
258 | "data": {
259 | "data": null,
260 | "contractAddress": "",
261 | "type": "binary",
262 | "nonce": 136,
263 | "gasLimit": "30000",
264 | "gasUsed": "20000",
265 | "chainId": 1001,
266 | "from": "n1JmhE82GNjdZPNZr6dgUuSfzy2WRwmD9zy",
267 | "to": "n1JmhE82GNjdZPNZr6dgUuSfzy2WRwmD9zy",
268 | "value": "1000000000000000000",
269 | "hash": "f9549a5c01f50f372607b9fd29bf15d483246578f6cc7008d6e2a537920802e6",
270 | "gasPrice": "1000000",
271 | "status": 1,
272 | "timestamp": 1525508076
273 | },
274 | "msg": "success"
275 | }
276 | ```
277 |
278 | For browser, if you specified a `listener` as callback function, then it will be called when a result is returned.
279 |
280 | **Note** Listener function has two parameters `function listener(serialNumber, result)`
281 |
282 | The result information is as follows.
283 | ```json
284 | //transaction error, such as user rejected it
285 | "Error: Transaction rejected by user
286 |
287 | //transaction successfully sent
288 | {
289 | "txhash": "a333288574df47b411ca43ed656e16c99c0af98fa3ab14647ce1ad66b45d43f1",
290 | "contract_address": ""
291 | }
292 | ```
293 | ### The transaction process using NebPay is as folows:
294 | 
295 |
296 | ### Example of Dapp using NebPay
297 | Here is a Dapp example Using NebPay: [SuperDictionary](https://yupnano.github.io/SuperDictionary/). It’s source code is on [GitHub](https://github.com/15010159959/super-dictionary).
298 |
299 | These videos blow explains the payment process of a Dapp using NebPay both on PC and mobile phone.
300 |
301 | Youtube:
302 | - [Nebulas Dapp Using NebPay SDK on PC](https://youtu.be/FSFZqoUIT8A)
303 | - [Nebulas Dapp Using NebPay SDK on mobile](https://youtu.be/Cjlo9KKwlNE)
304 |
305 | Or this duplicated video on Chinese vedio website:
306 | - [[星云链]如何在Dapp中使用NebPay SDK ](https://www.bilibili.com/video/av23217213/)
307 |
308 | ### More info
309 | If you don't like to use NebPay while developing your Dapp page, you can also use [neb.js](https://github.com/nebulasio/neb.js) to get access to Nebulas blockchain directly.
310 |
--------------------------------------------------------------------------------
/dist/nebPay.min.js:
--------------------------------------------------------------------------------
1 | require=function i(a,u,s){function f(e,t){if(!u[e]){if(!a[e]){var r="function"==typeof require&&require;if(!t&&r)return r(e,!0);if(c)return c(e,!0);var n=new Error("Cannot find module '"+e+"'");throw n.code="MODULE_NOT_FOUND",n}var o=u[e]={exports:{}};a[e][0].call(o.exports,function(t){return f(a[e][1][t]||t)},o,o.exports,i,a,u,s)}return u[e].exports}for(var c="function"==typeof require&&require,t=0;tNasNano to scan this QR-Code.',i.className="qrcode-text",n="background-color: white; \twidth: 300px",c.addCssRule(".qrcode-text",n),r.appendChild(i),o=document.createElement("br"),r.appendChild(o);var a=document.createElement("BUTTON");a.className="complete",a.innerHTML=t.qrcode.completeTip||"COMPLETE/完成支付",n="background-color: #000;\tborder-radius: 4px;\twidth: 295px; // 300px;\theight: 40px;\t// padding: 20px;\tmargin-top: 20px;\tcolor: #fff;\t",c.addCssRule(".complete",n),r.appendChild(a),o=document.createElement("br"),r.appendChild(o);var u=document.createElement("BUTTON");u.className="cancel",u.innerHTML=t.qrcode.cancelTip||"CANCEL/取消支付",n="background-color: #666;\tborder-radius: 4px;\twidth: 295px; // 300px;\theight: 40px;\t// padding: 20px;\tmargin-top: 10px;\tmargin-bottom: 20px;\tcolor: #fff;\t",c.addCssRule(".cancel",n),r.appendChild(u);var s=document.createElement("div");s.className="qrcode-background",n="position:absolute;\tleft:0;\ttop:0;\tz-index:100;\theight:100%;\twidth:100%;\tbackground-color: rgba(0, 0, 0, 0.4);",c.addCssRule(".qrcode-background",n),s.appendChild(r);var f=document.getElementsByTagName("body")[0];return f.appendChild(s),r.onclick=function(){event.cancelBubble=!0},s.onclick=function(){},u.onclick=function(){f.removeChild(s),s=null,l(!1,t)},a.onclick=function(){f.removeChild(s),l(!(s=null),t)},e}(e)),n.toCanvas(r,t,function(t){t&&console.error(t)})}}}},{"./Utils":1,qrcode:15}],8:[function(t,e,r){"use strict";r.byteLength=function(t){var e=l(t),r=e[0],n=e[1];return 3*(r+n)/4-n},r.toByteArray=function(t){for(var e,r=l(t),n=r[0],o=r[1],i=new c(function(t,e){return 3*(t+e)/4-e}(n,o)),a=0,u=0>16&255,i[a++]=e>>8&255,i[a++]=255&e;2===o&&(e=f[t.charCodeAt(s)]<<2|f[t.charCodeAt(s+1)]>>4,i[a++]=255&e);1===o&&(e=f[t.charCodeAt(s)]<<10|f[t.charCodeAt(s+1)]<<4|f[t.charCodeAt(s+2)]>>2,i[a++]=e>>8&255,i[a++]=255&e);return i},r.fromByteArray=function(t){for(var e,r=t.length,n=r%3,o=[],i=0,a=r-n;i>2]+u[e<<4&63]+"==")):2==n&&(e=(t[r-2]<<8)+t[r-1],o.push(u[e>>10]+u[e>>4&63]+u[e<<2&63]+"="));return o.join("")};for(var u=[],f=[],c="undefined"!=typeof Uint8Array?Uint8Array:Array,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o=0,i=n.length;o>18&63]+u[o>>12&63]+u[o>>6&63]+u[63&o]);return i.join("")}f["-".charCodeAt(0)]=62,f["_".charCodeAt(0)]=63},{}],9:[function(t,r,e){!function(t){"use strict";var e,D=/^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,j=Math.ceil,q=Math.floor,F=" not a boolean or binary digit",z="rounding mode",Y="number type has more than 15 significant digits",H="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_",V=1e14,J=14,K=9007199254740991,Q=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],$=1e7,G=1e9;function W(t){var e=0|t;return 0i[a]^r?1:-1;return s==f?0:f=e&&t<=r}function tt(t){return"[object Array]"==Object.prototype.toString.call(t)}function et(t,e,r){for(var n,o,i=[0],a=0,u=t.length;ar-1&&(null==i[n+1]&&(i[n+1]=0),i[n+1]+=i[n]/r|0,i[n]%=r)}return i.reverse()}function rt(t,e){return(1(r=t.length)){for(n="0",e-=r;--e;n+="0");t+=n}else ee;)f[o]=0,o||(++i,f=[1].concat(f));for(a=f.length;!f[--a];);for(l=0,t="";l<=a;t+=H.charAt(f[l++]));t=nt(t,i)}return t}function P(t,e,r){var n,o,i,a,u=0,s=t.length,f=e%$,c=e/$|0;for(t=t.slice();s--;)u=((o=f*(i=t[s]%$)+(n=c*i+(a=t[s]/$|0)*f)%$*$+u)/r|0)+(n/$|0)+c*a,t[s]=o%r;return u&&(t=[u].concat(t)),t}function S(t,e,r,n){var o,i;if(r!=n)i=ne[o]?1:-1;break}return i}function M(t,e,r,n){for(var o=0;r--;)t[r]-=o,o=t[r]E?t.c=t.e=null:r=l.length){if(!n)break t;for(;l.length<=f;l.push(0));s=c=0,a=(i%=J)-J+(o=1)}else{for(s=u=l[f],o=1;10<=u;u/=10,o++);c=(a=(i%=J)-J+o)<0?0:s/h[o-a-1]%10|0}if(n=n||e<0||null!=l[f+1]||(a<0?s:s%h[o-a-1]),n=r<4?(c||n)&&(0==r||r==(t.s<0?3:2)):5E?t.c=t.e=null:t.e>>11))?(r=crypto.getRandomValues(new Uint32Array(2)),e[a]=r[0],e[a+1]=r[1]):(u.push(i%1e14),a+=2);a=o/2}else if(crypto.randomBytes){for(e=crypto.randomBytes(o*=7);a(B[u]||0)&&a--,A<0)p.push(1),s=!0;else{for(m=B.length,b=C.length,A+=2,1<(f=q(o/(C[u=0]+1)))&&(C=P(C,f,o),B=P(B,f,o),b=C.length,m=B.length),v=b,d=(g=B.slice(0,b)).length;d=o/2&&w++;do{if(f=0,(i=S(C,g,b,d))<0){if(y=g[0],b!=d&&(y=y*o+(g[1]||0)),1<(f=q(y/w)))for(o<=f&&(f=o-1),l=(c=P(C,f,o)).length,d=g.length;1==S(c,g,l,d);)f--,M(c,bthis.c.length-2},n.isNaN=function(){return!this.s},n.isNegative=n.isNeg=function(){return this.s<0},n.isZero=function(){return!!this.c&&0==this.c[0]},n.lessThan=n.lt=function(t,e){return b=8,i(this,new x(t,e))<0},n.lessThanOrEqualTo=n.lte=function(t,e){return b=9,-1===(e=i(this,new x(t,e)))||0===e},n.minus=n.sub=function(t,e){var r,n,o,i,a=this,u=a.s;if(b=10,e=(t=new x(t,e)).s,!u||!e)return new x(NaN);if(u!=e)return t.s=-e,a.plus(t);var s=a.e/J,f=t.e/J,c=a.c,l=t.c;if(!s||!f){if(!c||!l)return c?(t.s=-e,t):new x(l?a:NaN);if(!c[0]||!l[0])return l[0]?(t.s=-e,t):new x(c[0]?a:3==m?-0:0)}if(s=W(s),f=W(f),c=c.slice(),u=s-f){for((o=(i=u<0)?(u=-u,c):(f=s,l)).reverse(),e=u;e--;o.push(0));o.reverse()}else for(n=(i=(u=c.length)<(e=l.length))?u:e,u=e=0;ee&&(e=this.e+1),e},n.round=function(t,e){var r=new x(this);return null!=t&&!B(t,0,G,15)||k(r,~~t+this.e+1,null!=e&&B(e,0,8,15,z)?0|e:m),r},n.shift=function(t){var e=this;return B(t,-K,K,16,"argument")?e.times("1e"+ot(t)):new x(e.c&&e.c[0]&&(t<-K||Kr&&(n.c.length=r):e&&(n=n.mod(e))}if(!(i=q(i/2)))break;a=a.times(a),r?a.c&&a.c.length>r&&(a.c.length=r):e&&(a=a.mod(e))}return e?n:(t<0&&(n=v.div(n)),o?n.mod(o):r?k(n,N,m):n)},n.toPrecision=function(t,e){return U(this,null!=t&&B(t,1,G,24,"precision")?0|t:null,e,24)},n.toString=function(t){var e,r=this.s,n=this.e;return null===n?r?(e="Infinity",r<0&&(e="-"+e)):e="NaN":(e=X(this.c),e=null!=t&&B(t,2,64,25,"base")?I(nt(e,n),0|t,10,r):(n<=p||d<=n?rt:nt)(e,n),r<0&&this.c[0]&&(e="-"+e)),e},n.truncated=n.trunc=function(){return k(new x(this),this.e+1,1)},n.valueOf=n.toJSON=function(){var t,e=this.e;return null===e?this.toString():(t=X(this.c),t=(e<=p||d<=e?rt:nt)(t,e),this.s<0?"-"+t:t)},n.isBigNumber=!0,null!=e&&x.config(e),x}()).default=e.BigNumber=e,"function"==typeof define&&define.amd?define(function(){return e}):void 0!==r&&r.exports?r.exports=e:(t=t||("undefined"!=typeof self?self:Function("return this")())).BigNumber=e}(this)},{}],10:[function(D,t,j){(function(l){"use strict";var n=D("base64-js"),i=D("ieee754"),t="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):null;j.Buffer=l,j.SlowBuffer=function(t){+t!=t&&(t=0);return l.alloc(+t)},j.INSPECT_MAX_BYTES=50;var r=2147483647;function a(t){if(r>>1;case"base64":return U(t).length;default:if(o)return n?-1:M(t).length;e=(""+e).toLowerCase(),o=!0}}function g(t,e,r){var n=t[e];t[e]=t[r],t[r]=n}function d(t,e,r,n,o){if(0===t.length)return-1;if("string"==typeof r?(n=r,r=0):2147483647=t.length){if(o)return-1;r=t.length-1}else if(r<0){if(!o)return-1;r=0}if("string"==typeof e&&(e=l.from(e,n)),l.isBuffer(e))return 0===e.length?-1:y(t,e,r,n,o);if("number"==typeof e)return e&=255,"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(t,e,r):Uint8Array.prototype.lastIndexOf.call(t,e,r):y(t,[e],r,n,o);throw new TypeError("val must be string, number or Buffer")}function y(t,e,r,n,o){var i,a=1,u=t.length,s=e.length;if(void 0!==n&&("ucs2"===(n=String(n).toLowerCase())||"ucs-2"===n||"utf16le"===n||"utf-16le"===n)){if(t.length<2||e.length<2)return-1;u/=a=2,s/=2,r/=2}function f(t,e){return 1===a?t[e]:t.readUInt16BE(e*a)}if(o){var c=-1;for(i=r;i>8,o=r%256,i.push(o),i.push(n);return i}(e,t.length-r),t,r,n)}function b(t,e,r){return 0===e&&r===t.length?n.fromByteArray(t):n.fromByteArray(t.slice(e,r))}function E(t,e,r){r=Math.min(t.length,r);for(var n=[],o=e;o>>10&1023|55296),c=56320|1023&c),n.push(c),o+=l}return function(t){var e=t.length;if(e<=A)return String.fromCharCode.apply(String,t);var r="",n=0;for(;nthis.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(e>>>=0))return"";for(t=t||"utf8";;)switch(t){case"hex":return T(this,e,r);case"utf8":case"utf-8":return E(this,e,r);case"ascii":return B(this,e,r);case"latin1":case"binary":return C(this,e,r);case"base64":return b(this,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return N(this,e,r);default:if(n)throw new TypeError("Unknown encoding: "+t);t=(t+"").toLowerCase(),n=!0}}.apply(this,arguments)},l.prototype.equals=function(t){if(!l.isBuffer(t))throw new TypeError("Argument must be a Buffer");return this===t||0===l.compare(this,t)},l.prototype.inspect=function(){var t="",e=j.INSPECT_MAX_BYTES;return t=this.toString("hex",0,e).replace(/(.{2})/g,"$1 ").trim(),this.length>e&&(t+=" ... "),""},t&&(l.prototype[t]=l.prototype.inspect),l.prototype.compare=function(t,e,r,n,o){if(O(t,Uint8Array)&&(t=l.from(t,t.offset,t.byteLength)),!l.isBuffer(t))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof t);if(void 0===e&&(e=0),void 0===r&&(r=t?t.length:0),void 0===n&&(n=0),void 0===o&&(o=this.length),e<0||r>t.length||n<0||o>this.length)throw new RangeError("out of range index");if(o<=n&&r<=e)return 0;if(o<=n)return-1;if(r<=e)return 1;if(this===t)return 0;for(var i=(o>>>=0)-(n>>>=0),a=(r>>>=0)-(e>>>=0),u=Math.min(i,a),s=this.slice(n,o),f=t.slice(e,r),c=0;c>>=0,isFinite(r)?(r>>>=0,void 0===n&&(n="utf8")):(n=r,r=void 0)}var o=this.length-e;if((void 0===r||othis.length)throw new RangeError("Attempt to write outside buffer bounds");n=n||"utf8";for(var i,a,u,s,f,c,l=!1;;)switch(n){case"hex":return v(this,t,e,r);case"utf8":case"utf-8":return f=e,c=r,L(M(t,(s=this).length-f),s,f,c);case"ascii":return m(this,t,e,r);case"latin1":case"binary":return m(this,t,e,r);case"base64":return i=this,a=e,u=r,L(U(t),i,a,u);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return w(this,t,e,r);default:if(l)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),l=!0}},l.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var A=4096;function B(t,e,r){var n="";r=Math.min(t.length,r);for(var o=e;ot.length)throw new RangeError("Index out of range")}function I(t,e,r,n){if(r+n>t.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function P(t,e,r,n,o){return e=+e,r>>>=0,o||I(t,0,r,4),i.write(t,e,r,n,23,4),r+4}function S(t,e,r,n,o){return e=+e,r>>>=0,o||I(t,0,r,8),i.write(t,e,r,n,52,8),r+8}l.prototype.slice=function(t,e){var r=this.length;(t=~~t)<0?(t+=r)<0&&(t=0):r>>=0,e>>>=0,r||R(t,e,this.length);for(var n=this[t],o=1,i=0;++i>>=0,e>>>=0,r||R(t,e,this.length);for(var n=this[t+--e],o=1;0>>=0,e||R(t,1,this.length),this[t]},l.prototype.readUInt16LE=function(t,e){return t>>>=0,e||R(t,2,this.length),this[t]|this[t+1]<<8},l.prototype.readUInt16BE=function(t,e){return t>>>=0,e||R(t,2,this.length),this[t]<<8|this[t+1]},l.prototype.readUInt32LE=function(t,e){return t>>>=0,e||R(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+16777216*this[t+3]},l.prototype.readUInt32BE=function(t,e){return t>>>=0,e||R(t,4,this.length),16777216*this[t]+(this[t+1]<<16|this[t+2]<<8|this[t+3])},l.prototype.readIntLE=function(t,e,r){t>>>=0,e>>>=0,r||R(t,e,this.length);for(var n=this[t],o=1,i=0;++i>>=0,e>>>=0,r||R(t,e,this.length);for(var n=e,o=1,i=this[t+--n];0>>=0,e||R(t,1,this.length),128&this[t]?-1*(255-this[t]+1):this[t]},l.prototype.readInt16LE=function(t,e){t>>>=0,e||R(t,2,this.length);var r=this[t]|this[t+1]<<8;return 32768&r?4294901760|r:r},l.prototype.readInt16BE=function(t,e){t>>>=0,e||R(t,2,this.length);var r=this[t+1]|this[t]<<8;return 32768&r?4294901760|r:r},l.prototype.readInt32LE=function(t,e){return t>>>=0,e||R(t,4,this.length),this[t]|this[t+1]<<8|this[t+2]<<16|this[t+3]<<24},l.prototype.readInt32BE=function(t,e){return t>>>=0,e||R(t,4,this.length),this[t]<<24|this[t+1]<<16|this[t+2]<<8|this[t+3]},l.prototype.readFloatLE=function(t,e){return t>>>=0,e||R(t,4,this.length),i.read(this,t,!0,23,4)},l.prototype.readFloatBE=function(t,e){return t>>>=0,e||R(t,4,this.length),i.read(this,t,!1,23,4)},l.prototype.readDoubleLE=function(t,e){return t>>>=0,e||R(t,8,this.length),i.read(this,t,!0,52,8)},l.prototype.readDoubleBE=function(t,e){return t>>>=0,e||R(t,8,this.length),i.read(this,t,!1,52,8)},l.prototype.writeUIntLE=function(t,e,r,n){t=+t,e>>>=0,r>>>=0,n||x(this,t,e,r,Math.pow(2,8*r)-1,0);var o=1,i=0;for(this[e]=255&t;++i>>=0,r>>>=0,n||x(this,t,e,r,Math.pow(2,8*r)-1,0);var o=r-1,i=1;for(this[e+o]=255&t;0<=--o&&(i*=256);)this[e+o]=t/i&255;return e+r},l.prototype.writeUInt8=function(t,e,r){return t=+t,e>>>=0,r||x(this,t,e,1,255,0),this[e]=255&t,e+1},l.prototype.writeUInt16LE=function(t,e,r){return t=+t,e>>>=0,r||x(this,t,e,2,65535,0),this[e]=255&t,this[e+1]=t>>>8,e+2},l.prototype.writeUInt16BE=function(t,e,r){return t=+t,e>>>=0,r||x(this,t,e,2,65535,0),this[e]=t>>>8,this[e+1]=255&t,e+2},l.prototype.writeUInt32LE=function(t,e,r){return t=+t,e>>>=0,r||x(this,t,e,4,4294967295,0),this[e+3]=t>>>24,this[e+2]=t>>>16,this[e+1]=t>>>8,this[e]=255&t,e+4},l.prototype.writeUInt32BE=function(t,e,r){return t=+t,e>>>=0,r||x(this,t,e,4,4294967295,0),this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t,e+4},l.prototype.writeIntLE=function(t,e,r,n){if(t=+t,e>>>=0,!n){var o=Math.pow(2,8*r-1);x(this,t,e,r,o-1,-o)}var i=0,a=1,u=0;for(this[e]=255&t;++i>0)-u&255;return e+r},l.prototype.writeIntBE=function(t,e,r,n){if(t=+t,e>>>=0,!n){var o=Math.pow(2,8*r-1);x(this,t,e,r,o-1,-o)}var i=r-1,a=1,u=0;for(this[e+i]=255&t;0<=--i&&(a*=256);)t<0&&0===u&&0!==this[e+i+1]&&(u=1),this[e+i]=(t/a>>0)-u&255;return e+r},l.prototype.writeInt8=function(t,e,r){return t=+t,e>>>=0,r||x(this,t,e,1,127,-128),t<0&&(t=255+t+1),this[e]=255&t,e+1},l.prototype.writeInt16LE=function(t,e,r){return t=+t,e>>>=0,r||x(this,t,e,2,32767,-32768),this[e]=255&t,this[e+1]=t>>>8,e+2},l.prototype.writeInt16BE=function(t,e,r){return t=+t,e>>>=0,r||x(this,t,e,2,32767,-32768),this[e]=t>>>8,this[e+1]=255&t,e+2},l.prototype.writeInt32LE=function(t,e,r){return t=+t,e>>>=0,r||x(this,t,e,4,2147483647,-2147483648),this[e]=255&t,this[e+1]=t>>>8,this[e+2]=t>>>16,this[e+3]=t>>>24,e+4},l.prototype.writeInt32BE=function(t,e,r){return t=+t,e>>>=0,r||x(this,t,e,4,2147483647,-2147483648),t<0&&(t=4294967295+t+1),this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t,e+4},l.prototype.writeFloatLE=function(t,e,r){return P(this,t,e,!0,r)},l.prototype.writeFloatBE=function(t,e,r){return P(this,t,e,!1,r)},l.prototype.writeDoubleLE=function(t,e,r){return S(this,t,e,!0,r)},l.prototype.writeDoubleBE=function(t,e,r){return S(this,t,e,!1,r)},l.prototype.copy=function(t,e,r,n){if(!l.isBuffer(t))throw new TypeError("argument should be a Buffer");if(r=r||0,n||0===n||(n=this.length),e>=t.length&&(e=t.length),e=e||0,0=this.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),t.length-e>>=0,r=void 0===r?this.length:r>>>0,"number"==typeof(t=t||0))for(i=e;i>6|192,63&r|128)}else if(r<65536){if((e-=3)<0)break;i.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((e-=4)<0)break;i.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return i}function U(t){return n.toByteArray(function(t){if((t=(t=t.split("=")[0]).trim().replace(e,"")).length<2)return"";for(;t.length%4!=0;)t+="=";return t}(t))}function L(t,e,r,n){for(var o=0;o=e.length||o>=t.length);++o)e[o+r]=t[o];return o}function O(t,e){return t instanceof e||null!=t&&null!=t.constructor&&null!=t.constructor.name&&t.constructor.name===e.name}function _(t){return t!=t}var k=function(){for(var t="0123456789abcdef",e=new Array(256),r=0;r<16;++r)for(var n=16*r,o=0;o<16;++o)e[n+o]=t[r]+t[o];return e}()}).call(this,D("buffer").Buffer)},{"base64-js":8,buffer:10,ieee754:13}],11:[function(t,e,r){"use strict";var g={single_source_shortest_paths:function(t,e,r){var n={},o={};o[e]=0;var i,a,u,s,f,c,l,h=g.PriorityQueue.make();for(h.push(e,0);!h.empty();)for(u in a=(i=h.pop()).value,s=i.cost,f=t[a]||{})f.hasOwnProperty(u)&&(c=s+f[u],l=o[u],(void 0===o[u]||c>1,c=-7,l=r?o-1:0,h=r?-1:1,p=t[e+l];for(l+=h,i=p&(1<<-c)-1,p>>=-c,c+=u;0>=-c,c+=n;0>1,h=23===o?Math.pow(2,-24)-Math.pow(2,-77):0,p=n?0:i-1,g=n?1:-1,d=e<0||0===e&&1/e<0?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(u=isNaN(e)?1:0,a=c):(a=Math.floor(Math.log(e)/Math.LN2),e*(s=Math.pow(2,-a))<1&&(a--,s*=2),2<=(e+=1<=a+l?h/s:h*Math.pow(2,1-l))*s&&(a++,s/=2),c<=a+l?(u=0,a=c):1<=a+l?(u=(e*s-1)*Math.pow(2,o),a+=l):(u=e*Math.pow(2,l-1)*Math.pow(2,o),a=0));8<=o;t[r+p]=255&u,p+=g,u/=256,o-=8);for(a=a<>>7-t%8&1)},put:function(t,e){for(var r=0;r>>e-r-1&1))},getLengthInBits:function(){return this.length},putBit:function(t){var e=Math.floor(this.length/8);this.buffer.length<=e&&this.buffer.push(0),t&&(this.buffer[e]|=128>>>this.length%8),this.length++}},e.exports=n},{}],20:[function(t,e,r){var n=t("../utils/buffer");function o(t){if(!t||t<1)throw new Error("BitMatrix size must be defined and greater than 0");this.size=t,this.data=n.alloc(t*t),this.reservedBit=n.alloc(t*t)}o.prototype.set=function(t,e,r,n){var o=t*this.size+e;this.data[o]=r,n&&(this.reservedBit[o]=!0)},o.prototype.get=function(t,e){return this.data[t*this.size+e]},o.prototype.xor=function(t,e,r){this.data[t*this.size+e]^=r},o.prototype.isReserved=function(t,e){return this.reservedBit[t*this.size+e]},e.exports=o},{"../utils/buffer":42}],21:[function(t,e,r){var n=t("../utils/buffer"),o=t("./mode");function i(t){this.mode=o.BYTE,this.data=n.from(t)}i.getBitsLength=function(t){return 8*t},i.prototype.getLength=function(){return this.data.length},i.prototype.getBitsLength=function(){return i.getBitsLength(this.data.length)},i.prototype.write=function(t){for(var e=0,r=this.data.length;e>>8&255)+(255&r),t.put(r,13)}},e.exports=i},{"./mode":29,"./utils":36}],28:[function(t,e,u){u.Patterns={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};var c=3,a=3,s=40,o=10;function i(t,e,r){switch(t){case u.Patterns.PATTERN000:return(e+r)%2==0;case u.Patterns.PATTERN001:return e%2==0;case u.Patterns.PATTERN010:return r%3==0;case u.Patterns.PATTERN011:return(e+r)%3==0;case u.Patterns.PATTERN100:return(Math.floor(e/2)+Math.floor(r/3))%2==0;case u.Patterns.PATTERN101:return e*r%2+e*r%3==0;case u.Patterns.PATTERN110:return(e*r%2+e*r%3)%2==0;case u.Patterns.PATTERN111:return(e*r%3+(e+r)%2)%2==0;default:throw new Error("bad maskPattern:"+t)}}u.isValid=function(t){return null!=t&&""!==t&&!isNaN(t)&&0<=t&&t<=7},u.from=function(t){return u.isValid(t)?parseInt(t,10):void 0},u.getPenaltyN1=function(t){for(var e=t.size,r=0,n=0,o=0,i=null,a=null,u=0;u>n&1),n<6?t.set(n,8,o,!0):n<8?t.set(n+1,8,o,!0):t.set(i-15+n,8,o,!0),n<8?t.set(8,i-n-1,o,!0):n<9?t.set(8,15-n-1+1,o,!0):t.set(8,15-n-1,o,!0);t.set(i-8,8,1,!0)}function w(e,t,r){var n=new u;r.forEach(function(t){n.put(t.mode.bit,4),n.put(t.getLength(),f.getCharCountIndicator(t.mode,e)),t.write(n)});var o=8*(T.getSymbolTotalCodewords(e)-N.getTotalCodewordsCount(e,t));for(n.getLengthInBits()+4<=o&&n.put(0,4);n.getLengthInBits()%8!=0;)n.putBit(0);for(var i=(o-n.getLengthInBits())/8,a=0;a>u&1),t.set(r,n,o,!0),t.set(n,r,o,!0)}(c,e),function(t,e){for(var r=t.size,n=-1,o=r-1,i=7,a=0,u=r-1;0>>i&1)),t.set(o,u-s,f),-1===--i&&(a++,i=7)}if((o+=n)<0||r<=o){o-=n,n=-n;break}}}(c,s),isNaN(n)&&(n=g.getBestMask(c,m.bind(null,c,r))),g.applyMask(n,c),m(c,r,n),{modules:c,version:e,errorCorrectionLevel:r,maskPattern:n,segments:o}}r.create=function(t,e){if(void 0===t||""===t)throw new Error("No input text");var r,n,o=i.M;return void 0!==e&&(o=i.from(e.errorCorrectionLevel,i.M),r=d.from(e.version),n=g.from(e.maskPattern),e.toSJISFunc&&T.setToSJISFunction(e.toSJISFunc)),a(t,r,o,n)}},{"../utils/buffer":42,"./alignment-pattern":17,"./bit-buffer":19,"./bit-matrix":20,"./error-correction-code":22,"./error-correction-level":23,"./finder-pattern":24,"./format-info":25,"./mask-pattern":28,"./mode":29,"./reed-solomon-encoder":33,"./segments":35,"./utils":36,"./version":38,isarray:14}],33:[function(t,e,r){var a=t("../utils/buffer"),u=t("./polynomial"),s=t("buffer").Buffer;function n(t){this.genPoly=void 0,this.degree=t,this.degree&&this.initialize(this.degree)}n.prototype.initialize=function(t){this.degree=t,this.genPoly=u.generateECPolynomial(this.degree)},n.prototype.encode=function(t){if(!this.genPoly)throw new Error("Encoder not initialized");var e=a.alloc(this.degree),r=s.concat([t,e],t.length+this.degree),n=u.mod(r,this.genPoly),o=this.degree-n.length;if(0>>=1;return e},r.setToSJISFunction=function(t){if("function"!=typeof t)throw new Error('"toSJISFunc" is not a valid function.');n=t},r.isKanjiModeEnabled=function(){return void 0!==n},r.toSJIS=function(t){return n(t)}},{}],37:[function(t,e,r){r.isValid=function(t){return!isNaN(t)&&1<=t&&t<=40}},{}],38:[function(t,e,o){var i=t("./utils"),a=t("./error-correction-code"),u=t("./error-correction-level"),s=t("./mode"),f=t("./version-check"),c=t("isarray"),r=i.getBCHDigit(7973);function l(t,e){return s.getCharCountIndicator(t,e)+4}function h(t,r){var n=0;return t.forEach(function(t){var e=l(t.mode,r);n+=e+t.getBitsLength()}),n}o.from=function(t,e){return f.isValid(t)?parseInt(t,10):e},o.getCapacity=function(t,e,r){if(!f.isValid(t))throw new Error("Invalid QR Code version");void 0===r&&(r=s.BYTE);var n=8*(i.getSymbolTotalCodewords(t)-a.getTotalCodewordsCount(t,e));if(r===s.MIXED)return n;var o=n-l(r,t);switch(r){case s.NUMERIC:return Math.floor(o/10*3);case s.ALPHANUMERIC:return Math.floor(o/11*2);case s.KANJI:return Math.floor(o/13);case s.BYTE:default:return Math.floor(o/8)}},o.getBestVersionForData=function(t,e){var r,n=u.from(e,u.M);if(c(t)){if(1':"",s="',f='viewBox="0 0 '+a+" "+a+'"',c='\n";return"function"==typeof r&&r(null,c),c}},{"./utils":41}],41:[function(t,e,p){function o(t){if("number"==typeof t&&(t=t.toString()),"string"!=typeof t)throw new Error("Color should be defined as hex string");var e=t.slice().replace("#","").split("");if(e.length<3||5===e.length||8>24&255,g:r>>16&255,b:r>>8&255,a:255&r,hex:"#"+e.slice(0,6).join("")}}p.getOptions=function(t){(t=t||{}).color||(t.color={});var e=void 0===t.margin||null===t.margin||t.margin<0?4:t.margin,r=t.width&&21<=t.width?t.width:void 0,n=t.scale||4;return{width:r,scale:r?4:n,margin:e,color:{dark:o(t.color.dark||"#000000ff"),light:o(t.color.light||"#ffffffff")},type:t.type,rendererOpts:t.rendererOpts||{}}},p.getScale=function(t,e){return e.width&&e.width>=t+2*e.margin?e.width/(t+2*e.margin):e.scale},p.getImageWidth=function(t,e){var r=p.getScale(t,e);return Math.floor((t+2*e.margin)*r)},p.qrToImageData=function(t,e,r){for(var n=e.modules.size,o=e.modules.data,i=p.getScale(n,r),a=Math.floor((n+2*r.margin)*i),u=r.margin*i,s=[r.color.light,r.color.dark],f=0;f>6|192,63&r|128)}else if(r<65536){if((e-=3)<0)break;i.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((e-=4)<0)break;i.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return i}function l(t){return u.isBuffer(t)?t.length:"undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(t)||t instanceof ArrayBuffer)?t.byteLength:("string"!=typeof t&&(t=""+t),0===t.length?0:o(t).length)}function h(t,e,r,n){return function(t,e,r,n){for(var o=0;o=e.length||o>=t.length);++o)e[o+r]=t[o];return o}(o(e,t.length-r),t,r,n)}u.TYPED_ARRAY_SUPPORT&&(u.prototype.__proto__=Uint8Array.prototype,u.__proto__=Uint8Array,"undefined"!=typeof Symbol&&Symbol.species&&u[Symbol.species]===u&&Object.defineProperty(u,Symbol.species,{value:null,configurable:!0,enumerable:!1,writable:!1})),u.prototype.write=function(t,e,r){void 0===e||void 0===r&&"string"==typeof e?(r=this.length,e=0):isFinite(e)&&(e|=0,isFinite(r)?r|=0:r=void 0);var n=this.length-e;if((void 0===r||nthis.length)throw new RangeError("Attempt to write outside buffer bounds");return h(this,t,e,r)},u.prototype.slice=function(t,e){var r,n=this.length;if((t=~~t)<0?(t+=n)<0&&(t=0):n=t.length&&(e=t.length),e=e||0,0=this.length)throw new RangeError("sourceStart out of bounds");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),t.length-e>>=0,r=void 0===r?this.length:r>>>0,"number"==typeof(t=t||0))for(o=e;o