@ledgerhq/revault-sdk 0.12.2 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/bake.cjs CHANGED
@@ -394,19 +394,22 @@ async function bakeWorkspace(options, logger) {
394
394
  }
395
395
  const name = `${role === "ADMIN" ? "Admin" : "Operator"} ${deviceIndex}`;
396
396
  logStep(`Creating ${name}`);
397
+ logSubStep("Creating invitation...");
398
+ let registration = await admin1.client.users.inviteNewUser.mutate({
399
+ name,
400
+ role,
401
+ deviceUserId: deviceId,
402
+ psdModel: "STAX"
403
+ });
404
+ logSubStep("Completing registration...");
405
+ registration = await userEngine.register(registration);
397
406
  logSubStep("Creating request...");
398
407
  let req = await admin1.client.requests.create.mutate({
399
408
  request: {
400
- type: role === "ADMIN" ? "CREATE_ADMIN" : "CREATE_OPERATOR",
401
- data: {
402
- deviceUserId: deviceId,
403
- name,
404
- deviceType: "PSD"
405
- }
409
+ type: "CREATE_PSD_USER",
410
+ data: { registrationId: registration.id }
406
411
  }
407
412
  });
408
- logSubStep("Registering user...");
409
- req = await userEngine.register({ requestId: req.id, name, role });
410
413
  req = await approveRequest(req, [admin1, admin2], logger);
411
414
  logSubStep(`${name} has been created`);
412
415
  const createdUser = await admin1.client.users.findById.query({ id: req.targetId });
@@ -638,27 +641,27 @@ var zManifestUser = _zod2.default.number().describe("User device index");
638
641
  var zManifestGroup = _zod2.default.object({
639
642
  name: _zod2.default.string().describe("Group name"),
640
643
  members: _zod2.default.array(zManifestUser).describe("Group members")
641
- }).describe("Operators group");
644
+ }).strict().describe("Operators group");
642
645
  var zManifestWhitelistAddress = _zod2.default.object({
643
646
  name: _zod2.default.string().describe("Whitelist address name"),
644
647
  currency: _zod2.default.string().describe("Whitelist address currency"),
645
648
  address: _zod2.default.string().describe("Whitelist address"),
646
649
  destinationTags: _zod2.default.array(_zod2.default.string()).optional().describe("List of destination tags (applicable for Ripple currency)")
647
- });
650
+ }).strict();
648
651
  var zManifestWhitelist = _zod2.default.object({
649
652
  name: _zod2.default.string().describe("Whitelist name"),
650
653
  description: _zod2.default.string().optional().default("").describe("Whitelist description"),
651
654
  type: _zod2.default.enum(["TRANSACTION", "SMART_CONTRACT"]).optional().default("TRANSACTION").describe("Whitelist type"),
652
655
  addresses: _zod2.default.array(zManifestWhitelistAddress).describe("Whitelist addresses")
653
- }).describe("Whitelist");
656
+ }).strict().describe("Whitelist");
654
657
  var zManifestGovernanceStepWithUsers = _zod2.default.object({
655
658
  quorum: _zod2.default.number(),
656
659
  members: _zod2.default.array(zManifestUser)
657
- });
660
+ }).strict();
658
661
  var zManifestGovernanceStepWithGroup = _zod2.default.object({
659
662
  quorum: _zod2.default.number(),
660
663
  group: _zod2.default.string()
661
- });
664
+ }).strict();
662
665
  var zManifestGovernanceStep = _zod2.default.union([
663
666
  zManifestGovernanceStepWithUsers,
664
667
  zManifestGovernanceStepWithGroup
@@ -675,26 +678,26 @@ var zManifestGovernanceRule = _zod2.default.object({
675
678
  "SIGN_MESSAGE"
676
679
  ]),
677
680
  steps: _zod2.default.array(zManifestGovernanceStep).min(1)
678
- });
681
+ }).strict();
679
682
  var zManifestPolicy = _zod2.default.object({
680
683
  name: _zod2.default.string(),
681
684
  currency: _zod2.default.string(),
682
685
  rules: _zod2.default.array(zManifestGovernanceRule)
683
- });
686
+ }).strict();
684
687
  var zManifestClassicAccountGovernance = _zod2.default.object({
685
688
  type: _zod2.default.literal("CLASSIC"),
686
689
  rules: _zod2.default.array(zManifestGovernanceRule)
687
- });
690
+ }).strict();
688
691
  var zManifestTradelinkExchangeConfig = _zod2.default.object({
689
692
  name: _zod2.default.string().describe("Exchange name"),
690
693
  repledgeAuthorized: _zod2.default.boolean().optional().describe("Whether repledge is authorized"),
691
694
  needsAssetManagerApprovalForSettlements: _zod2.default.boolean().optional().describe("Whether asset manager pre approval is needed")
692
- });
695
+ }).strict();
693
696
  var zManifestTradelinkAccountGovernance = _zod2.default.object({
694
697
  type: _zod2.default.literal("TRADELINK"),
695
698
  assetManager: _zod2.default.string().describe("Asset manager name"),
696
699
  exchanges: _zod2.default.array(zManifestTradelinkExchangeConfig)
697
- });
700
+ }).strict();
698
701
  var zManifestAccountGovernance = _zod2.default.discriminatedUnion("type", [
699
702
  zManifestClassicAccountGovernance,
700
703
  zManifestTradelinkAccountGovernance
@@ -704,44 +707,44 @@ var zManifestAccount = _zod2.default.object({
704
707
  currency: _zod2.default.string(),
705
708
  contractAddress: _zod2.default.string().optional(),
706
709
  governance: zManifestAccountGovernance
707
- });
710
+ }).strict();
708
711
  var zManifestPledgeAdjustment = _zod2.default.object({
709
712
  account: _zod2.default.string(),
710
713
  exchange: _zod2.default.string(),
711
714
  amount: _zod2.default.string()
712
- });
715
+ }).strict();
713
716
  var zManifestTradelinkGroup = _zod2.default.object({
714
717
  members: _zod2.default.array(zManifestUser),
715
718
  quorum: _zod2.default.number()
716
- }).describe("Tradelink group");
719
+ }).strict().describe("Tradelink group");
717
720
  var zManifestTradelinkGroups = _zod2.default.array(zManifestTradelinkGroup);
718
721
  var zManifestTradelinkWhitelistAddress = _zod2.default.object({
719
722
  name: _zod2.default.string().min(1),
720
723
  currency: _zod2.default.string().min(1),
721
724
  address: _zod2.default.string().min(1)
722
- }).describe("Tradelink whitelist address");
725
+ }).strict().describe("Tradelink whitelist address");
723
726
  var zManifestTradelinkWhitelist = _zod2.default.array(zManifestTradelinkWhitelistAddress).describe("Tradelink whitelist");
724
727
  var zManifestTradelinkEntity = _zod2.default.object({
725
728
  name: _zod2.default.string(),
726
729
  groups: zManifestTradelinkGroups,
727
730
  whitelist: zManifestTradelinkWhitelist
728
- });
731
+ }).strict();
729
732
  var zManifestTradelinkCustodian = _zod2.default.object({
730
733
  settlement: zManifestTradelinkGroups,
731
734
  withdraw: zManifestTradelinkGroups,
732
735
  arbitration: zManifestTradelinkGroups
733
- });
736
+ }).strict();
734
737
  var zManifestTradelinkNetworkBlueprint = _zod2.default.object({
735
738
  custodian: _zod2.default.string(),
736
739
  exchanges: _zod2.default.array(_zod2.default.string()),
737
740
  assetManagers: _zod2.default.array(_zod2.default.string())
738
- });
741
+ }).strict();
739
742
  var zManifestTradelinkNetwork = _zod2.default.object({
740
743
  networkBlueprint: zManifestTradelinkNetworkBlueprint.optional(),
741
744
  custodian: zManifestTradelinkCustodian.optional(),
742
745
  exchanges: _zod2.default.array(zManifestTradelinkEntity).optional(),
743
746
  assetManagers: _zod2.default.array(zManifestTradelinkEntity).optional()
744
- }).describe("Tradelink network configuration");
747
+ }).strict().describe("Tradelink network configuration");
745
748
  var zManifestWorkspace = _zod2.default.object({
746
749
  tradelink: zManifestTradelinkNetwork.optional(),
747
750
  users: _zod2.default.object({
@@ -753,22 +756,22 @@ var zManifestWorkspace = _zod2.default.object({
753
756
  policies: _zod2.default.array(zManifestPolicy).optional(),
754
757
  accounts: _zod2.default.array(zManifestAccount).optional(),
755
758
  pledges: _zod2.default.array(zManifestPledgeAdjustment).optional()
756
- }).describe("Workspace configuration");
759
+ }).strict().describe("Workspace configuration");
757
760
  var zManifestTradelinkOrgEntity = _zod2.default.object({
758
761
  name: _zod2.default.string(),
759
762
  code: _zod2.default.string(),
760
763
  logo: _zod2.default.string()
761
- }).describe("Tradelink organization entity");
764
+ }).strict().describe("Tradelink organization entity");
762
765
  var zManifestTradelinkOrg = _zod2.default.object({
763
766
  exchanges: _zod2.default.array(zManifestTradelinkOrgEntity).optional(),
764
767
  assetManagers: _zod2.default.array(zManifestTradelinkOrgEntity).optional(),
765
768
  custodians: _zod2.default.array(zManifestTradelinkOrgEntity).optional()
766
- }).describe("Tradelink organization configuration");
769
+ }).strict().describe("Tradelink organization configuration");
767
770
  var zManifest = _zod2.default.object({
768
771
  manifestVersion: _zod2.default.literal(2),
769
772
  tradelink: zManifestTradelinkOrg.optional(),
770
773
  workspace: zManifestWorkspace.optional()
771
- });
774
+ }).strict();
772
775
 
773
776
  // src/bake/index.ts
774
777
  async function bakeManifest(options, logger) {
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 \"@/types\";\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\";\n\nexport * from \"./types\";\n\nexport { 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 \"@/types\";\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: \"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 { RouterInputs } from \"@/trpc\";\nimport type { Logger } from \"@/types\";\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","import type { Logger } from \"@/types\";\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 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 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 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 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 CurrencyResponse,\n ReviewStepWithUsers,\n TokenResponse,\n TradelinkNetworkBlueprintResponse,\n UserResponse,\n} from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\nimport _ from \"lodash\";\n\nimport type { Logger } from \"@/types\";\nimport { createDeviceIndexResolver, fetchAll } from \"@/utils\";\n\nimport type {\n BakeOptions,\n ManifestAccount,\n ManifestGovernanceRule,\n ManifestGroup,\n ManifestPolicy,\n ManifestTradelinkEntity,\n ManifestTradelinkGroup,\n ManifestTradelinkNetwork,\n ManifestWhitelist,\n ManifestWorkspace,\n} from \"./types\";\nimport {\n type CreateRequestInput,\n approveRequest,\n createAndApproveRequest,\n createBakeLogHelpers,\n type inferRequestInputData,\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 existingAdmins,\n existingOperators,\n existingGroups,\n existingPolicies,\n existingAccounts,\n tradelinkNetworkBlueprint,\n ] = await Promise.all([\n fetchAll(admin1.client.users.list.query, { status: \"ACTIVE\", role: \"ADMIN\" }),\n fetchAll(admin1.client.users.list.query, { status: \"ACTIVE\", role: \"OPERATOR\" }),\n fetchAll(admin1.client.groups.list.query, { status: \"ACTIVE\" }),\n fetchAll(admin1.client.policies.list.query, { isPrivate: false }),\n fetchAll(admin1.client.accounts.list.query, { status: \"ACTIVE\", skipLiveData: true }),\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 existingUsers: UserResponse[] = [...existingAdmins, ...existingOperators];\n\n // Retrieve all device indexes for the existing users\n const usersWithDeviceIndex = await resolveDevicesIndexes(existingUsers);\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 if (workspace.users.operators) {\n for (const deviceIndex of workspace.users.operators) {\n await createUser(\"OPERATOR\", deviceIndex);\n }\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);\n }\n }\n\n async function createWhitelists(whitelists: ManifestWhitelist[]): Promise<void> {\n const existingWhitelists = await fetchAll(admin1.client.whitelists.list.query, {\n status: \"ACTIVE\",\n });\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 await createAndApproveRequest(input, [admin1, admin2], logger);\n logSubStep(`Whitelist \"${whitelist.name}\" has been created`);\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(userIdFromDeviceIndex),\n };\n }),\n };\n }\n\n async function createAccount(account: ManifestAccount): Promise<void> {\n const existing = existingAccounts.find((a) => a.name === account.name);\n if (existing) {\n logger.info(`[SKIPPED] Account \"${account.name}\" already exists`);\n return;\n }\n logStep(`Creating account \"${account.name}\"`);\n logSubStep(\"Fetching account asset...\");\n const asset = await fetchAsset({\n currency: account.currency,\n contractAddress: account.contractAddress,\n });\n const input: CreateRequestInput = {\n type: \"CREATE_ACCOUNT\",\n data: {\n // general fields\n name: account.name,\n\n // asset fields\n type: asset.type,\n currency: account.currency,\n contractAddress: account.contractAddress,\n\n // governance fields\n governance:\n account.governance.type === \"TRADELINK\"\n ? {\n type: \"TRADELINK\",\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 : {\n type: \"CLASSIC\",\n policy: {\n type: \"ACCOUNT_PRIVATE_POLICY\",\n rules: account.governance.rules.map(govRuleFromManifest),\n },\n },\n },\n };\n\n const req = await createAndApproveRequest(input, [admin1, admin2], logger);\n\n if (account.governance.type === \"TRADELINK\") {\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: \"ACTIVATE_TRADELINK_ACCOUNT\", targetId: req.targetId!, data: {} },\n loggedAssetManagerOperators,\n logger,\n );\n }\n\n logSubStep(`Account ${account.name} has been created`);\n }\n\n async function fetchAsset(params: {\n currency: string;\n contractAddress?: string;\n }): Promise<CurrencyResponse | TokenResponse> {\n const { currency, contractAddress } = params;\n if (contractAddress) {\n const tokens = await admin1.client.assets.tokens.query({ search: contractAddress });\n const t = tokens.results.find(\n (t) => t.contractAddress === contractAddress && t.currency === currency,\n );\n invariant(t, `Token ${contractAddress} (${currency}) not found`);\n return t;\n } else {\n const currencies = await admin1.client.assets.currencies.query({ search: currency });\n const c = currencies.results.find((c) => c.id === currency);\n invariant(c, `Currency ${currency} not found`);\n return c;\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 request...\");\n let req = await admin1.client.requests.create.mutate({\n request: {\n type: role === \"ADMIN\" ? \"CREATE_ADMIN\" : \"CREATE_OPERATOR\",\n data: {\n deviceUserId: deviceId,\n name,\n deviceType: \"PSD\",\n },\n },\n });\n\n logSubStep(\"Registering user...\");\n req = await userEngine.register({ requestId: req.id, name, role });\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 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(userIdFromDeviceIndex);\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 createTradelink(tradelink: ManifestTradelinkNetwork): Promise<void> {\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: \"CREATE_TRADELINK_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 if (tradelink.exchanges !== undefined) {\n await createTradelinkExchanges(networkBlueprint, tradelink.exchanges);\n }\n\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: \"CREATE_TRADELINK_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: \"CREATE_TRADELINK_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 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 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().describe(\"User device index\");\n\n// #endregion\n\n// #region ---------- Groups ----------------------------------------------------------------------\n\nconst zManifestGroup = z\n .object({\n name: z.string().describe(\"Group name\"),\n members: z.array(zManifestUser).describe(\"Group members\"),\n })\n .describe(\"Operators group\");\n\nexport type ManifestGroup = z.infer<typeof zManifestGroup>;\n\n// #endregion\n\n// #region ---------- Whitelists ------------------------------------------------------------------\n\nconst zManifestWhitelistAddress = z.object({\n name: z.string().describe(\"Whitelist address name\"),\n currency: z.string().describe(\"Whitelist address currency\"),\n address: z.string().describe(\"Whitelist address\"),\n destinationTags: z\n .array(z.string())\n .optional()\n .describe(\"List of destination tags (applicable for Ripple currency)\"),\n});\n\nconst zManifestWhitelist = z\n .object({\n name: z.string().describe(\"Whitelist name\"),\n description: z.string().optional().default(\"\").describe(\"Whitelist description\"),\n type: z\n .enum([\"TRANSACTION\", \"SMART_CONTRACT\"])\n .optional()\n .default(\"TRANSACTION\")\n .describe(\"Whitelist type\"),\n addresses: z.array(zManifestWhitelistAddress).describe(\"Whitelist addresses\"),\n })\n .describe(\"Whitelist\");\n\nexport type ManifestWhitelist = z.infer<typeof zManifestWhitelist>;\n\n// #endregion\n\n// #region ---------- Policies --------------------------------------------------------------------\n\nconst zManifestGovernanceStepWithUsers = z.object({\n quorum: z.number(),\n members: z.array(zManifestUser),\n});\n\nconst zManifestGovernanceStepWithGroup = z.object({\n quorum: z.number(),\n group: z.string(),\n});\n\nconst zManifestGovernanceStep = z.union([\n zManifestGovernanceStepWithUsers,\n zManifestGovernanceStepWithGroup,\n]);\n\nconst zManifestGovernanceRule = z.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_DIGESTS\",\n \"SIGN_MESSAGE\",\n ]),\n steps: z.array(zManifestGovernanceStep).min(1),\n});\n\nexport type ManifestGovernanceRule = z.infer<typeof zManifestGovernanceRule>;\n\nexport const zManifestPolicy = z.object({\n name: z.string(),\n currency: z.string(),\n rules: z.array(zManifestGovernanceRule),\n});\n\nexport type ManifestPolicy = z.infer<typeof zManifestPolicy>;\n\n// #endregion\n\n// #region ---------- Accounts --------------------------------------------------------------------\n\nconst zManifestClassicAccountGovernance = z.object({\n type: z.literal(\"CLASSIC\"),\n rules: z.array(zManifestGovernanceRule),\n});\n\nconst zManifestTradelinkExchangeConfig = z.object({\n name: z.string().describe(\"Exchange name\"),\n repledgeAuthorized: z.boolean().optional().describe(\"Whether repledge is authorized\"),\n needsAssetManagerApprovalForSettlements: z\n .boolean()\n .optional()\n .describe(\"Whether asset manager pre approval is needed\"),\n});\n\nconst zManifestTradelinkAccountGovernance = z.object({\n type: z.literal(\"TRADELINK\"),\n assetManager: z.string().describe(\"Asset manager name\"),\n exchanges: z.array(zManifestTradelinkExchangeConfig),\n});\n\nconst zManifestAccountGovernance = z.discriminatedUnion(\"type\", [\n zManifestClassicAccountGovernance,\n zManifestTradelinkAccountGovernance,\n]);\n\nconst zManifestAccount = z.object({\n name: z.string(),\n currency: z.string(),\n contractAddress: z.string().optional(),\n governance: zManifestAccountGovernance,\n});\n\nexport type ManifestAccount = z.infer<typeof zManifestAccount>;\n\n// #endregion\n\n// #region ---------- Pledge adjustments (increment/decrement) ------------------------------------\n\nconst zManifestPledgeAdjustment = z.object({\n account: z.string(),\n exchange: z.string(),\n amount: z.string(),\n});\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 .describe(\"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 .describe(\"Tradelink whitelist address\");\n\nconst zManifestTradelinkWhitelist = z\n .array(zManifestTradelinkWhitelistAddress)\n .describe(\"Tradelink whitelist\");\n\nconst zManifestTradelinkEntity = z.object({\n name: z.string(),\n groups: zManifestTradelinkGroups,\n whitelist: zManifestTradelinkWhitelist,\n});\n\nexport type ManifestTradelinkEntity = z.infer<typeof zManifestTradelinkEntity>;\n\nconst zManifestTradelinkCustodian = z.object({\n settlement: zManifestTradelinkGroups,\n withdraw: zManifestTradelinkGroups,\n arbitration: zManifestTradelinkGroups,\n});\n\nconst zManifestTradelinkNetworkBlueprint = z.object({\n custodian: z.string(),\n exchanges: z.array(z.string()),\n assetManagers: z.array(z.string()),\n});\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 .describe(\"Tradelink network configuration\");\n\nexport type ManifestTradelinkNetwork = z.infer<typeof zManifestTradelinkNetwork>;\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 })\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 pledges: z.array(zManifestPledgeAdjustment).optional(),\n })\n .describe(\"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 .describe(\"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 .describe(\"Tradelink organization configuration\");\n\nexport type ManifestTradelinkOrg = z.infer<typeof zManifestTradelinkOrg>;\n\n// #endregion\n\n// #region ---------- Manifest --------------------------------------------------------------------\n\nexport const zManifest = z.object({\n manifestVersion: z.literal(2),\n tradelink: zManifestTradelinkOrg.optional(),\n workspace: zManifestWorkspace.optional(),\n});\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 \"@/types\";\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\";\n\nexport * from \"./types\";\n\nexport { 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 \"@/types\";\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: \"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 { RouterInputs } from \"@/trpc\";\nimport type { Logger } from \"@/types\";\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","import type { Logger } from \"@/types\";\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 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 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 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 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 CurrencyResponse,\n ReviewStepWithUsers,\n TokenResponse,\n TradelinkNetworkBlueprintResponse,\n UserResponse,\n} from \"@ledgerhq/revault-api\";\nimport invariant from \"invariant\";\nimport _ from \"lodash\";\n\nimport type { Logger } from \"@/types\";\nimport { createDeviceIndexResolver, fetchAll } from \"@/utils\";\n\nimport type {\n BakeOptions,\n ManifestAccount,\n ManifestGovernanceRule,\n ManifestGroup,\n ManifestPolicy,\n ManifestTradelinkEntity,\n ManifestTradelinkGroup,\n ManifestTradelinkNetwork,\n ManifestWhitelist,\n ManifestWorkspace,\n} from \"./types\";\nimport {\n type CreateRequestInput,\n approveRequest,\n createAndApproveRequest,\n createBakeLogHelpers,\n type inferRequestInputData,\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 existingAdmins,\n existingOperators,\n existingGroups,\n existingPolicies,\n existingAccounts,\n tradelinkNetworkBlueprint,\n ] = await Promise.all([\n fetchAll(admin1.client.users.list.query, { status: \"ACTIVE\", role: \"ADMIN\" }),\n fetchAll(admin1.client.users.list.query, { status: \"ACTIVE\", role: \"OPERATOR\" }),\n fetchAll(admin1.client.groups.list.query, { status: \"ACTIVE\" }),\n fetchAll(admin1.client.policies.list.query, { isPrivate: false }),\n fetchAll(admin1.client.accounts.list.query, { status: \"ACTIVE\", skipLiveData: true }),\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 existingUsers: UserResponse[] = [...existingAdmins, ...existingOperators];\n\n // Retrieve all device indexes for the existing users\n const usersWithDeviceIndex = await resolveDevicesIndexes(existingUsers);\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 if (workspace.users.operators) {\n for (const deviceIndex of workspace.users.operators) {\n await createUser(\"OPERATOR\", deviceIndex);\n }\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);\n }\n }\n\n async function createWhitelists(whitelists: ManifestWhitelist[]): Promise<void> {\n const existingWhitelists = await fetchAll(admin1.client.whitelists.list.query, {\n status: \"ACTIVE\",\n });\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 await createAndApproveRequest(input, [admin1, admin2], logger);\n logSubStep(`Whitelist \"${whitelist.name}\" has been created`);\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(userIdFromDeviceIndex),\n };\n }),\n };\n }\n\n async function createAccount(account: ManifestAccount): Promise<void> {\n const existing = existingAccounts.find((a) => a.name === account.name);\n if (existing) {\n logger.info(`[SKIPPED] Account \"${account.name}\" already exists`);\n return;\n }\n logStep(`Creating account \"${account.name}\"`);\n logSubStep(\"Fetching account asset...\");\n const asset = await fetchAsset({\n currency: account.currency,\n contractAddress: account.contractAddress,\n });\n const input: CreateRequestInput = {\n type: \"CREATE_ACCOUNT\",\n data: {\n // general fields\n name: account.name,\n\n // asset fields\n type: asset.type,\n currency: account.currency,\n contractAddress: account.contractAddress,\n\n // governance fields\n governance:\n account.governance.type === \"TRADELINK\"\n ? {\n type: \"TRADELINK\",\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 : {\n type: \"CLASSIC\",\n policy: {\n type: \"ACCOUNT_PRIVATE_POLICY\",\n rules: account.governance.rules.map(govRuleFromManifest),\n },\n },\n },\n };\n\n const req = await createAndApproveRequest(input, [admin1, admin2], logger);\n\n if (account.governance.type === \"TRADELINK\") {\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: \"ACTIVATE_TRADELINK_ACCOUNT\", targetId: req.targetId!, data: {} },\n loggedAssetManagerOperators,\n logger,\n );\n }\n\n logSubStep(`Account ${account.name} has been created`);\n }\n\n async function fetchAsset(params: {\n currency: string;\n contractAddress?: string;\n }): Promise<CurrencyResponse | TokenResponse> {\n const { currency, contractAddress } = params;\n if (contractAddress) {\n const tokens = await admin1.client.assets.tokens.query({ search: contractAddress });\n const t = tokens.results.find(\n (t) => t.contractAddress === contractAddress && t.currency === currency,\n );\n invariant(t, `Token ${contractAddress} (${currency}) not found`);\n return t;\n } else {\n const currencies = await admin1.client.assets.currencies.query({ search: currency });\n const c = currencies.results.find((c) => c.id === currency);\n invariant(c, `Currency ${currency} not found`);\n return c;\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.users.inviteNewUser.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 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(userIdFromDeviceIndex);\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 createTradelink(tradelink: ManifestTradelinkNetwork): Promise<void> {\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: \"CREATE_TRADELINK_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 if (tradelink.exchanges !== undefined) {\n await createTradelinkExchanges(networkBlueprint, tradelink.exchanges);\n }\n\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: \"CREATE_TRADELINK_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: \"CREATE_TRADELINK_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 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 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().describe(\"User device index\");\n\n// #endregion\n\n// #region ---------- Groups ----------------------------------------------------------------------\n\nconst zManifestGroup = z\n .object({\n name: z.string().describe(\"Group name\"),\n members: z.array(zManifestUser).describe(\"Group members\"),\n })\n .strict()\n .describe(\"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().describe(\"Whitelist address name\"),\n currency: z.string().describe(\"Whitelist address currency\"),\n address: z.string().describe(\"Whitelist address\"),\n destinationTags: z\n .array(z.string())\n .optional()\n .describe(\"List of destination tags (applicable for Ripple currency)\"),\n })\n .strict();\n\nconst zManifestWhitelist = z\n .object({\n name: z.string().describe(\"Whitelist name\"),\n description: z.string().optional().default(\"\").describe(\"Whitelist description\"),\n type: z\n .enum([\"TRANSACTION\", \"SMART_CONTRACT\"])\n .optional()\n .default(\"TRANSACTION\")\n .describe(\"Whitelist type\"),\n addresses: z.array(zManifestWhitelistAddress).describe(\"Whitelist addresses\"),\n })\n .strict()\n .describe(\"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(zManifestUser),\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_DIGESTS\",\n \"SIGN_MESSAGE\",\n ]),\n steps: z.array(zManifestGovernanceStep).min(1),\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(),\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().describe(\"Exchange name\"),\n repledgeAuthorized: z.boolean().optional().describe(\"Whether repledge is authorized\"),\n needsAssetManagerApprovalForSettlements: z\n .boolean()\n .optional()\n .describe(\"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().describe(\"Asset manager name\"),\n exchanges: z.array(zManifestTradelinkExchangeConfig),\n })\n .strict();\n\nconst zManifestAccountGovernance = z.discriminatedUnion(\"type\", [\n zManifestClassicAccountGovernance,\n zManifestTradelinkAccountGovernance,\n]);\n\nconst zManifestAccount = z\n .object({\n name: z.string(),\n currency: z.string(),\n contractAddress: z.string().optional(),\n governance: zManifestAccountGovernance,\n })\n .strict();\n\nexport type ManifestAccount = z.infer<typeof zManifestAccount>;\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 .describe(\"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 .describe(\"Tradelink whitelist address\");\n\nconst zManifestTradelinkWhitelist = z\n .array(zManifestTradelinkWhitelistAddress)\n .describe(\"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 .describe(\"Tradelink network configuration\");\n\nexport type ManifestTradelinkNetwork = z.infer<typeof zManifestTradelinkNetwork>;\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 })\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 pledges: z.array(zManifestPledgeAdjustment).optional(),\n })\n .strict()\n .describe(\"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 .describe(\"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 .describe(\"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"]}