@audius/sdk 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/.eslintrc +38 -0
  2. package/.prettierrc.js +1 -0
  3. package/.python-version +1 -0
  4. package/Dockerfile +15 -0
  5. package/README.md +3 -0
  6. package/babel.config.js +3 -0
  7. package/data-contracts/ABIs/AdminUpgradeabilityProxy.json +132 -0
  8. package/data-contracts/ABIs/BaseAdminUpgradeabilityProxy.json +113 -0
  9. package/data-contracts/ABIs/BaseUpgradeabilityProxy.json +22 -0
  10. package/data-contracts/ABIs/DiscoveryProviderFactory.json +189 -0
  11. package/data-contracts/ABIs/DiscoveryProviderFactoryInterface.json +61 -0
  12. package/data-contracts/ABIs/DiscoveryProviderStorage.json +205 -0
  13. package/data-contracts/ABIs/DiscoveryProviderStorageInterface.json +65 -0
  14. package/data-contracts/ABIs/ECDSA.json +4 -0
  15. package/data-contracts/ABIs/IPLDBlacklistFactory.json +168 -0
  16. package/data-contracts/ABIs/Initializable.json +4 -0
  17. package/data-contracts/ABIs/Migrations.json +67 -0
  18. package/data-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
  19. package/data-contracts/ABIs/Ownable.json +79 -0
  20. package/data-contracts/ABIs/PlaylistFactory.json +669 -0
  21. package/data-contracts/ABIs/PlaylistFactoryInterface.json +42 -0
  22. package/data-contracts/ABIs/PlaylistStorage.json +250 -0
  23. package/data-contracts/ABIs/PlaylistStorageInterface.json +129 -0
  24. package/data-contracts/ABIs/Proxy.json +10 -0
  25. package/data-contracts/ABIs/Registry.json +240 -0
  26. package/data-contracts/ABIs/RegistryContract.json +102 -0
  27. package/data-contracts/ABIs/RegistryContractInterface.json +28 -0
  28. package/data-contracts/ABIs/RegistryInterface.json +66 -0
  29. package/data-contracts/ABIs/SigningLogic.json +43 -0
  30. package/data-contracts/ABIs/SigningLogicInitializable.json +46 -0
  31. package/data-contracts/ABIs/SocialFeatureFactory.json +460 -0
  32. package/data-contracts/ABIs/SocialFeatureStorage.json +225 -0
  33. package/data-contracts/ABIs/SocialFeatureStorageInterface.json +123 -0
  34. package/data-contracts/ABIs/TestContract.json +135 -0
  35. package/data-contracts/ABIs/TestContractInterface.json +19 -0
  36. package/data-contracts/ABIs/TestContractWithStorage.json +165 -0
  37. package/data-contracts/ABIs/TestContractWithStorageInterface.json +24 -0
  38. package/data-contracts/ABIs/TestStorage.json +144 -0
  39. package/data-contracts/ABIs/TestStorageInterface.json +42 -0
  40. package/data-contracts/ABIs/TestUserReplicaSetManager.json +432 -0
  41. package/data-contracts/ABIs/TrackFactory.json +391 -0
  42. package/data-contracts/ABIs/TrackFactoryInterface.json +73 -0
  43. package/data-contracts/ABIs/TrackStorage.json +223 -0
  44. package/data-contracts/ABIs/TrackStorageInterface.json +121 -0
  45. package/data-contracts/ABIs/UpgradeabilityProxy.json +37 -0
  46. package/data-contracts/ABIs/UserFactory.json +657 -0
  47. package/data-contracts/ABIs/UserFactoryInterface.json +65 -0
  48. package/data-contracts/ABIs/UserLibraryFactory.json +334 -0
  49. package/data-contracts/ABIs/UserReplicaSetManager.json +418 -0
  50. package/data-contracts/ABIs/UserStorage.json +233 -0
  51. package/data-contracts/ABIs/UserStorageInterface.json +93 -0
  52. package/data-contracts/signatureSchemas.ts +1236 -0
  53. package/dist/core.d.ts +446 -0
  54. package/dist/core.js +769 -0
  55. package/dist/core.js.map +1 -0
  56. package/dist/index.d.ts +689 -0
  57. package/dist/index.js +72850 -0
  58. package/dist/index.js.map +1 -0
  59. package/eth-contracts/ABIs/Address.json +4 -0
  60. package/eth-contracts/ABIs/AudiusAdminUpgradeabilityProxy.json +105 -0
  61. package/eth-contracts/ABIs/AudiusClaimDistributor.json +4968 -0
  62. package/eth-contracts/ABIs/AudiusToken.json +724 -0
  63. package/eth-contracts/ABIs/BaseUpgradeabilityProxy.json +23 -0
  64. package/eth-contracts/ABIs/Checkpointing.json +4 -0
  65. package/eth-contracts/ABIs/ClaimsManager.json +539 -0
  66. package/eth-contracts/ABIs/Context.json +11 -0
  67. package/eth-contracts/ABIs/DelegateManager.json +989 -0
  68. package/eth-contracts/ABIs/DelegateManagerV2.json +1049 -0
  69. package/eth-contracts/ABIs/DelegateManagerV2Bad.json +1049 -0
  70. package/eth-contracts/ABIs/ERC20.json +252 -0
  71. package/eth-contracts/ABIs/ERC20Burnable.json +287 -0
  72. package/eth-contracts/ABIs/ERC20Detailed.json +270 -0
  73. package/eth-contracts/ABIs/ERC20Mintable.json +364 -0
  74. package/eth-contracts/ABIs/ERC20Pausable.json +397 -0
  75. package/eth-contracts/ABIs/EthRewardsManager.json +174 -0
  76. package/eth-contracts/ABIs/Governance.json +938 -0
  77. package/eth-contracts/ABIs/GovernanceUpgraded.json +953 -0
  78. package/eth-contracts/ABIs/GovernanceV2.json +938 -0
  79. package/eth-contracts/ABIs/IERC20.json +200 -0
  80. package/eth-contracts/ABIs/Initializable.json +4 -0
  81. package/eth-contracts/ABIs/InitializableV2.json +14 -0
  82. package/eth-contracts/ABIs/Migrations.json +71 -0
  83. package/eth-contracts/ABIs/MinterRole.json +91 -0
  84. package/eth-contracts/ABIs/MockAccount.json +62 -0
  85. package/eth-contracts/ABIs/MockDelegateManager.json +55 -0
  86. package/eth-contracts/ABIs/MockStakingCaller.json +259 -0
  87. package/eth-contracts/ABIs/MockWormhole.json +106 -0
  88. package/eth-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
  89. package/eth-contracts/ABIs/Ownable.json +93 -0
  90. package/eth-contracts/ABIs/Pausable.json +150 -0
  91. package/eth-contracts/ABIs/PauserRole.json +91 -0
  92. package/eth-contracts/ABIs/Proxy.json +10 -0
  93. package/eth-contracts/ABIs/Registry.json +288 -0
  94. package/eth-contracts/ABIs/Roles.json +4 -0
  95. package/eth-contracts/ABIs/SafeERC20.json +4 -0
  96. package/eth-contracts/ABIs/SafeMath.json +4 -0
  97. package/eth-contracts/ABIs/ServiceProviderFactory.json +1153 -0
  98. package/eth-contracts/ABIs/ServiceTypeManager.json +337 -0
  99. package/eth-contracts/ABIs/Staking.json +555 -0
  100. package/eth-contracts/ABIs/StakingUpgraded.json +570 -0
  101. package/eth-contracts/ABIs/TestContract.json +44 -0
  102. package/eth-contracts/ABIs/TrustedNotifierManager.json +265 -0
  103. package/eth-contracts/ABIs/Uint256Helpers.json +4 -0
  104. package/eth-contracts/ABIs/UpgradeabilityProxy.json +40 -0
  105. package/eth-contracts/ABIs/Wormhole.json +45 -0
  106. package/eth-contracts/ABIs/WormholeClient.json +155 -0
  107. package/examples/file.mp3 +0 -0
  108. package/examples/initAudiusLibs.js +86 -0
  109. package/examples/initializeVersions.js +95 -0
  110. package/examples/pic.jpg +0 -0
  111. package/initScripts/configureLocalDiscProv.js +167 -0
  112. package/initScripts/helpers/claim.js +43 -0
  113. package/initScripts/helpers/distributeTokens.js +24 -0
  114. package/initScripts/helpers/spRegistration.js +138 -0
  115. package/initScripts/helpers/utils.js +34 -0
  116. package/initScripts/helpers/version.js +93 -0
  117. package/initScripts/local.js +617 -0
  118. package/initScripts/mainnet.js +131 -0
  119. package/initScripts/manageProdRelayerWallets.js +191 -0
  120. package/package.json +125 -0
  121. package/rollup.config.js +164 -0
  122. package/scripts/AudiusClaimDistributor.json +4968 -0
  123. package/scripts/Wormhole.json +155 -0
  124. package/scripts/addCIDToIpldBlacklist.js +124 -0
  125. package/scripts/circleci-test.sh +53 -0
  126. package/scripts/communityRewards/transferCommunityRewardsToSolana.js +222 -0
  127. package/scripts/ipfs.sh +58 -0
  128. package/scripts/migrate_contracts.sh +25 -0
  129. package/scripts/reset.sh +65 -0
  130. package/scripts/test.sh +77 -0
  131. package/src/api/account.js +670 -0
  132. package/src/api/base.js +122 -0
  133. package/src/api/file.js +168 -0
  134. package/src/api/playlist.js +328 -0
  135. package/src/api/rewards.d.ts +4 -0
  136. package/src/api/rewards.js +682 -0
  137. package/src/api/serviceProvider.js +154 -0
  138. package/src/api/track.js +604 -0
  139. package/src/api/user.js +888 -0
  140. package/src/api/user.test.js +172 -0
  141. package/src/constants.ts +7 -0
  142. package/src/core.ts +3 -0
  143. package/src/index.js +6 -0
  144. package/src/libs.d.ts +3 -0
  145. package/src/libs.js +619 -0
  146. package/src/sanityChecks/addSecondaries.js +40 -0
  147. package/src/sanityChecks/assignReplicaSetIfNecessary.js +10 -0
  148. package/src/sanityChecks/index.d.ts +9 -0
  149. package/src/sanityChecks/index.js +31 -0
  150. package/src/sanityChecks/isCreator.js +73 -0
  151. package/src/sanityChecks/needsRecoveryEmail.js +20 -0
  152. package/src/sanityChecks/rolloverNodes.js +74 -0
  153. package/src/sanityChecks/sanitizeNodes.js +24 -0
  154. package/src/sanityChecks/syncNodes.js +28 -0
  155. package/src/sdk/constants.ts +10 -0
  156. package/src/sdk/index.ts +1 -0
  157. package/src/sdk/oauth/Oauth.ts +265 -0
  158. package/src/sdk/oauth/index.ts +1 -0
  159. package/src/sdk/sdk.ts +102 -0
  160. package/src/service-selection/ServiceSelection.test.ts +320 -0
  161. package/src/service-selection/ServiceSelection.ts +460 -0
  162. package/src/service-selection/constants.ts +14 -0
  163. package/src/service-selection/index.ts +1 -0
  164. package/src/services/ABIDecoder/AudiusABIDecoder.ts +71 -0
  165. package/src/services/ABIDecoder/index.ts +1 -0
  166. package/src/services/comstock/Comstock.ts +39 -0
  167. package/src/services/comstock/index.ts +1 -0
  168. package/src/services/contracts/ContractClient.ts +227 -0
  169. package/src/services/contracts/GovernedContractClient.ts +53 -0
  170. package/src/services/contracts/ProviderSelection.ts +42 -0
  171. package/src/services/creatorNode/CreatorNode.ts +1065 -0
  172. package/src/services/creatorNode/CreatorNodeSelection.test.ts +997 -0
  173. package/src/services/creatorNode/CreatorNodeSelection.ts +488 -0
  174. package/src/services/creatorNode/constants.ts +10 -0
  175. package/src/services/creatorNode/index.ts +2 -0
  176. package/src/services/dataContracts/AudiusContracts.ts +234 -0
  177. package/src/services/dataContracts/IPLDBlacklistFactoryClient.ts +73 -0
  178. package/src/services/dataContracts/PlaylistFactoryClient.ts +370 -0
  179. package/src/services/dataContracts/RegistryClient.ts +95 -0
  180. package/src/services/dataContracts/SocialFeatureFactoryClient.ts +196 -0
  181. package/src/services/dataContracts/TrackFactoryClient.ts +131 -0
  182. package/src/services/dataContracts/UserFactoryClient.ts +351 -0
  183. package/src/services/dataContracts/UserLibraryFactoryClient.ts +115 -0
  184. package/src/services/dataContracts/UserReplicaSetManagerClient.ts +206 -0
  185. package/src/services/dataContracts/index.ts +1 -0
  186. package/src/services/discoveryProvider/DiscoveryProvider.ts +1168 -0
  187. package/src/services/discoveryProvider/DiscoveryProviderSelection.test.ts +536 -0
  188. package/src/services/discoveryProvider/DiscoveryProviderSelection.ts +383 -0
  189. package/src/services/discoveryProvider/constants.ts +13 -0
  190. package/src/services/discoveryProvider/index.ts +1 -0
  191. package/src/services/discoveryProvider/requests.ts +629 -0
  192. package/src/services/ethContracts/AudiusTokenClient.ts +163 -0
  193. package/src/services/ethContracts/ClaimDistributionClient.ts +45 -0
  194. package/src/services/ethContracts/ClaimsManagerClient.ts +102 -0
  195. package/src/services/ethContracts/DelegateManagerClient.ts +480 -0
  196. package/src/services/ethContracts/EthContracts.ts +359 -0
  197. package/src/services/ethContracts/EthRewardsManagerClient.ts +33 -0
  198. package/src/services/ethContracts/GovernanceClient.ts +451 -0
  199. package/src/services/ethContracts/RegistryClient.ts +33 -0
  200. package/src/services/ethContracts/ServiceProviderFactoryClient.ts +691 -0
  201. package/src/services/ethContracts/ServiceTypeManagerClient.ts +112 -0
  202. package/src/services/ethContracts/StakingProxyClient.ts +97 -0
  203. package/src/services/ethContracts/TrustedNotifierManagerClient.ts +101 -0
  204. package/src/services/ethContracts/WormholeClient.ts +97 -0
  205. package/src/services/ethContracts/index.ts +1 -0
  206. package/src/services/ethWeb3Manager/EthWeb3Manager.ts +239 -0
  207. package/src/services/ethWeb3Manager/index.ts +1 -0
  208. package/src/services/hedgehog/Hedgehog.ts +96 -0
  209. package/src/services/hedgehog/index.ts +1 -0
  210. package/src/services/identity/IdentityService.ts +551 -0
  211. package/src/services/identity/index.ts +1 -0
  212. package/src/services/identity/requests.ts +65 -0
  213. package/src/services/schemaValidator/SchemaValidator.ts +105 -0
  214. package/src/services/schemaValidator/index.ts +1 -0
  215. package/src/services/schemaValidator/schemas/trackSchema.json +267 -0
  216. package/src/services/schemaValidator/schemas/userSchema.json +230 -0
  217. package/src/services/solanaAudiusData/errors.ts +20 -0
  218. package/src/services/solanaAudiusData/index.ts +1189 -0
  219. package/src/services/solanaWeb3Manager/errors.js +101 -0
  220. package/src/services/solanaWeb3Manager/index.d.ts +46 -0
  221. package/src/services/solanaWeb3Manager/index.js +655 -0
  222. package/src/services/solanaWeb3Manager/padBNToUint8Array.ts +7 -0
  223. package/src/services/solanaWeb3Manager/rewards.js +941 -0
  224. package/src/services/solanaWeb3Manager/rewardsAttester.ts +1093 -0
  225. package/src/services/solanaWeb3Manager/tokenAccount.js +149 -0
  226. package/src/services/solanaWeb3Manager/transactionHandler.js +345 -0
  227. package/src/services/solanaWeb3Manager/transfer.js +272 -0
  228. package/src/services/solanaWeb3Manager/userBank.js +160 -0
  229. package/src/services/solanaWeb3Manager/utils.d.ts +31 -0
  230. package/src/services/solanaWeb3Manager/utils.js +163 -0
  231. package/src/services/solanaWeb3Manager/wAudio.js +28 -0
  232. package/src/services/solanaWeb3Manager/wAudio.test.js +30 -0
  233. package/src/services/web3Manager/Web3Config.ts +14 -0
  234. package/src/services/web3Manager/Web3Manager.ts +360 -0
  235. package/src/services/web3Manager/XMLHttpRequest.ts +11 -0
  236. package/src/services/web3Manager/index.ts +2 -0
  237. package/src/services/wormhole/index.js +424 -0
  238. package/src/types.ts +8 -0
  239. package/src/userStateManager.ts +53 -0
  240. package/src/utils/apiSigning.ts +51 -0
  241. package/src/utils/captcha.ts +97 -0
  242. package/src/utils/estimateGas.ts +64 -0
  243. package/src/utils/fileHasher.ts +278 -0
  244. package/src/utils/importContractABI.d.ts +9 -0
  245. package/src/utils/importContractABI.js +19 -0
  246. package/src/utils/index.ts +11 -0
  247. package/src/utils/multiProvider.ts +72 -0
  248. package/src/utils/network.test.ts +127 -0
  249. package/src/utils/network.ts +308 -0
  250. package/src/utils/promiseFight.test.ts +87 -0
  251. package/src/utils/promiseFight.ts +36 -0
  252. package/src/utils/signatures.ts +139 -0
  253. package/src/utils/types.ts +34 -0
  254. package/src/utils/utils.test.ts +36 -0
  255. package/src/utils/utils.ts +235 -0
  256. package/src/utils/uuid.ts +14 -0
  257. package/src/web3.d.ts +9 -0
  258. package/src/web3.js +8 -0
  259. package/tests/assets/static_image.png +0 -0
  260. package/tests/assets/static_text.txt +1 -0
  261. package/tests/audiusTokenClientTest.js +37 -0
  262. package/tests/creatorNodeTest.js +19 -0
  263. package/tests/fileHasherTest.js +125 -0
  264. package/tests/governanceTest.js +382 -0
  265. package/tests/helpers.js +105 -0
  266. package/tests/index.js +14 -0
  267. package/tests/playlistClientTest.js +157 -0
  268. package/tests/providerSelectionTest.js +241 -0
  269. package/tests/registryClientTest.js +19 -0
  270. package/tests/rewardsAttesterTest.js +373 -0
  271. package/tests/serviceTypeManagerClientTest.js +33 -0
  272. package/tests/socialFeatureClientTest.js +79 -0
  273. package/tests/stakingTest.js +302 -0
  274. package/tests/trackClientTest.js +86 -0
  275. package/tests/userClientTest.js +121 -0
  276. package/tsconfig.json +10 -0
  277. package/types/@audius-hedgehog/index.d.ts +39 -0
  278. package/types/abi-decoder/index.d.ts +41 -0
@@ -0,0 +1,460 @@
1
+ import { sampleSize } from 'lodash'
2
+ import {
3
+ raceRequests,
4
+ allRequests,
5
+ ServiceName,
6
+ ServiceWithEndpoint,
7
+ Service,
8
+ Maybe
9
+ } from '../utils'
10
+ import { DECISION_TREE_STATE } from './constants'
11
+ import type { AxiosResponse } from 'axios'
12
+
13
+ function isVerbose(service: Service): service is ServiceWithEndpoint {
14
+ return typeof service !== 'string'
15
+ }
16
+
17
+ export type GetServicesInput =
18
+ | (() => Promise<ServiceName[]>)
19
+ | ((config: { verbose: false }) => Promise<ServiceName[]>)
20
+ | ((config: { verbose: true }) => Promise<ServiceWithEndpoint[]>)
21
+ | ((config: {
22
+ verbose: boolean
23
+ }) => Promise<ServiceName[] | ServiceWithEndpoint[]>)
24
+
25
+ interface GetServices {
26
+ (): Promise<ServiceName[]>
27
+ (config: { verbose: false }): Promise<ServiceName[]>
28
+ (config: { verbose: true }): Promise<ServiceWithEndpoint[]>
29
+ (config: { verbose: boolean }): Promise<Service[]>
30
+ }
31
+
32
+ export interface Decision {
33
+ stage: string
34
+ val?: unknown
35
+ }
36
+
37
+ export type Backup = { block_difference: number; version: string }
38
+
39
+ export interface ServiceSelectionConfig {
40
+ // services from this list should not be picked
41
+ blacklist?: Set<string> | undefined | null
42
+ // only services from this list are allowed to be picked
43
+ whitelist?: Set<string> | undefined | null
44
+ /*
45
+ * an (async) method to get a
46
+ * list of services to choose from. Optionally may return a verbose object with service metadata
47
+ */
48
+ getServices: GetServicesInput
49
+ /*
50
+ * the maximum number of requests allowed to fire at
51
+ * once. Tweaking this value may impact browser performance
52
+ */
53
+ maxConcurrentRequests?: number
54
+ // the timeout at which to give up on a service
55
+ requestTimeout?: Maybe<number>
56
+ /*
57
+ *the point at which the unhealthy services are freed so they
58
+ * may be tried again (re-requested)
59
+ */
60
+ unhealthyTTL?: number
61
+ /*
62
+ * the point at which backup services are freed so they may be
63
+ * tried again (re-requested)
64
+ */
65
+ backupsTTL?: number
66
+ }
67
+
68
+ /**
69
+ * A class that assists with autoselecting services.
70
+ * `ServiceSelection` is intended to be overridden with further
71
+ * business logic that a particular sevice might preference.
72
+ *
73
+ * The general use case is as follows:
74
+ *
75
+ * ```
76
+ *
77
+ * const selector = new ServiceSelection({
78
+ * getServices: ethContracts.getDiscoveryProviders()
79
+ * })
80
+ *
81
+ * const service = await selector.select()
82
+ *
83
+ * ```
84
+ *
85
+ * This class operates by taking a list of services and
86
+ * round-robin makes requests at them until a suitable one is found.
87
+ *
88
+ * Two types of "bad" services are defined below:
89
+ * - Unhealthy: this service is bad and should not be used
90
+ * - Backup: this service is bad, but if we can't find anything better, maybe use it
91
+ *
92
+ * Classes that extend `ServiceSelection` can choose to implement custom logic on top
93
+ * of them and is generally how this class is intended to be used.
94
+ */
95
+ export class ServiceSelection {
96
+ blacklist: Set<string> | undefined | null
97
+ whitelist: Set<string> | undefined | null
98
+ getServices: GetServices
99
+ maxConcurrentRequests: number
100
+ requestTimeout: number
101
+ unhealthyTTL: number
102
+ backupsTTL: number
103
+ unhealthy: Set<string>
104
+ backups: Record<string, Backup>
105
+ totalAttempts: number
106
+ decisionTree: Decision[]
107
+ unhealthyCleanupTimeout: NodeJS.Timeout | null = null
108
+ backupCleanupTimeout: NodeJS.Timeout | null = null
109
+
110
+ constructor({
111
+ blacklist,
112
+ whitelist,
113
+ getServices,
114
+ maxConcurrentRequests = 6,
115
+ requestTimeout = 30 * 1000, // 30s
116
+ unhealthyTTL = 60 * 60 * 1000, // 1 hour
117
+ backupsTTL = 2 * 60 * 1000 // 2 min
118
+ }: ServiceSelectionConfig) {
119
+ // For Creator Node selection
120
+ this.blacklist = blacklist
121
+ this.whitelist = whitelist
122
+ this.getServices = getServices as GetServices
123
+ this.maxConcurrentRequests = maxConcurrentRequests
124
+ this.requestTimeout = requestTimeout
125
+ this.unhealthyTTL = unhealthyTTL
126
+ this.backupsTTL = backupsTTL
127
+
128
+ // Truly "unhealthy" services. Should not ever be picked.
129
+ this.unhealthy = new Set([])
130
+
131
+ // Selectable services but not optimal. Will be picked as a last resort.
132
+ this.backups = {}
133
+
134
+ // Total number of services attempted
135
+ this.totalAttempts = 0
136
+
137
+ // The decision tree path that was taken. Reset on each new selection.
138
+ this.decisionTree = []
139
+ }
140
+
141
+ /**
142
+ * Selects a service
143
+ * @param reset if reset is true, clear the decision tree
144
+ */
145
+ // we need any type here to allow sub-classes to more strictly type return type
146
+ async select(reset: any = true): Promise<any> {
147
+ if (reset) {
148
+ this.decisionTree = []
149
+ }
150
+
151
+ // If a short circuit is provided, take it. Don't check it, just use it.
152
+ const shortcircuit = this.shortcircuit()
153
+ this.decisionTree.push({
154
+ stage: DECISION_TREE_STATE.CHECK_SHORT_CIRCUIT,
155
+ val: shortcircuit
156
+ })
157
+ // If there is a shortcircuit defined and we have not blacklisted it, pick it
158
+ if (shortcircuit && (!this.blacklist || !this.blacklist.has(shortcircuit)))
159
+ return shortcircuit
160
+
161
+ // Get all the services
162
+ let services = await this.getServices()
163
+ this.decisionTree.push({
164
+ stage: DECISION_TREE_STATE.GET_ALL_SERVICES,
165
+ val: services
166
+ })
167
+
168
+ // If a whitelist is provided, filter down to it
169
+ if (this.whitelist) {
170
+ services = this.filterToWhitelist(services)
171
+ this.decisionTree.push({
172
+ stage: DECISION_TREE_STATE.FILTER_TO_WHITELIST,
173
+ val: services
174
+ })
175
+ }
176
+
177
+ // if a blacklist is provided, filter out services in the list
178
+ if (this.blacklist) {
179
+ services = this.filterFromBlacklist(services)
180
+ this.decisionTree.push({
181
+ stage: DECISION_TREE_STATE.FILTER_FROM_BLACKLIST,
182
+ val: services
183
+ })
184
+ }
185
+
186
+ // Filter out anything we know is already unhealthy
187
+ const filteredServices = this.filterOutKnownUnhealthy(services)
188
+ this.decisionTree.push({
189
+ stage: DECISION_TREE_STATE.FILTER_OUT_KNOWN_UNHEALTHY,
190
+ val: filteredServices
191
+ })
192
+
193
+ // Randomly sample a "round" to test
194
+ const round = this.getSelectionRound(filteredServices)
195
+ this.decisionTree.push({
196
+ stage: DECISION_TREE_STATE.GET_SELECTION_ROUND,
197
+ val: round
198
+ })
199
+
200
+ this.totalAttempts += round.length
201
+
202
+ // If there are no services left to try, either pick a backup or return null
203
+ if (filteredServices.length === 0) {
204
+ this.decisionTree.push({
205
+ stage: DECISION_TREE_STATE.NO_SERVICES_LEFT_TO_TRY
206
+ })
207
+ if (this.getBackupsSize() > 0) {
208
+ // Some backup exists
209
+ const backup = await this.selectFromBackups()
210
+ this.decisionTree.push({
211
+ stage: DECISION_TREE_STATE.SELECTED_FROM_BACKUP,
212
+ val: backup
213
+ })
214
+ return backup
215
+ } else {
216
+ // Nothing could be found that was healthy.
217
+ // Reset everything we know so that we might try again.
218
+ this.unhealthy = new Set([])
219
+ this.backups = {}
220
+ this.decisionTree.push({
221
+ stage: DECISION_TREE_STATE.FAILED_AND_RESETTING
222
+ })
223
+ return null
224
+ }
225
+ }
226
+
227
+ // Race this "round" of services, getting the best and ones that errored
228
+ // Note: ones that did not error or were not the best just get canceled so
229
+ // we don't really know anything about them at this point.
230
+ const { best, errored } = await this.race(round)
231
+
232
+ // Mark all the errored ones as unhealthy
233
+ errored.forEach((e) => {
234
+ if (e) {
235
+ this.addUnhealthy(e)
236
+ }
237
+ })
238
+
239
+ // Trigger a cleanup event for all of the unhealthy and backup services,
240
+ // so they can get retried in the future
241
+ this.triggerCleanup()
242
+
243
+ // Recursively try this selection function if we didn't find something
244
+ if (!best) {
245
+ this.decisionTree.push({ stage: DECISION_TREE_STATE.ROUND_FAILED_RETRY })
246
+ return await this.select(/* reset */ false)
247
+ }
248
+
249
+ this.decisionTree.push({
250
+ stage: DECISION_TREE_STATE.MADE_A_SELECTION,
251
+ val: best
252
+ })
253
+ // If we made it this far, we found the best service! (of the rounds we tried)
254
+ return best
255
+ }
256
+
257
+ /**
258
+ * Finds all selectable services (respecting whitelist, health checks & timeouts).
259
+ * Note: this method is potentially slow.
260
+ * If you need just a single service, prefer calling `.select()`
261
+ * @param {boolean} verbose whether or not to return full services metadata
262
+ * @param {Set} whitelist a whitelist to override the set of endpoints
263
+ */
264
+ async findAll({ verbose = false, whitelist = this.whitelist } = {}) {
265
+ // Get all the services
266
+ let services = await this.getServices({ verbose })
267
+
268
+ // If a whitelist is provided, filter down to it
269
+ if (whitelist) {
270
+ services = services.filter((service) =>
271
+ whitelist.has(isVerbose(service) ? service.endpoint : service)
272
+ )
273
+ }
274
+
275
+ // Key the services by their health check endpoint
276
+ const urlMap = services.reduce<Record<string, Service>>(
277
+ (urlMap, service) => {
278
+ urlMap[
279
+ ServiceSelection.getHealthCheckEndpoint(
280
+ isVerbose(service) ? service.endpoint : service
281
+ )
282
+ ] = service
283
+ return urlMap
284
+ },
285
+ {}
286
+ )
287
+
288
+ try {
289
+ const results = await allRequests({
290
+ urlMap,
291
+ timeout: this.requestTimeout,
292
+ validationCheck: (resp) => this.isHealthy(resp, urlMap)
293
+ })
294
+ return results
295
+ } catch (e) {
296
+ console.error(e)
297
+ return []
298
+ }
299
+ }
300
+
301
+ /** Triggers a clean up of unhealthy and backup services so they can be retried later */
302
+ triggerCleanup() {
303
+ if (this.unhealthyCleanupTimeout) {
304
+ clearTimeout(this.unhealthyCleanupTimeout)
305
+ }
306
+
307
+ if (this.backupCleanupTimeout) {
308
+ clearTimeout(this.backupCleanupTimeout)
309
+ }
310
+
311
+ this.unhealthyCleanupTimeout = setTimeout(() => {
312
+ this.clearUnhealthy()
313
+ }, this.unhealthyTTL)
314
+ this.backupCleanupTimeout = setTimeout(() => {
315
+ this.clearBackups()
316
+ }, this.backupsTTL)
317
+ }
318
+
319
+ clearUnhealthy() {
320
+ this.unhealthy = new Set([])
321
+ }
322
+
323
+ clearBackups() {
324
+ this.backups = {}
325
+ }
326
+
327
+ /** A short-circuit. If overriden, can be used to skip selection (which could be slow) */
328
+ shortcircuit(): null | string {
329
+ return null
330
+ }
331
+
332
+ /**
333
+ * Filter out services that are in the blacklist
334
+ * @param services endpoints
335
+ */
336
+ filterFromBlacklist(services: string[]) {
337
+ return services.filter((s) => !this.blacklist?.has(s))
338
+ }
339
+
340
+ /** Filter down services to those in the whitelist */
341
+ filterToWhitelist(services: string[]) {
342
+ return services.filter((s) => this.whitelist?.has(s))
343
+ }
344
+
345
+ /** Filter out known unhealthy services from the provided */
346
+ filterOutKnownUnhealthy(services: string[]) {
347
+ return services.filter((s) => !this.unhealthy.has(s))
348
+ }
349
+
350
+ /** Given a list of services, samples maxConcurrentRequests from them */
351
+ getSelectionRound(services: string[]) {
352
+ return sampleSize(services, this.maxConcurrentRequests)
353
+ }
354
+
355
+ /** Gets the total number of attempts we've made this instantiation */
356
+ getTotalAttempts() {
357
+ return this.totalAttempts
358
+ }
359
+
360
+ /** Where does the health check for this type of service live */
361
+ static getHealthCheckEndpoint(service: string) {
362
+ return `${service}/health_check`
363
+ }
364
+
365
+ /**
366
+ * What the criteria is for a healthy service
367
+ * @param response axios response
368
+ * @param {{ [key: string]: string}} urlMap health check urls mapped to their cannonical url
369
+ * e.g. https://discoveryprovider.audius.co/health_check => https://discoveryprovider.audius.co
370
+ */
371
+ isHealthy(response: AxiosResponse, _urlMap: Record<string, Service>) {
372
+ return response.status === 200
373
+ }
374
+
375
+ /** Races requests against each other with provided timeouts and health checks */
376
+ async race(services: string[]) {
377
+ // Key the services by their health check endpoint
378
+ const serviceMap = services.reduce<Record<string, string>>((acc, s) => {
379
+ acc[ServiceSelection.getHealthCheckEndpoint(s)] = s
380
+ return acc
381
+ }, {})
382
+
383
+ let best: string | null = null
384
+ try {
385
+ const { errored } = await raceRequests(
386
+ Object.keys(serviceMap),
387
+ (url) => {
388
+ best = serviceMap[url] as string
389
+ },
390
+ {},
391
+ /* timeout */ this.requestTimeout,
392
+ /* timeBetweenRequests */ 0,
393
+ /* validationCheck */ (resp) => this.isHealthy(resp, serviceMap)
394
+ )
395
+ this.decisionTree.push({
396
+ stage: DECISION_TREE_STATE.RACED_AND_FOUND_BEST,
397
+ val: best
398
+ })
399
+ return {
400
+ best,
401
+ errored: errored.map((e) => serviceMap[e.config.url ?? ''])
402
+ }
403
+ } catch (e) {
404
+ return { best: null, errored: [] }
405
+ }
406
+ }
407
+
408
+ /** Adds a service to the unhealthy set */
409
+ addUnhealthy(service: ServiceName) {
410
+ this.unhealthy.add(service)
411
+ }
412
+
413
+ /** Gets unhealthy set size */
414
+ getUnhealthySize() {
415
+ return this.unhealthy.size
416
+ }
417
+
418
+ /**
419
+ * Removes from unhealthy set
420
+ * @param key service endpoint
421
+ */
422
+ removeFromUnhealthy(key: string) {
423
+ if (this.unhealthy.has(key)) this.unhealthy.delete(key)
424
+ }
425
+
426
+ /**
427
+ * Adds a service to the list of backups
428
+ * @param service the service to add
429
+ * @param response the services response. This can be used to weigh various
430
+ * backups against eachother
431
+ */
432
+ addBackup(service: string, response: Backup) {
433
+ this.backups[service] = response
434
+ }
435
+
436
+ /**
437
+ * Controls how a backup is picked. Overriding methods may choose to use the backup's response.
438
+ * e.g. pick a backup that's the fewest versions behind
439
+ */
440
+ async selectFromBackups() {
441
+ return Object.keys(this.backups)[0]
442
+ }
443
+
444
+ /**
445
+ * Removes from backups
446
+ * @param key service endpoint
447
+ */
448
+ removeFromBackups(key: string) {
449
+ if (Object.prototype.hasOwnProperty.call(this.backups, key))
450
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
451
+ delete this.backups[key]
452
+ }
453
+
454
+ /**
455
+ * Returns the size of backups
456
+ */
457
+ getBackupsSize() {
458
+ return Object.keys(this.backups).length
459
+ }
460
+ }
@@ -0,0 +1,14 @@
1
+ export enum DECISION_TREE_STATE {
2
+ CHECK_SHORT_CIRCUIT = 'Check Short Circuit',
3
+ GET_ALL_SERVICES = 'Get All Services',
4
+ FILTER_TO_WHITELIST = 'Filter To Whitelist',
5
+ FILTER_FROM_BLACKLIST = 'Filter From Blacklist',
6
+ FILTER_OUT_KNOWN_UNHEALTHY = 'Filter Out Known Unhealthy',
7
+ GET_SELECTION_ROUND = 'Get Selection Round',
8
+ NO_SERVICES_LEFT_TO_TRY = 'No Services Left To Try',
9
+ SELECTED_FROM_BACKUP = 'Selected From Backup',
10
+ FAILED_AND_RESETTING = 'Failed Everything -- Resetting',
11
+ ROUND_FAILED_RETRY = 'Round Failed Retry',
12
+ MADE_A_SELECTION = 'Made A Selection',
13
+ RACED_AND_FOUND_BEST = 'Raced And Found Best'
14
+ }
@@ -0,0 +1 @@
1
+ export * from './ServiceSelection'
@@ -0,0 +1,71 @@
1
+ import abiDecoder from 'abi-decoder'
2
+ import { Utils } from '../../utils'
3
+ import type { AbiItem, AbiInput } from 'web3-utils'
4
+ import type { Log } from 'web3-core'
5
+
6
+ const abiMap: Record<string, AbiItem[]> = {}
7
+
8
+ function loadABI(abiFile: string) {
9
+ const contract = Utils.importDataContractABI(abiFile)
10
+ abiDecoder.addABI(contract.abi)
11
+ abiMap[contract.contractName] = contract.abi
12
+ }
13
+
14
+ loadABI('Registry.json')
15
+ loadABI('UserFactory.json')
16
+ loadABI('TrackFactory.json')
17
+ loadABI('DiscoveryProviderFactory.json')
18
+ loadABI('SocialFeatureFactory.json')
19
+ loadABI('PlaylistFactory.json')
20
+ loadABI('UserLibraryFactory.json')
21
+ loadABI('UserReplicaSetManager.json')
22
+
23
+ // eslint-disable-next-line @typescript-eslint/no-extraneous-class -- should just use esm
24
+ export class AudiusABIDecoder {
25
+ static decodeMethod(contractName: string, encodedABI: string) {
26
+ const decoded = abiDecoder.decodeMethod(encodedABI)
27
+ if (!decoded) {
28
+ throw new Error('No Audius ABI matches given data')
29
+ }
30
+
31
+ // hack around abi-decoder's lack of contract-specific support (only one global
32
+ // namespace of functions)
33
+ const abi = abiMap[contractName]
34
+ if (!abi) {
35
+ throw new Error('Unrecognized contract name')
36
+ }
37
+
38
+ let foundFunction: AbiItem | undefined
39
+ abi.forEach((item) => {
40
+ if (item.type === 'function' && item.name === decoded.name) {
41
+ foundFunction = item
42
+ }
43
+ })
44
+
45
+ if (!foundFunction) {
46
+ throw new Error(
47
+ `Unrecognized function ${decoded.name} for contract ${contractName}`
48
+ )
49
+ }
50
+
51
+ const paramSpecs = foundFunction.inputs as AbiInput[]
52
+ decoded.params.forEach((param, idx) => {
53
+ if (idx >= paramSpecs.length) {
54
+ throw new Error('Extra parameter')
55
+ }
56
+
57
+ const paramSpec = paramSpecs[idx]
58
+ if (paramSpec?.name !== param.name || paramSpec.type !== param.type) {
59
+ throw new Error(
60
+ `Invalid name or value for param ${paramSpec?.name}: ${paramSpec?.type}`
61
+ )
62
+ }
63
+ })
64
+
65
+ return decoded
66
+ }
67
+
68
+ static decodeLogs(_: string, logs: Log[]) {
69
+ return abiDecoder.decodeLogs(logs)
70
+ }
71
+ }
@@ -0,0 +1 @@
1
+ export * from './AudiusABIDecoder'
@@ -0,0 +1,39 @@
1
+ import axios, { AxiosError, AxiosRequestConfig } from 'axios'
2
+
3
+ export class Comstock {
4
+ comstockEndpoint: string
5
+
6
+ constructor(comstockEndpoint: string) {
7
+ this.comstockEndpoint = comstockEndpoint
8
+ }
9
+
10
+ async getComstock(obj: AxiosRequestConfig) {
11
+ const result = await this._makeRequest({
12
+ url: '/wallet_lookup',
13
+ method: 'get',
14
+ params: obj
15
+ })
16
+ return result
17
+ }
18
+
19
+ /* ------- INTERNAL FUNCTIONS ------- */
20
+
21
+ async _makeRequest(axiosRequestObj: AxiosRequestConfig) {
22
+ axiosRequestObj.baseURL = this.comstockEndpoint
23
+ // Axios throws for non-200 responses
24
+ try {
25
+ const resp = await axios(axiosRequestObj)
26
+ return resp.data
27
+ } catch (e) {
28
+ const error = e as AxiosError
29
+ if (error.response?.data?.error) {
30
+ throw new Error(
31
+ `Server returned error: [${error.response.status.toString()}] ${
32
+ error.response.data.error
33
+ }`
34
+ )
35
+ }
36
+ throw error
37
+ }
38
+ }
39
+ }
@@ -0,0 +1 @@
1
+ export * from './Comstock'