@@ -7,14 +7,15 @@ import {
7
7
} from '@0x/subproviders' ;
8
8
import P from 'bluebird' ;
9
9
import phin from 'phin' ;
10
- import { union , compact } from 'lodash' ;
10
+ import { union , compact , chunk } from 'lodash' ;
11
11
import { Context } from './Context' ;
12
12
import { getInjectedProvider } from './browserUtils' ;
13
- import { ErrorCode , TransactionSpeed } from './types' ;
13
+ import { ErrorCode , TransactionSpeed , Version } from './types' ;
14
14
import { SecurityToken , Wallet } from './entities' ;
15
15
import { ReserveSecurityToken } from './procedures' ;
16
16
import { PolymathError } from './PolymathError' ;
17
17
import { PolymathBase } from './PolymathBase' ;
18
+ import { convertVersionToEnum } from './utils' ;
18
19
19
20
interface PolymathNetworkParams {
20
21
polymathRegistryAddress ?: string ;
@@ -36,16 +37,10 @@ interface Connect {
36
37
( params : PolymathNetworkNodeParams ) : Promise < Polymath > ;
37
38
}
38
39
39
- /**
40
- * @param symbol Security Token symbol
41
- */
42
40
interface SymbolParams {
43
41
symbol : string ;
44
42
}
45
43
46
- /**
47
- * @param address Address of the Security Token contract
48
- */
49
44
interface AddressParams {
50
45
address : string ;
51
46
}
@@ -56,6 +51,13 @@ interface GetSecurityToken {
56
51
( params : string ) : Promise < SecurityToken > ;
57
52
}
58
53
54
+ /**
55
+ * @hidden
56
+ * Estimates the gas price to use in transactions
57
+ *
58
+ * @param speed - speed at which transactions should be mined
59
+ * @param basePrice - base to multiply depending on the desired speed
60
+ */
59
61
const calculateGasPrice = ( speed : TransactionSpeed , basePrice : BigNumber ) => {
60
62
let result = basePrice ;
61
63
switch ( speed ) {
@@ -85,17 +87,35 @@ const calculateGasPrice = (speed: TransactionSpeed, basePrice: BigNumber) => {
85
87
return result ;
86
88
} ;
87
89
90
+ /**
91
+ * Main entry point of the Polymath SDK
92
+ */
88
93
export class Polymath {
89
94
public isUnsupported : boolean = false ;
90
95
91
96
public isConnected : boolean = false ;
92
97
93
98
private context : Context = { } as Context ;
94
99
100
+ /**
101
+ * Connects the client to an Ethereum node
102
+ */
95
103
public connect : Connect = async ( {
104
+ /**
105
+ * address of a custom Polymath Registry contract. Defaults to the one deployed by Polymath
106
+ */
96
107
polymathRegistryAddress,
108
+ /**
109
+ * URL of an Ethereum node. If using Metamask, this parameter can be ignored
110
+ */
97
111
providerUrl,
112
+ /**
113
+ * private key of the wallet that will sign transactions. If using Metamask, this parameter can be ignored
114
+ */
98
115
privateKey,
116
+ /**
117
+ * desired transaction speed. More gas is spent if a faster speed is chosen
118
+ */
99
119
speed = TransactionSpeed . Fast ,
100
120
} : ConnectParams ) => {
101
121
let provider : Provider ;
@@ -150,8 +170,8 @@ export class Polymath {
150
170
/**
151
171
* Reserve a Security Token
152
172
*
153
- * @param symbol Security Token symbol
154
- * @param owner address that will own the reservation (optional, use this if you want to reserve a token on behalf of someone else)
173
+ * @param symbol - Security Token symbol
174
+ * @param owner - address that will own the reservation (optional, use this if you want to reserve a token on behalf of someone else)
155
175
*/
156
176
public reserveSecurityToken = async ( args : { symbol : string ; owner ?: string } ) => {
157
177
const procedure = new ReserveSecurityToken ( args , this . context ) ;
@@ -163,7 +183,7 @@ export class Polymath {
163
183
* Retrieve all Security Token Reservations currently owned by an issuer. This includes
164
184
* Security Tokens that have already been launched
165
185
*
166
- * @param owner issuer's address (defaults to current address)
186
+ * @param owner - issuer's address (defaults to current address)
167
187
*/
168
188
public getSecurityTokenReservations = async ( args ?: { owner : string } ) => {
169
189
const {
@@ -179,23 +199,23 @@ export class Polymath {
179
199
180
200
const symbols = await contractWrappers . securityTokenRegistry . getTickersByOwner ( { owner } ) ;
181
201
182
- const reservations = await P . map ( symbols , symbol => {
183
- return P . resolve ( this . getSecurityTokenReservation ( { symbol } ) ) . catch ( PolymathError , err => {
202
+ const reservations = await P . map ( symbols , symbol =>
203
+ P . resolve ( this . getSecurityTokenReservation ( { symbol } ) ) . catch ( PolymathError , err => {
184
204
if ( err . code === ErrorCode . FetcherValidationError ) {
185
205
return undefined ;
186
206
}
187
207
188
208
throw err ;
189
- } ) ;
190
- } ) ;
209
+ } )
210
+ ) ;
191
211
192
212
return compact ( reservations ) ;
193
213
} ;
194
214
195
215
/**
196
216
* Retrieve a Security Token Reservation by symbol or UUID
197
217
*
198
- * @param symbol Security Token symbol
218
+ * @param symbol - Security Token symbol
199
219
*/
200
220
public getSecurityTokenReservation = async ( args : { symbol : string } | string ) => {
201
221
let uid : string ;
@@ -214,7 +234,12 @@ export class Polymath {
214
234
* Retrieve all launched Security Tokens related to a wallet.
215
235
* This includes tokens owned by the wallet and tokens for which the wallet holds some role
216
236
*
217
- * @param walletAddress defaults to current address
237
+ * **Ignores** all tokens with version 2.0 or lower
238
+ *
239
+ * NOTE: This method is extremely slow if the wallet in question owns more than 20 tokens.
240
+ * If that is your case, use [[getSecurityTokenSymbols]]
241
+ *
242
+ * @param walletAddress - defaults to current address
218
243
*/
219
244
public getSecurityTokens = async ( args ?: { walletAddress : string } ) => {
220
245
const {
@@ -233,13 +258,62 @@ export class Polymath {
233
258
contractWrappers . securityTokenRegistry . getTokensByDelegate ( walletAddress ) ,
234
259
] ) ;
235
260
236
- return P . map ( union ( ownedAddresses , delegatedAddresses ) , address => {
237
- return this . getSecurityToken ( { address } ) ;
261
+ const addressChunks = chunk ( union ( ownedAddresses , delegatedAddresses ) , 10 ) ;
262
+
263
+ const result = await P . mapSeries ( addressChunks , addresses =>
264
+ P . map ( addresses , address =>
265
+ P . resolve ( this . getSecurityToken ( { address } ) ) . catch ( PolymathError , err => {
266
+ if ( err . code === ErrorCode . IncorrectVersion ) {
267
+ return undefined ;
268
+ }
269
+
270
+ throw err ;
271
+ } )
272
+ )
273
+ ) ;
274
+
275
+ return compact ( union ( ...result ) ) ;
276
+ } ;
277
+
278
+ /**
279
+ * Retrieve the symbols of all launched Security Tokens related to a wallet.
280
+ * This includes tokens owned by the wallet and tokens for which the wallet holds some role
281
+ *
282
+ * **Includes** token symbols for tokens with version 2.0 or lower
283
+ *
284
+ * @param walletAddress - defaults to current address
285
+ */
286
+ public getSecurityTokenSymbols = async ( args ?: { walletAddress : string } ) => {
287
+ const {
288
+ context : { currentWallet, contractWrappers } ,
289
+ } = this ;
290
+
291
+ let walletAddress : string ;
292
+ if ( args ) {
293
+ ( { walletAddress } = args ) ;
294
+ } else {
295
+ walletAddress = await currentWallet . address ( ) ;
296
+ }
297
+
298
+ const [ ownedTickers , delegatedAddresses ] = await Promise . all ( [
299
+ contractWrappers . securityTokenRegistry . getTickersByOwner ( { owner : walletAddress } ) ,
300
+ contractWrappers . securityTokenRegistry . getTokensByDelegate ( walletAddress ) ,
301
+ ] ) ;
302
+
303
+ const delegateTickers = await P . map ( delegatedAddresses , async address => {
304
+ const details = await contractWrappers . securityTokenRegistry . getSecurityTokenData ( {
305
+ securityTokenAddress : address ,
306
+ } ) ;
307
+ return details . ticker ;
238
308
} ) ;
309
+
310
+ return union ( ownedTickers , delegateTickers ) ;
239
311
} ;
240
312
241
313
/**
242
314
* Retrieve a security token by symbol, address or UUID
315
+ *
316
+ * @throws if the Security Token is v2.0 or lower
243
317
*/
244
318
public getSecurityToken : GetSecurityToken = async (
245
319
args :
@@ -253,6 +327,7 @@ export class Polymath {
253
327
) => {
254
328
let uid : string ;
255
329
330
+ // eslint-disable-next-line require-jsdoc
256
331
const isAddressArgs = ( a : any ) : a is { address : string } => {
257
332
return typeof a . address === 'string' ;
258
333
} ;
@@ -264,13 +339,17 @@ export class Polymath {
264
339
} ,
265
340
} = this ;
266
341
342
+ let securityToken ;
343
+
267
344
// fetch by UUID
268
345
if ( typeof args === 'string' ) {
346
+ const { symbol } = SecurityToken . unserialize ( args ) ;
347
+ securityToken = await tokenFactory . getSecurityTokenInstanceFromTicker ( symbol ) ;
269
348
uid = args ;
270
349
} else if ( isAddressArgs ( args ) ) {
271
350
const { address } = args ;
272
351
try {
273
- const securityToken = await tokenFactory . getSecurityTokenInstanceFromAddress ( address ) ;
352
+ securityToken = await tokenFactory . getSecurityTokenInstanceFromAddress ( address ) ;
274
353
275
354
const symbol = await securityToken . symbol ( ) ;
276
355
uid = SecurityToken . generateId ( { symbol } ) ;
@@ -281,16 +360,34 @@ export class Polymath {
281
360
} ) ;
282
361
}
283
362
} else {
363
+ securityToken = await tokenFactory . getSecurityTokenInstanceFromTicker ( args . symbol ) ;
284
364
uid = SecurityToken . generateId ( args ) ;
285
365
}
286
366
367
+ const versionArray = await securityToken . getVersion ( ) ;
368
+
369
+ const versionError = new PolymathError ( {
370
+ code : ErrorCode . IncorrectVersion ,
371
+ message : 'Security Token v2.0 not supported' ,
372
+ } ) ;
373
+
374
+ try {
375
+ const version = convertVersionToEnum ( versionArray ) ;
376
+
377
+ if ( ! [ Version . V3_0_0 , Version . V3_1_0 ] . includes ( version ) ) {
378
+ throw versionError ;
379
+ }
380
+ } catch ( err ) {
381
+ throw versionError ;
382
+ }
383
+
287
384
return factories . securityTokenFactory . fetch ( uid ) ;
288
385
} ;
289
386
290
387
/**
291
388
* Check if a token symbol (ticker) is available for reservation
292
389
*
293
- * @param symbol security token symbol for which to check availability
390
+ * @param symbol - Security Token symbol for which to check availability
294
391
*/
295
392
public isSymbolAvailable = async ( args : { symbol : string } ) => {
296
393
const { symbol } = args ;
@@ -301,7 +398,7 @@ export class Polymath {
301
398
/**
302
399
* Check if a token follows the ERC20 standard
303
400
*
304
- * @param address address of the token contract
401
+ * @param address - address of the token contract
305
402
*/
306
403
public isValidErc20 = async ( args : { address : string } ) => {
307
404
const { address } = args ;
@@ -315,7 +412,7 @@ export class Polymath {
315
412
/**
316
413
* Retrieve a Wallet by address
317
414
*
318
- * @param address wallet address
415
+ * @param address - wallet address
319
416
*/
320
417
public getWallet = ( args : { address : string } ) : Wallet => {
321
418
const { address } = args ;
@@ -356,17 +453,20 @@ export class Polymath {
356
453
} ;
357
454
358
455
/**
456
+ * @hidden
359
457
* Obtains a recommended default gas price based on the desired transaction speed
360
458
*
361
- * On mainnet, the gas price is fetched from ethgasstation.info (most reliable)\
362
- * On testnets (or if ethgasstation is unavailable), the gas price is fetched from the network itself via eth_gasPrice\
459
+ * On mainnet, the gas price is fetched from ethgasstation.info (most reliable)
460
+ *
461
+ * On testnets (or if ethgasstation is unavailable), the gas price is fetched from the network itself via eth_gasPrice
363
462
* If everything else fails, we use a base default of 1 GWEI
364
463
*
365
- * On the last two cases, the obtained price is multiplied by a factor depending on the speed:\
366
- * Slow = x1\
367
- * Medium = x2\
368
- * Fast = x3\
369
- * Fastest = x5
464
+ * On the last two cases, the obtained price is multiplied by a factor depending on the speed:
465
+ *
466
+ * - Slow = x1
467
+ * - Medium = x2
468
+ * - Fast = x3
469
+ * - Fastest = x5
370
470
*/
371
471
private getGasPrice = async ( {
372
472
provider,
0 commit comments