store.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import {
  2. AptosChain,
  3. Chain,
  4. CosmWasmChain,
  5. EvmChain,
  6. GlobalChain,
  7. SuiChain,
  8. } from "./chains";
  9. import {
  10. AptosContract,
  11. CosmWasmContract,
  12. EvmContract,
  13. SuiContract,
  14. } from "./contracts";
  15. import { Contract } from "./base";
  16. import { parse, stringify } from "yaml";
  17. import { readdirSync, readFileSync, statSync, writeFileSync } from "fs";
  18. import { Vault } from "./governance";
  19. export class Store {
  20. public chains: Record<string, Chain> = { global: new GlobalChain() };
  21. public contracts: Record<string, Contract> = {};
  22. public vaults: Record<string, Vault> = {};
  23. constructor(public path: string) {
  24. this.loadAllChains();
  25. this.loadAllContracts();
  26. this.loadAllVaults();
  27. }
  28. static serialize(obj: Contract | Chain | Vault) {
  29. return stringify([obj.toJson()]);
  30. }
  31. getYamlFiles(path: string) {
  32. const walk = function (dir: string) {
  33. let results: string[] = [];
  34. const list = readdirSync(dir);
  35. list.forEach(function (file) {
  36. file = dir + "/" + file;
  37. const stat = statSync(file);
  38. if (stat && stat.isDirectory()) {
  39. // Recurse into a subdirectory
  40. results = results.concat(walk(file));
  41. } else {
  42. // Is a file
  43. results.push(file);
  44. }
  45. });
  46. return results;
  47. };
  48. return walk(path).filter((file) => file.endsWith(".yaml"));
  49. }
  50. loadAllChains() {
  51. const allChainClasses = {
  52. [CosmWasmChain.type]: CosmWasmChain,
  53. [SuiChain.type]: SuiChain,
  54. [EvmChain.type]: EvmChain,
  55. [AptosChain.type]: AptosChain,
  56. };
  57. this.getYamlFiles(`${this.path}/chains/`).forEach((yamlFile) => {
  58. const parsedArray = parse(readFileSync(yamlFile, "utf-8"));
  59. for (const parsed of parsedArray) {
  60. if (allChainClasses[parsed.type] === undefined) return;
  61. const chain = allChainClasses[parsed.type].fromJson(parsed);
  62. if (this.chains[chain.getId()])
  63. throw new Error(`Multiple chains with id ${chain.getId()} found`);
  64. this.chains[chain.getId()] = chain;
  65. }
  66. });
  67. }
  68. saveAllContracts() {
  69. const contractsByType: Record<string, Contract[]> = {};
  70. for (const contract of Object.values(this.contracts)) {
  71. if (!contractsByType[contract.getType()]) {
  72. contractsByType[contract.getType()] = [];
  73. }
  74. contractsByType[contract.getType()].push(contract);
  75. }
  76. for (const [type, contracts] of Object.entries(contractsByType)) {
  77. writeFileSync(
  78. `${this.path}/contracts/${type}s.yaml`,
  79. stringify(contracts.map((c) => c.toJson()))
  80. );
  81. }
  82. }
  83. saveAllChains() {
  84. const chainsByType: Record<string, Chain[]> = {};
  85. for (const chain of Object.values(this.chains)) {
  86. if (!chainsByType[chain.getType()]) {
  87. chainsByType[chain.getType()] = [];
  88. }
  89. chainsByType[chain.getType()].push(chain);
  90. }
  91. for (const [type, chains] of Object.entries(chainsByType)) {
  92. writeFileSync(
  93. `${this.path}/chains/${type}s.yaml`,
  94. stringify(chains.map((c) => c.toJson()))
  95. );
  96. }
  97. }
  98. loadAllContracts() {
  99. const allContractClasses = {
  100. [CosmWasmContract.type]: CosmWasmContract,
  101. [SuiContract.type]: SuiContract,
  102. [EvmContract.type]: EvmContract,
  103. [AptosContract.type]: AptosContract,
  104. };
  105. this.getYamlFiles(`${this.path}/contracts/`).forEach((yamlFile) => {
  106. const parsedArray = parse(readFileSync(yamlFile, "utf-8"));
  107. for (const parsed of parsedArray) {
  108. if (allContractClasses[parsed.type] === undefined) return;
  109. if (!this.chains[parsed.chain])
  110. throw new Error(`Chain ${parsed.chain} not found`);
  111. const chain = this.chains[parsed.chain];
  112. const chainContract = allContractClasses[parsed.type].fromJson(
  113. chain,
  114. parsed
  115. );
  116. if (this.contracts[chainContract.getId()])
  117. throw new Error(
  118. `Multiple contracts with id ${chainContract.getId()} found`
  119. );
  120. this.contracts[chainContract.getId()] = chainContract;
  121. }
  122. });
  123. }
  124. loadAllVaults() {
  125. this.getYamlFiles(`${this.path}/vaults/`).forEach((yamlFile) => {
  126. const parsedArray = parse(readFileSync(yamlFile, "utf-8"));
  127. for (const parsed of parsedArray) {
  128. if (parsed.type !== Vault.type) return;
  129. const vault = Vault.fromJson(parsed);
  130. if (this.vaults[vault.getId()])
  131. throw new Error(`Multiple vaults with id ${vault.getId()} found`);
  132. this.vaults[vault.getId()] = vault;
  133. }
  134. });
  135. }
  136. }
  137. export const DefaultStore = new Store(`${__dirname}/../store`);