Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

feat: add order instructions #52

Merged
merged 14 commits into from
Jul 24, 2024
13 changes: 0 additions & 13 deletions lib/src/http_client/tbdex_http_client.dart
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:tbdex/src/http_client/exceptions/http_exceptions.dart';
import 'package:tbdex/src/http_client/exceptions/token_exceptions.dart';
import 'package:tbdex/src/http_client/exceptions/validation_exceptions.dart';
import 'package:tbdex/src/http_client/models/create_exchange_request.dart';
import 'package:tbdex/src/http_client/models/exchange.dart';
import 'package:tbdex/src/http_client/models/get_offerings_filter.dart';
import 'package:tbdex/src/http_client/models/submit_cancel_request.dart';
import 'package:tbdex/src/http_client/models/submit_close_request.dart';
import 'package:tbdex/src/http_client/models/submit_order_request.dart';
import 'package:tbdex/src/protocol/models/balance.dart';
import 'package:tbdex/src/protocol/models/close.dart';
import 'package:tbdex/src/protocol/models/offering.dart';
import 'package:tbdex/src/protocol/models/order.dart';
import 'package:tbdex/src/protocol/models/rfq.dart';
import 'package:tbdex/src/protocol/parser.dart';
import 'package:tbdex/src/protocol/validator.dart';
import 'package:tbdex/tbdex.dart';
import 'package:typeid/typeid.dart';
import 'package:web5/web5.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/protocol/jcs.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'dart:convert';
import 'dart:typed_data';

// TODO: turn into standalone lib
// TODO(ethan-tbd): turn into standalone lib

/// Implements the JSON Canonicalization Scheme specified in
/// [RFC8785](https://www.rfc-editor.org/rfc/rfc8785)
Expand Down
2 changes: 1 addition & 1 deletion lib/src/protocol/json_schemas/message_schema.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class MessageSchema {
},
"kind": {
"type": "string",
"enum": ["rfq", "quote", "order", "orderstatus", "close", "cancel"],
"enum": ["rfq", "quote", "order", "orderstatus", "close", "cancel", "orderinstructions"],
"description": "The message kind (e.g. rfq, quote)"
},
"id": {
Expand Down
35 changes: 35 additions & 0 deletions lib/src/protocol/json_schemas/orderinstructions_schema.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class OrderinstructionsSchema {
static const String json = r'''
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://tbdex.dev/orderinstructions.schema.json",
"type": "object",
"additionalProperties": false,
"properties": {
"payin": {
"$ref": "#/definitions/PaymentInstruction"
},
"payout": {
"$ref": "#/definitions/PaymentInstruction"
}
},
"definitions": {
"PaymentInstruction": {
"type": "object",
"additionalProperties": false,
"properties": {
"link": {
"type": "string",
"description": "Link to allow Alice to pay PFI, or be paid by the PFI"
},
"instruction": {
"type": "string",
"description": "Instruction on how Alice can pay PFI, or how Alice can be paid by the PFI"
}
}
}
},
"required": ["payin", "payout"]
}
''';
}
17 changes: 0 additions & 17 deletions lib/src/protocol/json_schemas/quote_schema.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,9 @@ class QuoteSchema {
"total": {
"$ref": "definitions.json#/definitions/decimalString",
"description": "The total amount of currency to be paid in or paid out. It is always a sum of subtotal and fee"
},
"paymentInstruction": {
"$ref": "#/definitions/PaymentInstruction"
}
},
"required": ["currencyCode", "subtotal", "total"]
},
"PaymentInstruction": {
"type": "object",
"additionalProperties": false,
"properties": {
"link": {
"type": "string",
"description": "Link to allow Alice to pay PFI, or be paid by the PFI"
},
"instruction": {
"type": "string",
"description": "Instruction on how Alice can pay PFI, or how Alice can be paid by the PFI"
}
}
}
},
"type": "object",
Expand Down
1 change: 1 addition & 0 deletions lib/src/protocol/models/message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ enum MessageKind {
cancel,
order,
orderstatus,
orderinstructions,
}

class MessageMetadata extends Metadata {
Expand Down
29 changes: 22 additions & 7 deletions lib/src/protocol/models/message_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -209,14 +209,12 @@ class QuoteDetails {
final String subtotal;
final String total;
final String? fee;
final PaymentInstruction? paymentInstruction;

QuoteDetails({
required this.currencyCode,
required this.subtotal,
required this.total,
this.fee,
this.paymentInstruction,
});

factory QuoteDetails.fromJson(Map<String, dynamic> json) {
Expand All @@ -225,9 +223,6 @@ class QuoteDetails {
subtotal: json['subtotal'],
total: json['total'],
fee: json['fee'],
paymentInstruction: json['paymentInstruction'] != null
? PaymentInstruction.fromJson(json['paymentInstruction'])
: null,
);
}

Expand All @@ -237,8 +232,6 @@ class QuoteDetails {
'subtotal': subtotal,
'total': total,
if (fee != null) 'fee': fee,
if (paymentInstruction != null)
'paymentInstruction': paymentInstruction?.toJson(),
};
}
}
Expand Down Expand Up @@ -338,3 +331,25 @@ class OrderStatusData extends MessageData {
};
}
}

class OrderInstructionsData extends MessageData {
final PaymentInstruction payin;
final PaymentInstruction payout;

OrderInstructionsData({required this.payin, required this.payout});

factory OrderInstructionsData.fromJson(Map<String, dynamic> json) {
return OrderInstructionsData(
payin: PaymentInstruction.fromJson(json['payin']),
payout: PaymentInstruction.fromJson(json['payout']),
);
}

@override
Map<String, dynamic> toJson() {
return {
'payin': payin.toJson(),
'payout': payout.toJson(),
};
}
}
3 changes: 2 additions & 1 deletion lib/src/protocol/models/order.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ class Order extends Message {
final OrderData data;

@override
Set<MessageKind> get validNext => {MessageKind.orderstatus};
Set<MessageKind> get validNext =>
{MessageKind.orderstatus, MessageKind.close, MessageKind.cancel};

Order._({
required this.metadata,
Expand Down
70 changes: 70 additions & 0 deletions lib/src/protocol/models/order_instructions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import 'package:tbdex/src/protocol/models/message.dart';
import 'package:tbdex/src/protocol/models/message_data.dart';
import 'package:tbdex/src/protocol/parser.dart';

class OrderInstructions extends Message {
@override
final MessageMetadata metadata;
@override
final OrderInstructionsData data;

@override
Set<MessageKind> get validNext =>
{MessageKind.orderstatus, MessageKind.close, MessageKind.cancel};

OrderInstructions._({
required this.metadata,
required this.data,
String? signature,
}) : super() {
this.signature = signature;
}

static OrderInstructions create(
String to,
String from,
String exchangeId,
OrderInstructionsData data, {
String? externalId,
String protocol = '1.0',
}) {
final now = DateTime.now().toUtc().toIso8601String();
final metadata = MessageMetadata(
kind: MessageKind.orderinstructions,
to: to,
from: from,
id: Message.generateId(MessageKind.orderinstructions),
exchangeId: exchangeId,
createdAt: now,
protocol: protocol,
externalId: externalId,
);

return OrderInstructions._(
metadata: metadata,
data: data,
);
}

static Future<OrderInstructions> parse(String rawMessage) async {
final orderStatus = Parser.parseMessage(rawMessage) as OrderInstructions;
await orderStatus.verify();
return orderStatus;
}

factory OrderInstructions.fromJson(Map<String, dynamic> json) {
return OrderInstructions._(
metadata: MessageMetadata.fromJson(json['metadata']),
data: OrderInstructionsData.fromJson(json['data']),
signature: json['signature'],
);
}

Map<String, dynamic> toJson() {
return {
'metadata': metadata.toJson(),
'data': data.toJson(),
'signature': signature,
};
}
}
2 changes: 1 addition & 1 deletion lib/src/protocol/models/order_status.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class OrderStatus extends Message {

@override
Set<MessageKind> get validNext =>
{MessageKind.orderstatus, MessageKind.close};
{MessageKind.orderstatus, MessageKind.close, MessageKind.cancel};

OrderStatus._({
required this.metadata,
Expand Down
3 changes: 2 additions & 1 deletion lib/src/protocol/models/quote.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ class Quote extends Message {
final QuoteData data;

@override
Set<MessageKind> get validNext => {MessageKind.order, MessageKind.close};
Set<MessageKind> get validNext =>
{MessageKind.order, MessageKind.close, MessageKind.cancel};

Quote._({
required this.metadata,
Expand Down
3 changes: 2 additions & 1 deletion lib/src/protocol/models/rfq.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class Rfq extends Message {
final RfqPrivateData? privateData;

@override
Set<MessageKind> get validNext => {MessageKind.quote, MessageKind.close};
Set<MessageKind> get validNext =>
{MessageKind.quote, MessageKind.close, MessageKind.cancel};

Rfq._({
required this.metadata,
Expand Down
3 changes: 3 additions & 0 deletions lib/src/protocol/parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:tbdex/src/protocol/models/close.dart';
import 'package:tbdex/src/protocol/models/message.dart';
import 'package:tbdex/src/protocol/models/offering.dart';
import 'package:tbdex/src/protocol/models/order.dart';
import 'package:tbdex/src/protocol/models/order_instructions.dart';
import 'package:tbdex/src/protocol/models/order_status.dart';
import 'package:tbdex/src/protocol/models/quote.dart';
import 'package:tbdex/src/protocol/models/resource.dart';
Expand Down Expand Up @@ -147,6 +148,8 @@ abstract class Parser {
return Order.fromJson(jsonObject);
case MessageKind.orderstatus:
return OrderStatus.fromJson(jsonObject);
case MessageKind.orderinstructions:
return OrderInstructions.fromJson(jsonObject);
}
}

Expand Down
13 changes: 13 additions & 0 deletions lib/src/protocol/validator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:tbdex/src/protocol/json_schemas/definitions_schema.dart';
import 'package:tbdex/src/protocol/json_schemas/message_schema.dart';
import 'package:tbdex/src/protocol/json_schemas/offering_schema.dart';
import 'package:tbdex/src/protocol/json_schemas/order_schema.dart';
import 'package:tbdex/src/protocol/json_schemas/orderinstructions_schema.dart';
import 'package:tbdex/src/protocol/json_schemas/orderstatus_schema.dart';
import 'package:tbdex/src/protocol/json_schemas/quote_schema.dart';
import 'package:tbdex/src/protocol/json_schemas/resource_schema.dart';
Expand All @@ -19,6 +20,7 @@ import 'package:tbdex/src/protocol/models/close.dart';
import 'package:tbdex/src/protocol/models/message.dart';
import 'package:tbdex/src/protocol/models/offering.dart';
import 'package:tbdex/src/protocol/models/order.dart';
import 'package:tbdex/src/protocol/models/order_instructions.dart';
import 'package:tbdex/src/protocol/models/order_status.dart';
import 'package:tbdex/src/protocol/models/quote.dart';
import 'package:tbdex/src/protocol/models/resource.dart';
Expand Down Expand Up @@ -103,6 +105,13 @@ class Validator {
orderStatus.metadata.kind.name,
);
break;
case MessageKind.orderinstructions:
final orderInstructions = message as OrderInstructions;
_instance._validate(orderInstructions.toJson(), 'message');
_instance._validate(
orderInstructions.data.toJson(),
orderInstructions.metadata.kind.name,
);
}
}

Expand Down Expand Up @@ -152,6 +161,10 @@ class Validator {
JsonSchema.create(MessageSchema.json, refProvider: refProvider);
_schemaMap['order'] =
JsonSchema.create(OrderSchema.json, refProvider: refProvider);
_schemaMap['orderinstructions'] = JsonSchema.create(
OrderinstructionsSchema.json,
refProvider: refProvider,
);
_schemaMap['orderstatus'] =
JsonSchema.create(OrderstatusSchema.json, refProvider: refProvider);
_schemaMap['quote'] =
Expand Down
Loading
Loading