@ledgerhq/hw-app-exchange 0.1.0
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/.turbo/turbo-build.log +4 -0
- package/README.md +15 -0
- package/jest.config.ts +6 -0
- package/lib/Exchange.d.ts +28 -0
- package/lib/Exchange.d.ts.map +1 -0
- package/lib/Exchange.js +225 -0
- package/lib/Exchange.js.map +1 -0
- package/lib/Exchange.test.d.ts +2 -0
- package/lib/Exchange.test.d.ts.map +1 -0
- package/lib/Exchange.test.js +130 -0
- package/lib/Exchange.test.js.map +1 -0
- package/lib-es/Exchange.d.ts +28 -0
- package/lib-es/Exchange.d.ts.map +1 -0
- package/lib-es/Exchange.js +220 -0
- package/lib-es/Exchange.js.map +1 -0
- package/lib-es/Exchange.test.d.ts +2 -0
- package/lib-es/Exchange.test.d.ts.map +1 -0
- package/lib-es/Exchange.test.js +125 -0
- package/lib-es/Exchange.test.js.map +1 -0
- package/package.json +53 -0
- package/src/Exchange.test.ts +87 -0
- package/src/Exchange.ts +206 -0
- package/tsconfig.json +7 -0
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<img src="https://user-images.githubusercontent.com/4631227/191834116-59cf590e-25cc-4956-ae5c-812ea464f324.png" height="100" />
|
|
2
|
+
|
|
3
|
+
[GitHub](https://github.com/LedgerHQ/ledger-live/),
|
|
4
|
+
[Ledger Devs Discord](https://developers.ledger.com/discord-pro),
|
|
5
|
+
[Developer Portal](https://developers.ledger.com/)
|
|
6
|
+
|
|
7
|
+
## @ledgerhq/hw-app-exchange
|
|
8
|
+
|
|
9
|
+
Ledger Hardware Wallet Exchange app.
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
|
14
|
+
|
|
15
|
+
### Table of Contents
|
package/jest.config.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import Transport from "@ledgerhq/hw-transport";
|
|
3
|
+
import { BigNumber } from "bignumber.js";
|
|
4
|
+
export declare const enum RateTypes {
|
|
5
|
+
Fixed = 0,
|
|
6
|
+
Floating = 1
|
|
7
|
+
}
|
|
8
|
+
export declare const enum ExchangeTypes {
|
|
9
|
+
Swap = 0,
|
|
10
|
+
Sell = 1,
|
|
11
|
+
Fund = 2
|
|
12
|
+
}
|
|
13
|
+
export default class Exchange {
|
|
14
|
+
transport: Transport;
|
|
15
|
+
transactionType: ExchangeTypes;
|
|
16
|
+
transactionRate: RateTypes;
|
|
17
|
+
allowedStatuses: Array<number>;
|
|
18
|
+
constructor(transport: Transport, transactionType: ExchangeTypes, transactionRate?: RateTypes);
|
|
19
|
+
startNewTransaction(): Promise<string>;
|
|
20
|
+
setPartnerKey(partnerNameAndPublicKey: Buffer): Promise<void>;
|
|
21
|
+
checkPartner(signatureOfPartnerData: Buffer): Promise<void>;
|
|
22
|
+
processTransaction(transaction: Buffer, fee: BigNumber): Promise<void>;
|
|
23
|
+
checkTransactionSignature(transactionSignature: Buffer): Promise<void>;
|
|
24
|
+
checkPayoutAddress(payoutCurrencyConfig: Buffer, currencyConfigSignature: Buffer, addressParameters: Buffer): Promise<void>;
|
|
25
|
+
checkRefundAddress(refundCurrencyConfig: Buffer, currencyConfigSignature: Buffer, addressParameters: Buffer): Promise<void>;
|
|
26
|
+
signCoinTransaction(): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=Exchange.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Exchange.d.ts","sourceRoot":"","sources":["../src/Exchange.ts"],"names":[],"mappings":";AAAA,OAAO,SAAS,MAAM,wBAAwB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAIzC,0BAAkB,SAAS;IACzB,KAAK,IAAO;IACZ,QAAQ,IAAO;CAChB;AAED,0BAAkB,aAAa;IAC7B,IAAI,IAAO;IACX,IAAI,IAAO;IACX,IAAI,IAAO;CACZ;AAqBD,MAAM,CAAC,OAAO,OAAO,QAAQ;IAC3B,SAAS,EAAE,SAAS,CAAC;IACrB,eAAe,EAAE,aAAa,CAAC;IAC/B,eAAe,EAAE,SAAS,CAAC;IAC3B,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAG5B;gBAGA,SAAS,EAAE,SAAS,EACpB,eAAe,EAAE,aAAa,EAC9B,eAAe,CAAC,EAAE,SAAS;IAOvB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAqBtC,aAAa,CAAC,uBAAuB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7D,YAAY,CAAC,sBAAsB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY3D,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBtE,yBAAyB,CAAC,oBAAoB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYtE,kBAAkB,CACtB,oBAAoB,EAAE,MAAM,EAC5B,uBAAuB,EAAE,MAAM,EAC/B,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC;IA4BV,kBAAkB,CACtB,oBAAoB,EAAE,MAAM,EAC5B,uBAAuB,EAAE,MAAM,EAC/B,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC;IA0BV,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;CAW3C"}
|
package/lib/Exchange.js
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
exports.__esModule = true;
|
|
42
|
+
var errors_1 = require("@ledgerhq/errors");
|
|
43
|
+
var invariant_1 = __importDefault(require("invariant"));
|
|
44
|
+
var START_NEW_TRANSACTION_COMMAND = 0x03;
|
|
45
|
+
var SET_PARTNER_KEY_COMMAND = 0x04;
|
|
46
|
+
var CHECK_PARTNER_COMMAND = 0x05;
|
|
47
|
+
var PROCESS_TRANSACTION_RESPONSE = 0x06;
|
|
48
|
+
var CHECK_TRANSACTION_SIGNATURE = 0x07;
|
|
49
|
+
var CHECK_PAYOUT_ADDRESS = 0x08;
|
|
50
|
+
var CHECK_ASSET_IN = 0x08;
|
|
51
|
+
var CHECK_REFUND_ADDRESS = 0x09;
|
|
52
|
+
var SIGN_COIN_TRANSACTION = 0x0a;
|
|
53
|
+
var maybeThrowProtocolError = function (result) {
|
|
54
|
+
(0, invariant_1["default"])(result.length >= 2, "ExchangeTransport: Unexpected result length");
|
|
55
|
+
var resultCode = result.readUInt16BE(result.length - 2);
|
|
56
|
+
if (resultCode !== 0x9000) {
|
|
57
|
+
throw new errors_1.TransportStatusError(resultCode);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var Exchange = /** @class */ (function () {
|
|
61
|
+
function Exchange(transport, transactionType, transactionRate) {
|
|
62
|
+
this.allowedStatuses = [
|
|
63
|
+
0x9000, 0x6a80, 0x6a81, 0x6a82, 0x6a83, 0x6a84, 0x6a85, 0x6e00, 0x6d00,
|
|
64
|
+
0x9d1a,
|
|
65
|
+
];
|
|
66
|
+
this.transactionType = transactionType;
|
|
67
|
+
this.transactionRate = transactionRate || 0 /* RateTypes.Fixed */;
|
|
68
|
+
this.transport = transport;
|
|
69
|
+
}
|
|
70
|
+
Exchange.prototype.startNewTransaction = function () {
|
|
71
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
72
|
+
var result;
|
|
73
|
+
return __generator(this, function (_a) {
|
|
74
|
+
switch (_a.label) {
|
|
75
|
+
case 0: return [4 /*yield*/, this.transport.send(0xe0, START_NEW_TRANSACTION_COMMAND, this.transactionRate, this.transactionType, Buffer.alloc(0), this.allowedStatuses)];
|
|
76
|
+
case 1:
|
|
77
|
+
result = _a.sent();
|
|
78
|
+
maybeThrowProtocolError(result);
|
|
79
|
+
if (this.transactionType === 1 /* ExchangeTypes.Sell */ ||
|
|
80
|
+
this.transactionType === 2 /* ExchangeTypes.Fund */) {
|
|
81
|
+
return [2 /*return*/, result.slice(0, 32).toString("base64")];
|
|
82
|
+
}
|
|
83
|
+
return [2 /*return*/, result.toString("ascii", 0, 10)];
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
Exchange.prototype.setPartnerKey = function (partnerNameAndPublicKey) {
|
|
89
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
90
|
+
var result;
|
|
91
|
+
return __generator(this, function (_a) {
|
|
92
|
+
switch (_a.label) {
|
|
93
|
+
case 0: return [4 /*yield*/, this.transport.send(0xe0, SET_PARTNER_KEY_COMMAND, this.transactionRate, this.transactionType, partnerNameAndPublicKey, this.allowedStatuses)];
|
|
94
|
+
case 1:
|
|
95
|
+
result = _a.sent();
|
|
96
|
+
maybeThrowProtocolError(result);
|
|
97
|
+
return [2 /*return*/];
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
Exchange.prototype.checkPartner = function (signatureOfPartnerData) {
|
|
103
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
104
|
+
var result;
|
|
105
|
+
return __generator(this, function (_a) {
|
|
106
|
+
switch (_a.label) {
|
|
107
|
+
case 0: return [4 /*yield*/, this.transport.send(0xe0, CHECK_PARTNER_COMMAND, this.transactionRate, this.transactionType, signatureOfPartnerData, this.allowedStatuses)];
|
|
108
|
+
case 1:
|
|
109
|
+
result = _a.sent();
|
|
110
|
+
maybeThrowProtocolError(result);
|
|
111
|
+
return [2 /*return*/];
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
Exchange.prototype.processTransaction = function (transaction, fee) {
|
|
117
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
118
|
+
var hex, feeHex, bufferToSend, result;
|
|
119
|
+
return __generator(this, function (_a) {
|
|
120
|
+
switch (_a.label) {
|
|
121
|
+
case 0:
|
|
122
|
+
hex = fee.toString(16);
|
|
123
|
+
hex = hex.padStart(hex.length + (hex.length % 2), "0");
|
|
124
|
+
feeHex = Buffer.from(hex, "hex");
|
|
125
|
+
bufferToSend = Buffer.concat([
|
|
126
|
+
Buffer.from([transaction.length]),
|
|
127
|
+
transaction,
|
|
128
|
+
Buffer.from([feeHex.length]),
|
|
129
|
+
feeHex,
|
|
130
|
+
]);
|
|
131
|
+
return [4 /*yield*/, this.transport.send(0xe0, PROCESS_TRANSACTION_RESPONSE, this.transactionRate, this.transactionType, bufferToSend, this.allowedStatuses)];
|
|
132
|
+
case 1:
|
|
133
|
+
result = _a.sent();
|
|
134
|
+
maybeThrowProtocolError(result);
|
|
135
|
+
return [2 /*return*/];
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
Exchange.prototype.checkTransactionSignature = function (transactionSignature) {
|
|
141
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
142
|
+
var result;
|
|
143
|
+
return __generator(this, function (_a) {
|
|
144
|
+
switch (_a.label) {
|
|
145
|
+
case 0: return [4 /*yield*/, this.transport.send(0xe0, CHECK_TRANSACTION_SIGNATURE, this.transactionRate, this.transactionType, transactionSignature, this.allowedStatuses)];
|
|
146
|
+
case 1:
|
|
147
|
+
result = _a.sent();
|
|
148
|
+
maybeThrowProtocolError(result);
|
|
149
|
+
return [2 /*return*/];
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
Exchange.prototype.checkPayoutAddress = function (payoutCurrencyConfig, currencyConfigSignature, addressParameters) {
|
|
155
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
156
|
+
var bufferToSend, result;
|
|
157
|
+
return __generator(this, function (_a) {
|
|
158
|
+
switch (_a.label) {
|
|
159
|
+
case 0:
|
|
160
|
+
(0, invariant_1["default"])(payoutCurrencyConfig.length <= 255, "Currency config is too big");
|
|
161
|
+
(0, invariant_1["default"])(addressParameters.length <= 255, "Address parameter is too big.");
|
|
162
|
+
(0, invariant_1["default"])(currencyConfigSignature.length >= 67 &&
|
|
163
|
+
currencyConfigSignature.length <= 73, "Signature should be DER serialized and have length in [67, 73] bytes.");
|
|
164
|
+
bufferToSend = Buffer.concat([
|
|
165
|
+
Buffer.from([payoutCurrencyConfig.length]),
|
|
166
|
+
payoutCurrencyConfig,
|
|
167
|
+
currencyConfigSignature,
|
|
168
|
+
Buffer.from([addressParameters.length]),
|
|
169
|
+
addressParameters,
|
|
170
|
+
]);
|
|
171
|
+
return [4 /*yield*/, this.transport.send(0xe0, this.transactionType === 0 /* ExchangeTypes.Swap */
|
|
172
|
+
? CHECK_PAYOUT_ADDRESS
|
|
173
|
+
: CHECK_ASSET_IN, this.transactionRate, this.transactionType, bufferToSend, this.allowedStatuses)];
|
|
174
|
+
case 1:
|
|
175
|
+
result = _a.sent();
|
|
176
|
+
maybeThrowProtocolError(result);
|
|
177
|
+
return [2 /*return*/];
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
};
|
|
182
|
+
Exchange.prototype.checkRefundAddress = function (refundCurrencyConfig, currencyConfigSignature, addressParameters) {
|
|
183
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
184
|
+
var bufferToSend, result;
|
|
185
|
+
return __generator(this, function (_a) {
|
|
186
|
+
switch (_a.label) {
|
|
187
|
+
case 0:
|
|
188
|
+
(0, invariant_1["default"])(refundCurrencyConfig.length <= 255, "Currency config is too big");
|
|
189
|
+
(0, invariant_1["default"])(addressParameters.length <= 255, "Address parameter is too big.");
|
|
190
|
+
(0, invariant_1["default"])(currencyConfigSignature.length >= 67 &&
|
|
191
|
+
currencyConfigSignature.length <= 73, "Signature should be DER serialized and have length in [67, 73] bytes.");
|
|
192
|
+
bufferToSend = Buffer.concat([
|
|
193
|
+
Buffer.from([refundCurrencyConfig.length]),
|
|
194
|
+
refundCurrencyConfig,
|
|
195
|
+
currencyConfigSignature,
|
|
196
|
+
Buffer.from([addressParameters.length]),
|
|
197
|
+
addressParameters,
|
|
198
|
+
]);
|
|
199
|
+
return [4 /*yield*/, this.transport.send(0xe0, CHECK_REFUND_ADDRESS, this.transactionRate, this.transactionType, bufferToSend, this.allowedStatuses)];
|
|
200
|
+
case 1:
|
|
201
|
+
result = _a.sent();
|
|
202
|
+
maybeThrowProtocolError(result);
|
|
203
|
+
return [2 /*return*/];
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
Exchange.prototype.signCoinTransaction = function () {
|
|
209
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
210
|
+
var result;
|
|
211
|
+
return __generator(this, function (_a) {
|
|
212
|
+
switch (_a.label) {
|
|
213
|
+
case 0: return [4 /*yield*/, this.transport.send(0xe0, SIGN_COIN_TRANSACTION, this.transactionRate, this.transactionType, Buffer.alloc(0), this.allowedStatuses)];
|
|
214
|
+
case 1:
|
|
215
|
+
result = _a.sent();
|
|
216
|
+
maybeThrowProtocolError(result);
|
|
217
|
+
return [2 /*return*/];
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
return Exchange;
|
|
223
|
+
}());
|
|
224
|
+
exports["default"] = Exchange;
|
|
225
|
+
//# sourceMappingURL=Exchange.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Exchange.js","sourceRoot":"","sources":["../src/Exchange.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,2CAAwD;AACxD,wDAAkC;AAalC,IAAM,6BAA6B,GAAG,IAAI,CAAC;AAC3C,IAAM,uBAAuB,GAAG,IAAI,CAAC;AACrC,IAAM,qBAAqB,GAAG,IAAI,CAAC;AACnC,IAAM,4BAA4B,GAAG,IAAI,CAAC;AAC1C,IAAM,2BAA2B,GAAG,IAAI,CAAC;AACzC,IAAM,oBAAoB,GAAG,IAAI,CAAC;AAClC,IAAM,cAAc,GAAG,IAAI,CAAC;AAC5B,IAAM,oBAAoB,GAAG,IAAI,CAAC;AAClC,IAAM,qBAAqB,GAAG,IAAI,CAAC;AAEnC,IAAM,uBAAuB,GAAG,UAAC,MAAc;IAC7C,IAAA,sBAAS,EAAC,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,6CAA6C,CAAC,CAAC;IAC7E,IAAM,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE1D,IAAI,UAAU,KAAK,MAAM,EAAE;QACzB,MAAM,IAAI,6BAAoB,CAAC,UAAU,CAAC,CAAC;KAC5C;AACH,CAAC,CAAC;AAEF;IASE,kBACE,SAAoB,EACpB,eAA8B,EAC9B,eAA2B;QAR7B,oBAAe,GAAkB;YAC/B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;YACtE,MAAM;SACP,CAAC;QAOA,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,eAAe,GAAG,eAAe,2BAAmB,CAAC;QAC1D,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAEK,sCAAmB,GAAzB;;;;;4BACyB,qBAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC9C,IAAI,EACJ,6BAA6B,EAC7B,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,eAAe,EACpB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EACf,IAAI,CAAC,eAAe,CACrB,EAAA;;wBAPK,MAAM,GAAW,SAOtB;wBACD,uBAAuB,CAAC,MAAM,CAAC,CAAC;wBAEhC,IACE,IAAI,CAAC,eAAe,+BAAuB;4BAC3C,IAAI,CAAC,eAAe,+BAAuB,EAC3C;4BACA,sBAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAC;yBAC/C;wBAED,sBAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,EAAC;;;;KACxC;IAEK,gCAAa,GAAnB,UAAoB,uBAA+B;;;;;4BAC1B,qBAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC9C,IAAI,EACJ,uBAAuB,EACvB,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,eAAe,EACpB,uBAAuB,EACvB,IAAI,CAAC,eAAe,CACrB,EAAA;;wBAPK,MAAM,GAAW,SAOtB;wBACD,uBAAuB,CAAC,MAAM,CAAC,CAAC;;;;;KACjC;IAEK,+BAAY,GAAlB,UAAmB,sBAA8B;;;;;4BACxB,qBAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC9C,IAAI,EACJ,qBAAqB,EACrB,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,eAAe,EACpB,sBAAsB,EACtB,IAAI,CAAC,eAAe,CACrB,EAAA;;wBAPK,MAAM,GAAW,SAOtB;wBACD,uBAAuB,CAAC,MAAM,CAAC,CAAC;;;;;KACjC;IAEK,qCAAkB,GAAxB,UAAyB,WAAmB,EAAE,GAAc;;;;;;wBACtD,GAAG,GAAW,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;wBACnC,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;wBACjD,MAAM,GAAW,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;wBACzC,YAAY,GAAW,MAAM,CAAC,MAAM,CAAC;4BACzC,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;4BACjC,WAAW;4BACX,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;4BAC5B,MAAM;yBACP,CAAC,CAAC;wBACoB,qBAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC9C,IAAI,EACJ,4BAA4B,EAC5B,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,eAAe,EACpB,YAAY,EACZ,IAAI,CAAC,eAAe,CACrB,EAAA;;wBAPK,MAAM,GAAW,SAOtB;wBACD,uBAAuB,CAAC,MAAM,CAAC,CAAC;;;;;KACjC;IAEK,4CAAyB,GAA/B,UAAgC,oBAA4B;;;;;4BACnC,qBAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC9C,IAAI,EACJ,2BAA2B,EAC3B,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,eAAe,EACpB,oBAAoB,EACpB,IAAI,CAAC,eAAe,CACrB,EAAA;;wBAPK,MAAM,GAAW,SAOtB;wBACD,uBAAuB,CAAC,MAAM,CAAC,CAAC;;;;;KACjC;IAEK,qCAAkB,GAAxB,UACE,oBAA4B,EAC5B,uBAA+B,EAC/B,iBAAyB;;;;;;wBAEzB,IAAA,sBAAS,EAAC,oBAAoB,CAAC,MAAM,IAAI,GAAG,EAAE,4BAA4B,CAAC,CAAC;wBAC5E,IAAA,sBAAS,EAAC,iBAAiB,CAAC,MAAM,IAAI,GAAG,EAAE,+BAA+B,CAAC,CAAC;wBAC5E,IAAA,sBAAS,EACP,uBAAuB,CAAC,MAAM,IAAI,EAAE;4BAClC,uBAAuB,CAAC,MAAM,IAAI,EAAE,EACtC,uEAAuE,CACxE,CAAC;wBACI,YAAY,GAAW,MAAM,CAAC,MAAM,CAAC;4BACzC,MAAM,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;4BAC1C,oBAAoB;4BACpB,uBAAuB;4BACvB,MAAM,CAAC,IAAI,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;4BACvC,iBAAiB;yBAClB,CAAC,CAAC;wBACoB,qBAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC9C,IAAI,EACJ,IAAI,CAAC,eAAe,+BAAuB;gCACzC,CAAC,CAAC,oBAAoB;gCACtB,CAAC,CAAC,cAAc,EAClB,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,eAAe,EACpB,YAAY,EACZ,IAAI,CAAC,eAAe,CACrB,EAAA;;wBATK,MAAM,GAAW,SAStB;wBACD,uBAAuB,CAAC,MAAM,CAAC,CAAC;;;;;KACjC;IAEK,qCAAkB,GAAxB,UACE,oBAA4B,EAC5B,uBAA+B,EAC/B,iBAAyB;;;;;;wBAEzB,IAAA,sBAAS,EAAC,oBAAoB,CAAC,MAAM,IAAI,GAAG,EAAE,4BAA4B,CAAC,CAAC;wBAC5E,IAAA,sBAAS,EAAC,iBAAiB,CAAC,MAAM,IAAI,GAAG,EAAE,+BAA+B,CAAC,CAAC;wBAC5E,IAAA,sBAAS,EACP,uBAAuB,CAAC,MAAM,IAAI,EAAE;4BAClC,uBAAuB,CAAC,MAAM,IAAI,EAAE,EACtC,uEAAuE,CACxE,CAAC;wBACI,YAAY,GAAW,MAAM,CAAC,MAAM,CAAC;4BACzC,MAAM,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;4BAC1C,oBAAoB;4BACpB,uBAAuB;4BACvB,MAAM,CAAC,IAAI,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;4BACvC,iBAAiB;yBAClB,CAAC,CAAC;wBACoB,qBAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC9C,IAAI,EACJ,oBAAoB,EACpB,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,eAAe,EACpB,YAAY,EACZ,IAAI,CAAC,eAAe,CACrB,EAAA;;wBAPK,MAAM,GAAW,SAOtB;wBACD,uBAAuB,CAAC,MAAM,CAAC,CAAC;;;;;KACjC;IAEK,sCAAmB,GAAzB;;;;;4BACyB,qBAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC9C,IAAI,EACJ,qBAAqB,EACrB,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,eAAe,EACpB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EACf,IAAI,CAAC,eAAe,CACrB,EAAA;;wBAPK,MAAM,GAAW,SAOtB;wBACD,uBAAuB,CAAC,MAAM,CAAC,CAAC;;;;;KACjC;IACH,eAAC;AAAD,CAAC,AA1KD,IA0KC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Exchange.test.d.ts","sourceRoot":"","sources":["../src/Exchange.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
exports.__esModule = true;
|
|
42
|
+
var hw_transport_mocker_1 = require("@ledgerhq/hw-transport-mocker");
|
|
43
|
+
var Exchange_1 = __importDefault(require("./Exchange"));
|
|
44
|
+
var util_1 = require("util");
|
|
45
|
+
describe("Contrustructor", function () {
|
|
46
|
+
[2 /* ExchangeTypes.Fund */, 1 /* ExchangeTypes.Sell */, 0 /* ExchangeTypes.Swap */].forEach(function (exchangeType) {
|
|
47
|
+
it("Exchange (value of ".concat(exchangeType, ") init with default rate types of fixed"), function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
48
|
+
var transport, exchange;
|
|
49
|
+
return __generator(this, function (_a) {
|
|
50
|
+
switch (_a.label) {
|
|
51
|
+
case 0: return [4 /*yield*/, (0, hw_transport_mocker_1.openTransportReplayer)(hw_transport_mocker_1.RecordStore.fromString(""))];
|
|
52
|
+
case 1:
|
|
53
|
+
transport = _a.sent();
|
|
54
|
+
exchange = new Exchange_1["default"](transport, exchangeType);
|
|
55
|
+
expect(exchange.transactionRate).toBe(0 /* RateTypes.Fixed */);
|
|
56
|
+
return [2 /*return*/];
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}); });
|
|
60
|
+
[0 /* RateTypes.Fixed */, 1 /* RateTypes.Floating */].forEach(function (rateType) {
|
|
61
|
+
it("Exchange (value of ".concat(exchangeType, ") init with rate types of value ").concat(rateType), function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
62
|
+
var transport, exchange;
|
|
63
|
+
return __generator(this, function (_a) {
|
|
64
|
+
switch (_a.label) {
|
|
65
|
+
case 0: return [4 /*yield*/, (0, hw_transport_mocker_1.openTransportReplayer)(hw_transport_mocker_1.RecordStore.fromString(""))];
|
|
66
|
+
case 1:
|
|
67
|
+
transport = _a.sent();
|
|
68
|
+
exchange = new Exchange_1["default"](transport, exchangeType, rateType);
|
|
69
|
+
expect(exchange.transactionRate).toBe(rateType);
|
|
70
|
+
return [2 /*return*/];
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}); });
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe("startNewTransaction", function () {
|
|
78
|
+
var textEncoder = new util_1.TextEncoder();
|
|
79
|
+
var mockResponse = "2ac38f187c"; // Response of length 10
|
|
80
|
+
it("sends a correct sequence of APDU", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
81
|
+
var recordStore, mockTransport, transport, exchange, result, expectCommand;
|
|
82
|
+
return __generator(this, function (_a) {
|
|
83
|
+
switch (_a.label) {
|
|
84
|
+
case 0:
|
|
85
|
+
recordStore = new hw_transport_mocker_1.RecordStore();
|
|
86
|
+
mockTransport = new hw_transport_mocker_1.MockTransport(Buffer.concat([
|
|
87
|
+
textEncoder.encode(mockResponse),
|
|
88
|
+
Buffer.from([0x90, 0x00]), // StatusCodes.OK
|
|
89
|
+
]));
|
|
90
|
+
transport = (0, hw_transport_mocker_1.createTransportRecorder)(mockTransport, recordStore);
|
|
91
|
+
exchange = new Exchange_1["default"](new transport(mockTransport), 0 /* ExchangeTypes.Swap */);
|
|
92
|
+
return [4 /*yield*/, exchange.startNewTransaction()];
|
|
93
|
+
case 1:
|
|
94
|
+
result = _a.sent();
|
|
95
|
+
expectCommand = Buffer.from([
|
|
96
|
+
0xe0,
|
|
97
|
+
0x03,
|
|
98
|
+
0 /* ExchangeTypes.Swap */,
|
|
99
|
+
0 /* RateTypes.Fixed */,
|
|
100
|
+
0x00, // Data
|
|
101
|
+
]).toString("hex");
|
|
102
|
+
expect(recordStore.queue[0][0]).toBe(expectCommand);
|
|
103
|
+
expect(result).toEqual(mockResponse);
|
|
104
|
+
return [2 /*return*/];
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}); });
|
|
108
|
+
// TOFIX: TransportError is not recognize as an Error type
|
|
109
|
+
xit("throws an error if status is not ok", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
110
|
+
var recordStore, mockTransport, transport, exchange;
|
|
111
|
+
return __generator(this, function (_a) {
|
|
112
|
+
recordStore = new hw_transport_mocker_1.RecordStore();
|
|
113
|
+
mockTransport = new hw_transport_mocker_1.MockTransport(Buffer.concat([
|
|
114
|
+
textEncoder.encode(mockResponse),
|
|
115
|
+
Buffer.from([0x6a, 0x80]),
|
|
116
|
+
]));
|
|
117
|
+
transport = (0, hw_transport_mocker_1.createTransportRecorder)(mockTransport, recordStore);
|
|
118
|
+
exchange = new Exchange_1["default"](new transport(mockTransport), 0 /* ExchangeTypes.Swap */);
|
|
119
|
+
// When & Then
|
|
120
|
+
expect(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
121
|
+
switch (_a.label) {
|
|
122
|
+
case 0: return [4 /*yield*/, exchange.startNewTransaction()];
|
|
123
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
124
|
+
}
|
|
125
|
+
}); }); }).toThrowError();
|
|
126
|
+
return [2 /*return*/];
|
|
127
|
+
});
|
|
128
|
+
}); });
|
|
129
|
+
});
|
|
130
|
+
//# sourceMappingURL=Exchange.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Exchange.test.js","sourceRoot":"","sources":["../src/Exchange.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import Transport from "@ledgerhq/hw-transport";
|
|
3
|
+
import { BigNumber } from "bignumber.js";
|
|
4
|
+
export declare const enum RateTypes {
|
|
5
|
+
Fixed = 0,
|
|
6
|
+
Floating = 1
|
|
7
|
+
}
|
|
8
|
+
export declare const enum ExchangeTypes {
|
|
9
|
+
Swap = 0,
|
|
10
|
+
Sell = 1,
|
|
11
|
+
Fund = 2
|
|
12
|
+
}
|
|
13
|
+
export default class Exchange {
|
|
14
|
+
transport: Transport;
|
|
15
|
+
transactionType: ExchangeTypes;
|
|
16
|
+
transactionRate: RateTypes;
|
|
17
|
+
allowedStatuses: Array<number>;
|
|
18
|
+
constructor(transport: Transport, transactionType: ExchangeTypes, transactionRate?: RateTypes);
|
|
19
|
+
startNewTransaction(): Promise<string>;
|
|
20
|
+
setPartnerKey(partnerNameAndPublicKey: Buffer): Promise<void>;
|
|
21
|
+
checkPartner(signatureOfPartnerData: Buffer): Promise<void>;
|
|
22
|
+
processTransaction(transaction: Buffer, fee: BigNumber): Promise<void>;
|
|
23
|
+
checkTransactionSignature(transactionSignature: Buffer): Promise<void>;
|
|
24
|
+
checkPayoutAddress(payoutCurrencyConfig: Buffer, currencyConfigSignature: Buffer, addressParameters: Buffer): Promise<void>;
|
|
25
|
+
checkRefundAddress(refundCurrencyConfig: Buffer, currencyConfigSignature: Buffer, addressParameters: Buffer): Promise<void>;
|
|
26
|
+
signCoinTransaction(): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=Exchange.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Exchange.d.ts","sourceRoot":"","sources":["../src/Exchange.ts"],"names":[],"mappings":";AAAA,OAAO,SAAS,MAAM,wBAAwB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAIzC,0BAAkB,SAAS;IACzB,KAAK,IAAO;IACZ,QAAQ,IAAO;CAChB;AAED,0BAAkB,aAAa;IAC7B,IAAI,IAAO;IACX,IAAI,IAAO;IACX,IAAI,IAAO;CACZ;AAqBD,MAAM,CAAC,OAAO,OAAO,QAAQ;IAC3B,SAAS,EAAE,SAAS,CAAC;IACrB,eAAe,EAAE,aAAa,CAAC;IAC/B,eAAe,EAAE,SAAS,CAAC;IAC3B,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAG5B;gBAGA,SAAS,EAAE,SAAS,EACpB,eAAe,EAAE,aAAa,EAC9B,eAAe,CAAC,EAAE,SAAS;IAOvB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAqBtC,aAAa,CAAC,uBAAuB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7D,YAAY,CAAC,sBAAsB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY3D,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBtE,yBAAyB,CAAC,oBAAoB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYtE,kBAAkB,CACtB,oBAAoB,EAAE,MAAM,EAC5B,uBAAuB,EAAE,MAAM,EAC/B,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC;IA4BV,kBAAkB,CACtB,oBAAoB,EAAE,MAAM,EAC5B,uBAAuB,EAAE,MAAM,EAC/B,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC;IA0BV,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;CAW3C"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
12
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
import { TransportStatusError } from "@ledgerhq/errors";
|
|
38
|
+
import invariant from "invariant";
|
|
39
|
+
var START_NEW_TRANSACTION_COMMAND = 0x03;
|
|
40
|
+
var SET_PARTNER_KEY_COMMAND = 0x04;
|
|
41
|
+
var CHECK_PARTNER_COMMAND = 0x05;
|
|
42
|
+
var PROCESS_TRANSACTION_RESPONSE = 0x06;
|
|
43
|
+
var CHECK_TRANSACTION_SIGNATURE = 0x07;
|
|
44
|
+
var CHECK_PAYOUT_ADDRESS = 0x08;
|
|
45
|
+
var CHECK_ASSET_IN = 0x08;
|
|
46
|
+
var CHECK_REFUND_ADDRESS = 0x09;
|
|
47
|
+
var SIGN_COIN_TRANSACTION = 0x0a;
|
|
48
|
+
var maybeThrowProtocolError = function (result) {
|
|
49
|
+
invariant(result.length >= 2, "ExchangeTransport: Unexpected result length");
|
|
50
|
+
var resultCode = result.readUInt16BE(result.length - 2);
|
|
51
|
+
if (resultCode !== 0x9000) {
|
|
52
|
+
throw new TransportStatusError(resultCode);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var Exchange = /** @class */ (function () {
|
|
56
|
+
function Exchange(transport, transactionType, transactionRate) {
|
|
57
|
+
this.allowedStatuses = [
|
|
58
|
+
0x9000, 0x6a80, 0x6a81, 0x6a82, 0x6a83, 0x6a84, 0x6a85, 0x6e00, 0x6d00,
|
|
59
|
+
0x9d1a,
|
|
60
|
+
];
|
|
61
|
+
this.transactionType = transactionType;
|
|
62
|
+
this.transactionRate = transactionRate || 0 /* RateTypes.Fixed */;
|
|
63
|
+
this.transport = transport;
|
|
64
|
+
}
|
|
65
|
+
Exchange.prototype.startNewTransaction = function () {
|
|
66
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
67
|
+
var result;
|
|
68
|
+
return __generator(this, function (_a) {
|
|
69
|
+
switch (_a.label) {
|
|
70
|
+
case 0: return [4 /*yield*/, this.transport.send(0xe0, START_NEW_TRANSACTION_COMMAND, this.transactionRate, this.transactionType, Buffer.alloc(0), this.allowedStatuses)];
|
|
71
|
+
case 1:
|
|
72
|
+
result = _a.sent();
|
|
73
|
+
maybeThrowProtocolError(result);
|
|
74
|
+
if (this.transactionType === 1 /* ExchangeTypes.Sell */ ||
|
|
75
|
+
this.transactionType === 2 /* ExchangeTypes.Fund */) {
|
|
76
|
+
return [2 /*return*/, result.slice(0, 32).toString("base64")];
|
|
77
|
+
}
|
|
78
|
+
return [2 /*return*/, result.toString("ascii", 0, 10)];
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
Exchange.prototype.setPartnerKey = function (partnerNameAndPublicKey) {
|
|
84
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
85
|
+
var result;
|
|
86
|
+
return __generator(this, function (_a) {
|
|
87
|
+
switch (_a.label) {
|
|
88
|
+
case 0: return [4 /*yield*/, this.transport.send(0xe0, SET_PARTNER_KEY_COMMAND, this.transactionRate, this.transactionType, partnerNameAndPublicKey, this.allowedStatuses)];
|
|
89
|
+
case 1:
|
|
90
|
+
result = _a.sent();
|
|
91
|
+
maybeThrowProtocolError(result);
|
|
92
|
+
return [2 /*return*/];
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
Exchange.prototype.checkPartner = function (signatureOfPartnerData) {
|
|
98
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
99
|
+
var result;
|
|
100
|
+
return __generator(this, function (_a) {
|
|
101
|
+
switch (_a.label) {
|
|
102
|
+
case 0: return [4 /*yield*/, this.transport.send(0xe0, CHECK_PARTNER_COMMAND, this.transactionRate, this.transactionType, signatureOfPartnerData, this.allowedStatuses)];
|
|
103
|
+
case 1:
|
|
104
|
+
result = _a.sent();
|
|
105
|
+
maybeThrowProtocolError(result);
|
|
106
|
+
return [2 /*return*/];
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
Exchange.prototype.processTransaction = function (transaction, fee) {
|
|
112
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
113
|
+
var hex, feeHex, bufferToSend, result;
|
|
114
|
+
return __generator(this, function (_a) {
|
|
115
|
+
switch (_a.label) {
|
|
116
|
+
case 0:
|
|
117
|
+
hex = fee.toString(16);
|
|
118
|
+
hex = hex.padStart(hex.length + (hex.length % 2), "0");
|
|
119
|
+
feeHex = Buffer.from(hex, "hex");
|
|
120
|
+
bufferToSend = Buffer.concat([
|
|
121
|
+
Buffer.from([transaction.length]),
|
|
122
|
+
transaction,
|
|
123
|
+
Buffer.from([feeHex.length]),
|
|
124
|
+
feeHex,
|
|
125
|
+
]);
|
|
126
|
+
return [4 /*yield*/, this.transport.send(0xe0, PROCESS_TRANSACTION_RESPONSE, this.transactionRate, this.transactionType, bufferToSend, this.allowedStatuses)];
|
|
127
|
+
case 1:
|
|
128
|
+
result = _a.sent();
|
|
129
|
+
maybeThrowProtocolError(result);
|
|
130
|
+
return [2 /*return*/];
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
Exchange.prototype.checkTransactionSignature = function (transactionSignature) {
|
|
136
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
137
|
+
var result;
|
|
138
|
+
return __generator(this, function (_a) {
|
|
139
|
+
switch (_a.label) {
|
|
140
|
+
case 0: return [4 /*yield*/, this.transport.send(0xe0, CHECK_TRANSACTION_SIGNATURE, this.transactionRate, this.transactionType, transactionSignature, this.allowedStatuses)];
|
|
141
|
+
case 1:
|
|
142
|
+
result = _a.sent();
|
|
143
|
+
maybeThrowProtocolError(result);
|
|
144
|
+
return [2 /*return*/];
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
Exchange.prototype.checkPayoutAddress = function (payoutCurrencyConfig, currencyConfigSignature, addressParameters) {
|
|
150
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
151
|
+
var bufferToSend, result;
|
|
152
|
+
return __generator(this, function (_a) {
|
|
153
|
+
switch (_a.label) {
|
|
154
|
+
case 0:
|
|
155
|
+
invariant(payoutCurrencyConfig.length <= 255, "Currency config is too big");
|
|
156
|
+
invariant(addressParameters.length <= 255, "Address parameter is too big.");
|
|
157
|
+
invariant(currencyConfigSignature.length >= 67 &&
|
|
158
|
+
currencyConfigSignature.length <= 73, "Signature should be DER serialized and have length in [67, 73] bytes.");
|
|
159
|
+
bufferToSend = Buffer.concat([
|
|
160
|
+
Buffer.from([payoutCurrencyConfig.length]),
|
|
161
|
+
payoutCurrencyConfig,
|
|
162
|
+
currencyConfigSignature,
|
|
163
|
+
Buffer.from([addressParameters.length]),
|
|
164
|
+
addressParameters,
|
|
165
|
+
]);
|
|
166
|
+
return [4 /*yield*/, this.transport.send(0xe0, this.transactionType === 0 /* ExchangeTypes.Swap */
|
|
167
|
+
? CHECK_PAYOUT_ADDRESS
|
|
168
|
+
: CHECK_ASSET_IN, this.transactionRate, this.transactionType, bufferToSend, this.allowedStatuses)];
|
|
169
|
+
case 1:
|
|
170
|
+
result = _a.sent();
|
|
171
|
+
maybeThrowProtocolError(result);
|
|
172
|
+
return [2 /*return*/];
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
Exchange.prototype.checkRefundAddress = function (refundCurrencyConfig, currencyConfigSignature, addressParameters) {
|
|
178
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
179
|
+
var bufferToSend, result;
|
|
180
|
+
return __generator(this, function (_a) {
|
|
181
|
+
switch (_a.label) {
|
|
182
|
+
case 0:
|
|
183
|
+
invariant(refundCurrencyConfig.length <= 255, "Currency config is too big");
|
|
184
|
+
invariant(addressParameters.length <= 255, "Address parameter is too big.");
|
|
185
|
+
invariant(currencyConfigSignature.length >= 67 &&
|
|
186
|
+
currencyConfigSignature.length <= 73, "Signature should be DER serialized and have length in [67, 73] bytes.");
|
|
187
|
+
bufferToSend = Buffer.concat([
|
|
188
|
+
Buffer.from([refundCurrencyConfig.length]),
|
|
189
|
+
refundCurrencyConfig,
|
|
190
|
+
currencyConfigSignature,
|
|
191
|
+
Buffer.from([addressParameters.length]),
|
|
192
|
+
addressParameters,
|
|
193
|
+
]);
|
|
194
|
+
return [4 /*yield*/, this.transport.send(0xe0, CHECK_REFUND_ADDRESS, this.transactionRate, this.transactionType, bufferToSend, this.allowedStatuses)];
|
|
195
|
+
case 1:
|
|
196
|
+
result = _a.sent();
|
|
197
|
+
maybeThrowProtocolError(result);
|
|
198
|
+
return [2 /*return*/];
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
Exchange.prototype.signCoinTransaction = function () {
|
|
204
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
205
|
+
var result;
|
|
206
|
+
return __generator(this, function (_a) {
|
|
207
|
+
switch (_a.label) {
|
|
208
|
+
case 0: return [4 /*yield*/, this.transport.send(0xe0, SIGN_COIN_TRANSACTION, this.transactionRate, this.transactionType, Buffer.alloc(0), this.allowedStatuses)];
|
|
209
|
+
case 1:
|
|
210
|
+
result = _a.sent();
|
|
211
|
+
maybeThrowProtocolError(result);
|
|
212
|
+
return [2 /*return*/];
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
};
|
|
217
|
+
return Exchange;
|
|
218
|
+
}());
|
|
219
|
+
export default Exchange;
|
|
220
|
+
//# sourceMappingURL=Exchange.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Exchange.js","sourceRoot":"","sources":["../src/Exchange.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Exchange.test.d.ts","sourceRoot":"","sources":["../src/Exchange.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
12
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
import { createTransportRecorder, MockTransport, openTransportReplayer, RecordStore, } from "@ledgerhq/hw-transport-mocker";
|
|
38
|
+
import Exchange from "./Exchange";
|
|
39
|
+
import { TextEncoder } from "util";
|
|
40
|
+
describe("Contrustructor", function () {
|
|
41
|
+
[2 /* ExchangeTypes.Fund */, 1 /* ExchangeTypes.Sell */, 0 /* ExchangeTypes.Swap */].forEach(function (exchangeType) {
|
|
42
|
+
it("Exchange (value of ".concat(exchangeType, ") init with default rate types of fixed"), function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
43
|
+
var transport, exchange;
|
|
44
|
+
return __generator(this, function (_a) {
|
|
45
|
+
switch (_a.label) {
|
|
46
|
+
case 0: return [4 /*yield*/, openTransportReplayer(RecordStore.fromString(""))];
|
|
47
|
+
case 1:
|
|
48
|
+
transport = _a.sent();
|
|
49
|
+
exchange = new Exchange(transport, exchangeType);
|
|
50
|
+
expect(exchange.transactionRate).toBe(0 /* RateTypes.Fixed */);
|
|
51
|
+
return [2 /*return*/];
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}); });
|
|
55
|
+
[0 /* RateTypes.Fixed */, 1 /* RateTypes.Floating */].forEach(function (rateType) {
|
|
56
|
+
it("Exchange (value of ".concat(exchangeType, ") init with rate types of value ").concat(rateType), function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
57
|
+
var transport, exchange;
|
|
58
|
+
return __generator(this, function (_a) {
|
|
59
|
+
switch (_a.label) {
|
|
60
|
+
case 0: return [4 /*yield*/, openTransportReplayer(RecordStore.fromString(""))];
|
|
61
|
+
case 1:
|
|
62
|
+
transport = _a.sent();
|
|
63
|
+
exchange = new Exchange(transport, exchangeType, rateType);
|
|
64
|
+
expect(exchange.transactionRate).toBe(rateType);
|
|
65
|
+
return [2 /*return*/];
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}); });
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe("startNewTransaction", function () {
|
|
73
|
+
var textEncoder = new TextEncoder();
|
|
74
|
+
var mockResponse = "2ac38f187c"; // Response of length 10
|
|
75
|
+
it("sends a correct sequence of APDU", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
76
|
+
var recordStore, mockTransport, transport, exchange, result, expectCommand;
|
|
77
|
+
return __generator(this, function (_a) {
|
|
78
|
+
switch (_a.label) {
|
|
79
|
+
case 0:
|
|
80
|
+
recordStore = new RecordStore();
|
|
81
|
+
mockTransport = new MockTransport(Buffer.concat([
|
|
82
|
+
textEncoder.encode(mockResponse),
|
|
83
|
+
Buffer.from([0x90, 0x00]), // StatusCodes.OK
|
|
84
|
+
]));
|
|
85
|
+
transport = createTransportRecorder(mockTransport, recordStore);
|
|
86
|
+
exchange = new Exchange(new transport(mockTransport), 0 /* ExchangeTypes.Swap */);
|
|
87
|
+
return [4 /*yield*/, exchange.startNewTransaction()];
|
|
88
|
+
case 1:
|
|
89
|
+
result = _a.sent();
|
|
90
|
+
expectCommand = Buffer.from([
|
|
91
|
+
0xe0,
|
|
92
|
+
0x03,
|
|
93
|
+
0 /* ExchangeTypes.Swap */,
|
|
94
|
+
0 /* RateTypes.Fixed */,
|
|
95
|
+
0x00, // Data
|
|
96
|
+
]).toString("hex");
|
|
97
|
+
expect(recordStore.queue[0][0]).toBe(expectCommand);
|
|
98
|
+
expect(result).toEqual(mockResponse);
|
|
99
|
+
return [2 /*return*/];
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}); });
|
|
103
|
+
// TOFIX: TransportError is not recognize as an Error type
|
|
104
|
+
xit("throws an error if status is not ok", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
105
|
+
var recordStore, mockTransport, transport, exchange;
|
|
106
|
+
return __generator(this, function (_a) {
|
|
107
|
+
recordStore = new RecordStore();
|
|
108
|
+
mockTransport = new MockTransport(Buffer.concat([
|
|
109
|
+
textEncoder.encode(mockResponse),
|
|
110
|
+
Buffer.from([0x6a, 0x80]),
|
|
111
|
+
]));
|
|
112
|
+
transport = createTransportRecorder(mockTransport, recordStore);
|
|
113
|
+
exchange = new Exchange(new transport(mockTransport), 0 /* ExchangeTypes.Swap */);
|
|
114
|
+
// When & Then
|
|
115
|
+
expect(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
116
|
+
switch (_a.label) {
|
|
117
|
+
case 0: return [4 /*yield*/, exchange.startNewTransaction()];
|
|
118
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
119
|
+
}
|
|
120
|
+
}); }); }).toThrowError();
|
|
121
|
+
return [2 /*return*/];
|
|
122
|
+
});
|
|
123
|
+
}); });
|
|
124
|
+
});
|
|
125
|
+
//# sourceMappingURL=Exchange.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Exchange.test.js","sourceRoot":"","sources":["../src/Exchange.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ledgerhq/hw-app-exchange",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Ledger Hardware Wallet Cosmos Application API",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"Ledger",
|
|
7
|
+
"LedgerWallet",
|
|
8
|
+
"NanoS",
|
|
9
|
+
"Blue",
|
|
10
|
+
"Hardware Wallet"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/LedgerHQ/ledger-live.git"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/LedgerHQ/ledger-live/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/LedgerHQ/ledger-live/tree/develop/libs/ledgerjs/packages/hw-app-exchange",
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"main": "lib/Exchange.js",
|
|
24
|
+
"module": "lib-es/Exchange.js",
|
|
25
|
+
"types": "lib/Exchange.d.ts",
|
|
26
|
+
"license": "Apache-2.0",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"bignumber.js": "^9.1.0",
|
|
29
|
+
"invariant": "^2.2.2",
|
|
30
|
+
"@ledgerhq/errors": "^6.12.4-nightly.2",
|
|
31
|
+
"@ledgerhq/hw-transport": "^6.28.2-nightly.2"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/jest": "^29.5.0",
|
|
35
|
+
"@types/node": "^18.15.3",
|
|
36
|
+
"documentation": "13.2.4",
|
|
37
|
+
"jest": "^28.1.1",
|
|
38
|
+
"ts-jest": "^28.0.5",
|
|
39
|
+
"ts-node": "^10.4.0",
|
|
40
|
+
"typescript": "^4",
|
|
41
|
+
"@ledgerhq/hw-transport-mocker": "^6.27.13-nightly.2"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"clean": "rimraf lib lib-es",
|
|
45
|
+
"build": "tsc && tsc -m ES6 --outDir lib-es",
|
|
46
|
+
"prewatch": "pnpm build",
|
|
47
|
+
"watch": "tsc --watch",
|
|
48
|
+
"doc": "documentation readme src/** --section=API --pe ts --re ts --re d.ts",
|
|
49
|
+
"lint": "eslint ./src --no-error-on-unmatched-pattern --ext .ts,.tsx",
|
|
50
|
+
"lint:fix": "pnpm lint --fix",
|
|
51
|
+
"test": "jest"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createTransportRecorder,
|
|
3
|
+
MockTransport,
|
|
4
|
+
openTransportReplayer,
|
|
5
|
+
RecordStore,
|
|
6
|
+
} from "@ledgerhq/hw-transport-mocker";
|
|
7
|
+
import Exchange, { ExchangeTypes, RateTypes } from "./Exchange";
|
|
8
|
+
import { TextEncoder } from "util";
|
|
9
|
+
|
|
10
|
+
describe("Contrustructor", () => {
|
|
11
|
+
[ExchangeTypes.Fund, ExchangeTypes.Sell, ExchangeTypes.Swap].forEach(
|
|
12
|
+
(exchangeType) => {
|
|
13
|
+
it(`Exchange (value of ${exchangeType}) init with default rate types of fixed`, async () => {
|
|
14
|
+
const transport = await openTransportReplayer(
|
|
15
|
+
RecordStore.fromString("")
|
|
16
|
+
);
|
|
17
|
+
const exchange = new Exchange(transport, exchangeType);
|
|
18
|
+
expect(exchange.transactionRate).toBe(RateTypes.Fixed);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
[RateTypes.Fixed, RateTypes.Floating].forEach((rateType) => {
|
|
22
|
+
it(`Exchange (value of ${exchangeType}) init with rate types of value ${rateType}`, async () => {
|
|
23
|
+
const transport = await openTransportReplayer(
|
|
24
|
+
RecordStore.fromString("")
|
|
25
|
+
);
|
|
26
|
+
const exchange = new Exchange(transport, exchangeType, rateType);
|
|
27
|
+
expect(exchange.transactionRate).toBe(rateType);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("startNewTransaction", () => {
|
|
35
|
+
const textEncoder = new TextEncoder();
|
|
36
|
+
const mockResponse = "2ac38f187c"; // Response of length 10
|
|
37
|
+
|
|
38
|
+
it("sends a correct sequence of APDU", async () => {
|
|
39
|
+
// Given
|
|
40
|
+
const recordStore = new RecordStore();
|
|
41
|
+
const mockTransport = new MockTransport(
|
|
42
|
+
Buffer.concat([
|
|
43
|
+
textEncoder.encode(mockResponse),
|
|
44
|
+
Buffer.from([0x90, 0x00]), // StatusCodes.OK
|
|
45
|
+
])
|
|
46
|
+
);
|
|
47
|
+
const transport = createTransportRecorder(mockTransport, recordStore);
|
|
48
|
+
const exchange = new Exchange(
|
|
49
|
+
new transport(mockTransport),
|
|
50
|
+
ExchangeTypes.Swap
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// When
|
|
54
|
+
const result = await exchange.startNewTransaction();
|
|
55
|
+
|
|
56
|
+
// Then
|
|
57
|
+
const expectCommand = Buffer.from([
|
|
58
|
+
0xe0,
|
|
59
|
+
0x03, // Start Exchance
|
|
60
|
+
ExchangeTypes.Swap,
|
|
61
|
+
RateTypes.Fixed,
|
|
62
|
+
0x00, // Data
|
|
63
|
+
]).toString("hex");
|
|
64
|
+
expect(recordStore.queue[0][0]).toBe(expectCommand);
|
|
65
|
+
expect(result).toEqual(mockResponse);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// TOFIX: TransportError is not recognize as an Error type
|
|
69
|
+
xit("throws an error if status is not ok", async () => {
|
|
70
|
+
// Given
|
|
71
|
+
const recordStore = new RecordStore();
|
|
72
|
+
const mockTransport = new MockTransport(
|
|
73
|
+
Buffer.concat([
|
|
74
|
+
textEncoder.encode(mockResponse),
|
|
75
|
+
Buffer.from([0x6a, 0x80]),
|
|
76
|
+
])
|
|
77
|
+
);
|
|
78
|
+
const transport = createTransportRecorder(mockTransport, recordStore);
|
|
79
|
+
const exchange = new Exchange(
|
|
80
|
+
new transport(mockTransport),
|
|
81
|
+
ExchangeTypes.Swap
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
// When & Then
|
|
85
|
+
expect(async () => await exchange.startNewTransaction()).toThrowError();
|
|
86
|
+
});
|
|
87
|
+
});
|
package/src/Exchange.ts
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import Transport from "@ledgerhq/hw-transport";
|
|
2
|
+
import { BigNumber } from "bignumber.js";
|
|
3
|
+
import { TransportStatusError } from "@ledgerhq/errors";
|
|
4
|
+
import invariant from "invariant";
|
|
5
|
+
|
|
6
|
+
export const enum RateTypes {
|
|
7
|
+
Fixed = 0x00,
|
|
8
|
+
Floating = 0x01,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const enum ExchangeTypes {
|
|
12
|
+
Swap = 0x00,
|
|
13
|
+
Sell = 0x01,
|
|
14
|
+
Fund = 0x02,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const START_NEW_TRANSACTION_COMMAND = 0x03;
|
|
18
|
+
const SET_PARTNER_KEY_COMMAND = 0x04;
|
|
19
|
+
const CHECK_PARTNER_COMMAND = 0x05;
|
|
20
|
+
const PROCESS_TRANSACTION_RESPONSE = 0x06;
|
|
21
|
+
const CHECK_TRANSACTION_SIGNATURE = 0x07;
|
|
22
|
+
const CHECK_PAYOUT_ADDRESS = 0x08;
|
|
23
|
+
const CHECK_ASSET_IN = 0x08;
|
|
24
|
+
const CHECK_REFUND_ADDRESS = 0x09;
|
|
25
|
+
const SIGN_COIN_TRANSACTION = 0x0a;
|
|
26
|
+
|
|
27
|
+
const maybeThrowProtocolError = (result: Buffer): void => {
|
|
28
|
+
invariant(result.length >= 2, "ExchangeTransport: Unexpected result length");
|
|
29
|
+
const resultCode = result.readUInt16BE(result.length - 2);
|
|
30
|
+
|
|
31
|
+
if (resultCode !== 0x9000) {
|
|
32
|
+
throw new TransportStatusError(resultCode);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default class Exchange {
|
|
37
|
+
transport: Transport;
|
|
38
|
+
transactionType: ExchangeTypes;
|
|
39
|
+
transactionRate: RateTypes;
|
|
40
|
+
allowedStatuses: Array<number> = [
|
|
41
|
+
0x9000, 0x6a80, 0x6a81, 0x6a82, 0x6a83, 0x6a84, 0x6a85, 0x6e00, 0x6d00,
|
|
42
|
+
0x9d1a,
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
constructor(
|
|
46
|
+
transport: Transport,
|
|
47
|
+
transactionType: ExchangeTypes,
|
|
48
|
+
transactionRate?: RateTypes
|
|
49
|
+
) {
|
|
50
|
+
this.transactionType = transactionType;
|
|
51
|
+
this.transactionRate = transactionRate || RateTypes.Fixed;
|
|
52
|
+
this.transport = transport;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async startNewTransaction(): Promise<string> {
|
|
56
|
+
const result: Buffer = await this.transport.send(
|
|
57
|
+
0xe0,
|
|
58
|
+
START_NEW_TRANSACTION_COMMAND,
|
|
59
|
+
this.transactionRate,
|
|
60
|
+
this.transactionType,
|
|
61
|
+
Buffer.alloc(0),
|
|
62
|
+
this.allowedStatuses
|
|
63
|
+
);
|
|
64
|
+
maybeThrowProtocolError(result);
|
|
65
|
+
|
|
66
|
+
if (
|
|
67
|
+
this.transactionType === ExchangeTypes.Sell ||
|
|
68
|
+
this.transactionType === ExchangeTypes.Fund
|
|
69
|
+
) {
|
|
70
|
+
return result.slice(0, 32).toString("base64");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return result.toString("ascii", 0, 10);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async setPartnerKey(partnerNameAndPublicKey: Buffer): Promise<void> {
|
|
77
|
+
const result: Buffer = await this.transport.send(
|
|
78
|
+
0xe0,
|
|
79
|
+
SET_PARTNER_KEY_COMMAND,
|
|
80
|
+
this.transactionRate,
|
|
81
|
+
this.transactionType,
|
|
82
|
+
partnerNameAndPublicKey,
|
|
83
|
+
this.allowedStatuses
|
|
84
|
+
);
|
|
85
|
+
maybeThrowProtocolError(result);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async checkPartner(signatureOfPartnerData: Buffer): Promise<void> {
|
|
89
|
+
const result: Buffer = await this.transport.send(
|
|
90
|
+
0xe0,
|
|
91
|
+
CHECK_PARTNER_COMMAND,
|
|
92
|
+
this.transactionRate,
|
|
93
|
+
this.transactionType,
|
|
94
|
+
signatureOfPartnerData,
|
|
95
|
+
this.allowedStatuses
|
|
96
|
+
);
|
|
97
|
+
maybeThrowProtocolError(result);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async processTransaction(transaction: Buffer, fee: BigNumber): Promise<void> {
|
|
101
|
+
let hex: string = fee.toString(16);
|
|
102
|
+
hex = hex.padStart(hex.length + (hex.length % 2), "0");
|
|
103
|
+
const feeHex: Buffer = Buffer.from(hex, "hex");
|
|
104
|
+
const bufferToSend: Buffer = Buffer.concat([
|
|
105
|
+
Buffer.from([transaction.length]),
|
|
106
|
+
transaction,
|
|
107
|
+
Buffer.from([feeHex.length]),
|
|
108
|
+
feeHex,
|
|
109
|
+
]);
|
|
110
|
+
const result: Buffer = await this.transport.send(
|
|
111
|
+
0xe0,
|
|
112
|
+
PROCESS_TRANSACTION_RESPONSE,
|
|
113
|
+
this.transactionRate,
|
|
114
|
+
this.transactionType,
|
|
115
|
+
bufferToSend,
|
|
116
|
+
this.allowedStatuses
|
|
117
|
+
);
|
|
118
|
+
maybeThrowProtocolError(result);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async checkTransactionSignature(transactionSignature: Buffer): Promise<void> {
|
|
122
|
+
const result: Buffer = await this.transport.send(
|
|
123
|
+
0xe0,
|
|
124
|
+
CHECK_TRANSACTION_SIGNATURE,
|
|
125
|
+
this.transactionRate,
|
|
126
|
+
this.transactionType,
|
|
127
|
+
transactionSignature,
|
|
128
|
+
this.allowedStatuses
|
|
129
|
+
);
|
|
130
|
+
maybeThrowProtocolError(result);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async checkPayoutAddress(
|
|
134
|
+
payoutCurrencyConfig: Buffer,
|
|
135
|
+
currencyConfigSignature: Buffer,
|
|
136
|
+
addressParameters: Buffer
|
|
137
|
+
): Promise<void> {
|
|
138
|
+
invariant(payoutCurrencyConfig.length <= 255, "Currency config is too big");
|
|
139
|
+
invariant(addressParameters.length <= 255, "Address parameter is too big.");
|
|
140
|
+
invariant(
|
|
141
|
+
currencyConfigSignature.length >= 67 &&
|
|
142
|
+
currencyConfigSignature.length <= 73,
|
|
143
|
+
"Signature should be DER serialized and have length in [67, 73] bytes."
|
|
144
|
+
);
|
|
145
|
+
const bufferToSend: Buffer = Buffer.concat([
|
|
146
|
+
Buffer.from([payoutCurrencyConfig.length]),
|
|
147
|
+
payoutCurrencyConfig,
|
|
148
|
+
currencyConfigSignature,
|
|
149
|
+
Buffer.from([addressParameters.length]),
|
|
150
|
+
addressParameters,
|
|
151
|
+
]);
|
|
152
|
+
const result: Buffer = await this.transport.send(
|
|
153
|
+
0xe0,
|
|
154
|
+
this.transactionType === ExchangeTypes.Swap
|
|
155
|
+
? CHECK_PAYOUT_ADDRESS
|
|
156
|
+
: CHECK_ASSET_IN,
|
|
157
|
+
this.transactionRate,
|
|
158
|
+
this.transactionType,
|
|
159
|
+
bufferToSend,
|
|
160
|
+
this.allowedStatuses
|
|
161
|
+
);
|
|
162
|
+
maybeThrowProtocolError(result);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async checkRefundAddress(
|
|
166
|
+
refundCurrencyConfig: Buffer,
|
|
167
|
+
currencyConfigSignature: Buffer,
|
|
168
|
+
addressParameters: Buffer
|
|
169
|
+
): Promise<void> {
|
|
170
|
+
invariant(refundCurrencyConfig.length <= 255, "Currency config is too big");
|
|
171
|
+
invariant(addressParameters.length <= 255, "Address parameter is too big.");
|
|
172
|
+
invariant(
|
|
173
|
+
currencyConfigSignature.length >= 67 &&
|
|
174
|
+
currencyConfigSignature.length <= 73,
|
|
175
|
+
"Signature should be DER serialized and have length in [67, 73] bytes."
|
|
176
|
+
);
|
|
177
|
+
const bufferToSend: Buffer = Buffer.concat([
|
|
178
|
+
Buffer.from([refundCurrencyConfig.length]),
|
|
179
|
+
refundCurrencyConfig,
|
|
180
|
+
currencyConfigSignature,
|
|
181
|
+
Buffer.from([addressParameters.length]),
|
|
182
|
+
addressParameters,
|
|
183
|
+
]);
|
|
184
|
+
const result: Buffer = await this.transport.send(
|
|
185
|
+
0xe0,
|
|
186
|
+
CHECK_REFUND_ADDRESS,
|
|
187
|
+
this.transactionRate,
|
|
188
|
+
this.transactionType,
|
|
189
|
+
bufferToSend,
|
|
190
|
+
this.allowedStatuses
|
|
191
|
+
);
|
|
192
|
+
maybeThrowProtocolError(result);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async signCoinTransaction(): Promise<void> {
|
|
196
|
+
const result: Buffer = await this.transport.send(
|
|
197
|
+
0xe0,
|
|
198
|
+
SIGN_COIN_TRANSACTION,
|
|
199
|
+
this.transactionRate,
|
|
200
|
+
this.transactionType,
|
|
201
|
+
Buffer.alloc(0),
|
|
202
|
+
this.allowedStatuses
|
|
203
|
+
);
|
|
204
|
+
maybeThrowProtocolError(result);
|
|
205
|
+
}
|
|
206
|
+
}
|