@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,31 @@
1
+ const isCreator = require('./isCreator')
2
+ const sanitizeNodes = require('./sanitizeNodes')
3
+ const addSecondaries = require('./addSecondaries')
4
+ const syncNodes = require('./syncNodes')
5
+ const rolloverNodes = require('./rolloverNodes')
6
+ const recoveryEmail = require('./needsRecoveryEmail')
7
+ const assignReplicaSetIfNecessary = require('./assignReplicaSetIfNecessary')
8
+
9
+ // Checks to run at startup to ensure a user is in a good state.
10
+ class SanityChecks {
11
+ constructor (libsInstance, options = { skipRollover: false }) {
12
+ this.libs = libsInstance
13
+ this.options = options
14
+ }
15
+
16
+ /**
17
+ * Runs sanity checks
18
+ * @param {Set<string>} creatorNodeWhitelist
19
+ */
20
+ async run (creatorNodeWhitelist = null) {
21
+ await isCreator(this.libs)
22
+ await sanitizeNodes(this.libs)
23
+ await addSecondaries(this.libs)
24
+ await assignReplicaSetIfNecessary(this.libs)
25
+ await syncNodes(this.libs)
26
+ if (!this.options.skipRollover) await rolloverNodes(this.libs, creatorNodeWhitelist)
27
+ await recoveryEmail(this.libs)
28
+ }
29
+ }
30
+
31
+ module.exports = SanityChecks
@@ -0,0 +1,73 @@
1
+ const axios = require('axios')
2
+
3
+ /** Sanity check for whether a user is a creator. If not, make them one. */
4
+
5
+ const hasCID = async (node, cid) => {
6
+ const url = `${node.endpoint}/ipfs/${cid}`
7
+ try {
8
+ const res = await axios.head(url)
9
+ return res.status === 200
10
+ } catch (e) {
11
+ return false
12
+ }
13
+ }
14
+
15
+ const hasAllCID = async (node, cids) => {
16
+ const hasAll = await Promise.all(cids.map(cid => hasCID(node, cid)))
17
+ return hasAll.every(Boolean)
18
+ }
19
+
20
+ const findCorrectNode = async (nodes, cids) => {
21
+ for (let i = 0; i < nodes.length; ++i) {
22
+ const hasAll = await hasAllCID(nodes[i], cids)
23
+ if (hasAll) return nodes[i]
24
+ }
25
+ return null
26
+ }
27
+
28
+ const isCreator = async (libs) => {
29
+ console.debug('Sanity Check - isCreator')
30
+ const user = libs.userStateManager.getCurrentUser()
31
+ if (
32
+ // There is no currently logged in user
33
+ !user ||
34
+ // The user has no tracks (they shouldn't become a creator)
35
+ !user.track_count ||
36
+ // The user is a creator and has a creator node endpoint
37
+ (user.is_creator && user.creator_node_endpoint)
38
+ ) return
39
+
40
+ console.debug('Sanity Check - isCreator - Running Check')
41
+
42
+ // Find the CIDs for all of the user's content (tracks + images)
43
+ let cids = [
44
+ user.profile_picture,
45
+ user.cover_photo
46
+ ]
47
+ const tracks = await libs.Track.getTracks(500, 0, null, user.user_id)
48
+ tracks.forEach(track => {
49
+ cids.push(track.cover_art)
50
+ cids.push(track.metadata_multihash)
51
+ track.track_segments.forEach(segment => {
52
+ cids.push(segment.multihash)
53
+ })
54
+ })
55
+ cids = cids.filter(Boolean)
56
+
57
+ // Check whether all the CIDs are availabile on a creator node
58
+ const nodes = await libs.ServiceProvider.listCreatorNodes()
59
+ const correctNode = await findCorrectNode(nodes, cids)
60
+
61
+ // Upgrade the user to a creator
62
+ if (correctNode) {
63
+ try {
64
+ console.debug('Sanity Check - isCreator - Upgrading to Creator')
65
+ await libs.User.upgradeToCreator(null, correctNode.endpoint)
66
+ } catch (e) {
67
+ console.error(e)
68
+ // We were actually a creator the whole time O_O
69
+ }
70
+ }
71
+ }
72
+
73
+ module.exports = isCreator
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Sanity check for whether a user needs a recovery email to be sent.
3
+ * Users with accounts created before email recovery existed need
4
+ * to be sent an email on their next log-in just in case they get logged
5
+ * out of their account.
6
+ */
7
+ const needsRecoveryEmail = async (libs) => {
8
+ console.debug('Sanity Check - needsRecoveryEmail')
9
+ const user = libs.userStateManager.getCurrentUser()
10
+ if (!user || !user.wallet) return
11
+
12
+ const events = await libs.identityService.getUserEvents(user.wallet)
13
+ if (events.needsRecoveryEmail) {
14
+ console.debug('Sanity Check - needsRecoveryEmail - Sending Email')
15
+ // Send email
16
+ await libs.Account.generateRecoveryLink()
17
+ }
18
+ }
19
+
20
+ module.exports = needsRecoveryEmail
@@ -0,0 +1,74 @@
1
+ const { Utils } = require('../utils')
2
+ const { CreatorNode } = require('../services/creatorNode')
3
+
4
+ const THREE_SECONDS = 3000
5
+ const MAX_TRIES = 3
6
+
7
+ /** Check if the user's primary creator node is healthy */
8
+ const checkPrimaryHealthy = async (libs, primary, tries) => {
9
+ const healthy = await Utils.isHealthy(primary)
10
+ if (healthy) return healthy
11
+ else {
12
+ if (tries === 0) {
13
+ return false
14
+ }
15
+ await Utils.wait(THREE_SECONDS)
16
+ return checkPrimaryHealthy(libs, primary, tries - 1)
17
+ }
18
+ }
19
+
20
+ /** Gets new endpoints from a user's secondaries */
21
+ const getNewPrimary = async (libs, secondaries) => {
22
+ for (const secondary of secondaries) {
23
+ const { isBehind } = await libs.creatorNode.getSyncStatus(secondary)
24
+ if (!isBehind) {
25
+ return secondary
26
+ }
27
+ }
28
+ throw new Error(`Could not find valid secondaries for user ${secondaries}`)
29
+ }
30
+
31
+ const rolloverNodes = async (libs, creatorNodeWhitelist) => {
32
+ console.debug('Sanity Check - rolloverNodes')
33
+ const user = libs.userStateManager.getCurrentUser()
34
+
35
+ if (!user || !user.is_creator) return
36
+
37
+ const primary = CreatorNode.getPrimary(user.creator_node_endpoint)
38
+ const healthy = await checkPrimaryHealthy(libs, primary, MAX_TRIES)
39
+ if (healthy) return
40
+
41
+ const secondaries = CreatorNode.getSecondaries(user.creator_node_endpoint)
42
+
43
+ try {
44
+ // Get a new primary
45
+ const newPrimary = await getNewPrimary(libs, secondaries)
46
+ const index = secondaries.indexOf(newPrimary)
47
+ // Get new secondaries and backfill up to 2
48
+ let newSecondaries = [...secondaries]
49
+ newSecondaries.splice(index, 1)
50
+ const autoselect = await libs.ServiceProvider.autoSelectCreatorNodes({
51
+ numberOfNodes: 2 - newSecondaries.length,
52
+ whitelist: creatorNodeWhitelist,
53
+ // Exclude ones we currently have
54
+ blacklist: new Set([newPrimary, ...newSecondaries]),
55
+ preferHigherPatchForPrimary: libs.User.preferHigherPatchForPrimary,
56
+ preferHigherPatchForSecondaries: libs.User.preferHigherPatchForSecondaries
57
+ })
58
+ newSecondaries = newSecondaries.concat([autoselect.primary, ...autoselect.secondaries])
59
+
60
+ // Set the new endpoint and connect to it
61
+ const newEndpoints = [newPrimary, ...newSecondaries]
62
+ await libs.creatorNode.setEndpoint(newEndpoints[0])
63
+
64
+ // Update the user
65
+ const newMetadata = { ...user }
66
+ newMetadata.creator_node_endpoint = newEndpoints.join(',')
67
+ console.debug(`Sanity Check - rolloverNodes - new nodes ${newMetadata.creator_node_endpoint}`)
68
+ await libs.User.updateCreator(user.user_id, newMetadata)
69
+ } catch (e) {
70
+ console.error(e)
71
+ }
72
+ }
73
+
74
+ module.exports = rolloverNodes
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Sanitize user.creator_node_endpoint
3
+ * Goal: Make it so we never end up in a state like creator_node_endpoint = "https://cn1.co,,"
4
+ */
5
+ const sanitizeNodes = async (libs, secondaries) => {
6
+ console.debug('Sanity Check - sanitizeNodes')
7
+ const user = libs.userStateManager.getCurrentUser()
8
+
9
+ if (!user || !user.is_creator) return
10
+
11
+ const sanitizedEndpoint = user.creator_node_endpoint
12
+ .split(',')
13
+ .filter(Boolean)
14
+ .join(',')
15
+
16
+ if (sanitizedEndpoint !== user.creator_node_endpoint) {
17
+ console.debug(`Sanity Check - sanitizingNodes - ${user.creator_node_endpoint} -> ${sanitizedEndpoint}`)
18
+ const newMetadata = { ...user }
19
+ newMetadata.creator_node_endpoint = sanitizedEndpoint
20
+ await libs.User.updateCreator(user.user_id, newMetadata)
21
+ }
22
+ }
23
+
24
+ module.exports = sanitizeNodes
@@ -0,0 +1,28 @@
1
+ const { CreatorNode } = require('../services/creatorNode')
2
+ /**
3
+ * Syncs a creator node if its blocknubmer is behind the passed
4
+ * in blocknumber.
5
+ */
6
+ const syncNodeIfBehind = async (libs, endpoint) => {
7
+ try {
8
+ const { isBehind, isConfigured } = await libs.creatorNode.getSyncStatus(endpoint)
9
+ if (isBehind || !isConfigured) {
10
+ console.debug(`Sanity Check - syncNodes - syncing ${endpoint}`)
11
+ await libs.creatorNode.syncSecondary(endpoint)
12
+ }
13
+ } catch (e) {
14
+ console.error(e)
15
+ }
16
+ }
17
+
18
+ const syncNodes = async (libs) => {
19
+ console.debug('Sanity Check - syncNodes')
20
+ const user = libs.userStateManager.getCurrentUser()
21
+
22
+ if (!user || !user.is_creator) return
23
+
24
+ const secondaries = CreatorNode.getSecondaries(user.creator_node_endpoint)
25
+ await Promise.all(secondaries.map(secondary => syncNodeIfBehind(libs, secondary)))
26
+ }
27
+
28
+ module.exports = syncNodes
@@ -0,0 +1,10 @@
1
+ export const CLAIM_DISTRIBUTION_CONTRACT_ADDRESS =
2
+ '0x683c19E621A0F107a291fdAB38f80179809d61B5'
3
+ export const ETH_OWNER_WALLET = '0xC7310a03e930DD659E15305ed7e1F5Df0F0426C5'
4
+ export const ETH_PROVIDER_URLS = 'https://eth.audius.co'
5
+ export const ETH_REGISTRY_ADDRESS = '0xd976d3b4f4e22a238c1A736b6612D22f17b6f64C'
6
+ export const ETH_TOKEN_ADDRESS = '0x18aAA7115705e8be94bfFEBDE57Af9BFc265B998'
7
+ export const IDENTITY_SERVICE_ENDPOINT = 'https://identityservice.audius.co'
8
+ export const REGISTRY_ADDRESS = '0xC611C82150b56E6e4Ec5973AcAbA8835Dd0d75A2'
9
+ export const WEB3_PROVIDER_URL = 'https://poa-gateway.audius.co'
10
+ export const WORMHOLE_ADDRESS = '0x6E7a1F7339bbB62b23D44797b63e4258d283E095'
@@ -0,0 +1 @@
1
+ export { sdk } from './sdk'
@@ -0,0 +1,265 @@
1
+ import type {
2
+ DiscoveryProvider,
3
+ UserProfile
4
+ } from '../../services/discoveryProvider'
5
+
6
+ export type LoginSuccessCallback = (profile: UserProfile) => void
7
+ export type LoginErrorCallback = (errorMessage: string) => void
8
+ export type ButtonOptions = {
9
+ size: 'small' | 'medium' | 'large'
10
+ corners: 'default' | 'pill'
11
+ customText: string
12
+ disableHoverGrow: boolean
13
+ fullWidth: boolean
14
+ }
15
+
16
+ const CSS = `
17
+ .audiusLoginButton {
18
+ cursor: pointer;
19
+ font-family: Helvetica, Arial, sans-serif;
20
+ text-align: center;
21
+ color: #FFFFFF;
22
+ font-weight: 700;
23
+ font-size: 14px;
24
+ line-height: 100%;
25
+ align-items: center;
26
+ display: flex;
27
+ border: 0;
28
+ height: 28px;
29
+ justify-content: center;
30
+ padding: 0px 16px;
31
+ background: #CC0FE0;
32
+ border-radius: 4px;
33
+ transition: all 0.07s ease-in-out;
34
+ }
35
+
36
+ .audiusLoginButton:hover {
37
+ background: #D127E3;
38
+ transform: perspective(1px) scale3d(1.04, 1.04, 1.04);
39
+ }
40
+
41
+ .audiusLoginButton.disableHoverGrow:hover {
42
+ transform: none;
43
+ }
44
+
45
+ .audiusLoginButton:active {
46
+ background: #A30CB3;
47
+ }
48
+
49
+ .audiusLoginButton.pill {
50
+ border-radius: 99px;
51
+ }
52
+
53
+ .audiusLoginButton.fullWidth {
54
+ width: 100%;
55
+ }
56
+
57
+ .audiusLoginButton.small {
58
+ height: 20px;
59
+ font-size: 11px;
60
+ padding: 0px 32px;
61
+ }
62
+
63
+ .audiusLoginButton.large {
64
+ height: 40px;
65
+ font-size: 18px;
66
+ padding: 0px 18px;
67
+ }
68
+ `
69
+ // From https://stackoverflow.com/a/27747377
70
+ const generateId = (): string => {
71
+ const arr = new Uint8Array(40 / 2) // Result of function will be 40 chars long
72
+ // @ts-expect-error TS doesn't understand `msCrypto` (which provides compatibility for IE)
73
+ ;(window.crypto || window.msCrypto).getRandomValues(arr)
74
+ return Array.from(arr, function dec2hex(dec) {
75
+ return dec.toString(16).padStart(2, '0')
76
+ }).join('')
77
+ }
78
+
79
+ const generateAudiusLogoSvg = (size: 'small' | 'medium' | 'large') => {
80
+ let height: number
81
+ let paddingRight: number
82
+ if (size === 'small') {
83
+ height = 16
84
+ paddingRight = 5
85
+ } else if (size === 'medium') {
86
+ height = 18
87
+ paddingRight = 5
88
+ } else {
89
+ height = 24
90
+ paddingRight = 10
91
+ }
92
+ return `<svg width="${height}px" height="${height}px" viewBox="0 0 56 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="padding-right: ${paddingRight}px;">
93
+ <g id="Assets" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
94
+ <g id="assets" transform="translate(-1555.000000, -2588.000000)">
95
+ <g id="audiusLogoGlyph" transform="translate(1555.000000, 2588.000000)">
96
+ <path d="M55.8191698,46.0362519 L42.4551012,23.3458831 L36.1870263,12.7036635 L29.0910326,0.65551431 C28.5766233,-0.217848954 27.2890668,-0.218676884 26.7734944,0.654065432 L13.3787621,23.3270477 L7.90582764,32.5909699 C7.39025522,33.4637122 8.03324043,34.5553386 9.06332791,34.5560631 L19.4031138,34.56279 C19.881044,34.5631005 20.3230236,34.3136864 20.5623059,33.9087249 L25.9362708,24.8122516 L26.7580568,23.4212248 C26.790518,23.3662709 26.8260456,23.3149392 26.8641108,23.2669192 C27.4325516,22.5520012 28.5935412,22.6041608 29.0755951,23.4226737 L34.6514114,32.8894388 L35.682239,34.6396841 C35.7412402,34.7399672 35.7843808,34.8430445 35.813987,34.9470533 C36.0430129,35.7492145 35.4339691,36.6039494 34.5220954,36.6034319 L22.3586676,36.5954631 C21.8806317,36.5951526 21.4387578,36.8445667 21.1994756,37.2496317 L16.0236614,46.0105861 C15.5080889,46.8833284 16.1510741,47.9749548 17.1810559,47.9756793 L27.9002253,47.9827167 L41.2664086,47.9913065 L54.6590261,47.9999997 C55.6892193,48.0006207 56.3335791,46.9096152 55.8191698,46.0362519" id="Audius-Logo" fill="#ffffff" fill-rule="evenodd"></path>
97
+ <rect id="bound" x="0" y="0" width="56" height="48"></rect>
98
+ </g>
99
+ </g>
100
+ </g>
101
+ </svg>`
102
+ }
103
+
104
+ const OAUTH_URL = 'https://audius.co/oauth/auth'
105
+ const CSRF_TOKEN_KEY = 'audiusOauthState'
106
+
107
+ type OauthConfig = {
108
+ appName?: string
109
+ discoveryProvider: DiscoveryProvider
110
+ }
111
+
112
+ export class Oauth {
113
+ discoveryProvider: DiscoveryProvider
114
+ appName: string | null
115
+ activePopupWindow: null | Window
116
+ popupCheckInterval: NodeJS.Timer | null
117
+ loginSuccessCallback: LoginSuccessCallback | null
118
+ loginErrorCallback: LoginErrorCallback | null
119
+
120
+ constructor({ discoveryProvider, appName }: OauthConfig) {
121
+ if (typeof window === 'undefined') {
122
+ // TODO(nkang): Add link to documentation once written
123
+ throw new Error(
124
+ 'Audius OAuth SDK functions are only available in browser. Refer to our documentation to learn how to implement Audius OAuth manually.'
125
+ )
126
+ }
127
+ this.discoveryProvider = discoveryProvider
128
+ this.appName = appName ?? null
129
+ this.activePopupWindow = null
130
+ this.loginSuccessCallback = null
131
+ this.loginErrorCallback = null
132
+ this.popupCheckInterval = null
133
+ }
134
+
135
+ init(
136
+ successCallback: LoginSuccessCallback,
137
+ errorCallback?: LoginErrorCallback
138
+ ) {
139
+ this.loginSuccessCallback = successCallback
140
+ this.loginErrorCallback = errorCallback ?? null
141
+ window.addEventListener(
142
+ 'message',
143
+ (e: MessageEvent) => {
144
+ this._receiveMessage(e)
145
+ },
146
+ false
147
+ )
148
+ }
149
+
150
+ login() {
151
+ if (!this.appName) {
152
+ this._surfaceError('App name not set (set with `init` method).')
153
+ return
154
+ }
155
+ if (!this.loginSuccessCallback) {
156
+ this._surfaceError(
157
+ 'Login success callback not set (set with `init` method).'
158
+ )
159
+ return
160
+ }
161
+
162
+ const csrfToken = generateId()
163
+ window.localStorage.setItem(CSRF_TOKEN_KEY, csrfToken)
164
+ const windowOptions =
165
+ 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=375, height=720, top=100, left=100'
166
+ const originURISafe = encodeURIComponent(window.location.origin)
167
+ const appNameURISafe = encodeURI(this.appName)
168
+ const fullOauthUrl = `${OAUTH_URL}?scope=read&state=${csrfToken}&redirect_uri=postMessage&origin=${originURISafe}&app_name=${appNameURISafe}`
169
+ this.activePopupWindow = window.open(fullOauthUrl, '', windowOptions)
170
+ this._clearPopupCheckInterval()
171
+ this.popupCheckInterval = setInterval(() => {
172
+ if (this.activePopupWindow?.closed) {
173
+ this._surfaceError('The login popup was closed prematurely.')
174
+ if (this.popupCheckInterval) {
175
+ clearInterval(this.popupCheckInterval)
176
+ }
177
+ }
178
+ }, 500)
179
+ }
180
+
181
+ renderButton(element: HTMLElement, options?: ButtonOptions) {
182
+ if (!element) {
183
+ console.error('Target element for Audius OAuth button is empty.')
184
+ }
185
+ const style = document.createElement('style')
186
+ style.textContent = CSS
187
+ document.head.appendChild(style)
188
+ const button = document.createElement('button')
189
+ button.id = 'audius-login-button'
190
+ button.classList.add('audiusLoginButton')
191
+ if (options?.corners === 'pill') {
192
+ button.classList.add('pill')
193
+ }
194
+ if (options?.size === 'small') {
195
+ button.classList.add('small')
196
+ }
197
+ if (options?.size === 'large') {
198
+ button.classList.add('large')
199
+ }
200
+ if (options?.fullWidth) {
201
+ button.classList.add('fullWidth')
202
+ }
203
+ if (options?.disableHoverGrow) {
204
+ button.classList.add('disableHoverGrow')
205
+ }
206
+ button.innerHTML = `${generateAudiusLogoSvg(options?.size ?? 'medium')} ${
207
+ options?.customText ?? 'Continue With Audius'
208
+ }`
209
+ button.onclick = () => {
210
+ this.login()
211
+ }
212
+ element.replaceWith(button)
213
+ }
214
+
215
+ async verifyToken(token: string) {
216
+ return await this.discoveryProvider.verifyToken(token)
217
+ }
218
+
219
+ /* ------- INTERNAL FUNCTIONS ------- */
220
+
221
+ _surfaceError(errorMessage: string) {
222
+ if (this.loginErrorCallback) {
223
+ this.loginErrorCallback(errorMessage)
224
+ } else {
225
+ console.error(errorMessage)
226
+ }
227
+ }
228
+
229
+ _clearPopupCheckInterval() {
230
+ if (this.popupCheckInterval) {
231
+ clearInterval(this.popupCheckInterval)
232
+ }
233
+ }
234
+
235
+ async _receiveMessage(event: MessageEvent) {
236
+ const oauthOrigin = new URL(OAUTH_URL).origin
237
+ if (
238
+ event.origin !== oauthOrigin ||
239
+ event.source !== this.activePopupWindow ||
240
+ !event.data.state ||
241
+ !event.data.token
242
+ ) {
243
+ return
244
+ }
245
+ this._clearPopupCheckInterval()
246
+ if (this.activePopupWindow) {
247
+ if (!this.activePopupWindow.closed) {
248
+ this.activePopupWindow.close()
249
+ }
250
+ this.activePopupWindow = null
251
+ }
252
+ if (window.localStorage.getItem(CSRF_TOKEN_KEY) !== event.data.state) {
253
+ this._surfaceError('State mismatch.')
254
+ }
255
+ // Verify token and decode
256
+ const decodedJwt = await this.verifyToken(event.data.token)
257
+ if (decodedJwt) {
258
+ if (this.loginSuccessCallback) {
259
+ this.loginSuccessCallback(decodedJwt)
260
+ }
261
+ } else {
262
+ this._surfaceError('The token was invalid.')
263
+ }
264
+ }
265
+ }
@@ -0,0 +1 @@
1
+ export * from './Oauth'
package/src/sdk/sdk.ts ADDED
@@ -0,0 +1,102 @@
1
+ import {
2
+ DiscoveryProvider,
3
+ DiscoveryProviderConfig
4
+ } from '../services/discoveryProvider'
5
+ import { EthContracts, EthContractsConfig } from '../services/ethContracts'
6
+ import { EthWeb3Config, EthWeb3Manager } from '../services/ethWeb3Manager'
7
+ import { IdentityService } from '../services/identity'
8
+ import { UserStateManager } from '../userStateManager'
9
+ import { Oauth } from './oauth'
10
+
11
+ import {
12
+ CLAIM_DISTRIBUTION_CONTRACT_ADDRESS,
13
+ ETH_OWNER_WALLET,
14
+ ETH_PROVIDER_URLS,
15
+ ETH_REGISTRY_ADDRESS,
16
+ ETH_TOKEN_ADDRESS,
17
+ IDENTITY_SERVICE_ENDPOINT,
18
+ WORMHOLE_ADDRESS
19
+ } from './constants'
20
+
21
+ type Web3Config = {
22
+ providers: string[]
23
+ }
24
+
25
+ type SdkConfig = {
26
+ appName: string
27
+ discoveryNodeConfig?: DiscoveryProviderConfig
28
+ ethContractsConfig?: EthContractsConfig
29
+ ethWeb3Config?: EthWeb3Config
30
+ identityServiceConfig?: IdentityService
31
+ web3Config?: Web3Config
32
+ }
33
+
34
+ /**
35
+ * The Audius SDK
36
+ */
37
+ export const sdk = async (config?: SdkConfig) => {
38
+ const {
39
+ appName,
40
+ discoveryNodeConfig,
41
+ ethContractsConfig,
42
+ ethWeb3Config,
43
+ identityServiceConfig
44
+ } = config ?? {}
45
+
46
+ /** Initialize services */
47
+
48
+ const userStateManager = new UserStateManager()
49
+
50
+ const identityService = new IdentityService({
51
+ identityServiceEndpoint: IDENTITY_SERVICE_ENDPOINT,
52
+ ...identityServiceConfig
53
+ })
54
+
55
+ const ethWeb3Manager = new EthWeb3Manager({
56
+ identityService,
57
+ web3Config: {
58
+ ownerWallet: ETH_OWNER_WALLET,
59
+ ...ethWeb3Config,
60
+ providers: formatProviders(ethWeb3Config?.providers ?? ETH_PROVIDER_URLS)
61
+ }
62
+ })
63
+
64
+ const ethContracts = new EthContracts({
65
+ ethWeb3Manager,
66
+ tokenContractAddress: ETH_TOKEN_ADDRESS,
67
+ registryAddress: ETH_REGISTRY_ADDRESS,
68
+ claimDistributionContractAddress: CLAIM_DISTRIBUTION_CONTRACT_ADDRESS,
69
+ wormholeContractAddress: WORMHOLE_ADDRESS,
70
+ ...ethContractsConfig
71
+ })
72
+
73
+ const discoveryNode = new DiscoveryProvider({
74
+ ethContracts,
75
+ userStateManager,
76
+ ...discoveryNodeConfig
77
+ })
78
+
79
+ // TODO: potentially don't await this and have a different method (callback/event) to
80
+ // know when the sdk is initialized
81
+ await discoveryNode.init()
82
+
83
+ const oauth =
84
+ typeof window !== 'undefined'
85
+ ? new Oauth({ discoveryProvider: discoveryNode, appName })
86
+ : undefined
87
+
88
+ return {
89
+ oauth,
90
+ discoveryNode
91
+ }
92
+ }
93
+
94
+ const formatProviders = (providers: string | string[]) => {
95
+ if (typeof providers === 'string') {
96
+ return providers.split(',')
97
+ } else if (Array.isArray(providers)) {
98
+ return providers
99
+ } else {
100
+ throw new Error('Providers must be of type string, Array, or Web3 instance')
101
+ }
102
+ }