@ledgerhq/revault-sdk 0.24.1 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/bake.cjs +1219 -1025
- package/lib/bake.cjs.map +1 -1
- package/lib/bake.d.cts +572 -548
- package/lib/bake.d.ts +572 -548
- package/lib/bake.js +1209 -1025
- package/lib/bake.js.map +1 -1
- package/lib/chunk-CKQMccvm.cjs +28 -0
- package/lib/crypto-BDBF_rfw.cjs +268 -0
- package/lib/crypto-BDBF_rfw.cjs.map +1 -0
- package/lib/crypto-CPCBrCSZ.js +245 -0
- package/lib/crypto-CPCBrCSZ.js.map +1 -0
- package/lib/crypto.cjs +5 -11
- package/lib/crypto.d.cts +10 -7
- package/lib/crypto.d.ts +10 -7
- package/lib/crypto.js +2 -11
- package/lib/device-0lcfYGHr.cjs +793 -0
- package/lib/device-0lcfYGHr.cjs.map +1 -0
- package/lib/device-B8Fww8_6.js +719 -0
- package/lib/device-B8Fww8_6.js.map +1 -0
- package/lib/device.cjs +6 -13
- package/lib/device.d.cts +2 -50
- package/lib/device.d.ts +2 -50
- package/lib/device.js +2 -13
- package/lib/engine.cjs +835 -886
- package/lib/engine.cjs.map +1 -1
- package/lib/engine.d.cts +3 -25
- package/lib/engine.d.ts +3 -25
- package/lib/engine.js +828 -885
- package/lib/engine.js.map +1 -1
- package/lib/index--fscLDTT.d.ts +237 -0
- package/lib/index-BE7oUpCb.d.cts +237 -0
- package/lib/index-C4Xjiv0k.d.cts +23 -0
- package/lib/index-CVjhPoZh.d.ts +23 -0
- package/lib/index.cjs +0 -1
- package/lib/index.d.cts +10 -5
- package/lib/index.d.ts +10 -5
- package/lib/index.js +1 -1
- package/lib/logger-Cme0iL1f.d.cts +10 -0
- package/lib/logger-DWLViq7U.d.ts +10 -0
- package/lib/onboarding.cjs +179 -181
- package/lib/onboarding.cjs.map +1 -1
- package/lib/onboarding.d.cts +1751 -1722
- package/lib/onboarding.d.ts +1751 -1722
- package/lib/onboarding.js +175 -181
- package/lib/onboarding.js.map +1 -1
- package/lib/trpc-CWGPr8Ox.d.ts +20 -0
- package/lib/trpc-C_dUOB1u.d.cts +20 -0
- package/lib/types-4CfR5--z.d.ts +203 -0
- package/lib/types-Byf9V35t.d.cts +203 -0
- package/lib/types-CQROu0nu.d.cts +6 -0
- package/lib/types-_QeBv1U4.d.ts +6 -0
- package/lib/types.cjs +0 -1
- package/lib/types.d.cts +3 -4
- package/lib/types.d.ts +3 -4
- package/lib/types.js +1 -1
- package/lib/utils-BGbdjOP9.js +61 -0
- package/lib/utils-BGbdjOP9.js.map +1 -0
- package/lib/utils-DbSFXp4c.cjs +86 -0
- package/lib/utils-DbSFXp4c.cjs.map +1 -0
- package/package.json +23 -23
- package/lib/chunk-2WGM7EWA.cjs +0 -282
- package/lib/chunk-2WGM7EWA.cjs.map +0 -1
- package/lib/chunk-AXI72NFY.js +0 -50
- package/lib/chunk-AXI72NFY.js.map +0 -1
- package/lib/chunk-EBMIZ52H.cjs +0 -814
- package/lib/chunk-EBMIZ52H.cjs.map +0 -1
- package/lib/chunk-KV5FO7N5.js +0 -282
- package/lib/chunk-KV5FO7N5.js.map +0 -1
- package/lib/chunk-LH4QQXUH.cjs +0 -50
- package/lib/chunk-LH4QQXUH.cjs.map +0 -1
- package/lib/chunk-XQ4BT4HB.js +0 -814
- package/lib/chunk-XQ4BT4HB.js.map +0 -1
- package/lib/crypto.cjs.map +0 -1
- package/lib/crypto.js.map +0 -1
- package/lib/device.cjs.map +0 -1
- package/lib/device.js.map +0 -1
- package/lib/index.cjs.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/logger-C-TPbnjv.d.cts +0 -9
- package/lib/logger-C-TPbnjv.d.ts +0 -9
- package/lib/types-C-ngtI5m.d.ts +0 -202
- package/lib/types-CpGEbAxh.d.cts +0 -19
- package/lib/types-CpGEbAxh.d.ts +0 -19
- package/lib/types-CryvY9pW.d.cts +0 -202
- package/lib/types-DJfbanPz.d.cts +0 -167
- package/lib/types-DJfbanPz.d.ts +0 -167
- package/lib/types.cjs.map +0 -1
- package/lib/types.js.map +0 -1
package/lib/bake.cjs
CHANGED
|
@@ -1,1079 +1,1273 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// src/bake/utils.ts
|
|
16
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_chunk = require("./chunk-CKQMccvm.cjs");
|
|
3
|
+
const require_utils = require("./utils-DbSFXp4c.cjs");
|
|
4
|
+
const require_crypto = require("./crypto-BDBF_rfw.cjs");
|
|
5
|
+
let invariant = require("invariant");
|
|
6
|
+
invariant = require_chunk.__toESM(invariant);
|
|
7
|
+
let lodash = require("lodash");
|
|
8
|
+
lodash = require_chunk.__toESM(lodash);
|
|
9
|
+
let ts_pattern = require("ts-pattern");
|
|
10
|
+
let zod = require("zod");
|
|
11
|
+
zod = require_chunk.__toESM(zod);
|
|
12
|
+
//#region src/bake/utils.ts
|
|
17
13
|
function createBakeLogHelpers(logger) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
14
|
+
return {
|
|
15
|
+
logTitle(title) {
|
|
16
|
+
logger.info(`:: ${title} ::`);
|
|
17
|
+
},
|
|
18
|
+
logStep(msg) {
|
|
19
|
+
logger.info(`=> ${msg}`);
|
|
20
|
+
},
|
|
21
|
+
logSubStep(msg) {
|
|
22
|
+
logger.info(` -> ${msg}`);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
29
25
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
INITIAL: false,
|
|
41
|
-
PENDING_APPROVAL: false
|
|
26
|
+
const IS_REQUEST_STATE_END_STATE = {
|
|
27
|
+
ABORTED: true,
|
|
28
|
+
BLOCKED: true,
|
|
29
|
+
EXECUTED: true,
|
|
30
|
+
EXPIRED: true,
|
|
31
|
+
FAILED: true,
|
|
32
|
+
STUCK: true,
|
|
33
|
+
EXECUTING: false,
|
|
34
|
+
INITIAL: false,
|
|
35
|
+
PENDING_APPROVAL: false
|
|
42
36
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
const isEndState = (state) => IS_REQUEST_STATE_END_STATE[state];
|
|
38
|
+
const DEFAULT_POLL_INTERVAL_MS = 250;
|
|
39
|
+
const DEFAULT_TIMEOUT_MS = 6e4;
|
|
40
|
+
const wait = (ms) => {
|
|
41
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
48
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Poll a request until its inflight field is false, indicating it has been processed by the system.
|
|
45
|
+
* Returns the updated request once inflight is false.
|
|
46
|
+
* Throws if the timeout is exceeded before inflight becomes false.
|
|
47
|
+
*/
|
|
49
48
|
async function waitForRequestInflightDone(client, request, logger, options) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return updated;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
throw new Error(
|
|
67
|
-
`Timed out waiting for request ${request.id} inflight to be processed (last inflight: ${JSON.stringify(
|
|
68
|
-
updated.inflight
|
|
69
|
-
)})`
|
|
70
|
-
);
|
|
49
|
+
const { logSubStep } = createBakeLogHelpers(logger);
|
|
50
|
+
if (request.inflight === void 0) return request;
|
|
51
|
+
logSubStep(`Waiting for inflight request to be processed...`);
|
|
52
|
+
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
53
|
+
const deadline = Date.now() + timeoutMs;
|
|
54
|
+
const pollIntervalMs = options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
55
|
+
let updated = request;
|
|
56
|
+
while (Date.now() < deadline) {
|
|
57
|
+
await wait(pollIntervalMs);
|
|
58
|
+
updated = await client.requests.findById.query({ id: request.id });
|
|
59
|
+
if (updated.inflight === void 0) return updated;
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`Timed out waiting for request ${request.id} inflight to be processed (last inflight: ${JSON.stringify(updated.inflight)})`);
|
|
71
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Poll a request until it reaches a terminal state (EXECUTED, FAILED, etc.).
|
|
65
|
+
*
|
|
66
|
+
* Returns the request once it is no longer in EXECUTING/STUCK state.
|
|
67
|
+
* Throws if the request reaches FAILED or STUCK state, or if the timeout is exceeded.
|
|
68
|
+
*/
|
|
72
69
|
async function waitForRequestExecuted(client, request, logger, options) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
throw new Error(`Request is in error state ${updated.state}`);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
throw new Error(
|
|
96
|
-
`Timed out waiting for request ${request.id} to reach a terminal state (last state: ${updated.state})`
|
|
97
|
-
);
|
|
70
|
+
const { logSubStep } = createBakeLogHelpers(logger);
|
|
71
|
+
if (isEndState(request.state)) {
|
|
72
|
+
if (request.state === "EXECUTED") return request;
|
|
73
|
+
throw new Error(`Request is in error state ${request.state}`);
|
|
74
|
+
}
|
|
75
|
+
const pollIntervalMs = options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
76
|
+
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
77
|
+
const deadline = Date.now() + timeoutMs;
|
|
78
|
+
logSubStep(`Waiting for request to be executed...`);
|
|
79
|
+
let updated = request;
|
|
80
|
+
while (Date.now() < deadline) {
|
|
81
|
+
await wait(pollIntervalMs);
|
|
82
|
+
updated = await client.requests.findById.query({ id: request.id });
|
|
83
|
+
if (isEndState(updated.state)) {
|
|
84
|
+
if (updated.state === "EXECUTED") return updated;
|
|
85
|
+
throw new Error(`Request is in error state ${updated.state}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
throw new Error(`Timed out waiting for request ${request.id} to reach a terminal state (last state: ${updated.state})`);
|
|
98
89
|
}
|
|
99
90
|
async function approveRequest(request, approvers, logger) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
91
|
+
const { logSubStep } = createBakeLogHelpers(logger);
|
|
92
|
+
for (let i = 0; i < approvers.length; i++) {
|
|
93
|
+
logSubStep(`Collecting approval (${i + 1}/${approvers.length})...`);
|
|
94
|
+
const approver = approvers[i];
|
|
95
|
+
request = await approver.approve(request);
|
|
96
|
+
request = await waitForRequestInflightDone(approver.client, request, logger);
|
|
97
|
+
}
|
|
98
|
+
return waitForRequestExecuted(approvers[0].client, request, logger);
|
|
108
99
|
}
|
|
109
100
|
async function createAndApproveRequest(input, approvers, logger) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return approveRequest(request, approvers, logger);
|
|
101
|
+
const { logSubStep } = createBakeLogHelpers(logger);
|
|
102
|
+
const creator = approvers[0];
|
|
103
|
+
(0, invariant.default)(creator, "Need at least 1 user to create a request");
|
|
104
|
+
logSubStep(`Creating request of type ${input.type}...`);
|
|
105
|
+
return approveRequest(await creator.client.requests.create.mutate({ request: input }), approvers, logger);
|
|
116
106
|
}
|
|
117
107
|
function stripUndefinedDeep(obj) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (obj && typeof obj === "object") {
|
|
122
|
-
return Object.fromEntries(
|
|
123
|
-
Object.entries(obj).filter(([_2, v]) => v !== void 0).map(([k, v]) => [k, stripUndefinedDeep(v)])
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
return obj;
|
|
108
|
+
if (Array.isArray(obj)) return obj.map(stripUndefinedDeep);
|
|
109
|
+
if (obj && typeof obj === "object") return Object.fromEntries(Object.entries(obj).filter(([_, v]) => v !== void 0).map(([k, v]) => [k, stripUndefinedDeep(v)]));
|
|
110
|
+
return obj;
|
|
127
111
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region src/bake/bake-pledge.ts
|
|
114
|
+
const flattenApprovers = (groups) => {
|
|
115
|
+
return groups.reduce((acc, cur) => {
|
|
116
|
+
acc.push(...cur.userIds.slice(0, cur.quorum));
|
|
117
|
+
return acc;
|
|
118
|
+
}, []);
|
|
135
119
|
};
|
|
136
120
|
async function bakePledgeAdjustment(options, logger) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
];
|
|
174
|
-
const approvers = await Promise.all(
|
|
175
|
-
approverIds.map(
|
|
176
|
-
(id) => admin.client.users.findById.query({ id }).then((user) => getDeviceIndex(user.deviceUserId)).then((index) => engine.withDeviceIndex(index).login())
|
|
177
|
-
)
|
|
178
|
-
);
|
|
179
|
-
await createAndApproveRequest(
|
|
180
|
-
{
|
|
181
|
-
type: "TRADELINK_ADJUST_PLEDGE",
|
|
182
|
-
data: {
|
|
183
|
-
accountId: account.id,
|
|
184
|
-
exchangeId: exchange.id,
|
|
185
|
-
amount: pledgeAdjustment.amount
|
|
186
|
-
}
|
|
187
|
-
},
|
|
188
|
-
approvers,
|
|
189
|
-
logger
|
|
190
|
-
);
|
|
191
|
-
logger.info(
|
|
192
|
-
`Successfully adjusted pledge for account ${pledgeAdjustment.account} on exchange ${pledgeAdjustment.exchange}`
|
|
193
|
-
);
|
|
121
|
+
const { pledgeAdjustment, engine } = options;
|
|
122
|
+
const getDeviceIndex = require_utils.createDeviceIndexResolver(engine);
|
|
123
|
+
logger.info("Logging in with admin...");
|
|
124
|
+
const admin = await engine.withDeviceIndex(4).login();
|
|
125
|
+
logger.info("Fetching account, tradelink blueprint and network...");
|
|
126
|
+
const [matchingAccounts, blueprint, network] = await Promise.all([
|
|
127
|
+
require_utils.fetchAll(admin.client.accounts.list.query, { name: pledgeAdjustment.account }),
|
|
128
|
+
admin.client.tradelink.getNetworkBlueprint.query(),
|
|
129
|
+
admin.client.tradelink.getNetwork.query()
|
|
130
|
+
]);
|
|
131
|
+
const account = matchingAccounts.find((account) => account.name === pledgeAdjustment.account);
|
|
132
|
+
(0, invariant.default)(account, `Account ${pledgeAdjustment.account} not found`);
|
|
133
|
+
(0, invariant.default)(blueprint, "Tradelink blueprint is not created yet");
|
|
134
|
+
(0, invariant.default)(network, "Tradelink network is not created yet");
|
|
135
|
+
const exchange = network.exchanges.find((exchange) => {
|
|
136
|
+
const blueprintExchange = blueprint.exchanges.find((blueprintExchange) => blueprintExchange.tradelinkId === exchange.tradelinkId);
|
|
137
|
+
(0, invariant.default)(blueprintExchange, `Exchange ${exchange.tradelinkId} not found in blueprint`);
|
|
138
|
+
return blueprintExchange.name === pledgeAdjustment.exchange;
|
|
139
|
+
});
|
|
140
|
+
(0, invariant.default)(exchange, `Exchange ${pledgeAdjustment.exchange} not found in network`);
|
|
141
|
+
const governance = account.governance;
|
|
142
|
+
(0, invariant.default)(governance.type === "TRADELINK", "Account governance is not TRADELINK");
|
|
143
|
+
const assetManager = network.assetManagers.find((am) => am.id === governance.assetManagerId);
|
|
144
|
+
(0, invariant.default)(assetManager, `Asset manager ${governance.assetManagerId} not found in network`);
|
|
145
|
+
(0, invariant.default)(!!governance.exchangeConfigs.find((e) => e.exchangeId === exchange.id), `Exchange ${exchange.id} is not configured for account ${account.id}`);
|
|
146
|
+
const approverIds = [...flattenApprovers(assetManager.groups), ...flattenApprovers(exchange.groups)];
|
|
147
|
+
const approvers = await Promise.all(approverIds.map((id) => admin.client.users.findById.query({ id }).then((user) => getDeviceIndex(user.deviceUserId)).then((index) => engine.withDeviceIndex(index).login())));
|
|
148
|
+
await createAndApproveRequest({
|
|
149
|
+
type: "TRADELINK_ADJUST_PLEDGE",
|
|
150
|
+
data: {
|
|
151
|
+
accountId: account.id,
|
|
152
|
+
exchangeId: exchange.id,
|
|
153
|
+
amount: pledgeAdjustment.amount
|
|
154
|
+
}
|
|
155
|
+
}, approvers, logger);
|
|
156
|
+
logger.info(`Successfully adjusted pledge for account ${pledgeAdjustment.account} on exchange ${pledgeAdjustment.exchange}`);
|
|
194
157
|
}
|
|
195
|
-
|
|
196
|
-
|
|
158
|
+
//#endregion
|
|
159
|
+
//#region src/bake/bake-tradelink-organization.ts
|
|
197
160
|
async function bakeTradelinkOrganization(options, logger) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
if (existingBlueprint) {
|
|
268
|
-
logger.info(`[SKIPPED] Network blueprint for ${workspaceName} workspace already exists`);
|
|
269
|
-
} else {
|
|
270
|
-
await rootClient.tradelink.root.createNetworkBlueprint.mutate({
|
|
271
|
-
workspaceName,
|
|
272
|
-
custodian: { name: blueprint.custodian },
|
|
273
|
-
exchanges: blueprint.exchanges.map((_2) => ({ name: _2 })),
|
|
274
|
-
assetManagers: blueprint.assetManagers.map((_2) => ({ name: _2 }))
|
|
275
|
-
});
|
|
276
|
-
logger.info(`Created network blueprint for ${networkBlueprint.workspaceName} workspace`);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
161
|
+
const { tradelink, engine, rootAuthToken, networkBlueprint } = options;
|
|
162
|
+
const { logStep } = createBakeLogHelpers(logger);
|
|
163
|
+
const rootClient = engine.createClient({ rootAuthToken });
|
|
164
|
+
/* v8 ignore else - TODO bake empty tradelink org -- @preserve */
|
|
165
|
+
if (tradelink.exchanges) {
|
|
166
|
+
logStep("Creating Tradelink organization exchanges...");
|
|
167
|
+
const existingOrgExchanges = await rootClient.tradelink.root.listOrgExchanges.query();
|
|
168
|
+
for (const orgExchange of tradelink.exchanges) {
|
|
169
|
+
const existingOrgExchange = existingOrgExchanges.find((e) => e.name === orgExchange.name);
|
|
170
|
+
if (existingOrgExchange) logger.info(`[SKIPPED] Organization exchange ${existingOrgExchange.name} (${existingOrgExchange.code}) already exists`);
|
|
171
|
+
else {
|
|
172
|
+
await rootClient.tradelink.root.createOrgExchange.mutate({
|
|
173
|
+
code: orgExchange.code,
|
|
174
|
+
name: orgExchange.name,
|
|
175
|
+
logoUrl: orgExchange.logo
|
|
176
|
+
});
|
|
177
|
+
logger.info(`Created organization exchange ${orgExchange.name} (${orgExchange.code})`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/* v8 ignore else -- @preserve */
|
|
182
|
+
if (tradelink.assetManagers) {
|
|
183
|
+
logStep("Creating Tradelink organization asset managers...");
|
|
184
|
+
const existingAssetManagers = await rootClient.tradelink.root.listOrgAssetManagers.query();
|
|
185
|
+
for (const orgAssetManager of tradelink.assetManagers) {
|
|
186
|
+
const existingOrgAssetManager = existingAssetManagers.find((e) => e.name === orgAssetManager.name);
|
|
187
|
+
if (existingOrgAssetManager) logger.info(`[SKIPPED] Organization asset manager ${existingOrgAssetManager.name} (${existingOrgAssetManager.code}) already exists`);
|
|
188
|
+
else {
|
|
189
|
+
await rootClient.tradelink.root.createOrgAssetManager.mutate({
|
|
190
|
+
code: orgAssetManager.code,
|
|
191
|
+
name: orgAssetManager.name,
|
|
192
|
+
logoUrl: orgAssetManager.logo
|
|
193
|
+
});
|
|
194
|
+
logger.info(`Created organization asset manager ${orgAssetManager.name} (${orgAssetManager.code})`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/* v8 ignore else -- @preserve */
|
|
199
|
+
if (tradelink.custodians) {
|
|
200
|
+
logStep("Creating Tradelink organization custodians...");
|
|
201
|
+
const existingCustodians = await rootClient.tradelink.root.listOrgCustodians.query();
|
|
202
|
+
for (const orgCustodian of tradelink.custodians) {
|
|
203
|
+
const existingOrgCustodian = existingCustodians.find((e) => e.name === orgCustodian.name);
|
|
204
|
+
if (existingOrgCustodian) logger.info(`[SKIPPED] Organization custodian ${existingOrgCustodian.name} (${existingOrgCustodian.code}) already exists`);
|
|
205
|
+
else {
|
|
206
|
+
await rootClient.tradelink.root.createOrgCustodian.mutate({
|
|
207
|
+
code: orgCustodian.code,
|
|
208
|
+
name: orgCustodian.name,
|
|
209
|
+
logoUrl: orgCustodian.logo
|
|
210
|
+
});
|
|
211
|
+
logger.info(`Created organization custodian ${orgCustodian.name} (${orgCustodian.code})`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/* v8 ignore else -- @preserve */
|
|
216
|
+
if (networkBlueprint) {
|
|
217
|
+
logStep("Creating Tradelink network blueprint...");
|
|
218
|
+
const { workspaceName, blueprint } = networkBlueprint;
|
|
219
|
+
if ((await rootClient.tradelink.root.listNetworkBlueprints.query()).find((e) => e.workspaceName === workspaceName)) logger.info(`[SKIPPED] Network blueprint for ${workspaceName} workspace already exists`);
|
|
220
|
+
else {
|
|
221
|
+
await rootClient.tradelink.root.createNetworkBlueprint.mutate({
|
|
222
|
+
workspaceName,
|
|
223
|
+
custodian: { name: blueprint.custodian },
|
|
224
|
+
exchanges: blueprint.exchanges.map((_) => ({ name: _ })),
|
|
225
|
+
assetManagers: blueprint.assetManagers.map((_) => ({ name: _ }))
|
|
226
|
+
});
|
|
227
|
+
logger.info(`Created network blueprint for ${networkBlueprint.workspaceName} workspace`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
279
230
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash);
|
|
284
|
-
var _tspattern = require('ts-pattern');
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/bake/bake-workspace.ts
|
|
285
233
|
async function bakeWorkspace(options, logger) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
234
|
+
const { workspace, engine, workspaceName } = options;
|
|
235
|
+
const workspaceEngine = engine.withWorkspace(workspaceName);
|
|
236
|
+
const { logTitle, logStep, logSubStep } = createBakeLogHelpers(logger);
|
|
237
|
+
const findDeviceIndex = require_utils.createDeviceIndexResolver(workspaceEngine);
|
|
238
|
+
logger.info("Authenticating with two admins...");
|
|
239
|
+
const [admin1, admin2] = await Promise.all([workspaceEngine.withDeviceIndex(4).login(), workspaceEngine.withDeviceIndex(5).login()]);
|
|
240
|
+
logger.info("Fetching existing data...");
|
|
241
|
+
const [existingUsers, existingGroups, existingWhitelists, existingPolicies, existingAccounts, existingEntities, tradelinkNetworkBlueprint] = await Promise.all([
|
|
242
|
+
require_utils.fetchAll(admin1.client.users.list.query, { status: "ACTIVE" }),
|
|
243
|
+
require_utils.fetchAll(admin1.client.groups.list.query, { status: "ACTIVE" }),
|
|
244
|
+
require_utils.fetchAll(admin1.client.whitelists.list.query, { status: "ACTIVE" }),
|
|
245
|
+
require_utils.fetchAll(admin1.client.policies.list.query, { isPrivate: false }),
|
|
246
|
+
require_utils.fetchAll(admin1.client.accounts.list.query, { status: "ACTIVE" }),
|
|
247
|
+
require_utils.fetchAll(admin1.client.entities.list.query, { status: "ACTIVE" }),
|
|
248
|
+
admin1.client.tradelink.getNetworkBlueprint.query()
|
|
249
|
+
]);
|
|
250
|
+
const tradelinkOrgExchangesByName = lodash.default.keyBy(tradelinkNetworkBlueprint?.exchanges, "name");
|
|
251
|
+
const tradelinkOrgAssetManagersByName = lodash.default.keyBy(tradelinkNetworkBlueprint?.assetManagers, "name");
|
|
252
|
+
let existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();
|
|
253
|
+
const existingPsdUsers = existingUsers.filter((user) => user.deviceType === "PSD");
|
|
254
|
+
const existingApiUsers = existingUsers.filter((user) => user.deviceType === "API");
|
|
255
|
+
const usersWithDeviceIndex = await resolveDevicesIndexes(existingPsdUsers);
|
|
256
|
+
if (workspace.users) {
|
|
257
|
+
logTitle("Users");
|
|
258
|
+
if (workspace.users.admins) for (const deviceIndex of workspace.users.admins) await createUser("ADMIN", deviceIndex);
|
|
259
|
+
/* v8 ignore else -- @preserve */
|
|
260
|
+
if (workspace.users.operators) for (const deviceIndex of workspace.users.operators) await createUser("OPERATOR", deviceIndex);
|
|
261
|
+
if (workspace.users.api) for (const apiUser of workspace.users.api) await createApiUser(apiUser);
|
|
262
|
+
}
|
|
263
|
+
if (workspace.workspaceRules) {
|
|
264
|
+
logTitle("Workspace Rules");
|
|
265
|
+
for (const workspaceRule of workspace.workspaceRules) await createWorkspaceRule(workspaceRule);
|
|
266
|
+
}
|
|
267
|
+
if (workspace.groups) {
|
|
268
|
+
logTitle("Groups");
|
|
269
|
+
for (const group of workspace.groups) await createGroup(group);
|
|
270
|
+
}
|
|
271
|
+
if (workspace.whitelists) {
|
|
272
|
+
logTitle("Whitelists");
|
|
273
|
+
await createWhitelists(workspace.whitelists);
|
|
274
|
+
}
|
|
275
|
+
if (workspace.policies) {
|
|
276
|
+
logTitle("Policies");
|
|
277
|
+
for (const policy of workspace.policies) await createPolicy(policy);
|
|
278
|
+
}
|
|
279
|
+
if (workspace.tradelink) {
|
|
280
|
+
logTitle("Tradelink");
|
|
281
|
+
await createTradelink(workspace.tradelink);
|
|
282
|
+
}
|
|
283
|
+
if (workspace.accounts) {
|
|
284
|
+
logTitle("Accounts");
|
|
285
|
+
for (const account of workspace.accounts) await createAccount(account, workspace);
|
|
286
|
+
}
|
|
287
|
+
if (workspace.entities) {
|
|
288
|
+
logTitle("Entities");
|
|
289
|
+
for (const entity of workspace.entities) await createEntity(entity);
|
|
290
|
+
}
|
|
291
|
+
async function editDomainObjectIfNeeded(params) {
|
|
292
|
+
const previousRequests = await admin1.client.requests.list.query({
|
|
293
|
+
type: params.requestTypes,
|
|
294
|
+
targetId: params.existingId,
|
|
295
|
+
state: "EXECUTED",
|
|
296
|
+
sortBy: "createdAt",
|
|
297
|
+
sortOrder: "desc",
|
|
298
|
+
pageSize: 1
|
|
299
|
+
});
|
|
300
|
+
if (previousRequests?.results && previousRequests.results.length > 0) {
|
|
301
|
+
const stateRequest = previousRequests.results[0];
|
|
302
|
+
(0, invariant.default)(stateRequest && params.requestTypes.includes(stateRequest.type), `State request should be a ${params.requestTypes[0]} or ${params.requestTypes[1]} request`);
|
|
303
|
+
const lastData = params.extractLastData(stateRequest.data);
|
|
304
|
+
if (lodash.default.isEqual(stripUndefinedDeep(params.editData), stripUndefinedDeep(lastData))) {
|
|
305
|
+
logger.info(`[SKIPPED] ${params.entityType} "${params.entityName}" has not changed`);
|
|
306
|
+
return "skipped";
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
logStep(`Editing ${params.entityType.toLowerCase()} "${params.entityName}"...`);
|
|
310
|
+
await createAndApproveRequest(params.editInput, [admin1, admin2], logger);
|
|
311
|
+
logger.info(`[EDITED] ${params.entityType} "${params.entityName}" has been edited`);
|
|
312
|
+
return "edited";
|
|
313
|
+
}
|
|
314
|
+
async function createWhitelists(whitelists) {
|
|
315
|
+
for (const whitelist of whitelists) await createWhitelist(whitelist);
|
|
316
|
+
async function createWhitelist(whitelist) {
|
|
317
|
+
const existing = existingWhitelists.find((w) => w.name === whitelist.name);
|
|
318
|
+
const normalizeAddresses = (addresses) => addresses.map(({ destinationTags, ...rest }) => ({
|
|
319
|
+
...rest,
|
|
320
|
+
...destinationTags?.length ? { destinationTags } : {}
|
|
321
|
+
}));
|
|
322
|
+
const whitelistEditData = {
|
|
323
|
+
name: whitelist.name,
|
|
324
|
+
addresses: normalizeAddresses(whitelist.addresses)
|
|
325
|
+
};
|
|
326
|
+
if (existing) {
|
|
327
|
+
await editDomainObjectIfNeeded({
|
|
328
|
+
entityType: "Whitelist",
|
|
329
|
+
entityName: whitelist.name,
|
|
330
|
+
existingId: existing.id,
|
|
331
|
+
editInput: {
|
|
332
|
+
type: "EDIT_WHITELIST",
|
|
333
|
+
targetId: existing.id,
|
|
334
|
+
data: {
|
|
335
|
+
name: whitelist.name,
|
|
336
|
+
addresses: whitelist.addresses
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
editData: whitelistEditData,
|
|
340
|
+
requestTypes: ["CREATE_WHITELIST", "EDIT_WHITELIST"],
|
|
341
|
+
extractLastData: (data) => ({
|
|
342
|
+
name: data.name,
|
|
343
|
+
addresses: normalizeAddresses(data.addresses)
|
|
344
|
+
})
|
|
345
|
+
});
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const req = await createAndApproveRequest({
|
|
349
|
+
type: "CREATE_WHITELIST",
|
|
350
|
+
data: {
|
|
351
|
+
...whitelist,
|
|
352
|
+
description: whitelist.description ?? null
|
|
353
|
+
}
|
|
354
|
+
}, [admin1, admin2], logger);
|
|
355
|
+
logSubStep(`Whitelist "${whitelist.name}" has been created`);
|
|
356
|
+
const createdWhitelist = await admin1.client.whitelists.findById.query({ id: req.targetId });
|
|
357
|
+
existingWhitelists.push(createdWhitelist);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function govRuleFromManifest(rule) {
|
|
361
|
+
return {
|
|
362
|
+
operationType: rule.type,
|
|
363
|
+
reviewSteps: rule.steps.map((step) => {
|
|
364
|
+
if ("group" in step) return {
|
|
365
|
+
quorum: step.quorum,
|
|
366
|
+
groupId: groupIdFromName(step.group)
|
|
367
|
+
};
|
|
368
|
+
return {
|
|
369
|
+
quorum: step.quorum,
|
|
370
|
+
userIds: step.members.map(userIdFromDeviceIndexOrName)
|
|
371
|
+
};
|
|
372
|
+
}),
|
|
373
|
+
threshold: rule.threshold,
|
|
374
|
+
whitelistIds: rule.whitelistNames?.map(whitelistIdFromName)
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
function rawSigningRuleFromManifest(rule) {
|
|
378
|
+
return {
|
|
379
|
+
operationType: rule.type,
|
|
380
|
+
reviewSteps: rule.steps.map((step) => ({
|
|
381
|
+
quorum: step.quorum,
|
|
382
|
+
userIds: step.members.map(userIdFromDeviceIndexOrName)
|
|
383
|
+
}))
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
async function createAccount(account, workspace) {
|
|
387
|
+
const existing = existingAccounts.find((a) => a.currency === account.currency && a.index === account.index && (a.contractAddress ?? null) === (account.contractAddress ?? null));
|
|
388
|
+
const governance = (0, ts_pattern.match)(account.governance).with({ type: "TRADELINK" }, (gov) => ({
|
|
389
|
+
type: "TRADELINK",
|
|
390
|
+
assetManagerId: assetManagerIdFromName(gov.assetManager),
|
|
391
|
+
exchangeConfigs: gov.exchanges.map((exchangeConfig) => ({
|
|
392
|
+
exchangeId: exchangeIdFromName(exchangeConfig.name),
|
|
393
|
+
repledgeAuthorized: exchangeConfig.repledgeAuthorized === true,
|
|
394
|
+
needsAssetManagerApprovalForSettlements: exchangeConfig.needsAssetManagerApprovalForSettlements === true
|
|
395
|
+
}))
|
|
396
|
+
})).with({ type: "RAW_SIGNING" }, (gov) => ({
|
|
397
|
+
type: "RAW_SIGNING",
|
|
398
|
+
policy: { rules: gov.rules.map(rawSigningRuleFromManifest) }
|
|
399
|
+
})).with({ type: "CLASSIC" }, (gov) => ({
|
|
400
|
+
type: "CLASSIC",
|
|
401
|
+
policy: { rules: gov.rules.map(govRuleFromManifest) }
|
|
402
|
+
})).with({ type: "POLICY" }, (gov) => ({
|
|
403
|
+
type: "CLASSIC",
|
|
404
|
+
policy: { policyId: policyIdFromName(gov.policy) }
|
|
405
|
+
})).exhaustive();
|
|
406
|
+
const accountData = {
|
|
407
|
+
name: account.name,
|
|
408
|
+
currency: account.currency,
|
|
409
|
+
contractAddress: account.contractAddress ?? null,
|
|
410
|
+
tokenIdentifier: account.tokenIdentifier ?? null,
|
|
411
|
+
index: account.index,
|
|
412
|
+
governance
|
|
413
|
+
};
|
|
414
|
+
if (existing) {
|
|
415
|
+
const editData = {
|
|
416
|
+
name: accountData.name,
|
|
417
|
+
governance
|
|
418
|
+
};
|
|
419
|
+
if (await editDomainObjectIfNeeded({
|
|
420
|
+
entityType: "Account",
|
|
421
|
+
entityName: account.name,
|
|
422
|
+
existingId: existing.id,
|
|
423
|
+
editInput: {
|
|
424
|
+
type: "EDIT_ACCOUNT",
|
|
425
|
+
targetId: existing.id,
|
|
426
|
+
data: editData
|
|
427
|
+
},
|
|
428
|
+
editData,
|
|
429
|
+
requestTypes: ["CREATE_ACCOUNT", "EDIT_ACCOUNT"],
|
|
430
|
+
extractLastData: (data) => ({
|
|
431
|
+
name: data.name,
|
|
432
|
+
governance: data.governance
|
|
433
|
+
})
|
|
434
|
+
}) === "skipped") await activateHederaAccount(account, workspace, existing.id);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
logStep(`Creating account "${account.name}"`);
|
|
438
|
+
const req = await createAndApproveRequest({
|
|
439
|
+
type: "CREATE_ACCOUNT",
|
|
440
|
+
data: accountData
|
|
441
|
+
}, [admin1, admin2], logger);
|
|
442
|
+
const createdAccount = await admin1.client.accounts.findById.query({ id: req.targetId });
|
|
443
|
+
existingAccounts.push(createdAccount);
|
|
444
|
+
if (account.governance.type === "TRADELINK") {
|
|
445
|
+
logStep(`Activating tradelink account "${account.name}"`);
|
|
446
|
+
const assetManagerId = assetManagerIdFromName(account.governance.assetManager);
|
|
447
|
+
const assetManager = existingTradelinkNetwork?.assetManagers.find((assetManager) => assetManager.id === assetManagerId);
|
|
448
|
+
(0, invariant.default)(assetManager, `Asset manager for account exists`);
|
|
449
|
+
const loggedAssetManagerOperators = await Promise.all(assetManager.groups.flatMap(({ quorum, userIds }) => userIds.slice(0, quorum).map((userId) => {
|
|
450
|
+
const deviceIndex = usersWithDeviceIndex.find((o) => o.user.id === userId)?.deviceIndex;
|
|
451
|
+
return workspaceEngine.withDeviceIndex(deviceIndex).login();
|
|
452
|
+
})));
|
|
453
|
+
await createAndApproveRequest({
|
|
454
|
+
type: "TRADELINK_ACTIVATE_ACCOUNT",
|
|
455
|
+
targetId: req.targetId,
|
|
456
|
+
data: null
|
|
457
|
+
}, loggedAssetManagerOperators, logger);
|
|
458
|
+
}
|
|
459
|
+
if (req.targetId) await activateHederaAccount(account, workspace, req.targetId);
|
|
460
|
+
logSubStep(`Account ${account.name} has been created`);
|
|
461
|
+
}
|
|
462
|
+
async function activateHederaAccount(account, workspace, accountId) {
|
|
463
|
+
if (account.currency === "hedera" && account.contractAddress === void 0 && workspace.hederaData && accountId) {
|
|
464
|
+
const salt = engine.__options.salt;
|
|
465
|
+
const hederaAccountData = workspace.hederaData[salt]?.find((h) => h.index === account.index && h.activate);
|
|
466
|
+
if (hederaAccountData) try {
|
|
467
|
+
await admin1.client.accounts.hedera.activateAccount.mutate({
|
|
468
|
+
id: accountId,
|
|
469
|
+
onchainId: hederaAccountData.onChainId
|
|
470
|
+
});
|
|
471
|
+
logSubStep(`Hedera account "${account.name}" has been activated`);
|
|
472
|
+
} catch (error) {
|
|
473
|
+
logger.warning(`Activation for "${account.name}" failed: ${error}`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
async function createUser(role, deviceIndex) {
|
|
478
|
+
const userEngine = workspaceEngine.withDeviceIndex(deviceIndex);
|
|
479
|
+
const deviceId = await userEngine.device.getDeviceUserId();
|
|
480
|
+
if (existingUsers.find((user) => user.deviceUserId === deviceId)) {
|
|
481
|
+
logger.info(`[SKIPPED] User with device index ${deviceIndex} already exists`);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const name = `${role === "ADMIN" ? "Admin" : "Operator"} ${deviceIndex}`;
|
|
485
|
+
logStep(`Creating ${name}`);
|
|
486
|
+
logSubStep("Creating invitation...");
|
|
487
|
+
let registration = await admin1.client.userRegistrations.invite.mutate({
|
|
488
|
+
name,
|
|
489
|
+
role,
|
|
490
|
+
deviceUserId: deviceId,
|
|
491
|
+
psdModel: "STAX"
|
|
492
|
+
});
|
|
493
|
+
logSubStep("Completing registration...");
|
|
494
|
+
registration = await userEngine.register(registration);
|
|
495
|
+
logSubStep("Creating request...");
|
|
496
|
+
let req = await admin1.client.requests.create.mutate({ request: {
|
|
497
|
+
type: "CREATE_PSD_USER",
|
|
498
|
+
data: { registrationId: registration.id }
|
|
499
|
+
} });
|
|
500
|
+
req = await approveRequest(req, [admin1, admin2], logger);
|
|
501
|
+
logSubStep(`${name} has been created`);
|
|
502
|
+
const createdUser = await admin1.client.users.findById.query({ id: req.targetId });
|
|
503
|
+
existingUsers.push(createdUser);
|
|
504
|
+
usersWithDeviceIndex.push({
|
|
505
|
+
user: createdUser,
|
|
506
|
+
deviceIndex
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
async function createApiUser(apiUser) {
|
|
510
|
+
const pubKey = apiUser.pubKey ?? require_crypto.genKeys(apiUser.name).hexPubKey;
|
|
511
|
+
if (existingApiUsers.find((user) => user.pubKey === pubKey || user.name === apiUser.name)) {
|
|
512
|
+
logger.info(`[SKIPPED] API user already exists with name "${apiUser.name}" or public key "${pubKey}"`);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
logStep(`Creating API user "${apiUser.name}"...`);
|
|
516
|
+
logSubStep("Creating request...");
|
|
517
|
+
let req = await admin1.client.requests.create.mutate({ request: {
|
|
518
|
+
type: "CREATE_API_USER",
|
|
519
|
+
data: {
|
|
520
|
+
name: apiUser.name,
|
|
521
|
+
role: apiUser.role,
|
|
522
|
+
pubKey,
|
|
523
|
+
viewAll: apiUser.viewAll
|
|
524
|
+
}
|
|
525
|
+
} });
|
|
526
|
+
req = await approveRequest(req, [admin1, admin2], logger);
|
|
527
|
+
logSubStep(`API user "${apiUser.name}" has been created`);
|
|
528
|
+
logSubStep("Generating credentials...");
|
|
529
|
+
const credentials = await admin1.client.users.resetApiUserCredentials.mutate({ id: req.targetId });
|
|
530
|
+
logSubStep(`API user "${apiUser.name}" credentials have been generated: apiKeyId=${credentials.apiKeyId}, apiKeySecret=${credentials.apiKeySecret}`);
|
|
531
|
+
const createdUser = await admin1.client.users.findById.query({ id: req.targetId });
|
|
532
|
+
existingApiUsers.push(createdUser);
|
|
533
|
+
}
|
|
534
|
+
async function createGroup(group) {
|
|
535
|
+
const existing = existingGroups.find((g) => g.name === group.name);
|
|
536
|
+
const members = group.members.map(userIdFromDeviceIndexOrName);
|
|
537
|
+
const groupData = {
|
|
538
|
+
name: group.name,
|
|
539
|
+
description: "",
|
|
540
|
+
members
|
|
541
|
+
};
|
|
542
|
+
if (existing) {
|
|
543
|
+
await editDomainObjectIfNeeded({
|
|
544
|
+
entityType: "Group",
|
|
545
|
+
entityName: group.name,
|
|
546
|
+
existingId: existing.id,
|
|
547
|
+
editInput: {
|
|
548
|
+
type: "EDIT_GROUP",
|
|
549
|
+
targetId: existing.id,
|
|
550
|
+
data: groupData
|
|
551
|
+
},
|
|
552
|
+
editData: groupData,
|
|
553
|
+
requestTypes: ["CREATE_GROUP", "EDIT_GROUP"],
|
|
554
|
+
extractLastData: (data) => ({
|
|
555
|
+
...data,
|
|
556
|
+
description: data.description ?? ""
|
|
557
|
+
})
|
|
558
|
+
});
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
logStep(`Creating group ${group.name}...`);
|
|
562
|
+
logSubStep("Creating request...");
|
|
563
|
+
let request = await admin1.client.requests.create.mutate({ request: {
|
|
564
|
+
type: "CREATE_GROUP",
|
|
565
|
+
data: groupData
|
|
566
|
+
} });
|
|
567
|
+
request = await approveRequest(request, [admin1, admin2], logger);
|
|
568
|
+
logSubStep(`${group.name} has been created`);
|
|
569
|
+
const createdGroup = await admin1.client.groups.findById.query({ id: request.targetId });
|
|
570
|
+
existingGroups.push(createdGroup);
|
|
571
|
+
}
|
|
572
|
+
async function createPolicy(policy) {
|
|
573
|
+
const existing = existingPolicies.find((p) => p.name === policy.name);
|
|
574
|
+
const policyEditData = {
|
|
575
|
+
name: policy.name,
|
|
576
|
+
description: "",
|
|
577
|
+
govRules: policy.rules.map(govRuleFromManifest)
|
|
578
|
+
};
|
|
579
|
+
if (existing) {
|
|
580
|
+
await editDomainObjectIfNeeded({
|
|
581
|
+
entityType: "Policy",
|
|
582
|
+
entityName: policy.name,
|
|
583
|
+
existingId: existing.id,
|
|
584
|
+
editInput: {
|
|
585
|
+
type: "EDIT_POLICY",
|
|
586
|
+
targetId: existing.id,
|
|
587
|
+
data: policyEditData
|
|
588
|
+
},
|
|
589
|
+
editData: policyEditData,
|
|
590
|
+
requestTypes: ["CREATE_POLICY", "EDIT_POLICY"],
|
|
591
|
+
extractLastData: (data) => ({
|
|
592
|
+
name: data.name,
|
|
593
|
+
description: data.description ?? "",
|
|
594
|
+
govRules: data.govRules
|
|
595
|
+
})
|
|
596
|
+
});
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
logStep(`Creating policy ${policy.name}...`);
|
|
600
|
+
logSubStep("Creating request...");
|
|
601
|
+
let request = await admin1.client.requests.create.mutate({ request: {
|
|
602
|
+
type: "CREATE_POLICY",
|
|
603
|
+
data: {
|
|
604
|
+
...policyEditData,
|
|
605
|
+
currency: policy.currency
|
|
606
|
+
}
|
|
607
|
+
} });
|
|
608
|
+
request = await approveRequest(request, [admin1, admin2], logger);
|
|
609
|
+
logSubStep(`${policy.name} has been created`);
|
|
610
|
+
const createdPolicy = await admin1.client.policies.findById.query({ id: request.targetId });
|
|
611
|
+
existingPolicies.push(createdPolicy);
|
|
612
|
+
}
|
|
613
|
+
async function createWorkspaceRule(workspaceRule) {
|
|
614
|
+
const { permission, quorum, members } = workspaceRule;
|
|
615
|
+
logStep(`Editing workspace rule for ${permission}...`);
|
|
616
|
+
const userIds = members.map(userIdFromDeviceIndexOrName);
|
|
617
|
+
logSubStep("Creating request...");
|
|
618
|
+
await createAndApproveRequest({
|
|
619
|
+
type: "EDIT_WORKSPACE_RULE",
|
|
620
|
+
data: {
|
|
621
|
+
permission,
|
|
622
|
+
reviewConfig: [{
|
|
623
|
+
quorum,
|
|
624
|
+
userIds
|
|
625
|
+
}]
|
|
626
|
+
}
|
|
627
|
+
}, [admin1, admin2], logger);
|
|
628
|
+
logSubStep(`Workspace rule for "${permission}" has been edited`);
|
|
629
|
+
}
|
|
630
|
+
async function createEntity(entity) {
|
|
631
|
+
const existing = existingEntities.find((e) => e.name === entity.name);
|
|
632
|
+
const accountIds = (entity.accounts ?? []).map(accountIdFromName);
|
|
633
|
+
const memberIds = (entity.members ?? []).map(userIdFromUserName);
|
|
634
|
+
const entityEditData = {
|
|
635
|
+
name: entity.name,
|
|
636
|
+
accountIds,
|
|
637
|
+
memberIds
|
|
638
|
+
};
|
|
639
|
+
if (existing) {
|
|
640
|
+
await editDomainObjectIfNeeded({
|
|
641
|
+
entityType: "Entity",
|
|
642
|
+
entityName: entity.name,
|
|
643
|
+
existingId: existing.id,
|
|
644
|
+
editInput: {
|
|
645
|
+
type: "EDIT_ENTITY",
|
|
646
|
+
targetId: existing.id,
|
|
647
|
+
data: entityEditData
|
|
648
|
+
},
|
|
649
|
+
editData: entityEditData,
|
|
650
|
+
requestTypes: ["CREATE_ENTITY", "EDIT_ENTITY"],
|
|
651
|
+
extractLastData: (data) => ({
|
|
652
|
+
name: data.name,
|
|
653
|
+
accountIds: data.accountIds,
|
|
654
|
+
memberIds: data.memberIds
|
|
655
|
+
})
|
|
656
|
+
});
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
logStep(`Creating entity "${entity.name}"...`);
|
|
660
|
+
const request = await createAndApproveRequest({
|
|
661
|
+
type: "CREATE_ENTITY",
|
|
662
|
+
data: entityEditData
|
|
663
|
+
}, [admin1, admin2], logger);
|
|
664
|
+
logSubStep(`Entity "${entity.name}" has been created`);
|
|
665
|
+
const createdEntity = await admin1.client.entities.findById.query({ id: request.targetId });
|
|
666
|
+
existingEntities.push(createdEntity);
|
|
667
|
+
}
|
|
668
|
+
async function createTradelink(tradelink) {
|
|
669
|
+
/* v8 ignore else -- @preserve */
|
|
670
|
+
if (tradelink.custodian) {
|
|
671
|
+
if (existingTradelinkNetwork === null) {
|
|
672
|
+
logStep("Creating custodian config...");
|
|
673
|
+
const { settlement, withdraw, arbitration } = tradelink.custodian;
|
|
674
|
+
const data = {
|
|
675
|
+
settlement: settlement.map(tradelinkReviewStepFromManifest),
|
|
676
|
+
withdraw: withdraw.map(tradelinkReviewStepFromManifest),
|
|
677
|
+
arbitration: arbitration.map(tradelinkReviewStepFromManifest)
|
|
678
|
+
};
|
|
679
|
+
logSubStep("Creating request...");
|
|
680
|
+
await approveRequest(await admin1.client.requests.create.mutate({ request: {
|
|
681
|
+
type: "TRADELINK_CREATE_CUSTODIAN",
|
|
682
|
+
data
|
|
683
|
+
} }), [admin1, admin2], logger);
|
|
684
|
+
logSubStep("Tradelink custodian config has been created");
|
|
685
|
+
existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();
|
|
686
|
+
} else logger.info("[SKIPPED] Custodian config already exists");
|
|
687
|
+
const networkBlueprint = await admin1.client.tradelink.getNetworkBlueprint.query();
|
|
688
|
+
if (networkBlueprint !== null) {
|
|
689
|
+
/* v8 ignore else -- @preserve */
|
|
690
|
+
if (tradelink.exchanges !== void 0) await createTradelinkExchanges(networkBlueprint, tradelink.exchanges);
|
|
691
|
+
/* v8 ignore else -- @preserve */
|
|
692
|
+
if (tradelink.assetManagers !== void 0) await createTradelinkAssetManagers(networkBlueprint, tradelink.assetManagers);
|
|
693
|
+
} else logger.error("Will not create exchanges and asset managers because there is no network blueprint for current workspace");
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
async function createTradelinkExchanges(networkBlueprint, exchanges) {
|
|
697
|
+
(0, invariant.default)(existingTradelinkNetwork !== null, "Network should exist");
|
|
698
|
+
const blueprintExchanges = networkBlueprint.exchanges;
|
|
699
|
+
for (const exchange of exchanges) {
|
|
700
|
+
const blueprintExchange = blueprintExchanges.find(({ name }) => name === exchange.name);
|
|
701
|
+
(0, invariant.default)(blueprintExchange !== void 0, `Exchange ${exchange.name} does not exist in network blueprint`);
|
|
702
|
+
const exchangeId = blueprintExchange.tradelinkId;
|
|
703
|
+
logStep(`Creating exchange ${exchange.name}...`);
|
|
704
|
+
if (existingTradelinkNetwork.exchanges.find(({ tradelinkId }) => tradelinkId === exchangeId) !== void 0) {
|
|
705
|
+
logger.info(`[SKIPPED] Exchange "${exchange.name}" already exists`);
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
logSubStep("Creating request...");
|
|
709
|
+
await approveRequest(await admin1.client.requests.create.mutate({ request: {
|
|
710
|
+
type: "TRADELINK_CREATE_EXCHANGE",
|
|
711
|
+
data: {
|
|
712
|
+
tradelinkId: exchangeId,
|
|
713
|
+
groups: exchange.groups.map(tradelinkReviewStepFromManifest),
|
|
714
|
+
whitelist: exchange.whitelist
|
|
715
|
+
}
|
|
716
|
+
} }), [
|
|
717
|
+
admin1,
|
|
718
|
+
admin2,
|
|
719
|
+
...await Promise.all(exchange.groups.flatMap(({ quorum, members }) => members.slice(0, quorum).map((deviceIndex) => workspaceEngine.withDeviceIndex(deviceIndex).login())))
|
|
720
|
+
], logger);
|
|
721
|
+
existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();
|
|
722
|
+
(0, invariant.default)(existingTradelinkNetwork !== null, "Tradelink network exists");
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
async function createTradelinkAssetManagers(networkBlueprint, assetManagers) {
|
|
726
|
+
(0, invariant.default)(existingTradelinkNetwork !== null, "Network should exist");
|
|
727
|
+
const blueprintAssetManagers = networkBlueprint.assetManagers;
|
|
728
|
+
for (const assetManager of assetManagers) {
|
|
729
|
+
const blueprintAssetManager = blueprintAssetManagers.find(({ name }) => name === assetManager.name);
|
|
730
|
+
(0, invariant.default)(blueprintAssetManager !== void 0, `AssetManager ${assetManager.name} does not exist in network blueprint`);
|
|
731
|
+
const assetManagerId = blueprintAssetManager.tradelinkId;
|
|
732
|
+
logStep(`Creating assetManager ${assetManager.name}...`);
|
|
733
|
+
if (existingTradelinkNetwork.assetManagers.find(({ tradelinkId }) => tradelinkId === assetManagerId) !== void 0) {
|
|
734
|
+
logger.info(`[SKIPPED] Asset manager "${assetManager.name}" already exists`);
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
logSubStep("Creating request...");
|
|
738
|
+
await approveRequest(await admin1.client.requests.create.mutate({ request: {
|
|
739
|
+
type: "TRADELINK_CREATE_ASSET_MANAGER",
|
|
740
|
+
data: {
|
|
741
|
+
tradelinkId: assetManagerId,
|
|
742
|
+
groups: assetManager.groups.map(tradelinkReviewStepFromManifest),
|
|
743
|
+
whitelist: assetManager.whitelist
|
|
744
|
+
}
|
|
745
|
+
} }), [
|
|
746
|
+
admin1,
|
|
747
|
+
admin2,
|
|
748
|
+
...await Promise.all(assetManager.groups.flatMap(({ quorum, members }) => members.slice(0, quorum).map((deviceIndex) => workspaceEngine.withDeviceIndex(deviceIndex).login())))
|
|
749
|
+
], logger);
|
|
750
|
+
existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();
|
|
751
|
+
(0, invariant.default)(existingTradelinkNetwork !== null, "Tradelink network exists");
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
async function resolveDevicesIndexes(users) {
|
|
755
|
+
return await users.reduce((acc, cur) => acc.then(async (acc) => {
|
|
756
|
+
acc.push(await withDeviceIndex(cur));
|
|
757
|
+
return acc;
|
|
758
|
+
}), Promise.resolve([]));
|
|
759
|
+
}
|
|
760
|
+
async function withDeviceIndex(user) {
|
|
761
|
+
(0, invariant.default)(user.deviceUserId, `User ${user.id} does not have any device user id`);
|
|
762
|
+
return {
|
|
763
|
+
user,
|
|
764
|
+
deviceIndex: await findDeviceIndex(user.deviceUserId)
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
function userIdFromDeviceIndex(deviceIndex) {
|
|
768
|
+
const corresponding = usersWithDeviceIndex.find((o) => o.deviceIndex === deviceIndex);
|
|
769
|
+
(0, invariant.default)(corresponding, `No user with device index ${deviceIndex}`);
|
|
770
|
+
return corresponding.user.id;
|
|
771
|
+
}
|
|
772
|
+
function userIdFromUserName(name) {
|
|
773
|
+
const user = existingApiUsers.find((u) => u.name === name);
|
|
774
|
+
(0, invariant.default)(user, `User ${name} not found`);
|
|
775
|
+
return user.id;
|
|
776
|
+
}
|
|
777
|
+
function userIdFromDeviceIndexOrName(identifier) {
|
|
778
|
+
if (typeof identifier === "number") return userIdFromDeviceIndex(identifier);
|
|
779
|
+
return userIdFromUserName(identifier);
|
|
780
|
+
}
|
|
781
|
+
function groupIdFromName(groupName) {
|
|
782
|
+
const group = existingGroups.find((g) => g.name === groupName);
|
|
783
|
+
(0, invariant.default)(group, `Group ${groupName} not found`);
|
|
784
|
+
return group.id;
|
|
785
|
+
}
|
|
786
|
+
function policyIdFromName(policyName) {
|
|
787
|
+
const policy = existingPolicies.find((g) => g.name === policyName);
|
|
788
|
+
(0, invariant.default)(policy, `Policy ${policyName} not found`);
|
|
789
|
+
return policy.id;
|
|
790
|
+
}
|
|
791
|
+
function whitelistIdFromName(whitelistName) {
|
|
792
|
+
const whitelist = existingWhitelists.find((w) => w.name === whitelistName);
|
|
793
|
+
(0, invariant.default)(whitelist, `Whitelist ${whitelistName} not found`);
|
|
794
|
+
return whitelist.id;
|
|
795
|
+
}
|
|
796
|
+
function accountIdFromName(accountName) {
|
|
797
|
+
const account = existingAccounts.find((a) => a.name === accountName);
|
|
798
|
+
(0, invariant.default)(account, `Account "${accountName}" not found`);
|
|
799
|
+
return account.id;
|
|
800
|
+
}
|
|
801
|
+
function assetManagerIdFromName(assetManagerName) {
|
|
802
|
+
const orgAssetManager = tradelinkOrgAssetManagersByName[assetManagerName];
|
|
803
|
+
(0, invariant.default)(orgAssetManager, `Can't find Tradelink organization asset manager ${assetManagerName}`);
|
|
804
|
+
const assetManager = existingTradelinkNetwork?.assetManagers.find((assetManager) => assetManager.tradelinkId === orgAssetManager.tradelinkId);
|
|
805
|
+
(0, invariant.default)(assetManager, `Can't find Tradelink assetManager ${assetManagerName}`);
|
|
806
|
+
return assetManager.id;
|
|
807
|
+
}
|
|
808
|
+
function exchangeIdFromName(exchangeName) {
|
|
809
|
+
const exchange = existingTradelinkNetwork?.exchanges.find((exchange) => {
|
|
810
|
+
const orgExchange = tradelinkOrgExchangesByName[exchangeName];
|
|
811
|
+
(0, invariant.default)(orgExchange, `Can't find Tradelink organization exchange ${exchange.tradelinkId}`);
|
|
812
|
+
return orgExchange.name === exchangeName;
|
|
813
|
+
});
|
|
814
|
+
(0, invariant.default)(exchange, `Can't find Tradelink exchange ${exchangeName}`);
|
|
815
|
+
return exchange.id;
|
|
816
|
+
}
|
|
817
|
+
function tradelinkReviewStepFromManifest({ members, quorum }) {
|
|
818
|
+
return {
|
|
819
|
+
userIds: members.map(userIdFromDeviceIndex),
|
|
820
|
+
quorum
|
|
821
|
+
};
|
|
822
|
+
}
|
|
855
823
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
824
|
+
//#endregion
|
|
825
|
+
//#region src/bake/recipe-workspace.ts
|
|
826
|
+
async function recipeWorkspace(options, logger) {
|
|
827
|
+
const { engine, workspaceName } = options;
|
|
828
|
+
const workspaceEngine = engine.withWorkspace(workspaceName);
|
|
829
|
+
const findDeviceIndex = require_utils.createDeviceIndexResolver(workspaceEngine);
|
|
830
|
+
logger.info("Authenticating with admin...");
|
|
831
|
+
const admin = await workspaceEngine.withDeviceIndex(4).login();
|
|
832
|
+
logger.info("Fetching existing data...");
|
|
833
|
+
const [existingUsers, existingGroups, existingWhitelists, publicPolicies, privatePolicies, existingAccounts, existingEntities, existingWorkspaceRules] = await Promise.all([
|
|
834
|
+
require_utils.fetchAll(admin.client.users.list.query, { status: "ACTIVE" }),
|
|
835
|
+
require_utils.fetchAll(admin.client.groups.list.query, { status: "ACTIVE" }),
|
|
836
|
+
require_utils.fetchAll(admin.client.whitelists.list.query, { status: "ACTIVE" }),
|
|
837
|
+
require_utils.fetchAll(admin.client.policies.list.query, { isPrivate: false }),
|
|
838
|
+
require_utils.fetchAll(admin.client.policies.list.query, { isPrivate: true }),
|
|
839
|
+
require_utils.fetchAll(admin.client.accounts.list.query, { status: "ACTIVE" }),
|
|
840
|
+
require_utils.fetchAll(admin.client.entities.list.query, { status: "ACTIVE" }),
|
|
841
|
+
admin.client.governance.listWorkspaceRules.query()
|
|
842
|
+
]);
|
|
843
|
+
const existingPolicies = [...publicPolicies, ...privatePolicies];
|
|
844
|
+
const existingPsdUsers = existingUsers.filter((user) => user.deviceType === "PSD");
|
|
845
|
+
const existingApiUsers = existingUsers.filter((user) => user.deviceType === "API");
|
|
846
|
+
logger.info("Resolving device indexes...");
|
|
847
|
+
const psdUsersWithIndex = await resolveDevicesIndexes(existingPsdUsers);
|
|
848
|
+
logger.info("Reading users...");
|
|
849
|
+
const adminIndexes = psdUsersWithIndex.filter((u) => u.user.role === "ADMIN").map((u) => u.deviceIndex);
|
|
850
|
+
const operatorIndexes = psdUsersWithIndex.filter((u) => u.user.role === "OPERATOR").map((u) => u.deviceIndex);
|
|
851
|
+
const apiUsers = existingApiUsers.map((user) => {
|
|
852
|
+
const role = (0, ts_pattern.match)(user.role).with("ADMIN", "OPERATOR", (role) => role).with("READ_ONLY_API_KEY", (role) => {
|
|
853
|
+
throw new Error(`Unexpected API user role "${role}" for user ${user.name}`);
|
|
854
|
+
}).exhaustive();
|
|
855
|
+
return {
|
|
856
|
+
name: user.name,
|
|
857
|
+
role,
|
|
858
|
+
pubKey: user.pubKey,
|
|
859
|
+
viewAll: user.legacyViewAll
|
|
860
|
+
};
|
|
861
|
+
});
|
|
862
|
+
logger.info("Reading groups...");
|
|
863
|
+
const groups = existingGroups.map((group) => ({
|
|
864
|
+
name: group.name,
|
|
865
|
+
members: group.members.map((member) => resolveUserIdentifier(member.id))
|
|
866
|
+
}));
|
|
867
|
+
logger.info("Reading whitelists...");
|
|
868
|
+
const whitelists = existingWhitelists.map((whitelist) => ({
|
|
869
|
+
name: whitelist.name,
|
|
870
|
+
description: whitelist.description ?? void 0,
|
|
871
|
+
type: "TRANSACTION",
|
|
872
|
+
addresses: whitelist.addresses.map((addr) => ({
|
|
873
|
+
name: addr.name,
|
|
874
|
+
currency: addr.currency,
|
|
875
|
+
address: addr.address,
|
|
876
|
+
...addr.destinationTags?.length ? { destinationTags: addr.destinationTags } : {}
|
|
877
|
+
}))
|
|
878
|
+
}));
|
|
879
|
+
logger.info("Reading policies...");
|
|
880
|
+
const policies = publicPolicies.map((policy) => ({
|
|
881
|
+
name: policy.name,
|
|
882
|
+
currency: policy.currency,
|
|
883
|
+
rules: policy.rules.map(govRuleToManifest)
|
|
884
|
+
}));
|
|
885
|
+
logger.info("Reading accounts...");
|
|
886
|
+
const accounts = existingAccounts.map((account) => {
|
|
887
|
+
const governance = (0, ts_pattern.match)(account.governance).with({ type: "CLASSIC" }, (gov) => {
|
|
888
|
+
const policy = existingPolicies.find((p) => p.id === gov.policyId);
|
|
889
|
+
(0, invariant.default)(policy, `Policy ${gov.policyId} not found for account ${account.name}`);
|
|
890
|
+
return policy.isPrivate ? {
|
|
891
|
+
type: "CLASSIC",
|
|
892
|
+
rules: policy.rules.map(govRuleToManifest)
|
|
893
|
+
} : {
|
|
894
|
+
type: "POLICY",
|
|
895
|
+
policy: policy.name
|
|
896
|
+
};
|
|
897
|
+
}).with({ type: "RAW_SIGNING" }, (gov) => {
|
|
898
|
+
const policy = existingPolicies.find((p) => p.id === gov.policyId);
|
|
899
|
+
(0, invariant.default)(policy, `Policy ${gov.policyId} not found for account ${account.name}`);
|
|
900
|
+
return {
|
|
901
|
+
type: "RAW_SIGNING",
|
|
902
|
+
rules: policy.rules.map((rule) => ({
|
|
903
|
+
type: "SIGN_DIGESTS",
|
|
904
|
+
steps: rule.reviewSteps.map((step) => {
|
|
905
|
+
(0, invariant.default)("userIds" in step, "RAW_SIGNING rules only support user steps");
|
|
906
|
+
return {
|
|
907
|
+
quorum: step.quorum,
|
|
908
|
+
members: step.userIds.map(resolveUserToDeviceIndexOrName)
|
|
909
|
+
};
|
|
910
|
+
})
|
|
911
|
+
}))
|
|
912
|
+
};
|
|
913
|
+
}).with({ type: "TRADELINK" }, (gov) => ({
|
|
914
|
+
type: "TRADELINK",
|
|
915
|
+
assetManager: resolveAssetManagerName(gov.assetManagerId),
|
|
916
|
+
exchanges: gov.exchangeConfigs.map((exchangeConfig) => ({
|
|
917
|
+
name: resolveExchangeName(exchangeConfig.exchangeId),
|
|
918
|
+
...exchangeConfig.repledgeAuthorized ? { repledgeAuthorized: true } : {},
|
|
919
|
+
...exchangeConfig.needsAssetManagerApprovalForSettlements ? { needsAssetManagerApprovalForSettlements: true } : {}
|
|
920
|
+
}))
|
|
921
|
+
})).exhaustive();
|
|
922
|
+
return {
|
|
923
|
+
name: account.name,
|
|
924
|
+
currency: account.currency,
|
|
925
|
+
index: account.index,
|
|
926
|
+
...account.contractAddress ? { contractAddress: account.contractAddress } : {},
|
|
927
|
+
...account.tokenIdentifier ? { tokenIdentifier: account.tokenIdentifier } : {},
|
|
928
|
+
governance
|
|
929
|
+
};
|
|
930
|
+
});
|
|
931
|
+
logger.info("Reading entities...");
|
|
932
|
+
const entities = existingEntities.map((entity) => ({
|
|
933
|
+
name: entity.name,
|
|
934
|
+
...entity.accountIds.length > 0 ? { accounts: entity.accountIds.map(accountNameFromId) } : {},
|
|
935
|
+
...entity.memberIds.length > 0 ? { members: entity.memberIds.map(userNameFromId) } : {}
|
|
936
|
+
}));
|
|
937
|
+
logger.info("Reading workspace rules...");
|
|
938
|
+
const workspaceRules = existingWorkspaceRules.results.filter((rule) => rule.permission !== "ROOT").map((rule) => {
|
|
939
|
+
(0, invariant.default)(rule.reviewSteps.length === 1, "Only one review step supported for workspace rules in manifest");
|
|
940
|
+
const step = rule.reviewSteps[0];
|
|
941
|
+
const quorum = step.quorum;
|
|
942
|
+
(0, invariant.default)(rule.permission !== "ROOT", "filtered out");
|
|
943
|
+
return {
|
|
944
|
+
permission: rule.permission,
|
|
945
|
+
quorum,
|
|
946
|
+
members: step.userIds.map(resolveUserToDeviceIndexOrName)
|
|
947
|
+
};
|
|
948
|
+
});
|
|
949
|
+
const workspace = {
|
|
950
|
+
users: {
|
|
951
|
+
...adminIndexes.length > 0 ? { admins: adminIndexes } : {},
|
|
952
|
+
...operatorIndexes.length > 0 ? { operators: operatorIndexes } : {},
|
|
953
|
+
...apiUsers.length > 0 ? { api: apiUsers } : {}
|
|
954
|
+
},
|
|
955
|
+
...groups.length > 0 ? { groups } : {},
|
|
956
|
+
...whitelists.length > 0 ? { whitelists } : {},
|
|
957
|
+
...policies.length > 0 ? { policies } : {},
|
|
958
|
+
...accounts.length > 0 ? { accounts } : {},
|
|
959
|
+
...entities.length > 0 ? { entities } : {},
|
|
960
|
+
...workspaceRules.length > 0 ? { workspaceRules } : {}
|
|
961
|
+
};
|
|
962
|
+
logger.info("Recipe completed");
|
|
963
|
+
return workspace;
|
|
964
|
+
async function resolveDevicesIndexes(users) {
|
|
965
|
+
const result = [];
|
|
966
|
+
for (const user of users) {
|
|
967
|
+
(0, invariant.default)(user.deviceUserId, `User ${user.id} does not have any device user id`);
|
|
968
|
+
const deviceIndex = await findDeviceIndex(user.deviceUserId);
|
|
969
|
+
result.push({
|
|
970
|
+
user,
|
|
971
|
+
deviceIndex
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
return result;
|
|
975
|
+
}
|
|
976
|
+
function resolveUserIdentifier(userId) {
|
|
977
|
+
const psdUser = psdUsersWithIndex.find((u) => u.user.id === userId);
|
|
978
|
+
if (psdUser) return psdUser.deviceIndex;
|
|
979
|
+
const apiUser = existingApiUsers.find((u) => u.id === userId);
|
|
980
|
+
if (apiUser) return apiUser.name;
|
|
981
|
+
throw new Error(`User ${userId} not found`);
|
|
982
|
+
}
|
|
983
|
+
function resolveUserToDeviceIndexOrName(userId) {
|
|
984
|
+
return resolveUserIdentifier(userId);
|
|
985
|
+
}
|
|
986
|
+
function validateGovernanceRuleType(value) {
|
|
987
|
+
(0, invariant.default)([
|
|
988
|
+
"SEND",
|
|
989
|
+
"STAKE",
|
|
990
|
+
"DEPLOY_CONTRACT",
|
|
991
|
+
"EXECUTE_CONTRACT",
|
|
992
|
+
"SIGN_MESSAGE",
|
|
993
|
+
"RECEIVE"
|
|
994
|
+
].includes(value), "Unexpected governance rule type: " + value);
|
|
995
|
+
return value;
|
|
996
|
+
}
|
|
997
|
+
function govRuleToManifest(rule) {
|
|
998
|
+
const operationType = validateGovernanceRuleType(rule.operationType);
|
|
999
|
+
const threshold = rule.threshold !== void 0 && (rule.threshold.min !== null || rule.threshold.max !== null) ? { threshold: {
|
|
1000
|
+
min: rule.threshold.min,
|
|
1001
|
+
max: rule.threshold.max
|
|
1002
|
+
} } : {};
|
|
1003
|
+
return {
|
|
1004
|
+
type: operationType,
|
|
1005
|
+
steps: rule.reviewSteps.map((step) => {
|
|
1006
|
+
if ("groupId" in step) {
|
|
1007
|
+
const group = existingGroups.find((g) => g.id === step.groupId);
|
|
1008
|
+
(0, invariant.default)(group, `Group ${step.groupId} not found`);
|
|
1009
|
+
return {
|
|
1010
|
+
quorum: step.quorum,
|
|
1011
|
+
group: group.name
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
return {
|
|
1015
|
+
quorum: step.quorum,
|
|
1016
|
+
members: step.userIds.map(resolveUserToDeviceIndexOrName)
|
|
1017
|
+
};
|
|
1018
|
+
}),
|
|
1019
|
+
...threshold,
|
|
1020
|
+
...rule.whitelistIds && rule.whitelistIds.length > 0 ? { whitelistNames: rule.whitelistIds.map(whitelistNameFromId) } : {}
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
function whitelistNameFromId(whitelistId) {
|
|
1024
|
+
const whitelist = existingWhitelists.find((w) => w.id === whitelistId);
|
|
1025
|
+
(0, invariant.default)(whitelist, `Whitelist ${whitelistId} not found`);
|
|
1026
|
+
return whitelist.name;
|
|
1027
|
+
}
|
|
1028
|
+
function accountNameFromId(accountId) {
|
|
1029
|
+
const account = existingAccounts.find((a) => a.id === accountId);
|
|
1030
|
+
(0, invariant.default)(account, `Account ${accountId} not found`);
|
|
1031
|
+
return account.name;
|
|
1032
|
+
}
|
|
1033
|
+
function userNameFromId(userId) {
|
|
1034
|
+
const user = existingApiUsers.find((u) => u.id === userId);
|
|
1035
|
+
(0, invariant.default)(user, `API user ${userId} not found`);
|
|
1036
|
+
return user.name;
|
|
1037
|
+
}
|
|
1038
|
+
function resolveAssetManagerName(assetManagerId) {
|
|
1039
|
+
return assetManagerId;
|
|
1040
|
+
}
|
|
1041
|
+
function resolveExchangeName(exchangeId) {
|
|
1042
|
+
return exchangeId;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
//#endregion
|
|
1046
|
+
//#region src/bake/recipe.ts
|
|
1047
|
+
async function recipeManifest(options, logger) {
|
|
1048
|
+
return {
|
|
1049
|
+
manifestVersion: 2,
|
|
1050
|
+
workspace: await recipeWorkspace(options, logger)
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
//#endregion
|
|
1054
|
+
//#region src/bake/types.ts
|
|
1055
|
+
const zManifestUser = zod.default.number().meta({ description: "User device index" });
|
|
1056
|
+
const zManifestUserName = zod.default.string().meta({ description: "User name" });
|
|
1057
|
+
const zManifestApiUser = zod.default.object({
|
|
1058
|
+
name: zod.default.string().meta({ description: "API user name" }),
|
|
1059
|
+
role: zod.default.enum(["ADMIN", "OPERATOR"]).meta({ description: "API user role" }).default("OPERATOR"),
|
|
1060
|
+
pubKey: zod.default.string().meta({ description: "API user public key. If not provided, one will be generated using the name as entropy" }).optional(),
|
|
1061
|
+
viewAll: zod.default.boolean().meta({ description: "Whether the API user can view all accounts" })
|
|
868
1062
|
});
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
1063
|
+
const zManifestGroup = zod.default.object({
|
|
1064
|
+
name: zod.default.string().meta({ description: "Group name" }),
|
|
1065
|
+
members: zod.default.array(zod.default.union([zManifestUser, zManifestUserName])).meta({ description: "Group members" })
|
|
872
1066
|
}).strict().meta({ description: "Operators group" });
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
1067
|
+
const zManifestWhitelistAddress = zod.default.object({
|
|
1068
|
+
name: zod.default.string().meta({ description: "Whitelist address name" }),
|
|
1069
|
+
currency: zod.default.string().meta({ description: "Whitelist address currency" }),
|
|
1070
|
+
address: zod.default.string().meta({ description: "Whitelist address" }),
|
|
1071
|
+
destinationTags: zod.default.array(zod.default.string()).optional().meta({ description: "List of destination tags (applicable for Ripple currency)" })
|
|
878
1072
|
}).strict();
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
1073
|
+
const zManifestWhitelist = zod.default.object({
|
|
1074
|
+
name: zod.default.string().meta({ description: "Whitelist name" }),
|
|
1075
|
+
description: zod.default.string().optional().meta({ description: "Whitelist description" }),
|
|
1076
|
+
type: zod.default.enum(["TRANSACTION", "SMART_CONTRACT"]).optional().default("TRANSACTION").meta({ description: "Whitelist type" }),
|
|
1077
|
+
addresses: zod.default.array(zManifestWhitelistAddress).meta({ description: "Whitelist addresses" })
|
|
884
1078
|
}).strict().meta({ description: "Whitelist" });
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
1079
|
+
const zManifestGovernanceStepWithUsers = zod.default.object({
|
|
1080
|
+
quorum: zod.default.number(),
|
|
1081
|
+
members: zod.default.array(zod.default.union([zManifestUser, zManifestUserName]))
|
|
888
1082
|
}).strict();
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1083
|
+
const zManifestGovernanceStepWithGroup = zod.default.object({
|
|
1084
|
+
quorum: zod.default.number(),
|
|
1085
|
+
group: zod.default.string()
|
|
892
1086
|
}).strict();
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
threshold: _zod2.default.object({
|
|
910
|
-
min: _zod2.default.string(),
|
|
911
|
-
max: _zod2.default.string()
|
|
912
|
-
}).optional(),
|
|
913
|
-
whitelistNames: _zod2.default.array(_zod2.default.string()).optional()
|
|
1087
|
+
const zManifestGovernanceStep = zod.default.union([zManifestGovernanceStepWithUsers, zManifestGovernanceStepWithGroup]);
|
|
1088
|
+
const zManifestGovernanceRule = zod.default.object({
|
|
1089
|
+
type: zod.default.enum([
|
|
1090
|
+
"SEND",
|
|
1091
|
+
"STAKE",
|
|
1092
|
+
"DEPLOY_CONTRACT",
|
|
1093
|
+
"EXECUTE_CONTRACT",
|
|
1094
|
+
"SIGN_MESSAGE",
|
|
1095
|
+
"RECEIVE"
|
|
1096
|
+
]),
|
|
1097
|
+
steps: zod.default.array(zManifestGovernanceStep).min(1),
|
|
1098
|
+
threshold: zod.default.object({
|
|
1099
|
+
min: zod.default.string().nullable(),
|
|
1100
|
+
max: zod.default.string().nullable()
|
|
1101
|
+
}).optional(),
|
|
1102
|
+
whitelistNames: zod.default.array(zod.default.string()).optional()
|
|
914
1103
|
}).strict();
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1104
|
+
const zManifestPolicy = zod.default.object({
|
|
1105
|
+
name: zod.default.string(),
|
|
1106
|
+
currency: zod.default.string().nullable(),
|
|
1107
|
+
rules: zod.default.array(zManifestGovernanceRule)
|
|
919
1108
|
}).strict();
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1109
|
+
const zManifestClassicAccountGovernance = zod.default.object({
|
|
1110
|
+
type: zod.default.literal("CLASSIC"),
|
|
1111
|
+
rules: zod.default.array(zManifestGovernanceRule)
|
|
923
1112
|
}).strict();
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1113
|
+
const zManifestClassicAccountGovernanceWithPolicy = zod.default.object({
|
|
1114
|
+
type: zod.default.literal("POLICY"),
|
|
1115
|
+
policy: zod.default.string()
|
|
927
1116
|
}).strict();
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
1117
|
+
const zManifestTradelinkExchangeConfig = zod.default.object({
|
|
1118
|
+
name: zod.default.string().meta({ description: "Exchange name" }),
|
|
1119
|
+
repledgeAuthorized: zod.default.boolean().optional().meta({ description: "Whether repledge is authorized" }),
|
|
1120
|
+
needsAssetManagerApprovalForSettlements: zod.default.boolean().optional().meta({ description: "Whether asset manager pre approval is needed" })
|
|
932
1121
|
}).strict();
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1122
|
+
const zManifestTradelinkAccountGovernance = zod.default.object({
|
|
1123
|
+
type: zod.default.literal("TRADELINK"),
|
|
1124
|
+
assetManager: zod.default.string().meta({ description: "Asset manager name" }),
|
|
1125
|
+
exchanges: zod.default.array(zManifestTradelinkExchangeConfig)
|
|
937
1126
|
}).strict();
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1127
|
+
const zManifestRawSigningGovernanceRule = zod.default.object({
|
|
1128
|
+
type: zod.default.literal("SIGN_DIGESTS"),
|
|
1129
|
+
steps: zod.default.array(zManifestGovernanceStepWithUsers).min(1)
|
|
941
1130
|
}).strict();
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1131
|
+
const zManifestRawSigningAccountGovernance = zod.default.object({
|
|
1132
|
+
type: zod.default.literal("RAW_SIGNING"),
|
|
1133
|
+
rules: zod.default.array(zManifestRawSigningGovernanceRule)
|
|
945
1134
|
}).strict();
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1135
|
+
const zManifestAccountGovernance = zod.default.discriminatedUnion("type", [
|
|
1136
|
+
zManifestClassicAccountGovernance,
|
|
1137
|
+
zManifestTradelinkAccountGovernance,
|
|
1138
|
+
zManifestRawSigningAccountGovernance,
|
|
1139
|
+
zManifestClassicAccountGovernanceWithPolicy
|
|
951
1140
|
]);
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
1141
|
+
const zManifestAccount = zod.default.object({
|
|
1142
|
+
name: zod.default.string(),
|
|
1143
|
+
currency: zod.default.string(),
|
|
1144
|
+
index: zod.default.number().nonnegative(),
|
|
1145
|
+
contractAddress: zod.default.string().optional(),
|
|
1146
|
+
tokenIdentifier: zod.default.string().optional(),
|
|
1147
|
+
governance: zManifestAccountGovernance
|
|
959
1148
|
}).strict();
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1149
|
+
const zManifestEntity = zod.default.object({
|
|
1150
|
+
name: zod.default.string().min(1).max(19).meta({ description: "Entity name" }),
|
|
1151
|
+
accounts: zod.default.array(zod.default.string()).optional().meta({ description: "Account names to include in this entity" }),
|
|
1152
|
+
members: zod.default.array(zod.default.string()).optional().meta({ description: "API operator names to include in this entity" })
|
|
1153
|
+
}).strict().meta({ description: "Entity" });
|
|
1154
|
+
const zManifestHederaData = zod.default.object({
|
|
1155
|
+
index: zod.default.number(),
|
|
1156
|
+
onChainId: zod.default.string(),
|
|
1157
|
+
activate: zod.default.boolean().default(true)
|
|
964
1158
|
}).strict();
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1159
|
+
const zManifestPledgeAdjustment = zod.default.object({
|
|
1160
|
+
account: zod.default.string(),
|
|
1161
|
+
exchange: zod.default.string(),
|
|
1162
|
+
amount: zod.default.string()
|
|
969
1163
|
}).strict();
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1164
|
+
const zManifestTradelinkGroup = zod.default.object({
|
|
1165
|
+
members: zod.default.array(zManifestUser),
|
|
1166
|
+
quorum: zod.default.number()
|
|
973
1167
|
}).strict().meta({ description: "Tradelink group" });
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1168
|
+
const zManifestTradelinkGroups = zod.default.array(zManifestTradelinkGroup);
|
|
1169
|
+
const zManifestTradelinkWhitelistAddress = zod.default.object({
|
|
1170
|
+
name: zod.default.string().min(1),
|
|
1171
|
+
currency: zod.default.string().min(1),
|
|
1172
|
+
address: zod.default.string().min(1)
|
|
979
1173
|
}).strict().meta({ description: "Tradelink whitelist address" });
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
1174
|
+
const zManifestTradelinkWhitelist = zod.default.array(zManifestTradelinkWhitelistAddress).meta({ description: "Tradelink whitelist" });
|
|
1175
|
+
const zManifestTradelinkEntity = zod.default.object({
|
|
1176
|
+
name: zod.default.string(),
|
|
1177
|
+
groups: zManifestTradelinkGroups,
|
|
1178
|
+
whitelist: zManifestTradelinkWhitelist
|
|
985
1179
|
}).strict();
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1180
|
+
const zManifestTradelinkCustodian = zod.default.object({
|
|
1181
|
+
settlement: zManifestTradelinkGroups,
|
|
1182
|
+
withdraw: zManifestTradelinkGroups,
|
|
1183
|
+
arbitration: zManifestTradelinkGroups
|
|
990
1184
|
}).strict();
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1185
|
+
const zManifestTradelinkNetworkBlueprint = zod.default.object({
|
|
1186
|
+
custodian: zod.default.string(),
|
|
1187
|
+
exchanges: zod.default.array(zod.default.string()),
|
|
1188
|
+
assetManagers: zod.default.array(zod.default.string())
|
|
995
1189
|
}).strict();
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1190
|
+
const zManifestTradelinkNetwork = zod.default.object({
|
|
1191
|
+
networkBlueprint: zManifestTradelinkNetworkBlueprint.optional(),
|
|
1192
|
+
custodian: zManifestTradelinkCustodian.optional(),
|
|
1193
|
+
exchanges: zod.default.array(zManifestTradelinkEntity).optional(),
|
|
1194
|
+
assetManagers: zod.default.array(zManifestTradelinkEntity).optional()
|
|
1001
1195
|
}).strict().meta({ description: "Tradelink network configuration" });
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1196
|
+
const zManifestWorkspaceRule = zod.default.object({
|
|
1197
|
+
permission: zod.default.enum(["CREATE_ACCOUNT_WITH_POLICY"]),
|
|
1198
|
+
quorum: zod.default.number().min(1),
|
|
1199
|
+
members: zod.default.array(zod.default.union([zManifestUser, zManifestUserName]))
|
|
1006
1200
|
}).strict().meta({ description: "Workspace rule for granting permissions" });
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1201
|
+
const zManifestWorkspace = zod.default.object({
|
|
1202
|
+
tradelink: zManifestTradelinkNetwork.optional(),
|
|
1203
|
+
users: zod.default.object({
|
|
1204
|
+
admins: zod.default.array(zManifestUser).optional(),
|
|
1205
|
+
operators: zod.default.array(zManifestUser).optional(),
|
|
1206
|
+
api: zod.default.array(zManifestApiUser).optional()
|
|
1207
|
+
}).optional(),
|
|
1208
|
+
groups: zod.default.array(zManifestGroup).optional(),
|
|
1209
|
+
whitelists: zod.default.array(zManifestWhitelist).optional(),
|
|
1210
|
+
policies: zod.default.array(zManifestPolicy).optional(),
|
|
1211
|
+
accounts: zod.default.array(zManifestAccount).optional(),
|
|
1212
|
+
entities: zod.default.array(zManifestEntity).optional(),
|
|
1213
|
+
hederaData: zod.default.record(zod.default.string(), zod.default.array(zManifestHederaData)).optional(),
|
|
1214
|
+
pledges: zod.default.array(zManifestPledgeAdjustment).optional(),
|
|
1215
|
+
workspaceRules: zod.default.array(zManifestWorkspaceRule).optional()
|
|
1021
1216
|
}).strict().meta({ description: "Workspace configuration" });
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1217
|
+
const zManifestTradelinkOrgEntity = zod.default.object({
|
|
1218
|
+
name: zod.default.string(),
|
|
1219
|
+
code: zod.default.string(),
|
|
1220
|
+
logo: zod.default.string()
|
|
1026
1221
|
}).strict().meta({ description: "Tradelink organization entity" });
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1222
|
+
const zManifestTradelinkOrg = zod.default.object({
|
|
1223
|
+
exchanges: zod.default.array(zManifestTradelinkOrgEntity).optional(),
|
|
1224
|
+
assetManagers: zod.default.array(zManifestTradelinkOrgEntity).optional(),
|
|
1225
|
+
custodians: zod.default.array(zManifestTradelinkOrgEntity).optional()
|
|
1031
1226
|
}).strict().meta({ description: "Tradelink organization configuration" });
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1227
|
+
const zManifest = zod.default.object({
|
|
1228
|
+
manifestVersion: zod.default.literal(2),
|
|
1229
|
+
tradelink: zManifestTradelinkOrg.optional(),
|
|
1230
|
+
workspace: zManifestWorkspace.optional()
|
|
1036
1231
|
}).strict();
|
|
1037
|
-
|
|
1038
|
-
|
|
1232
|
+
//#endregion
|
|
1233
|
+
//#region src/bake/index.ts
|
|
1039
1234
|
async function bakeManifest(options, logger) {
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1235
|
+
const { engine, workspaceName, rootAuthToken, manifest: { tradelink, workspace } } = options;
|
|
1236
|
+
if (tradelink) {
|
|
1237
|
+
(0, invariant.default)(rootAuthToken, `rootAuthToken is required to create Tradelink org entities`);
|
|
1238
|
+
await bakeTradelinkOrganization({
|
|
1239
|
+
engine,
|
|
1240
|
+
tradelink,
|
|
1241
|
+
rootAuthToken,
|
|
1242
|
+
...workspace?.tradelink?.networkBlueprint && workspaceName ? { networkBlueprint: {
|
|
1243
|
+
blueprint: workspace.tradelink.networkBlueprint,
|
|
1244
|
+
workspaceName
|
|
1245
|
+
} } : {}
|
|
1246
|
+
}, logger);
|
|
1247
|
+
}
|
|
1248
|
+
if (workspace) {
|
|
1249
|
+
(0, invariant.default)(workspaceName, `Can't bake workspace without specifying a workspace name`);
|
|
1250
|
+
await bakeWorkspace({
|
|
1251
|
+
engine,
|
|
1252
|
+
workspace,
|
|
1253
|
+
workspaceName
|
|
1254
|
+
}, logger);
|
|
1255
|
+
if (workspace.pledges) {
|
|
1256
|
+
const engineWithWorkspace = engine.withWorkspace(workspaceName);
|
|
1257
|
+
for (const pledgeAdjustment of workspace.pledges) await bakePledgeAdjustment({
|
|
1258
|
+
engine: engineWithWorkspace,
|
|
1259
|
+
pledgeAdjustment
|
|
1260
|
+
}, logger);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
logger.info("Successfully baked");
|
|
1069
1264
|
}
|
|
1265
|
+
//#endregion
|
|
1266
|
+
exports.bakeManifest = bakeManifest;
|
|
1267
|
+
exports.bakePledgeAdjustment = bakePledgeAdjustment;
|
|
1268
|
+
exports.createAndApproveRequest = createAndApproveRequest;
|
|
1269
|
+
exports.recipeManifest = recipeManifest;
|
|
1270
|
+
exports.zManifest = zManifest;
|
|
1271
|
+
exports.zManifestPolicy = zManifestPolicy;
|
|
1070
1272
|
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
exports.bakeManifest = bakeManifest; exports.bakePledgeAdjustment = bakePledgeAdjustment; exports.createAndApproveRequest = createAndApproveRequest; exports.zManifest = zManifest; exports.zManifestPolicy = zManifestPolicy;
|
|
1077
|
-
/* v8 ignore else - TODO bake empty tradelink org -- @preserve */
|
|
1078
|
-
/* v8 ignore else -- @preserve */
|
|
1079
1273
|
//# sourceMappingURL=bake.cjs.map
|