Skip to content

Commit

Permalink
feat: refine handling of custom currencies in Tiered STO
Browse files Browse the repository at this point in the history
  • Loading branch information
monitz87 committed Dec 16, 2019
1 parent 6beffbc commit c31ce47
Show file tree
Hide file tree
Showing 14 changed files with 414 additions and 92 deletions.
6 changes: 3 additions & 3 deletions src/PolymathBase.ts
Expand Up @@ -13,7 +13,6 @@ import {
SecurityToken,
ModuleType,
BigNumber,
isERC20DividendCheckpoint,
BlacklistTransferManager,
LockUpTransferManager,
VestingEscrowWallet,
Expand All @@ -33,11 +32,12 @@ import {
isVolumeRestrictionTransferManager,
isRestrictedPartialSaleTransferManager,
} from '@polymathnetwork/contract-wrappers';
import { range, flatten, includes } from 'lodash';
import { range, flatten } from 'lodash';
import P from 'bluebird';
import semver from 'semver';
import { PolymathError } from './PolymathError';
import { ErrorCode, Module, SecurityTokenRole } from './types';
import { ZERO_ADDRESS } from './utils/constants';

interface GetModuleAddressesByNameParams {
symbol: string;
Expand Down Expand Up @@ -266,7 +266,7 @@ export class PolymathBase extends PolymathAPI {
if (isUSDTieredSTO(module)) {
if (isUSDTieredSTO_3_0_0(module)) {
const wallet = await module.treasuryWallet();
return wallet === '0x0000000000000000000000000000000000000000' ? defaultWallet : wallet;
return wallet === ZERO_ADDRESS ? defaultWallet : wallet;
}
}

Expand Down
115 changes: 96 additions & 19 deletions src/entities/SecurityToken/Issuance/Offerings.ts
@@ -1,12 +1,98 @@
import { BigNumber, ModuleName } from '@polymathnetwork/contract-wrappers';
import { includes } from 'lodash';
import { SubModule } from '../SubModule';
import { StoTier, Currency, StoType, ErrorCode } from '../../../types';
import {
StoTier,
Currency,
StoType,
ErrorCode,
CustomCurrency,
LaunchTieredStoProcedureArgs,
Omit,
} from '../../../types';
import { LaunchSimpleSto, LaunchTieredSto } from '../../../procedures';
import { SimpleSto, TieredSto, Sto } from '../..';
import { PolymathError } from '../../../PolymathError';
import { TransactionQueue } from '../../TransactionQueue';

interface GetSto {
interface LaunchTieredStoParams {
startDate: Date;
endDate: Date;
tiers: StoTier[];
nonAccreditedInvestmentLimit: BigNumber;
minimumInvestment: BigNumber;
currencies: Currency[];
raisedFundsWallet: string;
unsoldTokensWallet: string;
stableCoinAddresses: string[];
customCurrency?: Partial<CustomCurrency>;
allowPreIssuance?: boolean;
}

type OnlyEth =
| [Currency.ETH]
| [Currency.StableCoin, Currency.ETH]
| [Currency.ETH, Currency.StableCoin];
type OnlyPoly =
| [Currency.POLY]
| [Currency.StableCoin, Currency.POLY]
| [Currency.POLY, Currency.StableCoin];
type EthAndPoly =
| [Currency.ETH, Currency.POLY]
| [Currency.POLY, Currency.ETH]
| [Currency.StableCoin, Currency.ETH, Currency.POLY]
| [Currency.ETH, Currency.StableCoin, Currency.POLY]
| [Currency.ETH, Currency.POLY, Currency.StableCoin]
| [Currency.StableCoin, Currency.POLY, Currency.ETH]
| [Currency.POLY, Currency.StableCoin, Currency.ETH]
| [Currency.POLY, Currency.ETH, Currency.StableCoin];

interface LaunchTieredStoNoCustomCurrencyParams
extends Omit<LaunchTieredStoParams, 'customCurrency'> {
currencies: OnlyEth | OnlyPoly | EthAndPoly;
}

interface LaunchTieredStoCustomCurrencyEthParams extends LaunchTieredStoParams {
currencies: OnlyEth;
customCurrency: {
currencySymbol?: string;
ethOracleAddress: string;
};
}

interface LaunchTieredStoCustomCurrencyPolyParams extends LaunchTieredStoParams {
currencies: OnlyPoly;
customCurrency: {
currencySymbol?: string;
polyOracleAddress: string;
};
}

interface LaunchTieredStoCustomCurrencyBothParams extends LaunchTieredStoParams {
currencies: EthAndPoly;
customCurrency: {
currencySymbol?: string;
ethOracleAddress: string;
polyOracleAddress: string;
};
}

interface LaunchTieredStoMethod {
(args: LaunchTieredStoNoCustomCurrencyParams): Promise<
TransactionQueue<LaunchTieredStoProcedureArgs>
>;
(args: LaunchTieredStoCustomCurrencyEthParams): Promise<
TransactionQueue<LaunchTieredStoProcedureArgs>
>;
(args: LaunchTieredStoCustomCurrencyPolyParams): Promise<
TransactionQueue<LaunchTieredStoProcedureArgs>
>;
(args: LaunchTieredStoCustomCurrencyBothParams): Promise<
TransactionQueue<LaunchTieredStoProcedureArgs>
>;
}

interface GetStoMethod {
(args: { stoType: StoType.Simple; address: string }): Promise<SimpleSto>;
(args: { stoType: StoType.Tiered; address: string }): Promise<TieredSto>;
(args: string): Promise<SimpleSto | TieredSto>;
Expand Down Expand Up @@ -63,24 +149,15 @@ export class Offerings extends SubModule {
* @param raisedFundsWallet wallet address that will receive the funds that are being raised
* @param unsoldTokensWallet wallet address that will receive unsold tokens when the end date is reached
* @param stableCoinAddresses array of stable coins that the offering supports
* @param customOracleAddresses array of stable coin price oracles
* @param denominatedCurrency denominated currency type of the tiered sto
* @param customCurrency custom currency data. Allows the STO to raise funds pegged to a different currency. Optional, defaults to USD
* @param customCurrency.currencySymbol symbol of the custom currency (USD, CAD, EUR, etc. Default is USD)
* @param customCurrency.ethOracleAddress address of the oracle that states the price of ETH in the custom currency. Only required if raising funds in ETH
* @param customCurrency.polyOracleAddress address of the oracle that states the price of POLY in the custom currency. Only required if raising funds in POLY
* @param allowPreIssuance whether to have all tokens issued on STO start. Default behavior is to issue on purchase
*/
public launchTieredSto = async (args: {
startDate: Date;
endDate: Date;
tiers: StoTier[];
nonAccreditedInvestmentLimit: BigNumber;
minimumInvestment: BigNumber;
currencies: Currency[];
raisedFundsWallet: string;
unsoldTokensWallet: string;
stableCoinAddresses: string[];
customOracleAddresses: string[];
denominatedCurrency: string;
allowPreIssuance?: boolean;
}) => {
public launchTieredSto: LaunchTieredStoMethod = async (
args: LaunchTieredStoParams
): Promise<any> => {
const { context, securityToken } = this;
const { symbol } = securityToken;
const procedure = new LaunchTieredSto(
Expand All @@ -99,7 +176,7 @@ export class Offerings extends SubModule {
* @param stoType type of the STO (Capped or Tiered)
* @param address address of the STO contract
*/
public getSto: GetSto = async (
public getSto: GetStoMethod = async (
args:
| {
stoType: StoType;
Expand Down
4 changes: 2 additions & 2 deletions src/entities/SimpleSto.ts
Expand Up @@ -9,7 +9,7 @@ import {
import { serialize } from '../utils';
import { Sto, UniqueIdentifiers, Params as StoParams } from './Sto';
import { Context } from '../Context';
import { InvestInCappedSto } from '../procedures';
import { InvestInSimpleSto } from '../procedures';
import { Investment } from './Investment';

const { weiToValue } = conversionUtils;
Expand Down Expand Up @@ -99,7 +99,7 @@ export class SimpleSto extends Sto<Params> {
public async invest(args: { amount: BigNumber; beneficiary?: string }) {
const { address: stoAddress, securityTokenSymbol: symbol } = this;

const procedure = new InvestInCappedSto({ stoAddress, symbol, ...args }, this.context);
const procedure = new InvestInSimpleSto({ stoAddress, symbol, ...args }, this.context);

return procedure.prepare();
}
Expand Down
18 changes: 9 additions & 9 deletions src/entities/Sto.ts
Expand Up @@ -28,7 +28,7 @@ export interface Params {
securityTokenSymbol: string;
startDate: Date;
endDate: Date;
currencies: Currency[];
fundraiseCurrencies: Currency[];
raisedFundsWallet: string;
unsoldTokensWallet: string;
raisedAmount: BigNumber;
Expand Down Expand Up @@ -66,7 +66,7 @@ export abstract class Sto<P> extends Entity<P> {

public investorCount: number;

public currencies: Currency[];
public fundraiseCurrencies: Currency[];

public isPaused: boolean;

Expand Down Expand Up @@ -101,7 +101,7 @@ export abstract class Sto<P> extends Entity<P> {
securityTokenSymbol,
securityTokenId,
stoType,
currencies,
fundraiseCurrencies,
startDate,
endDate,
raisedFundsWallet,
Expand All @@ -127,7 +127,7 @@ export abstract class Sto<P> extends Entity<P> {
this.raisedAmount = raisedAmount;
this.soldTokensAmount = soldTokensAmount;
this.investorCount = investorCount;
this.currencies = currencies;
this.fundraiseCurrencies = fundraiseCurrencies;
this.isPaused = isPaused;
this.capReached = capReached;
this.isFinalized = isFinalized;
Expand Down Expand Up @@ -289,7 +289,7 @@ export abstract class Sto<P> extends Entity<P> {
securityTokenId,
address,
securityTokenSymbol,
currencies,
fundraiseCurrencies,
raisedFundsWallet,
unsoldTokensWallet,
raisedAmount,
Expand All @@ -309,7 +309,7 @@ export abstract class Sto<P> extends Entity<P> {
securityTokenId,
address,
securityTokenSymbol,
currencies,
fundraiseCurrencies,
raisedFundsWallet,
unsoldTokensWallet,
raisedAmount,
Expand All @@ -330,7 +330,7 @@ export abstract class Sto<P> extends Entity<P> {
securityTokenSymbol,
startDate,
endDate,
currencies,
fundraiseCurrencies,
raisedFundsWallet,
unsoldTokensWallet,
raisedAmount,
Expand All @@ -355,8 +355,8 @@ export abstract class Sto<P> extends Entity<P> {
this.endDate = endDate;
}

if (currencies) {
this.currencies = currencies;
if (fundraiseCurrencies) {
this.fundraiseCurrencies = fundraiseCurrencies;
}

if (raisedFundsWallet) {
Expand Down
77 changes: 59 additions & 18 deletions src/entities/TieredSto.ts
Expand Up @@ -5,14 +5,17 @@ import {
BlockParamLiteral,
FULL_DECIMALS,
conversionUtils,
FundRaiseType,
isUSDTieredSTO_3_1_0,
} from '@polymathnetwork/contract-wrappers';
import { serialize } from '../utils';
import { Sto, UniqueIdentifiers, Params as StoParams } from './Sto';
import { Context } from '../Context';
import { StoTier, Currency, InvestInTieredStoProcedureArgs } from '../types';
import { StoTier, Currency, InvestInTieredStoProcedureArgs, CustomCurrency } from '../types';
import { ModifyTieredStoData, InvestInTieredSto } from '../procedures';
import { TransactionQueue } from './TransactionQueue';
import { Investment } from './Investment';
import { ZERO_ADDRESS } from '../utils/constants';

const { weiToValue } = conversionUtils;

Expand Down Expand Up @@ -121,7 +124,44 @@ export class TieredSto extends Sto<Params> {
}

/**
* Modifies STO parameters. Must be done before the STO starts
* Retrieve the denomination in which the tokens are priced in this STO
*/
public async getCurrency(): Promise<CustomCurrency> {
const {
context: { contractWrappers },
address,
} = this;

const module = await contractWrappers.moduleFactory.getModuleInstance({
name: ModuleName.UsdTieredSTO,
address,
});

let ethOracleAddress: string;
let polyOracleAddress: string;
let currencySymbol: string;
if (isUSDTieredSTO_3_1_0(module)) {
[ethOracleAddress, polyOracleAddress, currencySymbol] = await Promise.all([
module.getCustomOracleAddress({ fundRaiseType: FundRaiseType.ETH }),
module.getCustomOracleAddress({ fundRaiseType: FundRaiseType.POLY }),
module.denominatedCurrency(),
]);
} else {
// this has to be done this way because the 3.0.0 USDTieredSTO does not expose a getter for the oracles
ethOracleAddress = ZERO_ADDRESS;
polyOracleAddress = ZERO_ADDRESS;
currencySymbol = 'USD';
}

return {
ethOracleAddress,
polyOracleAddress,
currencySymbol,
};
}

/**
* Modify STO parameters. Must be done before the STO starts
*
* @param startDate date when the STO should start
* @param endDate date when the STO should end
Expand All @@ -132,25 +172,26 @@ export class TieredSto extends Sto<Params> {
* @param tiers[].discountedPrice price of discounted tokens on that tier (defaults to 0)
* @param nonAccreditedInvestmentLimit maximum investment for non-accredited investors
* @param minimumInvestment minimum investment amount
* @param currencies array of currencies in which the funds will be raised (ETH, POLY, StableCoin)
* @param fundraiseCurrencies array of currencies in which the funds will be raised (ETH, POLY, StableCoin)
* @param raisedFundsWallet wallet address that will receive the funds that are being raised
* @param unsoldTokensWallet wallet address that will receive unsold tokens when the end date is reached
* @param stableCoinAddresses array of stable coins that the offering supports
* @param customOracleAddresses array of stable coin price oracles
* @param denominatedCurrency denominated currency type of the tiered sto
* @param stableCoinAddresses addresses of supported stablecoins
* @param customCurrency custom currency data. Allows the STO to raise funds pegged to a different currency. Optional, defaults to USD
* @param customCurrency.currencySymbol symbol of the custom currency (USD, CAD, EUR, etc. Default is USD)
* @param customCurrency.ethOracleAddress address of the oracle that states the price of ETH in the custom currency. Only required if raising funds in ETH
* @param customCurrency.polyOracleAddress address of the oracle that states the price of POLY in the custom currency. Only required if raising funds in POLY
*/
public async modifyData(args: {
startDate: Date;
endDate: Date;
tiers: StoTier[];
nonAccreditedInvestmentLimit: BigNumber;
minimumInvestment: BigNumber;
currencies: Currency[];
raisedFundsWallet: string;
unsoldTokensWallet: string;
stableCoinAddresses: string[];
customOracleAddresses: string[];
denominatedCurrency: string;
startDate?: Date;
endDate?: Date;
tiers?: StoTier[];
nonAccreditedInvestmentLimit?: BigNumber;
minimumInvestment?: BigNumber;
fundariseCurrencies?: Currency[];
raisedFundsWallet?: string;
unsoldTokensWallet?: string;
stableCoinAddresses?: string[];
customCurrency?: Partial<CustomCurrency>;
}) {
const { address: stoAddress, securityTokenSymbol: symbol } = this;

Expand All @@ -168,7 +209,7 @@ export class TieredSto extends Sto<Params> {
): Promise<TransactionQueue<InvestInTieredStoProcedureArgs>>;

/**
* Invests in the STO
* Invest in the STO
*
* @param minTokens sets a minimum amount of tokens to buy. If the amount sent yields less tokens at the current price, the transaction will revert
* @param amount amount to spend
Expand Down
2 changes: 1 addition & 1 deletion src/entities/factories/SimpleStoFactory.ts
Expand Up @@ -54,7 +54,7 @@ export class SimpleStoFactory extends Factory<SimpleSto, Params, UniqueIdentifie
}

return {
currencies: isRaisedInPoly ? [Currency.POLY] : [Currency.ETH],
fundraiseCurrencies: isRaisedInPoly ? [Currency.POLY] : [Currency.ETH],
raisedFundsWallet,
unsoldTokensWallet,
raisedAmount: fundsRaised,
Expand Down

0 comments on commit c31ce47

Please sign in to comment.