@ledgerhq/revault-sdk 0.22.9 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/bake.cjs CHANGED
@@ -4,7 +4,7 @@
4
4
  var _chunkLH4QQXUHcjs = require('./chunk-LH4QQXUH.cjs');
5
5
 
6
6
 
7
- var _chunkP53CFOI6cjs = require('./chunk-P53CFOI6.cjs');
7
+ var _chunk2WGM7EWAcjs = require('./chunk-2WGM7EWA.cjs');
8
8
 
9
9
  // src/bake/index.ts
10
10
  var _invariant = require('invariant'); var _invariant2 = _interopRequireDefault(_invariant);
@@ -27,6 +27,52 @@ function createBakeLogHelpers(logger) {
27
27
  }
28
28
  };
29
29
  }
30
+ var IS_REQUEST_STATE_END_STATE = {
31
+ // end states:
32
+ ABORTED: true,
33
+ BLOCKED: true,
34
+ EXECUTED: true,
35
+ EXPIRED: true,
36
+ FAILED: true,
37
+ STUCK: true,
38
+ // not end states:
39
+ EXECUTING: false,
40
+ INITIAL: false,
41
+ PENDING_APPROVAL: false
42
+ };
43
+ var isEndState = (state) => IS_REQUEST_STATE_END_STATE[state];
44
+ var DEFAULT_POLL_INTERVAL_MS = 250;
45
+ var DEFAULT_TIMEOUT_MS = 6e4;
46
+ var wait = (ms) => {
47
+ return new Promise((resolve) => setTimeout(resolve, ms));
48
+ };
49
+ async function waitForRequestExecuted(client, request, logger, options) {
50
+ const { logSubStep } = createBakeLogHelpers(logger);
51
+ if (isEndState(request.state)) {
52
+ if (request.state === "EXECUTED") {
53
+ return request;
54
+ }
55
+ throw new Error(`Request is in error state ${request.state}`);
56
+ }
57
+ const pollIntervalMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _3 => _3.pollIntervalMs]), () => ( DEFAULT_POLL_INTERVAL_MS));
58
+ const timeoutMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _4 => _4.timeoutMs]), () => ( DEFAULT_TIMEOUT_MS));
59
+ const deadline = Date.now() + timeoutMs;
60
+ logSubStep(`Waiting for request to be executed...`);
61
+ let updated = request;
62
+ while (Date.now() < deadline) {
63
+ await wait(pollIntervalMs);
64
+ updated = await client.requests.findById.query({ id: request.id });
65
+ if (isEndState(updated.state)) {
66
+ if (updated.state === "EXECUTED") {
67
+ return updated;
68
+ }
69
+ throw new Error(`Request is in error state ${updated.state}`);
70
+ }
71
+ }
72
+ throw new Error(
73
+ `Timed out waiting for request ${request.id} to reach a terminal state (last state: ${updated.state})`
74
+ );
75
+ }
30
76
  async function approveRequest(request, approvers, logger) {
31
77
  const { logSubStep } = createBakeLogHelpers(logger);
32
78
  for (let i = 0; i < approvers.length; i++) {
@@ -34,7 +80,7 @@ async function approveRequest(request, approvers, logger) {
34
80
  const approver = approvers[i];
35
81
  request = await approver.approve(request);
36
82
  }
37
- return request;
83
+ return waitForRequestExecuted(approvers[0].client, request, logger);
38
84
  }
39
85
  async function createAndApproveRequest(input, approvers, logger) {
40
86
  const { logSubStep } = createBakeLogHelpers(logger);
@@ -211,6 +257,7 @@ async function bakeTradelinkOrganization(options, logger) {
211
257
  // src/bake/bake-workspace.ts
212
258
 
213
259
  var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash);
260
+ var _tspattern = require('ts-pattern');
214
261
  async function bakeWorkspace(options, logger) {
215
262
  const { workspace, engine, workspaceName } = options;
216
263
  const workspaceEngine = engine.withWorkspace(workspaceName);
@@ -237,8 +284,8 @@ async function bakeWorkspace(options, logger) {
237
284
  _chunkLH4QQXUHcjs.fetchAll.call(void 0, admin1.client.accounts.list.query, { status: "ACTIVE" }),
238
285
  admin1.client.tradelink.getNetworkBlueprint.query()
239
286
  ]);
240
- const tradelinkOrgExchangesByName = _lodash2.default.keyBy(_optionalChain([tradelinkNetworkBlueprint, 'optionalAccess', _3 => _3.exchanges]), "name");
241
- const tradelinkOrgAssetManagersByName = _lodash2.default.keyBy(_optionalChain([tradelinkNetworkBlueprint, 'optionalAccess', _4 => _4.assetManagers]), "name");
287
+ const tradelinkOrgExchangesByName = _lodash2.default.keyBy(_optionalChain([tradelinkNetworkBlueprint, 'optionalAccess', _5 => _5.exchanges]), "name");
288
+ const tradelinkOrgAssetManagersByName = _lodash2.default.keyBy(_optionalChain([tradelinkNetworkBlueprint, 'optionalAccess', _6 => _6.assetManagers]), "name");
242
289
  let existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();
243
290
  const existingPsdUsers = existingUsers.filter((user) => user.deviceType === "PSD");
244
291
  const existingApiUsers = existingUsers.filter((user) => user.deviceType === "API");
@@ -329,7 +376,7 @@ async function bakeWorkspace(options, logger) {
329
376
  };
330
377
  }),
331
378
  threshold: rule.threshold,
332
- whitelistIds: _optionalChain([rule, 'access', _5 => _5.whitelistNames, 'optionalAccess', _6 => _6.map, 'call', _7 => _7(whitelistIdFromName)])
379
+ whitelistIds: _optionalChain([rule, 'access', _7 => _7.whitelistNames, 'optionalAccess', _8 => _8.map, 'call', _9 => _9(whitelistIdFromName)])
333
380
  };
334
381
  }
335
382
  function rawSigningRuleFromManifest(rule) {
@@ -347,21 +394,24 @@ async function bakeWorkspace(options, logger) {
347
394
  const existing = existingAccounts.find(
348
395
  (a) => a.currency === account.currency && a.index === account.index && (_nullishCoalesce(a.contractAddress, () => ( null))) === (_nullishCoalesce(account.contractAddress, () => ( null)))
349
396
  );
350
- const governance = account.governance.type === "TRADELINK" ? {
397
+ const governance = _tspattern.match.call(void 0, account.governance).with({ type: "TRADELINK" }, (gov) => ({
351
398
  type: "TRADELINK",
352
- assetManagerId: assetManagerIdFromName(account.governance.assetManager),
353
- exchangeConfigs: account.governance.exchanges.map((exchangeConfig) => ({
399
+ assetManagerId: assetManagerIdFromName(gov.assetManager),
400
+ exchangeConfigs: gov.exchanges.map((exchangeConfig) => ({
354
401
  exchangeId: exchangeIdFromName(exchangeConfig.name),
355
402
  repledgeAuthorized: exchangeConfig.repledgeAuthorized === true,
356
403
  needsAssetManagerApprovalForSettlements: exchangeConfig.needsAssetManagerApprovalForSettlements === true
357
404
  }))
358
- } : account.governance.type === "RAW_SIGNING" ? {
405
+ })).with({ type: "RAW_SIGNING" }, (gov) => ({
359
406
  type: "RAW_SIGNING",
360
- policy: { rules: account.governance.rules.map(rawSigningRuleFromManifest) }
361
- } : {
407
+ policy: { rules: gov.rules.map(rawSigningRuleFromManifest) }
408
+ })).with({ type: "CLASSIC" }, (gov) => ({
362
409
  type: "CLASSIC",
363
- policy: { rules: account.governance.rules.map(govRuleFromManifest) }
364
- };
410
+ policy: { rules: gov.rules.map(govRuleFromManifest) }
411
+ })).with({ type: "POLICY" }, (gov) => ({
412
+ type: "CLASSIC",
413
+ policy: { policyId: policyIdFromName(gov.policy) }
414
+ })).exhaustive();
365
415
  const accountData = {
366
416
  name: account.name,
367
417
  currency: account.currency,
@@ -387,8 +437,8 @@ async function bakeWorkspace(options, logger) {
387
437
  sortBy: "createdAt",
388
438
  sortOrder: "desc"
389
439
  });
390
- if (_optionalChain([previousAccountRequests, 'optionalAccess', _8 => _8.results]) && previousAccountRequests.results.length > 0) {
391
- const stateRequest = _optionalChain([previousAccountRequests, 'access', _9 => _9.results, 'optionalAccess', _10 => _10[0]]);
440
+ if (_optionalChain([previousAccountRequests, 'optionalAccess', _10 => _10.results]) && previousAccountRequests.results.length > 0) {
441
+ const stateRequest = _optionalChain([previousAccountRequests, 'access', _11 => _11.results, 'optionalAccess', _12 => _12[0]]);
392
442
  _invariant2.default.call(void 0,
393
443
  stateRequest && (stateRequest.type === "EDIT_ACCOUNT" || stateRequest.type === "CREATE_ACCOUNT"),
394
444
  "State request should be an edit account request"
@@ -414,14 +464,14 @@ async function bakeWorkspace(options, logger) {
414
464
  if (account.governance.type === "TRADELINK" && req) {
415
465
  logStep(`Activating tradelink account "${account.name}"`);
416
466
  const assetManagerId = assetManagerIdFromName(account.governance.assetManager);
417
- const assetManager = _optionalChain([existingTradelinkNetwork, 'optionalAccess', _11 => _11.assetManagers, 'access', _12 => _12.find, 'call', _13 => _13(
467
+ const assetManager = _optionalChain([existingTradelinkNetwork, 'optionalAccess', _13 => _13.assetManagers, 'access', _14 => _14.find, 'call', _15 => _15(
418
468
  (assetManager2) => assetManager2.id === assetManagerId
419
469
  )]);
420
470
  _invariant2.default.call(void 0, assetManager, `Asset manager for account exists`);
421
471
  const loggedAssetManagerOperators = await Promise.all(
422
472
  assetManager.groups.flatMap(
423
473
  ({ quorum, userIds }) => userIds.slice(0, quorum).map((userId) => {
424
- const deviceIndex = _optionalChain([usersWithDeviceIndex, 'access', _14 => _14.find, 'call', _15 => _15((o) => o.user.id === userId), 'optionalAccess', _16 => _16.deviceIndex]);
474
+ const deviceIndex = _optionalChain([usersWithDeviceIndex, 'access', _16 => _16.find, 'call', _17 => _17((o) => o.user.id === userId), 'optionalAccess', _18 => _18.deviceIndex]);
425
475
  return workspaceEngine.withDeviceIndex(deviceIndex).login();
426
476
  })
427
477
  )
@@ -432,7 +482,7 @@ async function bakeWorkspace(options, logger) {
432
482
  logger
433
483
  );
434
484
  }
435
- if (_optionalChain([req, 'optionalAccess', _17 => _17.targetId])) {
485
+ if (_optionalChain([req, 'optionalAccess', _19 => _19.targetId])) {
436
486
  await activateHederaAccount(account, workspace2, req.targetId);
437
487
  }
438
488
  logSubStep(`Account ${account.name} has been created`);
@@ -441,7 +491,7 @@ async function bakeWorkspace(options, logger) {
441
491
  if (account.currency === "hedera" && account.contractAddress === void 0 && workspace2.hederaData && accountId) {
442
492
  const salt = engine.__options.salt;
443
493
  const hederaAccountsForSalt = workspace2.hederaData[salt];
444
- const hederaAccountData = _optionalChain([hederaAccountsForSalt, 'optionalAccess', _18 => _18.find, 'call', _19 => _19(
494
+ const hederaAccountData = _optionalChain([hederaAccountsForSalt, 'optionalAccess', _20 => _20.find, 'call', _21 => _21(
445
495
  (h) => h.index === account.index && h.activate
446
496
  )]);
447
497
  if (hederaAccountData) {
@@ -490,7 +540,7 @@ async function bakeWorkspace(options, logger) {
490
540
  usersWithDeviceIndex.push({ user: createdUser, deviceIndex });
491
541
  }
492
542
  async function createApiUser(apiUser) {
493
- const pubKey = _nullishCoalesce(apiUser.pubKey, () => ( _chunkP53CFOI6cjs.genKeys.call(void 0, apiUser.name).hexPubKey));
543
+ const pubKey = _nullishCoalesce(apiUser.pubKey, () => ( _chunk2WGM7EWAcjs.genKeys.call(void 0, apiUser.name).hexPubKey));
494
544
  const existing = existingApiUsers.find(
495
545
  (user) => user.pubKey === pubKey || user.name === apiUser.name
496
546
  );
@@ -738,6 +788,11 @@ async function bakeWorkspace(options, logger) {
738
788
  _invariant2.default.call(void 0, group, `Group ${groupName} not found`);
739
789
  return group.id;
740
790
  }
791
+ function policyIdFromName(policyName) {
792
+ const policy = existingPolicies.find((g) => g.name === policyName);
793
+ _invariant2.default.call(void 0, policy, `Policy ${policyName} not found`);
794
+ return policy.id;
795
+ }
741
796
  function whitelistIdFromName(whitelistName) {
742
797
  const whitelist = existingWhitelists.find((w) => w.name === whitelistName);
743
798
  _invariant2.default.call(void 0, whitelist, `Whitelist ${whitelistName} not found`);
@@ -749,14 +804,14 @@ async function bakeWorkspace(options, logger) {
749
804
  orgAssetManager,
750
805
  `Can't find Tradelink organization asset manager ${assetManagerName}`
751
806
  );
752
- const assetManager = _optionalChain([existingTradelinkNetwork, 'optionalAccess', _20 => _20.assetManagers, 'access', _21 => _21.find, 'call', _22 => _22(
807
+ const assetManager = _optionalChain([existingTradelinkNetwork, 'optionalAccess', _22 => _22.assetManagers, 'access', _23 => _23.find, 'call', _24 => _24(
753
808
  (assetManager2) => assetManager2.tradelinkId === orgAssetManager.tradelinkId
754
809
  )]);
755
810
  _invariant2.default.call(void 0, assetManager, `Can't find Tradelink assetManager ${assetManagerName}`);
756
811
  return assetManager.id;
757
812
  }
758
813
  function exchangeIdFromName(exchangeName) {
759
- const exchange = _optionalChain([existingTradelinkNetwork, 'optionalAccess', _23 => _23.exchanges, 'access', _24 => _24.find, 'call', _25 => _25((exchange2) => {
814
+ const exchange = _optionalChain([existingTradelinkNetwork, 'optionalAccess', _25 => _25.exchanges, 'access', _26 => _26.find, 'call', _27 => _27((exchange2) => {
760
815
  const orgExchange = tradelinkOrgExchangesByName[exchangeName];
761
816
  _invariant2.default.call(void 0, orgExchange, `Can't find Tradelink organization exchange ${exchange2.tradelinkId}`);
762
817
  return orgExchange.name === exchangeName;
@@ -842,6 +897,10 @@ var zManifestClassicAccountGovernance = _zod2.default.object({
842
897
  type: _zod2.default.literal("CLASSIC"),
843
898
  rules: _zod2.default.array(zManifestGovernanceRule)
844
899
  }).strict();
900
+ var zManifestClassicAccountGovernanceWithPolicy = _zod2.default.object({
901
+ type: _zod2.default.literal("POLICY"),
902
+ policy: _zod2.default.string()
903
+ }).strict();
845
904
  var zManifestTradelinkExchangeConfig = _zod2.default.object({
846
905
  name: _zod2.default.string().meta({ description: "Exchange name" }),
847
906
  repledgeAuthorized: _zod2.default.boolean().optional().meta({ description: "Whether repledge is authorized" }),
@@ -863,7 +922,8 @@ var zManifestRawSigningAccountGovernance = _zod2.default.object({
863
922
  var zManifestAccountGovernance = _zod2.default.discriminatedUnion("type", [
864
923
  zManifestClassicAccountGovernance,
865
924
  zManifestTradelinkAccountGovernance,
866
- zManifestRawSigningAccountGovernance
925
+ zManifestRawSigningAccountGovernance,
926
+ zManifestClassicAccountGovernanceWithPolicy
867
927
  ]);
868
928
  var zManifestAccount = _zod2.default.object({
869
929
  name: _zod2.default.string(),
@@ -966,7 +1026,7 @@ async function bakeManifest(options, logger) {
966
1026
  engine,
967
1027
  tradelink,
968
1028
  rootAuthToken,
969
- ..._optionalChain([workspace, 'optionalAccess', _26 => _26.tradelink, 'optionalAccess', _27 => _27.networkBlueprint]) && workspaceName ? { networkBlueprint: { blueprint: workspace.tradelink.networkBlueprint, workspaceName } } : {}
1029
+ ..._optionalChain([workspace, 'optionalAccess', _28 => _28.tradelink, 'optionalAccess', _29 => _29.networkBlueprint]) && workspaceName ? { networkBlueprint: { blueprint: workspace.tradelink.networkBlueprint, workspaceName } } : {}
970
1030
  },
971
1031
  logger
972
1032
  );
package/lib/bake.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/_work/revault/revault/packages/sdk/lib/bake.cjs","../src/bake/index.ts","../src/bake/bake-pledge.ts","../src/bake/utils.ts","../src/bake/bake-tradelink-organization.ts","../src/bake/bake-workspace.ts","../src/bake/types.ts"],"names":["blueprintExchange","invariant","assetManager","usersWithDeviceIndex","acc"],"mappings":"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","file":"/home/runner/_work/revault/revault/packages/sdk/lib/bake.cjs","sourcesContent":[null,"import invariant from \"invariant\";\n\nimport type { Logger } from \"@/logger\";\n\nimport { bakePledgeAdjustment } from \"./bake-pledge\";\nimport { bakeTradelinkOrganization } from \"./bake-tradelink-organization\";\nimport { bakeWorkspace } from \"./bake-workspace\";\nimport type { BakeOptions } from \"./types\";\n\nexport * from \"./bake-pledge\";\nexport * from \"./types\";\nexport { type CreateRequestInput, createAndApproveRequest } from \"./utils\";\n\nexport async function bakeManifest(options: BakeOptions, logger: Logger): Promise<void> {\n const {\n engine,\n workspaceName,\n rootAuthToken,\n manifest: { tradelink, workspace },\n } = options;\n\n if (tradelink) {\n invariant(rootAuthToken, `rootAuthToken is required to create Tradelink org entities`);\n await bakeTradelinkOrganization(\n {\n engine,\n tradelink,\n rootAuthToken,\n ...(workspace?.tradelink?.networkBlueprint && workspaceName\n ? { networkBlueprint: { blueprint: workspace.tradelink.networkBlueprint, workspaceName } }\n : {}),\n },\n logger,\n );\n }\n\n if (workspace) {\n invariant(workspaceName, `Can't bake workspace without specifying a workspace name`);\n await bakeWorkspace({ engine, workspace, workspaceName }, logger);\n\n if (workspace.pledges) {\n const engineWithWorkspace = engine.withWorkspace(workspaceName);\n for (const pledgeAdjustment of workspace.pledges) {\n await bakePledgeAdjustment({ engine: engineWithWorkspace, pledgeAdjustment }, logger);\n }\n }\n }\n\n logger.info(\"Successfully baked\");\n}\n","import invariant from \"invariant\";\n\nimport type { Engine, WithWorkspace } from \"@/engine\";\nimport type { Logger } from \"@/logger\";\nimport { createDeviceIndexResolver, fetchAll } from \"@/utils\";\n\nimport type { ManifestPledgeAdjustment } from \"./types\";\nimport { createAndApproveRequest } from \"./utils\";\n\ntype Options = {\n engine: Engine<WithWorkspace>;\n pledgeAdjustment: ManifestPledgeAdjustment;\n};\n\nconst flattenApprovers = (groups: { quorum: number; userIds: string[] }[]): string[] => {\n return groups.reduce<string[]>((acc, cur) => {\n acc.push(...cur.userIds.slice(0, cur.quorum));\n return acc;\n }, []);\n};\n\nexport async function bakePledgeAdjustment(options: Options, logger: Logger): Promise<void> {\n const { pledgeAdjustment, engine } = options;\n\n const getDeviceIndex = createDeviceIndexResolver(engine);\n\n logger.info(\"Logging in with admin...\");\n const admin = await engine.withDeviceIndex(4).login();\n\n logger.info(\"Fetching account, tradelink blueprint and network...\");\n const [matchingAccounts, blueprint, network] = await Promise.all([\n fetchAll(admin.client.accounts.list.query, { name: pledgeAdjustment.account }),\n admin.client.tradelink.getNetworkBlueprint.query(),\n admin.client.tradelink.getNetwork.query(),\n ]);\n\n const account = matchingAccounts.find((account) => account.name === pledgeAdjustment.account);\n invariant(account, `Account ${pledgeAdjustment.account} not found`);\n\n invariant(blueprint, \"Tradelink blueprint is not created yet\");\n invariant(network, \"Tradelink network is not created yet\");\n\n const exchange = network.exchanges.find((exchange) => {\n const blueprintExchange = blueprint.exchanges.find(\n (blueprintExchange) => blueprintExchange.tradelinkId === exchange.tradelinkId,\n );\n invariant(blueprintExchange, `Exchange ${exchange.tradelinkId} not found in blueprint`);\n return blueprintExchange.name === pledgeAdjustment.exchange;\n });\n invariant(exchange, `Exchange ${pledgeAdjustment.exchange} not found in network`);\n\n const governance = account.governance;\n invariant(governance.type === \"TRADELINK\", \"Account governance is not TRADELINK\");\n const assetManager = network.assetManagers.find((am) => am.id === governance.assetManagerId);\n invariant(assetManager, `Asset manager ${governance.assetManagerId} not found in network`);\n\n const exchangeIsConfiguredForAccount = !!governance.exchangeConfigs.find(\n (e) => e.exchangeId === exchange.id,\n );\n invariant(\n exchangeIsConfiguredForAccount,\n `Exchange ${exchange.id} is not configured for account ${account.id}`,\n );\n\n const approverIds = [\n ...flattenApprovers(assetManager.groups),\n ...flattenApprovers(exchange.groups),\n ];\n\n const approvers = await Promise.all(\n approverIds.map((id) =>\n admin.client.users.findById\n .query({ id })\n .then((user) => getDeviceIndex(user.deviceUserId!))\n .then((index) => engine.withDeviceIndex(index).login()),\n ),\n );\n\n await createAndApproveRequest(\n {\n type: \"TRADELINK_ADJUST_PLEDGE\",\n data: {\n accountId: account.id,\n exchangeId: exchange.id,\n amount: pledgeAdjustment.amount,\n },\n },\n approvers,\n logger,\n );\n\n logger.info(\n `Successfully adjusted pledge for account ${pledgeAdjustment.account} on exchange ${pledgeAdjustment.exchange}`,\n );\n}\n","import type { VaultRequestResponse } from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\n\nimport type { Engine, WithDevice, WithPsdAuth, WithWorkspace } from \"@/engine\";\nimport type { Logger } from \"@/logger\";\nimport type { RouterInputs } from \"@/trpc\";\n\ntype LogFunction = (msg: string) => void;\n\ntype LogHelpers = {\n logTitle: LogFunction;\n logStep: LogFunction;\n logSubStep: LogFunction;\n};\n\nexport function createBakeLogHelpers(logger: Logger): LogHelpers {\n return {\n logTitle(title: string): void {\n logger.info(`:: ${title} ::`);\n },\n logStep(msg: string): void {\n logger.info(`=> ${msg}`);\n },\n logSubStep(msg: string): void {\n logger.info(` -> ${msg}`);\n },\n };\n}\n\nexport type CreateRequestInput = RouterInputs[\"requests\"][\"create\"][\"request\"];\n\nexport type inferRequestInputData<T extends RouterInputs[\"requests\"][\"create\"][\"request\"][\"type\"]> =\n Extract<RouterInputs[\"requests\"][\"create\"][\"request\"], { type: T }>[\"data\"];\n\nexport async function approveRequest(\n request: VaultRequestResponse,\n approvers: Engine<WithWorkspace & WithDevice & WithPsdAuth>[],\n logger: Logger,\n): Promise<VaultRequestResponse> {\n const { logSubStep } = createBakeLogHelpers(logger);\n for (let i = 0; i < approvers.length; i++) {\n logSubStep(`Collecting approval (${i + 1}/${approvers.length})...`);\n const approver = approvers[i]!;\n request = await approver.approve(request);\n }\n return request;\n}\n\nexport async function createAndApproveRequest(\n input: CreateRequestInput,\n approvers: Engine<WithWorkspace & WithDevice & WithPsdAuth>[],\n logger: Logger,\n): Promise<VaultRequestResponse> {\n const { logSubStep } = createBakeLogHelpers(logger);\n const creator = approvers[0];\n invariant(creator, \"Need at least 1 user to create a request\");\n logSubStep(`Creating request of type ${input.type}...`);\n const request = await creator.client.requests.create.mutate({ request: input });\n return approveRequest(request, approvers, logger);\n}\n\nexport function stripUndefinedDeep<T>(obj: T): T {\n if (Array.isArray(obj)) {\n return obj.map(stripUndefinedDeep) as unknown as T;\n }\n\n if (obj && typeof obj === \"object\") {\n return Object.fromEntries(\n Object.entries(obj)\n .filter(([_, v]) => v !== undefined)\n .map(([k, v]) => [k, stripUndefinedDeep(v)]),\n ) as T;\n }\n\n return obj;\n}\n","import type { Logger } from \"@/logger\";\n\nimport type { BakeOptions, ManifestTradelinkNetworkBlueprint, ManifestTradelinkOrg } from \"./types\";\nimport { createBakeLogHelpers } from \"./utils\";\n\ntype Options = Omit<BakeOptions, \"manifest\" | \"rootAuthToken\"> & {\n tradelink: ManifestTradelinkOrg;\n rootAuthToken: string;\n networkBlueprint?: { workspaceName: string; blueprint: ManifestTradelinkNetworkBlueprint };\n};\n\nexport async function bakeTradelinkOrganization(options: Options, logger: Logger): Promise<void> {\n const { tradelink, engine, rootAuthToken, networkBlueprint } = options;\n\n const { logStep } = createBakeLogHelpers(logger);\n\n const rootClient = engine.createClient({ rootAuthToken });\n /* v8 ignore else - TODO bake empty tradelink org -- @preserve */\n if (tradelink.exchanges) {\n logStep(\"Creating Tradelink organization exchanges...\");\n const existingOrgExchanges = await rootClient.tradelink.root.listOrgExchanges.query();\n for (const orgExchange of tradelink.exchanges) {\n const existingOrgExchange = existingOrgExchanges.find((e) => e.name === orgExchange.name);\n if (existingOrgExchange) {\n logger.info(\n `[SKIPPED] Organization exchange ${existingOrgExchange.name} (${existingOrgExchange.code}) already exists`,\n );\n } else {\n await rootClient.tradelink.root.createOrgExchange.mutate({\n code: orgExchange.code,\n name: orgExchange.name,\n logoUrl: orgExchange.logo,\n });\n logger.info(`Created organization exchange ${orgExchange.name} (${orgExchange.code})`);\n }\n }\n }\n\n /* v8 ignore else -- @preserve */\n if (tradelink.assetManagers) {\n logStep(\"Creating Tradelink organization asset managers...\");\n const existingAssetManagers = await rootClient.tradelink.root.listOrgAssetManagers.query();\n for (const orgAssetManager of tradelink.assetManagers) {\n const existingOrgAssetManager = existingAssetManagers.find(\n (e) => e.name === orgAssetManager.name,\n );\n if (existingOrgAssetManager) {\n logger.info(\n `[SKIPPED] Organization asset manager ${existingOrgAssetManager.name} (${existingOrgAssetManager.code}) already exists`,\n );\n } else {\n await rootClient.tradelink.root.createOrgAssetManager.mutate({\n code: orgAssetManager.code,\n name: orgAssetManager.name,\n logoUrl: orgAssetManager.logo,\n });\n logger.info(\n `Created organization asset manager ${orgAssetManager.name} (${orgAssetManager.code})`,\n );\n }\n }\n }\n\n /* v8 ignore else -- @preserve */\n if (tradelink.custodians) {\n logStep(\"Creating Tradelink organization custodians...\");\n const existingCustodians = await rootClient.tradelink.root.listOrgCustodians.query();\n for (const orgCustodian of tradelink.custodians) {\n const existingOrgCustodian = existingCustodians.find((e) => e.name === orgCustodian.name);\n if (existingOrgCustodian) {\n logger.info(\n `[SKIPPED] Organization custodian ${existingOrgCustodian.name} (${existingOrgCustodian.code}) already exists`,\n );\n } else {\n await rootClient.tradelink.root.createOrgCustodian.mutate({\n code: orgCustodian.code,\n name: orgCustodian.name,\n logoUrl: orgCustodian.logo,\n });\n logger.info(`Created organization custodian ${orgCustodian.name} (${orgCustodian.code})`);\n }\n }\n }\n\n /* v8 ignore else -- @preserve */\n if (networkBlueprint) {\n logStep(\"Creating Tradelink network blueprint...\");\n const { workspaceName, blueprint } = networkBlueprint;\n const existingBlueprints = await rootClient.tradelink.root.listNetworkBlueprints.query();\n const existingBlueprint = existingBlueprints.find((e) => e.workspaceName === workspaceName);\n if (existingBlueprint) {\n logger.info(`[SKIPPED] Network blueprint for ${workspaceName} workspace already exists`);\n } else {\n await rootClient.tradelink.root.createNetworkBlueprint.mutate({\n workspaceName,\n custodian: { name: blueprint.custodian },\n exchanges: blueprint.exchanges.map((_) => ({ name: _ })),\n assetManagers: blueprint.assetManagers.map((_) => ({ name: _ })),\n });\n logger.info(`Created network blueprint for ${networkBlueprint.workspaceName} workspace`);\n }\n }\n}\n","import type {\n ReviewStepWithUsers,\n TradelinkNetworkBlueprintResponse,\n UserResponse,\n VaultRequestResponse,\n} from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\nimport _ from \"lodash\";\n\nimport { genKeys } from \"@/crypto\";\nimport type { Logger } from \"@/logger\";\nimport { createDeviceIndexResolver, fetchAll } from \"@/utils\";\n\nimport type {\n BakeOptions,\n ManifestAccount,\n ManifestApiUser,\n ManifestGovernanceRule,\n ManifestGroup,\n ManifestPolicy,\n ManifestRawSigningGovernanceRule,\n ManifestTradelinkEntity,\n ManifestTradelinkGroup,\n ManifestTradelinkNetwork,\n ManifestWhitelist,\n ManifestWorkspace,\n ManifestWorkspaceRule,\n} from \"./types\";\nimport {\n approveRequest,\n type CreateRequestInput,\n createAndApproveRequest,\n createBakeLogHelpers,\n type inferRequestInputData,\n stripUndefinedDeep,\n} from \"./utils\";\n\ntype GovRuleData = inferRequestInputData<\"CREATE_POLICY\">[\"govRules\"][number];\n\ntype Options = Omit<BakeOptions, \"manifest\" | \"workspaceName\"> & {\n workspace: ManifestWorkspace;\n workspaceName: string;\n};\n\nexport async function bakeWorkspace(options: Options, logger: Logger): Promise<void> {\n const { workspace, engine, workspaceName } = options;\n\n const workspaceEngine = engine.withWorkspace(workspaceName);\n const { logTitle, logStep, logSubStep } = createBakeLogHelpers(logger);\n\n // utility to retrieve device index based on device user id\n const findDeviceIndex = createDeviceIndexResolver(workspaceEngine);\n\n // Log-in once with the two admins (index 4 & 5 by convention) that will create all\n // the requests for the manifest objects.\n logger.info(\"Authenticating with two admins...\");\n const [admin1, admin2] = await Promise.all([\n workspaceEngine.withDeviceIndex(4).login(),\n workspaceEngine.withDeviceIndex(5).login(),\n ]);\n\n // Retrieve all existing data, so we are then able to skip creating stuff when not needed.\n logger.info(\"Fetching existing data...\");\n const [\n existingUsers,\n existingGroups,\n existingWhitelists,\n existingPolicies,\n existingAccounts,\n tradelinkNetworkBlueprint,\n ] = await Promise.all([\n fetchAll(admin1.client.users.list.query, { status: \"ACTIVE\" }),\n fetchAll(admin1.client.groups.list.query, { status: \"ACTIVE\" }),\n fetchAll(admin1.client.whitelists.list.query, { status: \"ACTIVE\" }),\n fetchAll(admin1.client.policies.list.query, { isPrivate: false }),\n fetchAll(admin1.client.accounts.list.query, { status: \"ACTIVE\" }),\n admin1.client.tradelink.getNetworkBlueprint.query(),\n ]);\n\n const tradelinkOrgExchangesByName = _.keyBy(tradelinkNetworkBlueprint?.exchanges, \"name\");\n const tradelinkOrgAssetManagersByName = _.keyBy(tradelinkNetworkBlueprint?.assetManagers, \"name\");\n\n let existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();\n\n // Merge admins & operators (we can't fetch all users in a row because we don't want API users,\n // and we don't have a way to retrieve both admins & operators in a single fetch)\n const existingPsdUsers = existingUsers.filter((user) => user.deviceType === \"PSD\");\n const existingApiUsers = existingUsers.filter((user) => user.deviceType === \"API\");\n // Retrieve all device indexes for the existing users\n const usersWithDeviceIndex = await resolveDevicesIndexes(existingPsdUsers);\n\n // ---------------------------------\n // USERS\n // ---------------------------------\n if (workspace.users) {\n logTitle(\"Users\");\n if (workspace.users.admins) {\n for (const deviceIndex of workspace.users.admins) {\n await createUser(\"ADMIN\", deviceIndex);\n }\n }\n\n /* v8 ignore else -- @preserve */\n if (workspace.users.operators) {\n for (const deviceIndex of workspace.users.operators) {\n await createUser(\"OPERATOR\", deviceIndex);\n }\n }\n if (workspace.users.api) {\n for (const apiUser of workspace.users.api) {\n await createApiUser(apiUser);\n }\n }\n }\n\n // ---------------------------------\n // WORKSPACE RULES\n // ---------------------------------\n // Must come after users are created (rules reference users by ID)\n if (workspace.workspaceRules) {\n logTitle(\"Workspace Rules\");\n for (const workspaceRule of workspace.workspaceRules) {\n await createWorkspaceRule(workspaceRule);\n }\n }\n\n // ---------------------------------\n // GROUPS\n // ---------------------------------\n if (workspace.groups) {\n logTitle(\"Groups\");\n for (const group of workspace.groups) {\n await createGroup(group);\n }\n }\n\n // ---------------------------------\n // WHITELISTS\n // ---------------------------------\n if (workspace.whitelists) {\n logTitle(\"Whitelists\");\n await createWhitelists(workspace.whitelists);\n }\n\n // POLICIES\n // ---------------------------------\n if (workspace.policies) {\n logTitle(\"Policies\");\n for (const policy of workspace.policies) {\n await createPolicy(policy);\n }\n }\n\n // ---------------------------------\n // TRADELINK NETWORK\n // ---------------------------------\n if (workspace.tradelink) {\n logTitle(\"Tradelink\");\n await createTradelink(workspace.tradelink);\n }\n\n // ---------------------------------\n // ACCOUNTS\n // ---------------------------------\n if (workspace.accounts) {\n logTitle(\"Accounts\");\n for (const account of workspace.accounts) {\n await createAccount(account, workspace);\n }\n }\n\n async function createWhitelists(whitelists: ManifestWhitelist[]): Promise<void> {\n for (const whitelist of whitelists) {\n await createWhitelist(whitelist);\n }\n\n async function createWhitelist(whitelist: ManifestWhitelist): Promise<void> {\n const existing = existingWhitelists.find((w) => w.name === whitelist.name);\n\n // TODO: compare with existing to eventually do an EDIT\n if (existing) {\n logger.info(`[SKIPPED] Whitelist \"${whitelist.name}\" already exists`);\n return;\n }\n\n const input: CreateRequestInput = {\n type: \"CREATE_WHITELIST\",\n data: whitelist,\n };\n\n const req = await createAndApproveRequest(input, [admin1, admin2], logger);\n logSubStep(`Whitelist \"${whitelist.name}\" has been created`);\n\n const createdWhitelist = await admin1.client.whitelists.findById.query({ id: req.targetId! });\n existingWhitelists.push(createdWhitelist);\n }\n }\n\n function govRuleFromManifest(rule: ManifestGovernanceRule): GovRuleData {\n return {\n operationType: rule.type,\n reviewSteps: rule.steps.map((step) => {\n if (\"group\" in step) {\n return {\n quorum: step.quorum,\n groupId: groupIdFromName(step.group),\n };\n }\n return {\n quorum: step.quorum,\n userIds: step.members.map(userIdFromDeviceIndexOrName),\n };\n }),\n threshold: rule.threshold,\n whitelistIds: rule.whitelistNames?.map(whitelistIdFromName),\n };\n }\n\n function rawSigningRuleFromManifest(rule: ManifestRawSigningGovernanceRule) {\n return {\n operationType: rule.type as \"SIGN_DIGESTS\",\n // RAW_SIGNING only supports steps with userIds (no groups)\n reviewSteps: rule.steps.map((step) => ({\n quorum: step.quorum,\n userIds: step.members.map(userIdFromDeviceIndexOrName),\n })),\n };\n }\n\n async function createAccount(\n account: ManifestAccount,\n workspace: ManifestWorkspace,\n ): Promise<void> {\n let req: VaultRequestResponse | null = null;\n const existing = existingAccounts.find(\n (a) =>\n a.currency === account.currency &&\n a.index === account.index &&\n (a.contractAddress ?? null) === (account.contractAddress ?? null),\n );\n\n const governance =\n account.governance.type === \"TRADELINK\"\n ? {\n type: \"TRADELINK\" as const,\n assetManagerId: assetManagerIdFromName(account.governance.assetManager),\n exchangeConfigs: account.governance.exchanges.map((exchangeConfig) => ({\n exchangeId: exchangeIdFromName(exchangeConfig.name),\n repledgeAuthorized: exchangeConfig.repledgeAuthorized === true,\n needsAssetManagerApprovalForSettlements:\n exchangeConfig.needsAssetManagerApprovalForSettlements === true,\n })),\n }\n : account.governance.type === \"RAW_SIGNING\"\n ? {\n type: \"RAW_SIGNING\" as const,\n policy: { rules: account.governance.rules.map(rawSigningRuleFromManifest) },\n }\n : {\n type: \"CLASSIC\" as const,\n policy: { rules: account.governance.rules.map(govRuleFromManifest) },\n };\n\n const accountData = {\n name: account.name,\n currency: account.currency,\n contractAddress: account.contractAddress ?? null,\n tokenIdentifier: account.tokenIdentifier ?? null,\n index: account.index,\n governance,\n };\n\n const createInput: Extract<CreateRequestInput, { type: \"CREATE_ACCOUNT\" }> = {\n type: \"CREATE_ACCOUNT\",\n data: accountData,\n };\n\n if (existing) {\n const editInput: Extract<CreateRequestInput, { type: \"EDIT_ACCOUNT\" }> = {\n type: \"EDIT_ACCOUNT\",\n targetId: existing.id,\n data: { name: accountData.name, governance },\n };\n\n const previousAccountRequests = await admin1.client.requests.list.query({\n type: [\"CREATE_ACCOUNT\", \"EDIT_ACCOUNT\"],\n targetId: existing.id,\n state: \"EXECUTED\",\n sortBy: \"createdAt\",\n sortOrder: \"desc\",\n });\n\n // Check if account needs an update\n // Look for the last request that updated its state\n /* v8 ignore else -- @preserve */\n if (previousAccountRequests?.results && previousAccountRequests.results.length > 0) {\n const stateRequest = previousAccountRequests.results?.[0];\n invariant(\n stateRequest &&\n (stateRequest.type === \"EDIT_ACCOUNT\" || stateRequest.type === \"CREATE_ACCOUNT\"),\n \"State request should be an edit account request\",\n );\n\n // Compare the create request data with current account config\n if (\n _.isEqual(\n stripUndefinedDeep(accountData.governance),\n stripUndefinedDeep(stateRequest.data.governance),\n ) &&\n accountData.name === stateRequest.data.name\n ) {\n logger.info(`[SKIPPED] Account \"${account.name}\" has not changed`);\n await activateHederaAccount(account, workspace, existing.id);\n return;\n }\n\n // Account needs to be updated\n req = await createAndApproveRequest(editInput, [admin1, admin2], logger);\n logger.info(`[EDITED] Account \"${account.name}\" has been edited`);\n return;\n }\n } else {\n logStep(`Creating account \"${account.name}\"`);\n req = await createAndApproveRequest(createInput, [admin1, admin2], logger);\n\n const createdAccount = await admin1.client.accounts.findById.query({ id: req.targetId! });\n existingAccounts.push(createdAccount);\n }\n\n if (account.governance.type === \"TRADELINK\" && req) {\n logStep(`Activating tradelink account \"${account.name}\"`);\n // we need to activate the account with the asset manager\n const assetManagerId = assetManagerIdFromName(account.governance.assetManager);\n const assetManager = existingTradelinkNetwork?.assetManagers.find(\n (assetManager) => assetManager.id === assetManagerId,\n );\n invariant(assetManager, `Asset manager for account exists`);\n const loggedAssetManagerOperators = await Promise.all(\n assetManager.groups.flatMap(({ quorum, userIds }) =>\n userIds.slice(0, quorum).map((userId) => {\n const deviceIndex = usersWithDeviceIndex.find((o) => o.user.id === userId)?.deviceIndex;\n return workspaceEngine.withDeviceIndex(deviceIndex!).login();\n }),\n ),\n );\n await createAndApproveRequest(\n { type: \"TRADELINK_ACTIVATE_ACCOUNT\", targetId: req.targetId!, data: null },\n loggedAssetManagerOperators,\n logger,\n );\n }\n\n if (req?.targetId) {\n await activateHederaAccount(account, workspace, req.targetId);\n }\n\n logSubStep(`Account ${account.name} has been created`);\n }\n\n async function activateHederaAccount(\n account: ManifestAccount,\n workspace: ManifestWorkspace,\n accountId: string,\n ): Promise<void> {\n // Activate Hedera native account right after creation (before token accounts are created)\n // This ensures token accounts can be created within one Bake process\n if (\n account.currency === \"hedera\" &&\n account.contractAddress === undefined &&\n workspace.hederaData &&\n accountId\n ) {\n const salt = engine.__options.salt;\n const hederaAccountsForSalt = workspace.hederaData[salt];\n const hederaAccountData = hederaAccountsForSalt?.find(\n (h) => h.index === account.index && h.activate,\n );\n if (hederaAccountData) {\n try {\n await admin1.client.accounts.hedera.activateAccount.mutate({\n id: accountId,\n onchainId: hederaAccountData.onChainId,\n });\n logSubStep(`Hedera account \"${account.name}\" has been activated`);\n } catch (error) {\n logger.warning(`Activation for \"${account.name}\" failed: ${error}`);\n }\n }\n }\n }\n\n async function createUser(role: \"ADMIN\" | \"OPERATOR\", deviceIndex: number): Promise<void> {\n const userEngine = workspaceEngine.withDeviceIndex(deviceIndex);\n const deviceId = await userEngine.device.getDeviceUserId();\n\n // eventually check if we can skip user creation\n const existing = existingUsers.find((user) => user.deviceUserId === deviceId);\n if (existing) {\n logger.info(`[SKIPPED] User with device index ${deviceIndex} already exists`);\n return;\n }\n\n const name = `${role === \"ADMIN\" ? \"Admin\" : \"Operator\"} ${deviceIndex}`;\n logStep(`Creating ${name}`);\n\n logSubStep(\"Creating invitation...\");\n let registration = await admin1.client.userRegistrations.invite.mutate({\n name,\n role,\n deviceUserId: deviceId,\n psdModel: \"STAX\",\n });\n\n logSubStep(\"Completing registration...\");\n registration = await userEngine.register(registration);\n\n logSubStep(\"Creating request...\");\n let req = await admin1.client.requests.create.mutate({\n request: {\n type: \"CREATE_PSD_USER\",\n data: { registrationId: registration.id },\n },\n });\n\n req = await approveRequest(req, [admin1, admin2], logger);\n logSubStep(`${name} has been created`);\n\n const createdUser = await admin1.client.users.findById.query({ id: req.targetId! });\n\n // patch the current state with the newly created user\n existingUsers.push(createdUser);\n usersWithDeviceIndex.push({ user: createdUser, deviceIndex });\n }\n\n async function createApiUser(apiUser: ManifestApiUser): Promise<void> {\n const pubKey = apiUser.pubKey ?? genKeys(apiUser.name).hexPubKey;\n const existing = existingApiUsers.find(\n (user) => user.pubKey === pubKey || user.name === apiUser.name,\n );\n if (existing) {\n logger.info(\n `[SKIPPED] API user already exists with name \"${apiUser.name}\" or public key \"${pubKey}\"`,\n );\n return;\n }\n\n logStep(`Creating API user \"${apiUser.name}\"...`);\n\n logSubStep(\"Creating request...\");\n let req = await admin1.client.requests.create.mutate({\n request: {\n type: \"CREATE_API_USER\",\n data: {\n name: apiUser.name,\n role: apiUser.role,\n pubKey: pubKey,\n viewAll: apiUser.viewAll,\n },\n },\n });\n req = await approveRequest(req, [admin1, admin2], logger);\n logSubStep(`API user \"${apiUser.name}\" has been created`);\n\n logSubStep(\"Generating credentials...\");\n const credentials = await admin1.client.users.resetApiUserCredentials.mutate({\n id: req.targetId!,\n });\n logSubStep(\n `API user \"${apiUser.name}\" credentials have been generated: apiKeyId=${credentials.apiKeyId}, apiKeySecret=${credentials.apiKeySecret}`,\n );\n const createdUser = await admin1.client.users.findById.query({ id: req.targetId! });\n // patch the current state with the newly created user\n existingApiUsers.push(createdUser);\n }\n\n async function createGroup(group: ManifestGroup): Promise<void> {\n const existing = existingGroups.find((g) => g.name === group.name);\n if (existing) {\n logger.info(`[SKIPPED] Group \"${group.name}\" already exists`);\n return;\n }\n\n logStep(`Creating group ${group.name}...`);\n\n const members = group.members.map(userIdFromDeviceIndexOrName);\n\n logSubStep(\"Creating request...\");\n let request = await admin1.client.requests.create.mutate({\n request: {\n type: \"CREATE_GROUP\",\n data: {\n name: group.name,\n description: \"\",\n members,\n },\n },\n });\n\n request = await approveRequest(request, [admin1, admin2], logger);\n logSubStep(`${group.name} has been created`);\n\n const createdGroup = await admin1.client.groups.findById.query({ id: request.targetId! });\n existingGroups.push(createdGroup);\n }\n\n async function createPolicy(policy: ManifestPolicy): Promise<void> {\n const existing = existingPolicies.find((p) => p.name === policy.name);\n if (existing) {\n logger.info(`[SKIPPED] Policy \"${policy.name}\" already exists`);\n return;\n }\n\n logStep(`Creating policy ${policy.name}...`);\n\n logSubStep(\"Creating request...\");\n let request = await admin1.client.requests.create.mutate({\n request: {\n type: \"CREATE_POLICY\",\n data: {\n name: policy.name,\n currency: policy.currency,\n description: \"\",\n govRules: policy.rules.map(govRuleFromManifest),\n },\n },\n });\n\n request = await approveRequest(request, [admin1, admin2], logger);\n logSubStep(`${policy.name} has been created`);\n\n const createdPolicy = await admin1.client.policies.findById.query({ id: request.targetId! });\n existingPolicies.push(createdPolicy);\n }\n\n async function createWorkspaceRule(workspaceRule: ManifestWorkspaceRule): Promise<void> {\n const { permission, quorum, members } = workspaceRule;\n\n // Always edit/upsert workspace rule - EDIT_WORKSPACE_RULE creates if not exists, updates if exists\n logStep(`Editing workspace rule for ${permission}...`);\n\n // Resolve user IDs from device indexes or names\n const userIds = members.map(userIdFromDeviceIndexOrName);\n\n logSubStep(\"Creating request...\");\n const input: CreateRequestInput = {\n type: \"EDIT_WORKSPACE_RULE\",\n data: {\n permission,\n reviewConfig: [{ quorum, userIds }],\n },\n };\n\n await createAndApproveRequest(input, [admin1, admin2], logger);\n logSubStep(`Workspace rule for \"${permission}\" has been edited`);\n }\n\n async function createTradelink(tradelink: ManifestTradelinkNetwork): Promise<void> {\n /* v8 ignore else -- @preserve */\n if (tradelink.custodian) {\n if (existingTradelinkNetwork === null) {\n logStep(\"Creating custodian config...\");\n const { settlement, withdraw, arbitration } = tradelink.custodian;\n const data = {\n settlement: settlement.map(tradelinkReviewStepFromManifest),\n withdraw: withdraw.map(tradelinkReviewStepFromManifest),\n arbitration: arbitration.map(tradelinkReviewStepFromManifest),\n };\n\n logSubStep(\"Creating request...\");\n const request = await admin1.client.requests.create.mutate({\n request: {\n type: \"TRADELINK_CREATE_CUSTODIAN\",\n data,\n },\n });\n\n await approveRequest(request, [admin1, admin2], logger);\n logSubStep(\"Tradelink custodian config has been created\");\n\n existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();\n } else {\n logger.info(\"[SKIPPED] Custodian config already exists\");\n }\n\n const networkBlueprint = await admin1.client.tradelink.getNetworkBlueprint.query();\n if (networkBlueprint !== null) {\n /* v8 ignore else -- @preserve */\n if (tradelink.exchanges !== undefined) {\n await createTradelinkExchanges(networkBlueprint, tradelink.exchanges);\n }\n\n /* v8 ignore else -- @preserve */\n if (tradelink.assetManagers !== undefined) {\n await createTradelinkAssetManagers(networkBlueprint, tradelink.assetManagers);\n }\n } else {\n logger.error(\n \"Will not create exchanges and asset managers because there is no network blueprint for current workspace\",\n );\n }\n }\n }\n\n async function createTradelinkExchanges(\n networkBlueprint: TradelinkNetworkBlueprintResponse,\n exchanges: ManifestTradelinkEntity[],\n ): Promise<void> {\n invariant(existingTradelinkNetwork !== null, \"Network should exist\");\n const blueprintExchanges = networkBlueprint.exchanges;\n for (const exchange of exchanges) {\n // find uid\n const blueprintExchange = blueprintExchanges.find(({ name }) => name === exchange.name);\n invariant(\n blueprintExchange !== undefined,\n `Exchange ${exchange.name} does not exist in network blueprint`,\n );\n const exchangeId = blueprintExchange.tradelinkId;\n logStep(`Creating exchange ${exchange.name}...`);\n if (\n existingTradelinkNetwork.exchanges.find(({ tradelinkId }) => tradelinkId === exchangeId) !==\n undefined\n ) {\n logger.info(`[SKIPPED] Exchange \"${exchange.name}\" already exists`);\n continue;\n }\n\n logSubStep(\"Creating request...\");\n const request = await admin1.client.requests.create.mutate({\n request: {\n type: \"TRADELINK_CREATE_EXCHANGE\",\n data: {\n tradelinkId: exchangeId,\n groups: exchange.groups.map(tradelinkReviewStepFromManifest),\n whitelist: exchange.whitelist,\n },\n },\n });\n\n const loggedExchangeOperators = await Promise.all(\n exchange.groups.flatMap(({ quorum, members }) =>\n members\n .slice(0, quorum)\n .map((deviceIndex) => workspaceEngine.withDeviceIndex(deviceIndex).login()),\n ),\n );\n\n await approveRequest(request, [admin1, admin2, ...loggedExchangeOperators], logger);\n\n // refresh tradelink network\n existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();\n invariant(existingTradelinkNetwork !== null, \"Tradelink network exists\");\n }\n }\n\n async function createTradelinkAssetManagers(\n networkBlueprint: TradelinkNetworkBlueprintResponse,\n assetManagers: ManifestTradelinkEntity[],\n ): Promise<void> {\n invariant(existingTradelinkNetwork !== null, \"Network should exist\");\n const blueprintAssetManagers = networkBlueprint.assetManagers;\n for (const assetManager of assetManagers) {\n // find uid\n const blueprintAssetManager = blueprintAssetManagers.find(\n ({ name }) => name === assetManager.name,\n );\n invariant(\n blueprintAssetManager !== undefined,\n `AssetManager ${assetManager.name} does not exist in network blueprint`,\n );\n const assetManagerId = blueprintAssetManager.tradelinkId;\n logStep(`Creating assetManager ${assetManager.name}...`);\n if (\n existingTradelinkNetwork.assetManagers.find(\n ({ tradelinkId }) => tradelinkId === assetManagerId,\n ) !== undefined\n ) {\n logger.info(`[SKIPPED] Asset manager \"${assetManager.name}\" already exists`);\n continue;\n }\n\n logSubStep(\"Creating request...\");\n const request = await admin1.client.requests.create.mutate({\n request: {\n type: \"TRADELINK_CREATE_ASSET_MANAGER\",\n data: {\n tradelinkId: assetManagerId,\n groups: assetManager.groups.map(tradelinkReviewStepFromManifest),\n whitelist: assetManager.whitelist,\n },\n },\n });\n\n const loggedAssetManagerOperators = await Promise.all(\n assetManager.groups.flatMap(({ quorum, members }) =>\n members\n .slice(0, quorum)\n .map((deviceIndex) => workspaceEngine.withDeviceIndex(deviceIndex).login()),\n ),\n );\n\n await approveRequest(request, [admin1, admin2, ...loggedAssetManagerOperators], logger);\n\n // refresh tradelink network\n existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();\n invariant(existingTradelinkNetwork !== null, \"Tradelink network exists\");\n }\n }\n\n // For each given user, retrieve (by brute force) their device index, by comparing their\n // device user id with the one computed for each tested index.\n // Using .reduce() here to leverage caching existing discoveries\n async function resolveDevicesIndexes(\n users: UserResponse[],\n ): Promise<{ user: UserResponse; deviceIndex: number }[]> {\n const usersWithDeviceIndex = await users.reduce<\n Promise<{ user: UserResponse; deviceIndex: number }[]>\n >(\n (acc, cur) =>\n acc.then(async (acc) => {\n acc.push(await withDeviceIndex(cur));\n return acc;\n }),\n Promise.resolve([]),\n );\n return usersWithDeviceIndex;\n }\n\n async function withDeviceIndex(\n user: UserResponse,\n ): Promise<{ user: UserResponse; deviceIndex: number }> {\n invariant(user.deviceUserId, `User ${user.id} does not have any device user id`);\n const deviceIndex = await findDeviceIndex(user.deviceUserId);\n return { user, deviceIndex };\n }\n\n function userIdFromDeviceIndex(deviceIndex: number): string {\n const corresponding = usersWithDeviceIndex.find((o) => o.deviceIndex === deviceIndex);\n invariant(corresponding, `No user with device index ${deviceIndex}`);\n return corresponding.user.id;\n }\n\n function userIdFromUserName(name: string): string {\n const user = existingApiUsers.find((u) => u.name === name);\n invariant(user, `User ${name} not found`);\n return user.id;\n }\n\n function userIdFromDeviceIndexOrName(identifier: number | string): string {\n if (typeof identifier === \"number\") {\n return userIdFromDeviceIndex(identifier);\n }\n return userIdFromUserName(identifier);\n }\n\n function groupIdFromName(groupName: string): string {\n const group = existingGroups.find((g) => g.name === groupName);\n invariant(group, `Group ${groupName} not found`);\n return group.id;\n }\n\n function whitelistIdFromName(whitelistName: string): string {\n const whitelist = existingWhitelists.find((w) => w.name === whitelistName);\n invariant(whitelist, `Whitelist ${whitelistName} not found`);\n return whitelist.id;\n }\n\n function assetManagerIdFromName(assetManagerName: string): string {\n const orgAssetManager = tradelinkOrgAssetManagersByName[assetManagerName];\n invariant(\n orgAssetManager,\n `Can't find Tradelink organization asset manager ${assetManagerName}`,\n );\n const assetManager = existingTradelinkNetwork?.assetManagers.find(\n (assetManager) => assetManager.tradelinkId === orgAssetManager.tradelinkId,\n );\n invariant(assetManager, `Can't find Tradelink assetManager ${assetManagerName}`);\n return assetManager.id;\n }\n\n function exchangeIdFromName(exchangeName: string): string {\n const exchange = existingTradelinkNetwork?.exchanges.find((exchange) => {\n const orgExchange = tradelinkOrgExchangesByName[exchangeName];\n invariant(orgExchange, `Can't find Tradelink organization exchange ${exchange.tradelinkId}`);\n return orgExchange.name === exchangeName;\n });\n invariant(exchange, `Can't find Tradelink exchange ${exchangeName}`);\n return exchange.id;\n }\n\n function tradelinkReviewStepFromManifest({\n members,\n quorum,\n }: ManifestTradelinkGroup): ReviewStepWithUsers {\n return {\n userIds: members.map(userIdFromDeviceIndex),\n quorum,\n };\n }\n}\n","import z from \"zod\";\n\nimport type { Engine } from \"@/engine\";\n\n// #region ---------- General types ---------------------------------------------------------------\n\nexport type BakeOptions = {\n manifest: Manifest;\n engine: Engine;\n workspaceName?: string;\n rootAuthToken?: string;\n};\n\n// #endregion\n\n// #region ---------- Users -----------------------------------------------------------------------\n\nconst zManifestUser = z.number().meta({ description: \"User device index\" });\nconst zManifestUserName = z.string().meta({ description: \"User name\" });\nconst zManifestApiUser = z.object({\n name: z.string().meta({ description: \"API user name\" }),\n role: z.enum([\"ADMIN\", \"OPERATOR\"]).meta({ description: \"API user role\" }).default(\"OPERATOR\"),\n pubKey: z\n .string()\n .meta({\n description:\n \"API user public key. If not provided, one will be generated using the name as entropy\",\n })\n .optional(),\n viewAll: z.boolean().meta({ description: \"Whether the API user can view all accounts\" }),\n});\n\nexport type ManifestApiUser = z.infer<typeof zManifestApiUser>;\n\n// #endregion\n\n// #region ---------- Groups ----------------------------------------------------------------------\n\nconst zManifestGroup = z\n .object({\n name: z.string().meta({ description: \"Group name\" }),\n members: z\n .array(z.union([zManifestUser, zManifestUserName]))\n .meta({ description: \"Group members\" }),\n })\n .strict()\n .meta({ description: \"Operators group\" });\n\nexport type ManifestGroup = z.infer<typeof zManifestGroup>;\n\n// #endregion\n\n// #region ---------- Whitelists ------------------------------------------------------------------\n\nconst zManifestWhitelistAddress = z\n .object({\n name: z.string().meta({ description: \"Whitelist address name\" }),\n currency: z.string().meta({ description: \"Whitelist address currency\" }),\n address: z.string().meta({ description: \"Whitelist address\" }),\n destinationTags: z\n .array(z.string())\n .optional()\n .meta({ description: \"List of destination tags (applicable for Ripple currency)\" }),\n })\n .strict();\n\nconst zManifestWhitelist = z\n .object({\n name: z.string().meta({ description: \"Whitelist name\" }),\n description: z.string().optional().default(\"\").meta({ description: \"Whitelist description\" }),\n type: z\n .enum([\"TRANSACTION\", \"SMART_CONTRACT\"])\n .optional()\n .default(\"TRANSACTION\")\n .meta({ description: \"Whitelist type\" }),\n addresses: z.array(zManifestWhitelistAddress).meta({ description: \"Whitelist addresses\" }),\n })\n .strict()\n .meta({ description: \"Whitelist\" });\n\nexport type ManifestWhitelist = z.infer<typeof zManifestWhitelist>;\n\n// #endregion\n\n// #region ---------- Policies --------------------------------------------------------------------\n\nconst zManifestGovernanceStepWithUsers = z\n .object({\n quorum: z.number(),\n members: z.array(z.union([zManifestUser, zManifestUserName])),\n })\n .strict();\n\nconst zManifestGovernanceStepWithGroup = z\n .object({\n quorum: z.number(),\n group: z.string(),\n })\n .strict();\n\nconst zManifestGovernanceStep = z.union([\n zManifestGovernanceStepWithUsers,\n zManifestGovernanceStepWithGroup,\n]);\n\nconst zManifestGovernanceRule = z\n .object({\n // TODO see if there is a way to import this from `api` package\n // (the challenge there is that enums are not transpiled)\n type: z.enum([\n \"SEND\",\n \"STAKE\",\n \"DEPLOY_CONTRACT\",\n \"EXECUTE_CONTRACT\",\n \"SIGN_MESSAGE\",\n \"RECEIVE\",\n ]),\n steps: z.array(zManifestGovernanceStep).min(1),\n threshold: z\n .object({\n min: z.string(),\n max: z.string(),\n })\n .optional(),\n whitelistNames: z.array(z.string()).optional(),\n })\n .strict();\n\nexport type ManifestGovernanceRule = z.infer<typeof zManifestGovernanceRule>;\n\nexport const zManifestPolicy = z\n .object({\n name: z.string(),\n currency: z.string().nullable(),\n rules: z.array(zManifestGovernanceRule),\n })\n .strict();\n\nexport type ManifestPolicy = z.infer<typeof zManifestPolicy>;\n\n// #endregion\n\n// #region ---------- Accounts --------------------------------------------------------------------\n\nconst zManifestClassicAccountGovernance = z\n .object({\n type: z.literal(\"CLASSIC\"),\n rules: z.array(zManifestGovernanceRule),\n })\n .strict();\n\nconst zManifestTradelinkExchangeConfig = z\n .object({\n name: z.string().meta({ description: \"Exchange name\" }),\n repledgeAuthorized: z\n .boolean()\n .optional()\n .meta({ description: \"Whether repledge is authorized\" }),\n needsAssetManagerApprovalForSettlements: z\n .boolean()\n .optional()\n .meta({ description: \"Whether asset manager pre approval is needed\" }),\n })\n .strict();\n\nconst zManifestTradelinkAccountGovernance = z\n .object({\n type: z.literal(\"TRADELINK\"),\n assetManager: z.string().meta({ description: \"Asset manager name\" }),\n exchanges: z.array(zManifestTradelinkExchangeConfig),\n })\n .strict();\n\n// RAW_SIGNING only supports steps with users (no groups)\nconst zManifestRawSigningGovernanceRule = z\n .object({\n type: z.literal(\"SIGN_DIGESTS\"),\n steps: z.array(zManifestGovernanceStepWithUsers).min(1),\n })\n .strict();\n\nexport type ManifestRawSigningGovernanceRule = z.infer<typeof zManifestRawSigningGovernanceRule>;\n\nconst zManifestRawSigningAccountGovernance = z\n .object({\n type: z.literal(\"RAW_SIGNING\"),\n rules: z.array(zManifestRawSigningGovernanceRule),\n })\n .strict();\n\nconst zManifestAccountGovernance = z.discriminatedUnion(\"type\", [\n zManifestClassicAccountGovernance,\n zManifestTradelinkAccountGovernance,\n zManifestRawSigningAccountGovernance,\n]);\n\nconst zManifestAccount = z\n .object({\n name: z.string(),\n currency: z.string(),\n index: z.number().nonnegative(),\n contractAddress: z.string().optional(),\n tokenIdentifier: z.string().optional(),\n governance: zManifestAccountGovernance,\n })\n .strict();\n\nexport type ManifestAccount = z.infer<typeof zManifestAccount>;\n\n// #endregion\n\n// #region ---------- Hedera data ------------------------------------------------------------------\n\nconst zManifestHederaData = z\n .object({\n index: z.number(),\n onChainId: z.string(),\n activate: z.boolean().default(true),\n })\n .strict();\n\nexport type ManifestHederaData = z.infer<typeof zManifestHederaData>;\n\n// #endregion\n\n// #region ---------- Pledge adjustments (increment/decrement) ------------------------------------\n\nconst zManifestPledgeAdjustment = z\n .object({\n account: z.string(),\n exchange: z.string(),\n amount: z.string(),\n })\n .strict();\n\nexport type ManifestPledgeAdjustment = z.infer<typeof zManifestPledgeAdjustment>;\n\n// #endregion\n\n// #region ---------- Tradelink network -----------------------------------------------------------\n\nconst zManifestTradelinkGroup = z\n .object({\n members: z.array(zManifestUser),\n quorum: z.number(),\n })\n .strict()\n .meta({ description: \"Tradelink group\" });\n\nexport type ManifestTradelinkGroup = z.infer<typeof zManifestTradelinkGroup>;\n\nconst zManifestTradelinkGroups = z.array(zManifestTradelinkGroup);\n\nconst zManifestTradelinkWhitelistAddress = z\n .object({\n name: z.string().min(1),\n currency: z.string().min(1),\n address: z.string().min(1),\n })\n .strict()\n .meta({ description: \"Tradelink whitelist address\" });\n\nconst zManifestTradelinkWhitelist = z\n .array(zManifestTradelinkWhitelistAddress)\n .meta({ description: \"Tradelink whitelist\" });\n\nconst zManifestTradelinkEntity = z\n .object({\n name: z.string(),\n groups: zManifestTradelinkGroups,\n whitelist: zManifestTradelinkWhitelist,\n })\n .strict();\n\nexport type ManifestTradelinkEntity = z.infer<typeof zManifestTradelinkEntity>;\n\nconst zManifestTradelinkCustodian = z\n .object({\n settlement: zManifestTradelinkGroups,\n withdraw: zManifestTradelinkGroups,\n arbitration: zManifestTradelinkGroups,\n })\n .strict();\n\nconst zManifestTradelinkNetworkBlueprint = z\n .object({\n custodian: z.string(),\n exchanges: z.array(z.string()),\n assetManagers: z.array(z.string()),\n })\n .strict();\n\nexport type ManifestTradelinkNetworkBlueprint = z.infer<typeof zManifestTradelinkNetworkBlueprint>;\n\nconst zManifestTradelinkNetwork = z\n .object({\n networkBlueprint: zManifestTradelinkNetworkBlueprint.optional(),\n custodian: zManifestTradelinkCustodian.optional(),\n exchanges: z.array(zManifestTradelinkEntity).optional(),\n assetManagers: z.array(zManifestTradelinkEntity).optional(),\n })\n .strict()\n .meta({ description: \"Tradelink network configuration\" });\n\nexport type ManifestTradelinkNetwork = z.infer<typeof zManifestTradelinkNetwork>;\n\n// #endregion\n\n// #region ---------- Workspace rules -------------------------------------------------------------\n\nconst zManifestWorkspaceRule = z\n .object({\n permission: z.enum([\"CREATE_ACCOUNT_WITH_POLICY\"]),\n quorum: z.number().min(1),\n members: z.array(z.union([zManifestUser, zManifestUserName])),\n })\n .strict()\n .meta({ description: \"Workspace rule for granting permissions\" });\n\nexport type ManifestWorkspaceRule = z.infer<typeof zManifestWorkspaceRule>;\n\n// #endregion\n\n// #region ---------- Workspace -------------------------------------------------------------------\n\nconst zManifestWorkspace = z\n .object({\n tradelink: zManifestTradelinkNetwork.optional(),\n users: z\n .object({\n admins: z.array(zManifestUser).optional(),\n operators: z.array(zManifestUser).optional(),\n api: z.array(zManifestApiUser).optional(),\n })\n .optional(),\n groups: z.array(zManifestGroup).optional(),\n whitelists: z.array(zManifestWhitelist).optional(),\n policies: z.array(zManifestPolicy).optional(),\n accounts: z.array(zManifestAccount).optional(),\n hederaData: z.record(z.string(), z.array(zManifestHederaData)).optional(),\n pledges: z.array(zManifestPledgeAdjustment).optional(),\n workspaceRules: z.array(zManifestWorkspaceRule).optional(),\n })\n .strict()\n .meta({ description: \"Workspace configuration\" });\n\nexport type ManifestWorkspace = z.infer<typeof zManifestWorkspace>;\n\n// #endregion\n\n// #region ---------- Tradelink organization ------------------------------------------------------\n\nconst zManifestTradelinkOrgEntity = z\n .object({\n name: z.string(),\n code: z.string(),\n logo: z.string(),\n })\n .strict()\n .meta({ description: \"Tradelink organization entity\" });\n\nconst zManifestTradelinkOrg = z\n .object({\n exchanges: z.array(zManifestTradelinkOrgEntity).optional(),\n assetManagers: z.array(zManifestTradelinkOrgEntity).optional(),\n custodians: z.array(zManifestTradelinkOrgEntity).optional(),\n })\n .strict()\n .meta({ description: \"Tradelink organization configuration\" });\n\nexport type ManifestTradelinkOrg = z.infer<typeof zManifestTradelinkOrg>;\n\n// #endregion\n\n// #region ---------- Manifest --------------------------------------------------------------------\n\nexport const zManifest = z\n .object({\n manifestVersion: z.literal(2),\n tradelink: zManifestTradelinkOrg.optional(),\n workspace: zManifestWorkspace.optional(),\n })\n .strict();\n\nexport type Manifest = z.infer<typeof zManifest>;\n\n// #endregion\n"]}
1
+ {"version":3,"sources":["/home/runner/_work/revault/revault/packages/sdk/lib/bake.cjs","../src/bake/index.ts","../src/bake/bake-pledge.ts","../src/bake/utils.ts","../src/bake/bake-tradelink-organization.ts","../src/bake/bake-workspace.ts","../src/bake/types.ts"],"names":["blueprintExchange","invariant","assetManager","usersWithDeviceIndex","acc"],"mappings":"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","file":"/home/runner/_work/revault/revault/packages/sdk/lib/bake.cjs","sourcesContent":[null,"import invariant from \"invariant\";\n\nimport type { Logger } from \"@/logger\";\n\nimport { bakePledgeAdjustment } from \"./bake-pledge\";\nimport { bakeTradelinkOrganization } from \"./bake-tradelink-organization\";\nimport { bakeWorkspace } from \"./bake-workspace\";\nimport type { BakeOptions } from \"./types\";\n\nexport * from \"./bake-pledge\";\nexport * from \"./types\";\nexport { type CreateRequestInput, createAndApproveRequest } from \"./utils\";\n\nexport async function bakeManifest(options: BakeOptions, logger: Logger): Promise<void> {\n const {\n engine,\n workspaceName,\n rootAuthToken,\n manifest: { tradelink, workspace },\n } = options;\n\n if (tradelink) {\n invariant(rootAuthToken, `rootAuthToken is required to create Tradelink org entities`);\n await bakeTradelinkOrganization(\n {\n engine,\n tradelink,\n rootAuthToken,\n ...(workspace?.tradelink?.networkBlueprint && workspaceName\n ? { networkBlueprint: { blueprint: workspace.tradelink.networkBlueprint, workspaceName } }\n : {}),\n },\n logger,\n );\n }\n\n if (workspace) {\n invariant(workspaceName, `Can't bake workspace without specifying a workspace name`);\n await bakeWorkspace({ engine, workspace, workspaceName }, logger);\n\n if (workspace.pledges) {\n const engineWithWorkspace = engine.withWorkspace(workspaceName);\n for (const pledgeAdjustment of workspace.pledges) {\n await bakePledgeAdjustment({ engine: engineWithWorkspace, pledgeAdjustment }, logger);\n }\n }\n }\n\n logger.info(\"Successfully baked\");\n}\n","import invariant from \"invariant\";\n\nimport type { Engine, WithWorkspace } from \"@/engine\";\nimport type { Logger } from \"@/logger\";\nimport { createDeviceIndexResolver, fetchAll } from \"@/utils\";\n\nimport type { ManifestPledgeAdjustment } from \"./types\";\nimport { createAndApproveRequest } from \"./utils\";\n\ntype Options = {\n engine: Engine<WithWorkspace>;\n pledgeAdjustment: ManifestPledgeAdjustment;\n};\n\nconst flattenApprovers = (groups: { quorum: number; userIds: string[] }[]): string[] => {\n return groups.reduce<string[]>((acc, cur) => {\n acc.push(...cur.userIds.slice(0, cur.quorum));\n return acc;\n }, []);\n};\n\nexport async function bakePledgeAdjustment(options: Options, logger: Logger): Promise<void> {\n const { pledgeAdjustment, engine } = options;\n\n const getDeviceIndex = createDeviceIndexResolver(engine);\n\n logger.info(\"Logging in with admin...\");\n const admin = await engine.withDeviceIndex(4).login();\n\n logger.info(\"Fetching account, tradelink blueprint and network...\");\n const [matchingAccounts, blueprint, network] = await Promise.all([\n fetchAll(admin.client.accounts.list.query, { name: pledgeAdjustment.account }),\n admin.client.tradelink.getNetworkBlueprint.query(),\n admin.client.tradelink.getNetwork.query(),\n ]);\n\n const account = matchingAccounts.find((account) => account.name === pledgeAdjustment.account);\n invariant(account, `Account ${pledgeAdjustment.account} not found`);\n\n invariant(blueprint, \"Tradelink blueprint is not created yet\");\n invariant(network, \"Tradelink network is not created yet\");\n\n const exchange = network.exchanges.find((exchange) => {\n const blueprintExchange = blueprint.exchanges.find(\n (blueprintExchange) => blueprintExchange.tradelinkId === exchange.tradelinkId,\n );\n invariant(blueprintExchange, `Exchange ${exchange.tradelinkId} not found in blueprint`);\n return blueprintExchange.name === pledgeAdjustment.exchange;\n });\n invariant(exchange, `Exchange ${pledgeAdjustment.exchange} not found in network`);\n\n const governance = account.governance;\n invariant(governance.type === \"TRADELINK\", \"Account governance is not TRADELINK\");\n const assetManager = network.assetManagers.find((am) => am.id === governance.assetManagerId);\n invariant(assetManager, `Asset manager ${governance.assetManagerId} not found in network`);\n\n const exchangeIsConfiguredForAccount = !!governance.exchangeConfigs.find(\n (e) => e.exchangeId === exchange.id,\n );\n invariant(\n exchangeIsConfiguredForAccount,\n `Exchange ${exchange.id} is not configured for account ${account.id}`,\n );\n\n const approverIds = [\n ...flattenApprovers(assetManager.groups),\n ...flattenApprovers(exchange.groups),\n ];\n\n const approvers = await Promise.all(\n approverIds.map((id) =>\n admin.client.users.findById\n .query({ id })\n .then((user) => getDeviceIndex(user.deviceUserId!))\n .then((index) => engine.withDeviceIndex(index).login()),\n ),\n );\n\n await createAndApproveRequest(\n {\n type: \"TRADELINK_ADJUST_PLEDGE\",\n data: {\n accountId: account.id,\n exchangeId: exchange.id,\n amount: pledgeAdjustment.amount,\n },\n },\n approvers,\n logger,\n );\n\n logger.info(\n `Successfully adjusted pledge for account ${pledgeAdjustment.account} on exchange ${pledgeAdjustment.exchange}`,\n );\n}\n","import type { VaultRequestResponse } from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\n\nimport type { Engine, WithDevice, WithPsdAuth, WithWorkspace } from \"@/engine\";\nimport type { Logger } from \"@/logger\";\nimport type { RevaultApiTRPCClient, RouterInputs } from \"@/trpc\";\n\ntype LogFunction = (msg: string) => void;\n\ntype LogHelpers = {\n logTitle: LogFunction;\n logStep: LogFunction;\n logSubStep: LogFunction;\n};\n\nexport function createBakeLogHelpers(logger: Logger): LogHelpers {\n return {\n logTitle(title: string): void {\n logger.info(`:: ${title} ::`);\n },\n logStep(msg: string): void {\n logger.info(`=> ${msg}`);\n },\n logSubStep(msg: string): void {\n logger.info(` -> ${msg}`);\n },\n };\n}\n\nexport type CreateRequestInput = RouterInputs[\"requests\"][\"create\"][\"request\"];\n\nexport type inferRequestInputData<T extends RouterInputs[\"requests\"][\"create\"][\"request\"][\"type\"]> =\n Extract<RouterInputs[\"requests\"][\"create\"][\"request\"], { type: T }>[\"data\"];\n\nconst IS_REQUEST_STATE_END_STATE: Record<VaultRequestResponse[\"state\"], boolean> = {\n // end states:\n ABORTED: true,\n BLOCKED: true,\n EXECUTED: true,\n EXPIRED: true,\n FAILED: true,\n STUCK: true,\n // not end states:\n EXECUTING: false,\n INITIAL: false,\n PENDING_APPROVAL: false,\n};\n\nconst isEndState = (state: VaultRequestResponse[\"state\"]): boolean =>\n IS_REQUEST_STATE_END_STATE[state];\n\nconst DEFAULT_POLL_INTERVAL_MS = 250;\nconst DEFAULT_TIMEOUT_MS = 60_000;\n\nconst wait = (ms: number): Promise<void> => {\n return new Promise((resolve) => setTimeout(resolve, ms));\n};\n\n/**\n * Poll a request until it reaches a terminal state (EXECUTED, FAILED, etc.).\n *\n * Returns the request once it is no longer in EXECUTING/STUCK state.\n * Throws if the request reaches FAILED or STUCK state, or if the timeout is exceeded.\n */\nexport async function waitForRequestExecuted(\n client: RevaultApiTRPCClient,\n request: VaultRequestResponse,\n logger: Logger,\n options?: { pollIntervalMs?: number; timeoutMs?: number },\n): Promise<VaultRequestResponse> {\n const { logSubStep } = createBakeLogHelpers(logger);\n\n if (isEndState(request.state)) {\n if (request.state === \"EXECUTED\") {\n return request;\n }\n throw new Error(`Request is in error state ${request.state}`);\n }\n\n const pollIntervalMs = options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const deadline = Date.now() + timeoutMs;\n\n logSubStep(`Waiting for request to be executed...`);\n\n let updated = request;\n\n while (Date.now() < deadline) {\n await wait(pollIntervalMs);\n\n updated = await client.requests.findById.query({ id: request.id });\n if (isEndState(updated.state)) {\n if (updated.state === \"EXECUTED\") {\n return updated;\n }\n throw new Error(`Request is in error state ${updated.state}`);\n }\n }\n\n throw new Error(\n `Timed out waiting for request ${request.id} to reach a terminal state (last state: ${updated.state})`,\n );\n}\n\nexport async function approveRequest(\n request: VaultRequestResponse,\n approvers: Engine<WithWorkspace & WithDevice & WithPsdAuth>[],\n logger: Logger,\n): Promise<VaultRequestResponse> {\n const { logSubStep } = createBakeLogHelpers(logger);\n for (let i = 0; i < approvers.length; i++) {\n logSubStep(`Collecting approval (${i + 1}/${approvers.length})...`);\n const approver = approvers[i]!;\n request = await approver.approve(request);\n }\n return waitForRequestExecuted(approvers[0]!.client, request, logger);\n}\n\nexport async function createAndApproveRequest(\n input: CreateRequestInput,\n approvers: Engine<WithWorkspace & WithDevice & WithPsdAuth>[],\n logger: Logger,\n): Promise<VaultRequestResponse> {\n const { logSubStep } = createBakeLogHelpers(logger);\n const creator = approvers[0];\n invariant(creator, \"Need at least 1 user to create a request\");\n logSubStep(`Creating request of type ${input.type}...`);\n const request = await creator.client.requests.create.mutate({ request: input });\n return approveRequest(request, approvers, logger);\n}\n\nexport function stripUndefinedDeep<T>(obj: T): T {\n if (Array.isArray(obj)) {\n return obj.map(stripUndefinedDeep) as unknown as T;\n }\n\n if (obj && typeof obj === \"object\") {\n return Object.fromEntries(\n Object.entries(obj)\n .filter(([_, v]) => v !== undefined)\n .map(([k, v]) => [k, stripUndefinedDeep(v)]),\n ) as T;\n }\n\n return obj;\n}\n","import type { Logger } from \"@/logger\";\n\nimport type { BakeOptions, ManifestTradelinkNetworkBlueprint, ManifestTradelinkOrg } from \"./types\";\nimport { createBakeLogHelpers } from \"./utils\";\n\ntype Options = Omit<BakeOptions, \"manifest\" | \"rootAuthToken\"> & {\n tradelink: ManifestTradelinkOrg;\n rootAuthToken: string;\n networkBlueprint?: { workspaceName: string; blueprint: ManifestTradelinkNetworkBlueprint };\n};\n\nexport async function bakeTradelinkOrganization(options: Options, logger: Logger): Promise<void> {\n const { tradelink, engine, rootAuthToken, networkBlueprint } = options;\n\n const { logStep } = createBakeLogHelpers(logger);\n\n const rootClient = engine.createClient({ rootAuthToken });\n /* v8 ignore else - TODO bake empty tradelink org -- @preserve */\n if (tradelink.exchanges) {\n logStep(\"Creating Tradelink organization exchanges...\");\n const existingOrgExchanges = await rootClient.tradelink.root.listOrgExchanges.query();\n for (const orgExchange of tradelink.exchanges) {\n const existingOrgExchange = existingOrgExchanges.find((e) => e.name === orgExchange.name);\n if (existingOrgExchange) {\n logger.info(\n `[SKIPPED] Organization exchange ${existingOrgExchange.name} (${existingOrgExchange.code}) already exists`,\n );\n } else {\n await rootClient.tradelink.root.createOrgExchange.mutate({\n code: orgExchange.code,\n name: orgExchange.name,\n logoUrl: orgExchange.logo,\n });\n logger.info(`Created organization exchange ${orgExchange.name} (${orgExchange.code})`);\n }\n }\n }\n\n /* v8 ignore else -- @preserve */\n if (tradelink.assetManagers) {\n logStep(\"Creating Tradelink organization asset managers...\");\n const existingAssetManagers = await rootClient.tradelink.root.listOrgAssetManagers.query();\n for (const orgAssetManager of tradelink.assetManagers) {\n const existingOrgAssetManager = existingAssetManagers.find(\n (e) => e.name === orgAssetManager.name,\n );\n if (existingOrgAssetManager) {\n logger.info(\n `[SKIPPED] Organization asset manager ${existingOrgAssetManager.name} (${existingOrgAssetManager.code}) already exists`,\n );\n } else {\n await rootClient.tradelink.root.createOrgAssetManager.mutate({\n code: orgAssetManager.code,\n name: orgAssetManager.name,\n logoUrl: orgAssetManager.logo,\n });\n logger.info(\n `Created organization asset manager ${orgAssetManager.name} (${orgAssetManager.code})`,\n );\n }\n }\n }\n\n /* v8 ignore else -- @preserve */\n if (tradelink.custodians) {\n logStep(\"Creating Tradelink organization custodians...\");\n const existingCustodians = await rootClient.tradelink.root.listOrgCustodians.query();\n for (const orgCustodian of tradelink.custodians) {\n const existingOrgCustodian = existingCustodians.find((e) => e.name === orgCustodian.name);\n if (existingOrgCustodian) {\n logger.info(\n `[SKIPPED] Organization custodian ${existingOrgCustodian.name} (${existingOrgCustodian.code}) already exists`,\n );\n } else {\n await rootClient.tradelink.root.createOrgCustodian.mutate({\n code: orgCustodian.code,\n name: orgCustodian.name,\n logoUrl: orgCustodian.logo,\n });\n logger.info(`Created organization custodian ${orgCustodian.name} (${orgCustodian.code})`);\n }\n }\n }\n\n /* v8 ignore else -- @preserve */\n if (networkBlueprint) {\n logStep(\"Creating Tradelink network blueprint...\");\n const { workspaceName, blueprint } = networkBlueprint;\n const existingBlueprints = await rootClient.tradelink.root.listNetworkBlueprints.query();\n const existingBlueprint = existingBlueprints.find((e) => e.workspaceName === workspaceName);\n if (existingBlueprint) {\n logger.info(`[SKIPPED] Network blueprint for ${workspaceName} workspace already exists`);\n } else {\n await rootClient.tradelink.root.createNetworkBlueprint.mutate({\n workspaceName,\n custodian: { name: blueprint.custodian },\n exchanges: blueprint.exchanges.map((_) => ({ name: _ })),\n assetManagers: blueprint.assetManagers.map((_) => ({ name: _ })),\n });\n logger.info(`Created network blueprint for ${networkBlueprint.workspaceName} workspace`);\n }\n }\n}\n","import type {\n ReviewStepWithUsers,\n TradelinkNetworkBlueprintResponse,\n UserResponse,\n VaultRequestResponse,\n} from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\nimport _ from \"lodash\";\nimport { match } from \"ts-pattern\";\n\nimport { genKeys } from \"@/crypto\";\nimport type { Logger } from \"@/logger\";\nimport { createDeviceIndexResolver, fetchAll } from \"@/utils\";\n\nimport type {\n BakeOptions,\n ManifestAccount,\n ManifestApiUser,\n ManifestGovernanceRule,\n ManifestGroup,\n ManifestPolicy,\n ManifestRawSigningGovernanceRule,\n ManifestTradelinkEntity,\n ManifestTradelinkGroup,\n ManifestTradelinkNetwork,\n ManifestWhitelist,\n ManifestWorkspace,\n ManifestWorkspaceRule,\n} from \"./types\";\nimport {\n approveRequest,\n type CreateRequestInput,\n createAndApproveRequest,\n createBakeLogHelpers,\n type inferRequestInputData,\n stripUndefinedDeep,\n} from \"./utils\";\n\ntype GovRuleData = inferRequestInputData<\"CREATE_POLICY\">[\"govRules\"][number];\n\ntype Options = Omit<BakeOptions, \"manifest\" | \"workspaceName\"> & {\n workspace: ManifestWorkspace;\n workspaceName: string;\n};\n\nexport async function bakeWorkspace(options: Options, logger: Logger): Promise<void> {\n const { workspace, engine, workspaceName } = options;\n\n const workspaceEngine = engine.withWorkspace(workspaceName);\n const { logTitle, logStep, logSubStep } = createBakeLogHelpers(logger);\n\n // utility to retrieve device index based on device user id\n const findDeviceIndex = createDeviceIndexResolver(workspaceEngine);\n\n // Log-in once with the two admins (index 4 & 5 by convention) that will create all\n // the requests for the manifest objects.\n logger.info(\"Authenticating with two admins...\");\n const [admin1, admin2] = await Promise.all([\n workspaceEngine.withDeviceIndex(4).login(),\n workspaceEngine.withDeviceIndex(5).login(),\n ]);\n\n // Retrieve all existing data, so we are then able to skip creating stuff when not needed.\n logger.info(\"Fetching existing data...\");\n const [\n existingUsers,\n existingGroups,\n existingWhitelists,\n existingPolicies,\n existingAccounts,\n tradelinkNetworkBlueprint,\n ] = await Promise.all([\n fetchAll(admin1.client.users.list.query, { status: \"ACTIVE\" }),\n fetchAll(admin1.client.groups.list.query, { status: \"ACTIVE\" }),\n fetchAll(admin1.client.whitelists.list.query, { status: \"ACTIVE\" }),\n fetchAll(admin1.client.policies.list.query, { isPrivate: false }),\n fetchAll(admin1.client.accounts.list.query, { status: \"ACTIVE\" }),\n admin1.client.tradelink.getNetworkBlueprint.query(),\n ]);\n\n const tradelinkOrgExchangesByName = _.keyBy(tradelinkNetworkBlueprint?.exchanges, \"name\");\n const tradelinkOrgAssetManagersByName = _.keyBy(tradelinkNetworkBlueprint?.assetManagers, \"name\");\n\n let existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();\n\n // Merge admins & operators (we can't fetch all users in a row because we don't want API users,\n // and we don't have a way to retrieve both admins & operators in a single fetch)\n const existingPsdUsers = existingUsers.filter((user) => user.deviceType === \"PSD\");\n const existingApiUsers = existingUsers.filter((user) => user.deviceType === \"API\");\n // Retrieve all device indexes for the existing users\n const usersWithDeviceIndex = await resolveDevicesIndexes(existingPsdUsers);\n\n // ---------------------------------\n // USERS\n // ---------------------------------\n if (workspace.users) {\n logTitle(\"Users\");\n if (workspace.users.admins) {\n for (const deviceIndex of workspace.users.admins) {\n await createUser(\"ADMIN\", deviceIndex);\n }\n }\n\n /* v8 ignore else -- @preserve */\n if (workspace.users.operators) {\n for (const deviceIndex of workspace.users.operators) {\n await createUser(\"OPERATOR\", deviceIndex);\n }\n }\n if (workspace.users.api) {\n for (const apiUser of workspace.users.api) {\n await createApiUser(apiUser);\n }\n }\n }\n\n // ---------------------------------\n // WORKSPACE RULES\n // ---------------------------------\n // Must come after users are created (rules reference users by ID)\n if (workspace.workspaceRules) {\n logTitle(\"Workspace Rules\");\n for (const workspaceRule of workspace.workspaceRules) {\n await createWorkspaceRule(workspaceRule);\n }\n }\n\n // ---------------------------------\n // GROUPS\n // ---------------------------------\n if (workspace.groups) {\n logTitle(\"Groups\");\n for (const group of workspace.groups) {\n await createGroup(group);\n }\n }\n\n // ---------------------------------\n // WHITELISTS\n // ---------------------------------\n if (workspace.whitelists) {\n logTitle(\"Whitelists\");\n await createWhitelists(workspace.whitelists);\n }\n\n // POLICIES\n // ---------------------------------\n if (workspace.policies) {\n logTitle(\"Policies\");\n for (const policy of workspace.policies) {\n await createPolicy(policy);\n }\n }\n\n // ---------------------------------\n // TRADELINK NETWORK\n // ---------------------------------\n if (workspace.tradelink) {\n logTitle(\"Tradelink\");\n await createTradelink(workspace.tradelink);\n }\n\n // ---------------------------------\n // ACCOUNTS\n // ---------------------------------\n if (workspace.accounts) {\n logTitle(\"Accounts\");\n for (const account of workspace.accounts) {\n await createAccount(account, workspace);\n }\n }\n\n async function createWhitelists(whitelists: ManifestWhitelist[]): Promise<void> {\n for (const whitelist of whitelists) {\n await createWhitelist(whitelist);\n }\n\n async function createWhitelist(whitelist: ManifestWhitelist): Promise<void> {\n const existing = existingWhitelists.find((w) => w.name === whitelist.name);\n\n // TODO: compare with existing to eventually do an EDIT\n if (existing) {\n logger.info(`[SKIPPED] Whitelist \"${whitelist.name}\" already exists`);\n return;\n }\n\n const input: CreateRequestInput = {\n type: \"CREATE_WHITELIST\",\n data: whitelist,\n };\n\n const req = await createAndApproveRequest(input, [admin1, admin2], logger);\n logSubStep(`Whitelist \"${whitelist.name}\" has been created`);\n\n const createdWhitelist = await admin1.client.whitelists.findById.query({ id: req.targetId! });\n existingWhitelists.push(createdWhitelist);\n }\n }\n\n function govRuleFromManifest(rule: ManifestGovernanceRule): GovRuleData {\n return {\n operationType: rule.type,\n reviewSteps: rule.steps.map((step) => {\n if (\"group\" in step) {\n return {\n quorum: step.quorum,\n groupId: groupIdFromName(step.group),\n };\n }\n return {\n quorum: step.quorum,\n userIds: step.members.map(userIdFromDeviceIndexOrName),\n };\n }),\n threshold: rule.threshold,\n whitelistIds: rule.whitelistNames?.map(whitelistIdFromName),\n };\n }\n\n function rawSigningRuleFromManifest(rule: ManifestRawSigningGovernanceRule) {\n return {\n operationType: rule.type as \"SIGN_DIGESTS\",\n // RAW_SIGNING only supports steps with userIds (no groups)\n reviewSteps: rule.steps.map((step) => ({\n quorum: step.quorum,\n userIds: step.members.map(userIdFromDeviceIndexOrName),\n })),\n };\n }\n\n async function createAccount(\n account: ManifestAccount,\n workspace: ManifestWorkspace,\n ): Promise<void> {\n let req: VaultRequestResponse | null = null;\n const existing = existingAccounts.find(\n (a) =>\n a.currency === account.currency &&\n a.index === account.index &&\n (a.contractAddress ?? null) === (account.contractAddress ?? null),\n );\n\n const governance = match(account.governance)\n .with({ type: \"TRADELINK\" }, (gov) => ({\n type: \"TRADELINK\" as const,\n assetManagerId: assetManagerIdFromName(gov.assetManager),\n exchangeConfigs: gov.exchanges.map((exchangeConfig) => ({\n exchangeId: exchangeIdFromName(exchangeConfig.name),\n repledgeAuthorized: exchangeConfig.repledgeAuthorized === true,\n needsAssetManagerApprovalForSettlements:\n exchangeConfig.needsAssetManagerApprovalForSettlements === true,\n })),\n }))\n .with({ type: \"RAW_SIGNING\" }, (gov) => ({\n type: \"RAW_SIGNING\" as const,\n policy: { rules: gov.rules.map(rawSigningRuleFromManifest) },\n }))\n .with({ type: \"CLASSIC\" }, (gov) => ({\n type: \"CLASSIC\" as const,\n policy: { rules: gov.rules.map(govRuleFromManifest) },\n }))\n .with({ type: \"POLICY\" }, (gov) => ({\n type: \"CLASSIC\" as const,\n policy: { policyId: policyIdFromName(gov.policy) },\n }))\n .exhaustive();\n\n const accountData = {\n name: account.name,\n currency: account.currency,\n contractAddress: account.contractAddress ?? null,\n tokenIdentifier: account.tokenIdentifier ?? null,\n index: account.index,\n governance,\n };\n\n const createInput: Extract<CreateRequestInput, { type: \"CREATE_ACCOUNT\" }> = {\n type: \"CREATE_ACCOUNT\",\n data: accountData,\n };\n\n if (existing) {\n const editInput: Extract<CreateRequestInput, { type: \"EDIT_ACCOUNT\" }> = {\n type: \"EDIT_ACCOUNT\",\n targetId: existing.id,\n data: { name: accountData.name, governance },\n };\n\n const previousAccountRequests = await admin1.client.requests.list.query({\n type: [\"CREATE_ACCOUNT\", \"EDIT_ACCOUNT\"],\n targetId: existing.id,\n state: \"EXECUTED\",\n sortBy: \"createdAt\",\n sortOrder: \"desc\",\n });\n\n // Check if account needs an update\n // Look for the last request that updated its state\n /* v8 ignore else -- @preserve */\n if (previousAccountRequests?.results && previousAccountRequests.results.length > 0) {\n const stateRequest = previousAccountRequests.results?.[0];\n invariant(\n stateRequest &&\n (stateRequest.type === \"EDIT_ACCOUNT\" || stateRequest.type === \"CREATE_ACCOUNT\"),\n \"State request should be an edit account request\",\n );\n\n // Compare the create request data with current account config\n if (\n _.isEqual(\n stripUndefinedDeep(accountData.governance),\n stripUndefinedDeep(stateRequest.data.governance),\n ) &&\n accountData.name === stateRequest.data.name\n ) {\n logger.info(`[SKIPPED] Account \"${account.name}\" has not changed`);\n await activateHederaAccount(account, workspace, existing.id);\n return;\n }\n\n // Account needs to be updated\n req = await createAndApproveRequest(editInput, [admin1, admin2], logger);\n logger.info(`[EDITED] Account \"${account.name}\" has been edited`);\n return;\n }\n } else {\n logStep(`Creating account \"${account.name}\"`);\n req = await createAndApproveRequest(createInput, [admin1, admin2], logger);\n\n const createdAccount = await admin1.client.accounts.findById.query({ id: req.targetId! });\n existingAccounts.push(createdAccount);\n }\n\n if (account.governance.type === \"TRADELINK\" && req) {\n logStep(`Activating tradelink account \"${account.name}\"`);\n // we need to activate the account with the asset manager\n const assetManagerId = assetManagerIdFromName(account.governance.assetManager);\n const assetManager = existingTradelinkNetwork?.assetManagers.find(\n (assetManager) => assetManager.id === assetManagerId,\n );\n invariant(assetManager, `Asset manager for account exists`);\n const loggedAssetManagerOperators = await Promise.all(\n assetManager.groups.flatMap(({ quorum, userIds }) =>\n userIds.slice(0, quorum).map((userId) => {\n const deviceIndex = usersWithDeviceIndex.find((o) => o.user.id === userId)?.deviceIndex;\n return workspaceEngine.withDeviceIndex(deviceIndex!).login();\n }),\n ),\n );\n await createAndApproveRequest(\n { type: \"TRADELINK_ACTIVATE_ACCOUNT\", targetId: req.targetId!, data: null },\n loggedAssetManagerOperators,\n logger,\n );\n }\n\n if (req?.targetId) {\n await activateHederaAccount(account, workspace, req.targetId);\n }\n\n logSubStep(`Account ${account.name} has been created`);\n }\n\n async function activateHederaAccount(\n account: ManifestAccount,\n workspace: ManifestWorkspace,\n accountId: string,\n ): Promise<void> {\n // Activate Hedera native account right after creation (before token accounts are created)\n // This ensures token accounts can be created within one Bake process\n if (\n account.currency === \"hedera\" &&\n account.contractAddress === undefined &&\n workspace.hederaData &&\n accountId\n ) {\n const salt = engine.__options.salt;\n const hederaAccountsForSalt = workspace.hederaData[salt];\n const hederaAccountData = hederaAccountsForSalt?.find(\n (h) => h.index === account.index && h.activate,\n );\n if (hederaAccountData) {\n try {\n await admin1.client.accounts.hedera.activateAccount.mutate({\n id: accountId,\n onchainId: hederaAccountData.onChainId,\n });\n logSubStep(`Hedera account \"${account.name}\" has been activated`);\n } catch (error) {\n logger.warning(`Activation for \"${account.name}\" failed: ${error}`);\n }\n }\n }\n }\n\n async function createUser(role: \"ADMIN\" | \"OPERATOR\", deviceIndex: number): Promise<void> {\n const userEngine = workspaceEngine.withDeviceIndex(deviceIndex);\n const deviceId = await userEngine.device.getDeviceUserId();\n\n // eventually check if we can skip user creation\n const existing = existingUsers.find((user) => user.deviceUserId === deviceId);\n if (existing) {\n logger.info(`[SKIPPED] User with device index ${deviceIndex} already exists`);\n return;\n }\n\n const name = `${role === \"ADMIN\" ? \"Admin\" : \"Operator\"} ${deviceIndex}`;\n logStep(`Creating ${name}`);\n\n logSubStep(\"Creating invitation...\");\n let registration = await admin1.client.userRegistrations.invite.mutate({\n name,\n role,\n deviceUserId: deviceId,\n psdModel: \"STAX\",\n });\n\n logSubStep(\"Completing registration...\");\n registration = await userEngine.register(registration);\n\n logSubStep(\"Creating request...\");\n let req = await admin1.client.requests.create.mutate({\n request: {\n type: \"CREATE_PSD_USER\",\n data: { registrationId: registration.id },\n },\n });\n\n req = await approveRequest(req, [admin1, admin2], logger);\n logSubStep(`${name} has been created`);\n\n const createdUser = await admin1.client.users.findById.query({ id: req.targetId! });\n\n // patch the current state with the newly created user\n existingUsers.push(createdUser);\n usersWithDeviceIndex.push({ user: createdUser, deviceIndex });\n }\n\n async function createApiUser(apiUser: ManifestApiUser): Promise<void> {\n const pubKey = apiUser.pubKey ?? genKeys(apiUser.name).hexPubKey;\n const existing = existingApiUsers.find(\n (user) => user.pubKey === pubKey || user.name === apiUser.name,\n );\n if (existing) {\n logger.info(\n `[SKIPPED] API user already exists with name \"${apiUser.name}\" or public key \"${pubKey}\"`,\n );\n return;\n }\n\n logStep(`Creating API user \"${apiUser.name}\"...`);\n\n logSubStep(\"Creating request...\");\n let req = await admin1.client.requests.create.mutate({\n request: {\n type: \"CREATE_API_USER\",\n data: {\n name: apiUser.name,\n role: apiUser.role,\n pubKey: pubKey,\n viewAll: apiUser.viewAll,\n },\n },\n });\n req = await approveRequest(req, [admin1, admin2], logger);\n logSubStep(`API user \"${apiUser.name}\" has been created`);\n\n logSubStep(\"Generating credentials...\");\n const credentials = await admin1.client.users.resetApiUserCredentials.mutate({\n id: req.targetId!,\n });\n logSubStep(\n `API user \"${apiUser.name}\" credentials have been generated: apiKeyId=${credentials.apiKeyId}, apiKeySecret=${credentials.apiKeySecret}`,\n );\n const createdUser = await admin1.client.users.findById.query({ id: req.targetId! });\n // patch the current state with the newly created user\n existingApiUsers.push(createdUser);\n }\n\n async function createGroup(group: ManifestGroup): Promise<void> {\n const existing = existingGroups.find((g) => g.name === group.name);\n if (existing) {\n logger.info(`[SKIPPED] Group \"${group.name}\" already exists`);\n return;\n }\n\n logStep(`Creating group ${group.name}...`);\n\n const members = group.members.map(userIdFromDeviceIndexOrName);\n\n logSubStep(\"Creating request...\");\n let request = await admin1.client.requests.create.mutate({\n request: {\n type: \"CREATE_GROUP\",\n data: {\n name: group.name,\n description: \"\",\n members,\n },\n },\n });\n\n request = await approveRequest(request, [admin1, admin2], logger);\n logSubStep(`${group.name} has been created`);\n\n const createdGroup = await admin1.client.groups.findById.query({ id: request.targetId! });\n existingGroups.push(createdGroup);\n }\n\n async function createPolicy(policy: ManifestPolicy): Promise<void> {\n const existing = existingPolicies.find((p) => p.name === policy.name);\n if (existing) {\n logger.info(`[SKIPPED] Policy \"${policy.name}\" already exists`);\n return;\n }\n\n logStep(`Creating policy ${policy.name}...`);\n\n logSubStep(\"Creating request...\");\n let request = await admin1.client.requests.create.mutate({\n request: {\n type: \"CREATE_POLICY\",\n data: {\n name: policy.name,\n currency: policy.currency,\n description: \"\",\n govRules: policy.rules.map(govRuleFromManifest),\n },\n },\n });\n\n request = await approveRequest(request, [admin1, admin2], logger);\n logSubStep(`${policy.name} has been created`);\n\n const createdPolicy = await admin1.client.policies.findById.query({ id: request.targetId! });\n existingPolicies.push(createdPolicy);\n }\n\n async function createWorkspaceRule(workspaceRule: ManifestWorkspaceRule): Promise<void> {\n const { permission, quorum, members } = workspaceRule;\n\n // Always edit/upsert workspace rule - EDIT_WORKSPACE_RULE creates if not exists, updates if exists\n logStep(`Editing workspace rule for ${permission}...`);\n\n // Resolve user IDs from device indexes or names\n const userIds = members.map(userIdFromDeviceIndexOrName);\n\n logSubStep(\"Creating request...\");\n const input: CreateRequestInput = {\n type: \"EDIT_WORKSPACE_RULE\",\n data: {\n permission,\n reviewConfig: [{ quorum, userIds }],\n },\n };\n\n await createAndApproveRequest(input, [admin1, admin2], logger);\n logSubStep(`Workspace rule for \"${permission}\" has been edited`);\n }\n\n async function createTradelink(tradelink: ManifestTradelinkNetwork): Promise<void> {\n /* v8 ignore else -- @preserve */\n if (tradelink.custodian) {\n if (existingTradelinkNetwork === null) {\n logStep(\"Creating custodian config...\");\n const { settlement, withdraw, arbitration } = tradelink.custodian;\n const data = {\n settlement: settlement.map(tradelinkReviewStepFromManifest),\n withdraw: withdraw.map(tradelinkReviewStepFromManifest),\n arbitration: arbitration.map(tradelinkReviewStepFromManifest),\n };\n\n logSubStep(\"Creating request...\");\n const request = await admin1.client.requests.create.mutate({\n request: {\n type: \"TRADELINK_CREATE_CUSTODIAN\",\n data,\n },\n });\n\n await approveRequest(request, [admin1, admin2], logger);\n logSubStep(\"Tradelink custodian config has been created\");\n\n existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();\n } else {\n logger.info(\"[SKIPPED] Custodian config already exists\");\n }\n\n const networkBlueprint = await admin1.client.tradelink.getNetworkBlueprint.query();\n if (networkBlueprint !== null) {\n /* v8 ignore else -- @preserve */\n if (tradelink.exchanges !== undefined) {\n await createTradelinkExchanges(networkBlueprint, tradelink.exchanges);\n }\n\n /* v8 ignore else -- @preserve */\n if (tradelink.assetManagers !== undefined) {\n await createTradelinkAssetManagers(networkBlueprint, tradelink.assetManagers);\n }\n } else {\n logger.error(\n \"Will not create exchanges and asset managers because there is no network blueprint for current workspace\",\n );\n }\n }\n }\n\n async function createTradelinkExchanges(\n networkBlueprint: TradelinkNetworkBlueprintResponse,\n exchanges: ManifestTradelinkEntity[],\n ): Promise<void> {\n invariant(existingTradelinkNetwork !== null, \"Network should exist\");\n const blueprintExchanges = networkBlueprint.exchanges;\n for (const exchange of exchanges) {\n // find uid\n const blueprintExchange = blueprintExchanges.find(({ name }) => name === exchange.name);\n invariant(\n blueprintExchange !== undefined,\n `Exchange ${exchange.name} does not exist in network blueprint`,\n );\n const exchangeId = blueprintExchange.tradelinkId;\n logStep(`Creating exchange ${exchange.name}...`);\n if (\n existingTradelinkNetwork.exchanges.find(({ tradelinkId }) => tradelinkId === exchangeId) !==\n undefined\n ) {\n logger.info(`[SKIPPED] Exchange \"${exchange.name}\" already exists`);\n continue;\n }\n\n logSubStep(\"Creating request...\");\n const request = await admin1.client.requests.create.mutate({\n request: {\n type: \"TRADELINK_CREATE_EXCHANGE\",\n data: {\n tradelinkId: exchangeId,\n groups: exchange.groups.map(tradelinkReviewStepFromManifest),\n whitelist: exchange.whitelist,\n },\n },\n });\n\n const loggedExchangeOperators = await Promise.all(\n exchange.groups.flatMap(({ quorum, members }) =>\n members\n .slice(0, quorum)\n .map((deviceIndex) => workspaceEngine.withDeviceIndex(deviceIndex).login()),\n ),\n );\n\n await approveRequest(request, [admin1, admin2, ...loggedExchangeOperators], logger);\n\n // refresh tradelink network\n existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();\n invariant(existingTradelinkNetwork !== null, \"Tradelink network exists\");\n }\n }\n\n async function createTradelinkAssetManagers(\n networkBlueprint: TradelinkNetworkBlueprintResponse,\n assetManagers: ManifestTradelinkEntity[],\n ): Promise<void> {\n invariant(existingTradelinkNetwork !== null, \"Network should exist\");\n const blueprintAssetManagers = networkBlueprint.assetManagers;\n for (const assetManager of assetManagers) {\n // find uid\n const blueprintAssetManager = blueprintAssetManagers.find(\n ({ name }) => name === assetManager.name,\n );\n invariant(\n blueprintAssetManager !== undefined,\n `AssetManager ${assetManager.name} does not exist in network blueprint`,\n );\n const assetManagerId = blueprintAssetManager.tradelinkId;\n logStep(`Creating assetManager ${assetManager.name}...`);\n if (\n existingTradelinkNetwork.assetManagers.find(\n ({ tradelinkId }) => tradelinkId === assetManagerId,\n ) !== undefined\n ) {\n logger.info(`[SKIPPED] Asset manager \"${assetManager.name}\" already exists`);\n continue;\n }\n\n logSubStep(\"Creating request...\");\n const request = await admin1.client.requests.create.mutate({\n request: {\n type: \"TRADELINK_CREATE_ASSET_MANAGER\",\n data: {\n tradelinkId: assetManagerId,\n groups: assetManager.groups.map(tradelinkReviewStepFromManifest),\n whitelist: assetManager.whitelist,\n },\n },\n });\n\n const loggedAssetManagerOperators = await Promise.all(\n assetManager.groups.flatMap(({ quorum, members }) =>\n members\n .slice(0, quorum)\n .map((deviceIndex) => workspaceEngine.withDeviceIndex(deviceIndex).login()),\n ),\n );\n\n await approveRequest(request, [admin1, admin2, ...loggedAssetManagerOperators], logger);\n\n // refresh tradelink network\n existingTradelinkNetwork = await admin1.client.tradelink.getNetwork.query();\n invariant(existingTradelinkNetwork !== null, \"Tradelink network exists\");\n }\n }\n\n // For each given user, retrieve (by brute force) their device index, by comparing their\n // device user id with the one computed for each tested index.\n // Using .reduce() here to leverage caching existing discoveries\n async function resolveDevicesIndexes(\n users: UserResponse[],\n ): Promise<{ user: UserResponse; deviceIndex: number }[]> {\n const usersWithDeviceIndex = await users.reduce<\n Promise<{ user: UserResponse; deviceIndex: number }[]>\n >(\n (acc, cur) =>\n acc.then(async (acc) => {\n acc.push(await withDeviceIndex(cur));\n return acc;\n }),\n Promise.resolve([]),\n );\n return usersWithDeviceIndex;\n }\n\n async function withDeviceIndex(\n user: UserResponse,\n ): Promise<{ user: UserResponse; deviceIndex: number }> {\n invariant(user.deviceUserId, `User ${user.id} does not have any device user id`);\n const deviceIndex = await findDeviceIndex(user.deviceUserId);\n return { user, deviceIndex };\n }\n\n function userIdFromDeviceIndex(deviceIndex: number): string {\n const corresponding = usersWithDeviceIndex.find((o) => o.deviceIndex === deviceIndex);\n invariant(corresponding, `No user with device index ${deviceIndex}`);\n return corresponding.user.id;\n }\n\n function userIdFromUserName(name: string): string {\n const user = existingApiUsers.find((u) => u.name === name);\n invariant(user, `User ${name} not found`);\n return user.id;\n }\n\n function userIdFromDeviceIndexOrName(identifier: number | string): string {\n if (typeof identifier === \"number\") {\n return userIdFromDeviceIndex(identifier);\n }\n return userIdFromUserName(identifier);\n }\n\n function groupIdFromName(groupName: string): string {\n const group = existingGroups.find((g) => g.name === groupName);\n invariant(group, `Group ${groupName} not found`);\n return group.id;\n }\n\n function policyIdFromName(policyName: string): string {\n const policy = existingPolicies.find((g) => g.name === policyName);\n invariant(policy, `Policy ${policyName} not found`);\n return policy.id;\n }\n\n function whitelistIdFromName(whitelistName: string): string {\n const whitelist = existingWhitelists.find((w) => w.name === whitelistName);\n invariant(whitelist, `Whitelist ${whitelistName} not found`);\n return whitelist.id;\n }\n\n function assetManagerIdFromName(assetManagerName: string): string {\n const orgAssetManager = tradelinkOrgAssetManagersByName[assetManagerName];\n invariant(\n orgAssetManager,\n `Can't find Tradelink organization asset manager ${assetManagerName}`,\n );\n const assetManager = existingTradelinkNetwork?.assetManagers.find(\n (assetManager) => assetManager.tradelinkId === orgAssetManager.tradelinkId,\n );\n invariant(assetManager, `Can't find Tradelink assetManager ${assetManagerName}`);\n return assetManager.id;\n }\n\n function exchangeIdFromName(exchangeName: string): string {\n const exchange = existingTradelinkNetwork?.exchanges.find((exchange) => {\n const orgExchange = tradelinkOrgExchangesByName[exchangeName];\n invariant(orgExchange, `Can't find Tradelink organization exchange ${exchange.tradelinkId}`);\n return orgExchange.name === exchangeName;\n });\n invariant(exchange, `Can't find Tradelink exchange ${exchangeName}`);\n return exchange.id;\n }\n\n function tradelinkReviewStepFromManifest({\n members,\n quorum,\n }: ManifestTradelinkGroup): ReviewStepWithUsers {\n return {\n userIds: members.map(userIdFromDeviceIndex),\n quorum,\n };\n }\n}\n","import z from \"zod\";\n\nimport type { Engine } from \"@/engine\";\n\n// #region ---------- General types ---------------------------------------------------------------\n\nexport type BakeOptions = {\n manifest: Manifest;\n engine: Engine;\n workspaceName?: string;\n rootAuthToken?: string;\n};\n\n// #endregion\n\n// #region ---------- Users -----------------------------------------------------------------------\n\nconst zManifestUser = z.number().meta({ description: \"User device index\" });\nconst zManifestUserName = z.string().meta({ description: \"User name\" });\nconst zManifestApiUser = z.object({\n name: z.string().meta({ description: \"API user name\" }),\n role: z.enum([\"ADMIN\", \"OPERATOR\"]).meta({ description: \"API user role\" }).default(\"OPERATOR\"),\n pubKey: z\n .string()\n .meta({\n description:\n \"API user public key. If not provided, one will be generated using the name as entropy\",\n })\n .optional(),\n viewAll: z.boolean().meta({ description: \"Whether the API user can view all accounts\" }),\n});\n\nexport type ManifestApiUser = z.infer<typeof zManifestApiUser>;\n\n// #endregion\n\n// #region ---------- Groups ----------------------------------------------------------------------\n\nconst zManifestGroup = z\n .object({\n name: z.string().meta({ description: \"Group name\" }),\n members: z\n .array(z.union([zManifestUser, zManifestUserName]))\n .meta({ description: \"Group members\" }),\n })\n .strict()\n .meta({ description: \"Operators group\" });\n\nexport type ManifestGroup = z.infer<typeof zManifestGroup>;\n\n// #endregion\n\n// #region ---------- Whitelists ------------------------------------------------------------------\n\nconst zManifestWhitelistAddress = z\n .object({\n name: z.string().meta({ description: \"Whitelist address name\" }),\n currency: z.string().meta({ description: \"Whitelist address currency\" }),\n address: z.string().meta({ description: \"Whitelist address\" }),\n destinationTags: z\n .array(z.string())\n .optional()\n .meta({ description: \"List of destination tags (applicable for Ripple currency)\" }),\n })\n .strict();\n\nconst zManifestWhitelist = z\n .object({\n name: z.string().meta({ description: \"Whitelist name\" }),\n description: z.string().optional().default(\"\").meta({ description: \"Whitelist description\" }),\n type: z\n .enum([\"TRANSACTION\", \"SMART_CONTRACT\"])\n .optional()\n .default(\"TRANSACTION\")\n .meta({ description: \"Whitelist type\" }),\n addresses: z.array(zManifestWhitelistAddress).meta({ description: \"Whitelist addresses\" }),\n })\n .strict()\n .meta({ description: \"Whitelist\" });\n\nexport type ManifestWhitelist = z.infer<typeof zManifestWhitelist>;\n\n// #endregion\n\n// #region ---------- Policies --------------------------------------------------------------------\n\nconst zManifestGovernanceStepWithUsers = z\n .object({\n quorum: z.number(),\n members: z.array(z.union([zManifestUser, zManifestUserName])),\n })\n .strict();\n\nconst zManifestGovernanceStepWithGroup = z\n .object({\n quorum: z.number(),\n group: z.string(),\n })\n .strict();\n\nconst zManifestGovernanceStep = z.union([\n zManifestGovernanceStepWithUsers,\n zManifestGovernanceStepWithGroup,\n]);\n\nconst zManifestGovernanceRule = z\n .object({\n // TODO see if there is a way to import this from `api` package\n // (the challenge there is that enums are not transpiled)\n type: z.enum([\n \"SEND\",\n \"STAKE\",\n \"DEPLOY_CONTRACT\",\n \"EXECUTE_CONTRACT\",\n \"SIGN_MESSAGE\",\n \"RECEIVE\",\n ]),\n steps: z.array(zManifestGovernanceStep).min(1),\n threshold: z\n .object({\n min: z.string(),\n max: z.string(),\n })\n .optional(),\n whitelistNames: z.array(z.string()).optional(),\n })\n .strict();\n\nexport type ManifestGovernanceRule = z.infer<typeof zManifestGovernanceRule>;\n\nexport const zManifestPolicy = z\n .object({\n name: z.string(),\n currency: z.string().nullable(),\n rules: z.array(zManifestGovernanceRule),\n })\n .strict();\n\nexport type ManifestPolicy = z.infer<typeof zManifestPolicy>;\n\n// #endregion\n\n// #region ---------- Accounts --------------------------------------------------------------------\n\nconst zManifestClassicAccountGovernance = z\n .object({\n type: z.literal(\"CLASSIC\"),\n rules: z.array(zManifestGovernanceRule),\n })\n .strict();\n\nconst zManifestClassicAccountGovernanceWithPolicy = z\n .object({\n type: z.literal(\"POLICY\"),\n policy: z.string(),\n })\n .strict();\n\nconst zManifestTradelinkExchangeConfig = z\n .object({\n name: z.string().meta({ description: \"Exchange name\" }),\n repledgeAuthorized: z\n .boolean()\n .optional()\n .meta({ description: \"Whether repledge is authorized\" }),\n needsAssetManagerApprovalForSettlements: z\n .boolean()\n .optional()\n .meta({ description: \"Whether asset manager pre approval is needed\" }),\n })\n .strict();\n\nconst zManifestTradelinkAccountGovernance = z\n .object({\n type: z.literal(\"TRADELINK\"),\n assetManager: z.string().meta({ description: \"Asset manager name\" }),\n exchanges: z.array(zManifestTradelinkExchangeConfig),\n })\n .strict();\n\n// RAW_SIGNING only supports steps with users (no groups)\nconst zManifestRawSigningGovernanceRule = z\n .object({\n type: z.literal(\"SIGN_DIGESTS\"),\n steps: z.array(zManifestGovernanceStepWithUsers).min(1),\n })\n .strict();\n\nexport type ManifestRawSigningGovernanceRule = z.infer<typeof zManifestRawSigningGovernanceRule>;\n\nconst zManifestRawSigningAccountGovernance = z\n .object({\n type: z.literal(\"RAW_SIGNING\"),\n rules: z.array(zManifestRawSigningGovernanceRule),\n })\n .strict();\n\nconst zManifestAccountGovernance = z.discriminatedUnion(\"type\", [\n zManifestClassicAccountGovernance,\n zManifestTradelinkAccountGovernance,\n zManifestRawSigningAccountGovernance,\n zManifestClassicAccountGovernanceWithPolicy,\n]);\n\nconst zManifestAccount = z\n .object({\n name: z.string(),\n currency: z.string(),\n index: z.number().nonnegative(),\n contractAddress: z.string().optional(),\n tokenIdentifier: z.string().optional(),\n governance: zManifestAccountGovernance,\n })\n .strict();\n\nexport type ManifestAccount = z.infer<typeof zManifestAccount>;\n\n// #endregion\n\n// #region ---------- Hedera data ------------------------------------------------------------------\n\nconst zManifestHederaData = z\n .object({\n index: z.number(),\n onChainId: z.string(),\n activate: z.boolean().default(true),\n })\n .strict();\n\nexport type ManifestHederaData = z.infer<typeof zManifestHederaData>;\n\n// #endregion\n\n// #region ---------- Pledge adjustments (increment/decrement) ------------------------------------\n\nconst zManifestPledgeAdjustment = z\n .object({\n account: z.string(),\n exchange: z.string(),\n amount: z.string(),\n })\n .strict();\n\nexport type ManifestPledgeAdjustment = z.infer<typeof zManifestPledgeAdjustment>;\n\n// #endregion\n\n// #region ---------- Tradelink network -----------------------------------------------------------\n\nconst zManifestTradelinkGroup = z\n .object({\n members: z.array(zManifestUser),\n quorum: z.number(),\n })\n .strict()\n .meta({ description: \"Tradelink group\" });\n\nexport type ManifestTradelinkGroup = z.infer<typeof zManifestTradelinkGroup>;\n\nconst zManifestTradelinkGroups = z.array(zManifestTradelinkGroup);\n\nconst zManifestTradelinkWhitelistAddress = z\n .object({\n name: z.string().min(1),\n currency: z.string().min(1),\n address: z.string().min(1),\n })\n .strict()\n .meta({ description: \"Tradelink whitelist address\" });\n\nconst zManifestTradelinkWhitelist = z\n .array(zManifestTradelinkWhitelistAddress)\n .meta({ description: \"Tradelink whitelist\" });\n\nconst zManifestTradelinkEntity = z\n .object({\n name: z.string(),\n groups: zManifestTradelinkGroups,\n whitelist: zManifestTradelinkWhitelist,\n })\n .strict();\n\nexport type ManifestTradelinkEntity = z.infer<typeof zManifestTradelinkEntity>;\n\nconst zManifestTradelinkCustodian = z\n .object({\n settlement: zManifestTradelinkGroups,\n withdraw: zManifestTradelinkGroups,\n arbitration: zManifestTradelinkGroups,\n })\n .strict();\n\nconst zManifestTradelinkNetworkBlueprint = z\n .object({\n custodian: z.string(),\n exchanges: z.array(z.string()),\n assetManagers: z.array(z.string()),\n })\n .strict();\n\nexport type ManifestTradelinkNetworkBlueprint = z.infer<typeof zManifestTradelinkNetworkBlueprint>;\n\nconst zManifestTradelinkNetwork = z\n .object({\n networkBlueprint: zManifestTradelinkNetworkBlueprint.optional(),\n custodian: zManifestTradelinkCustodian.optional(),\n exchanges: z.array(zManifestTradelinkEntity).optional(),\n assetManagers: z.array(zManifestTradelinkEntity).optional(),\n })\n .strict()\n .meta({ description: \"Tradelink network configuration\" });\n\nexport type ManifestTradelinkNetwork = z.infer<typeof zManifestTradelinkNetwork>;\n\n// #endregion\n\n// #region ---------- Workspace rules -------------------------------------------------------------\n\nconst zManifestWorkspaceRule = z\n .object({\n permission: z.enum([\"CREATE_ACCOUNT_WITH_POLICY\"]),\n quorum: z.number().min(1),\n members: z.array(z.union([zManifestUser, zManifestUserName])),\n })\n .strict()\n .meta({ description: \"Workspace rule for granting permissions\" });\n\nexport type ManifestWorkspaceRule = z.infer<typeof zManifestWorkspaceRule>;\n\n// #endregion\n\n// #region ---------- Workspace -------------------------------------------------------------------\n\nconst zManifestWorkspace = z\n .object({\n tradelink: zManifestTradelinkNetwork.optional(),\n users: z\n .object({\n admins: z.array(zManifestUser).optional(),\n operators: z.array(zManifestUser).optional(),\n api: z.array(zManifestApiUser).optional(),\n })\n .optional(),\n groups: z.array(zManifestGroup).optional(),\n whitelists: z.array(zManifestWhitelist).optional(),\n policies: z.array(zManifestPolicy).optional(),\n accounts: z.array(zManifestAccount).optional(),\n hederaData: z.record(z.string(), z.array(zManifestHederaData)).optional(),\n pledges: z.array(zManifestPledgeAdjustment).optional(),\n workspaceRules: z.array(zManifestWorkspaceRule).optional(),\n })\n .strict()\n .meta({ description: \"Workspace configuration\" });\n\nexport type ManifestWorkspace = z.infer<typeof zManifestWorkspace>;\n\n// #endregion\n\n// #region ---------- Tradelink organization ------------------------------------------------------\n\nconst zManifestTradelinkOrgEntity = z\n .object({\n name: z.string(),\n code: z.string(),\n logo: z.string(),\n })\n .strict()\n .meta({ description: \"Tradelink organization entity\" });\n\nconst zManifestTradelinkOrg = z\n .object({\n exchanges: z.array(zManifestTradelinkOrgEntity).optional(),\n assetManagers: z.array(zManifestTradelinkOrgEntity).optional(),\n custodians: z.array(zManifestTradelinkOrgEntity).optional(),\n })\n .strict()\n .meta({ description: \"Tradelink organization configuration\" });\n\nexport type ManifestTradelinkOrg = z.infer<typeof zManifestTradelinkOrg>;\n\n// #endregion\n\n// #region ---------- Manifest --------------------------------------------------------------------\n\nexport const zManifest = z\n .object({\n manifestVersion: z.literal(2),\n tradelink: zManifestTradelinkOrg.optional(),\n workspace: zManifestWorkspace.optional(),\n })\n .strict();\n\nexport type Manifest = z.infer<typeof zManifest>;\n\n// #endregion\n"]}
package/lib/bake.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { L as Logger } from './logger-C-TPbnjv.cjs';
2
2
  import z from 'zod';
3
- import { E as Engine, f as WithWorkspace, c as WithDevice, l as WithPsdAuth } from './types-mF8XT2Vl.cjs';
3
+ import { E as Engine, n as WithWorkspace, l as WithDevice, m as WithPsdAuth } from './types-6nV5J9yp.cjs';
4
4
  import { VaultRequestResponse } from '@ledgerhq/revault-api';
5
5
  import { a as RouterInputs } from './types-CpGEbAxh.cjs';
6
6
  import './types-DJfbanPz.cjs';
@@ -148,6 +148,9 @@ declare const zManifestAccount: z.ZodObject<{
148
148
  members: z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
149
149
  }, z.core.$strict>>;
150
150
  }, z.core.$strict>>;
151
+ }, z.core.$strict>, z.ZodObject<{
152
+ type: z.ZodLiteral<"POLICY">;
153
+ policy: z.ZodString;
151
154
  }, z.core.$strict>], "type">;
152
155
  }, z.core.$strict>;
153
156
  type ManifestAccount = z.infer<typeof zManifestAccount>;
@@ -391,6 +394,9 @@ declare const zManifestWorkspace: z.ZodObject<{
391
394
  members: z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
392
395
  }, z.core.$strict>>;
393
396
  }, z.core.$strict>>;
397
+ }, z.core.$strict>, z.ZodObject<{
398
+ type: z.ZodLiteral<"POLICY">;
399
+ policy: z.ZodString;
394
400
  }, z.core.$strict>], "type">;
395
401
  }, z.core.$strict>>>;
396
402
  hederaData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodObject<{
@@ -599,6 +605,9 @@ declare const zManifest: z.ZodObject<{
599
605
  members: z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
600
606
  }, z.core.$strict>>;
601
607
  }, z.core.$strict>>;
608
+ }, z.core.$strict>, z.ZodObject<{
609
+ type: z.ZodLiteral<"POLICY">;
610
+ policy: z.ZodString;
602
611
  }, z.core.$strict>], "type">;
603
612
  }, z.core.$strict>>>;
604
613
  hederaData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodObject<{