@bitpay-labs/bitcore-wallet-service 11.11.1 → 11.11.3

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.
Files changed (105) hide show
  1. package/Dockerfile +1 -1
  2. package/package.json +5 -5
  3. package/src/lib/chain/btc/index.ts +3 -2
  4. package/src/lib/chain/eth/index.ts +134 -117
  5. package/src/lib/chain/sol/index.ts +1 -1
  6. package/src/lib/chain/xrp/index.ts +1 -1
  7. package/src/lib/common/constants.ts +1 -1
  8. package/src/lib/common/utils.ts +18 -1
  9. package/src/lib/model/tsskeygen.ts +16 -0
  10. package/src/lib/routes/maintenance.ts +11 -2
  11. package/src/lib/routes/middleware/authTssRequest.ts +28 -16
  12. package/src/lib/routes/middleware/verifyTssMessage.ts +4 -1
  13. package/src/lib/routes/services.ts +7 -1
  14. package/src/lib/routes/tss.ts +33 -30
  15. package/src/lib/routes/wallets.ts +3 -1
  16. package/src/lib/server.ts +198 -105
  17. package/src/lib/storage.ts +129 -20
  18. package/src/lib/tss.ts +111 -7
  19. package/test/chain/eth.test.ts +70 -0
  20. package/test/chain/sol.test.ts +1 -1
  21. package/test/chain/xrp.test.ts +1 -1
  22. package/test/expressapp.test.ts +243 -0
  23. package/test/integration/addressReads.test.ts +503 -0
  24. package/test/integration/bcmonitor.test.ts +44 -0
  25. package/test/integration/server.test.ts +251 -49
  26. package/test/integration/tss.test.ts +428 -0
  27. package/test/integration/walletReads.test.ts +488 -0
  28. package/ts_build/package.json +4 -4
  29. package/ts_build/src/lib/chain/btc/index.d.ts.map +1 -1
  30. package/ts_build/src/lib/chain/btc/index.js +3 -2
  31. package/ts_build/src/lib/chain/btc/index.js.map +1 -1
  32. package/ts_build/src/lib/chain/eth/index.d.ts +8 -1
  33. package/ts_build/src/lib/chain/eth/index.d.ts.map +1 -1
  34. package/ts_build/src/lib/chain/eth/index.js +114 -102
  35. package/ts_build/src/lib/chain/eth/index.js.map +1 -1
  36. package/ts_build/src/lib/chain/sol/index.js +1 -1
  37. package/ts_build/src/lib/chain/sol/index.js.map +1 -1
  38. package/ts_build/src/lib/chain/xrp/index.js +1 -1
  39. package/ts_build/src/lib/chain/xrp/index.js.map +1 -1
  40. package/ts_build/src/lib/common/constants.d.ts +1 -1
  41. package/ts_build/src/lib/common/constants.js +1 -1
  42. package/ts_build/src/lib/common/index.d.ts +2 -1
  43. package/ts_build/src/lib/common/index.d.ts.map +1 -1
  44. package/ts_build/src/lib/common/utils.d.ts +1 -0
  45. package/ts_build/src/lib/common/utils.d.ts.map +1 -1
  46. package/ts_build/src/lib/common/utils.js +16 -1
  47. package/ts_build/src/lib/common/utils.js.map +1 -1
  48. package/ts_build/src/lib/model/tsskeygen.d.ts +10 -0
  49. package/ts_build/src/lib/model/tsskeygen.d.ts.map +1 -1
  50. package/ts_build/src/lib/model/tsskeygen.js +3 -0
  51. package/ts_build/src/lib/model/tsskeygen.js.map +1 -1
  52. package/ts_build/src/lib/routes/maintenance.d.ts.map +1 -1
  53. package/ts_build/src/lib/routes/maintenance.js +12 -4
  54. package/ts_build/src/lib/routes/maintenance.js.map +1 -1
  55. package/ts_build/src/lib/routes/middleware/authTssRequest.d.ts +6 -2
  56. package/ts_build/src/lib/routes/middleware/authTssRequest.d.ts.map +1 -1
  57. package/ts_build/src/lib/routes/middleware/authTssRequest.js +21 -14
  58. package/ts_build/src/lib/routes/middleware/authTssRequest.js.map +1 -1
  59. package/ts_build/src/lib/routes/middleware/verifyTssMessage.d.ts.map +1 -1
  60. package/ts_build/src/lib/routes/middleware/verifyTssMessage.js +2 -1
  61. package/ts_build/src/lib/routes/middleware/verifyTssMessage.js.map +1 -1
  62. package/ts_build/src/lib/routes/services.d.ts.map +1 -1
  63. package/ts_build/src/lib/routes/services.js +6 -1
  64. package/ts_build/src/lib/routes/services.js.map +1 -1
  65. package/ts_build/src/lib/routes/tss.d.ts.map +1 -1
  66. package/ts_build/src/lib/routes/tss.js +32 -30
  67. package/ts_build/src/lib/routes/tss.js.map +1 -1
  68. package/ts_build/src/lib/routes/wallets.d.ts.map +1 -1
  69. package/ts_build/src/lib/routes/wallets.js +2 -1
  70. package/ts_build/src/lib/routes/wallets.js.map +1 -1
  71. package/ts_build/src/lib/server.d.ts +24 -3
  72. package/ts_build/src/lib/server.d.ts.map +1 -1
  73. package/ts_build/src/lib/server.js +148 -97
  74. package/ts_build/src/lib/server.js.map +1 -1
  75. package/ts_build/src/lib/storage.d.ts +26 -10
  76. package/ts_build/src/lib/storage.d.ts.map +1 -1
  77. package/ts_build/src/lib/storage.js +99 -20
  78. package/ts_build/src/lib/storage.js.map +1 -1
  79. package/ts_build/src/lib/tss.d.ts +12 -0
  80. package/ts_build/src/lib/tss.d.ts.map +1 -1
  81. package/ts_build/src/lib/tss.js +64 -5
  82. package/ts_build/src/lib/tss.js.map +1 -1
  83. package/ts_build/test/chain/eth.test.js +59 -0
  84. package/ts_build/test/chain/eth.test.js.map +1 -1
  85. package/ts_build/test/chain/sol.test.js +1 -1
  86. package/ts_build/test/chain/sol.test.js.map +1 -1
  87. package/ts_build/test/chain/xrp.test.js +1 -1
  88. package/ts_build/test/chain/xrp.test.js.map +1 -1
  89. package/ts_build/test/expressapp.test.js +222 -0
  90. package/ts_build/test/expressapp.test.js.map +1 -1
  91. package/ts_build/test/integration/addressReads.test.d.ts +2 -0
  92. package/ts_build/test/integration/addressReads.test.d.ts.map +1 -0
  93. package/ts_build/test/integration/addressReads.test.js +465 -0
  94. package/ts_build/test/integration/addressReads.test.js.map +1 -0
  95. package/ts_build/test/integration/bcmonitor.test.js +40 -0
  96. package/ts_build/test/integration/bcmonitor.test.js.map +1 -1
  97. package/ts_build/test/integration/server.test.js +228 -48
  98. package/ts_build/test/integration/server.test.js.map +1 -1
  99. package/ts_build/test/integration/tss.test.d.ts.map +1 -1
  100. package/ts_build/test/integration/tss.test.js +344 -0
  101. package/ts_build/test/integration/tss.test.js.map +1 -1
  102. package/ts_build/test/integration/walletReads.test.d.ts +2 -0
  103. package/ts_build/test/integration/walletReads.test.d.ts.map +1 -0
  104. package/ts_build/test/integration/walletReads.test.js +436 -0
  105. package/ts_build/test/integration/walletReads.test.js.map +1 -0
@@ -0,0 +1,465 @@
1
+ 'use strict';
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const chai = __importStar(require("chai"));
40
+ require("chai/register-should");
41
+ const util_1 = __importDefault(require("util"));
42
+ const sinon_1 = __importDefault(require("sinon"));
43
+ const bchaddresstranslator_1 = require("../../src/lib/bchaddresstranslator");
44
+ const common_1 = require("../../src/lib/common");
45
+ const model_1 = require("../../src/lib/model");
46
+ const storage_1 = require("../../src/lib/storage");
47
+ const TestData = __importStar(require("../testdata"));
48
+ const helpers_1 = __importDefault(require("./helpers"));
49
+ const should = chai.should();
50
+ const { Defaults } = common_1.Common;
51
+ const ORDER = [
52
+ 'm/0/0', 'm/0/1', 'm/0/2', 'm/0/3', 'm/0/4', 'm/1/0',
53
+ 'm/0/10', 'm/0/11', 'm/0/12', 'm/0/5', 'm/0/6', 'm/0/7', 'm/0/8', 'm/0/9', 'm/1/1', 'm/1/2'
54
+ ];
55
+ const CREATED_ON = path => ['m/0/0', 'm/0/1', 'm/0/2', 'm/0/3', 'm/0/4', 'm/1/0'].includes(path) ? 1000 : 1001;
56
+ describe('Address reads', function () {
57
+ let blockchainExplorer;
58
+ let storage;
59
+ before(async function () {
60
+ ({ blockchainExplorer, storage } = await helpers_1.default.before());
61
+ });
62
+ beforeEach(async function () {
63
+ await helpers_1.default.beforeEach();
64
+ });
65
+ const restores = [];
66
+ afterEach(function () {
67
+ sinon_1.default.restore();
68
+ while (restores.length)
69
+ restores.pop()();
70
+ });
71
+ after(async function () {
72
+ await helpers_1.default.after();
73
+ });
74
+ const call = (server, method, opts = {}) => util_1.default.promisify(server[method]).call(server, opts);
75
+ const addresses = () => storage.db.collection(storage_1.Storage.collections.ADDRESSES);
76
+ const setCreatedOn = (walletId, paths, createdOn) => addresses().updateMany({ walletId, path: { $in: paths } }, { $set: { createdOn } });
77
+ const walletWithAddresses = async (opts = {}) => {
78
+ const { server, wallet } = await helpers_1.default.createAndJoinWallet(1, 1, opts);
79
+ await helpers_1.default.createAddresses(server, wallet, 13, 3);
80
+ for (const createdOn of [1000, 1001]) {
81
+ await setCreatedOn(wallet.id, ORDER.filter(path => CREATED_ON(path) === createdOn), createdOn);
82
+ }
83
+ const docs = await addresses().find({ walletId: wallet.id }).toArray();
84
+ const addressOf = Object.fromEntries(docs.map(d => [d.path, d.address]));
85
+ return { server, wallet, addressOf };
86
+ };
87
+ const expectedPaths = ({ noChange = false, reverse = false, skip = 0, limit = 0, paths = null, order = ORDER }) => {
88
+ let list = order.filter(path => !(noChange && path.startsWith('m/1/')) && (!paths || paths.includes(path)));
89
+ if (reverse)
90
+ list = [...list].reverse();
91
+ if (skip > 0)
92
+ list = list.slice(skip);
93
+ if (limit > 0)
94
+ list = list.slice(0, limit);
95
+ return list;
96
+ };
97
+ const failAddressQueries = () => {
98
+ const realCollection = storage.db.collection.bind(storage.db);
99
+ const failing = {
100
+ find: () => failing,
101
+ sort: () => failing,
102
+ skip: () => failing,
103
+ limit: () => failing,
104
+ project: () => failing,
105
+ toArray: cb => cb(new Error('addresses read failed')),
106
+ findOne: (...args) => args.pop()(new Error('addresses read failed'))
107
+ };
108
+ sinon_1.default.stub(storage.db, 'collection').callsFake(name => name === storage_1.Storage.collections.ADDRESSES ? failing : realCollection(name));
109
+ };
110
+ describe('getAddresses', function () {
111
+ it('orders by createdOn, then by path as a string', async function () {
112
+ const { server } = await walletWithAddresses();
113
+ const result = await call(server, 'getAddresses');
114
+ result.map(a => a.path).should.deep.equal(ORDER);
115
+ });
116
+ it('applies noChange, reverse, skip and limit in that order, for every combination', async function () {
117
+ const { server } = await walletWithAddresses();
118
+ for (const noChange of [false, true]) {
119
+ for (const reverse of [false, true]) {
120
+ for (const skip of [0, 2, 3, 4, 7, 20]) {
121
+ for (const limit of [0, 1, 3, 4, 5, 6, 8, 10, 20]) {
122
+ const opts = { noChange, reverse, skip, limit };
123
+ const result = await call(server, 'getAddresses', opts);
124
+ result.map(a => a.path).should.deep.equal(expectedPaths(opts), JSON.stringify(opts));
125
+ }
126
+ }
127
+ }
128
+ }
129
+ });
130
+ it('filters by address, keeping the order and the paging', async function () {
131
+ const { server, addressOf } = await walletWithAddresses();
132
+ const paths = ['m/0/2', 'm/0/11', 'm/1/2', 'm/0/9', 'm/0/0'];
133
+ for (const reverse of [false, true]) {
134
+ for (const [skip, limit] of [[0, 0], [1, 2], [0, 10]]) {
135
+ for (const noChange of [false, true]) {
136
+ const opts = { addresses: paths.map(p => addressOf[p]), noChange, reverse, skip, limit };
137
+ const result = await call(server, 'getAddresses', opts);
138
+ result.map(a => a.path).should.deep.equal(expectedPaths({ paths, noChange, reverse, skip, limit }), JSON.stringify({ reverse, skip, limit, noChange }));
139
+ }
140
+ }
141
+ }
142
+ });
143
+ const expectOrder = async (server, order, opts = {}) => {
144
+ for (const paging of [{}, { limit: 2 }, { reverse: true, limit: 2 }, { skip: 1, limit: 3 }]) {
145
+ const all = { ...opts, ...paging };
146
+ (await call(server, 'getAddresses', all)).map(a => a.path).should.deep.equal(expectedPaths({ ...all, order }), JSON.stringify(all));
147
+ }
148
+ };
149
+ it('puts an address with no createdOn last', async function () {
150
+ const { server, wallet } = await walletWithAddresses();
151
+ await addresses().updateOne({ walletId: wallet.id, path: 'm/0/3' }, { $unset: { createdOn: '' } });
152
+ await expectOrder(server, [...ORDER.filter(p => p !== 'm/0/3'), 'm/0/3']);
153
+ });
154
+ it('puts an address with a null createdOn first', async function () {
155
+ const { server, wallet } = await walletWithAddresses();
156
+ await setCreatedOn(wallet.id, ['m/0/9'], null);
157
+ await expectOrder(server, ['m/0/9', ...ORDER.filter(p => p !== 'm/0/9')]);
158
+ });
159
+ it('keeps the order of receive addresses when only a change address has no createdOn', async function () {
160
+ const { server, wallet } = await walletWithAddresses();
161
+ await addresses().updateOne({ walletId: wallet.id, path: 'm/1/0' }, { $unset: { createdOn: '' } });
162
+ await expectOrder(server, [...ORDER.filter(p => p !== 'm/1/0'), 'm/1/0'], { noChange: true });
163
+ });
164
+ it('leaves out addresses whose isChange is any truthy value when noChange is set', async function () {
165
+ const { server, wallet } = await walletWithAddresses();
166
+ await addresses().updateOne({ walletId: wallet.id, path: 'm/1/1' }, { $set: { isChange: 1 } });
167
+ for (const opts of [{ noChange: true }, { noChange: true, limit: 20 }]) {
168
+ (await call(server, 'getAddresses', opts)).map(a => a.path).should.deep.equal(expectedPaths({ noChange: true }), JSON.stringify(opts));
169
+ }
170
+ });
171
+ it('returns nothing for a wallet with no addresses, an empty address filter, or a skip past the end', async function () {
172
+ const { server: empty } = await helpers_1.default.createAndJoinWallet(1, 1);
173
+ for (const opts of [{}, { limit: 1 }, { reverse: true, limit: 1 }]) {
174
+ (await call(empty, 'getAddresses', opts)).should.deep.equal([]);
175
+ }
176
+ const { server } = await walletWithAddresses({ offset: 1 });
177
+ (await call(server, 'getAddresses', { addresses: [] })).should.deep.equal([]);
178
+ (await call(server, 'getAddresses', { skip: 30, limit: 2 })).should.deep.equal([]);
179
+ });
180
+ it('treats fractional, huge, infinite, negative and NaN skips and limits the way slice does', async function () {
181
+ const { server } = await walletWithAddresses();
182
+ for (const opts of [
183
+ { limit: 1.5 }, { limit: 0.5 }, { limit: Infinity }, { limit: 1e300 }, { skip: 2, limit: 2 ** 60 }, { limit: -1 }, { limit: NaN },
184
+ { skip: 1.5, limit: 2 }, { skip: Infinity, limit: 1 }, { skip: -2, limit: 2 }, { skip: NaN, limit: 2 }, { reverse: true, skip: 2.7, limit: 3.2 }
185
+ ]) {
186
+ (await call(server, 'getAddresses', opts)).map(a => a.path).should.deep.equal(expectedPaths(opts), JSON.stringify(opts));
187
+ }
188
+ });
189
+ it('returns BCH addresses in cash address format', async function () {
190
+ const { server, wallet } = await helpers_1.default.createAndJoinWallet(1, 1, { coin: 'bch' });
191
+ await helpers_1.default.createAddresses(server, wallet, 2, 0);
192
+ const stored = await addresses().find({ walletId: wallet.id }).sort({ path: 1 }).toArray();
193
+ const result = await call(server, 'getAddresses', { limit: 1 });
194
+ result.length.should.equal(1);
195
+ result[0].address.should.equal(bchaddresstranslator_1.BCHAddressTranslator.translate(stored[0].address, 'cashaddr'));
196
+ });
197
+ it('passes on a storage error', async function () {
198
+ const { server } = await walletWithAddresses();
199
+ failAddressQueries();
200
+ for (const opts of [{}, { limit: 2 }]) {
201
+ const err = await call(server, 'getAddresses', opts).catch(e => e);
202
+ err.message.should.equal('addresses read failed');
203
+ }
204
+ });
205
+ });
206
+ describe('createAddress', function () {
207
+ const walletAtTheGap = async () => {
208
+ const { server, wallet } = await helpers_1.default.createAndJoinWallet(1, 1);
209
+ await helpers_1.default.createAddresses(server, wallet, 13, 3);
210
+ await addresses().updateMany({ walletId: wallet.id }, { $set: { createdOn: 1001 } });
211
+ sinon_1.default.stub(Defaults, 'MAX_MAIN_ADDRESS_GAP').value(3);
212
+ const docs = await addresses().find({ walletId: wallet.id }).toArray();
213
+ const pathOf = Object.fromEntries(docs.map(d => [d.address, d.path]));
214
+ const addressOf = Object.fromEntries(docs.map(d => [d.path, d.address]));
215
+ return { server, wallet, pathOf, addressOf };
216
+ };
217
+ const recordActivityChecks = (pathOf, active, failsOn) => {
218
+ helpers_1.default.stubAddressActivity(active, failsOn);
219
+ return sinon_1.default.spy(blockchainExplorer, 'getAddressActivity');
220
+ };
221
+ it('fails at the gap after checking the newest receive addresses, newest first', async function () {
222
+ const { server, pathOf } = await walletAtTheGap();
223
+ const checks = recordActivityChecks(pathOf, []);
224
+ const err = await call(server, 'createAddress').catch(e => e);
225
+ err.code.should.equal('MAIN_ADDRESS_GAP_REACHED');
226
+ checks.getCalls().map(c => pathOf[c.args[0]]).should.deep.equal(['m/0/9', 'm/0/8', 'm/0/7']);
227
+ });
228
+ it('stops at the newest address with activity, marks it, and creates the next address', async function () {
229
+ const { server, wallet, pathOf, addressOf } = await walletAtTheGap();
230
+ const checks = recordActivityChecks(pathOf, [addressOf['m/0/8'], addressOf['m/0/7']]);
231
+ const address = await call(server, 'createAddress');
232
+ address.path.should.equal('m/0/13');
233
+ checks.getCalls().map(c => pathOf[c.args[0]]).should.deep.equal(['m/0/9', 'm/0/8']);
234
+ const marked = await addresses().find({ walletId: wallet.id, hasActivity: true }).toArray();
235
+ marked.map(d => d.path).should.deep.equal(['m/0/8']);
236
+ });
237
+ it('creates without checking when an address in the window already has activity', async function () {
238
+ const { server, wallet, pathOf } = await walletAtTheGap();
239
+ await addresses().updateOne({ walletId: wallet.id, path: 'm/0/7' }, { $set: { hasActivity: true } });
240
+ const checks = recordActivityChecks(pathOf, []);
241
+ (await call(server, 'createAddress')).path.should.equal('m/0/13');
242
+ checks.callCount.should.equal(0);
243
+ });
244
+ it('ignores activity on addresses outside the window and on change addresses', async function () {
245
+ const { server, wallet, pathOf } = await walletAtTheGap();
246
+ await addresses().updateMany({ walletId: wallet.id, path: { $in: ['m/0/6', 'm/0/10', 'm/1/2'] } }, { $set: { hasActivity: true } });
247
+ const checks = recordActivityChecks(pathOf, []);
248
+ const err = await call(server, 'createAddress').catch(e => e);
249
+ err.code.should.equal('MAIN_ADDRESS_GAP_REACHED');
250
+ checks.callCount.should.equal(3);
251
+ });
252
+ it('creates without checking when there are fewer receive addresses than the gap', async function () {
253
+ const { server, wallet } = await helpers_1.default.createAndJoinWallet(1, 1);
254
+ await helpers_1.default.createAddresses(server, wallet, 2, 5);
255
+ sinon_1.default.stub(Defaults, 'MAX_MAIN_ADDRESS_GAP').value(3);
256
+ const checks = recordActivityChecks({}, []);
257
+ (await call(server, 'createAddress')).path.should.equal('m/0/2');
258
+ checks.callCount.should.equal(0);
259
+ });
260
+ it('passes on an error checking activity', async function () {
261
+ const { server, pathOf } = await walletAtTheGap();
262
+ recordActivityChecks(pathOf, [], 2);
263
+ const err = await call(server, 'createAddress').catch(e => e);
264
+ err.should.equal('failed on request');
265
+ });
266
+ it('passes on a storage error', async function () {
267
+ const { server } = await walletAtTheGap();
268
+ failAddressQueries();
269
+ const err = await call(server, 'createAddress').catch(e => e);
270
+ err.message.should.equal('addresses read failed');
271
+ });
272
+ it('returns the first address of a single-address wallet', async function () {
273
+ const { server, wallet } = await helpers_1.default.createAndJoinWallet(1, 1, { singleAddress: true });
274
+ const first = await call(server, 'createAddress');
275
+ first.path.should.equal('m/0/0');
276
+ (await call(server, 'createAddress')).address.should.equal(first.address);
277
+ (await addresses().countDocuments({ walletId: wallet.id })).should.equal(1);
278
+ });
279
+ it('passes on a storage error for a single-address wallet', async function () {
280
+ const { server } = await helpers_1.default.createAndJoinWallet(1, 1, { singleAddress: true });
281
+ await call(server, 'createAddress');
282
+ failAddressQueries();
283
+ const err = await call(server, 'createAddress').catch(e => e);
284
+ err.message.should.equal('addresses read failed');
285
+ });
286
+ });
287
+ describe('reads only the addresses it needs', function () {
288
+ const largeWallet = async () => {
289
+ const { server, wallet } = await helpers_1.default.createAndJoinWallet(1, 1);
290
+ await helpers_1.default.createAddresses(server, wallet, 30, 10);
291
+ const docs = await addresses().find({ walletId: wallet.id }).toArray();
292
+ for (const [i, doc] of docs.entries()) {
293
+ await addresses().updateOne({ _id: doc._id }, { $set: { createdOn: 1000 + i } });
294
+ }
295
+ return { server, wallet };
296
+ };
297
+ const countBuilt = () => sinon_1.default.spy(model_1.Address, 'fromObj');
298
+ const wrapAddressQueries = ({ passing = Infinity } = {}) => {
299
+ const realCollection = storage.db.collection.bind(storage.db);
300
+ const counts = { finds: 0, docs: 0, findOnes: 0 };
301
+ sinon_1.default.stub(storage.db, 'collection').callsFake(name => {
302
+ const collection = realCollection(name);
303
+ if (name !== storage_1.Storage.collections.ADDRESSES)
304
+ return collection;
305
+ return Object.assign(Object.create(collection), {
306
+ find: (...args) => {
307
+ const cursor = collection.find(...args);
308
+ const fail = ++counts.finds > passing;
309
+ const toArray = cursor.toArray.bind(cursor);
310
+ cursor.toArray = cb => fail ? cb(new Error('addresses read failed')) : toArray((err, docs) => {
311
+ counts.docs += docs?.length || 0;
312
+ cb(err, docs);
313
+ });
314
+ return cursor;
315
+ },
316
+ findOne: (...args) => {
317
+ counts.findOnes++;
318
+ return collection.findOne(...args);
319
+ }
320
+ });
321
+ });
322
+ return counts;
323
+ };
324
+ it('getAddresses with a limit builds only that many addresses', async function () {
325
+ const { server } = await largeWallet();
326
+ const built = countBuilt();
327
+ const read = wrapAddressQueries();
328
+ (await call(server, 'getAddresses', { limit: 1 })).length.should.equal(1);
329
+ built.callCount.should.equal(1);
330
+ read.docs.should.equal(2);
331
+ read.findOnes.should.equal(1);
332
+ });
333
+ it('getAddresses with skip and a limit builds only the addresses up to the end of the page', async function () {
334
+ const { server } = await largeWallet();
335
+ const built = countBuilt();
336
+ const read = wrapAddressQueries();
337
+ (await call(server, 'getAddresses', { noChange: true, reverse: true, skip: 2, limit: 3 })).length.should.equal(3);
338
+ built.callCount.should.equal(5);
339
+ read.docs.should.equal(6);
340
+ });
341
+ it('getAddresses also builds the addresses that share the page\'s last createdOn', async function () {
342
+ const { server, wallet } = await largeWallet();
343
+ const first = await addresses().find({ walletId: wallet.id }).sort({ createdOn: 1 }).limit(4).toArray();
344
+ await addresses().updateMany({ _id: { $in: first.slice(1).map(d => d._id) } }, { $set: { createdOn: first[1].createdOn } });
345
+ const built = countBuilt();
346
+ const read = wrapAddressQueries();
347
+ (await call(server, 'getAddresses', { limit: 2 })).length.should.equal(2);
348
+ built.callCount.should.equal(4);
349
+ read.docs.should.equal(6);
350
+ });
351
+ it('getAddresses passes on a storage error reading the page', async function () {
352
+ const { server } = await largeWallet();
353
+ wrapAddressQueries({ passing: 0 });
354
+ const err = await call(server, 'getAddresses', { limit: 2 }).catch(e => e);
355
+ err.message.should.equal('addresses read failed');
356
+ });
357
+ it('getAddresses passes on a storage error reading the addresses that share the last createdOn', async function () {
358
+ const { server, wallet } = await largeWallet();
359
+ await addresses().updateMany({ walletId: wallet.id }, { $set: { createdOn: 1000 } });
360
+ wrapAddressQueries({ passing: 1 });
361
+ const err = await call(server, 'getAddresses', { limit: 2 }).catch(e => e);
362
+ err.message.should.equal('addresses read failed');
363
+ });
364
+ it('the single-address paths build only the first address', async function () {
365
+ for (const [coin, singleAddress] of [['eth', false], ['xrp', false], ['btc', true]]) {
366
+ const { server, wallet } = await helpers_1.default.createAndJoinWallet(1, 1, { coin, singleAddress, offset: coin === 'xrp' ? 1 : coin === 'btc' ? 2 : 0 });
367
+ await helpers_1.default.createAddresses(server, wallet, 10, 0);
368
+ const docs = await addresses().find({ walletId: wallet.id }).toArray();
369
+ for (const [i, doc] of docs.entries()) {
370
+ await addresses().updateOne({ _id: doc._id }, { $set: { createdOn: 1000 + i } });
371
+ }
372
+ await helpers_1.default.stubUtxos(server, wallet, [1]);
373
+ const built = countBuilt();
374
+ await call(server, coin === 'btc' ? 'createAddress' : 'getBalance');
375
+ built.callCount.should.equal(1, coin);
376
+ built.restore();
377
+ }
378
+ });
379
+ it('createAddress builds only the addresses in the gap window', async function () {
380
+ const { server } = await largeWallet();
381
+ sinon_1.default.stub(Defaults, 'MAX_MAIN_ADDRESS_GAP').value(3);
382
+ helpers_1.default.stubAddressActivity([]);
383
+ const built = countBuilt();
384
+ const read = wrapAddressQueries();
385
+ const err = await call(server, 'createAddress').catch(e => e);
386
+ err.code.should.equal('MAIN_ADDRESS_GAP_REACHED');
387
+ built.callCount.should.equal(3);
388
+ read.docs.should.equal(4);
389
+ });
390
+ });
391
+ describe('single-address chains use their first address', function () {
392
+ const SOL_ADDRESS = '7EcDhSYGxXyscszYEp35KHN8vvw3svAuLKTzXwCFLtV';
393
+ const SOL_ADDRESS_2 = 'GZNcvqb38Yd3TPD5JMvZJAGxxrDu8JLGECykcmzBpBw7';
394
+ const firstAddress = async (coin, server, wallet) => {
395
+ if (coin !== 'sol')
396
+ return call(server, 'createAddress');
397
+ const address = { walletId: wallet.id, address: SOL_ADDRESS, path: 'm/0/0', isChange: false, publicKeys: [], coin: 'sol', chain: 'sol', network: 'livenet', createdOn: 1000 };
398
+ await addresses().insertOne({ ...address });
399
+ return address;
400
+ };
401
+ const stubBalance = async (coin, server, wallet) => {
402
+ if (coin !== 'sol')
403
+ return helpers_1.default.stubUtxos(server, wallet, [1]);
404
+ const getRentMinimum = blockchainExplorer.getRentMinimum;
405
+ blockchainExplorer.getRentMinimum = (space, cb) => cb(null, Defaults.MIN_SOL_BALANCE);
406
+ restores.push(() => { blockchainExplorer.getRentMinimum = getRentMinimum; });
407
+ };
408
+ for (const coin of ['eth', 'xrp', 'sol']) {
409
+ it(`${coin} balance lists the first address`, async function () {
410
+ const { server, wallet } = await helpers_1.default.createAndJoinWallet(1, 1, { coin });
411
+ const address = await firstAddress(coin, server, wallet);
412
+ await stubBalance(coin, server, wallet);
413
+ const balance = await call(server, 'getBalance');
414
+ balance.byAddress.length.should.equal(1);
415
+ balance.byAddress[0].address.should.equal(address.address);
416
+ balance.byAddress[0].path.should.equal(address.path);
417
+ });
418
+ it(`${coin} balance passes on a storage error`, async function () {
419
+ const { server, wallet } = await helpers_1.default.createAndJoinWallet(1, 1, { coin });
420
+ await firstAddress(coin, server, wallet);
421
+ await stubBalance(coin, server, wallet);
422
+ failAddressQueries();
423
+ const err = await call(server, 'getBalance').catch(e => e);
424
+ err.message.should.equal('addresses read failed');
425
+ });
426
+ }
427
+ const tieForFirst = async (server, wallet) => {
428
+ await helpers_1.default.createAddresses(server, wallet, 11, 0);
429
+ await addresses().updateMany({ walletId: wallet.id }, { $set: { createdOn: 1001 } });
430
+ await setCreatedOn(wallet.id, ['m/0/2', 'm/0/10'], 1000);
431
+ return (await addresses().findOne({ walletId: wallet.id, path: 'm/0/10' })).address;
432
+ };
433
+ it('the first address is the first by createdOn, then by path as a string', async function () {
434
+ const { server: eth, wallet: ethWallet } = await helpers_1.default.createAndJoinWallet(1, 1, { coin: 'eth' });
435
+ const ethFirst = await tieForFirst(eth, ethWallet);
436
+ await helpers_1.default.stubUtxos(eth, ethWallet, [1]);
437
+ (await call(eth, 'getBalance')).byAddress.map(a => a.address).should.deep.equal([ethFirst]);
438
+ const { server: btc, wallet: btcWallet } = await helpers_1.default.createAndJoinWallet(1, 1, { singleAddress: true, offset: 1 });
439
+ const btcFirst = await tieForFirst(btc, btcWallet);
440
+ (await call(btc, 'createAddress')).address.should.equal(btcFirst);
441
+ await helpers_1.default.stubUtxos(btc, btcWallet, [1]);
442
+ const txp = await helpers_1.default.createAndPublishTx(btc, {
443
+ outputs: [{ toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: 0.5e8 }],
444
+ feePerKb: 100e2
445
+ }, TestData.copayers[1].privKey_1H_0);
446
+ txp.changeAddress.address.should.equal(btcFirst);
447
+ const { server: sol, wallet: solWallet } = await helpers_1.default.createAndJoinWallet(1, 1, { coin: 'sol', offset: 2 });
448
+ await firstAddress('sol', sol, solWallet);
449
+ await addresses().insertOne({ walletId: solWallet.id, address: SOL_ADDRESS_2, path: 'm/0/1', isChange: false, publicKeys: [], coin: 'sol', chain: 'sol', network: 'livenet', createdOn: 2000 });
450
+ await stubBalance('sol', sol, solWallet);
451
+ (await call(sol, 'getBalance')).byAddress.map(a => a.address).should.deep.equal([SOL_ADDRESS]);
452
+ });
453
+ it('a single-address BTC wallet sends change to its first address', async function () {
454
+ const { server, wallet } = await helpers_1.default.createAndJoinWallet(1, 1, { singleAddress: true });
455
+ const address = await call(server, 'createAddress');
456
+ await helpers_1.default.stubUtxos(server, wallet, [1]);
457
+ const txp = await helpers_1.default.createAndPublishTx(server, {
458
+ outputs: [{ toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: 0.5e8 }],
459
+ feePerKb: 100e2
460
+ }, TestData.copayers[0].privKey_1H_0);
461
+ txp.changeAddress.address.should.equal(address.address);
462
+ });
463
+ });
464
+ });
465
+ //# sourceMappingURL=addressReads.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addressReads.test.js","sourceRoot":"","sources":["../../../test/integration/addressReads.test.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEb,2CAA6B;AAC7B,gCAA8B;AAC9B,gDAAwB;AACxB,kDAA0B;AAC1B,6EAA0E;AAC1E,iDAA8C;AAC9C,+CAA8C;AAE9C,mDAAgD;AAChD,sDAAwC;AACxC,wDAAgC;AAEhC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;AAC7B,MAAM,EAAE,QAAQ,EAAE,GAAG,eAAM,CAAC;AAI5B,MAAM,KAAK,GAAG;IAEZ,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IAEpD,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;CAC5F,CAAC;AACF,MAAM,UAAU,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAE/G,QAAQ,CAAC,eAAe,EAAE;IACxB,IAAI,kBAAkB,CAAC;IACvB,IAAI,OAAgB,CAAC;IAErB,MAAM,CAAC,KAAK;QACV,CAAC,EAAE,kBAAkB,EAAE,OAAO,EAAE,GAAG,MAAM,iBAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,KAAK;QACd,MAAM,iBAAO,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC,CAAC,CAAC;IAGH,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,SAAS,CAAC;QACR,eAAK,CAAC,OAAO,EAAE,CAAC;QAChB,OAAO,QAAQ,CAAC,MAAM;YAAE,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,KAAK;QACT,MAAM,iBAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,CAAC,MAAqB,EAAE,MAAc,EAAE,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,cAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACrH,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,iBAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IAC7E,MAAM,YAAY,GAAG,CAAC,QAAgB,EAAE,KAAe,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;IAG3J,MAAM,mBAAmB,GAAG,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,EAAE;QAC9C,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QACzE,MAAM,iBAAO,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QACrD,KAAK,MAAM,SAAS,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACrC,MAAM,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC;QACjG,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QACvE,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACzE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACvC,CAAC,CAAC;IAGF,MAAM,aAAa,GAAG,CAAC,EAAE,QAAQ,GAAG,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,IAAI,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,KAAK,EAAE,EAAE,EAAE;QAChH,IAAI,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5G,IAAI,OAAO;YAAE,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QACxC,IAAI,IAAI,GAAG,CAAC;YAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,KAAK,GAAG,CAAC;YAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC3C,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAGF,MAAM,kBAAkB,GAAG,GAAG,EAAE;QAC9B,MAAM,cAAc,GAAG,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG;YACd,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO;YACnB,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO;YACnB,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO;YACnB,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO;YACpB,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO;YACtB,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;YACrD,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;SACrE,CAAC;QACF,eAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,iBAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;IAClI,CAAC,CAAC;IAEF,QAAQ,CAAC,cAAc,EAAE;QACvB,EAAE,CAAC,+CAA+C,EAAE,KAAK;YACvD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,mBAAmB,EAAE,CAAC;YAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;YAClD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gFAAgF,EAAE,KAAK;YACxF,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,mBAAmB,EAAE,CAAC;YAC/C,KAAK,MAAM,QAAQ,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;gBACrC,KAAK,MAAM,OAAO,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;oBACpC,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;wBACvC,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;4BAClD,MAAM,IAAI,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;4BAChD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;4BACxD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;wBACvF,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK;YAC9D,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,mBAAmB,EAAE,CAAC;YAC1D,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7D,KAAK,MAAM,OAAO,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;gBACpC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;oBACtD,KAAK,MAAM,QAAQ,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;wBACrC,MAAM,IAAI,GAAG,EAAE,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;wBACzF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;wBACxD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;oBAC1J,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,KAAK,EAAE,MAAM,EAAE,KAAe,EAAE,IAAI,GAAG,EAAE,EAAE,EAAE;YAC/D,KAAK,MAAM,MAAM,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC5F,MAAM,GAAG,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC;gBACnC,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;YACtI,CAAC;QACH,CAAC,CAAC;QAEF,EAAE,CAAC,wCAAwC,EAAE,KAAK;YAChD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,mBAAmB,EAAE,CAAC;YACvD,MAAM,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YACnG,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK;YACrD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,mBAAmB,EAAE,CAAC;YACvD,MAAM,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;YAC/C,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kFAAkF,EAAE,KAAK;YAC1F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,mBAAmB,EAAE,CAAC;YACvD,MAAM,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YACnG,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAChG,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8EAA8E,EAAE,KAAK;YACtF,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,mBAAmB,EAAE,CAAC;YACvD,MAAM,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/F,KAAK,MAAM,IAAI,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;gBACvE,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YACzI,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iGAAiG,EAAE,KAAK;YACzG,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAClE,KAAK,MAAM,IAAI,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;gBACnE,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClE,CAAC;YACD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;YAC5D,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC9E,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACrF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yFAAyF,EAAE,KAAK;YACjG,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,mBAAmB,EAAE,CAAC;YAC/C,KAAK,MAAM,IAAI,IAAI;gBACjB,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE;gBACjI,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE;aACjJ,EAAE,CAAC;gBACF,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAC3H,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK;YACtD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACpF,MAAM,iBAAO,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACpD,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YAE3F,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;YAEhE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2CAAoB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;QAChG,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2BAA2B,EAAE,KAAK;YACnC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,mBAAmB,EAAE,CAAC;YAC/C,kBAAkB,EAAE,CAAC;YACrB,KAAK,MAAM,IAAI,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;gBACtC,MAAM,GAAG,GAAQ,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBACxE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;YACpD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE;QAExB,MAAM,cAAc,GAAG,KAAK,IAAI,EAAE;YAChC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACnE,MAAM,iBAAO,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YACrD,MAAM,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACrF,eAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACtD,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YACvE,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACtE,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACzE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC/C,CAAC,CAAC;QACF,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,MAAgB,EAAE,OAAgB,EAAE,EAAE;YAC1E,iBAAO,CAAC,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC7C,OAAO,eAAK,CAAC,GAAG,CAAC,kBAAkB,EAAE,oBAAoB,CAAC,CAAC;QAC7D,CAAC,CAAC;QAEF,EAAE,CAAC,4EAA4E,EAAE,KAAK;YACpF,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;YAClD,MAAM,MAAM,GAAG,oBAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAEhD,MAAM,GAAG,GAAQ,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAEnE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAClD,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAC/F,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mFAAmF,EAAE,KAAK;YAC3F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;YACrE,MAAM,MAAM,GAAG,oBAAoB,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAEtF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;YAEpD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACpC,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;YACpF,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YAC5F,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6EAA6E,EAAE,KAAK;YACrF,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;YAC1D,MAAM,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACrG,MAAM,MAAM,GAAG,oBAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAEhD,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAClE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK;YAClF,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;YAC1D,MAAM,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACpI,MAAM,MAAM,GAAG,oBAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAEhD,MAAM,GAAG,GAAQ,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAEnE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAClD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8EAA8E,EAAE,KAAK;YACtF,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACnE,MAAM,iBAAO,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACpD,eAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACtD,MAAM,MAAM,GAAG,oBAAoB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAE5C,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACjE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK;YAC9C,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;YAClD,oBAAoB,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC9D,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2BAA2B,EAAE,KAAK;YACnC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;YAC1C,kBAAkB,EAAE,CAAC;YACrB,MAAM,GAAG,GAAQ,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACnE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK;YAC9D,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5F,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACjC,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC1E,CAAC,MAAM,SAAS,EAAE,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK;YAC/D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YACpF,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;YACpC,kBAAkB,EAAE,CAAC;YACrB,MAAM,GAAG,GAAQ,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACnE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mCAAmC,EAAE;QAE5C,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE;YAC7B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACnE,MAAM,iBAAO,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YACtD,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YACvE,KAAK,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;gBACtC,MAAM,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YACnF,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAC5B,CAAC,CAAC;QACF,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,eAAK,CAAC,GAAG,CAAC,eAAO,EAAE,SAAS,CAAC,CAAC;QAGvD,MAAM,kBAAkB,GAAG,CAAC,EAAE,OAAO,GAAG,QAAQ,EAAE,GAAG,EAAE,EAAE,EAAE;YACzD,MAAM,cAAc,GAAG,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC9D,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;YAClD,eAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;gBACpD,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;gBACxC,IAAI,IAAI,KAAK,iBAAO,CAAC,WAAW,CAAC,SAAS;oBAAE,OAAO,UAAU,CAAC;gBAC9D,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE;oBAC9C,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE;wBAChB,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;wBACxC,MAAM,IAAI,GAAG,EAAE,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC;wBACtC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;wBAC5C,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;4BAC3F,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC;4BACjC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;wBAChB,CAAC,CAAC,CAAC;wBACH,OAAO,MAAM,CAAC;oBAChB,CAAC;oBACD,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE;wBACnB,MAAM,CAAC,QAAQ,EAAE,CAAC;wBAClB,OAAO,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;oBACrC,CAAC;iBACF,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YACH,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QAEF,EAAE,CAAC,2DAA2D,EAAE,KAAK;YACnE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAC;YAClC,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1E,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wFAAwF,EAAE,KAAK;YAChG,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAC;YAClC,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAClH,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8EAA8E,EAAE,KAAK;YACtF,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;YAC/C,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YACxG,MAAM,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YAC5H,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAC;YAClC,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1E,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK;YACjE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;YACvC,kBAAkB,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;YACnC,MAAM,GAAG,GAAQ,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAChF,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4FAA4F,EAAE,KAAK;YACpG,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;YAC/C,MAAM,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACrF,kBAAkB,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;YACnC,MAAM,GAAG,GAAQ,MAAM,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAChF,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK;YAC/D,KAAK,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAA6B,EAAE,CAAC;gBAChH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACjJ,MAAM,iBAAO,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;gBACrD,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;gBACvE,KAAK,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;oBACtC,MAAM,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;gBACnF,CAAC;gBACD,MAAM,iBAAO,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC7C,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;gBAC3B,MAAM,IAAI,CAAC,MAAM,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;gBACpE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;gBACtC,KAAK,CAAC,OAAO,EAAE,CAAC;YAClB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK;YACnE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;YACvC,eAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACtD,iBAAO,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;YAChC,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAC;YAClC,MAAM,GAAG,GAAQ,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACnE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAClD,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,+CAA+C,EAAE;QAGxD,MAAM,WAAW,GAAG,6CAA6C,CAAC;QAClE,MAAM,aAAa,GAAG,8CAA8C,CAAC;QACrE,MAAM,YAAY,GAAG,KAAK,EAAE,IAAY,EAAE,MAAqB,EAAE,MAAM,EAAE,EAAE;YACzE,IAAI,IAAI,KAAK,KAAK;gBAAE,OAAO,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;YACzD,MAAM,OAAO,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;YAC9K,MAAM,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;YAC5C,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC;QAGF,MAAM,WAAW,GAAG,KAAK,EAAE,IAAY,EAAE,MAAqB,EAAE,MAAM,EAAE,EAAE;YACxE,IAAI,IAAI,KAAK,KAAK;gBAAE,OAAO,iBAAO,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAClE,MAAM,cAAc,GAAG,kBAAkB,CAAC,cAAc,CAAC;YACzD,kBAAkB,CAAC,cAAc,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;YACtF,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,kBAAkB,CAAC,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/E,CAAC,CAAC;QAEF,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;YACzC,EAAE,CAAC,GAAG,IAAI,kCAAkC,EAAE,KAAK;gBACjD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC7E,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;gBACzD,MAAM,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;gBAExC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;gBAEjD,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACzC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBAC3D,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACvD,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,GAAG,IAAI,oCAAoC,EAAE,KAAK;gBACnD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC7E,MAAM,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;gBACzC,MAAM,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;gBACxC,kBAAkB,EAAE,CAAC;gBACrB,MAAM,GAAG,GAAQ,MAAM,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAChE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;YACpD,CAAC,CAAC,CAAC;QACL,CAAC;QAGD,MAAM,WAAW,GAAG,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YAC3C,MAAM,iBAAO,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YACrD,MAAM,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACrF,MAAM,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;YACzD,OAAO,CAAC,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QACtF,CAAC,CAAC;QAEF,EAAE,CAAC,uEAAuE,EAAE,KAAK;YAC/E,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACpG,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YACnD,MAAM,iBAAO,CAAC,SAAS,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7C,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE5F,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;YACvH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YACnD,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAElE,MAAM,iBAAO,CAAC,SAAS,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7C,MAAM,GAAG,GAAG,MAAM,iBAAO,CAAC,kBAAkB,CAAC,GAAG,EAAE;gBAChD,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,oCAAoC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;gBAC7E,QAAQ,EAAE,KAAK;aAChB,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;YACtC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAEjD,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;YAC/G,MAAM,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;YAC1C,MAAM,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAChM,MAAM,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;YACzC,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;QACjG,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+DAA+D,EAAE,KAAK;YACvE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5F,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;YACpD,MAAM,iBAAO,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAE7C,MAAM,GAAG,GAAG,MAAM,iBAAO,CAAC,kBAAkB,CAAC,MAAM,EAAE;gBACnD,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,oCAAoC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;gBAC7E,QAAQ,EAAE,KAAK;aAChB,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;YAEtC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -41,6 +41,7 @@ const sinon_1 = __importDefault(require("sinon"));
41
41
  const util_1 = __importDefault(require("util"));
42
42
  const CWC = __importStar(require("@bitpay-labs/crypto-wallet-core"));
43
43
  const blockchainmonitor_1 = require("../../src/lib/blockchainmonitor");
44
+ const chain_1 = require("../../src/lib/chain");
44
45
  const constants_1 = require("../../src/lib/common/constants");
45
46
  const helpers_1 = __importDefault(require("./helpers"));
46
47
  const should = chai.should();
@@ -204,6 +205,45 @@ describe('Blockchain monitor', function () {
204
205
  });
205
206
  });
206
207
  });
208
+ describe('EVM tx events, as bitcore-node emits them', function () {
209
+ const token = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
210
+ const sender = '0xC877cBCF020A8AA259A1Efab1559B2A3A7259086';
211
+ const receive = tx => bcmonitor._handleIncomingPayments('eth', 'livenet', chain_1.ChainService.onTx('eth', tx));
212
+ const incomingNotifications = async (s) => {
213
+ const notifications = await util_1.default.promisify(s.getNotifications).call(s, {});
214
+ return notifications.filter(n => n.type === 'NewIncomingTx');
215
+ };
216
+ const ethAddress = async () => {
217
+ const { server: s } = await helpers_1.default.createAndJoinWallet(1, 1, { coin: 'eth' });
218
+ const address = await util_1.default.promisify(s.createAddress).call(s, {});
219
+ return { s, address: address.address };
220
+ };
221
+ it('notifies the recipient of a native transfer', async function () {
222
+ const { s, address } = await ethAddress();
223
+ receive({ chain: 'ETH', network: 'mainnet', txid: '0x01', to: address, from: sender, value: 5000, effects: [] });
224
+ await new Promise(resolve => setTimeout(resolve, 100));
225
+ const notifications = await incomingNotifications(s);
226
+ notifications.length.should.equal(1);
227
+ notifications[0].data.should.include({ txid: '0x01', address, amount: 5000 });
228
+ should.not.exist(notifications[0].data.tokenAddress);
229
+ });
230
+ it('notifies the recipient of an ERC20 transfer, with the token', async function () {
231
+ const { s, address } = await ethAddress();
232
+ receive({
233
+ chain: 'ETH',
234
+ network: 'mainnet',
235
+ txid: '0x02',
236
+ to: token,
237
+ from: sender,
238
+ value: 0,
239
+ effects: [{ type: 'ERC20:transfer', to: address, from: sender, amount: '1000000', contractAddress: token, callStack: '' }]
240
+ });
241
+ await new Promise(resolve => setTimeout(resolve, 100));
242
+ const notifications = await incomingNotifications(s);
243
+ notifications.length.should.equal(1);
244
+ notifications[0].data.should.include({ txid: '0x02', address, amount: '1000000', tokenAddress: token });
245
+ });
246
+ });
207
247
  it('should not notify copayers of incoming txs more than once', function (done) {
208
248
  server.createAddress({}, function (err, address) {
209
249
  should.not.exist(err);