├── MyEtherWallet:05-钱包项目整体架构设计 ├── index.js ├── package-lock.json ├── package.json ├── router │ └── router.js ├── static │ ├── css │ │ └── wallet.css │ ├── html │ │ └── nav.html │ └── js │ │ ├── lib │ │ ├── jquery-3.3.1.min.js │ │ └── jquery.url.js │ │ └── wallet.js ├── utils │ └── myUtils.js └── views │ └── newaccount.html ├── MyEtherWallet:06-Coding:生成账户的地址、私钥、keystore、助记词 ├── controllers │ └── newAccount.js ├── index.js ├── package-lock.json ├── package.json ├── router │ └── router.js ├── static │ ├── css │ │ └── wallet.css │ ├── html │ │ └── nav.html │ ├── js │ │ ├── lib │ │ │ ├── jquery-3.3.1.min.js │ │ │ └── jquery.url.js │ │ └── wallet.js │ └── keystore │ │ └── UTC--2018-09-25T06:24:28.689Z--42f971FC3443B43313441E68f7548b3BD0713dB9 ├── utils │ └── myUtils.js └── views │ ├── downloadkeystore.html │ └── newaccount.html ├── MyEtherWallet:07-解锁钱包账号姿势一:私钥 ├── controllers │ ├── account.js │ ├── newAccount.js │ └── transaction.js ├── index.js ├── package-lock.json ├── package.json ├── router │ └── router.js ├── static │ ├── css │ │ └── wallet.css │ ├── html │ │ └── nav.html │ ├── js │ │ ├── lib │ │ │ ├── jquery-3.3.1.min.js │ │ │ └── jquery.url.js │ │ └── wallet.js │ └── keystore │ │ ├── UTC--2018-09-25T06:24:28.689Z--42f971FC3443B43313441E68f7548b3BD0713dB9 │ │ ├── UTC--2018-09-25T06:33:18.858Z--709b7348Cb70D65b9C65C0c884B2bF7e02f5B939 │ │ └── UTC--2018-09-25T06:34:49.890Z--a2d73CF52034462ACBb359154c2fe3Fc688709A6 ├── utils │ └── myUtils.js └── views │ ├── downloadkeystore.html │ ├── newaccount.html │ └── transaction.html ├── MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码 ├── controllers │ ├── account.js │ ├── newAccount.js │ └── transaction.js ├── index.js ├── package-lock.json ├── package.json ├── router │ └── router.js ├── static │ ├── css │ │ └── wallet.css │ ├── html │ │ └── nav.html │ ├── js │ │ ├── lib │ │ │ ├── jquery-3.3.1.min.js │ │ │ └── jquery.url.js │ │ └── wallet.js │ └── keystore │ │ ├── UTC--2018-09-25T06:24:28.689Z--42f971FC3443B43313441E68f7548b3BD0713dB9 │ │ ├── UTC--2018-09-25T06:33:18.858Z--709b7348Cb70D65b9C65C0c884B2bF7e02f5B939 │ │ └── UTC--2018-09-25T06:34:49.890Z--a2d73CF52034462ACBb359154c2fe3Fc688709A6 ├── utils │ └── myUtils.js └── views │ ├── downloadkeystore.html │ ├── newaccount.html │ └── transaction.html ├── MyEtherWallet:09-解锁钱包账号姿势三:助记词 ├── controllers │ ├── account.js │ ├── newAccount.js │ └── transaction.js ├── index.js ├── models │ └── mnemonic.js ├── package-lock.json ├── package.json ├── router │ └── router.js ├── static │ ├── css │ │ └── wallet.css │ ├── html │ │ └── nav.html │ ├── js │ │ ├── lib │ │ │ ├── jquery-3.3.1.min.js │ │ │ └── jquery.url.js │ │ └── wallet.js │ └── keystore │ │ ├── UTC--2018-09-25T06:24:28.689Z--42f971FC3443B43313441E68f7548b3BD0713dB9 │ │ ├── UTC--2018-09-25T06:33:18.858Z--709b7348Cb70D65b9C65C0c884B2bF7e02f5B939 │ │ └── UTC--2018-09-25T06:34:49.890Z--a2d73CF52034462ACBb359154c2fe3Fc688709A6 ├── utils │ └── myUtils.js └── views │ ├── downloadkeystore.html │ ├── newaccount.html │ └── transaction.html ├── MyEtherWallet:10-浅出:如何实现以太币转账 ├── controllers │ ├── account.js │ ├── newAccount.js │ └── transaction.js ├── index.js ├── models │ └── mnemonic.js ├── package-lock.json ├── package.json ├── router │ └── router.js ├── static │ ├── css │ │ └── wallet.css │ ├── html │ │ └── nav.html │ ├── js │ │ ├── lib │ │ │ ├── jquery-3.3.1.min.js │ │ │ └── jquery.url.js │ │ └── wallet.js │ └── keystore │ │ ├── UTC--2018-09-25T06:24:28.689Z--42f971FC3443B43313441E68f7548b3BD0713dB9 │ │ ├── UTC--2018-09-25T06:33:18.858Z--709b7348Cb70D65b9C65C0c884B2bF7e02f5B939 │ │ └── UTC--2018-09-25T06:34:49.890Z--a2d73CF52034462ACBb359154c2fe3Fc688709A6 ├── utils │ └── myUtils.js └── views │ ├── downloadkeystore.html │ ├── newaccount.html │ └── transaction.html ├── MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 ├── controllers │ ├── account.js │ ├── newAccount.js │ ├── token.js │ └── transaction.js ├── index.js ├── models │ ├── contract.js │ └── mnemonic.js ├── package-lock.json ├── package.json ├── router │ └── router.js ├── static │ ├── css │ │ └── wallet.css │ ├── html │ │ └── nav.html │ ├── js │ │ ├── lib │ │ │ ├── jquery-3.3.1.min.js │ │ │ └── jquery.url.js │ │ └── wallet.js │ └── keystore │ │ ├── UTC--2018-09-25T06:24:28.689Z--42f971FC3443B43313441E68f7548b3BD0713dB9 │ │ ├── UTC--2018-09-25T06:33:18.858Z--709b7348Cb70D65b9C65C0c884B2bF7e02f5B939 │ │ └── UTC--2018-09-25T06:34:49.890Z--a2d73CF52034462ACBb359154c2fe3Fc688709A6 ├── utils │ └── myUtils.js └── views │ ├── downloadkeystore.html │ ├── newaccount.html │ └── transaction.html └── README.md /MyEtherWallet:05-钱包项目整体架构设计/index.js: -------------------------------------------------------------------------------- 1 | 2 | let koa = require("koa") 3 | //通过koa创建一个应用程序 4 | let app = new koa() 5 | //导入./router/route这个包,赋值给的router就是 ./router/router导出的数据 6 | let router = require("./router/router") 7 | let static = require("koa-static") 8 | let path = require("path") 9 | let views = require("koa-views") 10 | let koaBody = require("koa-body") 11 | 12 | app.use(async (ctx, next) => { 13 | console.log(`${ctx.method} ${ctx.url} ..........`) 14 | await next() 15 | }) 16 | 17 | //针对于文件上传的时候,可以解析多个字段 18 | app.use(koaBody({multipart:true})) 19 | //注册静态文件的库到中间件 20 | app.use(static(path.join(__dirname, "static"))) 21 | //注册模板引擎的库到中间件 22 | app.use(views(path.join(__dirname, "views"), {extension:"ejs", map:{html:"ejs"}})) 23 | app.use(router.routes()) 24 | 25 | console.log("正在监听3000端口") 26 | app.listen(3000) 27 | -------------------------------------------------------------------------------- /MyEtherWallet:05-钱包项目整体架构设计/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "4-wallet", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "bignumber": "^1.1.0", 13 | "ejs": "^2.6.1", 14 | "ethereumjs-tx": "^1.3.7", 15 | "koa": "^2.5.2", 16 | "koa-body": "^4.0.4", 17 | "koa-router": "^7.4.0", 18 | "koa-static": "^5.0.0", 19 | "koa-views": "^6.1.4", 20 | "web3": "^1.0.0-beta.35", 21 | "bip39": "^2.5.0", 22 | "ethereumjs-util": "^5.2.0", 23 | "ethereumjs-wallet": "^0.6.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MyEtherWallet:05-钱包项目整体架构设计/router/router.js: -------------------------------------------------------------------------------- 1 | 2 | let router = require("koa-router")() 3 | 4 | router.get("/", async (ctx) => { 5 | await ctx.render("newaccount.html") 6 | }) 7 | 8 | module.exports = router 9 | -------------------------------------------------------------------------------- /MyEtherWallet:05-钱包项目整体架构设计/static/css/wallet.css: -------------------------------------------------------------------------------- 1 | 2 | #main{ 3 | /*background-color: #8bc34a;*/ 4 | margin: 100px 50px 50px 50px; 5 | 6 | } 7 | .error{ 8 | color: red; 9 | } 10 | a{ 11 | color: black; 12 | text-decoration: none; 13 | } 14 | a:hover{ 15 | color: #666; 16 | } 17 | body{ 18 | margin: 0px; 19 | } 20 | .global-color{ 21 | color: #0abc9c; 22 | } 23 | a[class=button]{ 24 | background-color: beige; 25 | padding: 2px 10px; 26 | border: 1px solid gray; 27 | } 28 | 29 | /*导航-------------------------------------------------------------------------------------------------------*/ 30 | #nav{ 31 | display: flex; 32 | justify-content: space-between; 33 | background-color: #0abc9c; 34 | position: fixed; 35 | top: 0px; 36 | left: 0px; 37 | right: 0px; 38 | } 39 | #nav li{ 40 | display: inline-block; 41 | margin: 10px 2px; 42 | } 43 | #nav ul{ 44 | padding: 0px; 45 | } 46 | #nav a{ 47 | padding: 10px; 48 | font-size: 24px; 49 | } 50 | #nav-left{ 51 | margin-left: 20px; 52 | } 53 | #nav-right{ 54 | margin-right: 20px; 55 | } 56 | -------------------------------------------------------------------------------- /MyEtherWallet:05-钱包项目整体架构设计/static/html/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /MyEtherWallet:05-钱包项目整体架构设计/static/js/lib/jquery.url.js: -------------------------------------------------------------------------------- 1 | //cookie 2 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(3(a){4(v 9===\'3\'&&9.G){9([\'H\'],a)}I{a(J)}}(3($){2 m=/\\+/g;3 7(s){5 s}3 w(s){5 K(s.o(m,\' \'))}3 p(s){4(s.L(\'"\')===0){s=s.M(1,-1).o(/\\\\"/g,\'"\').o(/\\\\\\\\/g,\'\\\\\')}N{5 n.x?y.O(s):s}P(Q){}}2 n=$.8=3(a,b,c){4(b!==q){c=$.z({},n.A,c);4(v c.6===\'R\'){2 d=c.6,t=c.6=S T();t.U(t.V()+d)}b=n.x?y.W(b):X(b);5(B.8=[n.7?a:C(a),\'=\',n.7?b:C(b),c.6?\'; 6=\'+c.6.Y():\'\',c.r?\'; r=\'+c.r:\'\',c.u?\'; u=\'+c.u:\'\',c.D?\'; D\':\'\'].E(\'\'))}2 e=n.7?7:w;2 f=B.8.F(\'; \');2 g=a?q:{};Z(2 i=0,l=f.10;i=b&&y<=b+w.height()&&x+t.width()>=a&&x<=a+w.width()){if(!t.appeared)t.trigger('appear',s.data);}else{t.appeared=false;}};var m=function(){t.appeared=true;if(s.one){w.unbind('scroll',c);var i=$.inArray(c,$.fn.appear.checks);if(i>=0)$.fn.appear.checks.splice(i,1);}f.apply(this,arguments);};if(s.one)t.one('appear',s.data,m);else t.bind('appear',s.data,m);w.scroll(c);$.fn.appear.checks.push(c);(c)();});};$.extend($.fn.appear,{checks:[],timeout:null,checkAll:function(){var l=$.fn.appear.checks.length;if(l>0)while(l--)($.fn.appear.checks[l])();},run:function(){if($.fn.appear.timeout)clearTimeout($.fn.appear.timeout);$.fn.appear.timeout=setTimeout($.fn.appear.checkAll,20);}});$.each(['append','prepend','after','before','attr','removeAttr','addClass','removeClass','toggleClass','remove','css','show','hide'],function(i,n){var u=$.fn[n];if(u){$.fn[n]=function(){var r=u.apply(this,arguments);$.fn.appear.run();return r;}}});})(jQuery); 6 | 7 | //url 8 | ;(function($,undefined){var tag2attr={a:'href',img:'src',form:'action',base:'href',script:'src',iframe:'src',link:'href'},key=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","fragment"],aliases={"anchor":"fragment"},parser={strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/},querystring_parser=/(?:^|&|;)([^&=;]*)=?([^&;]*)/g,fragment_parser=/(?:^|&|;)([^&=;]*)=?([^&;]*)/g;function parseUri(url,strictMode){var str=decodeURI(url),res=parser[strictMode||false?"strict":"loose"].exec(str),uri={attr:{},param:{},seg:{}},i=14;while(i--){uri.attr[key[i]]=res[i]||"";}uri.param['query']={};uri.param['fragment']={};uri.attr['query'].replace(querystring_parser,function($0,$1,$2){if($1){uri.param['query'][$1]=$2;}});uri.attr['fragment'].replace(fragment_parser,function($0,$1,$2){if($1){uri.param['fragment'][$1]=$2;}});uri.seg['path']=uri.attr.path.replace(/^\/+|\/+$/g,'').split('/');uri.seg['fragment']=uri.attr.fragment.replace(/^\/+|\/+$/g,'').split('/');uri.attr['base']=uri.attr.host?uri.attr.protocol+"://"+uri.attr.host+(uri.attr.port?":"+uri.attr.port:''):'';return uri;};function getAttrName(elm){var tn=elm.tagName;if(tn!==undefined)return tag2attr[tn.toLowerCase()];return tn;}$.fn.url=function(strictMode){var url='';if(this.length){url=$(this).attr(getAttrName(this[0]))||'';}return $.url(url,strictMode);};$.url=function(url,strictMode){if(arguments.length===1&&url===true){strictMode=true;url=undefined;}strictMode=strictMode||false;url=url||window.location.toString();return{data:parseUri(url,strictMode),attr:function(attr){attr=aliases[attr]||attr;return attr!==undefined?this.data.attr[attr]:this.data.attr;},param:function(param){return param!==undefined?this.data.param.query[param]:this.data.param.query;},fparam:function(param){return param!==undefined?this.data.param.fragment[param]:this.data.param.fragment;},segment:function(seg){if(seg===undefined){return this.data.seg.path;}else{seg=seg<0?this.data.seg.path.length+seg:seg-1;return this.data.seg.path[seg];}},fsegment:function(seg){if(seg===undefined){return this.data.seg.fragment;}else{seg=seg<0?this.data.seg.fragment.length+seg:seg-1;return this.data.seg.fragment[seg];}}};};})(jQuery); 9 | 10 | //jquery form 11 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';(7($){"4j 4k";4 O={};O.2t=$("<1j R=\'2u\'/>").39(0).3a!==1c;O.3b=1d.3c!==1c;$.11.1k=7(z){3(!5.X){Y(\'1k: 4l Z 4m - 4n 4o 1S\');8 5}4 A,1p,16,$9=5;3(1g z==\'7\'){z={17:z}}A=5.18(\'3d\');1p=5.18(\'1p\');16=(1g 1p===\'2v\')?$.4p(1p):\'\';16=16||1d.2w.2x||\'\';3(16){16=(16.4q(/^([^#]+)/)||[])[1]}z=$.2y(1h,{16:16,17:$.1T.17,R:A||\'3e\',22:/^4r/i.1U(1d.2w.2x||\'\')?\'3f:14\':\'4s:4t\'},z);4 B={};5.1e(\'9-2z-3g\',[5,z,B]);3(B.3h){Y(\'1k: Z 3i 23 9-2z-3g 1e\');8 5}3(z.2A&&z.2A(5,z)===14){Y(\'1k: Z 1l 23 2A 2B\');8 5}4 C=z.3j;3(C===1c){C=$.1T.3j}4 D=[];4 E,a=5.2C(z.4u,D);3(z.1a){z.W=z.1a;E=$.1H(z.1a,C)}3(z.2D&&z.2D(a,5,z)===14){Y(\'1k: Z 1l 23 2D 2B\');8 5}5.1e(\'9-Z-3k\',[a,5,z,B]);3(B.3h){Y(\'1k: Z 3i 23 9-Z-3k 1e\');8 5}4 q=$.1H(a,C);3(E){q=(q?(q+\'&\'+E):E)}3(z.R.4v()==\'3e\'){z.16+=(z.16.24(\'?\')>=0?\'&\':\'?\')+q;z.1a=12}P{z.1a=q}4 F=[];3(z.2E){F.V(7(){$9.2E()})}3(z.2F){F.V(7(){$9.2F(z.4w)})}3(!z.1V&&z.1z){4 G=z.17||7(){};F.V(7(a){4 b=z.4x?\'4y\':\'4z\';$(z.1z)[b](a).1A(G,3l)})}P 3(z.17){F.V(z.17)}z.17=7(a,b,c){4 d=z.1i||5;1b(4 i=0,1m=F.X;i<1m;i++){F[i].4A(d,[a,b,c||$9,$9])}};4 H=$(\'1j[R=2u]:4B[S!=""]\',5);4 I=H.X>0;4 J=\'2G/9-1a\';4 K=($9.18(\'3m\')==J||$9.18(\'3n\')==J);4 L=O.2t&&O.3b;Y("4C :"+L);4 M=(I||K)&&!L;4 N;3(z.2H!==14&&(z.2H||M)){3(z.3o){$.39(z.3o,7(){N=2I(a)})}P{N=2I(a)}}P 3((I||K)&&L){N=3p(a)}P{N=$.3q(z)}$9.4D(\'3r\').1a(\'3r\',N);1b(4 k=0;k\');$U.4Z({3A:\'51\',3E:\'-3F\',3G:\'-3F\'})}U=$U[0];6={1l:0,1n:12,1K:12,1f:0,1t:\'n/a\',52:7(){},2L:7(){},53:7(){},1L:7(a){4 e=(a===\'1u\'?\'1u\':\'1l\');Y(\'54 28... \'+e);5.1l=1;3(U.2d.1M.3H){1N{U.2d.1M.3H(\'55\')}1W(56){}}$U.18(\'3D\',s.22);6.19=e;3(s.19)s.19.1q(s.1i,6,e,a);3(g)$.1C.1e("3I",[6,s,e]);3(s.2e)s.2e.1q(s.1i,6,e)}};g=s.3J;3(g&&0===$.2M++){$.1C.1e("57")}3(g){$.1C.1e("58",[6,s])}3(s.29&&s.29.1q(s.1i,6,s)===14){3(s.3J){$.2M--}o.1J();8 o}3(6.1l){o.1J();8 o}1B=l.1v;3(1B){n=1B.Q;3(n&&!1B.1s){s.W=s.W||{};s.W[n]=1B.S;3(1B.R=="1O"){s.W[n+\'.x\']=l.1D;s.W[n+\'.y\']=l.1E}}}4 p=1;4 q=2;7 2N(a){4 b=a.2d?a.2d.1M:a.3K?a.3K:a.1M;8 b}4 r=$(\'3L[Q=3M-59]\').18(\'2f\');4 u=$(\'3L[Q=3M-1H]\').18(\'2f\');3(u&&r){s.W=s.W||{};s.W[u]=r}7 2O(){4 t=$9.18(\'1z\'),a=$9.18(\'1p\');l.1X(\'1z\',1r);3(!A){l.1X(\'3d\',\'3x\')}3(a!=s.16){l.1X(\'1p\',s.16)}3(!s.5a&&(!A||/5b/i.1U(A))){$9.18({3n:\'2G/9-1a\',3m:\'2G/9-1a\'})}3(s.1u){1I=1F(7(){2a=1h;1w(p)},s.1u)}7 2P(){1N{4 a=2N(U).5c;Y(\'5d = \'+a);3(a&&a.1Y()==\'5e\')1F(2P,50)}1W(e){Y(\'5f 1L: \',e,\' (\',e.Q,\')\');1w(q);3(1I)3N(1I);1I=1c}}4 b=[];1N{3(s.W){1b(4 n 3w s.W){3(s.W.27(n)){3($.5g(s.W[n])&&s.W[n].27(\'Q\')&&s.W[n].27(\'S\')){b.V($(\'<1j R="2Q" Q="\'+s.W[n].Q+\'">\').18(\'S\',s.W[n].S).2R(l)[0])}P{b.V($(\'<1j R="2Q" Q="\'+n+\'">\').18(\'S\',s.W[n]).2R(l)[0])}}}}3(!s.2c){$U.2R(\'1P\');3(U.3O)U.3O(\'3P\',1w);P U.5h(\'3Q\',1w,14)}1F(2P,15);l.Z()}5i{l.1X(\'1p\',a);3(t){l.1X(\'1z\',t)}P{$9.3C(\'1z\')}$(b).3R()}}3(s.5j){2O()}P{1F(2O,10)}4 v,13,3S=50,2S;7 1w(e){3(6.1l||2S){8}1N{13=2N(U)}1W(3T){Y(\'5k 5l 5m 1M: \',3T);e=q}3(e===p&&6){6.1L(\'1u\');o.1J(6,\'1u\');8}P 3(e==q&&6){6.1L(\'3U 1L\');o.1J(6,\'19\',\'3U 1L\');8}3(!13||13.2w.2x==s.22){3(!2a)8}3(U.3V)U.3V(\'3P\',1w);P U.5n(\'3Q\',1w,14);4 c=\'17\',1x;1N{3(2a){5o\'1u\';}4 d=s.1V==\'1o\'||13.2T||$.5p(13);Y(\'5q=\'+d);3(!d&&1d.2g&&(13.1P===12||!13.1P.3W)){3(--3S){Y(\'5r 5s 2B, 2U 2b 5t\');1F(1w,5u);8}}4 f=13.1P?13.1P:13.2h;6.1n=f?f.3W:12;6.1K=13.2T?13.2T:13;3(d)s.1V=\'1o\';6.2L=7(a){4 b={\'2f-R\':s.1V};8 b[a]};3(f){6.1f=3X(f.2i(\'1f\'))||6.1f;6.1t=f.2i(\'1t\')||6.1t}4 h=(s.1V||\'\').1Y();4 i=/(2V|3Y|2j)/.1U(h);3(i||s.2k){4 j=13.2l(\'2k\')[0];3(j){6.1n=j.S;6.1f=3X(j.2i(\'1f\'))||6.1f;6.1t=j.2i(\'1t\')||6.1t}P 3(i){4 k=13.2l(\'2z\')[0];4 b=13.2l(\'1P\')[0];3(k){6.1n=k.2m?k.2m:k.3Z}P 3(b){6.1n=b.2m?b.2m:b.3Z}}}P 3(h==\'1o\'&&!6.1K&&6.1n){6.1K=w(6.1n)}1N{v=y(6,h,s)}1W(e){c=\'2n\';6.19=1x=(e||c)}}1W(e){Y(\'19 5v: \',e);c=\'19\';6.19=1x=(e||c)}3(6.1l){Y(\'28 1l\');c=12}3(6.1f){c=(6.1f>=5w&&6.1f<5x||6.1f===5y)?\'17\':\'19\'}3(c===\'17\'){3(s.17)s.17.1q(s.1i,v,\'17\',6);o.5z(6.1n,\'17\',6);3(g)$.1C.1e("5A",[6,s])}P 3(c){3(1x===1c)1x=6.1t;3(s.19)s.19.1q(s.1i,6,c,1x);o.1J(6,\'19\',1x);3(g)$.1C.1e("3I",[6,s,1x])}3(g)$.1C.1e("5B",[6,s]);3(g&&!--$.2M){$.1C.1e("5C")}3(s.2e)s.2e.1q(s.1i,6,c);2S=1h;3(s.1u)3N(1I);1F(7(){3(!s.2c)$U.3R();6.1K=12},2J)}4 w=$.5D||7(s,a){3(1d.40){a=26 40(\'5E.5F\');a.5G=\'14\';a.5H(s)}P{a=(26 5I()).5J(s,\'2j/1o\')}8(a&&a.2h&&a.2h.41!=\'2n\')?a:12};4 x=$.5K||7(s){8 1d[\'5L\'](\'(\'+s+\')\')};4 y=7(a,b,s){4 c=a.2L(\'2f-R\')||\'\',1o=b===\'1o\'||!b&&c.24(\'1o\')>=0,v=1o?a.1K:a.1n;3(1o&&v.2h.41===\'2n\'){3($.19)$.19(\'2n\')}3(s&&s.42){v=s.42(v,b)}3(1g v===\'2v\'){3(b===\'2V\'||!b&&c.24(\'2V\')>=0){v=x(v)}P 3(b==="3Y"||!b&&c.24("3f")>=0){$.5M(v)}}8 v};8 o}};$.11.2W=7(a){a=a||{};a.2o=a.2o&&$.5N($.11.2X);3(!a.2o&&5.X===0){4 o={s:5.1Q,c:5.1i};3(!$.43&&o.s){Y(\'2U 2b 44, 5O 2W\');$(7(){$(o.s,o.c).2W(a)});8 5}Y(\'5P; 5Q 2K 5R 5S 1Q\'+($.43?\'\':\' (2U 2b 44)\'));8 5}3(a.2o){$(1M).45(\'Z.9-1y\',5.1Q,2p).45(\'2q.9-1y\',5.1Q,2r).2X(\'Z.9-1y\',5.1Q,a,2p).2X(\'2q.9-1y\',5.1Q,a,2r);8 5}8 5.46().47(\'Z.9-1y\',a,2p).47(\'2q.9-1y\',a,2r)};7 2p(e){4 a=e.1a;3(!e.5T()){e.5U();$(5).1k(a)}}7 2r(e){4 a=e.1z;4 b=$(a);3(!(b.48("[R=Z],[R=1O]"))){4 t=b.5V(\'[R=Z]\');3(t.X===0){8}a=t[0]}4 c=5;c.1v=a;3(a.R==\'1O\'){3(e.49!==1c){c.1D=e.49;c.1E=e.5W}P 3(1g $.11.4a==\'7\'){4 d=b.4a();c.1D=e.4b-d.3G;c.1E=e.4c-d.3E}P{c.1D=e.4b-a.5X;c.1E=e.4c-a.5Y}}1F(7(){c.1v=c.1D=c.1E=12},2J)}$.11.46=7(){8 5.5Z(\'Z.9-1y 2q.9-1y\')};$.11.2C=7(b,c){4 a=[];3(5.X===0){8 a}4 d=5[0];4 e=b?d.2l(\'*\'):d.2K;3(!e){8 a}4 i,j,n,v,T,1m,2Y;1b(i=0,1m=e.X;i<1m;i++){T=e[i];n=T.Q;3(!n){2Z}3(b&&d.1v&&T.R=="1O"){3(!T.1s&&d.1v==T){a.V({Q:n,S:$(T).30(),R:T.R});a.V({Q:n+\'.x\',S:d.1D},{Q:n+\'.y\',S:d.1E})}2Z}v=$.1Z(T,1h);3(v&&v.2s==20){3(c)c.V(T);1b(j=0,2Y=v.X;j<2Y;j++){a.V({Q:n,S:v[j]})}}P 3(O.2t&&T.R==\'2u\'&&!T.1s){3(c)c.V(T);4 f=T.3a;3(f.X){1b(j=0;j35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(7($){$.J($.2F,{1c:7(c){8(!6.G){8(c&&c.29&&2G.1x){1x.4x("4y 3l, 4z\'t 1c, 4A 4B.")}l}p d=$.11(6[0],"v");8(d){l d}6.12("3m","3m");d=2H $.v(c,6[0]);$.11(6[0],"v",d);8(d.q.3n){6.2a(":2b","3o",7(a){8(d.q.2I){d.1P=a.2c}8($(a.2c).4C("4D")){d.2d=w}8($(a.2c).12("4E")!==1l){d.2d=w}});6.2b(7(b){8(d.q.29){b.4F()}7 2J(){p a;8(d.q.2I){8(d.1P){a=$("<2e F=\'3p\'/>").12("u",d.1P.u).W($(d.1P).W()).4G(d.X)}d.q.2I.16(d,d.X,b);8(d.1P){a.3q()}l K}l w}8(d.2d){d.2d=K;l 2J()}8(d.P()){8(d.1g){d.1m=w;l K}l 2J()}H{d.2f();l K}})}l d},L:7(){8($(6[0]).2K("P")){l 6.1c().P()}H{p a=w;p b=$(6[0].P).1c();6.U(7(){a=a&&b.I(6)});l a}},4H:7(c){p d={},$I=6;$.U(c.1y(/\\s/),7(a,b){d[b]=$I.12(b);$I.4I(b)});l d},13:7(c,d){p e=6[0];8(c){p f=$.11(e.P,"v").q;p g=f.13;p h=$.v.2L(e);2M(c){1z"1n":$.J(h,$.v.1Q(d));Q h.M;g[e.u]=h;8(d.M){f.M[e.u]=$.J(f.M[e.u],d.M)}2N;1z"3q":8(!d){Q g[e.u];l h}p i={};$.U(d.1y(/\\s/),7(a,b){i[b]=h[b];Q h[b]});l i}}p j=$.v.3r($.J({},$.v.3s(e),$.v.3t(e),$.v.3u(e),$.v.2L(e)),e);8(j.14){p k=j.14;Q j.14;j=$.J({14:k},j)}l j}});$.J($.4J[":"],{4K:7(a){l!$.1A(""+$(a).W())},4L:7(a){l!!$.1A(""+$(a).W())},4M:7(a){l!$(a).4N("2O")}});$.v=7(a,b){6.q=$.J(w,{},$.v.2P,a);6.X=b;6.3v()};$.v.15=7(b,c){8(17.G===1){l 7(){p a=$.3w(17);a.4O(b);l $.v.15.2g(6,a)}}8(17.G>2&&c.2h!==3x){c=$.3w(17).4P(1)}8(c.2h!==3x){c=[c]}$.U(c,7(i,n){b=b.1B(2H 4Q("\\\\{"+i+"\\\\}","g"),7(){l n})});l b};$.J($.v,{2P:{M:{},2i:{},13:{},1h:"3y",1R:"L",2Q:"4R",2f:w,3z:$([]),2R:$([]),3n:w,2S:":3p",3A:K,4S:7(a,b){6.3B=a;8(6.q.4T&&!6.4U){8(6.q.1S){6.q.1S.16(6,a,6.q.1h,6.q.1R)}6.2j(6.1T(a)).2T()}},3C:7(a,b){8(!6.1C(a)&&(a.u R 6.1i||!6.N(a))){6.I(a)}},4V:7(a,b){8(b.4W===9&&6.2k(a)===""){l}H 8(a.u R 6.1i||a===6.2U){6.I(a)}},4X:7(a,b){8(a.u R 6.1i){6.I(a)}H 8(a.3D.u R 6.1i){6.I(a.3D)}},2V:7(a,b,c){8(a.F==="1U"){6.1D(a.u).1o(b).1E(c)}H{$(a).1o(b).1E(c)}},1S:7(a,b,c){8(a.F==="1U"){6.1D(a.u).1E(b).1o(c)}H{$(a).1E(b).1o(c)}}},4Y:7(a){$.J($.v.2P,a)},M:{14:"4Z 3E 2K 14.",1p:"O 50 6 3E.",1F:"O S a L 1F 51.",1q:"O S a L 52.",1r:"O S a L 1r.",2l:"O S a L 1r (53).",1j:"O S a L 1j.",1V:"O S 54 1V.",2m:"O S a L 55 56 1j.",2n:"O S 3F 57 1d 58.",1e:$.v.15("O S 3G 59 2W {0} 2X."),1G:$.v.15("O S 5a 5b {0} 2X."),2o:$.v.15("O S a 1d 3H {0} 3I {1} 2X 5c."),1s:$.v.15("O S a 1d 3H {0} 3I {1}."),1H:$.v.15("O S a 1d 5d 2W 3J 3K 3L {0}."),1I:$.v.15("O S a 1d 5e 2W 3J 3K 3L {0}.")},3M:K,5f:{3v:7(){6.2p=$(6.q.2R);6.3N=6.2p.G&&6.2p||$(6.X);6.2q=$(6.q.3z).1n(6.q.2R);6.1i={};6.5g={};6.1g=0;6.1J={};6.18={};6.1W();p e=(6.2i={});$.U(6.q.2i,7(c,d){8(19 d==="1k"){d=d.1y(/\\s/)}$.U(d,7(a,b){e[b]=c})});p f=6.q.13;$.U(f,7(a,b){f[a]=$.v.1Q(b)});7 2Y(a){p b=$.11(6[0].P,"v"),2Z="5h"+a.F.1B(/^1c/,"");8(b.q[2Z]){b.q[2Z].16(b,6[0],a)}}$(6.X).2a(":30, [F=\'5i\'], [F=\'5j\'], 1X, 3O, "+"[F=\'1j\'], [F=\'5k\'] ,[F=\'5l\'], [F=\'1q\'], "+"[F=\'1F\'], [F=\'3P\'], [F=\'1r\'], [F=\'5m\'], "+"[F=\'5n\'], [F=\'5o\'], [F=\'3P-5p\'], "+"[F=\'1s\'], [F=\'5q\'] ","3Q 5r 5s",2Y).2a("[F=\'1U\'], [F=\'31\'], 1X, 3R","3o",2Y);8(6.q.3S){$(6.X).32("18-P.1c",6.q.3S)}},P:7(){6.3T();$.J(6.1i,6.1K);6.18=$.J({},6.1K);8(!6.L()){$(6.X).3U("18-P",[6])}6.1t();l 6.L()},3T:7(){6.33();T(p i=0,1a=(6.2r=6.1a());1a[i];i++){6.2s(1a[i])}l 6.L()},I:7(a){a=6.34(6.35(a));6.2U=a;6.36(a);6.2r=$(a);p b=6.2s(a)!==K;8(b){Q 6.18[a.u]}H{6.18[a.u]=w}8(!6.3V()){6.1b=6.1b.1n(6.2q)}6.1t();l b},1t:7(b){8(b){$.J(6.1K,b);6.V=[];T(p c R b){6.V.2t({1u:b[c],I:6.1D(c)[0]})}6.1v=$.3W(6.1v,7(a){l!(a.u R b)})}8(6.q.1t){6.q.1t.16(6,6.1K,6.V)}H{6.3X()}},37:7(){8($.2F.37){$(6.X).37()}6.1i={};6.2U=38;6.33();6.39();6.1a().1E(6.q.1h).5t("1Y")},3V:7(){l 6.2u(6.18)},2u:7(a){p b=0;T(p i R a){b++}l b},39:7(){6.2j(6.1b).2T()},L:7(){l 6.3Y()===0},3Y:7(){l 6.V.G},2f:7(){8(6.q.2f){3Z{$(6.40()||6.V.G&&6.V[0].I||[]).2v(":5u").5v().5w("3Q")}41(e){}}},40:7(){p a=6.3B;l a&&$.3W(6.V,7(n){l n.I.u===a.u}).G===1&&a},1a:7(){p a=6,3a={};l $(6.X).42("2e, 1X, 3O").1L(":2b, :1W, :5x, [5y]").1L(6.q.2S).2v(7(){8(!6.u&&a.q.29&&2G.1x){1x.3y("%o 5z 3G u 5A",6)}8(6.u R 3a||!a.2u($(6).13())){l K}3a[6.u]=w;l w})},35:7(a){l $(a)[0]},3b:7(){p a=6.q.1h.1B(" ",".");l $(6.q.2Q+"."+a,6.3N)},1W:7(){6.1v=[];6.V=[];6.1K={};6.1w=$([]);6.1b=$([]);6.2r=$([])},33:7(){6.1W();6.1b=6.3b().1n(6.2q)},36:7(a){6.1W();6.1b=6.1T(a)},2k:7(a){p b=$(a).12("F"),W=$(a).W();8(b==="1U"||b==="31"){l $("2e[u=\'"+$(a).12("u")+"\']:2O").W()}8(19 W==="1k"){l W.1B(/\\r/g,"")}l W},2s:7(a){a=6.34(6.35(a));p b=$(a).13();p c=K;p d=6.2k(a);p f;T(p g R b){p h={2w:g,2x:b[g]};3Z{f=$.v.1M[g].16(6,d,a,h.2x);8(f==="1Z-20"){c=w;5B}c=K;8(f==="1J"){6.1b=6.1b.1L(6.1T(a));l}8(!f){6.43(a,h);l K}}41(e){8(6.q.29&&2G.1x){1x.5C("5D 5E 5F 5G I "+a.44+", 2s 3F \'"+h.2w+"\' 2w.",e)}5H e;}}8(c){l}8(6.2u(b)){6.1v.2t(a)}l w},45:7(a,b){l $(a).11("46-"+b.21())||(a.5I&&$(a).12("11-46-"+b.21()))},47:7(a,b){p m=6.q.M[a];l m&&(m.2h===48?m:m[b])},49:7(){T(p i=0;i<17.G;i++){8(17[i]!==1l){l 17[i]}}l 1l},2y:7(a,b){l 6.49(6.47(a.u,b),6.45(a,b),!6.q.3A&&a.5J||1l,$.v.M[b],"<4a>5K: 5L 1u 5M T "+a.u+"")},43:7(a,b){p c=6.2y(a,b.2w),3c=/\\$?\\{(\\d+)\\}/g;8(19 c==="7"){c=c.16(6,b.2x,a)}H 8(3c.Y(c)){c=$.v.15(c.1B(3c,"{$1}"),b.2x)}6.V.2t({1u:c,I:a});6.1K[a.u]=c;6.1i[a.u]=c},2j:7(a){8(6.q.2z){a=a.1n(a.4b(6.q.2z))}l a},3X:7(){p i,1a;T(i=0;6.V[i];i++){p a=6.V[i];8(6.q.2V){6.q.2V.16(6,a.I,6.q.1h,6.q.1R)}6.3d(a.I,a.1u)}8(6.V.G){6.1w=6.1w.1n(6.2q)}8(6.q.1N){T(i=0;6.1v[i];i++){6.3d(6.1v[i])}}8(6.q.1S){T(i=0,1a=6.4c();1a[i];i++){6.q.1S.16(6,1a[i],6.q.1h,6.q.1R)}}6.1b=6.1b.1L(6.1w);6.39();6.2j(6.1w).4d()},4c:7(){l 6.2r.1L(6.4e())},4e:7(){l $(6.V).5N(7(){l 6.I})},3d:7(a,b){p c=6.1T(a);8(c.G){c.1E(6.q.1R).1o(6.q.1h);c.4f(b)}H{c=$("<"+6.q.2Q+">").12("T",6.3e(a)).1o(6.q.1h).4f(b||"");8(6.q.2z){c=c.2T().4d().5O("<"+6.q.2z+"/>").4b()}8(!6.2p.5P(c).G){8(6.q.4g){6.q.4g(c,$(a))}H{c.5Q(a)}}}8(!b&&6.q.1N){c.30("");8(19 6.q.1N==="1k"){c.1o(6.q.1N)}H{6.q.1N(c,a)}}6.1w=6.1w.1n(c)},1T:7(a){p b=6.3e(a);l 6.3b().2v(7(){l $(6).12("T")===b})},3e:7(a){l 6.2i[a.u]||(6.1C(a)?a.u:a.44||a.u)},34:7(a){8(6.1C(a)){a=6.1D(a.u).1L(6.q.2S)[0]}l a},1C:7(a){l(/1U|31/i).Y(a.F)},1D:7(a){l $(6.X).42("[u=\'"+a+"\']")},22:7(a,b){2M(b.4h.21()){1z"1X":l $("3R:3l",b).G;1z"2e":8(6.1C(b)){l 6.1D(b.u).2v(":2O").G}}l a.G},4i:7(a,b){l 6.3f[19 a]?6.3f[19 a](a,b):w},3f:{"5R":7(a,b){l a},"1k":7(a,b){l!!$(a,b.P).G},"7":7(a,b){l a(b)}},N:7(a){p b=6.2k(a);l!$.v.1M.14.16(6,b,a)&&"1Z-20"},4j:7(a){8(!6.1J[a.u]){6.1g++;6.1J[a.u]=w}},4k:7(a,b){6.1g--;8(6.1g<0){6.1g=0}Q 6.1J[a.u];8(b&&6.1g===0&&6.1m&&6.P()){$(6.X).2b();6.1m=K}H 8(!b&&6.1g===0&&6.1m){$(6.X).3U("18-P",[6]);6.1m=K}},1Y:7(a){l $.11(a,"1Y")||$.11(a,"1Y",{3g:38,L:w,1u:6.2y(a,"1p")})}},23:{14:{14:w},1F:{1F:w},1q:{1q:w},1r:{1r:w},2l:{2l:w},1j:{1j:w},1V:{1V:w},2m:{2m:w}},4l:7(a,b){8(a.2h===48){6.23[a]=b}H{$.J(6.23,a)}},3s:7(a){p b={};p c=$(a).12("5S");8(c){$.U(c.1y(" "),7(){8(6 R $.v.23){$.J(b,$.v.23[6])}})}l b},3t:7(a){p b={};p c=$(a);p d=c[0].4m("F");T(p e R $.v.1M){p f;8(e==="14"){f=c.5T(0).4m(e);8(f===""){f=w}f=!!f}H{f=c.12(e)}8(/1I|1H/.Y(e)&&(d===38||/1j|1s|30/.Y(d))){f=1O(f)}8(f){b[e]=f}H 8(d===e&&d!==\'1s\'){b[e]=w}}8(b.1e&&/-1|5U|5V/.Y(b.1e)){Q b.1e}l b},3u:7(a){p b,1d,13={},$I=$(a);T(b R $.v.1M){1d=$I.11("5W-"+b.21());8(1d!==1l){13[b]=1d}}l 13},2L:7(a){p b={};p c=$.11(a.P,"v");8(c.q.13){b=$.v.1Q(c.q.13[a.u])||{}}l b},3r:7(d,e){$.U(d,7(a,b){8(b===K){Q d[a];l}8(b.3h||b.2A){p c=w;2M(19 b.2A){1z"1k":c=!!$(b.2A,e.P).G;2N;1z"7":c=b.2A.16(e,e);2N}8(c){d[a]=b.3h!==1l?b.3h:w}H{Q d[a]}}});$.U(d,7(a,b){d[a]=$.4n(b)?b(e):b});$.U([\'1G\',\'1e\'],7(){8(d[6]){d[6]=1O(d[6])}});$.U([\'2o\',\'1s\'],7(){p a;8(d[6]){8($.2B(d[6])){d[6]=[1O(d[6][0]),1O(d[6][1])]}H 8(19 d[6]==="1k"){a=d[6].1y(/[\\s,]+/);d[6]=[1O(a[0]),1O(a[1])]}}});8($.v.3M){8(d.1I&&d.1H){d.1s=[d.1I,d.1H];Q d.1I;Q d.1H}8(d.1G&&d.1e){d.2o=[d.1G,d.1e];Q d.1G;Q d.1e}}l d},1Q:7(a){8(19 a==="1k"){p b={};$.U(a.1y(/\\s/),7(){b[6]=w});a=b}l a},5X:7(a,b,c){$.v.1M[a]=b;$.v.M[a]=c!==1l?c:$.v.M[a];8(b.G<3){$.v.4l(a,$.v.1Q(a))}},1M:{14:7(a,b,c){8(!6.4i(c,b)){l"1Z-20"}8(b.4h.21()==="1X"){p d=$(b).W();l d&&d.G>0}8(6.1C(b)){l 6.22(a,b)>0}l $.1A(a).G>0},1F:7(a,b){l 6.N(b)||/^((([a-z]|\\d|[!#\\$%&\'\\*\\+\\-\\/=\\?\\^Z`{\\|}~]|[\\x-\\y\\A-\\B\\C-\\E])+(\\.([a-z]|\\d|[!#\\$%&\'\\*\\+\\-\\/=\\?\\^Z`{\\|}~]|[\\x-\\y\\A-\\B\\C-\\E])+)*)|((\\4o)((((\\2C|\\24)*(\\3i\\4p))?(\\2C|\\24)+)?(([\\4q-\\5Y\\4r\\4s\\5Z-\\60\\4t]|\\61|[\\62-\\63]|[\\64-\\65]|[\\x-\\y\\A-\\B\\C-\\E])|(\\\\([\\4q-\\24\\4r\\4s\\3i-\\4t]|[\\x-\\y\\A-\\B\\C-\\E]))))*(((\\2C|\\24)*(\\3i\\4p))?(\\2C|\\24)+)?(\\4o)))@((([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])|(([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])*([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])))\\.)+(([a-z]|[\\x-\\y\\A-\\B\\C-\\E])|(([a-z]|[\\x-\\y\\A-\\B\\C-\\E])([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])*([a-z]|[\\x-\\y\\A-\\B\\C-\\E])))$/i.Y(a)},1q:7(a,b){l 6.N(b)||/^(66?|s?67):\\/\\/(((([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|((([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])|(([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])*([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])))\\.)+(([a-z]|[\\x-\\y\\A-\\B\\C-\\E])|(([a-z]|[\\x-\\y\\A-\\B\\C-\\E])([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])*([a-z]|[\\x-\\y\\A-\\B\\C-\\E])))\\.?)(:\\d*)?)(\\/((([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:|@)+(\\/(([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:|@)|[\\68-\\69]|\\/|\\?)*)?(#((([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$/i.Y(a)},1r:7(a,b){l 6.N(b)||!/6a|6b/.Y(2H 6c(a).6d())},2l:7(a,b){l 6.N(b)||/^\\d{4}[\\/\\-]\\d{1,2}[\\/\\-]\\d{1,2}$/.Y(a)},1j:7(a,b){l 6.N(b)||/^-?(?:\\d+|\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$/.Y(a)},1V:7(a,b){l 6.N(b)||/^\\d+$/.Y(a)},2m:7(a,b){8(6.N(b)){l"1Z-20"}8(/[^0-9 \\-]+/.Y(a)){l K}p c=0,27=0,2D=K;a=a.1B(/\\D/g,"");T(p n=a.G-1;n>=0;n--){p d=a.6e(n);27=6f(d,10);8(2D){8((27*=2)>9){27-=9}}c+=27;2D=!2D}l(c%10)===0},1G:7(a,b,c){p d=$.2B(a)?a.G:6.22($.1A(a),b);l 6.N(b)||d>=c},1e:7(a,b,c){p d=$.2B(a)?a.G:6.22($.1A(a),b);l 6.N(b)||d<=c},2o:7(a,b,c){p d=$.2B(a)?a.G:6.22($.1A(a),b);l 6.N(b)||(d>=c[0]&&d<=c[1])},1I:7(a,b,c){l 6.N(b)||a>=c},1H:7(a,b,c){l 6.N(b)||a<=c},1s:7(a,b,c){l 6.N(b)||(a>=c[0]&&a<=c[1])},2n:7(a,b,c){p d=$(c);8(6.q.3C){d.6g(".1c-2n").32("6h.1c-2n",7(){$(b).L()})}l a===d.W()},1p:7(f,g,h){8(6.N(g)){l"1Z-20"}p i=6.1Y(g);8(!6.q.M[g.u]){6.q.M[g.u]={}}i.4u=6.q.M[g.u].1p;6.q.M[g.u].1p=i.1u;h=19 h==="1k"&&{1q:h}||h;8(i.3g===f){l i.L}i.3g=f;p j=6;6.4j(g);p k={};k[g.u]=f;$.3j($.J(w,{1q:h,2E:"28",1f:"1c"+g.u,6i:"6j",11:k,1N:7(a){j.q.M[g.u].1p=i.4u;p b=a===w||a==="w";8(b){p c=j.1m;j.36(g);j.1m=c;j.1v.2t(g);Q j.18[g.u];j.1t()}H{p d={};p e=a||j.2y(g,"1p");d[g.u]=i.1u=$.4n(e)?e(f):e;j.18[g.u]=w;j.1t(d)}i.L=b;j.4k(g,b)}},h));l"1J"}}});$.15=$.v.15}(3k));(7($){p d={};8($.4v){$.4v(7(a,Z,b){p c=a.1f;8(a.2E==="28"){8(d[c]){d[c].28()}d[c]=b}})}H{p e=$.3j;$.3j=7(a){p b=("2E"R a?a:$.4w).2E,1f=("1f"R a?a:$.4w).1f;8(b==="28"){8(d[1f]){d[1f].28()}d[1f]=e.2g(6,17);l d[1f]}l e.2g(6,17)}}}(3k));(7($){$.J($.2F,{2a:7(c,d,e){l 6.32(d,7(a){p b=$(a.2c);8(b.2K(c)){l e.2g(b,17)}})}})}(3k));',62,392,'||||||this|function|if|||||||||||||return||||var|settings||||name|validator|true|u00A0|uD7FF||uF900|uFDCF|uFDF0||uFFEF|type|length|else|element|extend|false|valid|messages|optional|Please|form|delete|in|enter|for|each|errorList|val|currentForm|test|_||data|attr|rules|required|format|call|arguments|invalid|typeof|elements|toHide|validate|value|maxlength|port|pendingRequest|errorClass|submitted|number|string|undefined|formSubmitted|add|addClass|remote|url|date|range|showErrors|message|successList|toShow|console|split|case|trim|replace|checkable|findByName|removeClass|email|minlength|max|min|pending|errorMap|not|methods|success|Number|submitButton|normalizeRule|validClass|unhighlight|errorsFor|radio|digits|reset|select|previousValue|dependency|mismatch|toLowerCase|getLength|classRuleSettings|x09||da|nDigit|abort|debug|validateDelegate|submit|target|cancelSubmit|input|focusInvalid|apply|constructor|groups|addWrapper|elementValue|dateISO|creditcard|equalTo|rangelength|labelContainer|containers|currentElements|check|push|objectLength|filter|method|parameters|defaultMessage|wrapper|depends|isArray|x20|bEven|mode|fn|window|new|submitHandler|handle|is|staticRules|switch|break|checked|defaults|errorElement|errorLabelContainer|ignore|hide|lastElement|highlight|than|characters|delegate|eventType|text|checkbox|bind|prepareForm|validationTargetFor|clean|prepareElement|resetForm|null|hideErrors|rulesCache|errors|theregex|showLabel|idOrName|dependTypes|old|param|x0d|ajax|jQuery|selected|novalidate|onsubmit|click|hidden|remove|normalizeRules|classRules|attributeRules|dataRules|init|makeArray|Array|error|errorContainer|ignoreTitle|lastActive|onfocusout|parentNode|field|the|no|between|and|or|equal|to|autoCreateRanges|errorContext|textarea|datetime|focusin|option|invalidHandler|checkForm|triggerHandler|numberOfInvalids|grep|defaultShowErrors|size|try|findLastActive|catch|find|formatAndAdd|id|customDataMessage|msg|customMessage|String|findDefined|strong|parent|validElements|show|invalidElements|html|errorPlacement|nodeName|depend|startRequest|stopRequest|addClassRules|getAttribute|isFunction|x22|x0a|x01|x0b|x0c|x7f|originalMessage|ajaxPrefilter|ajaxSettings|warn|Nothing|can|returning|nothing|hasClass|cancel|formnovalidate|preventDefault|appendTo|removeAttrs|removeAttr|expr|blank|filled|unchecked|prop|unshift|slice|RegExp|label|onfocusin|focusCleanup|blockFocusCleanup|onkeyup|which|onclick|setDefaults|This|fix|address|URL|ISO|only|credit|card|same|again|more|at|least|long|less|greater|prototype|valueCache|on|password|mysql|search|tel|month|week|time|local|color|focusout|keyup|removeData|visible|focus|trigger|image|disabled|has|assigned|continue|log|Exception|occurred|when|checking|throw|attributes|title|Warning|No|defined|map|wrap|append|insertAfter|boolean|class|get|2147483647|524288|rule|addMethod|x08|x0e|x1f|x21|x23|x5b|x5d|x7e|https|ftp|uE000|uF8FF|Invalid|NaN|Date|toString|charAt|parseInt|unbind|blur|dataType|json'.split('|'),0,{})); 15 | -------------------------------------------------------------------------------- /MyEtherWallet:05-钱包项目整体架构设计/static/js/wallet.js: -------------------------------------------------------------------------------- 1 | 2 | $(document).ready(function () { 3 | alert("welcome!") 4 | }) -------------------------------------------------------------------------------- /MyEtherWallet:05-钱包项目整体架构设计/utils/myUtils.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | getweb3: () => { 4 | let Web3 = require("web3") 5 | var web3 = new Web3(Web3.givenProvider || 'https://kovan.infura.io/v3/bc76cd31e8bf48f9a28b73770ffca805'); 6 | 7 | return web3 8 | }, 9 | 10 | success: (data) => { 11 | responseData = { 12 | code:0, 13 | status:"success", 14 | data:data 15 | } 16 | return responseData 17 | }, 18 | 19 | fail: (msg) => { 20 | responseData = { 21 | code:1, 22 | status:"fail", 23 | msg:msg 24 | } 25 | return responseData 26 | } 27 | } -------------------------------------------------------------------------------- /MyEtherWallet:05-钱包项目整体架构设计/views/newaccount.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 创建钱包 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 |
18 | 创建账号 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /MyEtherWallet:06-Coding:生成账户的地址、私钥、keystore、助记词/controllers/newAccount.js: -------------------------------------------------------------------------------- 1 | let web3 = require("../utils/myUtils").getweb3() 2 | let fs = require("fs") 3 | let path = require("path") 4 | 5 | module.exports = { 6 | //获取创建账号的页面 7 | newAccountHtml: async (ctx) => { 8 | await ctx.render("newaccount.html") 9 | }, 10 | 11 | //创建账户的表单提交被触发的方法 12 | newAccount: async (ctx) => { 13 | console.log("password:", ctx.request.body.password) 14 | 15 | //1.创建钱包账号 16 | let account = web3.eth.accounts.create(ctx.request.body.password) 17 | console.log(account) 18 | 19 | //2.根据账号和密码生成keystore文件 20 | let keystore = account.encrypt(ctx.request.body.password) 21 | console.log(keystore) 22 | 23 | //3.将keysotr保存到文件 24 | let keystoreString = JSON.stringify(keystore) 25 | let time = new Date() 26 | let fileName = 'UTC--'+time.toISOString()+'--'+account.address.slice(2) 27 | console.log(fileName) 28 | let filePath = path.join(__dirname, "../static/keystore", fileName) 29 | fs.writeFileSync(filePath, keystoreString) 30 | 31 | //4.将账号信息返回给客户端 32 | await ctx.render("downloadkeystore.html", { 33 | "downloadurl":"/keystore/"+fileName, 34 | "privatekey":account.privateKey 35 | }) 36 | } 37 | } -------------------------------------------------------------------------------- /MyEtherWallet:06-Coding:生成账户的地址、私钥、keystore、助记词/index.js: -------------------------------------------------------------------------------- 1 | 2 | let koa = require("koa") 3 | //通过koa创建一个应用程序 4 | let app = new koa() 5 | //导入./router/route这个包,赋值给的router就是 ./router/router导出的数据 6 | let router = require("./router/router") 7 | let static = require("koa-static") 8 | let path = require("path") 9 | let views = require("koa-views") 10 | let koaBody = require("koa-body") 11 | 12 | app.use(async (ctx, next) => { 13 | console.log(`${ctx.method} ${ctx.url} ..........`) 14 | await next() 15 | }) 16 | 17 | //针对于文件上传的时候,可以解析多个字段 18 | app.use(koaBody({multipart:true})) 19 | //注册静态文件的库到中间件 20 | app.use(static(path.join(__dirname, "static"))) 21 | //注册模板引擎的库到中间件 22 | app.use(views(path.join(__dirname, "views"), {extension:"ejs", map:{html:"ejs"}})) 23 | app.use(router.routes()) 24 | 25 | console.log("正在监听3000端口") 26 | app.listen(3000) 27 | -------------------------------------------------------------------------------- /MyEtherWallet:06-Coding:生成账户的地址、私钥、keystore、助记词/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "4-wallet", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "bignumber": "^1.1.0", 13 | "ejs": "^2.6.1", 14 | "ethereumjs-tx": "^1.3.7", 15 | "koa": "^2.5.2", 16 | "koa-body": "^4.0.4", 17 | "koa-router": "^7.4.0", 18 | "koa-static": "^5.0.0", 19 | "koa-views": "^6.1.4", 20 | "web3": "^1.0.0-beta.35", 21 | "bip39": "^2.5.0", 22 | "ethereumjs-util": "^5.2.0", 23 | "ethereumjs-wallet": "^0.6.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MyEtherWallet:06-Coding:生成账户的地址、私钥、keystore、助记词/router/router.js: -------------------------------------------------------------------------------- 1 | 2 | let router = require("koa-router")() 3 | let newAccountController = require("../controllers/newAccount") 4 | 5 | router.get("/", async (ctx) => { 6 | //重定向 7 | ctx.response.redirect("/account/new.html") 8 | }) 9 | 10 | //获取创建钱包账户的页面 11 | router.get("/account/new.html", newAccountController.newAccountHtml) 12 | //提交创建钱包账户的表单 13 | router.post("/account/new", newAccountController.newAccount) 14 | 15 | module.exports = router 16 | -------------------------------------------------------------------------------- /MyEtherWallet:06-Coding:生成账户的地址、私钥、keystore、助记词/static/css/wallet.css: -------------------------------------------------------------------------------- 1 | 2 | #main{ 3 | /*background-color: #8bc34a;*/ 4 | margin: 100px 50px 50px 50px; 5 | 6 | } 7 | .error{ 8 | color: red; 9 | } 10 | a{ 11 | color: black; 12 | text-decoration: none; 13 | } 14 | a:hover{ 15 | color: #666; 16 | } 17 | body{ 18 | margin: 0px; 19 | } 20 | .global-color{ 21 | color: #0abc9c; 22 | } 23 | a[class=button]{ 24 | background-color: beige; 25 | padding: 2px 10px; 26 | border: 1px solid gray; 27 | } 28 | 29 | /*导航-------------------------------------------------------------------------------------------------------*/ 30 | #nav{ 31 | display: flex; 32 | justify-content: space-between; 33 | background-color: #0abc9c; 34 | position: fixed; 35 | top: 0px; 36 | left: 0px; 37 | right: 0px; 38 | } 39 | #nav li{ 40 | display: inline-block; 41 | margin: 10px 2px; 42 | } 43 | #nav ul{ 44 | padding: 0px; 45 | } 46 | #nav a{ 47 | padding: 10px; 48 | font-size: 24px; 49 | } 50 | #nav-left{ 51 | margin-left: 20px; 52 | } 53 | #nav-right{ 54 | margin-right: 20px; 55 | } 56 | -------------------------------------------------------------------------------- /MyEtherWallet:06-Coding:生成账户的地址、私钥、keystore、助记词/static/html/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /MyEtherWallet:06-Coding:生成账户的地址、私钥、keystore、助记词/static/js/wallet.js: -------------------------------------------------------------------------------- 1 | 2 | function saveKeystoreNext() { 3 | $("#save-keystore").hide() 4 | $("#save-privatekey").show() 5 | } 6 | 7 | $(document).ready(function () { 8 | 9 | }) 10 | -------------------------------------------------------------------------------- /MyEtherWallet:06-Coding:生成账户的地址、私钥、keystore、助记词/static/keystore/UTC--2018-09-25T06:24:28.689Z--42f971FC3443B43313441E68f7548b3BD0713dB9: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"a3b41a93-4812-4651-a5e7-f869f1c1c81a","address":"42f971fc3443b43313441e68f7548b3bd0713db9","crypto":{"ciphertext":"1b878fd78042a1aac1e1404c886eb823c29052599432c8a19840b8aa23c976ff","cipherparams":{"iv":"a261b97eca4c487d0f149f554e8d0767"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"04603dddcd4dc7f740f4f0d5ffc38277d0dc7f5180c235a1f26ab314bf4df413","n":8192,"r":8,"p":1},"mac":"7511195ae4a6f154b692e02739199b717ed9ed6f973d8de206fea6ea66ac829c"}} -------------------------------------------------------------------------------- /MyEtherWallet:06-Coding:生成账户的地址、私钥、keystore、助记词/utils/myUtils.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | getweb3: () => { 4 | let Web3 = require("web3") 5 | var web3 = new Web3(Web3.givenProvider || 'https://kovan.infura.io/v3/bc76cd31e8bf48f9a28b73770ffca805'); 6 | 7 | return web3 8 | }, 9 | 10 | success: (data) => { 11 | responseData = { 12 | code:0, 13 | status:"success", 14 | data:data 15 | } 16 | return responseData 17 | }, 18 | 19 | fail: (msg) => { 20 | responseData = { 21 | code:1, 22 | status:"fail", 23 | msg:msg 24 | } 25 | return responseData 26 | } 27 | } -------------------------------------------------------------------------------- /MyEtherWallet:06-Coding:生成账户的地址、私钥、keystore、助记词/views/downloadkeystore.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 保存你的keystore 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 |
18 |
19 |

保存你的keystore

20 | 下载keystore文件 21 |

22 | 23 |
24 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /MyEtherWallet:06-Coding:生成账户的地址、私钥、keystore、助记词/views/newaccount.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 创建钱包 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 |
16 |

创建一个新的账号

17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/controllers/account.js: -------------------------------------------------------------------------------- 1 | let { success, fail } = require("../utils/myUtils") 2 | let web3 = require("../utils/myUtils").getweb3() 3 | 4 | //获取以太币余额 5 | async function getAccountBalance(address) { 6 | let balance = await web3.eth.getBalance(address) 7 | return web3.utils.fromWei(balance, "ether") 8 | } 9 | 10 | //配置返回给前端的数据,包含以太币的数据,还会有Token的数据 11 | async function setResponseData(account) { 12 | //获取账户余额 13 | let balance = await getAccountBalance(account.address) 14 | console.log(balance) 15 | 16 | let resData = success({ 17 | balance: balance, 18 | address: account.address, 19 | privatekey: account.privateKey 20 | }) 21 | 22 | //返回相应数据给前端 23 | return resData 24 | } 25 | 26 | module.exports = { 27 | unlockAccountWithPrivate: async (ctx) => { 28 | //1.获取私钥 29 | let privatekey = ctx.request.body.privatekey 30 | console.log(privatekey) 31 | //2.通过私钥解锁账户 32 | let account = web3.eth.accounts.privateKeyToAccount(privatekey) 33 | console.log(account) 34 | //3.将账户信息返回给前端 35 | ctx.body = await setResponseData(account) 36 | }, 37 | } -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/controllers/newAccount.js: -------------------------------------------------------------------------------- 1 | let web3 = require("../utils/myUtils").getweb3() 2 | let fs = require("fs") 3 | let path = require("path") 4 | 5 | module.exports = { 6 | //获取创建账号的页面 7 | newAccountHtml: async (ctx) => { 8 | await ctx.render("newaccount.html") 9 | }, 10 | 11 | //创建账户的表单提交被触发的方法 12 | newAccount: async (ctx) => { 13 | console.log("password:", ctx.request.body.password) 14 | 15 | //1.创建钱包账号 16 | let account = web3.eth.accounts.create(ctx.request.body.password) 17 | console.log(account) 18 | 19 | //2.根据账号和密码生成keystore文件 20 | let keystore = account.encrypt(ctx.request.body.password) 21 | console.log(keystore) 22 | 23 | //3.将keysotr保存到文件 24 | let keystoreString = JSON.stringify(keystore) 25 | let time = new Date() 26 | let fileName = 'UTC--'+time.toISOString()+'--'+account.address.slice(2) 27 | console.log(fileName) 28 | let filePath = path.join(__dirname, "../static/keystore", fileName) 29 | fs.writeFileSync(filePath, keystoreString) 30 | 31 | //4.将账号信息返回给客户端 32 | await ctx.render("downloadkeystore.html", { 33 | "downloadurl":"/keystore/"+fileName, 34 | "privatekey":account.privateKey 35 | }) 36 | } 37 | } -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/controllers/transaction.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transactionHtml: async (ctx) => { 3 | await ctx.render("transaction.html") 4 | }, 5 | } -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/index.js: -------------------------------------------------------------------------------- 1 | 2 | let koa = require("koa") 3 | //通过koa创建一个应用程序 4 | let app = new koa() 5 | //导入./router/route这个包,赋值给的router就是 ./router/router导出的数据 6 | let router = require("./router/router") 7 | let static = require("koa-static") 8 | let path = require("path") 9 | let views = require("koa-views") 10 | let koaBody = require("koa-body") 11 | 12 | app.use(async (ctx, next) => { 13 | console.log(`${ctx.method} ${ctx.url} ..........`) 14 | await next() 15 | }) 16 | 17 | //针对于文件上传的时候,可以解析多个字段 18 | app.use(koaBody({multipart:true})) 19 | //注册静态文件的库到中间件 20 | app.use(static(path.join(__dirname, "static"))) 21 | //注册模板引擎的库到中间件 22 | app.use(views(path.join(__dirname, "views"), {extension:"ejs", map:{html:"ejs"}})) 23 | app.use(router.routes()) 24 | 25 | console.log("正在监听3000端口") 26 | app.listen(3000) 27 | -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "4-wallet", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "bignumber": "^1.1.0", 13 | "ejs": "^2.6.1", 14 | "ethereumjs-tx": "^1.3.7", 15 | "koa": "^2.5.2", 16 | "koa-body": "^4.0.4", 17 | "koa-router": "^7.4.0", 18 | "koa-static": "^5.0.0", 19 | "koa-views": "^6.1.4", 20 | "web3": "^1.0.0-beta.35", 21 | "bip39": "^2.5.0", 22 | "ethereumjs-util": "^5.2.0", 23 | "ethereumjs-wallet": "^0.6.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/router/router.js: -------------------------------------------------------------------------------- 1 | 2 | let router = require("koa-router")() 3 | let newAccountController = require("../controllers/newAccount") 4 | let trasactionConytoller = require("../controllers/transaction") 5 | let accountController = require("../controllers/account") 6 | 7 | 8 | router.get("/", async (ctx) => { 9 | //重定向 10 | ctx.response.redirect("/account/new.html") 11 | }) 12 | 13 | //获取创建钱包账户的页面 14 | router.get("/account/new.html", newAccountController.newAccountHtml) 15 | //提交创建钱包账户的表单 16 | router.post("/account/new", newAccountController.newAccount) 17 | 18 | //获取转账的页面 19 | router.get("/transaction.html", trasactionConytoller.transactionHtml) 20 | 21 | //通过私钥解锁账户 22 | router.post("/unlock/private", accountController.unlockAccountWithPrivate) 23 | 24 | module.exports = router 25 | -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/static/css/wallet.css: -------------------------------------------------------------------------------- 1 | 2 | #main{ 3 | /*background-color: #8bc34a;*/ 4 | margin: 100px 50px 50px 50px; 5 | 6 | } 7 | .error{ 8 | color: red; 9 | } 10 | a{ 11 | color: black; 12 | text-decoration: none; 13 | } 14 | a:hover{ 15 | color: #666; 16 | } 17 | body{ 18 | margin: 0px; 19 | } 20 | .global-color{ 21 | color: #0abc9c; 22 | } 23 | a[class=button]{ 24 | background-color: beige; 25 | padding: 2px 10px; 26 | border: 1px solid gray; 27 | } 28 | 29 | /*导航-------------------------------------------------------------------------------------------------------*/ 30 | #nav{ 31 | display: flex; 32 | justify-content: space-between; 33 | background-color: #0abc9c; 34 | position: fixed; 35 | top: 0px; 36 | left: 0px; 37 | right: 0px; 38 | } 39 | #nav li{ 40 | display: inline-block; 41 | margin: 10px 2px; 42 | } 43 | #nav ul{ 44 | padding: 0px; 45 | } 46 | #nav a{ 47 | padding: 10px; 48 | font-size: 24px; 49 | } 50 | #nav-left{ 51 | margin-left: 20px; 52 | } 53 | #nav-right{ 54 | margin-right: 20px; 55 | } 56 | -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/static/html/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/static/js/lib/jquery.url.js: -------------------------------------------------------------------------------- 1 | //cookie 2 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(3(a){4(v 9===\'3\'&&9.G){9([\'H\'],a)}I{a(J)}}(3($){2 m=/\\+/g;3 7(s){5 s}3 w(s){5 K(s.o(m,\' \'))}3 p(s){4(s.L(\'"\')===0){s=s.M(1,-1).o(/\\\\"/g,\'"\').o(/\\\\\\\\/g,\'\\\\\')}N{5 n.x?y.O(s):s}P(Q){}}2 n=$.8=3(a,b,c){4(b!==q){c=$.z({},n.A,c);4(v c.6===\'R\'){2 d=c.6,t=c.6=S T();t.U(t.V()+d)}b=n.x?y.W(b):X(b);5(B.8=[n.7?a:C(a),\'=\',n.7?b:C(b),c.6?\'; 6=\'+c.6.Y():\'\',c.r?\'; r=\'+c.r:\'\',c.u?\'; u=\'+c.u:\'\',c.D?\'; D\':\'\'].E(\'\'))}2 e=n.7?7:w;2 f=B.8.F(\'; \');2 g=a?q:{};Z(2 i=0,l=f.10;i=b&&y<=b+w.height()&&x+t.width()>=a&&x<=a+w.width()){if(!t.appeared)t.trigger('appear',s.data);}else{t.appeared=false;}};var m=function(){t.appeared=true;if(s.one){w.unbind('scroll',c);var i=$.inArray(c,$.fn.appear.checks);if(i>=0)$.fn.appear.checks.splice(i,1);}f.apply(this,arguments);};if(s.one)t.one('appear',s.data,m);else t.bind('appear',s.data,m);w.scroll(c);$.fn.appear.checks.push(c);(c)();});};$.extend($.fn.appear,{checks:[],timeout:null,checkAll:function(){var l=$.fn.appear.checks.length;if(l>0)while(l--)($.fn.appear.checks[l])();},run:function(){if($.fn.appear.timeout)clearTimeout($.fn.appear.timeout);$.fn.appear.timeout=setTimeout($.fn.appear.checkAll,20);}});$.each(['append','prepend','after','before','attr','removeAttr','addClass','removeClass','toggleClass','remove','css','show','hide'],function(i,n){var u=$.fn[n];if(u){$.fn[n]=function(){var r=u.apply(this,arguments);$.fn.appear.run();return r;}}});})(jQuery); 6 | 7 | //url 8 | ;(function($,undefined){var tag2attr={a:'href',img:'src',form:'action',base:'href',script:'src',iframe:'src',link:'href'},key=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","fragment"],aliases={"anchor":"fragment"},parser={strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/},querystring_parser=/(?:^|&|;)([^&=;]*)=?([^&;]*)/g,fragment_parser=/(?:^|&|;)([^&=;]*)=?([^&;]*)/g;function parseUri(url,strictMode){var str=decodeURI(url),res=parser[strictMode||false?"strict":"loose"].exec(str),uri={attr:{},param:{},seg:{}},i=14;while(i--){uri.attr[key[i]]=res[i]||"";}uri.param['query']={};uri.param['fragment']={};uri.attr['query'].replace(querystring_parser,function($0,$1,$2){if($1){uri.param['query'][$1]=$2;}});uri.attr['fragment'].replace(fragment_parser,function($0,$1,$2){if($1){uri.param['fragment'][$1]=$2;}});uri.seg['path']=uri.attr.path.replace(/^\/+|\/+$/g,'').split('/');uri.seg['fragment']=uri.attr.fragment.replace(/^\/+|\/+$/g,'').split('/');uri.attr['base']=uri.attr.host?uri.attr.protocol+"://"+uri.attr.host+(uri.attr.port?":"+uri.attr.port:''):'';return uri;};function getAttrName(elm){var tn=elm.tagName;if(tn!==undefined)return tag2attr[tn.toLowerCase()];return tn;}$.fn.url=function(strictMode){var url='';if(this.length){url=$(this).attr(getAttrName(this[0]))||'';}return $.url(url,strictMode);};$.url=function(url,strictMode){if(arguments.length===1&&url===true){strictMode=true;url=undefined;}strictMode=strictMode||false;url=url||window.location.toString();return{data:parseUri(url,strictMode),attr:function(attr){attr=aliases[attr]||attr;return attr!==undefined?this.data.attr[attr]:this.data.attr;},param:function(param){return param!==undefined?this.data.param.query[param]:this.data.param.query;},fparam:function(param){return param!==undefined?this.data.param.fragment[param]:this.data.param.fragment;},segment:function(seg){if(seg===undefined){return this.data.seg.path;}else{seg=seg<0?this.data.seg.path.length+seg:seg-1;return this.data.seg.path[seg];}},fsegment:function(seg){if(seg===undefined){return this.data.seg.fragment;}else{seg=seg<0?this.data.seg.fragment.length+seg:seg-1;return this.data.seg.fragment[seg];}}};};})(jQuery); 9 | 10 | //jquery form 11 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';(7($){"4j 4k";4 O={};O.2t=$("<1j R=\'2u\'/>").39(0).3a!==1c;O.3b=1d.3c!==1c;$.11.1k=7(z){3(!5.X){Y(\'1k: 4l Z 4m - 4n 4o 1S\');8 5}4 A,1p,16,$9=5;3(1g z==\'7\'){z={17:z}}A=5.18(\'3d\');1p=5.18(\'1p\');16=(1g 1p===\'2v\')?$.4p(1p):\'\';16=16||1d.2w.2x||\'\';3(16){16=(16.4q(/^([^#]+)/)||[])[1]}z=$.2y(1h,{16:16,17:$.1T.17,R:A||\'3e\',22:/^4r/i.1U(1d.2w.2x||\'\')?\'3f:14\':\'4s:4t\'},z);4 B={};5.1e(\'9-2z-3g\',[5,z,B]);3(B.3h){Y(\'1k: Z 3i 23 9-2z-3g 1e\');8 5}3(z.2A&&z.2A(5,z)===14){Y(\'1k: Z 1l 23 2A 2B\');8 5}4 C=z.3j;3(C===1c){C=$.1T.3j}4 D=[];4 E,a=5.2C(z.4u,D);3(z.1a){z.W=z.1a;E=$.1H(z.1a,C)}3(z.2D&&z.2D(a,5,z)===14){Y(\'1k: Z 1l 23 2D 2B\');8 5}5.1e(\'9-Z-3k\',[a,5,z,B]);3(B.3h){Y(\'1k: Z 3i 23 9-Z-3k 1e\');8 5}4 q=$.1H(a,C);3(E){q=(q?(q+\'&\'+E):E)}3(z.R.4v()==\'3e\'){z.16+=(z.16.24(\'?\')>=0?\'&\':\'?\')+q;z.1a=12}P{z.1a=q}4 F=[];3(z.2E){F.V(7(){$9.2E()})}3(z.2F){F.V(7(){$9.2F(z.4w)})}3(!z.1V&&z.1z){4 G=z.17||7(){};F.V(7(a){4 b=z.4x?\'4y\':\'4z\';$(z.1z)[b](a).1A(G,3l)})}P 3(z.17){F.V(z.17)}z.17=7(a,b,c){4 d=z.1i||5;1b(4 i=0,1m=F.X;i<1m;i++){F[i].4A(d,[a,b,c||$9,$9])}};4 H=$(\'1j[R=2u]:4B[S!=""]\',5);4 I=H.X>0;4 J=\'2G/9-1a\';4 K=($9.18(\'3m\')==J||$9.18(\'3n\')==J);4 L=O.2t&&O.3b;Y("4C :"+L);4 M=(I||K)&&!L;4 N;3(z.2H!==14&&(z.2H||M)){3(z.3o){$.39(z.3o,7(){N=2I(a)})}P{N=2I(a)}}P 3((I||K)&&L){N=3p(a)}P{N=$.3q(z)}$9.4D(\'3r\').1a(\'3r\',N);1b(4 k=0;k\');$U.4Z({3A:\'51\',3E:\'-3F\',3G:\'-3F\'})}U=$U[0];6={1l:0,1n:12,1K:12,1f:0,1t:\'n/a\',52:7(){},2L:7(){},53:7(){},1L:7(a){4 e=(a===\'1u\'?\'1u\':\'1l\');Y(\'54 28... \'+e);5.1l=1;3(U.2d.1M.3H){1N{U.2d.1M.3H(\'55\')}1W(56){}}$U.18(\'3D\',s.22);6.19=e;3(s.19)s.19.1q(s.1i,6,e,a);3(g)$.1C.1e("3I",[6,s,e]);3(s.2e)s.2e.1q(s.1i,6,e)}};g=s.3J;3(g&&0===$.2M++){$.1C.1e("57")}3(g){$.1C.1e("58",[6,s])}3(s.29&&s.29.1q(s.1i,6,s)===14){3(s.3J){$.2M--}o.1J();8 o}3(6.1l){o.1J();8 o}1B=l.1v;3(1B){n=1B.Q;3(n&&!1B.1s){s.W=s.W||{};s.W[n]=1B.S;3(1B.R=="1O"){s.W[n+\'.x\']=l.1D;s.W[n+\'.y\']=l.1E}}}4 p=1;4 q=2;7 2N(a){4 b=a.2d?a.2d.1M:a.3K?a.3K:a.1M;8 b}4 r=$(\'3L[Q=3M-59]\').18(\'2f\');4 u=$(\'3L[Q=3M-1H]\').18(\'2f\');3(u&&r){s.W=s.W||{};s.W[u]=r}7 2O(){4 t=$9.18(\'1z\'),a=$9.18(\'1p\');l.1X(\'1z\',1r);3(!A){l.1X(\'3d\',\'3x\')}3(a!=s.16){l.1X(\'1p\',s.16)}3(!s.5a&&(!A||/5b/i.1U(A))){$9.18({3n:\'2G/9-1a\',3m:\'2G/9-1a\'})}3(s.1u){1I=1F(7(){2a=1h;1w(p)},s.1u)}7 2P(){1N{4 a=2N(U).5c;Y(\'5d = \'+a);3(a&&a.1Y()==\'5e\')1F(2P,50)}1W(e){Y(\'5f 1L: \',e,\' (\',e.Q,\')\');1w(q);3(1I)3N(1I);1I=1c}}4 b=[];1N{3(s.W){1b(4 n 3w s.W){3(s.W.27(n)){3($.5g(s.W[n])&&s.W[n].27(\'Q\')&&s.W[n].27(\'S\')){b.V($(\'<1j R="2Q" Q="\'+s.W[n].Q+\'">\').18(\'S\',s.W[n].S).2R(l)[0])}P{b.V($(\'<1j R="2Q" Q="\'+n+\'">\').18(\'S\',s.W[n]).2R(l)[0])}}}}3(!s.2c){$U.2R(\'1P\');3(U.3O)U.3O(\'3P\',1w);P U.5h(\'3Q\',1w,14)}1F(2P,15);l.Z()}5i{l.1X(\'1p\',a);3(t){l.1X(\'1z\',t)}P{$9.3C(\'1z\')}$(b).3R()}}3(s.5j){2O()}P{1F(2O,10)}4 v,13,3S=50,2S;7 1w(e){3(6.1l||2S){8}1N{13=2N(U)}1W(3T){Y(\'5k 5l 5m 1M: \',3T);e=q}3(e===p&&6){6.1L(\'1u\');o.1J(6,\'1u\');8}P 3(e==q&&6){6.1L(\'3U 1L\');o.1J(6,\'19\',\'3U 1L\');8}3(!13||13.2w.2x==s.22){3(!2a)8}3(U.3V)U.3V(\'3P\',1w);P U.5n(\'3Q\',1w,14);4 c=\'17\',1x;1N{3(2a){5o\'1u\';}4 d=s.1V==\'1o\'||13.2T||$.5p(13);Y(\'5q=\'+d);3(!d&&1d.2g&&(13.1P===12||!13.1P.3W)){3(--3S){Y(\'5r 5s 2B, 2U 2b 5t\');1F(1w,5u);8}}4 f=13.1P?13.1P:13.2h;6.1n=f?f.3W:12;6.1K=13.2T?13.2T:13;3(d)s.1V=\'1o\';6.2L=7(a){4 b={\'2f-R\':s.1V};8 b[a]};3(f){6.1f=3X(f.2i(\'1f\'))||6.1f;6.1t=f.2i(\'1t\')||6.1t}4 h=(s.1V||\'\').1Y();4 i=/(2V|3Y|2j)/.1U(h);3(i||s.2k){4 j=13.2l(\'2k\')[0];3(j){6.1n=j.S;6.1f=3X(j.2i(\'1f\'))||6.1f;6.1t=j.2i(\'1t\')||6.1t}P 3(i){4 k=13.2l(\'2z\')[0];4 b=13.2l(\'1P\')[0];3(k){6.1n=k.2m?k.2m:k.3Z}P 3(b){6.1n=b.2m?b.2m:b.3Z}}}P 3(h==\'1o\'&&!6.1K&&6.1n){6.1K=w(6.1n)}1N{v=y(6,h,s)}1W(e){c=\'2n\';6.19=1x=(e||c)}}1W(e){Y(\'19 5v: \',e);c=\'19\';6.19=1x=(e||c)}3(6.1l){Y(\'28 1l\');c=12}3(6.1f){c=(6.1f>=5w&&6.1f<5x||6.1f===5y)?\'17\':\'19\'}3(c===\'17\'){3(s.17)s.17.1q(s.1i,v,\'17\',6);o.5z(6.1n,\'17\',6);3(g)$.1C.1e("5A",[6,s])}P 3(c){3(1x===1c)1x=6.1t;3(s.19)s.19.1q(s.1i,6,c,1x);o.1J(6,\'19\',1x);3(g)$.1C.1e("3I",[6,s,1x])}3(g)$.1C.1e("5B",[6,s]);3(g&&!--$.2M){$.1C.1e("5C")}3(s.2e)s.2e.1q(s.1i,6,c);2S=1h;3(s.1u)3N(1I);1F(7(){3(!s.2c)$U.3R();6.1K=12},2J)}4 w=$.5D||7(s,a){3(1d.40){a=26 40(\'5E.5F\');a.5G=\'14\';a.5H(s)}P{a=(26 5I()).5J(s,\'2j/1o\')}8(a&&a.2h&&a.2h.41!=\'2n\')?a:12};4 x=$.5K||7(s){8 1d[\'5L\'](\'(\'+s+\')\')};4 y=7(a,b,s){4 c=a.2L(\'2f-R\')||\'\',1o=b===\'1o\'||!b&&c.24(\'1o\')>=0,v=1o?a.1K:a.1n;3(1o&&v.2h.41===\'2n\'){3($.19)$.19(\'2n\')}3(s&&s.42){v=s.42(v,b)}3(1g v===\'2v\'){3(b===\'2V\'||!b&&c.24(\'2V\')>=0){v=x(v)}P 3(b==="3Y"||!b&&c.24("3f")>=0){$.5M(v)}}8 v};8 o}};$.11.2W=7(a){a=a||{};a.2o=a.2o&&$.5N($.11.2X);3(!a.2o&&5.X===0){4 o={s:5.1Q,c:5.1i};3(!$.43&&o.s){Y(\'2U 2b 44, 5O 2W\');$(7(){$(o.s,o.c).2W(a)});8 5}Y(\'5P; 5Q 2K 5R 5S 1Q\'+($.43?\'\':\' (2U 2b 44)\'));8 5}3(a.2o){$(1M).45(\'Z.9-1y\',5.1Q,2p).45(\'2q.9-1y\',5.1Q,2r).2X(\'Z.9-1y\',5.1Q,a,2p).2X(\'2q.9-1y\',5.1Q,a,2r);8 5}8 5.46().47(\'Z.9-1y\',a,2p).47(\'2q.9-1y\',a,2r)};7 2p(e){4 a=e.1a;3(!e.5T()){e.5U();$(5).1k(a)}}7 2r(e){4 a=e.1z;4 b=$(a);3(!(b.48("[R=Z],[R=1O]"))){4 t=b.5V(\'[R=Z]\');3(t.X===0){8}a=t[0]}4 c=5;c.1v=a;3(a.R==\'1O\'){3(e.49!==1c){c.1D=e.49;c.1E=e.5W}P 3(1g $.11.4a==\'7\'){4 d=b.4a();c.1D=e.4b-d.3G;c.1E=e.4c-d.3E}P{c.1D=e.4b-a.5X;c.1E=e.4c-a.5Y}}1F(7(){c.1v=c.1D=c.1E=12},2J)}$.11.46=7(){8 5.5Z(\'Z.9-1y 2q.9-1y\')};$.11.2C=7(b,c){4 a=[];3(5.X===0){8 a}4 d=5[0];4 e=b?d.2l(\'*\'):d.2K;3(!e){8 a}4 i,j,n,v,T,1m,2Y;1b(i=0,1m=e.X;i<1m;i++){T=e[i];n=T.Q;3(!n){2Z}3(b&&d.1v&&T.R=="1O"){3(!T.1s&&d.1v==T){a.V({Q:n,S:$(T).30(),R:T.R});a.V({Q:n+\'.x\',S:d.1D},{Q:n+\'.y\',S:d.1E})}2Z}v=$.1Z(T,1h);3(v&&v.2s==20){3(c)c.V(T);1b(j=0,2Y=v.X;j<2Y;j++){a.V({Q:n,S:v[j]})}}P 3(O.2t&&T.R==\'2u\'&&!T.1s){3(c)c.V(T);4 f=T.3a;3(f.X){1b(j=0;j35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(7($){$.J($.2F,{1c:7(c){8(!6.G){8(c&&c.29&&2G.1x){1x.4x("4y 3l, 4z\'t 1c, 4A 4B.")}l}p d=$.11(6[0],"v");8(d){l d}6.12("3m","3m");d=2H $.v(c,6[0]);$.11(6[0],"v",d);8(d.q.3n){6.2a(":2b","3o",7(a){8(d.q.2I){d.1P=a.2c}8($(a.2c).4C("4D")){d.2d=w}8($(a.2c).12("4E")!==1l){d.2d=w}});6.2b(7(b){8(d.q.29){b.4F()}7 2J(){p a;8(d.q.2I){8(d.1P){a=$("<2e F=\'3p\'/>").12("u",d.1P.u).W($(d.1P).W()).4G(d.X)}d.q.2I.16(d,d.X,b);8(d.1P){a.3q()}l K}l w}8(d.2d){d.2d=K;l 2J()}8(d.P()){8(d.1g){d.1m=w;l K}l 2J()}H{d.2f();l K}})}l d},L:7(){8($(6[0]).2K("P")){l 6.1c().P()}H{p a=w;p b=$(6[0].P).1c();6.U(7(){a=a&&b.I(6)});l a}},4H:7(c){p d={},$I=6;$.U(c.1y(/\\s/),7(a,b){d[b]=$I.12(b);$I.4I(b)});l d},13:7(c,d){p e=6[0];8(c){p f=$.11(e.P,"v").q;p g=f.13;p h=$.v.2L(e);2M(c){1z"1n":$.J(h,$.v.1Q(d));Q h.M;g[e.u]=h;8(d.M){f.M[e.u]=$.J(f.M[e.u],d.M)}2N;1z"3q":8(!d){Q g[e.u];l h}p i={};$.U(d.1y(/\\s/),7(a,b){i[b]=h[b];Q h[b]});l i}}p j=$.v.3r($.J({},$.v.3s(e),$.v.3t(e),$.v.3u(e),$.v.2L(e)),e);8(j.14){p k=j.14;Q j.14;j=$.J({14:k},j)}l j}});$.J($.4J[":"],{4K:7(a){l!$.1A(""+$(a).W())},4L:7(a){l!!$.1A(""+$(a).W())},4M:7(a){l!$(a).4N("2O")}});$.v=7(a,b){6.q=$.J(w,{},$.v.2P,a);6.X=b;6.3v()};$.v.15=7(b,c){8(17.G===1){l 7(){p a=$.3w(17);a.4O(b);l $.v.15.2g(6,a)}}8(17.G>2&&c.2h!==3x){c=$.3w(17).4P(1)}8(c.2h!==3x){c=[c]}$.U(c,7(i,n){b=b.1B(2H 4Q("\\\\{"+i+"\\\\}","g"),7(){l n})});l b};$.J($.v,{2P:{M:{},2i:{},13:{},1h:"3y",1R:"L",2Q:"4R",2f:w,3z:$([]),2R:$([]),3n:w,2S:":3p",3A:K,4S:7(a,b){6.3B=a;8(6.q.4T&&!6.4U){8(6.q.1S){6.q.1S.16(6,a,6.q.1h,6.q.1R)}6.2j(6.1T(a)).2T()}},3C:7(a,b){8(!6.1C(a)&&(a.u R 6.1i||!6.N(a))){6.I(a)}},4V:7(a,b){8(b.4W===9&&6.2k(a)===""){l}H 8(a.u R 6.1i||a===6.2U){6.I(a)}},4X:7(a,b){8(a.u R 6.1i){6.I(a)}H 8(a.3D.u R 6.1i){6.I(a.3D)}},2V:7(a,b,c){8(a.F==="1U"){6.1D(a.u).1o(b).1E(c)}H{$(a).1o(b).1E(c)}},1S:7(a,b,c){8(a.F==="1U"){6.1D(a.u).1E(b).1o(c)}H{$(a).1E(b).1o(c)}}},4Y:7(a){$.J($.v.2P,a)},M:{14:"4Z 3E 2K 14.",1p:"O 50 6 3E.",1F:"O S a L 1F 51.",1q:"O S a L 52.",1r:"O S a L 1r.",2l:"O S a L 1r (53).",1j:"O S a L 1j.",1V:"O S 54 1V.",2m:"O S a L 55 56 1j.",2n:"O S 3F 57 1d 58.",1e:$.v.15("O S 3G 59 2W {0} 2X."),1G:$.v.15("O S 5a 5b {0} 2X."),2o:$.v.15("O S a 1d 3H {0} 3I {1} 2X 5c."),1s:$.v.15("O S a 1d 3H {0} 3I {1}."),1H:$.v.15("O S a 1d 5d 2W 3J 3K 3L {0}."),1I:$.v.15("O S a 1d 5e 2W 3J 3K 3L {0}.")},3M:K,5f:{3v:7(){6.2p=$(6.q.2R);6.3N=6.2p.G&&6.2p||$(6.X);6.2q=$(6.q.3z).1n(6.q.2R);6.1i={};6.5g={};6.1g=0;6.1J={};6.18={};6.1W();p e=(6.2i={});$.U(6.q.2i,7(c,d){8(19 d==="1k"){d=d.1y(/\\s/)}$.U(d,7(a,b){e[b]=c})});p f=6.q.13;$.U(f,7(a,b){f[a]=$.v.1Q(b)});7 2Y(a){p b=$.11(6[0].P,"v"),2Z="5h"+a.F.1B(/^1c/,"");8(b.q[2Z]){b.q[2Z].16(b,6[0],a)}}$(6.X).2a(":30, [F=\'5i\'], [F=\'5j\'], 1X, 3O, "+"[F=\'1j\'], [F=\'5k\'] ,[F=\'5l\'], [F=\'1q\'], "+"[F=\'1F\'], [F=\'3P\'], [F=\'1r\'], [F=\'5m\'], "+"[F=\'5n\'], [F=\'5o\'], [F=\'3P-5p\'], "+"[F=\'1s\'], [F=\'5q\'] ","3Q 5r 5s",2Y).2a("[F=\'1U\'], [F=\'31\'], 1X, 3R","3o",2Y);8(6.q.3S){$(6.X).32("18-P.1c",6.q.3S)}},P:7(){6.3T();$.J(6.1i,6.1K);6.18=$.J({},6.1K);8(!6.L()){$(6.X).3U("18-P",[6])}6.1t();l 6.L()},3T:7(){6.33();T(p i=0,1a=(6.2r=6.1a());1a[i];i++){6.2s(1a[i])}l 6.L()},I:7(a){a=6.34(6.35(a));6.2U=a;6.36(a);6.2r=$(a);p b=6.2s(a)!==K;8(b){Q 6.18[a.u]}H{6.18[a.u]=w}8(!6.3V()){6.1b=6.1b.1n(6.2q)}6.1t();l b},1t:7(b){8(b){$.J(6.1K,b);6.V=[];T(p c R b){6.V.2t({1u:b[c],I:6.1D(c)[0]})}6.1v=$.3W(6.1v,7(a){l!(a.u R b)})}8(6.q.1t){6.q.1t.16(6,6.1K,6.V)}H{6.3X()}},37:7(){8($.2F.37){$(6.X).37()}6.1i={};6.2U=38;6.33();6.39();6.1a().1E(6.q.1h).5t("1Y")},3V:7(){l 6.2u(6.18)},2u:7(a){p b=0;T(p i R a){b++}l b},39:7(){6.2j(6.1b).2T()},L:7(){l 6.3Y()===0},3Y:7(){l 6.V.G},2f:7(){8(6.q.2f){3Z{$(6.40()||6.V.G&&6.V[0].I||[]).2v(":5u").5v().5w("3Q")}41(e){}}},40:7(){p a=6.3B;l a&&$.3W(6.V,7(n){l n.I.u===a.u}).G===1&&a},1a:7(){p a=6,3a={};l $(6.X).42("2e, 1X, 3O").1L(":2b, :1W, :5x, [5y]").1L(6.q.2S).2v(7(){8(!6.u&&a.q.29&&2G.1x){1x.3y("%o 5z 3G u 5A",6)}8(6.u R 3a||!a.2u($(6).13())){l K}3a[6.u]=w;l w})},35:7(a){l $(a)[0]},3b:7(){p a=6.q.1h.1B(" ",".");l $(6.q.2Q+"."+a,6.3N)},1W:7(){6.1v=[];6.V=[];6.1K={};6.1w=$([]);6.1b=$([]);6.2r=$([])},33:7(){6.1W();6.1b=6.3b().1n(6.2q)},36:7(a){6.1W();6.1b=6.1T(a)},2k:7(a){p b=$(a).12("F"),W=$(a).W();8(b==="1U"||b==="31"){l $("2e[u=\'"+$(a).12("u")+"\']:2O").W()}8(19 W==="1k"){l W.1B(/\\r/g,"")}l W},2s:7(a){a=6.34(6.35(a));p b=$(a).13();p c=K;p d=6.2k(a);p f;T(p g R b){p h={2w:g,2x:b[g]};3Z{f=$.v.1M[g].16(6,d,a,h.2x);8(f==="1Z-20"){c=w;5B}c=K;8(f==="1J"){6.1b=6.1b.1L(6.1T(a));l}8(!f){6.43(a,h);l K}}41(e){8(6.q.29&&2G.1x){1x.5C("5D 5E 5F 5G I "+a.44+", 2s 3F \'"+h.2w+"\' 2w.",e)}5H e;}}8(c){l}8(6.2u(b)){6.1v.2t(a)}l w},45:7(a,b){l $(a).11("46-"+b.21())||(a.5I&&$(a).12("11-46-"+b.21()))},47:7(a,b){p m=6.q.M[a];l m&&(m.2h===48?m:m[b])},49:7(){T(p i=0;i<17.G;i++){8(17[i]!==1l){l 17[i]}}l 1l},2y:7(a,b){l 6.49(6.47(a.u,b),6.45(a,b),!6.q.3A&&a.5J||1l,$.v.M[b],"<4a>5K: 5L 1u 5M T "+a.u+"")},43:7(a,b){p c=6.2y(a,b.2w),3c=/\\$?\\{(\\d+)\\}/g;8(19 c==="7"){c=c.16(6,b.2x,a)}H 8(3c.Y(c)){c=$.v.15(c.1B(3c,"{$1}"),b.2x)}6.V.2t({1u:c,I:a});6.1K[a.u]=c;6.1i[a.u]=c},2j:7(a){8(6.q.2z){a=a.1n(a.4b(6.q.2z))}l a},3X:7(){p i,1a;T(i=0;6.V[i];i++){p a=6.V[i];8(6.q.2V){6.q.2V.16(6,a.I,6.q.1h,6.q.1R)}6.3d(a.I,a.1u)}8(6.V.G){6.1w=6.1w.1n(6.2q)}8(6.q.1N){T(i=0;6.1v[i];i++){6.3d(6.1v[i])}}8(6.q.1S){T(i=0,1a=6.4c();1a[i];i++){6.q.1S.16(6,1a[i],6.q.1h,6.q.1R)}}6.1b=6.1b.1L(6.1w);6.39();6.2j(6.1w).4d()},4c:7(){l 6.2r.1L(6.4e())},4e:7(){l $(6.V).5N(7(){l 6.I})},3d:7(a,b){p c=6.1T(a);8(c.G){c.1E(6.q.1R).1o(6.q.1h);c.4f(b)}H{c=$("<"+6.q.2Q+">").12("T",6.3e(a)).1o(6.q.1h).4f(b||"");8(6.q.2z){c=c.2T().4d().5O("<"+6.q.2z+"/>").4b()}8(!6.2p.5P(c).G){8(6.q.4g){6.q.4g(c,$(a))}H{c.5Q(a)}}}8(!b&&6.q.1N){c.30("");8(19 6.q.1N==="1k"){c.1o(6.q.1N)}H{6.q.1N(c,a)}}6.1w=6.1w.1n(c)},1T:7(a){p b=6.3e(a);l 6.3b().2v(7(){l $(6).12("T")===b})},3e:7(a){l 6.2i[a.u]||(6.1C(a)?a.u:a.44||a.u)},34:7(a){8(6.1C(a)){a=6.1D(a.u).1L(6.q.2S)[0]}l a},1C:7(a){l(/1U|31/i).Y(a.F)},1D:7(a){l $(6.X).42("[u=\'"+a+"\']")},22:7(a,b){2M(b.4h.21()){1z"1X":l $("3R:3l",b).G;1z"2e":8(6.1C(b)){l 6.1D(b.u).2v(":2O").G}}l a.G},4i:7(a,b){l 6.3f[19 a]?6.3f[19 a](a,b):w},3f:{"5R":7(a,b){l a},"1k":7(a,b){l!!$(a,b.P).G},"7":7(a,b){l a(b)}},N:7(a){p b=6.2k(a);l!$.v.1M.14.16(6,b,a)&&"1Z-20"},4j:7(a){8(!6.1J[a.u]){6.1g++;6.1J[a.u]=w}},4k:7(a,b){6.1g--;8(6.1g<0){6.1g=0}Q 6.1J[a.u];8(b&&6.1g===0&&6.1m&&6.P()){$(6.X).2b();6.1m=K}H 8(!b&&6.1g===0&&6.1m){$(6.X).3U("18-P",[6]);6.1m=K}},1Y:7(a){l $.11(a,"1Y")||$.11(a,"1Y",{3g:38,L:w,1u:6.2y(a,"1p")})}},23:{14:{14:w},1F:{1F:w},1q:{1q:w},1r:{1r:w},2l:{2l:w},1j:{1j:w},1V:{1V:w},2m:{2m:w}},4l:7(a,b){8(a.2h===48){6.23[a]=b}H{$.J(6.23,a)}},3s:7(a){p b={};p c=$(a).12("5S");8(c){$.U(c.1y(" "),7(){8(6 R $.v.23){$.J(b,$.v.23[6])}})}l b},3t:7(a){p b={};p c=$(a);p d=c[0].4m("F");T(p e R $.v.1M){p f;8(e==="14"){f=c.5T(0).4m(e);8(f===""){f=w}f=!!f}H{f=c.12(e)}8(/1I|1H/.Y(e)&&(d===38||/1j|1s|30/.Y(d))){f=1O(f)}8(f){b[e]=f}H 8(d===e&&d!==\'1s\'){b[e]=w}}8(b.1e&&/-1|5U|5V/.Y(b.1e)){Q b.1e}l b},3u:7(a){p b,1d,13={},$I=$(a);T(b R $.v.1M){1d=$I.11("5W-"+b.21());8(1d!==1l){13[b]=1d}}l 13},2L:7(a){p b={};p c=$.11(a.P,"v");8(c.q.13){b=$.v.1Q(c.q.13[a.u])||{}}l b},3r:7(d,e){$.U(d,7(a,b){8(b===K){Q d[a];l}8(b.3h||b.2A){p c=w;2M(19 b.2A){1z"1k":c=!!$(b.2A,e.P).G;2N;1z"7":c=b.2A.16(e,e);2N}8(c){d[a]=b.3h!==1l?b.3h:w}H{Q d[a]}}});$.U(d,7(a,b){d[a]=$.4n(b)?b(e):b});$.U([\'1G\',\'1e\'],7(){8(d[6]){d[6]=1O(d[6])}});$.U([\'2o\',\'1s\'],7(){p a;8(d[6]){8($.2B(d[6])){d[6]=[1O(d[6][0]),1O(d[6][1])]}H 8(19 d[6]==="1k"){a=d[6].1y(/[\\s,]+/);d[6]=[1O(a[0]),1O(a[1])]}}});8($.v.3M){8(d.1I&&d.1H){d.1s=[d.1I,d.1H];Q d.1I;Q d.1H}8(d.1G&&d.1e){d.2o=[d.1G,d.1e];Q d.1G;Q d.1e}}l d},1Q:7(a){8(19 a==="1k"){p b={};$.U(a.1y(/\\s/),7(){b[6]=w});a=b}l a},5X:7(a,b,c){$.v.1M[a]=b;$.v.M[a]=c!==1l?c:$.v.M[a];8(b.G<3){$.v.4l(a,$.v.1Q(a))}},1M:{14:7(a,b,c){8(!6.4i(c,b)){l"1Z-20"}8(b.4h.21()==="1X"){p d=$(b).W();l d&&d.G>0}8(6.1C(b)){l 6.22(a,b)>0}l $.1A(a).G>0},1F:7(a,b){l 6.N(b)||/^((([a-z]|\\d|[!#\\$%&\'\\*\\+\\-\\/=\\?\\^Z`{\\|}~]|[\\x-\\y\\A-\\B\\C-\\E])+(\\.([a-z]|\\d|[!#\\$%&\'\\*\\+\\-\\/=\\?\\^Z`{\\|}~]|[\\x-\\y\\A-\\B\\C-\\E])+)*)|((\\4o)((((\\2C|\\24)*(\\3i\\4p))?(\\2C|\\24)+)?(([\\4q-\\5Y\\4r\\4s\\5Z-\\60\\4t]|\\61|[\\62-\\63]|[\\64-\\65]|[\\x-\\y\\A-\\B\\C-\\E])|(\\\\([\\4q-\\24\\4r\\4s\\3i-\\4t]|[\\x-\\y\\A-\\B\\C-\\E]))))*(((\\2C|\\24)*(\\3i\\4p))?(\\2C|\\24)+)?(\\4o)))@((([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])|(([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])*([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])))\\.)+(([a-z]|[\\x-\\y\\A-\\B\\C-\\E])|(([a-z]|[\\x-\\y\\A-\\B\\C-\\E])([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])*([a-z]|[\\x-\\y\\A-\\B\\C-\\E])))$/i.Y(a)},1q:7(a,b){l 6.N(b)||/^(66?|s?67):\\/\\/(((([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|((([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])|(([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])*([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])))\\.)+(([a-z]|[\\x-\\y\\A-\\B\\C-\\E])|(([a-z]|[\\x-\\y\\A-\\B\\C-\\E])([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])*([a-z]|[\\x-\\y\\A-\\B\\C-\\E])))\\.?)(:\\d*)?)(\\/((([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:|@)+(\\/(([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:|@)|[\\68-\\69]|\\/|\\?)*)?(#((([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$/i.Y(a)},1r:7(a,b){l 6.N(b)||!/6a|6b/.Y(2H 6c(a).6d())},2l:7(a,b){l 6.N(b)||/^\\d{4}[\\/\\-]\\d{1,2}[\\/\\-]\\d{1,2}$/.Y(a)},1j:7(a,b){l 6.N(b)||/^-?(?:\\d+|\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$/.Y(a)},1V:7(a,b){l 6.N(b)||/^\\d+$/.Y(a)},2m:7(a,b){8(6.N(b)){l"1Z-20"}8(/[^0-9 \\-]+/.Y(a)){l K}p c=0,27=0,2D=K;a=a.1B(/\\D/g,"");T(p n=a.G-1;n>=0;n--){p d=a.6e(n);27=6f(d,10);8(2D){8((27*=2)>9){27-=9}}c+=27;2D=!2D}l(c%10)===0},1G:7(a,b,c){p d=$.2B(a)?a.G:6.22($.1A(a),b);l 6.N(b)||d>=c},1e:7(a,b,c){p d=$.2B(a)?a.G:6.22($.1A(a),b);l 6.N(b)||d<=c},2o:7(a,b,c){p d=$.2B(a)?a.G:6.22($.1A(a),b);l 6.N(b)||(d>=c[0]&&d<=c[1])},1I:7(a,b,c){l 6.N(b)||a>=c},1H:7(a,b,c){l 6.N(b)||a<=c},1s:7(a,b,c){l 6.N(b)||(a>=c[0]&&a<=c[1])},2n:7(a,b,c){p d=$(c);8(6.q.3C){d.6g(".1c-2n").32("6h.1c-2n",7(){$(b).L()})}l a===d.W()},1p:7(f,g,h){8(6.N(g)){l"1Z-20"}p i=6.1Y(g);8(!6.q.M[g.u]){6.q.M[g.u]={}}i.4u=6.q.M[g.u].1p;6.q.M[g.u].1p=i.1u;h=19 h==="1k"&&{1q:h}||h;8(i.3g===f){l i.L}i.3g=f;p j=6;6.4j(g);p k={};k[g.u]=f;$.3j($.J(w,{1q:h,2E:"28",1f:"1c"+g.u,6i:"6j",11:k,1N:7(a){j.q.M[g.u].1p=i.4u;p b=a===w||a==="w";8(b){p c=j.1m;j.36(g);j.1m=c;j.1v.2t(g);Q j.18[g.u];j.1t()}H{p d={};p e=a||j.2y(g,"1p");d[g.u]=i.1u=$.4n(e)?e(f):e;j.18[g.u]=w;j.1t(d)}i.L=b;j.4k(g,b)}},h));l"1J"}}});$.15=$.v.15}(3k));(7($){p d={};8($.4v){$.4v(7(a,Z,b){p c=a.1f;8(a.2E==="28"){8(d[c]){d[c].28()}d[c]=b}})}H{p e=$.3j;$.3j=7(a){p b=("2E"R a?a:$.4w).2E,1f=("1f"R a?a:$.4w).1f;8(b==="28"){8(d[1f]){d[1f].28()}d[1f]=e.2g(6,17);l d[1f]}l e.2g(6,17)}}}(3k));(7($){$.J($.2F,{2a:7(c,d,e){l 6.32(d,7(a){p b=$(a.2c);8(b.2K(c)){l e.2g(b,17)}})}})}(3k));',62,392,'||||||this|function|if|||||||||||||return||||var|settings||||name|validator|true|u00A0|uD7FF||uF900|uFDCF|uFDF0||uFFEF|type|length|else|element|extend|false|valid|messages|optional|Please|form|delete|in|enter|for|each|errorList|val|currentForm|test|_||data|attr|rules|required|format|call|arguments|invalid|typeof|elements|toHide|validate|value|maxlength|port|pendingRequest|errorClass|submitted|number|string|undefined|formSubmitted|add|addClass|remote|url|date|range|showErrors|message|successList|toShow|console|split|case|trim|replace|checkable|findByName|removeClass|email|minlength|max|min|pending|errorMap|not|methods|success|Number|submitButton|normalizeRule|validClass|unhighlight|errorsFor|radio|digits|reset|select|previousValue|dependency|mismatch|toLowerCase|getLength|classRuleSettings|x09||da|nDigit|abort|debug|validateDelegate|submit|target|cancelSubmit|input|focusInvalid|apply|constructor|groups|addWrapper|elementValue|dateISO|creditcard|equalTo|rangelength|labelContainer|containers|currentElements|check|push|objectLength|filter|method|parameters|defaultMessage|wrapper|depends|isArray|x20|bEven|mode|fn|window|new|submitHandler|handle|is|staticRules|switch|break|checked|defaults|errorElement|errorLabelContainer|ignore|hide|lastElement|highlight|than|characters|delegate|eventType|text|checkbox|bind|prepareForm|validationTargetFor|clean|prepareElement|resetForm|null|hideErrors|rulesCache|errors|theregex|showLabel|idOrName|dependTypes|old|param|x0d|ajax|jQuery|selected|novalidate|onsubmit|click|hidden|remove|normalizeRules|classRules|attributeRules|dataRules|init|makeArray|Array|error|errorContainer|ignoreTitle|lastActive|onfocusout|parentNode|field|the|no|between|and|or|equal|to|autoCreateRanges|errorContext|textarea|datetime|focusin|option|invalidHandler|checkForm|triggerHandler|numberOfInvalids|grep|defaultShowErrors|size|try|findLastActive|catch|find|formatAndAdd|id|customDataMessage|msg|customMessage|String|findDefined|strong|parent|validElements|show|invalidElements|html|errorPlacement|nodeName|depend|startRequest|stopRequest|addClassRules|getAttribute|isFunction|x22|x0a|x01|x0b|x0c|x7f|originalMessage|ajaxPrefilter|ajaxSettings|warn|Nothing|can|returning|nothing|hasClass|cancel|formnovalidate|preventDefault|appendTo|removeAttrs|removeAttr|expr|blank|filled|unchecked|prop|unshift|slice|RegExp|label|onfocusin|focusCleanup|blockFocusCleanup|onkeyup|which|onclick|setDefaults|This|fix|address|URL|ISO|only|credit|card|same|again|more|at|least|long|less|greater|prototype|valueCache|on|password|mysql|search|tel|month|week|time|local|color|focusout|keyup|removeData|visible|focus|trigger|image|disabled|has|assigned|continue|log|Exception|occurred|when|checking|throw|attributes|title|Warning|No|defined|map|wrap|append|insertAfter|boolean|class|get|2147483647|524288|rule|addMethod|x08|x0e|x1f|x21|x23|x5b|x5d|x7e|https|ftp|uE000|uF8FF|Invalid|NaN|Date|toString|charAt|parseInt|unbind|blur|dataType|json'.split('|'),0,{})); 15 | -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/static/js/wallet.js: -------------------------------------------------------------------------------- 1 | 2 | function saveKeystoreNext() { 3 | $("#save-keystore").hide() 4 | $("#save-privatekey").show() 5 | } 6 | 7 | //通过私钥解锁账户 8 | function unlockAccountWithPrivatekey() { 9 | let privatekey = $("#input-privatekey").val() 10 | console.log(privatekey) 11 | $.post("/unlock/private", `privatekey=${privatekey}`, function (res, status) { 12 | console.log(status + JSON.stringify(res)) 13 | if (res.code == 0) { 14 | //将服务端返回的账户信息显示到页面 15 | //configAccountInfo(res.data) 16 | } 17 | }) 18 | } 19 | 20 | $(document).ready(function () { 21 | //改变了解锁账号的方式 22 | $("input[name=unlocktype]").change(function () { 23 | if (this.value == 1) { 24 | $("#unlock-account-privatekey").show() 25 | $("#unlock-account-keystore").hide() 26 | $("#unlock-account-mnemonic").hide() 27 | } else if (this.value == 2) { 28 | $("#unlock-account-privatekey").hide() 29 | $("#unlock-account-keystore").show() 30 | $("#unlock-account-mnemonic").hide() 31 | } else { 32 | $("#unlock-account-privatekey").hide() 33 | $("#unlock-account-keystore").hide() 34 | $("#unlock-account-mnemonic").show() 35 | } 36 | }) 37 | }) -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/static/keystore/UTC--2018-09-25T06:24:28.689Z--42f971FC3443B43313441E68f7548b3BD0713dB9: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"a3b41a93-4812-4651-a5e7-f869f1c1c81a","address":"42f971fc3443b43313441e68f7548b3bd0713db9","crypto":{"ciphertext":"1b878fd78042a1aac1e1404c886eb823c29052599432c8a19840b8aa23c976ff","cipherparams":{"iv":"a261b97eca4c487d0f149f554e8d0767"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"04603dddcd4dc7f740f4f0d5ffc38277d0dc7f5180c235a1f26ab314bf4df413","n":8192,"r":8,"p":1},"mac":"7511195ae4a6f154b692e02739199b717ed9ed6f973d8de206fea6ea66ac829c"}} -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/static/keystore/UTC--2018-09-25T06:33:18.858Z--709b7348Cb70D65b9C65C0c884B2bF7e02f5B939: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"b3348a71-cfee-445a-b06b-f15c7a989e05","address":"709b7348cb70d65b9c65c0c884b2bf7e02f5b939","crypto":{"ciphertext":"4f666348cf7083c5b66499493a230f3c264a313e36fe7b4c20bc8a574c9598dd","cipherparams":{"iv":"df4a0f386394a0bf2743eb7f952f4519"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"99f2680cb55bf1c7f7679b6df7be2dff58e67c16f3846cf58a15c468b1beabd6","n":8192,"r":8,"p":1},"mac":"127badb0241dd2a420af03dc7c2a494e8c590ff2ead36be48b9baa692815c0fe"}} -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/static/keystore/UTC--2018-09-25T06:34:49.890Z--a2d73CF52034462ACBb359154c2fe3Fc688709A6: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"bb7226c6-aa03-4879-85a3-a7d6df562a2e","address":"a2d73cf52034462acbb359154c2fe3fc688709a6","crypto":{"ciphertext":"30069b4e23c2c90530817f6920f7edbab43de8315f41e5322aaec6e198c2e6ee","cipherparams":{"iv":"632ce6e6012270fa426a06b3f1ace544"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"6081872f754b4060cb7e3a83b5805425fd968eae7653f1494d8511c004d93b0f","n":8192,"r":8,"p":1},"mac":"2b634a0be26989f3f9f9de586411c90f877ee16ea1d796edfe0ba2412cdca766"}} -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/utils/myUtils.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | getweb3: () => { 4 | let Web3 = require("web3") 5 | var web3 = new Web3(Web3.givenProvider || 'https://kovan.infura.io/v3/bc76cd31e8bf48f9a28b73770ffca805'); 6 | 7 | return web3 8 | }, 9 | 10 | success: (data) => { 11 | responseData = { 12 | code:0, 13 | status:"success", 14 | data:data 15 | } 16 | return responseData 17 | }, 18 | 19 | fail: (msg) => { 20 | responseData = { 21 | code:1, 22 | status:"fail", 23 | msg:msg 24 | } 25 | return responseData 26 | } 27 | } -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/views/downloadkeystore.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 保存你的keystore 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 |
18 |
19 |

保存你的keystore

20 | 下载keystore文件 21 |

22 | 23 |
24 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/views/newaccount.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 创建钱包 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 |
16 |

创建一个新的账号

17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /MyEtherWallet:07-解锁钱包账号姿势一:私钥/views/transaction.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 转账 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 |
18 |

发送以太币或者Token代币

19 |
20 | 21 | 22 | 23 |
24 | 25 | 26 |
27 | 28 | 29 |
30 | 31 | 37 | 38 | 40 | 41 | 43 |
44 | 45 | 47 |
48 | 49 | 50 | -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/controllers/account.js: -------------------------------------------------------------------------------- 1 | let { success, fail } = require("../utils/myUtils") 2 | let web3 = require("../utils/myUtils").getweb3() 3 | let fs = require("fs") 4 | 5 | //获取以太币余额 6 | async function getAccountBalance(address) { 7 | let balance = await web3.eth.getBalance(address) 8 | return web3.utils.fromWei(balance, "ether") 9 | } 10 | 11 | //配置返回给前端的数据,包含以太币的数据,还会有Token的数据 12 | async function setResponseData(account) { 13 | //获取账户余额 14 | let balance = await getAccountBalance(account.address) 15 | console.log(balance) 16 | 17 | let resData = success({ 18 | balance: balance, 19 | address: account.address, 20 | privatekey: account.privateKey 21 | }) 22 | 23 | //返回相应数据给前端 24 | return resData 25 | } 26 | 27 | module.exports = { 28 | unlockAccountWithPrivate: async (ctx) => { 29 | //1.获取私钥 30 | let privatekey = ctx.request.body.privatekey 31 | console.log(privatekey) 32 | //2.通过私钥解锁账户 33 | let account = web3.eth.accounts.privateKeyToAccount(privatekey) 34 | console.log(account) 35 | //3.将账户信息返回给前端 36 | ctx.body = await setResponseData(account) 37 | }, 38 | 39 | unlockAccountWithKeystore: async (ctx) => { 40 | //1. 获取前端传递的数据,包括keystore、密码 41 | let password = ctx.request.body.password 42 | console.log(password) 43 | let keystore = ctx.request.files.file 44 | console.log(keystore) 45 | //2.读取缓存文件中keystore的数据 46 | let keystoreData = fs.readFileSync(keystore.path, "utf8") 47 | console.log(keystoreData) 48 | //3. 通过keystore和密码解锁账户 49 | let account = web3.eth.accounts.decrypt(JSON.parse(keystoreData), password) 50 | console.log(account) 51 | //4.将账户信息返回给前端 52 | ctx.body = await setResponseData(account) 53 | }, 54 | } -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/controllers/newAccount.js: -------------------------------------------------------------------------------- 1 | let web3 = require("../utils/myUtils").getweb3() 2 | let fs = require("fs") 3 | let path = require("path") 4 | 5 | module.exports = { 6 | //获取创建账号的页面 7 | newAccountHtml: async (ctx) => { 8 | await ctx.render("newaccount.html") 9 | }, 10 | 11 | //创建账户的表单提交被触发的方法 12 | newAccount: async (ctx) => { 13 | console.log("password:", ctx.request.body.password) 14 | 15 | //1.创建钱包账号 16 | let account = web3.eth.accounts.create(ctx.request.body.password) 17 | console.log(account) 18 | 19 | //2.根据账号和密码生成keystore文件 20 | let keystore = account.encrypt(ctx.request.body.password) 21 | console.log(keystore) 22 | 23 | //3.将keysotr保存到文件 24 | let keystoreString = JSON.stringify(keystore) 25 | let time = new Date() 26 | let fileName = 'UTC--'+time.toISOString()+'--'+account.address.slice(2) 27 | console.log(fileName) 28 | let filePath = path.join(__dirname, "../static/keystore", fileName) 29 | fs.writeFileSync(filePath, keystoreString) 30 | 31 | //4.将账号信息返回给客户端 32 | await ctx.render("downloadkeystore.html", { 33 | "downloadurl":"/keystore/"+fileName, 34 | "privatekey":account.privateKey 35 | }) 36 | } 37 | } -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/controllers/transaction.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transactionHtml: async (ctx) => { 3 | await ctx.render("transaction.html") 4 | }, 5 | } -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/index.js: -------------------------------------------------------------------------------- 1 | 2 | let koa = require("koa") 3 | //通过koa创建一个应用程序 4 | let app = new koa() 5 | //导入./router/route这个包,赋值给的router就是 ./router/router导出的数据 6 | let router = require("./router/router") 7 | let static = require("koa-static") 8 | let path = require("path") 9 | let views = require("koa-views") 10 | let koaBody = require("koa-body") 11 | 12 | app.use(async (ctx, next) => { 13 | console.log(`${ctx.method} ${ctx.url} ..........`) 14 | await next() 15 | }) 16 | 17 | //针对于文件上传的时候,可以解析多个字段 18 | app.use(koaBody({multipart:true})) 19 | //注册静态文件的库到中间件 20 | app.use(static(path.join(__dirname, "static"))) 21 | //注册模板引擎的库到中间件 22 | app.use(views(path.join(__dirname, "views"), {extension:"ejs", map:{html:"ejs"}})) 23 | app.use(router.routes()) 24 | 25 | console.log("正在监听3000端口") 26 | app.listen(3000) 27 | -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "4-wallet", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "bignumber": "^1.1.0", 13 | "ejs": "^2.6.1", 14 | "ethereumjs-tx": "^1.3.7", 15 | "koa": "^2.5.2", 16 | "koa-body": "^4.0.4", 17 | "koa-router": "^7.4.0", 18 | "koa-static": "^5.0.0", 19 | "koa-views": "^6.1.4", 20 | "web3": "^1.0.0-beta.35", 21 | "bip39": "^2.5.0", 22 | "ethereumjs-util": "^5.2.0", 23 | "ethereumjs-wallet": "^0.6.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/router/router.js: -------------------------------------------------------------------------------- 1 | 2 | let router = require("koa-router")() 3 | let newAccountController = require("../controllers/newAccount") 4 | let trasactionConytoller = require("../controllers/transaction") 5 | let accountController = require("../controllers/account") 6 | 7 | 8 | router.get("/", async (ctx) => { 9 | //重定向 10 | ctx.response.redirect("/account/new.html") 11 | }) 12 | 13 | //获取创建钱包账户的页面 14 | router.get("/account/new.html", newAccountController.newAccountHtml) 15 | //提交创建钱包账户的表单 16 | router.post("/account/new", newAccountController.newAccount) 17 | 18 | //获取转账的页面 19 | router.get("/transaction.html", trasactionConytoller.transactionHtml) 20 | 21 | //通过私钥解锁账户 22 | router.post("/unlock/private", accountController.unlockAccountWithPrivate) 23 | //通过keystore解锁账户 24 | router.post("/unlock/keystore", accountController.unlockAccountWithKeystore) 25 | 26 | module.exports = router 27 | -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/static/css/wallet.css: -------------------------------------------------------------------------------- 1 | 2 | #main{ 3 | /*background-color: #8bc34a;*/ 4 | margin: 100px 50px 50px 50px; 5 | 6 | } 7 | .error{ 8 | color: red; 9 | } 10 | a{ 11 | color: black; 12 | text-decoration: none; 13 | } 14 | a:hover{ 15 | color: #666; 16 | } 17 | body{ 18 | margin: 0px; 19 | } 20 | .global-color{ 21 | color: #0abc9c; 22 | } 23 | a[class=button]{ 24 | background-color: beige; 25 | padding: 2px 10px; 26 | border: 1px solid gray; 27 | } 28 | 29 | /*导航-------------------------------------------------------------------------------------------------------*/ 30 | #nav{ 31 | display: flex; 32 | justify-content: space-between; 33 | background-color: #0abc9c; 34 | position: fixed; 35 | top: 0px; 36 | left: 0px; 37 | right: 0px; 38 | } 39 | #nav li{ 40 | display: inline-block; 41 | margin: 10px 2px; 42 | } 43 | #nav ul{ 44 | padding: 0px; 45 | } 46 | #nav a{ 47 | padding: 10px; 48 | font-size: 24px; 49 | } 50 | #nav-left{ 51 | margin-left: 20px; 52 | } 53 | #nav-right{ 54 | margin-right: 20px; 55 | } 56 | -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/static/html/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/static/js/wallet.js: -------------------------------------------------------------------------------- 1 | 2 | function saveKeystoreNext() { 3 | $("#save-keystore").hide() 4 | $("#save-privatekey").show() 5 | } 6 | 7 | //通过私钥解锁账户 8 | function unlockAccountWithPrivatekey() { 9 | let privatekey = $("#input-privatekey").val() 10 | console.log(privatekey) 11 | $.post("/unlock/private", `privatekey=${privatekey}`, function (res, status) { 12 | console.log(status + JSON.stringify(res)) 13 | if (res.code == 0) { 14 | //将服务端返回的账户信息显示到页面 15 | //configAccountInfo(res.data) 16 | } 17 | }) 18 | } 19 | 20 | //通过Keystore解锁账户 21 | function unlockAccountWithKeystore() { 22 | var filedata = $("#unlock-accoutn-file").val() 23 | if (filedata.length <= 0) { 24 | alert("请选择文件!") 25 | return 26 | } 27 | //文件上传通过Formdata去储存文件的数据 28 | var data = new FormData() 29 | data.append("file", $("#unlock-accoutn-file")[0].files[0]) 30 | data.append("password", $("#unlock-account-password").val()) 31 | var urlStr = "/unlock/keystore" 32 | $.ajax({ 33 | url: urlStr, 34 | type: "post", 35 | dataType: "json", 36 | contentType: false, 37 | data: data, 38 | processData: false, 39 | success: function (res, status) { 40 | console.log(status + JSON.stringify(res)) 41 | if (res.code == 0) { 42 | //将服务端返回的账户信息显示到页面 43 | //configAccountInfo(res.data) 44 | } 45 | }, 46 | error: function (res, status) { 47 | alert(JSON.stringify(res)+status) 48 | } 49 | }) 50 | } 51 | 52 | $(document).ready(function () { 53 | //改变了解锁账号的方式 54 | $("input[name=unlocktype]").change(function () { 55 | if (this.value == 1) { 56 | $("#unlock-account-privatekey").show() 57 | $("#unlock-account-keystore").hide() 58 | $("#unlock-account-mnemonic").hide() 59 | } else if (this.value == 2) { 60 | $("#unlock-account-privatekey").hide() 61 | $("#unlock-account-keystore").show() 62 | $("#unlock-account-mnemonic").hide() 63 | } else { 64 | $("#unlock-account-privatekey").hide() 65 | $("#unlock-account-keystore").hide() 66 | $("#unlock-account-mnemonic").show() 67 | } 68 | }) 69 | }) -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/static/keystore/UTC--2018-09-25T06:24:28.689Z--42f971FC3443B43313441E68f7548b3BD0713dB9: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"a3b41a93-4812-4651-a5e7-f869f1c1c81a","address":"42f971fc3443b43313441e68f7548b3bd0713db9","crypto":{"ciphertext":"1b878fd78042a1aac1e1404c886eb823c29052599432c8a19840b8aa23c976ff","cipherparams":{"iv":"a261b97eca4c487d0f149f554e8d0767"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"04603dddcd4dc7f740f4f0d5ffc38277d0dc7f5180c235a1f26ab314bf4df413","n":8192,"r":8,"p":1},"mac":"7511195ae4a6f154b692e02739199b717ed9ed6f973d8de206fea6ea66ac829c"}} -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/static/keystore/UTC--2018-09-25T06:33:18.858Z--709b7348Cb70D65b9C65C0c884B2bF7e02f5B939: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"b3348a71-cfee-445a-b06b-f15c7a989e05","address":"709b7348cb70d65b9c65c0c884b2bf7e02f5b939","crypto":{"ciphertext":"4f666348cf7083c5b66499493a230f3c264a313e36fe7b4c20bc8a574c9598dd","cipherparams":{"iv":"df4a0f386394a0bf2743eb7f952f4519"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"99f2680cb55bf1c7f7679b6df7be2dff58e67c16f3846cf58a15c468b1beabd6","n":8192,"r":8,"p":1},"mac":"127badb0241dd2a420af03dc7c2a494e8c590ff2ead36be48b9baa692815c0fe"}} -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/static/keystore/UTC--2018-09-25T06:34:49.890Z--a2d73CF52034462ACBb359154c2fe3Fc688709A6: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"bb7226c6-aa03-4879-85a3-a7d6df562a2e","address":"a2d73cf52034462acbb359154c2fe3fc688709a6","crypto":{"ciphertext":"30069b4e23c2c90530817f6920f7edbab43de8315f41e5322aaec6e198c2e6ee","cipherparams":{"iv":"632ce6e6012270fa426a06b3f1ace544"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"6081872f754b4060cb7e3a83b5805425fd968eae7653f1494d8511c004d93b0f","n":8192,"r":8,"p":1},"mac":"2b634a0be26989f3f9f9de586411c90f877ee16ea1d796edfe0ba2412cdca766"}} -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/utils/myUtils.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | getweb3: () => { 4 | let Web3 = require("web3") 5 | var web3 = new Web3(Web3.givenProvider || 'https://kovan.infura.io/v3/bc76cd31e8bf48f9a28b73770ffca805'); 6 | 7 | return web3 8 | }, 9 | 10 | success: (data) => { 11 | responseData = { 12 | code:0, 13 | status:"success", 14 | data:data 15 | } 16 | return responseData 17 | }, 18 | 19 | fail: (msg) => { 20 | responseData = { 21 | code:1, 22 | status:"fail", 23 | msg:msg 24 | } 25 | return responseData 26 | } 27 | } -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/views/downloadkeystore.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 保存你的keystore 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 |
18 |
19 |

保存你的keystore

20 | 下载keystore文件 21 |

22 | 23 |
24 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/views/newaccount.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 创建钱包 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 |
16 |

创建一个新的账号

17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /MyEtherWallet:08-解锁钱包账号姿势二:keystore+密码/views/transaction.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 转账 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 |
18 |

发送以太币或者Token代币

19 |
20 | 21 | 22 | 23 |
24 | 25 | 26 |
27 | 28 | 29 |
30 | 31 | 37 | 38 | 48 | 49 | 51 |
52 | 53 | 55 |
56 | 57 | 58 | -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/controllers/account.js: -------------------------------------------------------------------------------- 1 | let { success, fail } = require("../utils/myUtils") 2 | let web3 = require("../utils/myUtils").getweb3() 3 | let fs = require("fs") 4 | let menmonicModel = require("../models/mnemonic") 5 | 6 | //获取以太币余额 7 | async function getAccountBalance(address) { 8 | let balance = await web3.eth.getBalance(address) 9 | return web3.utils.fromWei(balance, "ether") 10 | } 11 | 12 | //配置返回给前端的数据,包含以太币的数据,还会有Token的数据 13 | async function setResponseData(account) { 14 | //获取账户余额 15 | let balance = await getAccountBalance(account.address) 16 | console.log(balance) 17 | 18 | let resData = success({ 19 | balance: balance, 20 | address: account.address, 21 | privatekey: account.privateKey 22 | }) 23 | 24 | //返回相应数据给前端 25 | return resData 26 | } 27 | 28 | module.exports = { 29 | unlockAccountWithPrivate: async (ctx) => { 30 | //1.获取私钥 31 | let privatekey = ctx.request.body.privatekey 32 | console.log(privatekey) 33 | //2.通过私钥解锁账户 34 | let account = web3.eth.accounts.privateKeyToAccount(privatekey) 35 | console.log(account) 36 | //3.将账户信息返回给前端 37 | ctx.body = await setResponseData(account) 38 | }, 39 | 40 | unlockAccountWithKeystore: async (ctx) => { 41 | //1. 获取前端传递的数据,包括keystore、密码 42 | let password = ctx.request.body.password 43 | console.log(password) 44 | let keystore = ctx.request.files.file 45 | console.log(keystore) 46 | //2.读取缓存文件中keystore的数据 47 | let keystoreData = fs.readFileSync(keystore.path, "utf8") 48 | console.log(keystoreData) 49 | //3. 通过keystore和密码解锁账户 50 | let account = web3.eth.accounts.decrypt(JSON.parse(keystoreData), password) 51 | console.log(account) 52 | //4.将账户信息返回给前端 53 | ctx.body = await setResponseData(account) 54 | }, 55 | 56 | unlockAccountWithMnemonic: async (ctx) => { 57 | //1.获取助记词 58 | let mnemonic = ctx.request.body.mnemonic 59 | console.log("mnemonic:",mnemonic) 60 | 61 | //2.通过助记词获取私钥 62 | /* 63 | 注意这里为了简化前端实现过程,故只获取了助记词的第一对公私钥,即"m/44'/60'/0'/0/0",在实际开发工作中需枚举路径"m/44'/60'/0'/0/0"的最后一位0,可继续取值为0,1,2,3,4…… 64 | */ 65 | let privatekey = menmonicModel.getPrivatekeyWithMnemonic(mnemonic, "m/44'/60'/0'/0/0") 66 | console.log("私钥:"+privatekey) 67 | 68 | //3.通过私钥解锁账户 69 | let account = web3.eth.accounts.privateKeyToAccount(privatekey) 70 | console.log("account:",account) 71 | 72 | //4.将账户信息返回给前端 73 | ctx.body = await setResponseData(account) 74 | }, 75 | } -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/controllers/newAccount.js: -------------------------------------------------------------------------------- 1 | let web3 = require("../utils/myUtils").getweb3() 2 | let fs = require("fs") 3 | let path = require("path") 4 | 5 | module.exports = { 6 | //获取创建账号的页面 7 | newAccountHtml: async (ctx) => { 8 | await ctx.render("newaccount.html") 9 | }, 10 | 11 | //创建账户的表单提交被触发的方法 12 | newAccount: async (ctx) => { 13 | console.log("password:", ctx.request.body.password) 14 | 15 | //1.创建钱包账号 16 | let account = web3.eth.accounts.create(ctx.request.body.password) 17 | console.log(account) 18 | 19 | //2.根据账号和密码生成keystore文件 20 | let keystore = account.encrypt(ctx.request.body.password) 21 | console.log(keystore) 22 | 23 | //3.将keysotr保存到文件 24 | let keystoreString = JSON.stringify(keystore) 25 | let time = new Date() 26 | let fileName = 'UTC--'+time.toISOString()+'--'+account.address.slice(2) 27 | console.log(fileName) 28 | let filePath = path.join(__dirname, "../static/keystore", fileName) 29 | fs.writeFileSync(filePath, keystoreString) 30 | 31 | //4.将账号信息返回给客户端 32 | await ctx.render("downloadkeystore.html", { 33 | "downloadurl":"/keystore/"+fileName, 34 | "privatekey":account.privateKey 35 | }) 36 | } 37 | } -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/controllers/transaction.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transactionHtml: async (ctx) => { 3 | await ctx.render("transaction.html") 4 | }, 5 | } -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/index.js: -------------------------------------------------------------------------------- 1 | 2 | let koa = require("koa") 3 | //通过koa创建一个应用程序 4 | let app = new koa() 5 | //导入./router/route这个包,赋值给的router就是 ./router/router导出的数据 6 | let router = require("./router/router") 7 | let static = require("koa-static") 8 | let path = require("path") 9 | let views = require("koa-views") 10 | let koaBody = require("koa-body") 11 | 12 | app.use(async (ctx, next) => { 13 | console.log(`${ctx.method} ${ctx.url} ..........`) 14 | await next() 15 | }) 16 | 17 | //针对于文件上传的时候,可以解析多个字段 18 | app.use(koaBody({multipart:true})) 19 | //注册静态文件的库到中间件 20 | app.use(static(path.join(__dirname, "static"))) 21 | //注册模板引擎的库到中间件 22 | app.use(views(path.join(__dirname, "views"), {extension:"ejs", map:{html:"ejs"}})) 23 | app.use(router.routes()) 24 | 25 | console.log("正在监听3000端口") 26 | app.listen(3000) 27 | -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/models/mnemonic.js: -------------------------------------------------------------------------------- 1 | let bip39 = require('bip39') 2 | let hdkey = require('ethereumjs-wallet/hdkey') 3 | let util = require('ethereumjs-util') 4 | 5 | module.exports = { 6 | getPrivatekeyWithMnemonic: (mnemonic, derivePath) => { 7 | //将助记词转成seed 8 | let seed = bip39.mnemonicToSeed(mnemonic) 9 | //通过hdkey将seed生成HDWallet 10 | let hdWallet = hdkey.fromMasterSeed(seed) 11 | //生成钱包中在m/44'/60'/0'/0/0路径的第一个帐户的keypair。 12 | let key = hdWallet.derivePath(derivePath) 13 | //获取私钥 14 | return util.bufferToHex(key._hdkey._privateKey) 15 | } 16 | } -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "4-wallet", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "bignumber": "^1.1.0", 13 | "ejs": "^2.6.1", 14 | "ethereumjs-tx": "^1.3.7", 15 | "koa": "^2.5.2", 16 | "koa-body": "^4.0.4", 17 | "koa-router": "^7.4.0", 18 | "koa-static": "^5.0.0", 19 | "koa-views": "^6.1.4", 20 | "web3": "^1.0.0-beta.35", 21 | "bip39": "^2.5.0", 22 | "ethereumjs-util": "^5.2.0", 23 | "ethereumjs-wallet": "^0.6.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/router/router.js: -------------------------------------------------------------------------------- 1 | 2 | let router = require("koa-router")() 3 | let newAccountController = require("../controllers/newAccount") 4 | let trasactionConytoller = require("../controllers/transaction") 5 | let accountController = require("../controllers/account") 6 | 7 | 8 | router.get("/", async (ctx) => { 9 | //重定向 10 | ctx.response.redirect("/account/new.html") 11 | }) 12 | 13 | //获取创建钱包账户的页面 14 | router.get("/account/new.html", newAccountController.newAccountHtml) 15 | //提交创建钱包账户的表单 16 | router.post("/account/new", newAccountController.newAccount) 17 | 18 | //获取转账的页面 19 | router.get("/transaction.html", trasactionConytoller.transactionHtml) 20 | 21 | //通过私钥解锁账户 22 | router.post("/unlock/private", accountController.unlockAccountWithPrivate) 23 | //通过keystore解锁账户 24 | router.post("/unlock/keystore", accountController.unlockAccountWithKeystore) 25 | //通过助记词解锁账户 26 | router.post("/unlock/mnemonic", accountController.unlockAccountWithMnemonic) 27 | 28 | module.exports = router 29 | -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/static/css/wallet.css: -------------------------------------------------------------------------------- 1 | 2 | #main{ 3 | /*background-color: #8bc34a;*/ 4 | margin: 100px 50px 50px 50px; 5 | 6 | } 7 | .error{ 8 | color: red; 9 | } 10 | a{ 11 | color: black; 12 | text-decoration: none; 13 | } 14 | a:hover{ 15 | color: #666; 16 | } 17 | body{ 18 | margin: 0px; 19 | } 20 | .global-color{ 21 | color: #0abc9c; 22 | } 23 | a[class=button]{ 24 | background-color: beige; 25 | padding: 2px 10px; 26 | border: 1px solid gray; 27 | } 28 | 29 | /*导航-------------------------------------------------------------------------------------------------------*/ 30 | #nav{ 31 | display: flex; 32 | justify-content: space-between; 33 | background-color: #0abc9c; 34 | position: fixed; 35 | top: 0px; 36 | left: 0px; 37 | right: 0px; 38 | } 39 | #nav li{ 40 | display: inline-block; 41 | margin: 10px 2px; 42 | } 43 | #nav ul{ 44 | padding: 0px; 45 | } 46 | #nav a{ 47 | padding: 10px; 48 | font-size: 24px; 49 | } 50 | #nav-left{ 51 | margin-left: 20px; 52 | } 53 | #nav-right{ 54 | margin-right: 20px; 55 | } 56 | -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/static/html/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/static/js/wallet.js: -------------------------------------------------------------------------------- 1 | 2 | function saveKeystoreNext() { 3 | $("#save-keystore").hide() 4 | $("#save-privatekey").show() 5 | } 6 | 7 | //通过私钥解锁账户 8 | function unlockAccountWithPrivatekey() { 9 | let privatekey = $("#input-privatekey").val() 10 | console.log(privatekey) 11 | $.post("/unlock/private", `privatekey=${privatekey}`, function (res, status) { 12 | console.log(status + JSON.stringify(res)) 13 | if (res.code == 0) { 14 | //将服务端返回的账户信息显示到页面 15 | //configAccountInfo(res.data) 16 | } 17 | }) 18 | } 19 | 20 | //通过Keystore解锁账户 21 | function unlockAccountWithKeystore() { 22 | var filedata = $("#unlock-accoutn-file").val() 23 | if (filedata.length <= 0) { 24 | alert("请选择文件!") 25 | return 26 | } 27 | //文件上传通过Formdata去储存文件的数据 28 | var data = new FormData() 29 | data.append("file", $("#unlock-accoutn-file")[0].files[0]) 30 | data.append("password", $("#unlock-account-password").val()) 31 | var urlStr = "/unlock/keystore" 32 | $.ajax({ 33 | url: urlStr, 34 | type: "post", 35 | dataType: "json", 36 | contentType: false, 37 | data: data, 38 | processData: false, 39 | success: function (res, status) { 40 | console.log(status + JSON.stringify(res)) 41 | if (res.code == 0) { 42 | //将服务端返回的账户信息显示到页面 43 | //configAccountInfo(res.data) 44 | } 45 | }, 46 | error: function (res, status) { 47 | alert(JSON.stringify(res)+status) 48 | } 49 | }) 50 | } 51 | 52 | //通过助记词解锁账户 53 | function unlockAccountWithMnemonic() { 54 | let mnemonic = $("#input-mnemonic").val() 55 | console.log(mnemonic) 56 | $.post("/unlock/mnemonic", `mnemonic=${mnemonic}`, function (res, status) { 57 | console.log(status + JSON.stringify(res)) 58 | if (res.code == 0) { 59 | //将服务端返回的账户信息显示到页面 60 | //configAccountInfo(res.data) 61 | } 62 | }) 63 | } 64 | 65 | $(document).ready(function () { 66 | //改变了解锁账号的方式 67 | $("input[name=unlocktype]").change(function () { 68 | if (this.value == 1) { 69 | $("#unlock-account-privatekey").show() 70 | $("#unlock-account-keystore").hide() 71 | $("#unlock-account-mnemonic").hide() 72 | } else if (this.value == 2) { 73 | $("#unlock-account-privatekey").hide() 74 | $("#unlock-account-keystore").show() 75 | $("#unlock-account-mnemonic").hide() 76 | } else { 77 | $("#unlock-account-privatekey").hide() 78 | $("#unlock-account-keystore").hide() 79 | $("#unlock-account-mnemonic").show() 80 | } 81 | }) 82 | }) -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/static/keystore/UTC--2018-09-25T06:24:28.689Z--42f971FC3443B43313441E68f7548b3BD0713dB9: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"a3b41a93-4812-4651-a5e7-f869f1c1c81a","address":"42f971fc3443b43313441e68f7548b3bd0713db9","crypto":{"ciphertext":"1b878fd78042a1aac1e1404c886eb823c29052599432c8a19840b8aa23c976ff","cipherparams":{"iv":"a261b97eca4c487d0f149f554e8d0767"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"04603dddcd4dc7f740f4f0d5ffc38277d0dc7f5180c235a1f26ab314bf4df413","n":8192,"r":8,"p":1},"mac":"7511195ae4a6f154b692e02739199b717ed9ed6f973d8de206fea6ea66ac829c"}} -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/static/keystore/UTC--2018-09-25T06:33:18.858Z--709b7348Cb70D65b9C65C0c884B2bF7e02f5B939: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"b3348a71-cfee-445a-b06b-f15c7a989e05","address":"709b7348cb70d65b9c65c0c884b2bf7e02f5b939","crypto":{"ciphertext":"4f666348cf7083c5b66499493a230f3c264a313e36fe7b4c20bc8a574c9598dd","cipherparams":{"iv":"df4a0f386394a0bf2743eb7f952f4519"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"99f2680cb55bf1c7f7679b6df7be2dff58e67c16f3846cf58a15c468b1beabd6","n":8192,"r":8,"p":1},"mac":"127badb0241dd2a420af03dc7c2a494e8c590ff2ead36be48b9baa692815c0fe"}} -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/static/keystore/UTC--2018-09-25T06:34:49.890Z--a2d73CF52034462ACBb359154c2fe3Fc688709A6: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"bb7226c6-aa03-4879-85a3-a7d6df562a2e","address":"a2d73cf52034462acbb359154c2fe3fc688709a6","crypto":{"ciphertext":"30069b4e23c2c90530817f6920f7edbab43de8315f41e5322aaec6e198c2e6ee","cipherparams":{"iv":"632ce6e6012270fa426a06b3f1ace544"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"6081872f754b4060cb7e3a83b5805425fd968eae7653f1494d8511c004d93b0f","n":8192,"r":8,"p":1},"mac":"2b634a0be26989f3f9f9de586411c90f877ee16ea1d796edfe0ba2412cdca766"}} -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/utils/myUtils.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | getweb3: () => { 4 | let Web3 = require("web3") 5 | var web3 = new Web3(Web3.givenProvider || 'https://kovan.infura.io/v3/bc76cd31e8bf48f9a28b73770ffca805'); 6 | 7 | return web3 8 | }, 9 | 10 | success: (data) => { 11 | responseData = { 12 | code:0, 13 | status:"success", 14 | data:data 15 | } 16 | return responseData 17 | }, 18 | 19 | fail: (msg) => { 20 | responseData = { 21 | code:1, 22 | status:"fail", 23 | msg:msg 24 | } 25 | return responseData 26 | } 27 | } -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/views/downloadkeystore.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 保存你的keystore 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 |
18 |
19 |

保存你的keystore

20 | 下载keystore文件 21 |

22 | 23 |
24 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/views/newaccount.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 创建钱包 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 |
16 |

创建一个新的账号

17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /MyEtherWallet:09-解锁钱包账号姿势三:助记词/views/transaction.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 转账 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 |
18 |

发送以太币或者Token代币

19 |
20 | 21 | 22 | 23 |
24 | 25 | 26 |
27 | 28 | 29 |
30 | 31 | 37 | 38 | 48 | 49 | 55 |
56 | 57 | 59 |
60 | 61 | 62 | -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/controllers/account.js: -------------------------------------------------------------------------------- 1 | let { success, fail } = require("../utils/myUtils") 2 | let web3 = require("../utils/myUtils").getweb3() 3 | let fs = require("fs") 4 | let menmonicModel = require("../models/mnemonic") 5 | 6 | //获取以太币余额 7 | async function getAccountBalance(address) { 8 | let balance = await web3.eth.getBalance(address) 9 | return web3.utils.fromWei(balance, "ether") 10 | } 11 | 12 | //配置返回给前端的数据,包含以太币的数据,还会有Token的数据 13 | async function setResponseData(account) { 14 | //获取账户余额 15 | let balance = await getAccountBalance(account.address) 16 | console.log(balance) 17 | 18 | let resData = success({ 19 | balance: balance, 20 | address: account.address, 21 | privatekey: account.privateKey 22 | }) 23 | 24 | //返回相应数据给前端 25 | return resData 26 | } 27 | 28 | module.exports = { 29 | unlockAccountWithPrivate: async (ctx) => { 30 | //1.获取私钥 31 | let privatekey = ctx.request.body.privatekey 32 | console.log(privatekey) 33 | //2.通过私钥解锁账户 34 | let account = web3.eth.accounts.privateKeyToAccount(privatekey) 35 | console.log(account) 36 | //3.将账户信息返回给前端 37 | ctx.body = await setResponseData(account) 38 | }, 39 | 40 | unlockAccountWithKeystore: async (ctx) => { 41 | //1. 获取前端传递的数据,包括keystore、密码 42 | let password = ctx.request.body.password 43 | console.log(password) 44 | let keystore = ctx.request.files.file 45 | console.log(keystore) 46 | //2.读取缓存文件中keystore的数据 47 | let keystoreData = fs.readFileSync(keystore.path, "utf8") 48 | console.log(keystoreData) 49 | //3. 通过keystore和密码解锁账户 50 | let account = web3.eth.accounts.decrypt(JSON.parse(keystoreData), password) 51 | console.log(account) 52 | //4.将账户信息返回给前端 53 | ctx.body = await setResponseData(account) 54 | }, 55 | 56 | unlockAccountWithMnemonic: async (ctx) => { 57 | //1.获取助记词 58 | let mnemonic = ctx.request.body.mnemonic 59 | console.log("mnemonic:",mnemonic) 60 | 61 | //2.通过助记词获取私钥 62 | /* 63 | 注意这里为了简化前端实现过程,故只获取了助记词的第一对公私钥,即"m/44'/60'/0'/0/0",在实际开发工作中需枚举路径"m/44'/60'/0'/0/0"的最后一位0,可继续取值为0,1,2,3,4…… 64 | */ 65 | let privatekey = menmonicModel.getPrivatekeyWithMnemonic(mnemonic, "m/44'/60'/0'/0/0") 66 | console.log("私钥:"+privatekey) 67 | 68 | //3.通过私钥解锁账户 69 | let account = web3.eth.accounts.privateKeyToAccount(privatekey) 70 | console.log("account:",account) 71 | 72 | //4.将账户信息返回给前端 73 | ctx.body = await setResponseData(account) 74 | }, 75 | } -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/controllers/newAccount.js: -------------------------------------------------------------------------------- 1 | let web3 = require("../utils/myUtils").getweb3() 2 | let fs = require("fs") 3 | let path = require("path") 4 | 5 | module.exports = { 6 | //获取创建账号的页面 7 | newAccountHtml: async (ctx) => { 8 | await ctx.render("newaccount.html") 9 | }, 10 | 11 | //创建账户的表单提交被触发的方法 12 | newAccount: async (ctx) => { 13 | console.log("password:", ctx.request.body.password) 14 | 15 | //1.创建钱包账号 16 | let account = web3.eth.accounts.create(ctx.request.body.password) 17 | console.log(account) 18 | 19 | //2.根据账号和密码生成keystore文件 20 | let keystore = account.encrypt(ctx.request.body.password) 21 | console.log(keystore) 22 | 23 | //3.将keysotr保存到文件 24 | let keystoreString = JSON.stringify(keystore) 25 | let time = new Date() 26 | let fileName = 'UTC--'+time.toISOString()+'--'+account.address.slice(2) 27 | console.log(fileName) 28 | let filePath = path.join(__dirname, "../static/keystore", fileName) 29 | fs.writeFileSync(filePath, keystoreString) 30 | 31 | //4.将账号信息返回给客户端 32 | await ctx.render("downloadkeystore.html", { 33 | "downloadurl":"/keystore/"+fileName, 34 | "privatekey":account.privateKey 35 | }) 36 | } 37 | } -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/controllers/transaction.js: -------------------------------------------------------------------------------- 1 | let { success, fail } = require("../utils/myUtils") 2 | let web3 = require("../utils/myUtils").getweb3() 3 | 4 | module.exports = { 5 | transactionHtml: async (ctx) => { 6 | await ctx.render("transaction.html") 7 | }, 8 | 9 | sendTransaction: async (ctx) => { 10 | let { fromaddress, toaddress, number, privatekey } = ctx.request.body 11 | console.log(JSON.stringify(ctx.request.body)) 12 | 13 | let nonce = await web3.eth.getTransactionCount(fromaddress) 14 | let gasPrice = await web3.eth.getGasPrice() 15 | let balance = await web3.utils.toWei(number) 16 | 17 | var rawTx = { 18 | nonce: nonce, 19 | gasPrice: gasPrice, 20 | to: toaddress, 21 | value: balance, 22 | data: '0x00'//转Token代币会用到的一个字段 23 | } 24 | //需要将交易的数据进行预估gas计算,然后将gas值设置到数据参数中 25 | let gas = await web3.eth.estimateGas(rawTx) 26 | rawTx.gas = gas 27 | 28 | var Tx = require('ethereumjs-tx'); 29 | var tx = new Tx(rawTx); 30 | var privateKey = new Buffer(privatekey.slice(2), 'hex') 31 | tx.sign(privateKey); 32 | 33 | var serializedTx = tx.serialize(); 34 | let responseData; 35 | await web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex'), function(err, data) { 36 | console.log(err) 37 | console.log(data) 38 | 39 | if (err) { 40 | responseData = fail(err) 41 | } 42 | }) 43 | .then(function(data) { 44 | console.log(data) 45 | if (data) { 46 | responseData = success({ 47 | "blockHash":data.blockHash, 48 | "transactionHash":data.transactionHash 49 | }) 50 | } else { 51 | responseData = fail("交易失败") 52 | } 53 | }) 54 | 55 | ctx.body = responseData 56 | }, 57 | } -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/index.js: -------------------------------------------------------------------------------- 1 | 2 | let koa = require("koa") 3 | //通过koa创建一个应用程序 4 | let app = new koa() 5 | //导入./router/route这个包,赋值给的router就是 ./router/router导出的数据 6 | let router = require("./router/router") 7 | let static = require("koa-static") 8 | let path = require("path") 9 | let views = require("koa-views") 10 | let koaBody = require("koa-body") 11 | 12 | app.use(async (ctx, next) => { 13 | console.log(`${ctx.method} ${ctx.url} ..........`) 14 | await next() 15 | }) 16 | 17 | //针对于文件上传的时候,可以解析多个字段 18 | app.use(koaBody({multipart:true})) 19 | //注册静态文件的库到中间件 20 | app.use(static(path.join(__dirname, "static"))) 21 | //注册模板引擎的库到中间件 22 | app.use(views(path.join(__dirname, "views"), {extension:"ejs", map:{html:"ejs"}})) 23 | app.use(router.routes()) 24 | 25 | console.log("正在监听3000端口") 26 | app.listen(3000) 27 | -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/models/mnemonic.js: -------------------------------------------------------------------------------- 1 | let bip39 = require('bip39') 2 | let hdkey = require('ethereumjs-wallet/hdkey') 3 | let util = require('ethereumjs-util') 4 | 5 | module.exports = { 6 | getPrivatekeyWithMnemonic: (mnemonic, derivePath) => { 7 | //将助记词转成seed 8 | let seed = bip39.mnemonicToSeed(mnemonic) 9 | //通过hdkey将seed生成HDWallet 10 | let hdWallet = hdkey.fromMasterSeed(seed) 11 | //生成钱包中在m/44'/60'/0'/0/0路径的第一个帐户的keypair。 12 | let key = hdWallet.derivePath(derivePath) 13 | //获取私钥 14 | return util.bufferToHex(key._hdkey._privateKey) 15 | } 16 | } -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "4-wallet", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "bignumber": "^1.1.0", 13 | "ejs": "^2.6.1", 14 | "ethereumjs-tx": "^1.3.7", 15 | "koa": "^2.5.2", 16 | "koa-body": "^4.0.4", 17 | "koa-router": "^7.4.0", 18 | "koa-static": "^5.0.0", 19 | "koa-views": "^6.1.4", 20 | "web3": "^1.0.0-beta.35", 21 | "bip39": "^2.5.0", 22 | "ethereumjs-util": "^5.2.0", 23 | "ethereumjs-wallet": "^0.6.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/router/router.js: -------------------------------------------------------------------------------- 1 | 2 | let router = require("koa-router")() 3 | let newAccountController = require("../controllers/newAccount") 4 | let trasactionConytoller = require("../controllers/transaction") 5 | let accountController = require("../controllers/account") 6 | 7 | 8 | router.get("/", async (ctx) => { 9 | //重定向 10 | ctx.response.redirect("/account/new.html") 11 | }) 12 | 13 | //获取创建钱包账户的页面 14 | router.get("/account/new.html", newAccountController.newAccountHtml) 15 | //提交创建钱包账户的表单 16 | router.post("/account/new", newAccountController.newAccount) 17 | 18 | //获取转账的页面 19 | router.get("/transaction.html", trasactionConytoller.transactionHtml) 20 | //发送转账交易 21 | router.post("/transaction/send", trasactionConytoller.sendTransaction) 22 | 23 | //通过私钥解锁账户 24 | router.post("/unlock/private", accountController.unlockAccountWithPrivate) 25 | //通过keystore解锁账户 26 | router.post("/unlock/keystore", accountController.unlockAccountWithKeystore) 27 | //通过助记词解锁账户 28 | router.post("/unlock/mnemonic", accountController.unlockAccountWithMnemonic) 29 | 30 | module.exports = router 31 | -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/static/css/wallet.css: -------------------------------------------------------------------------------- 1 | 2 | #main{ 3 | /*background-color: #8bc34a;*/ 4 | margin: 100px 50px 50px 50px; 5 | 6 | } 7 | .error{ 8 | color: red; 9 | } 10 | a{ 11 | color: black; 12 | text-decoration: none; 13 | } 14 | a:hover{ 15 | color: #666; 16 | } 17 | body{ 18 | margin: 0px; 19 | } 20 | .global-color{ 21 | color: #0abc9c; 22 | } 23 | a[class=button]{ 24 | background-color: beige; 25 | padding: 2px 10px; 26 | border: 1px solid gray; 27 | } 28 | 29 | /*导航-------------------------------------------------------------------------------------------------------*/ 30 | #nav{ 31 | display: flex; 32 | justify-content: space-between; 33 | background-color: #0abc9c; 34 | position: fixed; 35 | top: 0px; 36 | left: 0px; 37 | right: 0px; 38 | } 39 | #nav li{ 40 | display: inline-block; 41 | margin: 10px 2px; 42 | } 43 | #nav ul{ 44 | padding: 0px; 45 | } 46 | #nav a{ 47 | padding: 10px; 48 | font-size: 24px; 49 | } 50 | #nav-left{ 51 | margin-left: 20px; 52 | } 53 | #nav-right{ 54 | margin-right: 20px; 55 | } 56 | -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/static/html/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/static/js/lib/jquery.url.js: -------------------------------------------------------------------------------- 1 | //cookie 2 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(3(a){4(v 9===\'3\'&&9.G){9([\'H\'],a)}I{a(J)}}(3($){2 m=/\\+/g;3 7(s){5 s}3 w(s){5 K(s.o(m,\' \'))}3 p(s){4(s.L(\'"\')===0){s=s.M(1,-1).o(/\\\\"/g,\'"\').o(/\\\\\\\\/g,\'\\\\\')}N{5 n.x?y.O(s):s}P(Q){}}2 n=$.8=3(a,b,c){4(b!==q){c=$.z({},n.A,c);4(v c.6===\'R\'){2 d=c.6,t=c.6=S T();t.U(t.V()+d)}b=n.x?y.W(b):X(b);5(B.8=[n.7?a:C(a),\'=\',n.7?b:C(b),c.6?\'; 6=\'+c.6.Y():\'\',c.r?\'; r=\'+c.r:\'\',c.u?\'; u=\'+c.u:\'\',c.D?\'; D\':\'\'].E(\'\'))}2 e=n.7?7:w;2 f=B.8.F(\'; \');2 g=a?q:{};Z(2 i=0,l=f.10;i=b&&y<=b+w.height()&&x+t.width()>=a&&x<=a+w.width()){if(!t.appeared)t.trigger('appear',s.data);}else{t.appeared=false;}};var m=function(){t.appeared=true;if(s.one){w.unbind('scroll',c);var i=$.inArray(c,$.fn.appear.checks);if(i>=0)$.fn.appear.checks.splice(i,1);}f.apply(this,arguments);};if(s.one)t.one('appear',s.data,m);else t.bind('appear',s.data,m);w.scroll(c);$.fn.appear.checks.push(c);(c)();});};$.extend($.fn.appear,{checks:[],timeout:null,checkAll:function(){var l=$.fn.appear.checks.length;if(l>0)while(l--)($.fn.appear.checks[l])();},run:function(){if($.fn.appear.timeout)clearTimeout($.fn.appear.timeout);$.fn.appear.timeout=setTimeout($.fn.appear.checkAll,20);}});$.each(['append','prepend','after','before','attr','removeAttr','addClass','removeClass','toggleClass','remove','css','show','hide'],function(i,n){var u=$.fn[n];if(u){$.fn[n]=function(){var r=u.apply(this,arguments);$.fn.appear.run();return r;}}});})(jQuery); 6 | 7 | //url 8 | ;(function($,undefined){var tag2attr={a:'href',img:'src',form:'action',base:'href',script:'src',iframe:'src',link:'href'},key=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","fragment"],aliases={"anchor":"fragment"},parser={strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/},querystring_parser=/(?:^|&|;)([^&=;]*)=?([^&;]*)/g,fragment_parser=/(?:^|&|;)([^&=;]*)=?([^&;]*)/g;function parseUri(url,strictMode){var str=decodeURI(url),res=parser[strictMode||false?"strict":"loose"].exec(str),uri={attr:{},param:{},seg:{}},i=14;while(i--){uri.attr[key[i]]=res[i]||"";}uri.param['query']={};uri.param['fragment']={};uri.attr['query'].replace(querystring_parser,function($0,$1,$2){if($1){uri.param['query'][$1]=$2;}});uri.attr['fragment'].replace(fragment_parser,function($0,$1,$2){if($1){uri.param['fragment'][$1]=$2;}});uri.seg['path']=uri.attr.path.replace(/^\/+|\/+$/g,'').split('/');uri.seg['fragment']=uri.attr.fragment.replace(/^\/+|\/+$/g,'').split('/');uri.attr['base']=uri.attr.host?uri.attr.protocol+"://"+uri.attr.host+(uri.attr.port?":"+uri.attr.port:''):'';return uri;};function getAttrName(elm){var tn=elm.tagName;if(tn!==undefined)return tag2attr[tn.toLowerCase()];return tn;}$.fn.url=function(strictMode){var url='';if(this.length){url=$(this).attr(getAttrName(this[0]))||'';}return $.url(url,strictMode);};$.url=function(url,strictMode){if(arguments.length===1&&url===true){strictMode=true;url=undefined;}strictMode=strictMode||false;url=url||window.location.toString();return{data:parseUri(url,strictMode),attr:function(attr){attr=aliases[attr]||attr;return attr!==undefined?this.data.attr[attr]:this.data.attr;},param:function(param){return param!==undefined?this.data.param.query[param]:this.data.param.query;},fparam:function(param){return param!==undefined?this.data.param.fragment[param]:this.data.param.fragment;},segment:function(seg){if(seg===undefined){return this.data.seg.path;}else{seg=seg<0?this.data.seg.path.length+seg:seg-1;return this.data.seg.path[seg];}},fsegment:function(seg){if(seg===undefined){return this.data.seg.fragment;}else{seg=seg<0?this.data.seg.fragment.length+seg:seg-1;return this.data.seg.fragment[seg];}}};};})(jQuery); 9 | 10 | //jquery form 11 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';(7($){"4j 4k";4 O={};O.2t=$("<1j R=\'2u\'/>").39(0).3a!==1c;O.3b=1d.3c!==1c;$.11.1k=7(z){3(!5.X){Y(\'1k: 4l Z 4m - 4n 4o 1S\');8 5}4 A,1p,16,$9=5;3(1g z==\'7\'){z={17:z}}A=5.18(\'3d\');1p=5.18(\'1p\');16=(1g 1p===\'2v\')?$.4p(1p):\'\';16=16||1d.2w.2x||\'\';3(16){16=(16.4q(/^([^#]+)/)||[])[1]}z=$.2y(1h,{16:16,17:$.1T.17,R:A||\'3e\',22:/^4r/i.1U(1d.2w.2x||\'\')?\'3f:14\':\'4s:4t\'},z);4 B={};5.1e(\'9-2z-3g\',[5,z,B]);3(B.3h){Y(\'1k: Z 3i 23 9-2z-3g 1e\');8 5}3(z.2A&&z.2A(5,z)===14){Y(\'1k: Z 1l 23 2A 2B\');8 5}4 C=z.3j;3(C===1c){C=$.1T.3j}4 D=[];4 E,a=5.2C(z.4u,D);3(z.1a){z.W=z.1a;E=$.1H(z.1a,C)}3(z.2D&&z.2D(a,5,z)===14){Y(\'1k: Z 1l 23 2D 2B\');8 5}5.1e(\'9-Z-3k\',[a,5,z,B]);3(B.3h){Y(\'1k: Z 3i 23 9-Z-3k 1e\');8 5}4 q=$.1H(a,C);3(E){q=(q?(q+\'&\'+E):E)}3(z.R.4v()==\'3e\'){z.16+=(z.16.24(\'?\')>=0?\'&\':\'?\')+q;z.1a=12}P{z.1a=q}4 F=[];3(z.2E){F.V(7(){$9.2E()})}3(z.2F){F.V(7(){$9.2F(z.4w)})}3(!z.1V&&z.1z){4 G=z.17||7(){};F.V(7(a){4 b=z.4x?\'4y\':\'4z\';$(z.1z)[b](a).1A(G,3l)})}P 3(z.17){F.V(z.17)}z.17=7(a,b,c){4 d=z.1i||5;1b(4 i=0,1m=F.X;i<1m;i++){F[i].4A(d,[a,b,c||$9,$9])}};4 H=$(\'1j[R=2u]:4B[S!=""]\',5);4 I=H.X>0;4 J=\'2G/9-1a\';4 K=($9.18(\'3m\')==J||$9.18(\'3n\')==J);4 L=O.2t&&O.3b;Y("4C :"+L);4 M=(I||K)&&!L;4 N;3(z.2H!==14&&(z.2H||M)){3(z.3o){$.39(z.3o,7(){N=2I(a)})}P{N=2I(a)}}P 3((I||K)&&L){N=3p(a)}P{N=$.3q(z)}$9.4D(\'3r\').1a(\'3r\',N);1b(4 k=0;k\');$U.4Z({3A:\'51\',3E:\'-3F\',3G:\'-3F\'})}U=$U[0];6={1l:0,1n:12,1K:12,1f:0,1t:\'n/a\',52:7(){},2L:7(){},53:7(){},1L:7(a){4 e=(a===\'1u\'?\'1u\':\'1l\');Y(\'54 28... \'+e);5.1l=1;3(U.2d.1M.3H){1N{U.2d.1M.3H(\'55\')}1W(56){}}$U.18(\'3D\',s.22);6.19=e;3(s.19)s.19.1q(s.1i,6,e,a);3(g)$.1C.1e("3I",[6,s,e]);3(s.2e)s.2e.1q(s.1i,6,e)}};g=s.3J;3(g&&0===$.2M++){$.1C.1e("57")}3(g){$.1C.1e("58",[6,s])}3(s.29&&s.29.1q(s.1i,6,s)===14){3(s.3J){$.2M--}o.1J();8 o}3(6.1l){o.1J();8 o}1B=l.1v;3(1B){n=1B.Q;3(n&&!1B.1s){s.W=s.W||{};s.W[n]=1B.S;3(1B.R=="1O"){s.W[n+\'.x\']=l.1D;s.W[n+\'.y\']=l.1E}}}4 p=1;4 q=2;7 2N(a){4 b=a.2d?a.2d.1M:a.3K?a.3K:a.1M;8 b}4 r=$(\'3L[Q=3M-59]\').18(\'2f\');4 u=$(\'3L[Q=3M-1H]\').18(\'2f\');3(u&&r){s.W=s.W||{};s.W[u]=r}7 2O(){4 t=$9.18(\'1z\'),a=$9.18(\'1p\');l.1X(\'1z\',1r);3(!A){l.1X(\'3d\',\'3x\')}3(a!=s.16){l.1X(\'1p\',s.16)}3(!s.5a&&(!A||/5b/i.1U(A))){$9.18({3n:\'2G/9-1a\',3m:\'2G/9-1a\'})}3(s.1u){1I=1F(7(){2a=1h;1w(p)},s.1u)}7 2P(){1N{4 a=2N(U).5c;Y(\'5d = \'+a);3(a&&a.1Y()==\'5e\')1F(2P,50)}1W(e){Y(\'5f 1L: \',e,\' (\',e.Q,\')\');1w(q);3(1I)3N(1I);1I=1c}}4 b=[];1N{3(s.W){1b(4 n 3w s.W){3(s.W.27(n)){3($.5g(s.W[n])&&s.W[n].27(\'Q\')&&s.W[n].27(\'S\')){b.V($(\'<1j R="2Q" Q="\'+s.W[n].Q+\'">\').18(\'S\',s.W[n].S).2R(l)[0])}P{b.V($(\'<1j R="2Q" Q="\'+n+\'">\').18(\'S\',s.W[n]).2R(l)[0])}}}}3(!s.2c){$U.2R(\'1P\');3(U.3O)U.3O(\'3P\',1w);P U.5h(\'3Q\',1w,14)}1F(2P,15);l.Z()}5i{l.1X(\'1p\',a);3(t){l.1X(\'1z\',t)}P{$9.3C(\'1z\')}$(b).3R()}}3(s.5j){2O()}P{1F(2O,10)}4 v,13,3S=50,2S;7 1w(e){3(6.1l||2S){8}1N{13=2N(U)}1W(3T){Y(\'5k 5l 5m 1M: \',3T);e=q}3(e===p&&6){6.1L(\'1u\');o.1J(6,\'1u\');8}P 3(e==q&&6){6.1L(\'3U 1L\');o.1J(6,\'19\',\'3U 1L\');8}3(!13||13.2w.2x==s.22){3(!2a)8}3(U.3V)U.3V(\'3P\',1w);P U.5n(\'3Q\',1w,14);4 c=\'17\',1x;1N{3(2a){5o\'1u\';}4 d=s.1V==\'1o\'||13.2T||$.5p(13);Y(\'5q=\'+d);3(!d&&1d.2g&&(13.1P===12||!13.1P.3W)){3(--3S){Y(\'5r 5s 2B, 2U 2b 5t\');1F(1w,5u);8}}4 f=13.1P?13.1P:13.2h;6.1n=f?f.3W:12;6.1K=13.2T?13.2T:13;3(d)s.1V=\'1o\';6.2L=7(a){4 b={\'2f-R\':s.1V};8 b[a]};3(f){6.1f=3X(f.2i(\'1f\'))||6.1f;6.1t=f.2i(\'1t\')||6.1t}4 h=(s.1V||\'\').1Y();4 i=/(2V|3Y|2j)/.1U(h);3(i||s.2k){4 j=13.2l(\'2k\')[0];3(j){6.1n=j.S;6.1f=3X(j.2i(\'1f\'))||6.1f;6.1t=j.2i(\'1t\')||6.1t}P 3(i){4 k=13.2l(\'2z\')[0];4 b=13.2l(\'1P\')[0];3(k){6.1n=k.2m?k.2m:k.3Z}P 3(b){6.1n=b.2m?b.2m:b.3Z}}}P 3(h==\'1o\'&&!6.1K&&6.1n){6.1K=w(6.1n)}1N{v=y(6,h,s)}1W(e){c=\'2n\';6.19=1x=(e||c)}}1W(e){Y(\'19 5v: \',e);c=\'19\';6.19=1x=(e||c)}3(6.1l){Y(\'28 1l\');c=12}3(6.1f){c=(6.1f>=5w&&6.1f<5x||6.1f===5y)?\'17\':\'19\'}3(c===\'17\'){3(s.17)s.17.1q(s.1i,v,\'17\',6);o.5z(6.1n,\'17\',6);3(g)$.1C.1e("5A",[6,s])}P 3(c){3(1x===1c)1x=6.1t;3(s.19)s.19.1q(s.1i,6,c,1x);o.1J(6,\'19\',1x);3(g)$.1C.1e("3I",[6,s,1x])}3(g)$.1C.1e("5B",[6,s]);3(g&&!--$.2M){$.1C.1e("5C")}3(s.2e)s.2e.1q(s.1i,6,c);2S=1h;3(s.1u)3N(1I);1F(7(){3(!s.2c)$U.3R();6.1K=12},2J)}4 w=$.5D||7(s,a){3(1d.40){a=26 40(\'5E.5F\');a.5G=\'14\';a.5H(s)}P{a=(26 5I()).5J(s,\'2j/1o\')}8(a&&a.2h&&a.2h.41!=\'2n\')?a:12};4 x=$.5K||7(s){8 1d[\'5L\'](\'(\'+s+\')\')};4 y=7(a,b,s){4 c=a.2L(\'2f-R\')||\'\',1o=b===\'1o\'||!b&&c.24(\'1o\')>=0,v=1o?a.1K:a.1n;3(1o&&v.2h.41===\'2n\'){3($.19)$.19(\'2n\')}3(s&&s.42){v=s.42(v,b)}3(1g v===\'2v\'){3(b===\'2V\'||!b&&c.24(\'2V\')>=0){v=x(v)}P 3(b==="3Y"||!b&&c.24("3f")>=0){$.5M(v)}}8 v};8 o}};$.11.2W=7(a){a=a||{};a.2o=a.2o&&$.5N($.11.2X);3(!a.2o&&5.X===0){4 o={s:5.1Q,c:5.1i};3(!$.43&&o.s){Y(\'2U 2b 44, 5O 2W\');$(7(){$(o.s,o.c).2W(a)});8 5}Y(\'5P; 5Q 2K 5R 5S 1Q\'+($.43?\'\':\' (2U 2b 44)\'));8 5}3(a.2o){$(1M).45(\'Z.9-1y\',5.1Q,2p).45(\'2q.9-1y\',5.1Q,2r).2X(\'Z.9-1y\',5.1Q,a,2p).2X(\'2q.9-1y\',5.1Q,a,2r);8 5}8 5.46().47(\'Z.9-1y\',a,2p).47(\'2q.9-1y\',a,2r)};7 2p(e){4 a=e.1a;3(!e.5T()){e.5U();$(5).1k(a)}}7 2r(e){4 a=e.1z;4 b=$(a);3(!(b.48("[R=Z],[R=1O]"))){4 t=b.5V(\'[R=Z]\');3(t.X===0){8}a=t[0]}4 c=5;c.1v=a;3(a.R==\'1O\'){3(e.49!==1c){c.1D=e.49;c.1E=e.5W}P 3(1g $.11.4a==\'7\'){4 d=b.4a();c.1D=e.4b-d.3G;c.1E=e.4c-d.3E}P{c.1D=e.4b-a.5X;c.1E=e.4c-a.5Y}}1F(7(){c.1v=c.1D=c.1E=12},2J)}$.11.46=7(){8 5.5Z(\'Z.9-1y 2q.9-1y\')};$.11.2C=7(b,c){4 a=[];3(5.X===0){8 a}4 d=5[0];4 e=b?d.2l(\'*\'):d.2K;3(!e){8 a}4 i,j,n,v,T,1m,2Y;1b(i=0,1m=e.X;i<1m;i++){T=e[i];n=T.Q;3(!n){2Z}3(b&&d.1v&&T.R=="1O"){3(!T.1s&&d.1v==T){a.V({Q:n,S:$(T).30(),R:T.R});a.V({Q:n+\'.x\',S:d.1D},{Q:n+\'.y\',S:d.1E})}2Z}v=$.1Z(T,1h);3(v&&v.2s==20){3(c)c.V(T);1b(j=0,2Y=v.X;j<2Y;j++){a.V({Q:n,S:v[j]})}}P 3(O.2t&&T.R==\'2u\'&&!T.1s){3(c)c.V(T);4 f=T.3a;3(f.X){1b(j=0;j35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(7($){$.J($.2F,{1c:7(c){8(!6.G){8(c&&c.29&&2G.1x){1x.4x("4y 3l, 4z\'t 1c, 4A 4B.")}l}p d=$.11(6[0],"v");8(d){l d}6.12("3m","3m");d=2H $.v(c,6[0]);$.11(6[0],"v",d);8(d.q.3n){6.2a(":2b","3o",7(a){8(d.q.2I){d.1P=a.2c}8($(a.2c).4C("4D")){d.2d=w}8($(a.2c).12("4E")!==1l){d.2d=w}});6.2b(7(b){8(d.q.29){b.4F()}7 2J(){p a;8(d.q.2I){8(d.1P){a=$("<2e F=\'3p\'/>").12("u",d.1P.u).W($(d.1P).W()).4G(d.X)}d.q.2I.16(d,d.X,b);8(d.1P){a.3q()}l K}l w}8(d.2d){d.2d=K;l 2J()}8(d.P()){8(d.1g){d.1m=w;l K}l 2J()}H{d.2f();l K}})}l d},L:7(){8($(6[0]).2K("P")){l 6.1c().P()}H{p a=w;p b=$(6[0].P).1c();6.U(7(){a=a&&b.I(6)});l a}},4H:7(c){p d={},$I=6;$.U(c.1y(/\\s/),7(a,b){d[b]=$I.12(b);$I.4I(b)});l d},13:7(c,d){p e=6[0];8(c){p f=$.11(e.P,"v").q;p g=f.13;p h=$.v.2L(e);2M(c){1z"1n":$.J(h,$.v.1Q(d));Q h.M;g[e.u]=h;8(d.M){f.M[e.u]=$.J(f.M[e.u],d.M)}2N;1z"3q":8(!d){Q g[e.u];l h}p i={};$.U(d.1y(/\\s/),7(a,b){i[b]=h[b];Q h[b]});l i}}p j=$.v.3r($.J({},$.v.3s(e),$.v.3t(e),$.v.3u(e),$.v.2L(e)),e);8(j.14){p k=j.14;Q j.14;j=$.J({14:k},j)}l j}});$.J($.4J[":"],{4K:7(a){l!$.1A(""+$(a).W())},4L:7(a){l!!$.1A(""+$(a).W())},4M:7(a){l!$(a).4N("2O")}});$.v=7(a,b){6.q=$.J(w,{},$.v.2P,a);6.X=b;6.3v()};$.v.15=7(b,c){8(17.G===1){l 7(){p a=$.3w(17);a.4O(b);l $.v.15.2g(6,a)}}8(17.G>2&&c.2h!==3x){c=$.3w(17).4P(1)}8(c.2h!==3x){c=[c]}$.U(c,7(i,n){b=b.1B(2H 4Q("\\\\{"+i+"\\\\}","g"),7(){l n})});l b};$.J($.v,{2P:{M:{},2i:{},13:{},1h:"3y",1R:"L",2Q:"4R",2f:w,3z:$([]),2R:$([]),3n:w,2S:":3p",3A:K,4S:7(a,b){6.3B=a;8(6.q.4T&&!6.4U){8(6.q.1S){6.q.1S.16(6,a,6.q.1h,6.q.1R)}6.2j(6.1T(a)).2T()}},3C:7(a,b){8(!6.1C(a)&&(a.u R 6.1i||!6.N(a))){6.I(a)}},4V:7(a,b){8(b.4W===9&&6.2k(a)===""){l}H 8(a.u R 6.1i||a===6.2U){6.I(a)}},4X:7(a,b){8(a.u R 6.1i){6.I(a)}H 8(a.3D.u R 6.1i){6.I(a.3D)}},2V:7(a,b,c){8(a.F==="1U"){6.1D(a.u).1o(b).1E(c)}H{$(a).1o(b).1E(c)}},1S:7(a,b,c){8(a.F==="1U"){6.1D(a.u).1E(b).1o(c)}H{$(a).1E(b).1o(c)}}},4Y:7(a){$.J($.v.2P,a)},M:{14:"4Z 3E 2K 14.",1p:"O 50 6 3E.",1F:"O S a L 1F 51.",1q:"O S a L 52.",1r:"O S a L 1r.",2l:"O S a L 1r (53).",1j:"O S a L 1j.",1V:"O S 54 1V.",2m:"O S a L 55 56 1j.",2n:"O S 3F 57 1d 58.",1e:$.v.15("O S 3G 59 2W {0} 2X."),1G:$.v.15("O S 5a 5b {0} 2X."),2o:$.v.15("O S a 1d 3H {0} 3I {1} 2X 5c."),1s:$.v.15("O S a 1d 3H {0} 3I {1}."),1H:$.v.15("O S a 1d 5d 2W 3J 3K 3L {0}."),1I:$.v.15("O S a 1d 5e 2W 3J 3K 3L {0}.")},3M:K,5f:{3v:7(){6.2p=$(6.q.2R);6.3N=6.2p.G&&6.2p||$(6.X);6.2q=$(6.q.3z).1n(6.q.2R);6.1i={};6.5g={};6.1g=0;6.1J={};6.18={};6.1W();p e=(6.2i={});$.U(6.q.2i,7(c,d){8(19 d==="1k"){d=d.1y(/\\s/)}$.U(d,7(a,b){e[b]=c})});p f=6.q.13;$.U(f,7(a,b){f[a]=$.v.1Q(b)});7 2Y(a){p b=$.11(6[0].P,"v"),2Z="5h"+a.F.1B(/^1c/,"");8(b.q[2Z]){b.q[2Z].16(b,6[0],a)}}$(6.X).2a(":30, [F=\'5i\'], [F=\'5j\'], 1X, 3O, "+"[F=\'1j\'], [F=\'5k\'] ,[F=\'5l\'], [F=\'1q\'], "+"[F=\'1F\'], [F=\'3P\'], [F=\'1r\'], [F=\'5m\'], "+"[F=\'5n\'], [F=\'5o\'], [F=\'3P-5p\'], "+"[F=\'1s\'], [F=\'5q\'] ","3Q 5r 5s",2Y).2a("[F=\'1U\'], [F=\'31\'], 1X, 3R","3o",2Y);8(6.q.3S){$(6.X).32("18-P.1c",6.q.3S)}},P:7(){6.3T();$.J(6.1i,6.1K);6.18=$.J({},6.1K);8(!6.L()){$(6.X).3U("18-P",[6])}6.1t();l 6.L()},3T:7(){6.33();T(p i=0,1a=(6.2r=6.1a());1a[i];i++){6.2s(1a[i])}l 6.L()},I:7(a){a=6.34(6.35(a));6.2U=a;6.36(a);6.2r=$(a);p b=6.2s(a)!==K;8(b){Q 6.18[a.u]}H{6.18[a.u]=w}8(!6.3V()){6.1b=6.1b.1n(6.2q)}6.1t();l b},1t:7(b){8(b){$.J(6.1K,b);6.V=[];T(p c R b){6.V.2t({1u:b[c],I:6.1D(c)[0]})}6.1v=$.3W(6.1v,7(a){l!(a.u R b)})}8(6.q.1t){6.q.1t.16(6,6.1K,6.V)}H{6.3X()}},37:7(){8($.2F.37){$(6.X).37()}6.1i={};6.2U=38;6.33();6.39();6.1a().1E(6.q.1h).5t("1Y")},3V:7(){l 6.2u(6.18)},2u:7(a){p b=0;T(p i R a){b++}l b},39:7(){6.2j(6.1b).2T()},L:7(){l 6.3Y()===0},3Y:7(){l 6.V.G},2f:7(){8(6.q.2f){3Z{$(6.40()||6.V.G&&6.V[0].I||[]).2v(":5u").5v().5w("3Q")}41(e){}}},40:7(){p a=6.3B;l a&&$.3W(6.V,7(n){l n.I.u===a.u}).G===1&&a},1a:7(){p a=6,3a={};l $(6.X).42("2e, 1X, 3O").1L(":2b, :1W, :5x, [5y]").1L(6.q.2S).2v(7(){8(!6.u&&a.q.29&&2G.1x){1x.3y("%o 5z 3G u 5A",6)}8(6.u R 3a||!a.2u($(6).13())){l K}3a[6.u]=w;l w})},35:7(a){l $(a)[0]},3b:7(){p a=6.q.1h.1B(" ",".");l $(6.q.2Q+"."+a,6.3N)},1W:7(){6.1v=[];6.V=[];6.1K={};6.1w=$([]);6.1b=$([]);6.2r=$([])},33:7(){6.1W();6.1b=6.3b().1n(6.2q)},36:7(a){6.1W();6.1b=6.1T(a)},2k:7(a){p b=$(a).12("F"),W=$(a).W();8(b==="1U"||b==="31"){l $("2e[u=\'"+$(a).12("u")+"\']:2O").W()}8(19 W==="1k"){l W.1B(/\\r/g,"")}l W},2s:7(a){a=6.34(6.35(a));p b=$(a).13();p c=K;p d=6.2k(a);p f;T(p g R b){p h={2w:g,2x:b[g]};3Z{f=$.v.1M[g].16(6,d,a,h.2x);8(f==="1Z-20"){c=w;5B}c=K;8(f==="1J"){6.1b=6.1b.1L(6.1T(a));l}8(!f){6.43(a,h);l K}}41(e){8(6.q.29&&2G.1x){1x.5C("5D 5E 5F 5G I "+a.44+", 2s 3F \'"+h.2w+"\' 2w.",e)}5H e;}}8(c){l}8(6.2u(b)){6.1v.2t(a)}l w},45:7(a,b){l $(a).11("46-"+b.21())||(a.5I&&$(a).12("11-46-"+b.21()))},47:7(a,b){p m=6.q.M[a];l m&&(m.2h===48?m:m[b])},49:7(){T(p i=0;i<17.G;i++){8(17[i]!==1l){l 17[i]}}l 1l},2y:7(a,b){l 6.49(6.47(a.u,b),6.45(a,b),!6.q.3A&&a.5J||1l,$.v.M[b],"<4a>5K: 5L 1u 5M T "+a.u+"")},43:7(a,b){p c=6.2y(a,b.2w),3c=/\\$?\\{(\\d+)\\}/g;8(19 c==="7"){c=c.16(6,b.2x,a)}H 8(3c.Y(c)){c=$.v.15(c.1B(3c,"{$1}"),b.2x)}6.V.2t({1u:c,I:a});6.1K[a.u]=c;6.1i[a.u]=c},2j:7(a){8(6.q.2z){a=a.1n(a.4b(6.q.2z))}l a},3X:7(){p i,1a;T(i=0;6.V[i];i++){p a=6.V[i];8(6.q.2V){6.q.2V.16(6,a.I,6.q.1h,6.q.1R)}6.3d(a.I,a.1u)}8(6.V.G){6.1w=6.1w.1n(6.2q)}8(6.q.1N){T(i=0;6.1v[i];i++){6.3d(6.1v[i])}}8(6.q.1S){T(i=0,1a=6.4c();1a[i];i++){6.q.1S.16(6,1a[i],6.q.1h,6.q.1R)}}6.1b=6.1b.1L(6.1w);6.39();6.2j(6.1w).4d()},4c:7(){l 6.2r.1L(6.4e())},4e:7(){l $(6.V).5N(7(){l 6.I})},3d:7(a,b){p c=6.1T(a);8(c.G){c.1E(6.q.1R).1o(6.q.1h);c.4f(b)}H{c=$("<"+6.q.2Q+">").12("T",6.3e(a)).1o(6.q.1h).4f(b||"");8(6.q.2z){c=c.2T().4d().5O("<"+6.q.2z+"/>").4b()}8(!6.2p.5P(c).G){8(6.q.4g){6.q.4g(c,$(a))}H{c.5Q(a)}}}8(!b&&6.q.1N){c.30("");8(19 6.q.1N==="1k"){c.1o(6.q.1N)}H{6.q.1N(c,a)}}6.1w=6.1w.1n(c)},1T:7(a){p b=6.3e(a);l 6.3b().2v(7(){l $(6).12("T")===b})},3e:7(a){l 6.2i[a.u]||(6.1C(a)?a.u:a.44||a.u)},34:7(a){8(6.1C(a)){a=6.1D(a.u).1L(6.q.2S)[0]}l a},1C:7(a){l(/1U|31/i).Y(a.F)},1D:7(a){l $(6.X).42("[u=\'"+a+"\']")},22:7(a,b){2M(b.4h.21()){1z"1X":l $("3R:3l",b).G;1z"2e":8(6.1C(b)){l 6.1D(b.u).2v(":2O").G}}l a.G},4i:7(a,b){l 6.3f[19 a]?6.3f[19 a](a,b):w},3f:{"5R":7(a,b){l a},"1k":7(a,b){l!!$(a,b.P).G},"7":7(a,b){l a(b)}},N:7(a){p b=6.2k(a);l!$.v.1M.14.16(6,b,a)&&"1Z-20"},4j:7(a){8(!6.1J[a.u]){6.1g++;6.1J[a.u]=w}},4k:7(a,b){6.1g--;8(6.1g<0){6.1g=0}Q 6.1J[a.u];8(b&&6.1g===0&&6.1m&&6.P()){$(6.X).2b();6.1m=K}H 8(!b&&6.1g===0&&6.1m){$(6.X).3U("18-P",[6]);6.1m=K}},1Y:7(a){l $.11(a,"1Y")||$.11(a,"1Y",{3g:38,L:w,1u:6.2y(a,"1p")})}},23:{14:{14:w},1F:{1F:w},1q:{1q:w},1r:{1r:w},2l:{2l:w},1j:{1j:w},1V:{1V:w},2m:{2m:w}},4l:7(a,b){8(a.2h===48){6.23[a]=b}H{$.J(6.23,a)}},3s:7(a){p b={};p c=$(a).12("5S");8(c){$.U(c.1y(" "),7(){8(6 R $.v.23){$.J(b,$.v.23[6])}})}l b},3t:7(a){p b={};p c=$(a);p d=c[0].4m("F");T(p e R $.v.1M){p f;8(e==="14"){f=c.5T(0).4m(e);8(f===""){f=w}f=!!f}H{f=c.12(e)}8(/1I|1H/.Y(e)&&(d===38||/1j|1s|30/.Y(d))){f=1O(f)}8(f){b[e]=f}H 8(d===e&&d!==\'1s\'){b[e]=w}}8(b.1e&&/-1|5U|5V/.Y(b.1e)){Q b.1e}l b},3u:7(a){p b,1d,13={},$I=$(a);T(b R $.v.1M){1d=$I.11("5W-"+b.21());8(1d!==1l){13[b]=1d}}l 13},2L:7(a){p b={};p c=$.11(a.P,"v");8(c.q.13){b=$.v.1Q(c.q.13[a.u])||{}}l b},3r:7(d,e){$.U(d,7(a,b){8(b===K){Q d[a];l}8(b.3h||b.2A){p c=w;2M(19 b.2A){1z"1k":c=!!$(b.2A,e.P).G;2N;1z"7":c=b.2A.16(e,e);2N}8(c){d[a]=b.3h!==1l?b.3h:w}H{Q d[a]}}});$.U(d,7(a,b){d[a]=$.4n(b)?b(e):b});$.U([\'1G\',\'1e\'],7(){8(d[6]){d[6]=1O(d[6])}});$.U([\'2o\',\'1s\'],7(){p a;8(d[6]){8($.2B(d[6])){d[6]=[1O(d[6][0]),1O(d[6][1])]}H 8(19 d[6]==="1k"){a=d[6].1y(/[\\s,]+/);d[6]=[1O(a[0]),1O(a[1])]}}});8($.v.3M){8(d.1I&&d.1H){d.1s=[d.1I,d.1H];Q d.1I;Q d.1H}8(d.1G&&d.1e){d.2o=[d.1G,d.1e];Q d.1G;Q d.1e}}l d},1Q:7(a){8(19 a==="1k"){p b={};$.U(a.1y(/\\s/),7(){b[6]=w});a=b}l a},5X:7(a,b,c){$.v.1M[a]=b;$.v.M[a]=c!==1l?c:$.v.M[a];8(b.G<3){$.v.4l(a,$.v.1Q(a))}},1M:{14:7(a,b,c){8(!6.4i(c,b)){l"1Z-20"}8(b.4h.21()==="1X"){p d=$(b).W();l d&&d.G>0}8(6.1C(b)){l 6.22(a,b)>0}l $.1A(a).G>0},1F:7(a,b){l 6.N(b)||/^((([a-z]|\\d|[!#\\$%&\'\\*\\+\\-\\/=\\?\\^Z`{\\|}~]|[\\x-\\y\\A-\\B\\C-\\E])+(\\.([a-z]|\\d|[!#\\$%&\'\\*\\+\\-\\/=\\?\\^Z`{\\|}~]|[\\x-\\y\\A-\\B\\C-\\E])+)*)|((\\4o)((((\\2C|\\24)*(\\3i\\4p))?(\\2C|\\24)+)?(([\\4q-\\5Y\\4r\\4s\\5Z-\\60\\4t]|\\61|[\\62-\\63]|[\\64-\\65]|[\\x-\\y\\A-\\B\\C-\\E])|(\\\\([\\4q-\\24\\4r\\4s\\3i-\\4t]|[\\x-\\y\\A-\\B\\C-\\E]))))*(((\\2C|\\24)*(\\3i\\4p))?(\\2C|\\24)+)?(\\4o)))@((([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])|(([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])*([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])))\\.)+(([a-z]|[\\x-\\y\\A-\\B\\C-\\E])|(([a-z]|[\\x-\\y\\A-\\B\\C-\\E])([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])*([a-z]|[\\x-\\y\\A-\\B\\C-\\E])))$/i.Y(a)},1q:7(a,b){l 6.N(b)||/^(66?|s?67):\\/\\/(((([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|((([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])|(([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])*([a-z]|\\d|[\\x-\\y\\A-\\B\\C-\\E])))\\.)+(([a-z]|[\\x-\\y\\A-\\B\\C-\\E])|(([a-z]|[\\x-\\y\\A-\\B\\C-\\E])([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])*([a-z]|[\\x-\\y\\A-\\B\\C-\\E])))\\.?)(:\\d*)?)(\\/((([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:|@)+(\\/(([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:|@)|[\\68-\\69]|\\/|\\?)*)?(#((([a-z]|\\d|-|\\.|Z|~|[\\x-\\y\\A-\\B\\C-\\E])|(%[\\26-f]{2})|[!\\$&\'\\(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$/i.Y(a)},1r:7(a,b){l 6.N(b)||!/6a|6b/.Y(2H 6c(a).6d())},2l:7(a,b){l 6.N(b)||/^\\d{4}[\\/\\-]\\d{1,2}[\\/\\-]\\d{1,2}$/.Y(a)},1j:7(a,b){l 6.N(b)||/^-?(?:\\d+|\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$/.Y(a)},1V:7(a,b){l 6.N(b)||/^\\d+$/.Y(a)},2m:7(a,b){8(6.N(b)){l"1Z-20"}8(/[^0-9 \\-]+/.Y(a)){l K}p c=0,27=0,2D=K;a=a.1B(/\\D/g,"");T(p n=a.G-1;n>=0;n--){p d=a.6e(n);27=6f(d,10);8(2D){8((27*=2)>9){27-=9}}c+=27;2D=!2D}l(c%10)===0},1G:7(a,b,c){p d=$.2B(a)?a.G:6.22($.1A(a),b);l 6.N(b)||d>=c},1e:7(a,b,c){p d=$.2B(a)?a.G:6.22($.1A(a),b);l 6.N(b)||d<=c},2o:7(a,b,c){p d=$.2B(a)?a.G:6.22($.1A(a),b);l 6.N(b)||(d>=c[0]&&d<=c[1])},1I:7(a,b,c){l 6.N(b)||a>=c},1H:7(a,b,c){l 6.N(b)||a<=c},1s:7(a,b,c){l 6.N(b)||(a>=c[0]&&a<=c[1])},2n:7(a,b,c){p d=$(c);8(6.q.3C){d.6g(".1c-2n").32("6h.1c-2n",7(){$(b).L()})}l a===d.W()},1p:7(f,g,h){8(6.N(g)){l"1Z-20"}p i=6.1Y(g);8(!6.q.M[g.u]){6.q.M[g.u]={}}i.4u=6.q.M[g.u].1p;6.q.M[g.u].1p=i.1u;h=19 h==="1k"&&{1q:h}||h;8(i.3g===f){l i.L}i.3g=f;p j=6;6.4j(g);p k={};k[g.u]=f;$.3j($.J(w,{1q:h,2E:"28",1f:"1c"+g.u,6i:"6j",11:k,1N:7(a){j.q.M[g.u].1p=i.4u;p b=a===w||a==="w";8(b){p c=j.1m;j.36(g);j.1m=c;j.1v.2t(g);Q j.18[g.u];j.1t()}H{p d={};p e=a||j.2y(g,"1p");d[g.u]=i.1u=$.4n(e)?e(f):e;j.18[g.u]=w;j.1t(d)}i.L=b;j.4k(g,b)}},h));l"1J"}}});$.15=$.v.15}(3k));(7($){p d={};8($.4v){$.4v(7(a,Z,b){p c=a.1f;8(a.2E==="28"){8(d[c]){d[c].28()}d[c]=b}})}H{p e=$.3j;$.3j=7(a){p b=("2E"R a?a:$.4w).2E,1f=("1f"R a?a:$.4w).1f;8(b==="28"){8(d[1f]){d[1f].28()}d[1f]=e.2g(6,17);l d[1f]}l e.2g(6,17)}}}(3k));(7($){$.J($.2F,{2a:7(c,d,e){l 6.32(d,7(a){p b=$(a.2c);8(b.2K(c)){l e.2g(b,17)}})}})}(3k));',62,392,'||||||this|function|if|||||||||||||return||||var|settings||||name|validator|true|u00A0|uD7FF||uF900|uFDCF|uFDF0||uFFEF|type|length|else|element|extend|false|valid|messages|optional|Please|form|delete|in|enter|for|each|errorList|val|currentForm|test|_||data|attr|rules|required|format|call|arguments|invalid|typeof|elements|toHide|validate|value|maxlength|port|pendingRequest|errorClass|submitted|number|string|undefined|formSubmitted|add|addClass|remote|url|date|range|showErrors|message|successList|toShow|console|split|case|trim|replace|checkable|findByName|removeClass|email|minlength|max|min|pending|errorMap|not|methods|success|Number|submitButton|normalizeRule|validClass|unhighlight|errorsFor|radio|digits|reset|select|previousValue|dependency|mismatch|toLowerCase|getLength|classRuleSettings|x09||da|nDigit|abort|debug|validateDelegate|submit|target|cancelSubmit|input|focusInvalid|apply|constructor|groups|addWrapper|elementValue|dateISO|creditcard|equalTo|rangelength|labelContainer|containers|currentElements|check|push|objectLength|filter|method|parameters|defaultMessage|wrapper|depends|isArray|x20|bEven|mode|fn|window|new|submitHandler|handle|is|staticRules|switch|break|checked|defaults|errorElement|errorLabelContainer|ignore|hide|lastElement|highlight|than|characters|delegate|eventType|text|checkbox|bind|prepareForm|validationTargetFor|clean|prepareElement|resetForm|null|hideErrors|rulesCache|errors|theregex|showLabel|idOrName|dependTypes|old|param|x0d|ajax|jQuery|selected|novalidate|onsubmit|click|hidden|remove|normalizeRules|classRules|attributeRules|dataRules|init|makeArray|Array|error|errorContainer|ignoreTitle|lastActive|onfocusout|parentNode|field|the|no|between|and|or|equal|to|autoCreateRanges|errorContext|textarea|datetime|focusin|option|invalidHandler|checkForm|triggerHandler|numberOfInvalids|grep|defaultShowErrors|size|try|findLastActive|catch|find|formatAndAdd|id|customDataMessage|msg|customMessage|String|findDefined|strong|parent|validElements|show|invalidElements|html|errorPlacement|nodeName|depend|startRequest|stopRequest|addClassRules|getAttribute|isFunction|x22|x0a|x01|x0b|x0c|x7f|originalMessage|ajaxPrefilter|ajaxSettings|warn|Nothing|can|returning|nothing|hasClass|cancel|formnovalidate|preventDefault|appendTo|removeAttrs|removeAttr|expr|blank|filled|unchecked|prop|unshift|slice|RegExp|label|onfocusin|focusCleanup|blockFocusCleanup|onkeyup|which|onclick|setDefaults|This|fix|address|URL|ISO|only|credit|card|same|again|more|at|least|long|less|greater|prototype|valueCache|on|password|mysql|search|tel|month|week|time|local|color|focusout|keyup|removeData|visible|focus|trigger|image|disabled|has|assigned|continue|log|Exception|occurred|when|checking|throw|attributes|title|Warning|No|defined|map|wrap|append|insertAfter|boolean|class|get|2147483647|524288|rule|addMethod|x08|x0e|x1f|x21|x23|x5b|x5d|x7e|https|ftp|uE000|uF8FF|Invalid|NaN|Date|toString|charAt|parseInt|unbind|blur|dataType|json'.split('|'),0,{})); 15 | -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/static/js/wallet.js: -------------------------------------------------------------------------------- 1 | 2 | function saveKeystoreNext() { 3 | $("#save-keystore").hide() 4 | $("#save-privatekey").show() 5 | } 6 | 7 | //通过私钥解锁账户 8 | function unlockAccountWithPrivatekey() { 9 | let privatekey = $("#input-privatekey").val() 10 | console.log(privatekey) 11 | $.post("/unlock/private", `privatekey=${privatekey}`, function (res, status) { 12 | console.log(status + JSON.stringify(res)) 13 | if (res.code == 0) { 14 | //将服务端返回的账户信息显示到页面 15 | configAccountInfo(res.data) 16 | } 17 | }) 18 | } 19 | 20 | //通过Keystore解锁账户 21 | function unlockAccountWithKeystore() { 22 | var filedata = $("#unlock-accoutn-file").val() 23 | if (filedata.length <= 0) { 24 | alert("请选择文件!") 25 | return 26 | } 27 | //文件上传通过Formdata去储存文件的数据 28 | var data = new FormData() 29 | data.append("file", $("#unlock-accoutn-file")[0].files[0]) 30 | data.append("password", $("#unlock-account-password").val()) 31 | var urlStr = "/unlock/keystore" 32 | $.ajax({ 33 | url: urlStr, 34 | type: "post", 35 | dataType: "json", 36 | contentType: false, 37 | data: data, 38 | processData: false, 39 | success: function (res, status) { 40 | console.log(status + JSON.stringify(res)) 41 | if (res.code == 0) { 42 | //将服务端返回的账户信息显示到页面 43 | configAccountInfo(res.data) 44 | } 45 | }, 46 | error: function (res, status) { 47 | alert(JSON.stringify(res)+status) 48 | } 49 | }) 50 | } 51 | 52 | //通过助记词解锁账户 53 | function unlockAccountWithMnemonic() { 54 | let mnemonic = $("#input-mnemonic").val() 55 | console.log(mnemonic) 56 | $.post("/unlock/mnemonic", `mnemonic=${mnemonic}`, function (res, status) { 57 | console.log(status + JSON.stringify(res)) 58 | if (res.code == 0) { 59 | //将服务端返回的账户信息显示到页面 60 | configAccountInfo(res.data) 61 | } 62 | }) 63 | } 64 | 65 | //解锁成功后给账户设置数据 66 | function configAccountInfo(data) { 67 | $("#account-address").text(data.address) 68 | $("#account-balance").text(data.balance + " ETH") 69 | 70 | $("#transaction-first").hide() 71 | $("#transaction-second").show() 72 | 73 | $("input[name=fromaddress]").val(data.address) 74 | $("input[name=privatekey]").val(data.privatekey) 75 | } 76 | 77 | $(document).ready(function () { 78 | //改变了解锁账号的方式 79 | $("input[name=unlocktype]").change(function () { 80 | if (this.value == 1) { 81 | $("#unlock-account-privatekey").show() 82 | $("#unlock-account-keystore").hide() 83 | $("#unlock-account-mnemonic").hide() 84 | } else if (this.value == 2) { 85 | $("#unlock-account-privatekey").hide() 86 | $("#unlock-account-keystore").show() 87 | $("#unlock-account-mnemonic").hide() 88 | } else { 89 | $("#unlock-account-privatekey").hide() 90 | $("#unlock-account-keystore").hide() 91 | $("#unlock-account-mnemonic").show() 92 | } 93 | }) 94 | 95 | //转账 96 | $("#send-transaction-form").validate({ 97 | rules:{ 98 | toaddress:{ 99 | required: true, 100 | }, 101 | number:{ 102 | required:true, 103 | }, 104 | }, 105 | messages:{ 106 | toaddress:{ 107 | required:"请输入对方地址", 108 | }, 109 | number:{ 110 | required:"请输入转账数额" 111 | }, 112 | }, 113 | submitHandler: function(form) 114 | { 115 | var urlStr 116 | let tokenType = $("#send-transaction-token-type").val() 117 | if (tokenType == 1) { 118 | urlStr = "/transaction/send" 119 | } else { 120 | urlStr = "/token/send" 121 | } 122 | 123 | $(form).ajaxSubmit({ 124 | url:urlStr, 125 | type:"post", 126 | dataType:"json", 127 | success:function (res, status) { 128 | console.log(status + JSON.stringify(res)) 129 | if (res.code == 0) { 130 | $("#transaction-complate-hash").text(res.data.transactionHash) 131 | $("#transaction-complate").show() 132 | } 133 | }, 134 | error:function (res, status) { 135 | console.log(status + JSON.stringify(res)) 136 | } 137 | }); 138 | } 139 | }) 140 | }) -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/static/keystore/UTC--2018-09-25T06:24:28.689Z--42f971FC3443B43313441E68f7548b3BD0713dB9: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"a3b41a93-4812-4651-a5e7-f869f1c1c81a","address":"42f971fc3443b43313441e68f7548b3bd0713db9","crypto":{"ciphertext":"1b878fd78042a1aac1e1404c886eb823c29052599432c8a19840b8aa23c976ff","cipherparams":{"iv":"a261b97eca4c487d0f149f554e8d0767"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"04603dddcd4dc7f740f4f0d5ffc38277d0dc7f5180c235a1f26ab314bf4df413","n":8192,"r":8,"p":1},"mac":"7511195ae4a6f154b692e02739199b717ed9ed6f973d8de206fea6ea66ac829c"}} -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/static/keystore/UTC--2018-09-25T06:33:18.858Z--709b7348Cb70D65b9C65C0c884B2bF7e02f5B939: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"b3348a71-cfee-445a-b06b-f15c7a989e05","address":"709b7348cb70d65b9c65c0c884b2bf7e02f5b939","crypto":{"ciphertext":"4f666348cf7083c5b66499493a230f3c264a313e36fe7b4c20bc8a574c9598dd","cipherparams":{"iv":"df4a0f386394a0bf2743eb7f952f4519"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"99f2680cb55bf1c7f7679b6df7be2dff58e67c16f3846cf58a15c468b1beabd6","n":8192,"r":8,"p":1},"mac":"127badb0241dd2a420af03dc7c2a494e8c590ff2ead36be48b9baa692815c0fe"}} -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/static/keystore/UTC--2018-09-25T06:34:49.890Z--a2d73CF52034462ACBb359154c2fe3Fc688709A6: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"bb7226c6-aa03-4879-85a3-a7d6df562a2e","address":"a2d73cf52034462acbb359154c2fe3fc688709a6","crypto":{"ciphertext":"30069b4e23c2c90530817f6920f7edbab43de8315f41e5322aaec6e198c2e6ee","cipherparams":{"iv":"632ce6e6012270fa426a06b3f1ace544"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"6081872f754b4060cb7e3a83b5805425fd968eae7653f1494d8511c004d93b0f","n":8192,"r":8,"p":1},"mac":"2b634a0be26989f3f9f9de586411c90f877ee16ea1d796edfe0ba2412cdca766"}} -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/utils/myUtils.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | getweb3: () => { 4 | let Web3 = require("web3") 5 | var web3 = new Web3(Web3.givenProvider || 'https://kovan.infura.io/v3/bc76cd31e8bf48f9a28b73770ffca805'); 6 | 7 | return web3 8 | }, 9 | 10 | success: (data) => { 11 | responseData = { 12 | code:0, 13 | status:"success", 14 | data:data 15 | } 16 | return responseData 17 | }, 18 | 19 | fail: (msg) => { 20 | responseData = { 21 | code:1, 22 | status:"fail", 23 | msg:msg 24 | } 25 | return responseData 26 | } 27 | } -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/views/downloadkeystore.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 保存你的keystore 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 |
18 |
19 |

保存你的keystore

20 | 下载keystore文件 21 |

22 | 23 |
24 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/views/newaccount.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 创建钱包 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 |
16 |

创建一个新的账号

17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /MyEtherWallet:10-浅出:如何实现以太币转账/views/transaction.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 转账 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 |
18 |

发送以太币或者Token代币

19 |
20 | 21 | 22 | 23 |
24 | 25 | 26 |
27 | 28 | 29 |
30 | 31 | 37 | 38 | 48 | 49 | 55 |
56 | 57 | 95 |
96 | 97 | 98 | -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /controllers/account.js: -------------------------------------------------------------------------------- 1 | let { success, fail } = require("../utils/myUtils") 2 | let web3 = require("../utils/myUtils").getweb3() 3 | let fs = require("fs") 4 | let menmonicModel = require("../models/mnemonic") 5 | let myContract = require("../models/contract").getContract() 6 | let haveToken = true 7 | 8 | //获取以太币余额 9 | async function getAccountBalance(address) { 10 | let balance = await web3.eth.getBalance(address) 11 | return web3.utils.fromWei(balance, "ether") 12 | } 13 | 14 | //配置返回给前端的数据,包含以太币的数据,还会有Token的数据 15 | async function setResponseData(account) { 16 | //获取账户余额 17 | let balance = await getAccountBalance(account.address) 18 | console.log(balance) 19 | 20 | let resData = success({ 21 | balance: balance, 22 | address: account.address, 23 | privatekey: account.privateKey 24 | }) 25 | 26 | //获取代币的数据 27 | if (haveToken) { 28 | let myBalance = await myContract.methods.balanceOf(account.address).call() 29 | let decimals = await myContract.methods.decimals().call() 30 | myBalance = myBalance / Math.pow(10, decimals) 31 | let symbol = await myContract.methods.symbol().call() 32 | 33 | resData.data.tokenbalance = myBalance 34 | resData.data.symbol = symbol 35 | } 36 | 37 | //返回相应数据给前端 38 | return resData 39 | } 40 | 41 | module.exports = { 42 | unlockAccountWithPrivate: async (ctx) => { 43 | //1.获取私钥 44 | let privatekey = ctx.request.body.privatekey 45 | console.log(privatekey) 46 | //2.通过私钥解锁账户 47 | let account = web3.eth.accounts.privateKeyToAccount(privatekey) 48 | console.log(account) 49 | //3.将账户信息返回给前端 50 | ctx.body = await setResponseData(account) 51 | }, 52 | 53 | unlockAccountWithKeystore: async (ctx) => { 54 | //1. 获取前端传递的数据,包括keystore、密码 55 | let password = ctx.request.body.password 56 | console.log(password) 57 | let keystore = ctx.request.files.file 58 | console.log(keystore) 59 | //2.读取缓存文件中keystore的数据 60 | let keystoreData = fs.readFileSync(keystore.path, "utf8") 61 | console.log(keystoreData) 62 | //3. 通过keystore和密码解锁账户 63 | let account = web3.eth.accounts.decrypt(JSON.parse(keystoreData), password) 64 | console.log(account) 65 | //4.将账户信息返回给前端 66 | ctx.body = await setResponseData(account) 67 | }, 68 | 69 | unlockAccountWithMnemonic: async (ctx) => { 70 | //1.获取助记词 71 | let mnemonic = ctx.request.body.mnemonic 72 | console.log("mnemonic:",mnemonic) 73 | 74 | //2.通过助记词获取私钥 75 | /* 76 | 注意这里为了简化前端实现过程,故只获取了助记词的第一对公私钥,即"m/44'/60'/0'/0/0",在实际开发工作中需枚举路径"m/44'/60'/0'/0/0"的最后一位0,可继续取值为0,1,2,3,4…… 77 | */ 78 | let privatekey = menmonicModel.getPrivatekeyWithMnemonic(mnemonic, "m/44'/60'/0'/0/0") 79 | console.log("私钥:"+privatekey) 80 | 81 | //3.通过私钥解锁账户 82 | let account = web3.eth.accounts.privateKeyToAccount(privatekey) 83 | console.log("account:",account) 84 | 85 | //4.将账户信息返回给前端 86 | ctx.body = await setResponseData(account) 87 | }, 88 | } -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /controllers/newAccount.js: -------------------------------------------------------------------------------- 1 | let web3 = require("../utils/myUtils").getweb3() 2 | let fs = require("fs") 3 | let path = require("path") 4 | 5 | module.exports = { 6 | //获取创建账号的页面 7 | newAccountHtml: async (ctx) => { 8 | await ctx.render("newaccount.html") 9 | }, 10 | 11 | //创建账户的表单提交被触发的方法 12 | newAccount: async (ctx) => { 13 | console.log("password:", ctx.request.body.password) 14 | 15 | //1.创建钱包账号 16 | let account = web3.eth.accounts.create(ctx.request.body.password) 17 | console.log(account) 18 | 19 | //2.根据账号和密码生成keystore文件 20 | let keystore = account.encrypt(ctx.request.body.password) 21 | console.log(keystore) 22 | 23 | //3.将keysotr保存到文件 24 | let keystoreString = JSON.stringify(keystore) 25 | let time = new Date() 26 | let fileName = 'UTC--'+time.toISOString()+'--'+account.address.slice(2) 27 | console.log(fileName) 28 | let filePath = path.join(__dirname, "../static/keystore", fileName) 29 | fs.writeFileSync(filePath, keystoreString) 30 | 31 | //4.将账号信息返回给客户端 32 | await ctx.render("downloadkeystore.html", { 33 | "downloadurl":"/keystore/"+fileName, 34 | "privatekey":account.privateKey 35 | }) 36 | } 37 | } -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /controllers/token.js: -------------------------------------------------------------------------------- 1 | let myContract = require("../models/contract").getContract() 2 | let web3 = require("../utils/myUtils").getweb3() 3 | let {success, fail} = require("../utils/myUtils") 4 | 5 | module.exports = { 6 | 7 | sendTokenTransaction: async (ctx) => { 8 | let { fromaddress, toaddress, number, privatekey } = ctx.request.body 9 | console.log(JSON.stringify(ctx.request.body)) 10 | 11 | let nonce = await web3.eth.getTransactionCount(fromaddress) 12 | let gasPrice = await web3.eth.getGasPrice() 13 | 14 | let decimals = await myContract.methods.decimals().call() 15 | let balance = number * Math.pow(10, decimals) 16 | 17 | let myBalance = await myContract.methods.balanceOf(fromaddress).call() 18 | if (myBalance < balance) { 19 | ctx.body = fail("余额不足") 20 | return 21 | } 22 | let tokenData = await myContract.methods.transfer(toaddress, balance).encodeABI() 23 | 24 | var rawTx = { 25 | nonce: nonce, 26 | gasPrice: gasPrice, 27 | to: myContract.options.address,//如果转的是Token代币,那么这个to就是合约地址 28 | from: fromaddress, 29 | data: tokenData//转Token会用到的一个字段 30 | } 31 | //需要讲交易的数据进行预估Gas计算,然后将Gas值设置到数据参数中 32 | let gas = await web3.eth.estimateGas(rawTx) 33 | rawTx.gas = gas 34 | 35 | var Tx = require('ethereumjs-tx'); 36 | var privateKey = new Buffer(privatekey.slice(2), 'hex') 37 | 38 | var tx = new Tx(rawTx); 39 | tx.sign(privateKey); 40 | 41 | var serializedTx = tx.serialize(); 42 | 43 | let responseData; 44 | await web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex'), function(err, data) { 45 | console.log(err) 46 | console.log(data) 47 | 48 | if (err) { 49 | responseData = fail(err) 50 | } 51 | }) 52 | .then(function(data) { 53 | console.log(data) 54 | if (data) { 55 | responseData = success({ 56 | "transactionHash":data.transactionHash 57 | }) 58 | } else { 59 | responseData = fail("交易失败") 60 | } 61 | }) 62 | 63 | ctx.body = responseData 64 | } 65 | } -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /controllers/transaction.js: -------------------------------------------------------------------------------- 1 | let { success, fail } = require("../utils/myUtils") 2 | let web3 = require("../utils/myUtils").getweb3() 3 | 4 | module.exports = { 5 | transactionHtml: async (ctx) => { 6 | await ctx.render("transaction.html") 7 | }, 8 | 9 | sendTransaction: async (ctx) => { 10 | let { fromaddress, toaddress, number, privatekey } = ctx.request.body 11 | console.log(JSON.stringify(ctx.request.body)) 12 | 13 | let nonce = await web3.eth.getTransactionCount(fromaddress) 14 | let gasPrice = await web3.eth.getGasPrice() 15 | let balance = await web3.utils.toWei(number) 16 | 17 | var rawTx = { 18 | nonce: nonce, 19 | gasPrice: gasPrice, 20 | to: toaddress, 21 | value: balance, 22 | data: '0x00'//转Token代币会用到的一个字段 23 | } 24 | //需要将交易的数据进行预估gas计算,然后将gas值设置到数据参数中 25 | let gas = await web3.eth.estimateGas(rawTx) 26 | rawTx.gas = gas 27 | 28 | var Tx = require('ethereumjs-tx'); 29 | var tx = new Tx(rawTx); 30 | var privateKey = new Buffer(privatekey.slice(2), 'hex') 31 | tx.sign(privateKey); 32 | 33 | var serializedTx = tx.serialize(); 34 | let responseData; 35 | await web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex'), function(err, data) { 36 | console.log(err) 37 | console.log(data) 38 | 39 | if (err) { 40 | responseData = fail(err) 41 | } 42 | }) 43 | .then(function(data) { 44 | console.log(data) 45 | if (data) { 46 | responseData = success({ 47 | "blockHash":data.blockHash, 48 | "transactionHash":data.transactionHash 49 | }) 50 | } else { 51 | responseData = fail("交易失败") 52 | } 53 | }) 54 | 55 | ctx.body = responseData 56 | }, 57 | } -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /index.js: -------------------------------------------------------------------------------- 1 | 2 | let koa = require("koa") 3 | //通过koa创建一个应用程序 4 | let app = new koa() 5 | //导入./router/route这个包,赋值给的router就是 ./router/router导出的数据 6 | let router = require("./router/router") 7 | let static = require("koa-static") 8 | let path = require("path") 9 | let views = require("koa-views") 10 | let koaBody = require("koa-body") 11 | 12 | app.use(async (ctx, next) => { 13 | console.log(`${ctx.method} ${ctx.url} ..........`) 14 | await next() 15 | }) 16 | 17 | //针对于文件上传的时候,可以解析多个字段 18 | app.use(koaBody({multipart:true})) 19 | //注册静态文件的库到中间件 20 | app.use(static(path.join(__dirname, "static"))) 21 | //注册模板引擎的库到中间件 22 | app.use(views(path.join(__dirname, "views"), {extension:"ejs", map:{html:"ejs"}})) 23 | app.use(router.routes()) 24 | 25 | console.log("正在监听3000端口") 26 | app.listen(3000) 27 | -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /models/contract.js: -------------------------------------------------------------------------------- 1 | let web3 = require("../utils/myUtils").getweb3() 2 | 3 | module.exports = { 4 | getContract: () => { 5 | let ABI = [{"anonymous": false,"inputs": [{"indexed": true,"name": "_owner","type": "address"},{"indexed": true,"name": "_spender","type": "address"},{"indexed": false,"name": "_value","type": "uint256"}],"name": "Approval","type": "event"},{"anonymous": false,"inputs": [{"indexed": true,"name": "_from","type": "address"},{"indexed": true,"name": "_to","type": "address"},{"indexed": false,"name": "_value","type": "uint256"}],"name": "Transfer","type": "event"},{"constant": false,"inputs": [{"name": "_spender","type": "address"},{"name": "_value","type": "uint256"}],"name": "approve","outputs": [{"name": "success","type": "bool"}],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": false,"inputs": [{"name": "_to","type": "address"},{"name": "_value","type": "uint256"}],"name": "transfer","outputs": [{"name": "success","type": "bool"}],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": false,"inputs": [{"name": "_from","type": "address"},{"name": "_to","type": "address"},{"name": "_value","type": "uint256"}],"name": "transferFrom","outputs": [{"name": "success","type": "bool"}],"payable": false,"stateMutability": "nonpayable","type": "function"},{"inputs": [{"name": "_name","type": "string"},{"name": "_symbol","type": "string"},{"name": "_decimals","type": "uint8"},{"name": "_totalSupply","type": "uint256"}],"payable": false,"stateMutability": "nonpayable","type": "constructor"},{"constant": true,"inputs": [{"name": "_owner","type": "address"},{"name": "_spender","type": "address"}],"name": "allowance","outputs": [{"name": "remaining","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [{"name": "_owner","type": "address"}],"name": "balanceOf","outputs": [{"name": "balance","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "decimals","outputs": [{"name": "","type": "uint8"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "name","outputs": [{"name": "","type": "string"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "symbol","outputs": [{"name": "","type": "string"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "totalSupply","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"}] 6 | 7 | let contractAddress = "0xe5b2f5a38d6fe39a45f825d39d4cbf0a0aef5a7e" 8 | let myContract = new web3.eth.Contract(ABI, contractAddress) 9 | return myContract 10 | }, 11 | } -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /models/mnemonic.js: -------------------------------------------------------------------------------- 1 | let bip39 = require('bip39') 2 | let hdkey = require('ethereumjs-wallet/hdkey') 3 | let util = require('ethereumjs-util') 4 | 5 | module.exports = { 6 | getPrivatekeyWithMnemonic: (mnemonic, derivePath) => { 7 | //将助记词转成seed 8 | let seed = bip39.mnemonicToSeed(mnemonic) 9 | //通过hdkey将seed生成HDWallet 10 | let hdWallet = hdkey.fromMasterSeed(seed) 11 | //生成钱包中在m/44'/60'/0'/0/0路径的第一个帐户的keypair。 12 | let key = hdWallet.derivePath(derivePath) 13 | //获取私钥 14 | return util.bufferToHex(key._hdkey._privateKey) 15 | } 16 | } -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "4-wallet", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "bignumber": "^1.1.0", 13 | "ejs": "^2.6.1", 14 | "ethereumjs-tx": "^1.3.7", 15 | "koa": "^2.5.2", 16 | "koa-body": "^4.0.4", 17 | "koa-router": "^7.4.0", 18 | "koa-static": "^5.0.0", 19 | "koa-views": "^6.1.4", 20 | "web3": "^1.0.0-beta.35", 21 | "bip39": "^2.5.0", 22 | "ethereumjs-util": "^5.2.0", 23 | "ethereumjs-wallet": "^0.6.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /router/router.js: -------------------------------------------------------------------------------- 1 | 2 | let router = require("koa-router")() 3 | let newAccountController = require("../controllers/newAccount") 4 | let trasactionConytoller = require("../controllers/transaction") 5 | let accountController = require("../controllers/account") 6 | let tokenController = require("../controllers/token") 7 | 8 | router.get("/", async (ctx) => { 9 | //重定向 10 | ctx.response.redirect("/account/new.html") 11 | }) 12 | 13 | //获取创建钱包账户的页面 14 | router.get("/account/new.html", newAccountController.newAccountHtml) 15 | //提交创建钱包账户的表单 16 | router.post("/account/new", newAccountController.newAccount) 17 | 18 | //获取转账的页面 19 | router.get("/transaction.html", trasactionConytoller.transactionHtml) 20 | //发送转账交易 21 | router.post("/transaction/send", trasactionConytoller.sendTransaction) 22 | 23 | //通过私钥解锁账户 24 | router.post("/unlock/private", accountController.unlockAccountWithPrivate) 25 | //通过keystore解锁账户 26 | router.post("/unlock/keystore", accountController.unlockAccountWithKeystore) 27 | //通过助记词解锁账户 28 | router.post("/unlock/mnemonic", accountController.unlockAccountWithMnemonic) 29 | 30 | //Token转账 31 | router.post("/token/send", tokenController.sendTokenTransaction) 32 | 33 | module.exports = router 34 | -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /static/css/wallet.css: -------------------------------------------------------------------------------- 1 | 2 | #main{ 3 | /*background-color: #8bc34a;*/ 4 | margin: 100px 50px 50px 50px; 5 | 6 | } 7 | .error{ 8 | color: red; 9 | } 10 | a{ 11 | color: black; 12 | text-decoration: none; 13 | } 14 | a:hover{ 15 | color: #666; 16 | } 17 | body{ 18 | margin: 0px; 19 | } 20 | .global-color{ 21 | color: #0abc9c; 22 | } 23 | a[class=button]{ 24 | background-color: beige; 25 | padding: 2px 10px; 26 | border: 1px solid gray; 27 | } 28 | 29 | /*导航-------------------------------------------------------------------------------------------------------*/ 30 | #nav{ 31 | display: flex; 32 | justify-content: space-between; 33 | background-color: #0abc9c; 34 | position: fixed; 35 | top: 0px; 36 | left: 0px; 37 | right: 0px; 38 | } 39 | #nav li{ 40 | display: inline-block; 41 | margin: 10px 2px; 42 | } 43 | #nav ul{ 44 | padding: 0px; 45 | } 46 | #nav a{ 47 | padding: 10px; 48 | font-size: 24px; 49 | } 50 | #nav-left{ 51 | margin-left: 20px; 52 | } 53 | #nav-right{ 54 | margin-right: 20px; 55 | } 56 | -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /static/html/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /static/js/wallet.js: -------------------------------------------------------------------------------- 1 | 2 | function saveKeystoreNext() { 3 | $("#save-keystore").hide() 4 | $("#save-privatekey").show() 5 | } 6 | 7 | //通过私钥解锁账户 8 | function unlockAccountWithPrivatekey() { 9 | let privatekey = $("#input-privatekey").val() 10 | console.log(privatekey) 11 | $.post("/unlock/private", `privatekey=${privatekey}`, function (res, status) { 12 | console.log(status + JSON.stringify(res)) 13 | if (res.code == 0) { 14 | //将服务端返回的账户信息显示到页面 15 | configAccountInfo(res.data) 16 | } 17 | }) 18 | } 19 | 20 | //通过Keystore解锁账户 21 | function unlockAccountWithKeystore() { 22 | var filedata = $("#unlock-accoutn-file").val() 23 | if (filedata.length <= 0) { 24 | alert("请选择文件!") 25 | return 26 | } 27 | //文件上传通过Formdata去储存文件的数据 28 | var data = new FormData() 29 | data.append("file", $("#unlock-accoutn-file")[0].files[0]) 30 | data.append("password", $("#unlock-account-password").val()) 31 | var urlStr = "/unlock/keystore" 32 | $.ajax({ 33 | url: urlStr, 34 | type: "post", 35 | dataType: "json", 36 | contentType: false, 37 | data: data, 38 | processData: false, 39 | success: function (res, status) { 40 | console.log(status + JSON.stringify(res)) 41 | if (res.code == 0) { 42 | //将服务端返回的账户信息显示到页面 43 | configAccountInfo(res.data) 44 | } 45 | }, 46 | error: function (res, status) { 47 | alert(JSON.stringify(res)+status) 48 | } 49 | }) 50 | } 51 | 52 | //通过助记词解锁账户 53 | function unlockAccountWithMnemonic() { 54 | let mnemonic = $("#input-mnemonic").val() 55 | console.log(mnemonic) 56 | $.post("/unlock/mnemonic", `mnemonic=${mnemonic}`, function (res, status) { 57 | console.log(status + JSON.stringify(res)) 58 | if (res.code == 0) { 59 | //将服务端返回的账户信息显示到页面 60 | configAccountInfo(res.data) 61 | } 62 | }) 63 | } 64 | 65 | //解锁成功后给账户设置数据 66 | function configAccountInfo(data) { 67 | $("#account-address").text(data.address) 68 | $("#account-balance").text(data.balance + " ETH") 69 | 70 | $("#transaction-first").hide() 71 | $("#transaction-second").show() 72 | 73 | $("input[name=fromaddress]").val(data.address) 74 | $("input[name=privatekey]").val(data.privatekey) 75 | 76 | $("#account-token-info").text(data.tokenbalance + " " + data.symbol) 77 | $("#send-transaction-token-symbol").text(data.symbol) 78 | } 79 | 80 | $(document).ready(function () { 81 | //改变了解锁账号的方式 82 | $("input[name=unlocktype]").change(function () { 83 | if (this.value == 1) { 84 | $("#unlock-account-privatekey").show() 85 | $("#unlock-account-keystore").hide() 86 | $("#unlock-account-mnemonic").hide() 87 | } else if (this.value == 2) { 88 | $("#unlock-account-privatekey").hide() 89 | $("#unlock-account-keystore").show() 90 | $("#unlock-account-mnemonic").hide() 91 | } else { 92 | $("#unlock-account-privatekey").hide() 93 | $("#unlock-account-keystore").hide() 94 | $("#unlock-account-mnemonic").show() 95 | } 96 | }) 97 | 98 | //转账 99 | $("#send-transaction-form").validate({ 100 | rules:{ 101 | toaddress:{ 102 | required: true, 103 | }, 104 | number:{ 105 | required:true, 106 | }, 107 | }, 108 | messages:{ 109 | toaddress:{ 110 | required:"请输入对方地址", 111 | }, 112 | number:{ 113 | required:"请输入转账数额" 114 | }, 115 | }, 116 | submitHandler: function(form) 117 | { 118 | var urlStr 119 | let tokenType = $("#send-transaction-token-type").val() 120 | if (tokenType == 1) { 121 | urlStr = "/transaction/send" 122 | } else { 123 | urlStr = "/token/send" 124 | } 125 | 126 | $(form).ajaxSubmit({ 127 | url:urlStr, 128 | type:"post", 129 | dataType:"json", 130 | success:function (res, status) { 131 | console.log(status + JSON.stringify(res)) 132 | if (res.code == 0) { 133 | $("#transaction-complate-hash").text(res.data.transactionHash) 134 | $("#transaction-complate").show() 135 | } 136 | }, 137 | error:function (res, status) { 138 | console.log(status + JSON.stringify(res)) 139 | } 140 | }); 141 | } 142 | }) 143 | }) -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /static/keystore/UTC--2018-09-25T06:24:28.689Z--42f971FC3443B43313441E68f7548b3BD0713dB9: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"a3b41a93-4812-4651-a5e7-f869f1c1c81a","address":"42f971fc3443b43313441e68f7548b3bd0713db9","crypto":{"ciphertext":"1b878fd78042a1aac1e1404c886eb823c29052599432c8a19840b8aa23c976ff","cipherparams":{"iv":"a261b97eca4c487d0f149f554e8d0767"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"04603dddcd4dc7f740f4f0d5ffc38277d0dc7f5180c235a1f26ab314bf4df413","n":8192,"r":8,"p":1},"mac":"7511195ae4a6f154b692e02739199b717ed9ed6f973d8de206fea6ea66ac829c"}} -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /static/keystore/UTC--2018-09-25T06:33:18.858Z--709b7348Cb70D65b9C65C0c884B2bF7e02f5B939: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"b3348a71-cfee-445a-b06b-f15c7a989e05","address":"709b7348cb70d65b9c65c0c884b2bf7e02f5b939","crypto":{"ciphertext":"4f666348cf7083c5b66499493a230f3c264a313e36fe7b4c20bc8a574c9598dd","cipherparams":{"iv":"df4a0f386394a0bf2743eb7f952f4519"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"99f2680cb55bf1c7f7679b6df7be2dff58e67c16f3846cf58a15c468b1beabd6","n":8192,"r":8,"p":1},"mac":"127badb0241dd2a420af03dc7c2a494e8c590ff2ead36be48b9baa692815c0fe"}} -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /static/keystore/UTC--2018-09-25T06:34:49.890Z--a2d73CF52034462ACBb359154c2fe3Fc688709A6: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"bb7226c6-aa03-4879-85a3-a7d6df562a2e","address":"a2d73cf52034462acbb359154c2fe3fc688709a6","crypto":{"ciphertext":"30069b4e23c2c90530817f6920f7edbab43de8315f41e5322aaec6e198c2e6ee","cipherparams":{"iv":"632ce6e6012270fa426a06b3f1ace544"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"6081872f754b4060cb7e3a83b5805425fd968eae7653f1494d8511c004d93b0f","n":8192,"r":8,"p":1},"mac":"2b634a0be26989f3f9f9de586411c90f877ee16ea1d796edfe0ba2412cdca766"}} -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /utils/myUtils.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | getweb3: () => { 4 | let Web3 = require("web3") 5 | var web3 = new Web3(Web3.givenProvider || 'https://kovan.infura.io/v3/bc76cd31e8bf48f9a28b73770ffca805'); 6 | 7 | return web3 8 | }, 9 | 10 | success: (data) => { 11 | responseData = { 12 | code:0, 13 | status:"success", 14 | data:data 15 | } 16 | return responseData 17 | }, 18 | 19 | fail: (msg) => { 20 | responseData = { 21 | code:1, 22 | status:"fail", 23 | msg:msg 24 | } 25 | return responseData 26 | } 27 | } -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /views/downloadkeystore.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 保存你的keystore 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 |
18 |
19 |

保存你的keystore

20 | 下载keystore文件 21 |

22 | 23 |
24 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /views/newaccount.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 创建钱包 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 |
16 |

创建一个新的账号

17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /MyEtherWallet:11-深入:如何通过钱包集成第三方数字货币以及转账实现 /views/transaction.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 转账 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 |
18 |

发送以太币或者Token代币

19 |
20 | 21 | 22 | 23 |
24 | 25 | 26 |
27 | 28 | 29 |
30 | 31 | 37 | 38 | 48 | 49 | 55 |
56 | 57 | 98 |
99 | 100 | 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MyEtherWallet 2 | 二十四小时玩转MyEtherWallet钱包开发,主要功能:账户的创建、解锁(助记词)、以太币转账、代币转账交易。 3 | 4 | ### 教程大纲 5 | 6 | 1. 项目概述 7 | 2. 以太坊MyEtherWallet钱包功能演示 8 | 3. 不得不说:钱包地址生成过程 9 | 4. 密码、私钥、keystore与助记词之间的爱恨情仇 10 | 5. 钱包项目整体架构设计 11 | 6. Coding:生成账户的地址、私钥、keystore、助记词 12 | 7. 解锁钱包账号姿势一:私钥 13 | 8. 解锁钱包账号姿势二:keystore+密码 14 | 9. 解锁钱包账号姿势三:助记词 15 | 10. 浅出:如何实现以太币转账 16 | 11. 深入:如何通过钱包集成第三方数字货币以及转账实现 17 | 12. Game Over:总结 18 | 19 | 20 | 21 | ### 项目路线 22 | 23 | 本次课程以 MyEtherWallet 网页钱包的重要功能作为开发需求,由此,项目的路线规划是: 24 | 25 | - 清晰MyEtherWallet的功能并掌握其用法 26 | - 介绍以太坊钱包中涉及的重点理论知识 27 | - 项目架构搭建:以NodeJS开发后端,使用了Koa与相关框架,前端以web进行交互 28 | - 使用web3.js与以太坊区块链进行交互一步步实现各个功能,其中只有助记词使用了其它技术实现 29 | 30 | --- 31 | 32 | **完整文档请查看原文:http://chaindesk.cn/columnlist.html?id=1** 33 | 34 | **版权声明:博客中的文章版权归博主所有,未经授权,禁止转载,转载请联系作者(微信:lixu1770105)取得同意并注明出处。** 35 | --------------------------------------------------------------------------------