diff options
-rw-r--r-- | packages/website/ts/blockchain.ts | 34 | ||||
-rw-r--r-- | packages/website/ts/components/fill_order.tsx | 71 | ||||
-rw-r--r-- | packages/website/ts/components/generate_order/generate_order_form.tsx | 17 | ||||
-rw-r--r-- | packages/website/ts/components/portal.tsx | 3 | ||||
-rw-r--r-- | packages/website/ts/components/visual_order.tsx | 2 | ||||
-rw-r--r-- | packages/website/ts/containers/generate_order_form.tsx | 2 | ||||
-rw-r--r-- | packages/website/ts/redux/reducer.ts | 3 | ||||
-rw-r--r-- | packages/website/ts/schemas/metadata_schema.ts | 4 | ||||
-rw-r--r-- | packages/website/ts/schemas/order_schema.ts | 2 | ||||
-rw-r--r-- | packages/website/ts/schemas/signature_data_schema.ts | 10 | ||||
-rw-r--r-- | packages/website/ts/schemas/signed_order_schema.ts | 34 | ||||
-rw-r--r-- | packages/website/ts/schemas/token_schema.ts | 2 | ||||
-rw-r--r-- | packages/website/ts/schemas/validator.ts | 23 | ||||
-rw-r--r-- | packages/website/ts/types.ts | 4 | ||||
-rw-r--r-- | packages/website/ts/utils/utils.ts | 3 |
15 files changed, 57 insertions, 157 deletions
diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts index 697ff4f10..ae79651d5 100644 --- a/packages/website/ts/blockchain.ts +++ b/packages/website/ts/blockchain.ts @@ -39,7 +39,6 @@ import { ProviderType, Side, SideToAssetToken, - SignatureData, Token, TokenByAddress, } from 'ts/types'; @@ -289,39 +288,6 @@ export class Blockchain { }), ); } - public portalOrderToSignedOrder( - maker: string, - taker: string, - makerTokenAddress: string, - takerTokenAddress: string, - makerTokenAmount: BigNumber, - takerTokenAmount: BigNumber, - makerFee: BigNumber, - takerFee: BigNumber, - expirationUnixTimestampSec: BigNumber, - feeRecipient: string, - ecSignature: ECSignature, - salt: BigNumber, - ): SignedOrder { - const exchangeContractAddress = this.getExchangeContractAddressIfExists(); - const takerOrNullAddress = _.isEmpty(taker) ? constants.NULL_ADDRESS : taker; - const signedOrder = { - ecSignature, - exchangeContractAddress, - expirationUnixTimestampSec, - feeRecipient, - maker, - makerFee, - makerTokenAddress, - makerTokenAmount, - salt, - taker: takerOrNullAddress, - takerFee, - takerTokenAddress, - takerTokenAmount, - }; - return signedOrder; - } public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber): Promise<BigNumber> { utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); diff --git a/packages/website/ts/components/fill_order.tsx b/packages/website/ts/components/fill_order.tsx index 4252747ec..2582581b1 100644 --- a/packages/website/ts/components/fill_order.tsx +++ b/packages/website/ts/components/fill_order.tsx @@ -19,7 +19,7 @@ import { Identicon } from 'ts/components/ui/identicon'; import { VisualOrder } from 'ts/components/visual_order'; import { Dispatcher } from 'ts/redux/dispatcher'; import { orderSchema } from 'ts/schemas/order_schema'; -import { SchemaValidator } from 'ts/schemas/validator'; +import { validator } from 'ts/schemas/validator'; import { AlertTypes, BlockchainErrs, Order, Token, TokenByAddress, WebsitePaths } from 'ts/types'; import { colors } from 'ts/utils/colors'; import { constants } from 'ts/utils/constants'; @@ -59,7 +59,6 @@ interface FillOrderState { } export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { - private _validator: SchemaValidator; private _isUnmounted: boolean; constructor(props: FillOrderProps) { super(props); @@ -82,7 +81,6 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { isConfirmingTokenTracking: false, tokensToTrack: [], }; - this._validator = new SchemaValidator(); } public componentWillMount() { if (!_.isEmpty(this.state.orderJSON)) { @@ -199,9 +197,6 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { amount: this.props.orderFillAmount, symbol: takerToken.symbol, }; - const orderTaker = !_.isEmpty(this.state.parsedOrder.signedOrder.taker) - ? this.state.parsedOrder.signedOrder.taker - : this.props.userAddress; const parsedOrderExpiration = new BigNumber(this.state.parsedOrder.signedOrder.expirationUnixTimestampSec); const exchangeRate = orderMakerAmount.div(orderTakerAmount); @@ -236,8 +231,6 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { <div className="lg-px4 md-px4 sm-px0"> <div className="lg-px4 md-px4 sm-px1 pt1"> <VisualOrder - orderTakerAddress={orderTaker} - orderMakerAddress={this.state.parsedOrder.signedOrder.maker} makerAssetToken={makerAssetToken} takerAssetToken={takerAssetToken} tokenByAddress={this.props.tokenByAddress} @@ -407,7 +400,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { let orderHash: string; try { const order = JSON.parse(orderJSON); - const validationResult = this._validator.validate(order, orderSchema); + const validationResult = validator.validate(order, orderSchema); if (validationResult.errors.length > 0) { orderJSONErrMsg = 'Submitted order JSON is not a valid order'; utils.consoleLog(`Unexpected order JSON validation error: ${validationResult.errors.join(', ')}`); @@ -415,7 +408,6 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { } parsedOrder = order; - const exchangeContractAddr = this.props.blockchain.getExchangeContractAddressIfExists(); const makerAmount = new BigNumber(parsedOrder.signedOrder.makerTokenAmount); const takerAmount = new BigNumber(parsedOrder.signedOrder.takerTokenAmount); const expiration = new BigNumber(parsedOrder.signedOrder.expirationUnixTimestampSec); @@ -441,6 +433,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { }; orderHash = ZeroEx.getOrderHashHex(zeroExOrder); + const exchangeContractAddr = this.props.blockchain.getExchangeContractAddressIfExists(); const signature = parsedOrder.signedOrder.ecSignature; const isValidSignature = ZeroEx.isValidSignature(orderHash, signature, parsedOrder.signedOrder.maker); if (exchangeContractAddr !== parsedOrder.signedOrder.exchangeContractAddress) { @@ -525,20 +518,21 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { globalErrMsg = 'You must specify a fill amount'; } - const signedOrder = this.props.blockchain.portalOrderToSignedOrder( - parsedOrder.signedOrder.maker, - parsedOrder.signedOrder.taker, - parsedOrder.signedOrder.makerTokenAddress, - parsedOrder.signedOrder.takerTokenAddress, - new BigNumber(parsedOrder.signedOrder.makerTokenAmount), - new BigNumber(parsedOrder.signedOrder.takerTokenAmount), - new BigNumber(parsedOrder.signedOrder.makerFee), - new BigNumber(parsedOrder.signedOrder.takerFee), - new BigNumber(this.state.parsedOrder.signedOrder.expirationUnixTimestampSec), - parsedOrder.signedOrder.feeRecipient, - parsedOrder.signedOrder.ecSignature, - new BigNumber(parsedOrder.signedOrder.salt), - ); + const signedOrder = { + exchangeContractAddress: this.props.blockchain.getExchangeContractAddressIfExists(), + maker: parsedOrder.signedOrder.maker, + taker: _.isEmpty(parsedOrder.signedOrder.taker) ? constants.NULL_ADDRESS : parsedOrder.signedOrder.taker, + makerTokenAddress: parsedOrder.signedOrder.makerTokenAddress, + takerTokenAddress: parsedOrder.signedOrder.takerTokenAddress, + makerTokenAmount: new BigNumber(parsedOrder.signedOrder.makerTokenAmount), + takerTokenAmount: new BigNumber(parsedOrder.signedOrder.takerTokenAmount), + makerFee: new BigNumber(parsedOrder.signedOrder.makerFee), + takerFee: new BigNumber(parsedOrder.signedOrder.takerFee), + expirationUnixTimestampSec: new BigNumber(this.state.parsedOrder.signedOrder.expirationUnixTimestampSec), + feeRecipient: parsedOrder.signedOrder.feeRecipient, + ecSignature: parsedOrder.signedOrder.ecSignature, + salt: new BigNumber(parsedOrder.signedOrder.salt), + }; if (_.isEmpty(globalErrMsg)) { try { await this.props.blockchain.validateFillOrderThrowIfInvalidAsync( @@ -627,20 +621,21 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { const takerTokenAmount = new BigNumber(parsedOrder.signedOrder.takerTokenAmount); - const signedOrder = this.props.blockchain.portalOrderToSignedOrder( - parsedOrder.signedOrder.maker, - parsedOrder.signedOrder.taker, - parsedOrder.signedOrder.makerTokenAddress, - parsedOrder.signedOrder.takerTokenAddress, - new BigNumber(parsedOrder.signedOrder.makerTokenAmount), - takerTokenAmount, - new BigNumber(parsedOrder.signedOrder.makerFee), - new BigNumber(parsedOrder.signedOrder.takerFee), - new BigNumber(this.state.parsedOrder.signedOrder.expirationUnixTimestampSec), - parsedOrder.signedOrder.feeRecipient, - parsedOrder.signedOrder.ecSignature, - new BigNumber(parsedOrder.signedOrder.salt), - ); + const signedOrder = { + exchangeContractAddress: this.props.blockchain.getExchangeContractAddressIfExists(), + maker: parsedOrder.signedOrder.maker, + taker: parsedOrder.signedOrder.taker, + makerTokenAddress: parsedOrder.signedOrder.makerTokenAddress, + takerTokenAddress: parsedOrder.signedOrder.takerTokenAddress, + makerTokenAmount: new BigNumber(parsedOrder.signedOrder.makerTokenAmount), + takerTokenAmount: new BigNumber(parsedOrder.signedOrder.takerTokenAmount), + makerFee: new BigNumber(parsedOrder.signedOrder.makerFee), + takerFee: new BigNumber(parsedOrder.signedOrder.takerFee), + expirationUnixTimestampSec: new BigNumber(this.state.parsedOrder.signedOrder.expirationUnixTimestampSec), + feeRecipient: parsedOrder.signedOrder.feeRecipient, + ecSignature: parsedOrder.signedOrder.ecSignature, + salt: new BigNumber(parsedOrder.signedOrder.salt), + }; const orderHash = ZeroEx.getOrderHashHex(signedOrder); const unavailableTakerAmount = await this.props.blockchain.getUnavailableTakerAmountAsync(orderHash); const availableTakerTokenAmount = takerTokenAmount.minus(unavailableTakerAmount); diff --git a/packages/website/ts/components/generate_order/generate_order_form.tsx b/packages/website/ts/components/generate_order/generate_order_form.tsx index 5f1cf3c8e..fcabd4844 100644 --- a/packages/website/ts/components/generate_order/generate_order_form.tsx +++ b/packages/website/ts/components/generate_order/generate_order_form.tsx @@ -18,7 +18,7 @@ import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button' import { SwapIcon } from 'ts/components/ui/swap_icon'; import { Dispatcher } from 'ts/redux/dispatcher'; import { orderSchema } from 'ts/schemas/order_schema'; -import { SchemaValidator } from 'ts/schemas/validator'; +import { validator } from 'ts/schemas/validator'; import { AlertTypes, BlockchainErrs, HashData, Side, SideToAssetToken, Token, TokenByAddress } from 'ts/types'; import { colors } from 'ts/utils/colors'; import { constants } from 'ts/utils/constants'; @@ -55,7 +55,6 @@ interface GenerateOrderFormState { } export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, GenerateOrderFormState> { - private _validator: SchemaValidator; constructor(props: GenerateOrderFormProps) { super(props); this.state = { @@ -63,7 +62,6 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G shouldShowIncompleteErrs: false, signingState: SigningState.UNSIGNED, }; - this._validator = new SchemaValidator(); } public componentDidMount() { window.scrollTo(0, 0); @@ -79,6 +77,8 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G allowed to fill this order. If no taker is<br> \ specified, anyone is able to fill it.'; const exchangeContractIfExists = this.props.blockchain.getExchangeContractAddressIfExists(); + const initialTakerAddress = + this.props.orderTakerAddress === ZeroEx.NULL_ADDRESS ? '' : this.props.orderTakerAddress; return ( <div className="clearfix mb2 lg-px4 md-px4 sm-px2"> <h3>Generate an order</h3> @@ -159,7 +159,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G <div className="pt1 flex mx-auto"> <IdenticonAddressInput label="Taker" - initialAddress={this.props.orderTakerAddress} + initialAddress={initialTakerAddress} updateOrderAddress={this._updateOrderAddress.bind(this)} /> <div className="pt3"> @@ -317,7 +317,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G let globalErrMsg = ''; try { - const signatureData = await this.props.blockchain.signOrderHashAsync(orderHash); + const ecSignature = await this.props.blockchain.signOrderHashAsync(orderHash); const order = utils.generateOrder( exchangeContractAddr, this.props.sideToAssetToken, @@ -327,11 +327,11 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G hashData.makerFee, hashData.takerFee, hashData.feeRecipientAddress, - signatureData, + ecSignature, this.props.tokenByAddress, hashData.orderSalt, ); - const validationResult = this._validator.validate(order, orderSchema); + const validationResult = validator.validate(order, orderSchema); if (validationResult.errors.length > 0) { globalErrMsg = 'Order signing failed. Please refresh and try again'; utils.consoleLog(`Unexpected error occured: Order validation failed: @@ -356,7 +356,8 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G } private _updateOrderAddress(address?: string): void { if (!_.isUndefined(address)) { - this.props.dispatcher.updateOrderTakerAddress(address); + const normalizedAddress = _.isEmpty(address) ? ZeroEx.NULL_ADDRESS : address; + this.props.dispatcher.updateOrderTakerAddress(normalizedAddress); } } } diff --git a/packages/website/ts/components/portal.tsx b/packages/website/ts/components/portal.tsx index 92589f75c..0d4fb8fdc 100644 --- a/packages/website/ts/components/portal.tsx +++ b/packages/website/ts/components/portal.tsx @@ -22,7 +22,7 @@ import { GenerateOrderForm } from 'ts/containers/generate_order_form'; import { localStorage } from 'ts/local_storage/local_storage'; import { Dispatcher } from 'ts/redux/dispatcher'; import { orderSchema } from 'ts/schemas/order_schema'; -import { SchemaValidator } from 'ts/schemas/validator'; +import { validator } from 'ts/schemas/validator'; import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress, WebsitePaths } from 'ts/types'; import { colors } from 'ts/utils/colors'; import { configs } from 'ts/utils/configs'; @@ -367,7 +367,6 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { return undefined; } - const validator = new SchemaValidator(); const order = JSON.parse(decodeURIComponent(orderPair[1])); const validationResult = validator.validate(order, orderSchema); if (validationResult.errors.length > 0) { diff --git a/packages/website/ts/components/visual_order.tsx b/packages/website/ts/components/visual_order.tsx index 092954086..ec2d47f39 100644 --- a/packages/website/ts/components/visual_order.tsx +++ b/packages/website/ts/components/visual_order.tsx @@ -8,8 +8,6 @@ import { utils } from 'ts/utils/utils'; const PRECISION = 5; interface VisualOrderProps { - orderTakerAddress: string; - orderMakerAddress: string; makerAssetToken: AssetToken; takerAssetToken: AssetToken; makerToken: Token; diff --git a/packages/website/ts/containers/generate_order_form.tsx b/packages/website/ts/containers/generate_order_form.tsx index 2cdb7b810..8c5deb690 100644 --- a/packages/website/ts/containers/generate_order_form.tsx +++ b/packages/website/ts/containers/generate_order_form.tsx @@ -7,7 +7,7 @@ import { Blockchain } from 'ts/blockchain'; import { GenerateOrderForm as GenerateOrderFormComponent } from 'ts/components/generate_order/generate_order_form'; import { Dispatcher } from 'ts/redux/dispatcher'; import { State } from 'ts/redux/reducer'; -import { BlockchainErrs, HashData, SideToAssetToken, SignatureData, TokenByAddress } from 'ts/types'; +import { BlockchainErrs, HashData, SideToAssetToken, TokenByAddress } from 'ts/types'; interface GenerateOrderFormProps { blockchain: Blockchain; diff --git a/packages/website/ts/redux/reducer.ts b/packages/website/ts/redux/reducer.ts index cab8cbfe6..c2a21dc07 100644 --- a/packages/website/ts/redux/reducer.ts +++ b/packages/website/ts/redux/reducer.ts @@ -11,7 +11,6 @@ import { ScreenWidths, Side, SideToAssetToken, - SignatureData, TokenByAddress, } from 'ts/types'; import { utils } from 'ts/utils/utils'; @@ -64,7 +63,7 @@ const INITIAL_STATE: State = { s: '', v: 27, }, - orderTakerAddress: '', + orderTakerAddress: ZeroEx.NULL_ADDRESS, orderSalt: ZeroEx.generatePseudoRandomSalt(), nodeVersion: undefined, screenWidth: utils.getScreenWidth(), diff --git a/packages/website/ts/schemas/metadata_schema.ts b/packages/website/ts/schemas/metadata_schema.ts index ff3bea13a..cd4045d10 100644 --- a/packages/website/ts/schemas/metadata_schema.ts +++ b/packages/website/ts/schemas/metadata_schema.ts @@ -1,8 +1,8 @@ export const orderMetadataSchema = { id: '/OrderMetadata', properties: { - makerToken: { $ref: '/Token' }, - takerToken: { $ref: '/Token' }, + makerToken: { $ref: '/PortalTokenMetadata' }, + takerToken: { $ref: '/PortalTokenMetadata' }, }, required: ['makerToken', 'takerToken'], type: 'object', diff --git a/packages/website/ts/schemas/order_schema.ts b/packages/website/ts/schemas/order_schema.ts index 0c5a6d425..4d427d8ce 100644 --- a/packages/website/ts/schemas/order_schema.ts +++ b/packages/website/ts/schemas/order_schema.ts @@ -1,5 +1,5 @@ export const orderSchema = { - id: '/Order', + id: '/PortalOrder', properties: { signedOrder: { $ref: '/SignedOrder' }, metadata: { $ref: '/OrderMetadata' }, diff --git a/packages/website/ts/schemas/signature_data_schema.ts b/packages/website/ts/schemas/signature_data_schema.ts deleted file mode 100644 index 7852abfef..000000000 --- a/packages/website/ts/schemas/signature_data_schema.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const signatureDataSchema = { - id: '/SignatureData', - properties: { - r: { type: 'string' }, - s: { type: 'string' }, - v: { type: 'number' }, - }, - required: ['r', 's', 'v'], - type: 'object', -}; diff --git a/packages/website/ts/schemas/signed_order_schema.ts b/packages/website/ts/schemas/signed_order_schema.ts deleted file mode 100644 index 385008ab8..000000000 --- a/packages/website/ts/schemas/signed_order_schema.ts +++ /dev/null @@ -1,34 +0,0 @@ -export const signedOrderSchema = { - id: '/SignedOrder', - properties: { - maker: { type: 'string' }, - taker: { type: 'string' }, - makerTokenAddress: { type: 'string' }, - takerTokenAddress: { type: 'string' }, - makerFee: { type: 'string' }, - takerFee: { type: 'string' }, - makerTokenAmount: { type: 'string' }, - takerTokenAmount: { type: 'string' }, - salt: { type: 'string' }, - ecSignature: { $ref: '/SignatureData' }, - expirationUnixTimestampSec: { type: 'string' }, - feeRecipient: { type: 'string' }, - exchangeContractAddress: { type: 'string' }, - }, - required: [ - 'maker', - 'taker', - 'makerTokenAddress', - 'takerTokenAddress', - 'makerFee', - 'takerFee', - 'makerTokenAmount', - 'takerTokenAmount', - 'salt', - 'ecSignature', - 'expirationUnixTimestampSec', - 'feeRecipient', - 'exchangeContractAddress', - ], - type: 'object', -}; diff --git a/packages/website/ts/schemas/token_schema.ts b/packages/website/ts/schemas/token_schema.ts index 34cd6f676..4d1febfee 100644 --- a/packages/website/ts/schemas/token_schema.ts +++ b/packages/website/ts/schemas/token_schema.ts @@ -1,5 +1,5 @@ export const tokenSchema = { - id: '/Token', + id: '/PortalTokenMetadata', properties: { name: { type: 'string' }, symbol: { type: 'string' }, diff --git a/packages/website/ts/schemas/validator.ts b/packages/website/ts/schemas/validator.ts index 14061e2a3..f0b5e6676 100644 --- a/packages/website/ts/schemas/validator.ts +++ b/packages/website/ts/schemas/validator.ts @@ -1,21 +1,12 @@ +import { SchemaValidator } from '@0xproject/json-schemas'; import { Schema as JSONSchema, Validator } from 'jsonschema'; import { orderMetadataSchema } from 'ts/schemas/metadata_schema'; import { orderSchema } from 'ts/schemas/order_schema'; -import { signatureDataSchema } from 'ts/schemas/signature_data_schema'; -import { signedOrderSchema } from 'ts/schemas/signed_order_schema'; import { tokenSchema } from 'ts/schemas/token_schema'; -export class SchemaValidator { - private _validator: Validator; - constructor() { - this._validator = new Validator(); - this._validator.addSchema(signatureDataSchema as JSONSchema, signatureDataSchema.id); - this._validator.addSchema(tokenSchema as JSONSchema, tokenSchema.id); - this._validator.addSchema(orderMetadataSchema as JSONSchema, orderMetadataSchema.id); - this._validator.addSchema(signedOrderSchema as JSONSchema, signedOrderSchema.id); - this._validator.addSchema(orderSchema as JSONSchema, orderSchema.id); - } - public validate(instance: object, schema: Schema) { - return this._validator.validate(instance, schema); - } -} +const validator = new SchemaValidator(); +validator.addSchema(tokenSchema); +validator.addSchema(orderMetadataSchema); +validator.addSchema(orderSchema); + +export { validator }; diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 2b255f523..19fc24852 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -35,10 +35,6 @@ export interface SideToAssetToken { [side: string]: AssetToken; } -export interface SignatureData extends ECSignature { - hash: string; -} - export interface HashData { depositAmount: BigNumber; depositTokenContractAddr: string; diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts index bf6b70f84..68eb7c813 100644 --- a/packages/website/ts/utils/utils.ts +++ b/packages/website/ts/utils/utils.ts @@ -1,4 +1,4 @@ -import { ECSignature, ExchangeContractErrs, ZeroExError } from '0x.js'; +import { ECSignature, ExchangeContractErrs, ZeroEx, ZeroExError } from '0x.js'; import { BigNumber } from '@0xproject/utils'; import deepEqual = require('deep-equal'); import isMobile = require('is-mobile'); @@ -11,7 +11,6 @@ import { ScreenWidths, Side, SideToAssetToken, - SignatureData, Token, TokenByAddress, } from 'ts/types'; |