@leofcoin/chain 1.3.11 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/block-worker.js +1 -1
- package/demo/chain.browser.js +4 -0
- package/dist/browser/workers/block-worker.js +1977 -5692
- package/dist/browser/workers/machine-worker.js +1955 -5670
- package/dist/browser/workers/pool-worker.js +1636 -5531
- package/dist/browser/workers/transaction-worker.js +1626 -5521
- package/dist/chain.js +9865 -1192
- package/dist/client-80bc8156.js +491 -0
- package/dist/commonjs-7fe3c381.js +270 -0
- package/dist/generate-account-445db122.js +46 -0
- package/dist/index-57f93805.js +718 -0
- package/dist/{messages.browser.js → messages-bce1b91d-81af3b00.js} +26 -39
- package/dist/module/chain.js +9820 -1174
- package/dist/module/client-8031ec88.js +489 -0
- package/dist/module/commonjs-9005d5c0.js +268 -0
- package/dist/module/generate-account-489552b6.js +44 -0
- package/dist/module/index-ac2285c4.js +688 -0
- package/dist/module/messages-bce1b91d-eaf75d83.js +302 -0
- package/dist/module/node.js +6833 -2
- package/dist/module/workers/block-worker.js +3 -287
- package/dist/module/workers/machine-worker.js +3 -287
- package/dist/node.js +6845 -8
- package/dist/workers/machine-worker.js +1 -1
- package/package.json +11 -20
- package/src/chain.js +9 -12
- package/src/contract.js +2 -2
- package/src/machine.js +10 -7
- package/src/node.js +2 -2
- package/src/transaction.js +5 -5
- package/test/chain.js +5 -7
- package/test/index.js +1 -3
- package/tsconfig.js +15 -0
- package/workers/block-worker.js +40 -0
- package/workers/machine-worker.js +219 -0
- package/workers/pool-worker.js +28 -0
- package/workers/transaction-worker.js +20 -0
- package/workers/workers.js +9 -0
- package/dist/865.browser.js +0 -10
- package/dist/chain.browser.js +0 -66838
- package/dist/generate-account.browser.js +0 -50
- package/dist/multi-wallet.browser.js +0 -15
- package/dist/node.browser.js +0 -9858
- package/dist/pako.browser.js +0 -6900
- package/dist/peernet-swarm.browser.js +0 -839
- package/dist/storage.browser.js +0 -3724
- package/dist/wrtc.browser.js +0 -28
- package/rollup.config.js +0 -229
- package/src/standards/initializer.js +0 -10
- package/webpack.config.js +0 -109
|
@@ -0,0 +1,688 @@
|
|
|
1
|
+
import bs58Check from 'bs58check';
|
|
2
|
+
import * as bip32 from 'bip32';
|
|
3
|
+
import randombytes from 'randombytes';
|
|
4
|
+
import '@ethersproject/bignumber';
|
|
5
|
+
import '@ethersproject/units';
|
|
6
|
+
import secp256k1 from 'secp256k1';
|
|
7
|
+
import { createKeccak } from 'hash-wasm';
|
|
8
|
+
import base58 from '@vandeurenglenn/base58';
|
|
9
|
+
import base32 from '@vandeurenglenn/base32';
|
|
10
|
+
import varint from 'varint';
|
|
11
|
+
|
|
12
|
+
var testnets = {
|
|
13
|
+
'leofcoin:olivia': {
|
|
14
|
+
messagePrefix: '\u0019Leofcoin Signed Message:',
|
|
15
|
+
pubKeyHash: 0x73, // o
|
|
16
|
+
scriptHash: 0x76, // p
|
|
17
|
+
multiTxHash: 0x8b4125, // omtx
|
|
18
|
+
payments: {
|
|
19
|
+
version: 0,
|
|
20
|
+
unspent: 0x1fa443d7 // ounsp
|
|
21
|
+
},
|
|
22
|
+
wif: 0x7D, // s
|
|
23
|
+
multiCodec: 0x7c4,
|
|
24
|
+
bip32: { public: 0x13BBF2D5, private: 0x13BBCBC5 }
|
|
25
|
+
},
|
|
26
|
+
'bitcoin:testnet': {
|
|
27
|
+
messagePrefix: '\x18Bitcoin Signed Message:\n',
|
|
28
|
+
bech32: 'tb',
|
|
29
|
+
pubKeyHash: 0x6f,
|
|
30
|
+
scriptHash: 0xc4,
|
|
31
|
+
wif: 0xef,
|
|
32
|
+
bip32: {
|
|
33
|
+
public: 0x043587cf,
|
|
34
|
+
private: 0x04358394
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// https://en.bitcoin.it/wiki/List_of_address_prefixes
|
|
41
|
+
/**
|
|
42
|
+
* Main network
|
|
43
|
+
* @return {messagePrefix, pubKeyHash, scriptHash, wif, bip32}
|
|
44
|
+
*/
|
|
45
|
+
const leofcoin = {
|
|
46
|
+
messagePrefix: '\u0019Leofcoin Signed Message:',
|
|
47
|
+
pubKeyHash: 0x30, // L
|
|
48
|
+
scriptHash: 0x37, // P
|
|
49
|
+
multiTxHash: 0x3adeed, // Lmtx
|
|
50
|
+
payments: {
|
|
51
|
+
version: 0,
|
|
52
|
+
unspent: 0x0d6e0327 // Lunsp
|
|
53
|
+
},
|
|
54
|
+
coin_type: 640,
|
|
55
|
+
wif: 0x3F, // S
|
|
56
|
+
multiCodec: 0x3c4,
|
|
57
|
+
bip32: { public: 0x13BBF2D4, private: 0x13BBCBC4 },
|
|
58
|
+
testnet: testnets['leofcoin:olivia']
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const bitcoin = {
|
|
62
|
+
messagePrefix: '\x18Bitcoin Signed Message:\n',
|
|
63
|
+
bech32: 'bc',
|
|
64
|
+
pubKeyHash: 0x00,
|
|
65
|
+
multiCodec: 0x00,
|
|
66
|
+
scriptHash: 0x05,
|
|
67
|
+
wif: 0x80,
|
|
68
|
+
coin_type: 0,
|
|
69
|
+
bip32: {
|
|
70
|
+
public: 0x0488b21e, private: 0x0488ade4
|
|
71
|
+
},
|
|
72
|
+
testnet: testnets['bitcoin:testnet']
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const litecoin = {
|
|
76
|
+
messagePrefix: '\x19Litecoin Signed Message:\n',
|
|
77
|
+
pubKeyHash: 0x30,
|
|
78
|
+
scriptHash: 0x32,
|
|
79
|
+
wif: 0xb0,
|
|
80
|
+
bip32: {
|
|
81
|
+
public: 0x019da462,
|
|
82
|
+
private: 0x019d9cfe
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const ethereum = {
|
|
87
|
+
messagePrefix: '\x19Ethereum Signed Message:\n',
|
|
88
|
+
pubKeyHash: 0x30,
|
|
89
|
+
scriptHash: 0x32,
|
|
90
|
+
bip32: {
|
|
91
|
+
private: 0x0488ADE4, public: 0x0488B21E
|
|
92
|
+
},
|
|
93
|
+
coin_type: 60,
|
|
94
|
+
wif: 0x45,//E
|
|
95
|
+
multiCodec: 0x3c5
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Our & supported networks
|
|
100
|
+
* @return {leofcoin, olivia}
|
|
101
|
+
*/
|
|
102
|
+
var networks = {
|
|
103
|
+
leofcoin,
|
|
104
|
+
bitcoin,
|
|
105
|
+
litecoin,
|
|
106
|
+
ethereum
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const fromNetworkString = network => {
|
|
110
|
+
const parts = network.split(':');
|
|
111
|
+
network = networks[parts[0]];
|
|
112
|
+
if (parts[1]) {
|
|
113
|
+
if (network[parts[1]]) network = network[parts[1]];
|
|
114
|
+
|
|
115
|
+
network.coin_type = 1;
|
|
116
|
+
}
|
|
117
|
+
return network;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// see https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt
|
|
121
|
+
|
|
122
|
+
var wordlist = ["abandon","ability","able","about","above","absent","absorb","abstract","absurd","abuse","access","accident","account","accuse","achieve","acid","acoustic","acquire","across","act","action","actor","actress","actual","adapt","add","addict","address","adjust","admit","adult","advance","advice","aerobic","affair","afford","afraid","again","age","agent","agree","ahead","aim","air","airport","aisle","alarm","album","alcohol","alert","alien","all","alley","allow","almost","alone","alpha","already","also","alter","always","amateur","amazing","among","amount","amused","analyst","anchor","ancient","anger","angle","angry","animal","ankle","announce","annual","another","answer","antenna","antique","anxiety","any","apart","apology","appear","apple","approve","april","arch","arctic","area","arena","argue","arm","armed","armor","army","around","arrange","arrest","arrive","arrow","art","artefact","artist","artwork","ask","aspect","assault","asset","assist","assume","asthma","athlete","atom","attack","attend","attitude","attract","auction","audit","august","aunt","author","auto","autumn","average","avocado","avoid","awake","aware","away","awesome","awful","awkward","axis","baby","bachelor","bacon","badge","bag","balance","balcony","ball","bamboo","banana","banner","bar","barely","bargain","barrel","base","basic","basket","battle","beach","bean","beauty","because","become","beef","before","begin","behave","behind","believe","below","belt","bench","benefit","best","betray","better","between","beyond","bicycle","bid","bike","bind","biology","bird","birth","bitter","black","blade","blame","blanket","blast","bleak","bless","blind","blood","blossom","blouse","blue","blur","blush","board","boat","body","boil","bomb","bone","bonus","book","boost","border","boring","borrow","boss","bottom","bounce","box","boy","bracket","brain","brand","brass","brave","bread","breeze","brick","bridge","brief","bright","bring","brisk","broccoli","broken","bronze","broom","brother","brown","brush","bubble","buddy","budget","buffalo","build","bulb","bulk","bullet","bundle","bunker","burden","burger","burst","bus","business","busy","butter","buyer","buzz","cabbage","cabin","cable","cactus","cage","cake","call","calm","camera","camp","can","canal","cancel","candy","cannon","canoe","canvas","canyon","capable","capital","captain","car","carbon","card","cargo","carpet","carry","cart","case","cash","casino","castle","casual","cat","catalog","catch","category","cattle","caught","cause","caution","cave","ceiling","celery","cement","census","century","cereal","certain","chair","chalk","champion","change","chaos","chapter","charge","chase","chat","cheap","check","cheese","chef","cherry","chest","chicken","chief","child","chimney","choice","choose","chronic","chuckle","chunk","churn","cigar","cinnamon","circle","citizen","city","civil","claim","clap","clarify","claw","clay","clean","clerk","clever","click","client","cliff","climb","clinic","clip","clock","clog","close","cloth","cloud","clown","club","clump","cluster","clutch","coach","coast","coconut","code","coffee","coil","coin","collect","color","column","combine","come","comfort","comic","common","company","concert","conduct","confirm","congress","connect","consider","control","convince","cook","cool","copper","copy","coral","core","corn","correct","cost","cotton","couch","country","couple","course","cousin","cover","coyote","crack","cradle","craft","cram","crane","crash","crater","crawl","crazy","cream","credit","creek","crew","cricket","crime","crisp","critic","crop","cross","crouch","crowd","crucial","cruel","cruise","crumble","crunch","crush","cry","crystal","cube","culture","cup","cupboard","curious","current","curtain","curve","cushion","custom","cute","cycle","dad","damage","damp","dance","danger","daring","dash","daughter","dawn","day","deal","debate","debris","decade","december","decide","decline","decorate","decrease","deer","defense","define","defy","degree","delay","deliver","demand","demise","denial","dentist","deny","depart","depend","deposit","depth","deputy","derive","describe","desert","design","desk","despair","destroy","detail","detect","develop","device","devote","diagram","dial","diamond","diary","dice","diesel","diet","differ","digital","dignity","dilemma","dinner","dinosaur","direct","dirt","disagree","discover","disease","dish","dismiss","disorder","display","distance","divert","divide","divorce","dizzy","doctor","document","dog","doll","dolphin","domain","donate","donkey","donor","door","dose","double","dove","draft","dragon","drama","drastic","draw","dream","dress","drift","drill","drink","drip","drive","drop","drum","dry","duck","dumb","dune","during","dust","dutch","duty","dwarf","dynamic","eager","eagle","early","earn","earth","easily","east","easy","echo","ecology","economy","edge","edit","educate","effort","egg","eight","either","elbow","elder","electric","elegant","element","elephant","elevator","elite","else","embark","embody","embrace","emerge","emotion","employ","empower","empty","enable","enact","end","endless","endorse","enemy","energy","enforce","engage","engine","enhance","enjoy","enlist","enough","enrich","enroll","ensure","enter","entire","entry","envelope","episode","equal","equip","era","erase","erode","erosion","error","erupt","escape","essay","essence","estate","eternal","ethics","evidence","evil","evoke","evolve","exact","example","excess","exchange","excite","exclude","excuse","execute","exercise","exhaust","exhibit","exile","exist","exit","exotic","expand","expect","expire","explain","expose","express","extend","extra","eye","eyebrow","fabric","face","faculty","fade","faint","faith","fall","false","fame","family","famous","fan","fancy","fantasy","farm","fashion","fat","fatal","father","fatigue","fault","favorite","feature","february","federal","fee","feed","feel","female","fence","festival","fetch","fever","few","fiber","fiction","field","figure","file","film","filter","final","find","fine","finger","finish","fire","firm","first","fiscal","fish","fit","fitness","fix","flag","flame","flash","flat","flavor","flee","flight","flip","float","flock","floor","flower","fluid","flush","fly","foam","focus","fog","foil","fold","follow","food","foot","force","forest","forget","fork","fortune","forum","forward","fossil","foster","found","fox","fragile","frame","frequent","fresh","friend","fringe","frog","front","frost","frown","frozen","fruit","fuel","fun","funny","furnace","fury","future","gadget","gain","galaxy","gallery","game","gap","garage","garbage","garden","garlic","garment","gas","gasp","gate","gather","gauge","gaze","general","genius","genre","gentle","genuine","gesture","ghost","giant","gift","giggle","ginger","giraffe","girl","give","glad","glance","glare","glass","glide","glimpse","globe","gloom","glory","glove","glow","glue","goat","goddess","gold","good","goose","gorilla","gospel","gossip","govern","gown","grab","grace","grain","grant","grape","grass","gravity","great","green","grid","grief","grit","grocery","group","grow","grunt","guard","guess","guide","guilt","guitar","gun","gym","habit","hair","half","hammer","hamster","hand","happy","harbor","hard","harsh","harvest","hat","have","hawk","hazard","head","health","heart","heavy","hedgehog","height","hello","helmet","help","hen","hero","hidden","high","hill","hint","hip","hire","history","hobby","hockey","hold","hole","holiday","hollow","home","honey","hood","hope","horn","horror","horse","hospital","host","hotel","hour","hover","hub","huge","human","humble","humor","hundred","hungry","hunt","hurdle","hurry","hurt","husband","hybrid","ice","icon","idea","identify","idle","ignore","ill","illegal","illness","image","imitate","immense","immune","impact","impose","improve","impulse","inch","include","income","increase","index","indicate","indoor","industry","infant","inflict","inform","inhale","inherit","initial","inject","injury","inmate","inner","innocent","input","inquiry","insane","insect","inside","inspire","install","intact","interest","into","invest","invite","involve","iron","island","isolate","issue","item","ivory","jacket","jaguar","jar","jazz","jealous","jeans","jelly","jewel","job","join","joke","journey","joy","judge","juice","jump","jungle","junior","junk","just","kangaroo","keen","keep","ketchup","key","kick","kid","kidney","kind","kingdom","kiss","kit","kitchen","kite","kitten","kiwi","knee","knife","knock","know","lab","label","labor","ladder","lady","lake","lamp","language","laptop","large","later","latin","laugh","laundry","lava","law","lawn","lawsuit","layer","lazy","leader","leaf","learn","leave","lecture","left","leg","legal","legend","leisure","lemon","lend","length","lens","leopard","lesson","letter","level","liar","liberty","library","license","life","lift","light","like","limb","limit","link","lion","liquid","list","little","live","lizard","load","loan","lobster","local","lock","logic","lonely","long","loop","lottery","loud","lounge","love","loyal","lucky","luggage","lumber","lunar","lunch","luxury","lyrics","machine","mad","magic","magnet","maid","mail","main","major","make","mammal","man","manage","mandate","mango","mansion","manual","maple","marble","march","margin","marine","market","marriage","mask","mass","master","match","material","math","matrix","matter","maximum","maze","meadow","mean","measure","meat","mechanic","medal","media","melody","melt","member","memory","mention","menu","mercy","merge","merit","merry","mesh","message","metal","method","middle","midnight","milk","million","mimic","mind","minimum","minor","minute","miracle","mirror","misery","miss","mistake","mix","mixed","mixture","mobile","model","modify","mom","moment","monitor","monkey","monster","month","moon","moral","more","morning","mosquito","mother","motion","motor","mountain","mouse","move","movie","much","muffin","mule","multiply","muscle","museum","mushroom","music","must","mutual","myself","mystery","myth","naive","name","napkin","narrow","nasty","nation","nature","near","neck","need","negative","neglect","neither","nephew","nerve","nest","net","network","neutral","never","news","next","nice","night","noble","noise","nominee","noodle","normal","north","nose","notable","note","nothing","notice","novel","now","nuclear","number","nurse","nut","oak","obey","object","oblige","obscure","observe","obtain","obvious","occur","ocean","october","odor","off","offer","office","often","oil","okay","old","olive","olympic","omit","once","one","onion","online","only","open","opera","opinion","oppose","option","orange","orbit","orchard","order","ordinary","organ","orient","original","orphan","ostrich","other","outdoor","outer","output","outside","oval","oven","over","own","owner","oxygen","oyster","ozone","pact","paddle","page","pair","palace","palm","panda","panel","panic","panther","paper","parade","parent","park","parrot","party","pass","patch","path","patient","patrol","pattern","pause","pave","payment","peace","peanut","pear","peasant","pelican","pen","penalty","pencil","people","pepper","perfect","permit","person","pet","phone","photo","phrase","physical","piano","picnic","picture","piece","pig","pigeon","pill","pilot","pink","pioneer","pipe","pistol","pitch","pizza","place","planet","plastic","plate","play","please","pledge","pluck","plug","plunge","poem","poet","point","polar","pole","police","pond","pony","pool","popular","portion","position","possible","post","potato","pottery","poverty","powder","power","practice","praise","predict","prefer","prepare","present","pretty","prevent","price","pride","primary","print","priority","prison","private","prize","problem","process","produce","profit","program","project","promote","proof","property","prosper","protect","proud","provide","public","pudding","pull","pulp","pulse","pumpkin","punch","pupil","puppy","purchase","purity","purpose","purse","push","put","puzzle","pyramid","quality","quantum","quarter","question","quick","quit","quiz","quote","rabbit","raccoon","race","rack","radar","radio","rail","rain","raise","rally","ramp","ranch","random","range","rapid","rare","rate","rather","raven","raw","razor","ready","real","reason","rebel","rebuild","recall","receive","recipe","record","recycle","reduce","reflect","reform","refuse","region","regret","regular","reject","relax","release","relief","rely","remain","remember","remind","remove","render","renew","rent","reopen","repair","repeat","replace","report","require","rescue","resemble","resist","resource","response","result","retire","retreat","return","reunion","reveal","review","reward","rhythm","rib","ribbon","rice","rich","ride","ridge","rifle","right","rigid","ring","riot","ripple","risk","ritual","rival","river","road","roast","robot","robust","rocket","romance","roof","rookie","room","rose","rotate","rough","round","route","royal","rubber","rude","rug","rule","run","runway","rural","sad","saddle","sadness","safe","sail","salad","salmon","salon","salt","salute","same","sample","sand","satisfy","satoshi","sauce","sausage","save","say","scale","scan","scare","scatter","scene","scheme","school","science","scissors","scorpion","scout","scrap","screen","script","scrub","sea","search","season","seat","second","secret","section","security","seed","seek","segment","select","sell","seminar","senior","sense","sentence","series","service","session","settle","setup","seven","shadow","shaft","shallow","share","shed","shell","sheriff","shield","shift","shine","ship","shiver","shock","shoe","shoot","shop","short","shoulder","shove","shrimp","shrug","shuffle","shy","sibling","sick","side","siege","sight","sign","silent","silk","silly","silver","similar","simple","since","sing","siren","sister","situate","six","size","skate","sketch","ski","skill","skin","skirt","skull","slab","slam","sleep","slender","slice","slide","slight","slim","slogan","slot","slow","slush","small","smart","smile","smoke","smooth","snack","snake","snap","sniff","snow","soap","soccer","social","sock","soda","soft","solar","soldier","solid","solution","solve","someone","song","soon","sorry","sort","soul","sound","soup","source","south","space","spare","spatial","spawn","speak","special","speed","spell","spend","sphere","spice","spider","spike","spin","spirit","split","spoil","sponsor","spoon","sport","spot","spray","spread","spring","spy","square","squeeze","squirrel","stable","stadium","staff","stage","stairs","stamp","stand","start","state","stay","steak","steel","stem","step","stereo","stick","still","sting","stock","stomach","stone","stool","story","stove","strategy","street","strike","strong","struggle","student","stuff","stumble","style","subject","submit","subway","success","such","sudden","suffer","sugar","suggest","suit","summer","sun","sunny","sunset","super","supply","supreme","sure","surface","surge","surprise","surround","survey","suspect","sustain","swallow","swamp","swap","swarm","swear","sweet","swift","swim","swing","switch","sword","symbol","symptom","syrup","system","table","tackle","tag","tail","talent","talk","tank","tape","target","task","taste","tattoo","taxi","teach","team","tell","ten","tenant","tennis","tent","term","test","text","thank","that","theme","then","theory","there","they","thing","this","thought","three","thrive","throw","thumb","thunder","ticket","tide","tiger","tilt","timber","time","tiny","tip","tired","tissue","title","toast","tobacco","today","toddler","toe","together","toilet","token","tomato","tomorrow","tone","tongue","tonight","tool","tooth","top","topic","topple","torch","tornado","tortoise","toss","total","tourist","toward","tower","town","toy","track","trade","traffic","tragic","train","transfer","trap","trash","travel","tray","treat","tree","trend","trial","tribe","trick","trigger","trim","trip","trophy","trouble","truck","true","truly","trumpet","trust","truth","try","tube","tuition","tumble","tuna","tunnel","turkey","turn","turtle","twelve","twenty","twice","twin","twist","two","type","typical","ugly","umbrella","unable","unaware","uncle","uncover","under","undo","unfair","unfold","unhappy","uniform","unique","unit","universe","unknown","unlock","until","unusual","unveil","update","upgrade","uphold","upon","upper","upset","urban","urge","usage","use","used","useful","useless","usual","utility","vacant","vacuum","vague","valid","valley","valve","van","vanish","vapor","various","vast","vault","vehicle","velvet","vendor","venture","venue","verb","verify","version","very","vessel","veteran","viable","vibrant","vicious","victory","video","view","village","vintage","violin","virtual","virus","visa","visit","visual","vital","vivid","vocal","voice","void","volcano","volume","vote","voyage","wage","wagon","wait","walk","wall","walnut","want","warfare","warm","warrior","wash","wasp","waste","water","wave","way","wealth","weapon","wear","weasel","weather","web","wedding","weekend","weird","welcome","west","wet","whale","what","wheat","wheel","when","where","whip","whisper","wide","width","wife","wild","will","win","window","wine","wing","wink","winner","winter","wire","wisdom","wise","wish","witness","wolf","woman","wonder","wood","wool","word","work","world","worry","worth","wrap","wreck","wrestle","wrist","write","wrong","yard","year","yellow","you","young","youth","zebra","zero","zone","zoo"];
|
|
123
|
+
|
|
124
|
+
const {subtle} = crypto;
|
|
125
|
+
|
|
126
|
+
const uint8ArrayToHex = uint8Array =>
|
|
127
|
+
[...uint8Array].map(x => x.toString(16).padStart(2, '0')).join('');
|
|
128
|
+
|
|
129
|
+
const arrayBufferToHex = arrayBuffer =>
|
|
130
|
+
uint8ArrayToHex(new Uint8Array(arrayBuffer));
|
|
131
|
+
|
|
132
|
+
const hexToUint8Array = hex =>
|
|
133
|
+
new Uint8Array(hex.match(/[\da-f]{2}/gi).map(x => parseInt(x, 16)));
|
|
134
|
+
|
|
135
|
+
const generatePbkdf2 = async (password) => {
|
|
136
|
+
return subtle.importKey(
|
|
137
|
+
'raw',
|
|
138
|
+
password,
|
|
139
|
+
'PBKDF2',
|
|
140
|
+
false,
|
|
141
|
+
['deriveBits']
|
|
142
|
+
)
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const pbkdf2 = async (password, salt, iterations = 4096, length = 64, hash = 'SHA-512') => {
|
|
146
|
+
const key = await generatePbkdf2(password);
|
|
147
|
+
const bits = await subtle.deriveBits({
|
|
148
|
+
name: 'PBKDF2',
|
|
149
|
+
hash,
|
|
150
|
+
salt: salt,
|
|
151
|
+
iterations,
|
|
152
|
+
}, key, length);
|
|
153
|
+
return bits;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const generateAesKey = async (length = 256) => {
|
|
157
|
+
const key = await subtle.generateKey({
|
|
158
|
+
name: 'AES-CBC',
|
|
159
|
+
length
|
|
160
|
+
}, true, ['encrypt', 'decrypt']);
|
|
161
|
+
|
|
162
|
+
return key;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const importAesKey = async (exported, format = 'raw', length = 256) => {
|
|
166
|
+
return await subtle.importKey(format, exported, {
|
|
167
|
+
name: 'AES-CBC',
|
|
168
|
+
length
|
|
169
|
+
}, true, ['encrypt', 'decrypt'])
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const exportAesKey = async (key, format = 'raw') => {
|
|
173
|
+
return await subtle.exportKey(format, key)
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const encryptAes = async (uint8Array, key, iv) => subtle.encrypt({
|
|
177
|
+
name: 'AES-CBC',
|
|
178
|
+
iv,
|
|
179
|
+
}, key, uint8Array);
|
|
180
|
+
|
|
181
|
+
const decryptAes = async (uint8Array, key, iv) => subtle.decrypt({
|
|
182
|
+
name: 'AES-CBC',
|
|
183
|
+
iv,
|
|
184
|
+
}, key, uint8Array);
|
|
185
|
+
|
|
186
|
+
const encrypt = async string => {
|
|
187
|
+
const ec = new TextEncoder();
|
|
188
|
+
const key = await generateAesKey();
|
|
189
|
+
const iv = await randombytes(16);
|
|
190
|
+
const ciphertext = await encryptAes(ec.encode(string), key, iv);
|
|
191
|
+
const exported = await exportAesKey(key);
|
|
192
|
+
return {
|
|
193
|
+
key: arrayBufferToHex(exported),
|
|
194
|
+
iv: iv.toString('hex'),
|
|
195
|
+
cipher: arrayBufferToHex(ciphertext)
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const decrypt = async (cipher, key, iv) => {
|
|
200
|
+
if (!key.type) key = await importAesKey(hexToUint8Array(key));
|
|
201
|
+
cipher = new Uint8Array(hexToUint8Array(cipher));
|
|
202
|
+
iv = new Uint8Array(hexToUint8Array(iv));
|
|
203
|
+
|
|
204
|
+
const dec = new TextDecoder();
|
|
205
|
+
const plaintext = await decryptAes(cipher, key, iv);
|
|
206
|
+
|
|
207
|
+
return dec.decode(plaintext);
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const createHash = async (data, algorithm = 'SHA-512') => {
|
|
211
|
+
return await subtle.digest(algorithm, data)
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
class Mnemonic {
|
|
215
|
+
constructor(options = {}) {
|
|
216
|
+
if (!options.wordlist) this.wordlist = wordlist; // english always loaded, rest included by dev
|
|
217
|
+
else this.wordlist = options.wordlist;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
lpad(string, padString, length) {
|
|
221
|
+
while (string.length < length) {
|
|
222
|
+
string = padString + string;
|
|
223
|
+
}
|
|
224
|
+
return string;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
normalize(string) {
|
|
228
|
+
return (string || '').normalize('NFKD');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
bytesToBinary(bytes) {
|
|
232
|
+
return bytes.map(byte => this.lpad(byte.toString(2), '0', 8)).join('');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async deriveChecksumBits(entropyBuffer) {
|
|
236
|
+
const entropy = entropyBuffer.length * 8;
|
|
237
|
+
const cs = entropy / 32;
|
|
238
|
+
const hash = await createHash(entropyBuffer, 'SHA-512');
|
|
239
|
+
return this.bytesToBinary(Array.from(hash)).slice(0, cs);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async mnemonicFromEntropy(entropy) {
|
|
243
|
+
if (!Buffer.isBuffer(entropy)) entropy = Buffer.from(entropy, 'hex');
|
|
244
|
+
let checksum = await this.deriveChecksumBits(entropy);
|
|
245
|
+
console.log(checksum);
|
|
246
|
+
entropy = this.bytesToBinary(Array.from(entropy));
|
|
247
|
+
let bits = entropy + checksum;
|
|
248
|
+
bits = bits.match(/(.{1,11})/g);
|
|
249
|
+
return bits.map(binary => {
|
|
250
|
+
const index = parseInt(binary, 2);
|
|
251
|
+
return this.wordlist[index]
|
|
252
|
+
}).join(' ')
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
*
|
|
257
|
+
* @param {Number} strength 256 / 8 = 32 = 24 words
|
|
258
|
+
* @returns {String}
|
|
259
|
+
*/
|
|
260
|
+
generate(strength = 256) {
|
|
261
|
+
return this.mnemonicFromEntropy(randombytes(strength / 8))
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
salt(password) {
|
|
265
|
+
return 'mnemonic' + this.normalize(password);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
seedFromMnemonic(mnemonic, password) {
|
|
269
|
+
const encoder =new TextEncoder();
|
|
270
|
+
return pbkdf2(
|
|
271
|
+
encoder.encode(this.normalize(mnemonic)),
|
|
272
|
+
encoder.encode(this.salt(password)),
|
|
273
|
+
4096,
|
|
274
|
+
64,
|
|
275
|
+
'SHA-512')
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const { publicKeyConvert } = secp256k1;
|
|
280
|
+
|
|
281
|
+
const publicKeyToEthereumAddress = async (publicKeyBuffer) => {
|
|
282
|
+
let uncompressed = publicKeyConvert(publicKeyBuffer, false);
|
|
283
|
+
const hasher = await createKeccak(256);
|
|
284
|
+
hasher.update(uncompressed);
|
|
285
|
+
|
|
286
|
+
const hash = hasher.digest();
|
|
287
|
+
return `0x${hash.slice(-40).toString('hex')}`
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
class HDWallet {
|
|
291
|
+
|
|
292
|
+
get chainCodeBuffer() {
|
|
293
|
+
return this.ifNotLocked(() => this.hdnode.chainCode)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
get chainCode() {
|
|
297
|
+
return this.ifNotLocked(() => this.chainCodeBuffer.toString('hex'))
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
get privateKeyBuffer() {
|
|
301
|
+
return this.ifNotLocked(() => this.hdnode.privateKey)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
get privateKey() {
|
|
305
|
+
return this.ifNotLocked(() => this.privateKeyBuffer.toString('hex'))
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
get publicKeyBuffer() {
|
|
309
|
+
return this.ifNotLocked(() => this.hdnode.publicKey)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
get publicKey() {
|
|
313
|
+
return this.ifNotLocked(() => this.publicKeyBuffer.toString('hex'))
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async ethereumAddress() {
|
|
317
|
+
const address = await publicKeyToEthereumAddress(this.publicKeyBuffer);
|
|
318
|
+
return address
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
get leofcoinAddress() {
|
|
322
|
+
return bs58Check.encode(this.neutered.publicKeyBuffer)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
get address() {
|
|
326
|
+
return this.getAddressForCoin()
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async getAddressForCoin(coin_type) {
|
|
330
|
+
if (!coin_type) coin_type = this.hdnode.network.coin_type;
|
|
331
|
+
if (coin_type === 1) {
|
|
332
|
+
if (this.networkName?.split(':')[0] === 'ethereum') coin_type = 60;
|
|
333
|
+
if (this.networkName?.split(':')[0] === 'leofcoin') coin_type = 640;
|
|
334
|
+
}
|
|
335
|
+
// if (coin_type === 0) return this.bitcoinAddress
|
|
336
|
+
if (coin_type === 60) return this.ethereumAddress()
|
|
337
|
+
if (coin_type === 640) return this.leofcoinAddress
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
get accountAddress() {
|
|
341
|
+
return this.ifNotLocked(() => bs58Check.encode(this.hdnode.publicKeyBuffer))
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
get isTestnet() {
|
|
345
|
+
if (typeof network === 'string')
|
|
346
|
+
this.hdnode.network = fromNetworkString(network);
|
|
347
|
+
|
|
348
|
+
return Boolean(this.hdnode.network.coin_type === 1)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
constructor(network, hdnode) {
|
|
352
|
+
if (typeof network === 'string') {
|
|
353
|
+
this.networkName = network;
|
|
354
|
+
this.network = fromNetworkString(network);
|
|
355
|
+
} else if (typeof network === 'object')
|
|
356
|
+
this.network = network;
|
|
357
|
+
|
|
358
|
+
if (hdnode) this.defineHDNode(hdnode);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
ifNotLocked(fn, params) {
|
|
362
|
+
if (!this.locked) return fn(params);
|
|
363
|
+
return null
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
defineHDNode(value) {
|
|
367
|
+
Object.defineProperty(this, 'hdnode', {
|
|
368
|
+
configurable: false,
|
|
369
|
+
writable: false,
|
|
370
|
+
value: value
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
validateNetwork(network) {
|
|
375
|
+
if (!network && !this.network) return console.error(`expected network to be defined`);
|
|
376
|
+
if (!network && this.network) network = this.network;
|
|
377
|
+
if (typeof network === 'string') network = fromNetworkString(network);
|
|
378
|
+
if (typeof network !== 'object') return console.error('network not found');
|
|
379
|
+
return network;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
async generate(password, network) {
|
|
383
|
+
network = this.validateNetwork(network);
|
|
384
|
+
const mnemonic = await new Mnemonic().generate(512);
|
|
385
|
+
const seed = await new Mnemonic().seedFromMnemonic(mnemonic, password, 512);
|
|
386
|
+
this.defineHDNode(bip32.fromSeed(Buffer.from(seed, 'arrayBuffer'), network));
|
|
387
|
+
return mnemonic;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* recover using mnemonic (recovery word list)
|
|
392
|
+
*/
|
|
393
|
+
async recover(mnemonic, password, network) {
|
|
394
|
+
network = this.validateNetwork(network, password);
|
|
395
|
+
const seed = await new Mnemonic().seedFromMnemonic(mnemonic, password, 512);
|
|
396
|
+
this.defineHDNode(bip32.fromSeed(Buffer.from(seed, 'arrayBuffer'), network));
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
load(base58, network) {
|
|
400
|
+
network = this.validateNetwork(network);
|
|
401
|
+
this.defineHDNode(bip32.fromBase58(base58, network));
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
save() {
|
|
405
|
+
return this.hdnode.toBase58();
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
fromAddress(address, chainCode, network) {
|
|
409
|
+
network = this.validateNetwork(network);
|
|
410
|
+
// if (network.coin_type === 60) {
|
|
411
|
+
// address = Buffer.from(address, 'hex')
|
|
412
|
+
// } else {
|
|
413
|
+
address = bs58Check.decode(address);
|
|
414
|
+
// }
|
|
415
|
+
|
|
416
|
+
if (!chainCode || chainCode && !Buffer.isBuffer(chainCode)) chainCode = address.slice(1);
|
|
417
|
+
this.defineHDNode(bip32.fromPublicKey(address, chainCode, network));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
fromPublicKey(hex, chainCode, network) {
|
|
421
|
+
network = this.validateNetwork(network);
|
|
422
|
+
if (!Buffer.isBuffer(hex)) hex = Buffer.from(hex, 'hex');
|
|
423
|
+
if (!chainCode || chainCode && !Buffer.isBuffer(chainCode)) chainCode = hex.slice(1);
|
|
424
|
+
this.defineHDNode(bip32.fromPublicKey(hex, chainCode, network));
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const { ecdsaSign, ecdsaVerify } = secp256k1;
|
|
429
|
+
class MultiSignature {
|
|
430
|
+
multiCodec;
|
|
431
|
+
version;
|
|
432
|
+
decoded;
|
|
433
|
+
encoded;
|
|
434
|
+
#multiSignature;
|
|
435
|
+
constructor(version, multiCodec) {
|
|
436
|
+
if (version === undefined)
|
|
437
|
+
throw ReferenceError('version undefined');
|
|
438
|
+
if (multiCodec === undefined)
|
|
439
|
+
throw ReferenceError('multicodec undefined');
|
|
440
|
+
this.multiCodec = multiCodec;
|
|
441
|
+
this.version = version;
|
|
442
|
+
}
|
|
443
|
+
set multiSignature(value) {
|
|
444
|
+
this.#multiSignature = value;
|
|
445
|
+
}
|
|
446
|
+
get signature() {
|
|
447
|
+
return this.decoded.signature;
|
|
448
|
+
}
|
|
449
|
+
get multiSignature() {
|
|
450
|
+
return this.#multiSignature || this.encoded || this.encode(this.signature);
|
|
451
|
+
}
|
|
452
|
+
export() {
|
|
453
|
+
return base58.encode(this.multiSignature);
|
|
454
|
+
}
|
|
455
|
+
import(encoded) {
|
|
456
|
+
return base58.decode(encoded);
|
|
457
|
+
}
|
|
458
|
+
sign(hash, privateKey) {
|
|
459
|
+
if (!hash || !privateKey)
|
|
460
|
+
throw ReferenceError(`${hash ? 'privateKey' : 'hash'} undefined`);
|
|
461
|
+
const { signature } = ecdsaSign(hash, privateKey);
|
|
462
|
+
this.decoded = {
|
|
463
|
+
version: this.version,
|
|
464
|
+
multiCodec: this.multiCodec,
|
|
465
|
+
signature
|
|
466
|
+
};
|
|
467
|
+
return this.encode(signature);
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* verify signature (multiSignature.signature)
|
|
471
|
+
*/
|
|
472
|
+
verifySignature(signature, hash, publicKey) {
|
|
473
|
+
return ecdsaVerify(signature, hash, publicKey);
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* verify multiSignature
|
|
477
|
+
*/
|
|
478
|
+
verify(multiSignature, hash, publicKey) {
|
|
479
|
+
multiSignature = this.decode(multiSignature);
|
|
480
|
+
return ecdsaVerify(multiSignature.signature, hash, publicKey);
|
|
481
|
+
}
|
|
482
|
+
encode(signature) {
|
|
483
|
+
signature = signature || this.signature;
|
|
484
|
+
if (!signature)
|
|
485
|
+
throw ReferenceError('signature undefined');
|
|
486
|
+
const encodedVersion = varint.encode(this.version);
|
|
487
|
+
const encodedCodec = varint.encode(this.multiCodec);
|
|
488
|
+
const uint8Array = new Uint8Array(encodedVersion.length + encodedCodec.length + signature.length);
|
|
489
|
+
uint8Array.set(encodedVersion);
|
|
490
|
+
uint8Array.set(encodedCodec, encodedVersion.length);
|
|
491
|
+
uint8Array.set(signature, encodedVersion.length + encodedCodec.length);
|
|
492
|
+
this.multiSignature = uint8Array;
|
|
493
|
+
return this.multiSignature;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* decode exported multi signature to object
|
|
497
|
+
* @param {multiSignature} multiSignature base58 encoded string
|
|
498
|
+
* @return {decodedMultiSignature} { version, multiCodec, signature }
|
|
499
|
+
*/
|
|
500
|
+
decode(multiSignature) {
|
|
501
|
+
if (multiSignature)
|
|
502
|
+
this.multiSignature = multiSignature;
|
|
503
|
+
if (!this.multiSignature)
|
|
504
|
+
throw ReferenceError('multiSignature undefined');
|
|
505
|
+
let buffer = this.multiSignature;
|
|
506
|
+
const version = varint.decode(buffer);
|
|
507
|
+
buffer = buffer.slice(varint.decode.bytes);
|
|
508
|
+
const codec = varint.decode(buffer);
|
|
509
|
+
const signature = buffer.slice(varint.decode.bytes);
|
|
510
|
+
if (version !== this.version)
|
|
511
|
+
throw TypeError('Invalid version');
|
|
512
|
+
if (this.multiCodec !== codec)
|
|
513
|
+
throw TypeError('Invalid multiCodec');
|
|
514
|
+
this.decoded = {
|
|
515
|
+
version,
|
|
516
|
+
multiCodec: codec,
|
|
517
|
+
signature
|
|
518
|
+
};
|
|
519
|
+
return this.decoded;
|
|
520
|
+
}
|
|
521
|
+
toHex() {
|
|
522
|
+
return this.multiSignature.toString('hex');
|
|
523
|
+
}
|
|
524
|
+
fromHex(hex) {
|
|
525
|
+
return base58.decode(hex);
|
|
526
|
+
}
|
|
527
|
+
toBs58() {
|
|
528
|
+
return base58.encode(this.multiSignature);
|
|
529
|
+
}
|
|
530
|
+
fromBs58(multiSignature) {
|
|
531
|
+
return base58.decode(multiSignature);
|
|
532
|
+
}
|
|
533
|
+
toBs32() {
|
|
534
|
+
return base32.encode(this.multiSignature);
|
|
535
|
+
}
|
|
536
|
+
fromBs32(multiSignature) {
|
|
537
|
+
return base32.decode(multiSignature);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// TODO: multihash addresses
|
|
542
|
+
class HDAccount {
|
|
543
|
+
/**
|
|
544
|
+
* @param {number} depth - acount depth
|
|
545
|
+
*/
|
|
546
|
+
constructor(node, depth = 0) {
|
|
547
|
+
this.node = node;
|
|
548
|
+
this.depth = depth;
|
|
549
|
+
this._prefix = `m/44'/${node.network.coin_type}'/${depth}'/`;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* @param {number} index - address index
|
|
554
|
+
*/
|
|
555
|
+
internal(index = 0) {
|
|
556
|
+
return this.node.derivePath(`${this._prefix}1/${index}`)
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* @param {number} index - address index
|
|
561
|
+
*/
|
|
562
|
+
external(index = 0) {
|
|
563
|
+
return this.node.derivePath(`${this._prefix}0/${index}`)
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
class MultiWallet extends HDWallet {
|
|
568
|
+
constructor(network, hdnode) {
|
|
569
|
+
super(network, hdnode);
|
|
570
|
+
this.multiCodec = this.network.multiCodec;
|
|
571
|
+
this.version = 0x00;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
get id() {
|
|
575
|
+
const buffer = Buffer.concat([
|
|
576
|
+
Buffer.from(varint.encode(this.multiCodec)),
|
|
577
|
+
Buffer.from(this.account(0).node.neutered.publicKey, 'hex')
|
|
578
|
+
]);
|
|
579
|
+
return bs58Check.encode(buffer)
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
get multiWIF() {
|
|
583
|
+
return this.ifNotLocked(() => this.encode())
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
get neutered() {
|
|
587
|
+
const neutered = this.ifNotLocked(() => new MultiWallet(this.networkName, this.hdnode.neutered()));
|
|
588
|
+
if (neutered) this._neutered = neutered;
|
|
589
|
+
return this._neutered
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
fromId(id) {
|
|
593
|
+
let buffer = bs58Check.decode(id);
|
|
594
|
+
varint.decode(buffer);
|
|
595
|
+
buffer = buffer.slice(varint.decode.bytes);
|
|
596
|
+
this.fromPublicKey(buffer, null, this.networkName);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
async lock(multiWIF) {
|
|
600
|
+
if (!multiWIF) multiWIF = this.multiWIF;
|
|
601
|
+
this.encrypted = await encrypt(multiWIF.toString('hex'));
|
|
602
|
+
this.locked = true;
|
|
603
|
+
return this.encrypted
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
async unlock({key, iv, cipher}) {
|
|
607
|
+
const decrypted = await decrypt(cipher, key, iv);
|
|
608
|
+
this.import(decrypted);
|
|
609
|
+
this.locked = false;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
export() {
|
|
613
|
+
return this.encode();
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* encodes the multiWIF and loads wallet from bs58
|
|
618
|
+
*
|
|
619
|
+
* @param {multiWIF} multiWIF - note a multiWIF is not the same as a wif
|
|
620
|
+
*/
|
|
621
|
+
import(multiWIF) {
|
|
622
|
+
const { bs58, version, multiCodec } = this.decode(multiWIF);
|
|
623
|
+
this.network = Object.values(networks).reduce((p, c) => {
|
|
624
|
+
if (c.multiCodec===multiCodec) return c
|
|
625
|
+
else if (c.testnet && c.testnet.multiCodec === multiCodec) return c.testnet
|
|
626
|
+
else return p
|
|
627
|
+
}, networks['leofcoin']);
|
|
628
|
+
this.load(bs58, this.networkName);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* @return base58Check encoded string
|
|
633
|
+
*/
|
|
634
|
+
encode() {
|
|
635
|
+
const buffer = Buffer.concat([
|
|
636
|
+
Buffer.from(varint.encode(this.version)),
|
|
637
|
+
Buffer.from(varint.encode(this.multiCodec)),
|
|
638
|
+
bs58Check.decode(this.save())
|
|
639
|
+
]);
|
|
640
|
+
return bs58Check.encode(buffer);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
decode(bs58) {
|
|
644
|
+
let buffer = bs58Check.decode(bs58);
|
|
645
|
+
const version = varint.decode(buffer);
|
|
646
|
+
buffer = buffer.slice(varint.decode.bytes);
|
|
647
|
+
const multiCodec = varint.decode(buffer);
|
|
648
|
+
buffer = buffer.slice(varint.decode.bytes);
|
|
649
|
+
bs58 = bs58Check.encode(buffer);
|
|
650
|
+
if (version !== this.version) throw TypeError('Invalid version');
|
|
651
|
+
if (this.multiCodec !== multiCodec) throw TypeError('Invalid multiCodec');
|
|
652
|
+
return { version, multiCodec, bs58 };
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
sign(hash) {
|
|
656
|
+
return new MultiSignature(this.version, this.network.multiCodec)
|
|
657
|
+
.sign(hash, this.privateKeyBuffer);
|
|
658
|
+
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
verify(multiSignature, hash) {
|
|
662
|
+
return new MultiSignature(this.version, this.network.multiCodec)
|
|
663
|
+
.verify(multiSignature, hash, this.publicKeyBuffer)
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* @param {number} account - account to return chain for
|
|
668
|
+
* @return { internal(addressIndex), external(addressIndex) }
|
|
669
|
+
*/
|
|
670
|
+
account(index) {
|
|
671
|
+
return new HDAccount(new MultiWallet(this.networkName, this.hdnode), index);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* m / purpose' / coin_type' / account' / change / aadress_index
|
|
676
|
+
*
|
|
677
|
+
* see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
|
678
|
+
*/
|
|
679
|
+
derivePath(path) {
|
|
680
|
+
return new MultiWallet(this.networkName, this.hdnode.derivePath(path))
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
derive(index) {
|
|
684
|
+
return new MultiWallet(this.networkName, this.hdnode.derive(index));
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
export { MultiWallet as default };
|