@com-chain/jsc3l 2.0.1-rc.0 → 2.0.1-rc.10
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/build/bcRead.d.ts +8 -9
- package/build/bcRead.js +93 -35
- package/build/bcRead.js.map +1 -1
- package/build/bcTransaction.d.ts +2 -1
- package/build/bcTransaction.js +55 -76
- package/build/bcTransaction.js.map +1 -1
- package/build/config/transactions.d.ts +44 -0
- package/build/config/transactions.js +29 -0
- package/build/config/transactions.js.map +1 -0
- package/build/connection.js +14 -8
- package/build/connection.js.map +1 -1
- package/build/customization.js +11 -2
- package/build/customization.js.map +1 -1
- package/build/ethereum/ethFuncs.js +1 -1
- package/build/ethereum/ethFuncs.js.map +1 -1
- package/build/ethereum/etherUnits.js +5 -5
- package/build/ethereum/etherUnits.js.map +1 -1
- package/build/ethereum/uiFuncs.d.ts +1 -3
- package/build/ethereum/uiFuncs.js +13 -23
- package/build/ethereum/uiFuncs.js.map +1 -1
- package/build/index.d.ts +10 -6
- package/build/index.js +35 -21
- package/build/index.js.map +1 -1
- package/build/qr.d.ts +31 -6
- package/build/qr.js +32 -12
- package/build/qr.js.map +1 -1
- package/build/rest/ajaxReq.d.ts +2 -10
- package/build/rest/ajaxReq.js +10 -32
- package/build/rest/ajaxReq.js.map +1 -1
- package/build/type.d.ts +4 -4
- package/build/wallet.d.ts +7 -9
- package/build/wallet.js +31 -39
- package/build/wallet.js.map +1 -1
- package/package.json +3 -1
- package/src/bcRead.ts +108 -49
- package/src/bcTransaction.ts +58 -77
- package/src/config/transactions.ts +30 -0
- package/src/connection.ts +15 -7
- package/src/customization.ts +17 -2
- package/src/ethereum/ethFuncs.ts +1 -1
- package/src/ethereum/etherUnits.ts +5 -5
- package/src/ethereum/uiFuncs.ts +16 -25
- package/src/index.ts +50 -28
- package/src/qr.ts +86 -12
- package/src/rest/ajaxReq.ts +10 -39
- package/src/wallet.ts +40 -50
package/src/customization.ts
CHANGED
|
@@ -131,14 +131,25 @@ export default abstract class CustomizationAbstract {
|
|
|
131
131
|
if (!currencyName) {
|
|
132
132
|
currencyName = this.cfg.server.name
|
|
133
133
|
}
|
|
134
|
+
if (!this.cfg.custoRepo) {
|
|
135
|
+
throw Error(
|
|
136
|
+
'Requested getCurrencyAssetBaseUrl while configuration is not available (yet?)'
|
|
137
|
+
)
|
|
138
|
+
}
|
|
134
139
|
return `${this.cfg.custoRepo}${currencyName}`
|
|
135
140
|
}
|
|
136
141
|
|
|
137
142
|
public getCssUrl (currencyName?: string) {
|
|
138
143
|
try {
|
|
139
|
-
// XXXvlab: I guess that we don't need to keep 'etherwallet' css
|
|
140
|
-
|
|
144
|
+
// XXXvlab: I guess that we don't need to keep 'etherwallet' css
|
|
145
|
+
// names
|
|
146
|
+
return this.getCurrencyAssetBaseUrl(currencyName) +
|
|
147
|
+
'/css/etherwallet-master.min.css'
|
|
141
148
|
} catch (e) {
|
|
149
|
+
console.log(
|
|
150
|
+
'`customization.getCssUrl(..)` called before configuration was ' +
|
|
151
|
+
"ready. Returning `localDefaultConf`'s value."
|
|
152
|
+
)
|
|
142
153
|
return this.localDefaultConf.server.url_Css
|
|
143
154
|
}
|
|
144
155
|
}
|
|
@@ -149,6 +160,10 @@ export default abstract class CustomizationAbstract {
|
|
|
149
160
|
// be agnostic ?
|
|
150
161
|
return `${this.getCurrencyAssetBaseUrl(currencyName)}/images/lem.png`
|
|
151
162
|
} catch (e) {
|
|
163
|
+
console.log(
|
|
164
|
+
'`customization.getCurrencyLogoUrl(..)` called before configuration ' +
|
|
165
|
+
'was ready. Returning empty string.'
|
|
166
|
+
)
|
|
152
167
|
return ''
|
|
153
168
|
}
|
|
154
169
|
}
|
package/src/ethereum/ethFuncs.ts
CHANGED
|
@@ -41,26 +41,26 @@ export function getValueOfUnit (unit) {
|
|
|
41
41
|
export function fiatToWei (number, pricePerEther) {
|
|
42
42
|
return new BigNumber(String(number))
|
|
43
43
|
.div(pricePerEther)
|
|
44
|
-
.times(
|
|
44
|
+
.times(getValueOfUnit('ether'))
|
|
45
45
|
.round(0)
|
|
46
46
|
.toString(10)
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
export function toFiat (number, unit, multi) {
|
|
50
|
-
return new BigNumber(
|
|
50
|
+
return new BigNumber(toEther(number, unit))
|
|
51
51
|
.times(multi)
|
|
52
52
|
.round(5)
|
|
53
53
|
.toString(10)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
export function toEther (number, unit) {
|
|
57
|
-
return new BigNumber(
|
|
58
|
-
.div(
|
|
57
|
+
return new BigNumber(toWei(number, unit))
|
|
58
|
+
.div(getValueOfUnit('ether'))
|
|
59
59
|
.toString(10)
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
export function toWei (number, unit) {
|
|
63
63
|
return new BigNumber(String(number))
|
|
64
|
-
.times(
|
|
64
|
+
.times(getValueOfUnit(unit))
|
|
65
65
|
.toString(10)
|
|
66
66
|
}
|
package/src/ethereum/uiFuncs.ts
CHANGED
|
@@ -24,32 +24,23 @@ function isTxDataValid (txData) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export function generateTx (txData, data) {
|
|
27
|
-
|
|
28
|
-
isTxDataValid(txData)
|
|
27
|
+
isTxDataValid(txData)
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
const eTx = new Tx(rawTx)
|
|
42
|
-
|
|
43
|
-
eTx.sign(Buffer.from(txData.key, 'hex'))
|
|
44
|
-
rawTx.rawTx = JSON.stringify(rawTx)
|
|
45
|
-
rawTx.signedTx = '0x' + eTx.serialize().toString('hex')
|
|
46
|
-
rawTx.isError = false
|
|
47
|
-
return rawTx
|
|
48
|
-
} catch (e) {
|
|
49
|
-
return {
|
|
50
|
-
isError: true,
|
|
51
|
-
error: e
|
|
52
|
-
}
|
|
29
|
+
const rawTx: {[k: string]: any} = {
|
|
30
|
+
nonce: ethFuncs.sanitizeHex(data.nonce),
|
|
31
|
+
gasPrice: ethFuncs.sanitizeHex(
|
|
32
|
+
ethFuncs.addTinyMoreToGas(data.gasprice)),
|
|
33
|
+
gasLimit: ethFuncs.sanitizeHex(
|
|
34
|
+
ethFuncs.decimalToHex(txData.gasLimit)),
|
|
35
|
+
to: ethFuncs.sanitizeHex(txData.to),
|
|
36
|
+
value: ethFuncs.sanitizeHex(
|
|
37
|
+
ethFuncs.decimalToHex(etherUnits.toWei(txData.value, txData.unit))),
|
|
38
|
+
data: ethFuncs.sanitizeHex(txData.data)
|
|
53
39
|
}
|
|
40
|
+
const eTx = new Tx(rawTx)
|
|
41
|
+
|
|
42
|
+
eTx.sign(Buffer.from(txData.key, 'hex'))
|
|
43
|
+
rawTx.rawTx = JSON.stringify(rawTx)
|
|
44
|
+
return '0x' + eTx.serialize().toString('hex')
|
|
54
45
|
}
|
|
55
46
|
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as ethFuncs from './ethereum/ethFuncs' // Utilities to pass on
|
|
2
2
|
import * as memo from './memo'
|
|
3
|
+
import * as qr from './qr'
|
|
3
4
|
|
|
4
5
|
// Only required for blockie helper
|
|
5
6
|
import blockies from './blockies'
|
|
@@ -17,8 +18,8 @@ import ConnectionMgrAbstract from './connection'
|
|
|
17
18
|
import CustomizationAbstract from './customization'
|
|
18
19
|
import MessagingWalletAbstract from './wallet'
|
|
19
20
|
import BcReadAbstract from './bcRead'
|
|
20
|
-
import BcTransactionAbstract from './bcTransaction'
|
|
21
|
-
|
|
21
|
+
import { BcTransactionAbstract, transactionFactory } from './bcTransaction'
|
|
22
|
+
import localTransactionDefs from './config/transactions'
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
function createIcon (address: string | Wallet) {
|
|
@@ -39,6 +40,7 @@ abstract class AbstractJsc3l {
|
|
|
39
40
|
protected abstract persistentStore: t.IPersistentStore
|
|
40
41
|
|
|
41
42
|
localDefaultConf: {}
|
|
43
|
+
defaultTransactionDefs: []
|
|
42
44
|
|
|
43
45
|
endpoint: string
|
|
44
46
|
|
|
@@ -47,8 +49,9 @@ abstract class AbstractJsc3l {
|
|
|
47
49
|
_http: null | HttpAbstract
|
|
48
50
|
|
|
49
51
|
|
|
50
|
-
constructor (localDefaultConf?) {
|
|
52
|
+
constructor (localDefaultConf?, defaultTransactionDefs?) {
|
|
51
53
|
this.localDefaultConf = localDefaultConf || {}
|
|
54
|
+
this.defaultTransactionDefs = defaultTransactionDefs || localTransactionDefs
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
/**
|
|
@@ -163,23 +166,30 @@ abstract class AbstractJsc3l {
|
|
|
163
166
|
}
|
|
164
167
|
|
|
165
168
|
|
|
166
|
-
getBcTransaction (
|
|
169
|
+
getBcTransaction (
|
|
170
|
+
endpointUrl, contracts, transactionDefs
|
|
171
|
+
): BcTransactionAbstract {
|
|
167
172
|
const self = this
|
|
168
173
|
class BcTransaction extends BcTransactionAbstract {
|
|
169
174
|
ajaxReq = self.getAjaxReq(endpointUrl)
|
|
170
175
|
contracts = contracts
|
|
171
176
|
}
|
|
177
|
+
transactionFactory(transactionDefs, BcTransaction)
|
|
172
178
|
return new BcTransaction()
|
|
173
179
|
}
|
|
174
180
|
|
|
175
181
|
|
|
176
182
|
_currencyMgrPromises = {}
|
|
177
|
-
async getCurrencyMgr (
|
|
178
|
-
|
|
183
|
+
async getCurrencyMgr (
|
|
184
|
+
currencyName: string, endpointUrl?: string, repoUrl?: string,
|
|
185
|
+
transactionDefs?: any[],
|
|
186
|
+
) {
|
|
187
|
+
|
|
188
|
+
const key = JSON.stringify(Array.from(arguments))
|
|
179
189
|
|
|
180
190
|
if (!this._currencyMgrPromises[key]) {
|
|
181
191
|
this._currencyMgrPromises[key] =
|
|
182
|
-
this._getCurrencyMgr(currencyName, endpointUrl, repoUrl)
|
|
192
|
+
this._getCurrencyMgr(currencyName, endpointUrl, repoUrl, transactionDefs)
|
|
183
193
|
}
|
|
184
194
|
|
|
185
195
|
return await this._currencyMgrPromises[key]
|
|
@@ -188,7 +198,9 @@ abstract class AbstractJsc3l {
|
|
|
188
198
|
|
|
189
199
|
async _getCurrencyMgr (currencyName: string,
|
|
190
200
|
endpointUrl?: string,
|
|
191
|
-
repoUrl?: string
|
|
201
|
+
repoUrl?: string,
|
|
202
|
+
transactionDefs?: any[],
|
|
203
|
+
): Promise<any> {
|
|
192
204
|
if (!repoUrl) {
|
|
193
205
|
if (this.connection.repo) {
|
|
194
206
|
repoUrl = this.connection.repo
|
|
@@ -205,16 +217,19 @@ abstract class AbstractJsc3l {
|
|
|
205
217
|
}
|
|
206
218
|
}
|
|
207
219
|
|
|
220
|
+
transactionDefs = transactionDefs || localTransactionDefs
|
|
221
|
+
|
|
208
222
|
const config = await this.getConfig(repoUrl, currencyName)
|
|
209
223
|
const customization = this.getCustomization(config)
|
|
210
224
|
const contracts = [
|
|
211
225
|
customization.getContract1(),
|
|
212
|
-
customization.getContract2()
|
|
226
|
+
customization.getContract2(),
|
|
227
|
+
customization.getContract3()
|
|
213
228
|
]
|
|
214
229
|
|
|
215
|
-
const self = this
|
|
216
230
|
const wallet = this.getWallet(
|
|
217
|
-
|
|
231
|
+
endpointUrl, currencyName, customization.getUnlockUrl()
|
|
232
|
+
)
|
|
218
233
|
return {
|
|
219
234
|
// unlockWallet: (jsonData, password) => wallet.getWalletFromPrivKeyFile(jsonData, password),
|
|
220
235
|
jsc3l: this,
|
|
@@ -222,20 +237,19 @@ abstract class AbstractJsc3l {
|
|
|
222
237
|
ajaxReq: this.getAjaxReq(endpointUrl),
|
|
223
238
|
wallet: wallet,
|
|
224
239
|
bcRead: this.getBcRead(endpointUrl, contracts),
|
|
225
|
-
bcTransaction: this.getBcTransaction(
|
|
240
|
+
bcTransaction: this.getBcTransaction(
|
|
241
|
+
endpointUrl, contracts, transactionDefs
|
|
242
|
+
),
|
|
226
243
|
}
|
|
227
244
|
}
|
|
228
245
|
}
|
|
229
246
|
|
|
230
247
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
248
|
Object.assign(AbstractJsc3l.prototype, {
|
|
236
249
|
memo,
|
|
237
250
|
ethFuncs,
|
|
238
|
-
createIcon
|
|
251
|
+
createIcon,
|
|
252
|
+
qr,
|
|
239
253
|
})
|
|
240
254
|
|
|
241
255
|
|
|
@@ -257,7 +271,10 @@ abstract class IntegratedJsc3lAbstract extends AbstractJsc3l {
|
|
|
257
271
|
|
|
258
272
|
/**
|
|
259
273
|
* `customization` depends on a local configuration being available
|
|
260
|
-
* through a previous call to
|
|
274
|
+
* through a previous call to
|
|
275
|
+
* `this.connection.getConfJSON(..)`. Although as it has some
|
|
276
|
+
* fallback available, we need to be able to support being called
|
|
277
|
+
* even if no local conf is loaded yet.
|
|
261
278
|
*
|
|
262
279
|
* XXXvlab: We could cache the result with result of
|
|
263
280
|
* `connection.getLocalConf()` being the key.
|
|
@@ -265,11 +282,11 @@ abstract class IntegratedJsc3lAbstract extends AbstractJsc3l {
|
|
|
265
282
|
get customization (): CustomizationAbstract {
|
|
266
283
|
// XXXvlab: Probably don't need a module for that, as the configuration
|
|
267
284
|
// is always re-queried and quite small, we could cache-it in memory.
|
|
268
|
-
|
|
285
|
+
let localCfg = this.connection.getLocalConfJSON()
|
|
269
286
|
if (!localCfg) {
|
|
270
|
-
|
|
287
|
+
console.log('No local configuration available yet.')
|
|
288
|
+
localCfg = {}
|
|
271
289
|
}
|
|
272
|
-
|
|
273
290
|
return this.getCustomization(localCfg)
|
|
274
291
|
}
|
|
275
292
|
|
|
@@ -288,13 +305,13 @@ abstract class IntegratedJsc3lAbstract extends AbstractJsc3l {
|
|
|
288
305
|
*/
|
|
289
306
|
get wallet (): MessagingWalletAbstract["constructor"] {
|
|
290
307
|
if (!this.ajaxReq) {
|
|
291
|
-
throw Error('a connect() is required before accessing wallet')
|
|
308
|
+
throw new Error('a connect() is required before accessing wallet')
|
|
292
309
|
}
|
|
293
310
|
let localCfg: any
|
|
294
311
|
try {
|
|
295
312
|
localCfg = this.customization
|
|
296
313
|
} catch (e) {
|
|
297
|
-
throw Error('A local conf needs to be available before accessing wallet')
|
|
314
|
+
throw new Error('A local conf needs to be available before accessing wallet')
|
|
298
315
|
}
|
|
299
316
|
return this.getWallet(
|
|
300
317
|
this.ajaxReq.endpoint.baseUrl,
|
|
@@ -317,13 +334,13 @@ abstract class IntegratedJsc3lAbstract extends AbstractJsc3l {
|
|
|
317
334
|
*/
|
|
318
335
|
get bcRead (): BcReadAbstract {
|
|
319
336
|
if (!this.ajaxReq) {
|
|
320
|
-
throw Error('an init() is required before accessing bcRead')
|
|
337
|
+
throw new Error('an init() is required before accessing bcRead')
|
|
321
338
|
}
|
|
322
339
|
let localCfg: any
|
|
323
340
|
try {
|
|
324
341
|
localCfg = this.customization
|
|
325
342
|
} catch (e) {
|
|
326
|
-
throw Error('A local conf needs to be available before accessing wallet')
|
|
343
|
+
throw new Error('A local conf needs to be available before accessing wallet')
|
|
327
344
|
}
|
|
328
345
|
return this.getBcRead(
|
|
329
346
|
this.ajaxReq.endpoint.baseUrl,
|
|
@@ -346,17 +363,22 @@ abstract class IntegratedJsc3lAbstract extends AbstractJsc3l {
|
|
|
346
363
|
*/
|
|
347
364
|
get bcTransaction (): BcTransactionAbstract {
|
|
348
365
|
if (!this.ajaxReq) {
|
|
349
|
-
throw Error('an init() is required before accessing bcTransaction')
|
|
366
|
+
throw new Error('an init() is required before accessing bcTransaction')
|
|
350
367
|
}
|
|
351
368
|
let localCfg: any
|
|
352
369
|
try {
|
|
353
370
|
localCfg = this.customization
|
|
354
371
|
} catch (e) {
|
|
355
|
-
throw Error('A local conf needs to be available before accessing wallet')
|
|
372
|
+
throw new Error('A local conf needs to be available before accessing wallet')
|
|
356
373
|
}
|
|
357
374
|
return this.getBcTransaction(
|
|
358
375
|
this.ajaxReq.endpoint.baseUrl,
|
|
359
|
-
[
|
|
376
|
+
[
|
|
377
|
+
localCfg.getContract1(),
|
|
378
|
+
localCfg.getContract2(),
|
|
379
|
+
localCfg.getContract3(),
|
|
380
|
+
],
|
|
381
|
+
this.defaultTransactionDefs
|
|
360
382
|
)
|
|
361
383
|
}
|
|
362
384
|
|
package/src/qr.ts
CHANGED
|
@@ -1,20 +1,43 @@
|
|
|
1
1
|
import ethUtil from 'ethereumjs-util'
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
|
|
5
|
+
type Signature = {
|
|
6
|
+
v: string,
|
|
7
|
+
r: string,
|
|
8
|
+
s: string,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type QRDataRaw = {
|
|
12
|
+
address: string,
|
|
13
|
+
destinary: string,
|
|
14
|
+
begin: string,
|
|
15
|
+
end: string,
|
|
16
|
+
viewbalance: boolean,
|
|
17
|
+
viewoldtran: boolean,
|
|
18
|
+
message_key?: string,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type QRData = {
|
|
22
|
+
address: string,
|
|
23
|
+
destinary: string,
|
|
24
|
+
begin: Date,
|
|
25
|
+
end: Date,
|
|
26
|
+
viewbalance: boolean,
|
|
27
|
+
viewoldtran: boolean,
|
|
28
|
+
message_key?: string,
|
|
12
29
|
}
|
|
13
30
|
|
|
14
|
-
|
|
31
|
+
|
|
32
|
+
export type SignedQR = {data: QRDataRaw, signature: Signature}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
export function checkSignedQR (qrContent: SignedQR, intendedRecipientAddress) {
|
|
36
|
+
|
|
15
37
|
let hash: string
|
|
16
38
|
let publicSignKey: string
|
|
17
39
|
let receiverAddress: string
|
|
40
|
+
const { data, signature } = qrContent
|
|
18
41
|
try {
|
|
19
42
|
hash = ethUtil.sha3(JSON.stringify(data))
|
|
20
43
|
publicSignKey = ethUtil.ecrecover(
|
|
@@ -22,13 +45,64 @@ export function checkSignedQR (data, signature, intendedRecipientAddress) {
|
|
|
22
45
|
receiverAddress = ethUtil.bufferToHex(
|
|
23
46
|
ethUtil.publicToAddress(publicSignKey))
|
|
24
47
|
} catch (e) {
|
|
48
|
+
// XXXVlab: should probably use exceptions
|
|
25
49
|
return 'InvalidFormat'
|
|
26
50
|
}
|
|
27
51
|
|
|
28
|
-
if (receiverAddress !== data.address) {
|
|
29
|
-
|
|
52
|
+
if (receiverAddress !== data.address) {
|
|
53
|
+
return 'InvalidSignature'
|
|
54
|
+
}
|
|
55
|
+
if (data.destinary !== intendedRecipientAddress) {
|
|
56
|
+
return 'NotForYou'
|
|
57
|
+
}
|
|
30
58
|
if ((new Date(data.end)).getTime() < (new Date()).getTime()) {
|
|
31
59
|
return 'Expired'
|
|
32
60
|
}
|
|
33
|
-
return
|
|
61
|
+
return true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
export function makeSignedQRFragments (
|
|
66
|
+
qrContent: SignedQR,
|
|
67
|
+
fragmentCount: number
|
|
68
|
+
) {
|
|
69
|
+
|
|
70
|
+
const signatureId = qrContent.signature.s.substring(4, 8)
|
|
71
|
+
|
|
72
|
+
const qrString = JSON.stringify(qrContent)
|
|
73
|
+
const fragmentSize = Math.ceil(qrString.length / fragmentCount)
|
|
74
|
+
const fragments = {
|
|
75
|
+
full: qrString,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
for (let i = 0; i < fragmentCount; i++) {
|
|
79
|
+
fragments[i] = `FRAG_CR${signatureId}${i}${qrString.substring(
|
|
80
|
+
fragmentSize * i,
|
|
81
|
+
Math.min(fragmentSize * (i + 1), qrString.length)
|
|
82
|
+
)}`
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return fragments
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
export function makeSignedQRContent (obj: QRData, privKey: string): SignedQR {
|
|
90
|
+
const { begin, end } = obj
|
|
91
|
+
const formatDate = (date: Date) =>
|
|
92
|
+
`${date.getFullYear()}/${(date.getMonth()+1)}/${date.getDate()}`
|
|
93
|
+
const data = Object.assign(obj, {
|
|
94
|
+
begin: formatDate(begin),
|
|
95
|
+
end: formatDate(end),
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
const hash = ethUtil.sha3(JSON.stringify(data))
|
|
99
|
+
const { v, r, s } = ethUtil.ecsign(hash, privKey)
|
|
100
|
+
const signature = {
|
|
101
|
+
v,
|
|
102
|
+
r: '0x' + r.toString('hex'),
|
|
103
|
+
s: '0x' + s.toString('hex'),
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { data, signature }
|
|
107
|
+
|
|
34
108
|
}
|
package/src/rest/ajaxReq.ts
CHANGED
|
@@ -3,7 +3,6 @@ class URL {
|
|
|
3
3
|
static SERVER = 'api.php';
|
|
4
4
|
static ENROLL = 'enroll.php';
|
|
5
5
|
static TRANLIST = 'trnslist.php';
|
|
6
|
-
static TRANCHECK = 'api.php';
|
|
7
6
|
static EXPORTTRAN = 'export.php';
|
|
8
7
|
static GETCODE = 'getuid.php';
|
|
9
8
|
static GETADDRESS = 'getadd.php';
|
|
@@ -35,14 +34,12 @@ export default abstract class AjaxReqAbstract {
|
|
|
35
34
|
queuePost () {
|
|
36
35
|
const { data, resolve, reject } = this.pendingPosts[0]
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
resolve(data
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
reject(err)
|
|
45
|
-
}
|
|
37
|
+
this.endpoint.post(URL.SERVER, data).then(data => {
|
|
38
|
+
if (data.error) {
|
|
39
|
+
resolve(data)
|
|
40
|
+
}
|
|
41
|
+
resolve(data.data)
|
|
42
|
+
})
|
|
46
43
|
this.pendingPosts.splice(0, 1)
|
|
47
44
|
if (this.pendingPosts.length > 0) { this.queuePost() }
|
|
48
45
|
}
|
|
@@ -50,18 +47,7 @@ export default abstract class AjaxReqAbstract {
|
|
|
50
47
|
|
|
51
48
|
getBalance (addr) { return this.post({ balance: addr }) }
|
|
52
49
|
getTransactionData (addr) { return this.post({ txdata: addr }) }
|
|
53
|
-
|
|
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 }) }
|
|
50
|
+
sendTx (rawTx, more) { return this.post({ rawtx: rawTx, ...(more ?? {}) }) }
|
|
65
51
|
getEthCall (txobj) { return this.post({ ethCall: txobj }) }
|
|
66
52
|
|
|
67
53
|
getEthCallAt (txobj, blockNb) {
|
|
@@ -77,14 +63,6 @@ export default abstract class AjaxReqAbstract {
|
|
|
77
63
|
return this.endpoint.post(URL.ENROLL, { data: JSON.stringify(data) })
|
|
78
64
|
}
|
|
79
65
|
|
|
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
66
|
async getTransList (id, count, offset) {
|
|
89
67
|
// for some strange reasons, the answer is stringified 2 times,
|
|
90
68
|
// so we need to unpack each entry a second time.
|
|
@@ -92,16 +70,9 @@ export default abstract class AjaxReqAbstract {
|
|
|
92
70
|
return data.map((dataJSON) => JSON.parse(dataJSON))
|
|
93
71
|
}
|
|
94
72
|
|
|
95
|
-
|
|
96
|
-
|
|
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 })
|
|
73
|
+
async getExportTransList (id, start, end) {
|
|
74
|
+
const data = await this.endpoint.get(URL.EXPORTTRAN, { addr: id, start, end })
|
|
75
|
+
return data.map((dataJSON) => JSON.parse(dataJSON))
|
|
105
76
|
}
|
|
106
77
|
|
|
107
78
|
getCodesFromAddresses (addresses, currency, caller, signature) {
|
package/src/wallet.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import ethUtil from 'ethereumjs-util'
|
|
2
|
-
|
|
3
1
|
import AjaxReq from './rest/ajaxReq'
|
|
2
|
+
import {
|
|
3
|
+
checkSignedQR, SignedQR, makeSignedQRContent, makeSignedQRFragments
|
|
4
|
+
} from './qr'
|
|
4
5
|
import { shortenAddress, cipherMsg, decipherMsg } from './ethereum/cipher'
|
|
5
6
|
import Wallet from './ethereum/myetherwallet'
|
|
6
7
|
|
|
@@ -15,7 +16,8 @@ export default abstract class MessagingWalletAbstract extends Wallet {
|
|
|
15
16
|
|
|
16
17
|
public static async createWallet (this: { new(): MessagingWalletAbstract }) {
|
|
17
18
|
const wallet = new this()
|
|
18
|
-
|
|
19
|
+
await wallet.ensureWalletMessageKey()
|
|
20
|
+
return wallet
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
private publishMessageKey () {
|
|
@@ -49,7 +51,7 @@ export default abstract class MessagingWalletAbstract extends Wallet {
|
|
|
49
51
|
const remoteKey = await this.ajaxReq.getMessageKey(
|
|
50
52
|
this.getAddressString(), true)
|
|
51
53
|
const walletMessageKey = this?.message_key
|
|
52
|
-
if (remoteKey.public_message_key !== undefined) {
|
|
54
|
+
if (typeof remoteKey.public_message_key !== 'undefined') {
|
|
53
55
|
this.message_key = {
|
|
54
56
|
pub: remoteKey.public_message_key,
|
|
55
57
|
priv: remoteKey.private_message_key,
|
|
@@ -94,7 +96,7 @@ export default abstract class MessagingWalletAbstract extends Wallet {
|
|
|
94
96
|
const newKey = Wallet.generate(false)
|
|
95
97
|
const mPub = newKey.getPublicKeyString()
|
|
96
98
|
const mPriv = newKey.getPrivateKeyString()
|
|
97
|
-
return { pub: mPub, priv: cipherMsg(this.
|
|
99
|
+
return { pub: mPub, priv: cipherMsg(this.getPublicKeyString(), mPriv) }
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
public messageKeysFromCrypted (cipheredKey) {
|
|
@@ -120,10 +122,14 @@ export default abstract class MessagingWalletAbstract extends Wallet {
|
|
|
120
122
|
})
|
|
121
123
|
}
|
|
122
124
|
|
|
123
|
-
public enrollAddress (
|
|
124
|
-
return this.ajaxReq.
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
public enrollAddress (id, token) {
|
|
126
|
+
return this.ajaxReq.enrollPost({
|
|
127
|
+
id,
|
|
128
|
+
token,
|
|
129
|
+
currency: this.currencyName,
|
|
130
|
+
// XXXvlab: Yes, typo is intentional here (in PHP API):
|
|
131
|
+
adresse: this.getAddressString(),
|
|
132
|
+
})
|
|
127
133
|
}
|
|
128
134
|
|
|
129
135
|
public requestUnlock () {
|
|
@@ -147,54 +153,38 @@ export default abstract class MessagingWalletAbstract extends Wallet {
|
|
|
147
153
|
}
|
|
148
154
|
}
|
|
149
155
|
|
|
150
|
-
|
|
151
156
|
//
|
|
152
|
-
// QR
|
|
157
|
+
// QR Code helpers
|
|
153
158
|
//
|
|
154
159
|
|
|
155
|
-
public
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
160
|
+
public makeSignedQRContent (obj, pubKey: string | null) {
|
|
161
|
+
return makeSignedQRContent({
|
|
162
|
+
server: this.currencyName,
|
|
163
|
+
address: this.getAddressString(),
|
|
164
|
+
...obj,
|
|
165
|
+
...pubKey && {
|
|
166
|
+
message_key: cipherMsg(pubKey, this.messageKeysFromWallet())
|
|
167
|
+
},
|
|
168
|
+
}, this.privKey)
|
|
161
169
|
}
|
|
162
170
|
|
|
163
|
-
public
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
`${begin.getFullYear()}/${begin.getMonth()}/${begin.getDate()}`
|
|
172
|
-
const objContent = Object.assign(obj, {
|
|
173
|
-
address: this.getAddressString(),
|
|
174
|
-
begin: formatDate(begin),
|
|
175
|
-
end: formatDate(end)
|
|
176
|
-
})
|
|
171
|
+
public makeSignedQRFragments (
|
|
172
|
+
obj, fragmentCount: number, pubKey: string | null
|
|
173
|
+
) {
|
|
174
|
+
return makeSignedQRFragments(
|
|
175
|
+
this.makeSignedQRContent(obj, pubKey),
|
|
176
|
+
fragmentCount,
|
|
177
|
+
)
|
|
178
|
+
}
|
|
177
179
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
signature: {
|
|
185
|
-
v: signature.v,
|
|
186
|
-
r: '0x' + signature.r.toString('hex'),
|
|
187
|
-
s: '0x' + signature.s.toString('hex')
|
|
188
|
-
}
|
|
189
|
-
})
|
|
180
|
+
public checkSignedQRFromString (qrString: string) {
|
|
181
|
+
let qrContent: SignedQR
|
|
182
|
+
try {
|
|
183
|
+
qrContent = JSON.parse(qrString)
|
|
184
|
+
} catch (e) {
|
|
185
|
+
return 'InvalidFormat'
|
|
190
186
|
}
|
|
187
|
+
return checkSignedQR(qrContent, this.getAddressString())
|
|
191
188
|
}
|
|
192
189
|
|
|
193
190
|
}
|
|
194
|
-
|
|
195
|
-
// // TODO: What to do with this validateEnrollment
|
|
196
|
-
// public static validateEnrollment (codeId, signature) {
|
|
197
|
-
// return this.ajaxReq.validateEnrollmentLetter(
|
|
198
|
-
// codeId, this.currencyName, signature)
|
|
199
|
-
// }
|
|
200
|
-
|