Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/beta' into feat/improve-procedur…
Browse files Browse the repository at this point in the history
…e-tests
  • Loading branch information
Victor Wiebe committed Feb 5, 2020
2 parents 8fc244e + 1da5bc5 commit 5272c17
Show file tree
Hide file tree
Showing 32 changed files with 364 additions and 101 deletions.
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@polymathnetwork/sdk",
"version": "2.0.1-beta.118",
"version": "2.0.1-beta.120",
"description": "A Javascript SDK for interacting with the Polymath network for the browser and Node.js",
"bugs": {
"url": "https://github.com/PolymathNetwork/polymath-sdk/issues"
Expand Down Expand Up @@ -53,7 +53,7 @@
"@0x/subproviders": "^3.0.2",
"@babel/polyfill": "^7.0.0",
"@babel/runtime": "^7.2.0",
"@polymathnetwork/contract-wrappers": "3.0.0-beta.59",
"@polymathnetwork/contract-wrappers": "3.0.0-beta.61",
"@types/sinon": "^7.5.0",
"bluebird": "^3.5.5",
"ethereum-address": "^0.0.4",
Expand Down Expand Up @@ -98,7 +98,6 @@
"eslint-config-prettier": "^4.1.0",
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-jest": "^22.15.0",
"eslint-plugin-tsdoc": "^0.2.0",
"husky": "^1.3.1",
"jest": "^24.1.0",
"lint-staged": "^8.1.5",
Expand Down
1 change: 1 addition & 0 deletions src/Context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export class Context {

public factories: Factories;

// eslint-disable-next-line require-jsdoc
constructor(params: ConstructorParams) {
const { contractWrappers } = params;

Expand Down
160 changes: 130 additions & 30 deletions src/Polymath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import {
} from '@0x/subproviders';
import P from 'bluebird';
import phin from 'phin';
import { union, compact } from 'lodash';
import { union, compact, chunk } from 'lodash';
import { Context } from './Context';
import { getInjectedProvider } from './browserUtils';
import { ErrorCode, TransactionSpeed } from './types';
import { ErrorCode, TransactionSpeed, Version } from './types';
import { SecurityToken, Wallet } from './entities';
import { ReserveSecurityToken } from './procedures';
import { PolymathError } from './PolymathError';
import { PolymathBase } from './PolymathBase';
import { convertVersionToEnum } from './utils';

interface PolymathNetworkParams {
polymathRegistryAddress?: string;
Expand All @@ -36,16 +37,10 @@ interface Connect {
(params: PolymathNetworkNodeParams): Promise<Polymath>;
}

/**
* @param symbol Security Token symbol
*/
interface SymbolParams {
symbol: string;
}

/**
* @param address Address of the Security Token contract
*/
interface AddressParams {
address: string;
}
Expand All @@ -56,6 +51,13 @@ interface GetSecurityToken {
(params: string): Promise<SecurityToken>;
}

/**
* @hidden
* Estimates the gas price to use in transactions
*
* @param speed - speed at which transactions should be mined
* @param basePrice - base to multiply depending on the desired speed
*/
const calculateGasPrice = (speed: TransactionSpeed, basePrice: BigNumber) => {
let result = basePrice;
switch (speed) {
Expand Down Expand Up @@ -85,17 +87,35 @@ const calculateGasPrice = (speed: TransactionSpeed, basePrice: BigNumber) => {
return result;
};

/**
* Main entry point of the Polymath SDK
*/
export class Polymath {
public isUnsupported: boolean = false;

public isConnected: boolean = false;

private context: Context = {} as Context;

/**
* Connects the client to an Ethereum node
*/
public connect: Connect = async ({
/**
* address of a custom Polymath Registry contract. Defaults to the one deployed by Polymath
*/
polymathRegistryAddress,
/**
* URL of an Ethereum node. If using Metamask, this parameter can be ignored
*/
providerUrl,
/**
* private key of the wallet that will sign transactions. If using Metamask, this parameter can be ignored
*/
privateKey,
/**
* desired transaction speed. More gas is spent if a faster speed is chosen
*/
speed = TransactionSpeed.Fast,
}: ConnectParams) => {
let provider: Provider;
Expand Down Expand Up @@ -150,8 +170,8 @@ export class Polymath {
/**
* Reserve a Security Token
*
* @param symbol Security Token symbol
* @param owner address that will own the reservation (optional, use this if you want to reserve a token on behalf of someone else)
* @param symbol - Security Token symbol
* @param owner - address that will own the reservation (optional, use this if you want to reserve a token on behalf of someone else)
*/
public reserveSecurityToken = async (args: { symbol: string; owner?: string }) => {
const procedure = new ReserveSecurityToken(args, this.context);
Expand All @@ -163,7 +183,7 @@ export class Polymath {
* Retrieve all Security Token Reservations currently owned by an issuer. This includes
* Security Tokens that have already been launched
*
* @param owner issuer's address (defaults to current address)
* @param owner - issuer's address (defaults to current address)
*/
public getSecurityTokenReservations = async (args?: { owner: string }) => {
const {
Expand All @@ -179,23 +199,23 @@ export class Polymath {

const symbols = await contractWrappers.securityTokenRegistry.getTickersByOwner({ owner });

const reservations = await P.map(symbols, symbol => {
return P.resolve(this.getSecurityTokenReservation({ symbol })).catch(PolymathError, err => {
const reservations = await P.map(symbols, symbol =>
P.resolve(this.getSecurityTokenReservation({ symbol })).catch(PolymathError, err => {
if (err.code === ErrorCode.FetcherValidationError) {
return undefined;
}

throw err;
});
});
})
);

return compact(reservations);
};

/**
* Retrieve a Security Token Reservation by symbol or UUID
*
* @param symbol Security Token symbol
* @param symbol - Security Token symbol
*/
public getSecurityTokenReservation = async (args: { symbol: string } | string) => {
let uid: string;
Expand All @@ -214,7 +234,12 @@ export class Polymath {
* Retrieve all launched Security Tokens related to a wallet.
* This includes tokens owned by the wallet and tokens for which the wallet holds some role
*
* @param walletAddress defaults to current address
* **Ignores** all tokens with version 2.0 or lower
*
* NOTE: This method is extremely slow if the wallet in question owns more than 20 tokens.
* If that is your case, use [[getSecurityTokenSymbols]]
*
* @param walletAddress - defaults to current address
*/
public getSecurityTokens = async (args?: { walletAddress: string }) => {
const {
Expand All @@ -233,13 +258,62 @@ export class Polymath {
contractWrappers.securityTokenRegistry.getTokensByDelegate(walletAddress),
]);

return P.map(union(ownedAddresses, delegatedAddresses), address => {
return this.getSecurityToken({ address });
const addressChunks = chunk(union(ownedAddresses, delegatedAddresses), 10);

const result = await P.mapSeries(addressChunks, addresses =>
P.map(addresses, address =>
P.resolve(this.getSecurityToken({ address })).catch(PolymathError, err => {
if (err.code === ErrorCode.IncorrectVersion) {
return undefined;
}

throw err;
})
)
);

return compact(union(...result));
};

/**
* Retrieve the symbols of all launched Security Tokens related to a wallet.
* This includes tokens owned by the wallet and tokens for which the wallet holds some role
*
* **Includes** token symbols for tokens with version 2.0 or lower
*
* @param walletAddress - defaults to current address
*/
public getSecurityTokenSymbols = async (args?: { walletAddress: string }) => {
const {
context: { currentWallet, contractWrappers },
} = this;

let walletAddress: string;
if (args) {
({ walletAddress } = args);
} else {
walletAddress = await currentWallet.address();
}

const [ownedTickers, delegatedAddresses] = await Promise.all([
contractWrappers.securityTokenRegistry.getTickersByOwner({ owner: walletAddress }),
contractWrappers.securityTokenRegistry.getTokensByDelegate(walletAddress),
]);

const delegateTickers = await P.map(delegatedAddresses, async address => {
const details = await contractWrappers.securityTokenRegistry.getSecurityTokenData({
securityTokenAddress: address,
});
return details.ticker;
});

return union(ownedTickers, delegateTickers);
};

/**
* Retrieve a security token by symbol, address or UUID
*
* @throws if the Security Token is v2.0 or lower
*/
public getSecurityToken: GetSecurityToken = async (
args:
Expand All @@ -253,6 +327,7 @@ export class Polymath {
) => {
let uid: string;

// eslint-disable-next-line require-jsdoc
const isAddressArgs = (a: any): a is { address: string } => {
return typeof a.address === 'string';
};
Expand All @@ -264,13 +339,17 @@ export class Polymath {
},
} = this;

let securityToken;

// fetch by UUID
if (typeof args === 'string') {
const { symbol } = SecurityToken.unserialize(args);
securityToken = await tokenFactory.getSecurityTokenInstanceFromTicker(symbol);
uid = args;
} else if (isAddressArgs(args)) {
const { address } = args;
try {
const securityToken = await tokenFactory.getSecurityTokenInstanceFromAddress(address);
securityToken = await tokenFactory.getSecurityTokenInstanceFromAddress(address);

const symbol = await securityToken.symbol();
uid = SecurityToken.generateId({ symbol });
Expand All @@ -281,16 +360,34 @@ export class Polymath {
});
}
} else {
securityToken = await tokenFactory.getSecurityTokenInstanceFromTicker(args.symbol);
uid = SecurityToken.generateId(args);
}

const versionArray = await securityToken.getVersion();

const versionError = new PolymathError({
code: ErrorCode.IncorrectVersion,
message: 'Security Token v2.0 not supported',
});

try {
const version = convertVersionToEnum(versionArray);

if (![Version.V3_0_0, Version.V3_1_0].includes(version)) {
throw versionError;
}
} catch (err) {
throw versionError;
}

return factories.securityTokenFactory.fetch(uid);
};

/**
* Check if a token symbol (ticker) is available for reservation
*
* @param symbol security token symbol for which to check availability
* @param symbol - Security Token symbol for which to check availability
*/
public isSymbolAvailable = async (args: { symbol: string }) => {
const { symbol } = args;
Expand All @@ -301,7 +398,7 @@ export class Polymath {
/**
* Check if a token follows the ERC20 standard
*
* @param address address of the token contract
* @param address - address of the token contract
*/
public isValidErc20 = async (args: { address: string }) => {
const { address } = args;
Expand All @@ -315,7 +412,7 @@ export class Polymath {
/**
* Retrieve a Wallet by address
*
* @param address wallet address
* @param address - wallet address
*/
public getWallet = (args: { address: string }): Wallet => {
const { address } = args;
Expand Down Expand Up @@ -356,17 +453,20 @@ export class Polymath {
};

/**
* @hidden
* Obtains a recommended default gas price based on the desired transaction speed
*
* On mainnet, the gas price is fetched from ethgasstation.info (most reliable)\
* On testnets (or if ethgasstation is unavailable), the gas price is fetched from the network itself via eth_gasPrice\
* On mainnet, the gas price is fetched from ethgasstation.info (most reliable)
*
* On testnets (or if ethgasstation is unavailable), the gas price is fetched from the network itself via eth_gasPrice
* If everything else fails, we use a base default of 1 GWEI
*
* On the last two cases, the obtained price is multiplied by a factor depending on the speed:\
* Slow = x1\
* Medium = x2\
* Fast = x3\
* Fastest = x5
* On the last two cases, the obtained price is multiplied by a factor depending on the speed:
*
* - Slow = x1
* - Medium = x2
* - Fast = x3
* - Fastest = x5
*/
private getGasPrice = async ({
provider,
Expand Down
4 changes: 4 additions & 0 deletions src/PolymathError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ export const ErrorMessagesPerCode: {
'You must install the Metamask browser extension if attempting to use Polymath SDK from the browser',
};

/**
* Wraps an error to give more information about it's type
*/
export class PolymathError extends Error {
public code: ErrorCode;

// eslint-disable-next-line require-jsdoc
constructor({ message, code }: { message?: string; code: ErrorCode }) {
super(message || ErrorMessagesPerCode[code] || `Unknown error, code: ${code}`);
// eslint:disable-next-line
Expand Down
Loading

0 comments on commit 5272c17

Please sign in to comment.