@com-chain/jsc3l 2.0.1-rc.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/LICENSE +661 -0
- package/README.md +45 -0
- package/build/bcRead.d.ts +15 -0
- package/build/bcRead.js +123 -0
- package/build/bcRead.js.map +1 -0
- package/build/bcTransaction.d.ts +10 -0
- package/build/bcTransaction.js +135 -0
- package/build/bcTransaction.js.map +1 -0
- package/build/blockies.d.ts +1 -0
- package/build/blockies.js +91 -0
- package/build/blockies.js.map +1 -0
- package/build/config.d.ts +6 -0
- package/build/config.js +25 -0
- package/build/config.js.map +1 -0
- package/build/connection.d.ts +58 -0
- package/build/connection.js +204 -0
- package/build/connection.js.map +1 -0
- package/build/customization.d.ts +37 -0
- package/build/customization.js +129 -0
- package/build/customization.js.map +1 -0
- package/build/ethereum/cipher.d.ts +3 -0
- package/build/ethereum/cipher.js +94 -0
- package/build/ethereum/cipher.js.map +1 -0
- package/build/ethereum/ethFuncs.d.ts +12 -0
- package/build/ethereum/ethFuncs.js +70 -0
- package/build/ethereum/ethFuncs.js.map +1 -0
- package/build/ethereum/etherUnits.d.ts +5 -0
- package/build/ethereum/etherUnits.js +60 -0
- package/build/ethereum/etherUnits.js.map +1 -0
- package/build/ethereum/myetherwallet.d.ts +47 -0
- package/build/ethereum/myetherwallet.js +294 -0
- package/build/ethereum/myetherwallet.js.map +1 -0
- package/build/ethereum/uiFuncs.d.ts +3 -0
- package/build/ethereum/uiFuncs.js +51 -0
- package/build/ethereum/uiFuncs.js.map +1 -0
- package/build/index.d.ts +111 -0
- package/build/index.js +310 -0
- package/build/index.js.map +1 -0
- package/build/memo.d.ts +6 -0
- package/build/memo.js +24 -0
- package/build/memo.js.map +1 -0
- package/build/qr.d.ts +8 -0
- package/build/qr.js +35 -0
- package/build/qr.js.map +1 -0
- package/build/rest/ajaxReq.d.ts +31 -0
- package/build/rest/ajaxReq.js +127 -0
- package/build/rest/ajaxReq.js.map +1 -0
- package/build/rest/endpoint.d.ts +18 -0
- package/build/rest/endpoint.js +26 -0
- package/build/rest/endpoint.js.map +1 -0
- package/build/rest/http.d.ts +10 -0
- package/build/rest/http.js +60 -0
- package/build/rest/http.js.map +1 -0
- package/build/rest/serializer.d.ts +1 -0
- package/build/rest/serializer.js +94 -0
- package/build/rest/serializer.js.map +1 -0
- package/build/type.d.ts +24 -0
- package/build/type.js +9 -0
- package/build/type.js.map +1 -0
- package/build/wallet.d.ts +35 -0
- package/build/wallet.js +162 -0
- package/build/wallet.js.map +1 -0
- package/package.json +41 -0
- package/src/bcRead.ts +184 -0
- package/src/bcTransaction.ts +157 -0
- package/src/blockies.ts +113 -0
- package/src/config.ts +33 -0
- package/src/connection.ts +243 -0
- package/src/customization.ts +156 -0
- package/src/ethereum/cipher.ts +118 -0
- package/src/ethereum/ethFuncs.ts +73 -0
- package/src/ethereum/etherUnits.ts +66 -0
- package/src/ethereum/myetherwallet.ts +354 -0
- package/src/ethereum/uiFuncs.ts +55 -0
- package/src/index.ts +366 -0
- package/src/memo.ts +37 -0
- package/src/qr.ts +34 -0
- package/src/rest/ajaxReq.ts +160 -0
- package/src/rest/endpoint.ts +31 -0
- package/src/rest/http.ts +69 -0
- package/src/rest/serializer.ts +99 -0
- package/src/type.ts +37 -0
- package/src/wallet.ts +200 -0
- package/tsconfig.json +31 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import * as ethFuncs from './ethereum/ethFuncs' // Utilities to pass on
|
|
2
|
+
import * as memo from './memo'
|
|
3
|
+
|
|
4
|
+
// Only required for blockie helper
|
|
5
|
+
import blockies from './blockies'
|
|
6
|
+
import Wallet from './ethereum/myetherwallet'
|
|
7
|
+
|
|
8
|
+
import * as t from './type'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
// Abstracts
|
|
12
|
+
|
|
13
|
+
import HttpAbstract from './rest/http'
|
|
14
|
+
import EndpointAbstract from './rest/endpoint'
|
|
15
|
+
import AjaxReqAbstract from './rest/ajaxReq'
|
|
16
|
+
import ConnectionMgrAbstract from './connection'
|
|
17
|
+
import CustomizationAbstract from './customization'
|
|
18
|
+
import MessagingWalletAbstract from './wallet'
|
|
19
|
+
import BcReadAbstract from './bcRead'
|
|
20
|
+
import BcTransactionAbstract from './bcTransaction'
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
function createIcon (address: string | Wallet) {
|
|
25
|
+
if (address instanceof Wallet) {
|
|
26
|
+
address = address.getAddressString()
|
|
27
|
+
}
|
|
28
|
+
return blockies({
|
|
29
|
+
seed: address.toLowerCase(),
|
|
30
|
+
size: 8,
|
|
31
|
+
scale: 16
|
|
32
|
+
}).toDataURL()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
abstract class AbstractJsc3l {
|
|
37
|
+
|
|
38
|
+
protected abstract httpRequest: t.HttpRequest
|
|
39
|
+
protected abstract persistentStore: t.IPersistentStore
|
|
40
|
+
|
|
41
|
+
localDefaultConf: {}
|
|
42
|
+
|
|
43
|
+
endpoint: string
|
|
44
|
+
|
|
45
|
+
_Endpoint: new (baseUrl: any) => EndpointAbstract
|
|
46
|
+
_connection: null | ConnectionMgrAbstract
|
|
47
|
+
_http: null | HttpAbstract
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
constructor (localDefaultConf?) {
|
|
51
|
+
this.localDefaultConf = localDefaultConf || {}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* `connection` facility needs to be lazy loaded as `this` and
|
|
56
|
+
* abstract `httpRequest` is not available in constructor.
|
|
57
|
+
*/
|
|
58
|
+
get connection () {
|
|
59
|
+
if (!this._connection) {
|
|
60
|
+
const self = this
|
|
61
|
+
class ConnectionMgr extends ConnectionMgrAbstract {
|
|
62
|
+
http = self.http
|
|
63
|
+
persistentStore = self.persistentStore
|
|
64
|
+
}
|
|
65
|
+
this._connection = new ConnectionMgr()
|
|
66
|
+
}
|
|
67
|
+
return this._connection
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* `Endpoint` class is a facility that needs to be lazy loaded as
|
|
72
|
+
* `this` and abstract `httpRequest` is not available in
|
|
73
|
+
* constructor.
|
|
74
|
+
*/
|
|
75
|
+
get Endpoint () {
|
|
76
|
+
if (!this._Endpoint) {
|
|
77
|
+
const self = this
|
|
78
|
+
class Endpoint extends EndpointAbstract {
|
|
79
|
+
httpRequest = self.httpRequest
|
|
80
|
+
}
|
|
81
|
+
this._Endpoint = Endpoint
|
|
82
|
+
}
|
|
83
|
+
return this._Endpoint
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 'http' facility needs to be lazy loaded as 'this' and abstract
|
|
88
|
+
* httpRequest is not available in constructor.
|
|
89
|
+
*/
|
|
90
|
+
get http () {
|
|
91
|
+
if (!this._http) {
|
|
92
|
+
const self = this
|
|
93
|
+
// ConnectionMgr
|
|
94
|
+
|
|
95
|
+
class Http extends HttpAbstract {
|
|
96
|
+
httpRequest = self.httpRequest
|
|
97
|
+
}
|
|
98
|
+
this._http = new Http()
|
|
99
|
+
}
|
|
100
|
+
return this._http
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
getAjaxReq (endpointUrl: string): AjaxReqAbstract {
|
|
106
|
+
const self = this
|
|
107
|
+
class AjaxReq extends AjaxReqAbstract {
|
|
108
|
+
endpoint = new self.Endpoint(endpointUrl)
|
|
109
|
+
}
|
|
110
|
+
return new AjaxReq()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* `getConfJson` check persistent storage for configuration for
|
|
115
|
+
* given currency, otherwise will use the given repo to fetch
|
|
116
|
+
* it (and save it in persistent storage).
|
|
117
|
+
*/
|
|
118
|
+
async getConfig (repo: string, currencyName: string) {
|
|
119
|
+
const cfgJson = this.connection.getLocalConfJSON()
|
|
120
|
+
if (cfgJson && cfgJson.server.name === currencyName) {
|
|
121
|
+
return cfgJson
|
|
122
|
+
}
|
|
123
|
+
return await this.connection.getConfJSON(currencyName, repo)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* `getConfJson` check persistent storage for configuration for
|
|
129
|
+
* given currency, otherwise will use the given repo to fetch
|
|
130
|
+
* it (and save it in persistent storage).
|
|
131
|
+
*/
|
|
132
|
+
getCustomization (config: any): CustomizationAbstract {
|
|
133
|
+
class Customization extends CustomizationAbstract {
|
|
134
|
+
cfg = config
|
|
135
|
+
}
|
|
136
|
+
return new Customization(this.localDefaultConf)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
getWallet (
|
|
141
|
+
endpointUrl: string,
|
|
142
|
+
currencyName: string,
|
|
143
|
+
unlockUrl: string): new () => MessagingWalletAbstract {
|
|
144
|
+
|
|
145
|
+
const self = this
|
|
146
|
+
class MessagingWallet extends MessagingWalletAbstract {
|
|
147
|
+
ajaxReq = self.getAjaxReq(endpointUrl)
|
|
148
|
+
currencyName = currencyName
|
|
149
|
+
unlockUrl = unlockUrl
|
|
150
|
+
}
|
|
151
|
+
// XXXvlab: should we instanciate this ?
|
|
152
|
+
return MessagingWallet
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
getBcRead (endpointUrl, contracts): BcReadAbstract {
|
|
157
|
+
const self = this
|
|
158
|
+
class BcRead extends BcReadAbstract {
|
|
159
|
+
ajaxReq = self.getAjaxReq(endpointUrl)
|
|
160
|
+
contracts = contracts
|
|
161
|
+
}
|
|
162
|
+
return new BcRead()
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
getBcTransaction (endpointUrl, contracts): BcTransactionAbstract {
|
|
167
|
+
const self = this
|
|
168
|
+
class BcTransaction extends BcTransactionAbstract {
|
|
169
|
+
ajaxReq = self.getAjaxReq(endpointUrl)
|
|
170
|
+
contracts = contracts
|
|
171
|
+
}
|
|
172
|
+
return new BcTransaction()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
_currencyMgrPromises = {}
|
|
177
|
+
async getCurrencyMgr (currencyName: string, endpointUrl?: string, repoUrl?: string) {
|
|
178
|
+
const key = Array.from(arguments).join('\0')
|
|
179
|
+
|
|
180
|
+
if (!this._currencyMgrPromises[key]) {
|
|
181
|
+
this._currencyMgrPromises[key] =
|
|
182
|
+
this._getCurrencyMgr(currencyName, endpointUrl, repoUrl)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return await this._currencyMgrPromises[key]
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
async _getCurrencyMgr (currencyName: string,
|
|
190
|
+
endpointUrl?: string,
|
|
191
|
+
repoUrl?: string): Promise<any> {
|
|
192
|
+
if (!repoUrl) {
|
|
193
|
+
if (this.connection.repo) {
|
|
194
|
+
repoUrl = this.connection.repo
|
|
195
|
+
} else {
|
|
196
|
+
repoUrl = await this.connection.lookupAvailableComChainRepo()
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!endpointUrl) {
|
|
201
|
+
if (this.connection.endpoint) {
|
|
202
|
+
endpointUrl = this.connection.endpoint
|
|
203
|
+
} else {
|
|
204
|
+
endpointUrl = (await this.connection.acquireEndPoint(repoUrl)).endpoint
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const config = await this.getConfig(repoUrl, currencyName)
|
|
209
|
+
const customization = this.getCustomization(config)
|
|
210
|
+
const contracts = [
|
|
211
|
+
customization.getContract1(),
|
|
212
|
+
customization.getContract2()
|
|
213
|
+
]
|
|
214
|
+
|
|
215
|
+
const self = this
|
|
216
|
+
const wallet = this.getWallet(
|
|
217
|
+
endpointUrl, currencyName, customization.getUnlockUrl())
|
|
218
|
+
return {
|
|
219
|
+
// unlockWallet: (jsonData, password) => wallet.getWalletFromPrivKeyFile(jsonData, password),
|
|
220
|
+
jsc3l: this,
|
|
221
|
+
customization,
|
|
222
|
+
ajaxReq: this.getAjaxReq(endpointUrl),
|
|
223
|
+
wallet: wallet,
|
|
224
|
+
bcRead: this.getBcRead(endpointUrl, contracts),
|
|
225
|
+
bcTransaction: this.getBcTransaction(endpointUrl, contracts),
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
Object.assign(AbstractJsc3l.prototype, {
|
|
236
|
+
memo,
|
|
237
|
+
ethFuncs,
|
|
238
|
+
createIcon
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
abstract class IntegratedJsc3lAbstract extends AbstractJsc3l {
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* `ajaxReq` depends on a loaded endpoint in
|
|
246
|
+
* `this.connection.endpoint` obtained through
|
|
247
|
+
* `this.endpoint.acquireEndPoint(..)`. XXXvlab: We could cache the
|
|
248
|
+
* result with endpoint being a key.
|
|
249
|
+
*/
|
|
250
|
+
get ajaxReq (): AjaxReqAbstract {
|
|
251
|
+
if (!this.connection.endpoint) {
|
|
252
|
+
throw new Error('An endpoint need to have been acquired.')
|
|
253
|
+
}
|
|
254
|
+
return this.getAjaxReq(this.connection.endpoint)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* `customization` depends on a local configuration being available
|
|
260
|
+
* through a previous call to `this.connection.getConfJSON(..)`
|
|
261
|
+
*
|
|
262
|
+
* XXXvlab: We could cache the result with result of
|
|
263
|
+
* `connection.getLocalConf()` being the key.
|
|
264
|
+
*/
|
|
265
|
+
get customization (): CustomizationAbstract {
|
|
266
|
+
// XXXvlab: Probably don't need a module for that, as the configuration
|
|
267
|
+
// is always re-queried and quite small, we could cache-it in memory.
|
|
268
|
+
const localCfg = this.connection.getLocalConfJSON()
|
|
269
|
+
if (!localCfg) {
|
|
270
|
+
throw new Error('No configuration is available locally.')
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return this.getCustomization(localCfg)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* `wallet` depends on both:
|
|
279
|
+
* - a local configuration (only for the `currencyName`) being
|
|
280
|
+
* available through a previous call to
|
|
281
|
+
* `this.connection.getConfJSON(..)`
|
|
282
|
+
* - a loaded endpoint in `this.connection.endpoint` obtained
|
|
283
|
+
* through `this.endpoint.acquireEndPoint(..)`.
|
|
284
|
+
*
|
|
285
|
+
* XXXvlab: We could cache the result with result of
|
|
286
|
+
* `connection.getLocalConf()` and `this.connection.endpoint` being
|
|
287
|
+
* the keys.
|
|
288
|
+
*/
|
|
289
|
+
get wallet (): MessagingWalletAbstract["constructor"] {
|
|
290
|
+
if (!this.ajaxReq) {
|
|
291
|
+
throw Error('a connect() is required before accessing wallet')
|
|
292
|
+
}
|
|
293
|
+
let localCfg: any
|
|
294
|
+
try {
|
|
295
|
+
localCfg = this.customization
|
|
296
|
+
} catch (e) {
|
|
297
|
+
throw Error('A local conf needs to be available before accessing wallet')
|
|
298
|
+
}
|
|
299
|
+
return this.getWallet(
|
|
300
|
+
this.ajaxReq.endpoint.baseUrl,
|
|
301
|
+
localCfg.getCurrencyName(),
|
|
302
|
+
this.customization.getUnlockUrl())
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* `bcRead` access depends on both:
|
|
308
|
+
* - a local configuration (only for contracts information) being
|
|
309
|
+
* available through a previous call to
|
|
310
|
+
* `this.connection.getConfJSON(..)`
|
|
311
|
+
* - a loaded endpoint in `this.connection.endpoint` obtained through
|
|
312
|
+
* `this.endpoint.acquireEndPoint(..)`.
|
|
313
|
+
*
|
|
314
|
+
* XXXvlab: We could cache the result with result of
|
|
315
|
+
* `connection.getLocalConf()` and `this.connection.endpoint` being
|
|
316
|
+
* the keys.
|
|
317
|
+
*/
|
|
318
|
+
get bcRead (): BcReadAbstract {
|
|
319
|
+
if (!this.ajaxReq) {
|
|
320
|
+
throw Error('an init() is required before accessing bcRead')
|
|
321
|
+
}
|
|
322
|
+
let localCfg: any
|
|
323
|
+
try {
|
|
324
|
+
localCfg = this.customization
|
|
325
|
+
} catch (e) {
|
|
326
|
+
throw Error('A local conf needs to be available before accessing wallet')
|
|
327
|
+
}
|
|
328
|
+
return this.getBcRead(
|
|
329
|
+
this.ajaxReq.endpoint.baseUrl,
|
|
330
|
+
[localCfg.getContract1(), localCfg.getContract2()]
|
|
331
|
+
)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* `bcTransaction` access depends on both:
|
|
337
|
+
* - a local configuration (only for contracts information) being
|
|
338
|
+
* available through a previous call to
|
|
339
|
+
* `this.connection.getConfJSON(..)`
|
|
340
|
+
* - a loaded endpoint in `this.connection.endpoint` obtained through
|
|
341
|
+
* `this.endpoint.acquireEndPoint(..)`.
|
|
342
|
+
*
|
|
343
|
+
* XXXvlab: We could cache the result with result of
|
|
344
|
+
* `connection.getLocalConf()` and `this.connection.endpoint` being
|
|
345
|
+
* the keys.
|
|
346
|
+
*/
|
|
347
|
+
get bcTransaction (): BcTransactionAbstract {
|
|
348
|
+
if (!this.ajaxReq) {
|
|
349
|
+
throw Error('an init() is required before accessing bcTransaction')
|
|
350
|
+
}
|
|
351
|
+
let localCfg: any
|
|
352
|
+
try {
|
|
353
|
+
localCfg = this.customization
|
|
354
|
+
} catch (e) {
|
|
355
|
+
throw Error('A local conf needs to be available before accessing wallet')
|
|
356
|
+
}
|
|
357
|
+
return this.getBcTransaction(
|
|
358
|
+
this.ajaxReq.endpoint.baseUrl,
|
|
359
|
+
[localCfg.getContract1(), localCfg.getContract2()]
|
|
360
|
+
)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
export default IntegratedJsc3lAbstract
|
package/src/memo.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { cipherMsg, decipherMsg } from './ethereum/cipher'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
// Used in the test
|
|
5
|
+
export function getMyTransactionMemo (msgWallet, transaction) {
|
|
6
|
+
const key = msgWallet.messageKeysFromWallet()
|
|
7
|
+
const watchedAddress = msgWallet.getAddressString().toLowerCase()
|
|
8
|
+
const { addr_to, message_to, addr_from, message_from } = transaction
|
|
9
|
+
|
|
10
|
+
return getTransactionMemo(transaction, watchedAddress, key)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export function getTransactionMemo (transaction, forAddress, messageKey) {
|
|
15
|
+
const { addr_to, message_to, addr_from, message_from } = transaction
|
|
16
|
+
|
|
17
|
+
if (addr_to.toLowerCase() === forAddress && message_to) {
|
|
18
|
+
return decipherMsg(messageKey, message_to)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (addr_from.toLowerCase() === forAddress && message_from) {
|
|
22
|
+
return decipherMsg(messageKey, message_from)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return ''
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
export function getTxMemoCipheredData (fromMsgKey, toMsgKey, msgFrom, msgTo) {
|
|
30
|
+
return {
|
|
31
|
+
...(fromMsgKey && msgFrom) &&
|
|
32
|
+
{ memo_from: cipherMsg(fromMsgKey, msgFrom) },
|
|
33
|
+
...(toMsgKey && msgTo) &&
|
|
34
|
+
{ memo_to: cipherMsg(toMsgKey, msgTo) },
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
package/src/qr.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import ethUtil from 'ethereumjs-util'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export function checkSignedQRFromString (qrString, intendedRecipientAddress) {
|
|
5
|
+
let data:string, signature: string
|
|
6
|
+
try {
|
|
7
|
+
({ data, signature } = JSON.parse(qrString))
|
|
8
|
+
} catch (e) {
|
|
9
|
+
return 'InvalidFormat'
|
|
10
|
+
}
|
|
11
|
+
return checkSignedQR(data, signature, intendedRecipientAddress)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function checkSignedQR (data, signature, intendedRecipientAddress) {
|
|
15
|
+
let hash: string
|
|
16
|
+
let publicSignKey: string
|
|
17
|
+
let receiverAddress: string
|
|
18
|
+
try {
|
|
19
|
+
hash = ethUtil.sha3(JSON.stringify(data))
|
|
20
|
+
publicSignKey = ethUtil.ecrecover(
|
|
21
|
+
hash, signature.v, signature.r, signature.s)
|
|
22
|
+
receiverAddress = ethUtil.bufferToHex(
|
|
23
|
+
ethUtil.publicToAddress(publicSignKey))
|
|
24
|
+
} catch (e) {
|
|
25
|
+
return 'InvalidFormat'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (receiverAddress !== data.address) { return 'InvalidSignature' }
|
|
29
|
+
if (data.destinary !== intendedRecipientAddress) { return 'NotForYou' }
|
|
30
|
+
if ((new Date(data.end)).getTime() < (new Date()).getTime()) {
|
|
31
|
+
return 'Expired'
|
|
32
|
+
}
|
|
33
|
+
return { signature, data }
|
|
34
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
|
|
2
|
+
class URL {
|
|
3
|
+
static SERVER = 'api.php';
|
|
4
|
+
static ENROLL = 'enroll.php';
|
|
5
|
+
static TRANLIST = 'trnslist.php';
|
|
6
|
+
static TRANCHECK = 'api.php';
|
|
7
|
+
static EXPORTTRAN = 'export.php';
|
|
8
|
+
static GETCODE = 'getuid.php';
|
|
9
|
+
static GETADDRESS = 'getadd.php';
|
|
10
|
+
static KEYSTORE = 'keys.php';
|
|
11
|
+
static requestMessages = 'requestMessages.php';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export default abstract class AjaxReqAbstract {
|
|
16
|
+
|
|
17
|
+
// XXXvlab: need to be public only to allow integrated mode (used in
|
|
18
|
+
// ``jsc3l.wallet``)
|
|
19
|
+
public abstract endpoint: any
|
|
20
|
+
|
|
21
|
+
pendingPosts = []
|
|
22
|
+
|
|
23
|
+
//
|
|
24
|
+
// URL.SERVER POST requests (that are using queuing mecanism)
|
|
25
|
+
//
|
|
26
|
+
|
|
27
|
+
post (data) {
|
|
28
|
+
const self = this
|
|
29
|
+
return new Promise(function (resolve, reject) {
|
|
30
|
+
self.pendingPosts.push({ data, resolve, reject })
|
|
31
|
+
if (self.pendingPosts.length === 1) self.queuePost()
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
queuePost () {
|
|
36
|
+
const { data, resolve, reject } = this.pendingPosts[0]
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
this.endpoint.post(URL.SERVER, data).then(data => {
|
|
40
|
+
resolve(data.data)
|
|
41
|
+
})
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.log(err)
|
|
44
|
+
reject(err)
|
|
45
|
+
}
|
|
46
|
+
this.pendingPosts.splice(0, 1)
|
|
47
|
+
if (this.pendingPosts.length > 0) { this.queuePost() }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
getBalance (addr) { return this.post({ balance: addr }) }
|
|
52
|
+
getTransactionData (addr) { return this.post({ txdata: addr }) }
|
|
53
|
+
async sendTx (rawTx, additionalData) {
|
|
54
|
+
const data: {[k: string]: any} =
|
|
55
|
+
await this.post(Object.assign({}, { rawtx: rawTx }, additionalData ?? {}))
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
isError: !!data.error,
|
|
59
|
+
error: data.error ? data.data : data.msg
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
getEstimatedGas (txobj) { return this.post({ estimatedGas: txobj }) }
|
|
65
|
+
getEthCall (txobj) { return this.post({ ethCall: txobj }) }
|
|
66
|
+
|
|
67
|
+
getEthCallAt (txobj, blockNb) {
|
|
68
|
+
return this.post({ ethCallAt: txobj, blockNb })
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
//
|
|
73
|
+
// Other calls
|
|
74
|
+
//
|
|
75
|
+
|
|
76
|
+
enrollPost (data) {
|
|
77
|
+
return this.endpoint.post(URL.ENROLL, { data: JSON.stringify(data) })
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
validateEnrollmentLetter (id, currency, signature) {
|
|
81
|
+
return this.enrollPost({ id, currency, signature })
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
enrollAddress (id, address, currency, token) {
|
|
85
|
+
return this.enrollPost({ id, addresse: address, token, currency })
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async getTransList (id, count, offset) {
|
|
89
|
+
// for some strange reasons, the answer is stringified 2 times,
|
|
90
|
+
// so we need to unpack each entry a second time.
|
|
91
|
+
const data = await this.endpoint.get(URL.TRANLIST, { addr: id, count, offset })
|
|
92
|
+
return data.map((dataJSON) => JSON.parse(dataJSON))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
getTransCheck (hash) {
|
|
96
|
+
return this.endpoint.get(URL.TRANCHECK, { hash })
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
getExportTransList (id, start, end) {
|
|
100
|
+
return this.endpoint.get(URL.EXPORTTRAN, { addr: id, start, end })
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getExportTransListWithId (id, start, end) {
|
|
104
|
+
return this.endpoint.get(URL.EXPORTTRAN, { addr: id, start, end })
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
getCodesFromAddresses (addresses, currency, caller, signature) {
|
|
108
|
+
return this.endpoint.post(URL.GETCODE, {
|
|
109
|
+
server: currency,
|
|
110
|
+
caller,
|
|
111
|
+
signature,
|
|
112
|
+
addresses
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
getAddressesFromCode (code, currency, caller, signature) {
|
|
117
|
+
return this.endpoint.post(URL.GETADDRESS, {
|
|
118
|
+
server: currency,
|
|
119
|
+
caller,
|
|
120
|
+
signature,
|
|
121
|
+
code
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
getMessageKey (addr, withPrivate) {
|
|
126
|
+
const data: {[k: string]: any} = { addr }
|
|
127
|
+
if (withPrivate) data.private = '1'
|
|
128
|
+
return this.endpoint.get(URL.KEYSTORE, data)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
publishMessageKey (data, sign) {
|
|
132
|
+
return this.endpoint.post(URL.KEYSTORE, { data, sign })
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
requestUnlock (address, url) {
|
|
136
|
+
return this.endpoint.post(url, { address })
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
getReqMessages (addFrom, addTo) {
|
|
140
|
+
return this.endpoint.get(
|
|
141
|
+
URL.requestMessages,
|
|
142
|
+
{ add_req: addFrom, add_cli: addTo })
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
publishReqMessages (data, sign) {
|
|
146
|
+
return this.endpoint.post(URL.requestMessages, { data, sign })
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
currBlock () { return this.endpoint.get(URL.SERVER) }
|
|
150
|
+
|
|
151
|
+
async getBlock (hash) {
|
|
152
|
+
let res = await this.endpoint.get(URL.SERVER, { hash })
|
|
153
|
+
if (res && typeof res !== 'object') {
|
|
154
|
+
res = JSON.parse(res).transaction
|
|
155
|
+
}
|
|
156
|
+
return res
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
}
|
|
160
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import HttpAbstract from './http'
|
|
2
|
+
import postSerializer from './serializer'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Serialize data, adds default config and transfer to code http module
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
abstract class PostSerializedHttpAbstract extends HttpAbstract {
|
|
9
|
+
post (...[url, data, opts]: any[]) {
|
|
10
|
+
return super.post(url, postSerializer(data), opts)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Prepend endpoint address to url, and support passing data to
|
|
16
|
+
* querystring when method is GET.
|
|
17
|
+
*/
|
|
18
|
+
export default abstract class EndpointAbstract extends PostSerializedHttpAbstract {
|
|
19
|
+
|
|
20
|
+
baseUrl: string
|
|
21
|
+
|
|
22
|
+
constructor (baseUrl) {
|
|
23
|
+
super()
|
|
24
|
+
this.baseUrl = baseUrl
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
request (method, url, ...args: any[]) {
|
|
28
|
+
url = url.includes('://') ? url : this.baseUrl + url
|
|
29
|
+
return super.request(method, url, ...args)
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/rest/http.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as t from '../type'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function getHostOrUrlParts (HostOrUrl: string): t.UrlParts {
|
|
5
|
+
let protocol: string, host: string, port: number, path: string
|
|
6
|
+
if (HostOrUrl.includes('://')) {
|
|
7
|
+
;[protocol, HostOrUrl] = HostOrUrl.split('://')
|
|
8
|
+
} else {
|
|
9
|
+
protocol = 'https'
|
|
10
|
+
HostOrUrl = HostOrUrl.replace(/\/$/, '')
|
|
11
|
+
}
|
|
12
|
+
if (HostOrUrl.includes('/')) {
|
|
13
|
+
const splits = HostOrUrl.split('/')
|
|
14
|
+
;[host, path] = [splits[0], '/' + splits.slice(1).join('/')]
|
|
15
|
+
} else {
|
|
16
|
+
// assume host only
|
|
17
|
+
path = ''
|
|
18
|
+
host = HostOrUrl
|
|
19
|
+
}
|
|
20
|
+
if (host.includes(':')) {
|
|
21
|
+
const splits = host.split(':')
|
|
22
|
+
if (splits.length > 2) {
|
|
23
|
+
throw new Error(`Too many ':' to get host and port: ${host}`)
|
|
24
|
+
}
|
|
25
|
+
;[host, port] = [splits[0], parseInt(splits[1])]
|
|
26
|
+
} else {
|
|
27
|
+
if (protocol === 'http') {
|
|
28
|
+
port = 80
|
|
29
|
+
} else if (protocol === 'https') {
|
|
30
|
+
port = 443
|
|
31
|
+
} else {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Could not infer port from unknown protocol ${protocol}`
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
protocol,
|
|
39
|
+
host,
|
|
40
|
+
port,
|
|
41
|
+
path,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Support passing data to querystring when method is GET.
|
|
48
|
+
*/
|
|
49
|
+
export default abstract class HttpAbstract {
|
|
50
|
+
|
|
51
|
+
protected abstract httpRequest: t.HttpRequest
|
|
52
|
+
|
|
53
|
+
async request (...[method, url, data, opts]: any[]) {
|
|
54
|
+
if (method === 'GET' && data && Object.keys(data).length > 0) {
|
|
55
|
+
url += '?' + (new URLSearchParams(data)).toString()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
var coreOpts = {
|
|
59
|
+
method,
|
|
60
|
+
data: method === 'GET' ? null : data,
|
|
61
|
+
...opts,
|
|
62
|
+
...getHostOrUrlParts(url)
|
|
63
|
+
}
|
|
64
|
+
return await <any> this.httpRequest(coreOpts)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get (...args: any[]) { return this.request('GET', ...args) }
|
|
68
|
+
post (...args: any[]) { return this.request('POST', ...args) }
|
|
69
|
+
}
|