Skip to content

Commit

Permalink
feat(offerings): add offerings.launchSto method
Browse files Browse the repository at this point in the history
Also improved the signature of `getPortfolio`
  • Loading branch information
monitz87 committed Feb 1, 2021
1 parent cc0ec63 commit 728392b
Show file tree
Hide file tree
Showing 16 changed files with 932 additions and 37 deletions.
4 changes: 4 additions & 0 deletions src/api/entities/Identity/Portfolios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ export class Portfolios extends Namespace<Identity> {
*
* @param args.porfolioId - optional, defaults to the default portfolio
*/
public async getPortfolio(): Promise<DefaultPortfolio>;
public async getPortfolio(args: { portfolioId: BigNumber }): Promise<NumberedPortfolio>;

// eslint-disable-next-line require-jsdoc
public async getPortfolio(args?: {
portfolioId: BigNumber;
}): Promise<DefaultPortfolio | NumberedPortfolio> {
Expand Down
15 changes: 3 additions & 12 deletions src/api/entities/Identity/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import { CddStatus, DidRecord } from 'polymesh-types/types';

import {
Context,
DefaultPortfolio,
Entity,
NumberedPortfolio,
PolymeshError,
SecurityToken,
TickerReservation,
Expand Down Expand Up @@ -34,6 +32,7 @@ import {
balanceToBigNumber,
cddStatusToBoolean,
identityIdToString,
portfolioIdToPortfolio,
stringToIdentityId,
stringToTicker,
u64ToBigNumber,
Expand Down Expand Up @@ -134,17 +133,9 @@ export class Identity extends Entity<UniqueIdentifiers> {

return owner.did === did;
} else if (isPortfolioCustodianRole(role)) {
const {
portfolioId: { did: portfolioDid, number },
} = role;

let portfolio;
const { portfolioId } = role;

if (number) {
portfolio = new NumberedPortfolio({ did: portfolioDid, id: number }, context);
} else {
portfolio = new DefaultPortfolio({ did: portfolioDid }, context);
}
const portfolio = portfolioIdToPortfolio(portfolioId, context);

return portfolio.isCustodiedBy();
}
Expand Down
41 changes: 39 additions & 2 deletions src/api/entities/SecurityToken/Offerings.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,43 @@
import { Namespace, SecurityToken } from '~/internal';
import { Context, launchSto, LaunchStoParams, Namespace, SecurityToken, Sto } from '~/internal';
import { ProcedureMethod } from '~/types/internal';
import { createProcedureMethod } from '~/utils/internal';

/**
* Handles all Security Token Offerings related functionality
*/
export class Offerings extends Namespace<SecurityToken> {}
export class Offerings extends Namespace<SecurityToken> {
/**
* @hidden
*/
constructor(parent: SecurityToken, context: Context) {
super(parent, context);

const { ticker } = parent;

this.launch = createProcedureMethod(args => [launchSto, { ticker, ...args }], context);
}

/**
* Launch a Security Token Offering
*
* @param args.offeringPortfolio - portfolio in which the Tokens to be sold are stored
* (optional, defaults to the default portfolio of the Security Token's Primary Issuance Agent)
* @param args.raisingPorfolio - portfolio in which the raised funds will be stored
* @param args.raisingCurrency - ticker symbol of the currency in which the funds are being raised (i.e. 'USD' or 'CAD').
* Other Security Tokens can be used as currency as well
* @param args.venue - venue through which all offering related trades will be settled
* (optional, defaults to the first `Sto` type Venue owned by the owner of the Offering Portfolio.
* If passed, it must be of type `Sto`)
* @param start - start date of the Offering (optional, defaults to right now)
* @param end - end date of the Offering (optional, defaults to never)
* @param tiers - array of sale tiers. Each tier consists of an amount of Tokens to be sold at a certain price.
* Tokens in a tier can only be bought when all Tokens in previous tiers have been bought
* @param minInvestment - minimum amount that can be spent on this offering
*
* @note required roles:
* - Security Token Primary Issuance Agent
* - Offering Portfolio Custodian
* - Raising Portfolio Custodian
*/
public launch: ProcedureMethod<LaunchStoParams, Sto>;
}
36 changes: 35 additions & 1 deletion src/api/entities/SecurityToken/__tests__/Offerings.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { Namespace } from '~/internal';
import BigNumber from 'bignumber.js';
import sinon from 'sinon';

import { launchSto, Namespace, Sto, TransactionQueue } from '~/internal';
import { dsMockUtils, entityMockUtils } from '~/testUtils/mocks';

import { Offerings } from '../Offerings';
Expand Down Expand Up @@ -27,4 +30,35 @@ describe('Offerings class', () => {
test('should extend namespace', () => {
expect(Offerings.prototype instanceof Namespace).toBe(true);
});

describe('method: launch', () => {
afterAll(() => {
sinon.restore();
});

test('should prepare the procedure with the correct arguments and context, and return the resulting transaction queue', async () => {
const context = dsMockUtils.getContextInstance();
const token = entityMockUtils.getSecurityTokenInstance();
const ticker = 'SOME_TICKER';
const offerings = new Offerings(token, context);

const expectedQueue = ('someQueue' as unknown) as TransactionQueue<Sto>;
const args = {
raisingCurrency: 'USD',
raisingPortfolio: 'someDid',
name: 'someName',
tiers: [],
minInvestment: new BigNumber(100),
};

sinon
.stub(launchSto, 'prepare')
.withArgs({ ticker, ...args }, context)
.resolves(expectedQueue);

const queue = await offerings.launch(args);

expect(queue).toBe(expectedQueue);
});
});
});
7 changes: 5 additions & 2 deletions src/api/entities/Sto/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export interface Placeholder {
foo: number;
import BigNumber from 'bignumber.js';

export interface StoTier {
amount: BigNumber;
price: BigNumber;
}
5 changes: 5 additions & 0 deletions src/api/entities/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import {
CurrentAccount as CurrentAccountClass,
CurrentIdentity as CurrentIdentityClass,
DefaultPortfolio as DefaultPortfolioClass,
DefaultTrustedClaimIssuer as DefaultTrustedClaimIssuerClass,
Identity as IdentityClass,
Instruction as InstructionClass,
NumberedPortfolio as NumberedPortfolioClass,
Portfolio as PortfolioClass,
// Proposal as ProposalClass,
SecurityToken as SecurityTokenClass,
Sto as StoClass,
TickerReservation as TickerReservationClass,
Venue as VenueClass,
} from '~/internal';
Expand All @@ -28,11 +30,14 @@ export type Instruction = InstanceType<typeof InstructionClass>;
export type Portfolio = InstanceType<typeof PortfolioClass>;
export type DefaultPortfolio = InstanceType<typeof DefaultPortfolioClass>;
export type NumberedPortfolio = InstanceType<typeof NumberedPortfolioClass>;
export type DefaultTrustedClaimIssuer = InstanceType<typeof DefaultTrustedClaimIssuerClass>;
export type Sto = InstanceType<typeof StoClass>;
// export type Proposal = InstanceType<typeof ProposalClass>;

export * from './TickerReservation/types';
export * from './SecurityToken/types';
export * from './Venue/types';
export * from './Instruction/types';
export * from './Portfolio/types';
export * from './Sto/types';
// export * from './Proposal/types';
6 changes: 3 additions & 3 deletions src/api/procedures/__tests__/createVenue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import * as utilsInternalModule from '~/utils/internal';

describe('createVenue procedure', () => {
let mockContext: Mocked<Context>;
let stringToVenueuDetailsStub: sinon.SinonStub<[string, Context], VenueDetails>;
let stringToVenueDetailsStub: sinon.SinonStub<[string, Context], VenueDetails>;
let venueTypeToMeshVenueTypeStub: sinon.SinonStub<[VenueType, Context], MeshVenueType>;
let addTransactionStub: sinon.SinonStub;
let createVenueTransaction: PolymeshTx<unknown[]>;
Expand All @@ -24,7 +24,7 @@ describe('createVenue procedure', () => {
entityMockUtils.initMocks();
procedureMockUtils.initMocks();
dsMockUtils.initMocks();
stringToVenueuDetailsStub = sinon.stub(utilsConversionModule, 'stringToVenueDetails');
stringToVenueDetailsStub = sinon.stub(utilsConversionModule, 'stringToVenueDetails');
venueTypeToMeshVenueTypeStub = sinon.stub(utilsConversionModule, 'venueTypeToMeshVenueType');
venue = ('venue' as unknown) as PostTransactionValue<Venue>;
});
Expand Down Expand Up @@ -59,7 +59,7 @@ describe('createVenue procedure', () => {

const proc = procedureMockUtils.getInstance<CreateVenueParams, Venue>(mockContext);

stringToVenueuDetailsStub.withArgs(details, mockContext).returns(rawDetails);
stringToVenueDetailsStub.withArgs(details, mockContext).returns(rawDetails);
venueTypeToMeshVenueTypeStub.withArgs(type, mockContext).returns(rawType);

const result = await prepareCreateVenue.call(proc, args);
Expand Down

0 comments on commit 728392b

Please sign in to comment.