@loafmarkets/shared-types 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # Shared Types
2
+
3
+ Shared contracts (TypeScript interfaces + protobuf schemas) used by the Loaf Markets backend, frontend, and matching engine.
4
+
5
+ ## Repository layout
6
+
7
+ ```
8
+ Shared-Types/
9
+ ├── proto/ # trading.proto (matching engine contracts)
10
+ ├── src/
11
+ │ └── index.ts # TypeScript schemas and interfaces shared across services
12
+ ├── dist/ # Build output (generated via `pnpm run build`)
13
+ ├── package.json # npm package settings
14
+ └── tsconfig.json
15
+ ```
16
+
17
+ ## Getting started
18
+
19
+ ```bash
20
+ # Install dependencies
21
+ pnpm install
22
+
23
+ # Build once to emit dist/
24
+ pnpm run build
25
+
26
+ # Run type-check only
27
+ pnpm exec tsc --noEmit
28
+ ```
29
+
30
+ ## Consuming the package
31
+
32
+ In any Loaf service repo:
33
+
34
+ ```bash
35
+ pnpm add @loafmarkets/shared-types@<version>
36
+ ```
37
+
38
+ Then import types from TypeScript:
39
+
40
+ ```ts
41
+ import type { OrderApiRequestBody, propertySchema } from '@loafmarkets/shared-types';
42
+ ```
43
+
44
+ To use the protobuf definition (for gRPC or codegen):
45
+
46
+ ```
47
+ node_modules/@loafmarkets/shared-types/proto/trading.proto
48
+ ```
49
+
50
+ ## Making changes
51
+
52
+ 1. **Modify contracts** in `src/index.ts` (TypeScript) or `proto/trading.proto`.
53
+ 2. **Run tests/build** locally:
54
+ ```bash
55
+ pnpm run build
56
+ ```
57
+ 3. **Update version** in `package.json` following semver (e.g., bump patch for backward-compatible additions).
58
+ 4. **Document changes** in the commit message or a CHANGELOG entry if you maintain one.
59
+
60
+ ## Release process
61
+
62
+ ```bash
63
+ # Ensure working tree is clean
64
+ git status
65
+
66
+ # Build artifacts
67
+ pnpm run build
68
+
69
+ # Commit and push
70
+ git commit -am "feat: add XYZ contract"
71
+ git push origin main
72
+
73
+ # Tag the release (match package.json version)
74
+ git tag v<version>
75
+ git push origin v<version>
76
+
77
+ # Publish to registry
78
+ pnpm publish --tag latest
79
+ ```
80
+
81
+ Once published, update each consumer repository:
82
+
83
+ ```bash
84
+ pnpm add @loafmarkets/shared-types@<version>
85
+ ```
86
+
87
+ ## Notes
88
+
89
+ - `dist/` and `node_modules/` should never be committed; they are generated during install/publish.
90
+ - The `prepare` script ensures `pnpm install` (even from Git) builds `dist/`, so consumers always have compiled output.
91
+ - Use Renovate/Dependabot to automate dependency bump PRs in downstream repos.
@@ -0,0 +1,255 @@
1
+ import { z } from 'zod';
2
+ export declare const MARKET_ORDER_PRICE = 0;
3
+ export declare const ORDER_QUANTITY_MAX_DECIMALS: 8;
4
+ export declare const ORDER_PRICE_MAX_DECIMALS: 2;
5
+ export type OrderSide = 'BUY' | 'SELL';
6
+ export type OrderType = 'MARKET' | 'LIMIT';
7
+ export type OrderStatus = 'PENDING' | 'OPEN' | 'PARTIALLY_FILLED' | 'FILLED' | 'CANCELLED' | 'REJECTED' | 'EXPIRED';
8
+ export type TimeInForce = 'GTC' | 'IOC' | 'FOK' | 'GTD';
9
+ export declare const orderBodySchema: z.ZodObject<{
10
+ propertyId: z.ZodNumber;
11
+ price: z.ZodNumber;
12
+ quantity: z.ZodNumber;
13
+ side: z.ZodEnum<{
14
+ BUY: "BUY";
15
+ SELL: "SELL";
16
+ }>;
17
+ type: z.ZodDefault<z.ZodEnum<{
18
+ MARKET: "MARKET";
19
+ LIMIT: "LIMIT";
20
+ }>>;
21
+ timeInForce: z.ZodDefault<z.ZodEnum<{
22
+ GTC: "GTC";
23
+ IOC: "IOC";
24
+ FOK: "FOK";
25
+ GTD: "GTD";
26
+ }>>;
27
+ expiresAt: z.ZodOptional<z.ZodString>;
28
+ nonce: z.ZodString;
29
+ walletAddress: z.ZodString;
30
+ signature: z.ZodString;
31
+ }, z.core.$strip>;
32
+ export type OrderApiRequestBody = z.infer<typeof orderBodySchema>;
33
+ export declare const sessionSignerOrderBodySchema: z.ZodObject<{
34
+ propertyId: z.ZodNumber;
35
+ price: z.ZodNumber;
36
+ quantity: z.ZodNumber;
37
+ side: z.ZodEnum<{
38
+ BUY: "BUY";
39
+ SELL: "SELL";
40
+ }>;
41
+ type: z.ZodDefault<z.ZodEnum<{
42
+ MARKET: "MARKET";
43
+ LIMIT: "LIMIT";
44
+ }>>;
45
+ timeInForce: z.ZodDefault<z.ZodEnum<{
46
+ GTC: "GTC";
47
+ IOC: "IOC";
48
+ FOK: "FOK";
49
+ GTD: "GTD";
50
+ }>>;
51
+ expiresAt: z.ZodOptional<z.ZodString>;
52
+ nonce: z.ZodString;
53
+ walletAddress: z.ZodString;
54
+ tokenName: z.ZodString;
55
+ }, z.core.$strip>;
56
+ export type SessionSignerOrderRequestBody = z.infer<typeof sessionSignerOrderBodySchema>;
57
+ export interface SessionSignerInfo {
58
+ quorumId: string;
59
+ policyId: string | undefined;
60
+ enabled: boolean;
61
+ }
62
+ export interface SessionSignerStatus {
63
+ enabled: boolean;
64
+ reason?: string;
65
+ }
66
+ export interface OrderApiResponse {
67
+ success: boolean;
68
+ orderId: number;
69
+ errorMessage?: string;
70
+ }
71
+ export interface OrderNonceResponse {
72
+ nonce: string;
73
+ expiresAt: string;
74
+ }
75
+ export declare const cancelOrderBodySchema: z.ZodObject<{
76
+ orderId: z.ZodNumber;
77
+ }, z.core.$strip>;
78
+ export type CancelOrderRequestBody = z.infer<typeof cancelOrderBodySchema>;
79
+ export interface CancelOrderResponse {
80
+ success: boolean;
81
+ orderId: number;
82
+ errorMessage?: string;
83
+ }
84
+ export interface OrderHistoryItem {
85
+ readonly id: number;
86
+ readonly propertyId: number;
87
+ readonly side: OrderSide;
88
+ readonly type: OrderType;
89
+ readonly timeInForce: TimeInForce;
90
+ readonly quantity: number;
91
+ readonly limitPrice: number | null;
92
+ readonly status: OrderStatus;
93
+ readonly filledQuantity: number;
94
+ readonly averageFillPrice: number | null;
95
+ readonly rejectionReason: string | null;
96
+ readonly expiresAt: string | null;
97
+ readonly filledAt: string | null;
98
+ readonly cancelledAt: string | null;
99
+ readonly createdAt: string;
100
+ }
101
+ export interface OrderPositionMetrics {
102
+ readonly propertyId: number;
103
+ readonly netPosition: number;
104
+ readonly averageEntryPrice: number | null;
105
+ readonly realizedPnl: number;
106
+ readonly unrealizedPnl: number;
107
+ readonly totalPnl: number;
108
+ }
109
+ export interface TradeHistoryItem {
110
+ readonly tradeId: number;
111
+ readonly propertyId: number;
112
+ readonly side: OrderSide;
113
+ readonly quantity: number;
114
+ readonly price: number;
115
+ readonly fee: number;
116
+ readonly executedAt: string;
117
+ }
118
+ export interface PortfolioBalance {
119
+ readonly assetType: string;
120
+ readonly available: number;
121
+ readonly frozen: number;
122
+ readonly total: number;
123
+ }
124
+ export interface OrderHistoryResponse {
125
+ readonly orders: readonly OrderHistoryItem[];
126
+ readonly total: number;
127
+ readonly page: number;
128
+ readonly pageSize: number;
129
+ }
130
+ export interface TradeHistoryResponse {
131
+ readonly trades: readonly TradeHistoryItem[];
132
+ readonly total: number;
133
+ readonly page: number;
134
+ readonly pageSize: number;
135
+ }
136
+ export interface PortfolioResponse {
137
+ readonly orderHistory: readonly OrderHistoryItem[];
138
+ readonly tradeHistory: readonly TradeHistoryItem[];
139
+ readonly metrics: readonly OrderPositionMetrics[];
140
+ readonly balances: readonly PortfolioBalance[];
141
+ }
142
+ export interface PriceLevel {
143
+ price: number;
144
+ quantity: number;
145
+ }
146
+ export interface OrderBook {
147
+ property_id: number;
148
+ bids: PriceLevel[];
149
+ asks: PriceLevel[];
150
+ }
151
+ export interface UserProfileResponse {
152
+ readonly userId: string;
153
+ readonly user_type: 'INVESTOR' | 'HOMEOWNER' | 'ADMIN' | 'MARKET_MAKER';
154
+ readonly kycVerified: boolean;
155
+ }
156
+ export declare const propertySchema: z.ZodObject<{
157
+ id: z.ZodNumber;
158
+ tokenName: z.ZodString;
159
+ address: z.ZodString;
160
+ price: z.ZodNumber;
161
+ imageUrl: z.ZodString;
162
+ }, z.core.$strip>;
163
+ export declare const propertyListSchema: z.ZodArray<z.ZodObject<{
164
+ id: z.ZodNumber;
165
+ tokenName: z.ZodString;
166
+ address: z.ZodString;
167
+ price: z.ZodNumber;
168
+ imageUrl: z.ZodString;
169
+ }, z.core.$strip>>;
170
+ export type Property = z.infer<typeof propertySchema>;
171
+ export interface Candle {
172
+ readonly time: number;
173
+ readonly open: number;
174
+ readonly high: number;
175
+ readonly low: number;
176
+ readonly close: number;
177
+ readonly volume?: number;
178
+ }
179
+ export interface PropertyResponse {
180
+ readonly property: Property;
181
+ readonly orderBook: OrderBook | null;
182
+ readonly candlesticks: readonly Candle[];
183
+ }
184
+ interface BaseWebSocketMessage {
185
+ timestamp: string;
186
+ }
187
+ export interface ConnectionMessage extends BaseWebSocketMessage {
188
+ type: 'connection';
189
+ message: string;
190
+ }
191
+ export interface EchoMessage extends BaseWebSocketMessage {
192
+ type: 'echo';
193
+ data: unknown;
194
+ }
195
+ export interface TestMessage extends BaseWebSocketMessage {
196
+ type: 'test';
197
+ message: string;
198
+ }
199
+ export interface ErrorMessage extends BaseWebSocketMessage {
200
+ type: 'error';
201
+ message: string;
202
+ code?: string;
203
+ }
204
+ export interface OrderbookUpdateMessage extends BaseWebSocketMessage {
205
+ type: 'orderbook_update';
206
+ propertyId: number;
207
+ bids: PriceLevel[];
208
+ asks: PriceLevel[];
209
+ }
210
+ export interface OrderStatusMessage extends BaseWebSocketMessage {
211
+ type: 'order_status';
212
+ orderId: number;
213
+ status: OrderStatus;
214
+ }
215
+ export interface MarketDataMessage extends BaseWebSocketMessage {
216
+ type: 'market_data';
217
+ propertyId: number;
218
+ lastPrice: number;
219
+ volume24h: number;
220
+ priceChange24h: number;
221
+ }
222
+ export interface CandleUpdateMessage extends BaseWebSocketMessage {
223
+ type: 'candle_update';
224
+ propertyId: number;
225
+ candle: Candle;
226
+ }
227
+ export interface SubscribeMessage extends BaseWebSocketMessage {
228
+ type: 'subscribe';
229
+ channels: string[];
230
+ }
231
+ export interface UnsubscribeMessage extends BaseWebSocketMessage {
232
+ type: 'unsubscribe';
233
+ channels: string[];
234
+ }
235
+ export interface SubscriptionConfirmMessage extends BaseWebSocketMessage {
236
+ type: 'subscription_confirmed';
237
+ channels: string[];
238
+ }
239
+ export interface PortfolioUpdateMessage extends BaseWebSocketMessage {
240
+ type: 'portfolio_update';
241
+ userId: number;
242
+ totalValue: number;
243
+ totalPnL: number;
244
+ pnLPercentage: number;
245
+ holdings: Array<{
246
+ propertyId: number;
247
+ quantity: number;
248
+ avgPrice: number;
249
+ currentPrice: number;
250
+ pnL: number;
251
+ }>;
252
+ }
253
+ export type WebSocketMessage = ConnectionMessage | EchoMessage | TestMessage | ErrorMessage | OrderbookUpdateMessage | OrderStatusMessage | MarketDataMessage | CandleUpdateMessage | PortfolioUpdateMessage | SubscribeMessage | UnsubscribeMessage | SubscriptionConfirmMessage;
254
+ export {};
255
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,90 @@
1
+ import { z } from 'zod';
2
+ // -----------------------------------------------------------------------------
3
+ // Orders & Trading
4
+ // -----------------------------------------------------------------------------
5
+ export const MARKET_ORDER_PRICE = 0;
6
+ export const ORDER_QUANTITY_MAX_DECIMALS = 8;
7
+ export const ORDER_PRICE_MAX_DECIMALS = 2;
8
+ const orderSideEnum = z.enum(['BUY', 'SELL']);
9
+ const orderTypeEnum = z.enum(['MARKET', 'LIMIT']);
10
+ const timeInForceEnum = z.enum(['GTC', 'IOC', 'FOK', 'GTD']);
11
+ const DECIMAL_SEPARATOR = '.';
12
+ function hasExcessDecimals(value, maxDecimals) {
13
+ const [, fractional = ''] = value.toString().split(DECIMAL_SEPARATOR);
14
+ return fractional.length > maxDecimals;
15
+ }
16
+ const baseOrderSchema = z
17
+ .object({
18
+ propertyId: z.number().int().positive(),
19
+ price: z.number().nonnegative(),
20
+ quantity: z.number().positive(),
21
+ side: orderSideEnum,
22
+ type: orderTypeEnum.default('MARKET'),
23
+ timeInForce: timeInForceEnum.default('GTC'),
24
+ expiresAt: z.string().optional(),
25
+ nonce: z.string(),
26
+ walletAddress: z.string(),
27
+ })
28
+ .superRefine((data, ctx) => {
29
+ // LIMIT orders must have a positive price
30
+ if (data.type === 'LIMIT' && (typeof data.price !== 'number' || data.price <= 0)) {
31
+ ctx.addIssue({
32
+ code: 'custom',
33
+ message: 'Limit orders require a positive price',
34
+ path: ['price'],
35
+ });
36
+ }
37
+ // MARKET orders must have price = MARKET_ORDER_PRICE
38
+ if (data.type === 'MARKET' && data.price !== MARKET_ORDER_PRICE) {
39
+ ctx.addIssue({
40
+ code: 'custom',
41
+ message: `Market orders must have price = ${MARKET_ORDER_PRICE}`,
42
+ path: ['price'],
43
+ });
44
+ }
45
+ // GTD requires expiresAt
46
+ if (data.timeInForce === 'GTD' && !data.expiresAt) {
47
+ ctx.addIssue({
48
+ code: 'custom',
49
+ message: 'GTD orders require an expiration timestamp',
50
+ path: ['expiresAt'],
51
+ });
52
+ }
53
+ if (hasExcessDecimals(data.quantity, ORDER_QUANTITY_MAX_DECIMALS)) {
54
+ ctx.addIssue({
55
+ code: 'custom',
56
+ message: `Quantity must have at most ${ORDER_QUANTITY_MAX_DECIMALS} decimal places`,
57
+ path: ['quantity'],
58
+ });
59
+ }
60
+ if (data.type === 'LIMIT' && hasExcessDecimals(data.price, ORDER_PRICE_MAX_DECIMALS)) {
61
+ ctx.addIssue({
62
+ code: 'custom',
63
+ message: `Limit price must have at most ${ORDER_PRICE_MAX_DECIMALS} decimal places`,
64
+ path: ['price'],
65
+ });
66
+ }
67
+ });
68
+ // Schema for orders signed client-side (signature provided in request)
69
+ export const orderBodySchema = baseOrderSchema.safeExtend({
70
+ signature: z.string(),
71
+ });
72
+ // Schema for orders signed server-side via session signer
73
+ export const sessionSignerOrderBodySchema = baseOrderSchema.safeExtend({
74
+ tokenName: z.string(),
75
+ });
76
+ export const cancelOrderBodySchema = z.object({
77
+ orderId: z.number().int().positive(),
78
+ });
79
+ // -----------------------------------------------------------------------------
80
+ // Properties
81
+ // -----------------------------------------------------------------------------
82
+ export const propertySchema = z.object({
83
+ id: z.number().int(),
84
+ tokenName: z.string(),
85
+ address: z.string(),
86
+ price: z.number(),
87
+ imageUrl: z.string(),
88
+ });
89
+ export const propertyListSchema = z.array(propertySchema);
90
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@loafmarkets/shared-types",
3
+ "version": "1.0.1",
4
+ "description": "Shared contracts for Loaf Markets frontend, backend, and matching engine.",
5
+ "type": "module",
6
+ "private": false,
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./proto/trading.proto": "./proto/trading.proto"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "proto"
19
+ ],
20
+ "keywords": [],
21
+ "author": "Cohen",
22
+ "dependencies": {
23
+ "zod": "^4.2.1"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^25.0.3",
27
+ "rimraf": "^6.1.2",
28
+ "typescript": "^5.9.3"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc -p tsconfig.json",
35
+ "clean": "rimraf dist"
36
+ }
37
+ }
@@ -0,0 +1,172 @@
1
+ syntax = "proto3";
2
+
3
+ package loaf.trading;
4
+
5
+ // Order message
6
+ message Order {
7
+ uint64 order_id = 1;
8
+ uint32 user_id = 2;
9
+ uint32 property_id = 3;
10
+ uint64 price = 4;
11
+ uint32 quantity = 5;
12
+ OrderSide side = 6;
13
+ OrderType type = 7;
14
+ TimeInForce time_in_force = 8;
15
+ string expires_at = 9;
16
+ string signature = 10;
17
+ string wallet_address = 11;
18
+ }
19
+
20
+ enum OrderSide {
21
+ BUY = 0;
22
+ SELL = 1;
23
+ }
24
+
25
+ enum OrderType {
26
+ MARKET = 0;
27
+ LIMIT = 1;
28
+ }
29
+
30
+ enum TimeInForce {
31
+ GTC = 0;
32
+ IOC = 1;
33
+ FOK = 2;
34
+ GTD = 3;
35
+ }
36
+
37
+ // enum OrderStatus {
38
+ // PENDING = 0;
39
+ // PARTIALLY_FILLED = 1;
40
+ // FILLED = 2;
41
+ // CANCELLED = 3;
42
+ // REJECTED = 4;
43
+ // }
44
+
45
+
46
+ // Trade execution
47
+ message TradeExecution {
48
+ uint64 trade_id = 1;
49
+ uint64 buy_order_id = 2;
50
+ uint64 sell_order_id = 3;
51
+ uint32 property_id = 4;
52
+ string property_token_address = 5;
53
+ double price = 6;
54
+ double quantity = 7;
55
+ double fee_amount = 8;
56
+ string buyer_wallet = 9;
57
+ string seller_wallet = 10;
58
+ OrderSide side = 11;
59
+ int64 timestamp = 12;
60
+ int64 deadline = 13;
61
+ string buyer_signature = 14;
62
+ string seller_signature = 15;
63
+ string cpp_signature = 16;
64
+ }
65
+
66
+ // Order book
67
+ message PriceLevel {
68
+ double price = 1;
69
+ double quantity = 2;
70
+ }
71
+
72
+ message OrderBookSnapshot {
73
+ uint32 property_id = 1;
74
+ repeated PriceLevel bids = 2;
75
+ repeated PriceLevel asks = 3;
76
+ repeated uint64 cancelled_order_ids = 4;
77
+ }
78
+
79
+ // Quote book
80
+ message QuoteLevel {
81
+ OrderSide side = 1;
82
+ OrderType type = 2;
83
+ uint64 price = 3;
84
+ uint32 quantity = 4;
85
+ }
86
+
87
+ message QuoteBook {
88
+ uint32 property_id = 1;
89
+ repeated QuoteLevel bids = 2;
90
+ repeated QuoteLevel asks = 3;
91
+ }
92
+
93
+
94
+ // --------------------------------------------------------------
95
+ // Service 1: OrderService (for Node.js Backend)
96
+ // --------------------------------------------------------------
97
+
98
+ service OrderService {
99
+ rpc SubmitOrder(SubmitOrderRequest) returns (SubmitOrderResponse);
100
+ rpc CancelOrder(CancelOrderRequest) returns (CancelOrderResponse);
101
+ rpc GetOrderStatus(GetOrderStatusRequest) returns (Order);
102
+ }
103
+
104
+ message SubmitOrderRequest {
105
+ uint32 user_id = 1;
106
+ uint32 property_id = 2;
107
+ uint64 price = 3;
108
+ uint32 quantity = 4;
109
+ OrderSide side = 5;
110
+ OrderType type = 6;
111
+ TimeInForce time_in_force = 7;
112
+ string expires_at = 8;
113
+ uint64 order_id = 9;
114
+ string signature = 10;
115
+ string wallet_address = 11;
116
+ }
117
+
118
+ message SubmitOrderResponse {
119
+ bool success = 1;
120
+ uint64 order_id = 2;
121
+ string error_message = 3;
122
+ }
123
+
124
+ message GetOrderStatusRequest {
125
+ // string order_id = 1;
126
+ // string user_id = 2;
127
+ }
128
+
129
+ message CancelOrderRequest {
130
+ uint64 order_id = 1;
131
+ uint32 property_id = 2;
132
+ }
133
+
134
+ message CancelOrderResponse {
135
+ bool success = 1;
136
+ uint64 order_id = 2;
137
+ string error_message = 3;
138
+ }
139
+
140
+ // --------------------------------------------------------------
141
+ // Service 2: TradingService (for Market Maker)
142
+ // --------------------------------------------------------------
143
+
144
+ // service TradingService {
145
+ // rpc StreamTradingData(stream MarketMakerMessage) returns (stream EngineMessage);
146
+ // }
147
+
148
+ // message MarketMakerMessage {
149
+ // oneof message {
150
+ // MarketMakerRegistration registration = 1;
151
+ // Quote quote = 2;
152
+ // TradeAck trade_ack = 3;
153
+ // }
154
+ // }
155
+
156
+ // message EngineMessage {
157
+ // oneof message {
158
+ // Order order = 1;
159
+ // TradeExecution trade_execution = 2;
160
+ // }
161
+ // }
162
+
163
+ // message MarketMakerRegistration {
164
+ // string market_maker_id = 1;
165
+ // repeated string property_ids = 2;
166
+ // }
167
+
168
+ // message TradeAck {
169
+ // string trade_id = 1;
170
+ // bool acknowledged = 2;
171
+ // string error_message = 3;
172
+ // }