@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,670 @@
1
+ const { Base, Services } = require('./base')
2
+ const { CreatorNode } = require('../services/creatorNode')
3
+ const { Utils } = require('../utils')
4
+ const { AuthHeaders } = require('../constants')
5
+ const {
6
+ getPermitDigest, sign
7
+ } = require('../utils/signatures')
8
+ const { PublicKey } = require('@solana/web3.js')
9
+ const { BN } = require('@project-serum/anchor')
10
+
11
+ class Account extends Base {
12
+ constructor (userApi, ...services) {
13
+ super(...services)
14
+
15
+ this.User = userApi
16
+
17
+ this.getCurrentUser = this.getCurrentUser.bind(this)
18
+ this.login = this.login.bind(this)
19
+ this.logout = this.logout.bind(this)
20
+ this.signUp = this.signUp.bind(this)
21
+ this.generateRecoveryLink = this.generateRecoveryLink.bind(this)
22
+ this.confirmCredentials = this.confirmCredentials.bind(this)
23
+ this.changePassword = this.changePassword.bind(this)
24
+ this.resetPassword = this.resetPassword.bind(this)
25
+ this.checkIfEmailRegistered = this.checkIfEmailRegistered.bind(this)
26
+ this.getUserEmail = this.getUserEmail.bind(this)
27
+ this.associateTwitterUser = this.associateTwitterUser.bind(this)
28
+ this.associateInstagramUser = this.associateInstagramUser.bind(this)
29
+ this.handleIsValid = this.handleIsValid.bind(this)
30
+ this.lookupTwitterHandle = this.lookupTwitterHandle.bind(this)
31
+ this.updateCreatorNodeEndpoint = this.updateCreatorNodeEndpoint.bind(this)
32
+ this.searchFull = this.searchFull.bind(this)
33
+ this.searchAutocomplete = this.searchAutocomplete.bind(this)
34
+ this.searchTags = this.searchTags.bind(this)
35
+ this.sendTokensFromEthToSol = this.sendTokensFromEthToSol.bind(this)
36
+ this.sendTokensFromSolToEth = this.sendTokensFromSolToEth.bind(this)
37
+ this.getUserAccountOnSolana = this.getUserAccountOnSolana.bind(this)
38
+ this.userHasClaimedSolAccount = this.userHasClaimedSolAccount.bind(this)
39
+ }
40
+
41
+ /**
42
+ * Fetches the user metadata for the current account
43
+ * @return {Object} user metadata
44
+ */
45
+ getCurrentUser () {
46
+ return this.userStateManager.getCurrentUser()
47
+ }
48
+
49
+ /**
50
+ * Logs a user into Audius
51
+ * @param {string} email
52
+ * @param {string} password
53
+ */
54
+ async login (email, password) {
55
+ const phases = {
56
+ FIND_WALLET: 'FIND_WALLET',
57
+ FIND_USER: 'FIND_USER'
58
+ }
59
+ let phase = ''
60
+
61
+ phase = phases.FIND_WALLET
62
+ if (!this.web3Manager.web3IsExternal()) {
63
+ this.REQUIRES(Services.HEDGEHOG)
64
+
65
+ try {
66
+ const ownerWallet = await this.hedgehog.login(email, password)
67
+ await this.web3Manager.setOwnerWallet(ownerWallet)
68
+ } catch (e) {
69
+ return { error: e.message, phase }
70
+ }
71
+ }
72
+
73
+ phase = phases.FIND_USER
74
+ const userAccount = await this.discoveryProvider.getUserAccount(this.web3Manager.getWalletAddress())
75
+ if (userAccount) {
76
+ this.userStateManager.setCurrentUser(userAccount)
77
+ const creatorNodeEndpoint = userAccount.creator_node_endpoint
78
+ if (creatorNodeEndpoint) {
79
+ this.creatorNode.setEndpoint(CreatorNode.getPrimary(creatorNodeEndpoint))
80
+ }
81
+ return { user: userAccount, error: false, phase }
82
+ }
83
+ return { error: 'No user found', phase }
84
+ }
85
+
86
+ /**
87
+ * Logs a user out of Audius
88
+ * Note: Actions will stop working at this point, but
89
+ * clients may wish to call window.location.reload()
90
+ * to show the user as logged out
91
+ */
92
+ logout () {
93
+ if (!this.web3Manager.web3IsExternal()) {
94
+ this.REQUIRES(Services.HEDGEHOG)
95
+ this.hedgehog.logout()
96
+ this.userStateManager.clearUser()
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Signs a user up for Audius
102
+ * @param {string} email
103
+ * @param {string} password
104
+ * @param {Object} metadata
105
+ * @param {?File} [profilePictureFile] an optional file to upload as the profile picture
106
+ * @param {?File} [coverPhotoFile] an optional file to upload as the cover phtoo
107
+ * @param {?boolean} [hasWallet]
108
+ * @param {?boolean} [host] The host url used for the recovery email
109
+ * @param {?boolean} [createWAudioUserBank] an optional flag to create the solana user bank account
110
+ * @param {?Function} [handleUserBankOutcomes] an optional callback to record user bank outcomes
111
+ * @param {?Object} [userBankOutcomes] an optional object with request, succes, and failure keys to record user bank outcomes
112
+ * @param {?string} [feePayerOverride] an optional string in case the client wants to switch between fee payers
113
+ * @param {?boolean} [generateRecoveryLink] an optional flag to skip generating recovery link for testing purposes
114
+ */
115
+ async signUp (
116
+ email,
117
+ password,
118
+ metadata,
119
+ profilePictureFile = null,
120
+ coverPhotoFile = null,
121
+ hasWallet = false,
122
+ host = (typeof window !== 'undefined' && window.location.origin) || null,
123
+ handleUserBankOutcomes = () => {},
124
+ userBankOutcomes = {},
125
+ feePayerOverride = null,
126
+ generateRecoveryLink = true
127
+ ) {
128
+ const phases = {
129
+ ADD_REPLICA_SET: 'ADD_REPLICA_SET',
130
+ CREATE_USER_RECORD: 'CREATE_USER_RECORD',
131
+ HEDGEHOG_SIGNUP: 'HEDGEHOG_SIGNUP',
132
+ SOLANA_USER_BANK_CREATION: 'SOLANA_USER_BANK_CREATION',
133
+ UPLOAD_PROFILE_IMAGES: 'UPLOAD_PROFILE_IMAGES',
134
+ ADD_USER: 'ADD_USER'
135
+ }
136
+ let phase = ''
137
+ let userId, blockHash, blockNumber
138
+
139
+ try {
140
+ this.REQUIRES(Services.CREATOR_NODE, Services.IDENTITY_SERVICE)
141
+
142
+ if (this.web3Manager.web3IsExternal()) {
143
+ phase = phases.CREATE_USER_RECORD
144
+ await this.identityService.createUserRecord(email, this.web3Manager.getWalletAddress())
145
+ } else {
146
+ this.REQUIRES(Services.HEDGEHOG)
147
+ // If an owner wallet already exists, don't try to recreate it
148
+ if (!hasWallet) {
149
+ phase = phases.HEDGEHOG_SIGNUP
150
+ const ownerWallet = await this.hedgehog.signUp(email, password)
151
+ await this.web3Manager.setOwnerWallet(ownerWallet)
152
+ if (generateRecoveryLink) {
153
+ await this.generateRecoveryLink({ handle: metadata.handle, host })
154
+ }
155
+ }
156
+ }
157
+
158
+ // Create a wAudio user bank address.
159
+ // If userbank creation fails, we still proceed
160
+ // through signup
161
+ if (this.solanaWeb3Manager) {
162
+ phase = phases.SOLANA_USER_BANK_CREATION;
163
+ // Fire and forget createUserBank. In the case of failure, we will
164
+ // retry to create user banks in a later session before usage
165
+ (async () => {
166
+ try {
167
+ handleUserBankOutcomes(userBankOutcomes.Request)
168
+ const { error, errorCode } = await this.solanaWeb3Manager.createUserBank(feePayerOverride)
169
+ if (error || errorCode) {
170
+ console.error(
171
+ `Failed to create userbank, with err: ${error}, ${errorCode}`
172
+ )
173
+ handleUserBankOutcomes(userBankOutcomes.Failure, { error, errorCode })
174
+ } else {
175
+ console.log('Successfully created userbank!')
176
+ handleUserBankOutcomes('Create User Bank: Success')
177
+ }
178
+ } catch (err) {
179
+ console.error(`Got error creating userbank: ${err}, continuing...`)
180
+ handleUserBankOutcomes(userBankOutcomes.Failure, { error: err.toString() })
181
+ }
182
+ })()
183
+ }
184
+
185
+ // Add user to chain
186
+ phase = phases.ADD_USER
187
+ const response = await this.User.addUser(metadata)
188
+ userId = response.userId
189
+ blockHash = response.blockHash
190
+ blockNumber = response.blockNumber
191
+
192
+ // Assign replica set to user, updates creator_node_endpoint on chain, and then update metadata object on content node + chain (in this order)
193
+ phase = phases.ADD_REPLICA_SET
194
+ metadata = await this.User.assignReplicaSet({ userId })
195
+
196
+ // Upload profile pic and cover photo to primary Content Node and sync across secondaries
197
+ phase = phases.UPLOAD_PROFILE_IMAGES
198
+ await this.User.uploadProfileImages(profilePictureFile, coverPhotoFile, metadata)
199
+ } catch (e) {
200
+ return { error: e.message, phase, errorStatus: e.response ? e.response.status : null }
201
+ }
202
+ return { blockHash, blockNumber, userId }
203
+ }
204
+
205
+ /**
206
+ * Generates and sends a recovery email for a user
207
+ * @param {string} [handle] The user handle, defaults to the current user handle
208
+ * @param {string} [host] The host domain, defaults to window.location.origin
209
+ */
210
+ async generateRecoveryLink ({ handle, host } = {}) {
211
+ this.REQUIRES(Services.IDENTITY_SERVICE)
212
+ try {
213
+ const recoveryInfo = await this.hedgehog.generateRecoveryInfo()
214
+ handle = handle || this.userStateManager.getCurrentUser().handle
215
+
216
+ const unixTs = Math.round((new Date()).getTime() / 1000) // current unix timestamp (sec)
217
+ const data = `Click sign to authenticate with identity service: ${unixTs}`
218
+ const signature = await this.web3Manager.sign(data)
219
+
220
+ const recoveryData = {
221
+ login: recoveryInfo.login,
222
+ host: host || recoveryInfo.host,
223
+ data,
224
+ signature,
225
+ handle
226
+ }
227
+
228
+ await this.identityService.sendRecoveryInfo(recoveryData)
229
+ } catch (e) {
230
+ console.error(e)
231
+ }
232
+ }
233
+
234
+ async resetPassword (email, newpassword) {
235
+ return this.hedgehog.resetPassword(email, newpassword)
236
+ }
237
+
238
+ async changePassword (email, newpassword, oldpassword) {
239
+ return this.hedgehog.changePassword(email, newpassword, oldpassword)
240
+ }
241
+
242
+ async confirmCredentials (email, password) {
243
+ return this.hedgehog.confirmCredentials(email, password)
244
+ }
245
+
246
+ /**
247
+ * Check if an email address has been previously registered.
248
+ * @param {string} email
249
+ * @returns {{exists: boolean}}
250
+ */
251
+ async checkIfEmailRegistered (email) {
252
+ this.REQUIRES(Services.IDENTITY_SERVICE)
253
+ return this.identityService.checkIfEmailRegistered(email)
254
+ }
255
+
256
+ /**
257
+ * Get the current user's email address
258
+ * @returns {{email: string | undefined | null}}
259
+ */
260
+ async getUserEmail () {
261
+ this.REQUIRES(Services.IDENTITY_SERVICE)
262
+ return this.identityService.getUserEmail()
263
+ }
264
+
265
+ /**
266
+ * Associates a user with a twitter uuid.
267
+ * @param {string} uuid from the Twitter API
268
+ * @param {number} userId
269
+ * @param {string} handle
270
+ */
271
+ async associateTwitterUser (uuid, userId, handle) {
272
+ this.REQUIRES(Services.IDENTITY_SERVICE)
273
+ return this.identityService.associateTwitterUser(uuid, userId, handle)
274
+ }
275
+
276
+ /**
277
+ * Associates a user with an instagram uuid.
278
+ * @param {string} uuid from the Instagram API
279
+ * @param {number} userId
280
+ * @param {string} handle
281
+ */
282
+ async associateInstagramUser (uuid, userId, handle) {
283
+ this.REQUIRES(Services.IDENTITY_SERVICE)
284
+ return this.identityService.associateInstagramUser(uuid, userId, handle)
285
+ }
286
+
287
+ /**
288
+ * Checks if a requested handle is valid (unused).
289
+ * @param {string} handle
290
+ */
291
+ async handleIsValid (handle) {
292
+ return this.contracts.UserFactoryClient.handleIsValid(handle)
293
+ }
294
+
295
+ /**
296
+ * Looks up a Twitter account by handle.
297
+ * @returns {Object} twitter API response.
298
+ */
299
+ async lookupTwitterHandle (handle) {
300
+ this.REQUIRES(Services.IDENTITY_SERVICE)
301
+ return this.identityService.lookupTwitterHandle(handle)
302
+ }
303
+
304
+ /**
305
+ * Updates a user's creator node endpoint. Sets the connected creator node in the libs instance
306
+ * and updates the user's metadata blob.
307
+ * @param {string} url
308
+ */
309
+ async updateCreatorNodeEndpoint (url) {
310
+ this.REQUIRES(Services.CREATOR_NODE)
311
+
312
+ const user = this.userStateManager.getCurrentUser()
313
+ if (user.is_creator) {
314
+ await this.creatorNode.setEndpoint(url)
315
+ // Only a creator will have a creator node endpoint
316
+ user.creator_node_endpoint = url
317
+ await this.User.updateCreator(user.user_id, user)
318
+ }
319
+ }
320
+
321
+ /**
322
+ * Perform a full-text search. Returns tracks, users, playlists, albums
323
+ * with optional user-specific results for each
324
+ * - user, track, and playlist objects have all same data as returned from standalone endpoints
325
+ * @param {string} text search query
326
+ * @param {string} kind 'tracks', 'users', 'playlists', 'albums', 'all'
327
+ * @param {number} limit max # of items to return per list (for pagination)
328
+ * @param {number} offset offset into list to return from (for pagination)
329
+ */
330
+ async searchFull (text, kind, limit = 100, offset = 0) {
331
+ this.REQUIRES(Services.DISCOVERY_PROVIDER)
332
+ return this.discoveryProvider.searchFull(text, kind, limit, offset)
333
+ }
334
+
335
+ /**
336
+ * Perform a lighter-weight full-text search. Returns tracks, users, playlists, albums
337
+ * with optional user-specific results for each
338
+ * - user, track, and playlist objects have core data, and track & playlist objects
339
+ * also return user object
340
+ * @param {string} text search query
341
+ * @param {number} limit max # of items to return per list (for pagination)
342
+ * @param {number} offset offset into list to return from (for pagination)
343
+ */
344
+ async searchAutocomplete (text, limit = 100, offset = 0) {
345
+ this.REQUIRES(Services.DISCOVERY_PROVIDER)
346
+ return this.discoveryProvider.searchAutocomplete(text, limit, offset)
347
+ }
348
+
349
+ /**
350
+ * Perform a tags-only search. Returns tracks with required tag and users
351
+ * that have used a tag greater than a specified number of times
352
+ * @param {string} text search query
353
+ * @param {number} user_tag_count min # of times a user must have used a tag to be returned
354
+ * @param {string} kind 'tracks', 'users', 'playlists', 'albums', 'all'
355
+ * @param {number} limit max # of items to return per list (for pagination)
356
+ * @param {number} offset offset into list to return from (for pagination)
357
+ */
358
+ async searchTags (text, user_tag_count = 2, kind, limit = 100, offset = 0) {
359
+ this.REQUIRES(Services.DISCOVERY_PROVIDER)
360
+ return this.discoveryProvider.searchTags(text, user_tag_count, kind, limit, offset)
361
+ }
362
+
363
+ /**
364
+ * Check if the user has a distribution claim
365
+ * @param {number?} index The index of the claim to check (if known)
366
+ */
367
+ async getHasClaimed (index) {
368
+ this.REQUIRES(Services.COMSTOCK)
369
+ if (index) {
370
+ return this.ethContracts.ClaimDistributionClient.isClaimed(index)
371
+ }
372
+ const userWallet = this.web3Manager.getWalletAddress()
373
+ const web3 = this.web3Manager.getWeb3()
374
+ const wallet = web3.utils.toChecksumAddress(userWallet)
375
+ const claim = await this.comstock.getComstock({ wallet })
376
+ return this.ethContracts.ClaimDistributionClient.isClaimed(claim.index)
377
+ }
378
+
379
+ /**
380
+ * Get the distribution claim amount
381
+ */
382
+ async getClaimDistributionAmount () {
383
+ this.REQUIRES(Services.COMSTOCK)
384
+ const userWallet = this.web3Manager.getWalletAddress()
385
+ const web3 = this.web3Manager.getWeb3()
386
+ const wallet = web3.utils.toChecksumAddress(userWallet)
387
+ const claimDistribution = await this.comstock.getComstock({ wallet })
388
+ const amount = Utils.toBN(claimDistribution.amount.replace('0x', ''), 16)
389
+ return amount
390
+ }
391
+
392
+ /**
393
+ * Make the claim
394
+ * @param {number?} index The index of the claim to check
395
+ * @param {BN?} amount The amount to be claimed
396
+ * @param {Array<string>?} merkleProof The merkle proof for the claim
397
+ */
398
+ async makeDistributionClaim (index, amount, merkleProof) {
399
+ this.REQUIRES(Services.COMSTOCK, Services.IDENTITY_SERVICE)
400
+ const userWallet = this.web3Manager.getWalletAddress()
401
+ const web3 = this.web3Manager.getWeb3()
402
+ const wallet = web3.utils.toChecksumAddress(userWallet)
403
+ if (index && amount && merkleProof) {
404
+ return this.ethContracts.ClaimDistributionClient.claim(
405
+ index,
406
+ userWallet,
407
+ amount,
408
+ merkleProof
409
+ )
410
+ }
411
+ const claim = await this.comstock.getComstock({ wallet })
412
+ return this.ethContracts.ClaimDistributionClient.claim(
413
+ claim.index,
414
+ userWallet,
415
+ claim.amount,
416
+ claim.proof
417
+ )
418
+ }
419
+
420
+ /**
421
+ * Sends `amount` tokens to `recipientAddress`
422
+ */
423
+ async permitAndSendTokens (recipientAddress, amount) {
424
+ this.REQUIRES(Services.IDENTITY_SERVICE)
425
+ const myWalletAddress = this.web3Manager.getWalletAddress()
426
+ const { selectedEthWallet } = await this.identityService.getEthRelayer(myWalletAddress)
427
+ await this.permitProxySendTokens(myWalletAddress, selectedEthWallet, amount)
428
+ await this.sendTokens(myWalletAddress, recipientAddress, selectedEthWallet, amount)
429
+ }
430
+
431
+ /**
432
+ * Sends Eth `amount` tokens to `solanaAccount` by way of the wormhole
433
+ * 1.) Permits the eth relay to proxy send tokens on behalf of the user
434
+ * 2.) Transfers the tokens on the eth side to the wormhole contract
435
+ * 3.) Gathers attestations from wormhole oracles and relizes the tokens on sol
436
+ */
437
+ async sendTokensFromEthToSol (amount, solanaAccount) {
438
+ this.REQUIRES(Services.IDENTITY_SERVICE)
439
+ const phases = {
440
+ PERMIT_PROXY_SEND: 'PERMIT_PROXY_SEND',
441
+ TRANSFER_TOKENS: 'TRANSFER_TOKENS',
442
+ ATTEST_AND_COMPLETE_TRANSFER: 'ATTEST_AND_COMPLETE_TRANSFER'
443
+ }
444
+ let phase = phases.PERMIT_PROXY_SEND
445
+ const logs = [`Send tokens from eth to sol to ${solanaAccount} for ${amount.toString()}`]
446
+ try {
447
+ const myWalletAddress = this.web3Manager.getWalletAddress()
448
+ const wormholeAddress = this.ethContracts.WormholeClient.contractAddress
449
+ const { selectedEthWallet } = await this.identityService.getEthRelayer(myWalletAddress)
450
+ await this.permitProxySendTokens(myWalletAddress, wormholeAddress, amount)
451
+
452
+ logs.push('Completed permit proxy send tokens')
453
+ phase = phases.TRANSFER_TOKENS
454
+ const transferTokensTx = await this.wormholeClient.transferTokensToEthWormhole(
455
+ myWalletAddress, amount, solanaAccount, selectedEthWallet
456
+ )
457
+
458
+ const transferTransactionHash = transferTokensTx.txHash
459
+ logs.push(`Completed transfer tokens with tx ${transferTransactionHash}`)
460
+ phase = phases.ATTEST_AND_COMPLETE_TRANSFER
461
+
462
+ const response = await this.wormholeClient.attestAndCompleteTransferEthToSol(transferTransactionHash)
463
+ if (response.transactionSignature) {
464
+ logs.push(`Receive sol wrapped tokens in tx ${response.transactionSignature}`)
465
+ }
466
+ return {
467
+ txSignature: response.transactionSignature,
468
+ phase: response.phase,
469
+ error: response.error || null,
470
+ logs: logs.concat(response.logs)
471
+ }
472
+ } catch (error) {
473
+ return {
474
+ error: error.message,
475
+ phase,
476
+ logs
477
+ }
478
+ }
479
+ }
480
+
481
+ /**
482
+ * Sends Eth `amount` tokens to `solanaAccount` on the identity service
483
+ * by way of the wormhole.
484
+ */
485
+ async proxySendTokensFromEthToSol (amount, solanaAccount) {
486
+ this.REQUIRES(Services.IDENTITY_SERVICE)
487
+ const myWalletAddress = this.web3Manager.getWalletAddress()
488
+ const wormholeAddress = this.ethContracts.WormholeClient.contractAddress
489
+ const { selectedEthWallet } = await this.identityService.getEthRelayer(myWalletAddress)
490
+ const permitMethod = await this.getPermitProxySendTokensMethod(myWalletAddress, wormholeAddress, amount)
491
+ const permit = await this.ethWeb3Manager.getRelayMethodParams(this.ethContracts.AudiusTokenClient.contractAddress, permitMethod, selectedEthWallet)
492
+ const transferTokensMethod = await this.wormholeClient.getTransferTokensToEthWormholeMethod(
493
+
494
+ myWalletAddress, amount, solanaAccount, selectedEthWallet
495
+ )
496
+ const transferTokens = await this.ethWeb3Manager.getRelayMethodParams(this.ethContracts.WormholeClient.contractAddress, transferTokensMethod, selectedEthWallet)
497
+ return this.identityService.wormholeRelay({
498
+ senderAddress: myWalletAddress,
499
+ permit,
500
+ transferTokens
501
+ })
502
+ }
503
+
504
+ /**
505
+ * Sends `amount` tokens to `ethAccount` by way of the wormhole
506
+ * 1.) Creates a solana root wallet
507
+ * 2.) Sends the tokens from the user bank account to the solana wallet
508
+ * 3.) Permits the solana wallet to approve transfer to wormhole
509
+ * 4.) Transfers to the wrapped audio to the sol wormhole contract
510
+ * 5.) Gathers attestations from wormhole oracles and realizes the tokens on eth
511
+ */
512
+ async sendTokensFromSolToEth (amount, ethAccount) {
513
+ const { error, logs, phase } = await this.wormholeClient.sendTokensFromSolToEthViaWormhole(amount, ethAccount)
514
+ return { error, logs, phase }
515
+ }
516
+
517
+ async _getPermitProxySendTokensParams (owner, relayerAddress, amount) {
518
+ const web3 = this.ethWeb3Manager.getWeb3()
519
+ const myPrivateKey = this.web3Manager.getOwnerWalletPrivateKey()
520
+ const chainId = await new Promise(resolve => web3.eth.getChainId((_, chainId) => resolve(chainId)))
521
+ const name = await this.ethContracts.AudiusTokenClient.name()
522
+ const tokenAddress = this.ethContracts.AudiusTokenClient.contractAddress
523
+
524
+ // Submit permit request to give address approval, via relayer
525
+ const nonce = await this.ethContracts.AudiusTokenClient.nonces(owner)
526
+ const currentBlockNumber = await web3.eth.getBlockNumber()
527
+ const currentBlock = await web3.eth.getBlock(currentBlockNumber)
528
+ // 1 hour, sufficiently far in future
529
+ const deadline = currentBlock.timestamp + (60 * 60 * 1)
530
+
531
+ const digest = getPermitDigest(
532
+ web3,
533
+ name,
534
+ tokenAddress,
535
+ chainId,
536
+ { owner: owner, spender: relayerAddress, value: amount },
537
+ nonce,
538
+ deadline
539
+ )
540
+ const result = sign(digest, myPrivateKey)
541
+ return {
542
+ result,
543
+ deadline
544
+ }
545
+ }
546
+
547
+ /**
548
+ * Permits `relayerAddress` to send `amount` on behalf of the current user, `owner`
549
+ */
550
+ async permitProxySendTokens (owner, relayerAddress, amount) {
551
+ const {
552
+ result,
553
+ deadline
554
+ } = await this._getPermitProxySendTokensParams(owner, relayerAddress, amount)
555
+ const tx = await this.ethContracts.AudiusTokenClient.permit(
556
+ owner,
557
+ relayerAddress,
558
+ amount,
559
+ deadline,
560
+ result.v,
561
+ result.r,
562
+ result.s
563
+ )
564
+ return tx
565
+ }
566
+
567
+ /**
568
+ * Gets the permit method to proxy send tokens `relayerAddress` to send `amount` on behalf of the current user, `owner`
569
+ */
570
+ async getPermitProxySendTokensMethod (owner, relayerAddress, amount) {
571
+ const {
572
+ result,
573
+ deadline
574
+ } = await this._getPermitProxySendTokensParams(owner, relayerAddress, amount)
575
+ const contractMethod = this.ethContracts.AudiusTokenClient.AudiusTokenContract.methods.permit(
576
+ owner,
577
+ relayerAddress,
578
+ amount,
579
+ deadline,
580
+ result.v,
581
+ result.r,
582
+ result.s
583
+ )
584
+ return contractMethod
585
+ }
586
+
587
+ /**
588
+ * Sends `amount` tokens to `address` from `owner`
589
+ */
590
+ async sendTokens (owner, address, relayer, amount) {
591
+ this.REQUIRES(Services.IDENTITY_SERVICE)
592
+ return this.ethContracts.AudiusTokenClient.transferFrom(owner, address, relayer, amount)
593
+ }
594
+
595
+ /**
596
+ * Updates the minimum delegation amount for a user in identity
597
+ * NOTE: Requests eth account signature
598
+ */
599
+ async updateMinimumDelegationAmount (amount) {
600
+ this.REQUIRES(Services.IDENTITY_SERVICE)
601
+ const unixTs = Math.round(new Date().getTime() / 1000) // current unix timestamp (sec)
602
+ const message = `Click sign to authenticate with identity service: ${unixTs}`
603
+ const signature = await this.ethWeb3Manager.sign(message)
604
+ const wallet = this.ethWeb3Manager.getWalletAddress()
605
+ return this.identityService.updateMinimumDelegationAmount(wallet, amount, {
606
+ [AuthHeaders.MESSAGE]: message,
607
+ [AuthHeaders.SIGNATURE]: signature
608
+ })
609
+ }
610
+
611
+ /**
612
+ * Get current user account PDA from SOL given an ID and ETH wallet address
613
+ * @returns {object} with keys ethAddress, authority, replicaSet or
614
+ * null when account not found
615
+ */
616
+ async getUserAccountOnSolana (
617
+ { userId, wallet } = { userId: null, wallet: null }
618
+ ) {
619
+ this.REQUIRES(Services.SOLANA_WEB3_MANAGER)
620
+
621
+ // If wallet or userId are not passed in, use the user loaded in libs
622
+ if (!wallet || !userId) {
623
+ const user = this.getCurrentUser()
624
+ wallet = user.wallet
625
+ userId = user.userId
626
+ }
627
+
628
+ if (!(userId instanceof BN)) {
629
+ userId = new BN(userId)
630
+ }
631
+ // matches format for PDA derivation seed in SOL program
632
+ // use BN.toArrayLike instead of .toBuffer for browser compat reasons
633
+ const userIdSeed = userId.toArrayLike(Buffer, 'le', 4)
634
+
635
+ const { derivedAddress: userAccountPDA } =
636
+ await this.solanaWeb3Manager.findDerivedPair(
637
+ this.solanaWeb3Manager.audiusDataProgramId,
638
+ this.solanaWeb3Manager.audiusDataAdminStorageKeypairPublicKey,
639
+ userIdSeed
640
+ )
641
+
642
+ const account = await this.solanaWeb3Manager.fetchAccount(userAccountPDA)
643
+ return account
644
+ }
645
+
646
+ /**
647
+ * Checks that the current user has claimed account PDA on SOL
648
+ * @returns {boolean} userHasClaimedAccount
649
+ */
650
+ async userHasClaimedSolAccount (
651
+ { account = null, wallet = null, userId = null } = {
652
+ account: null,
653
+ wallet: null,
654
+ userId: null
655
+ }
656
+ ) {
657
+ if (!account && !wallet && !userId) {
658
+ throw new Error('Must supply EITHER an `account` OR `wallet` and `userId` to look up whether userHasClaimedSolAccount')
659
+ }
660
+ if (!account && wallet && userId) {
661
+ account = await this.getUserAccountOnSolana({ wallet, userId })
662
+ }
663
+ const userHasClaimedAccount =
664
+ PublicKey.default.toString() !== account.authority.toString()
665
+
666
+ return userHasClaimedAccount
667
+ }
668
+ }
669
+
670
+ module.exports = Account