@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,655 @@
1
+ const solanaWeb3 = require('@solana/web3.js')
2
+ const splToken = require('@solana/spl-token')
3
+ const anchor = require('@project-serum/anchor')
4
+ const { idl } = require('@audius/anchor-audius-data')
5
+
6
+ const { transferWAudioBalance } = require('./transfer')
7
+ const { getBankAccountAddress, createUserBankFrom } = require('./userBank')
8
+ const {
9
+ createAssociatedTokenAccount,
10
+ getAssociatedTokenAccountInfo,
11
+ findAssociatedTokenAddress
12
+ } = require('./tokenAccount')
13
+ const { wAudioFromWeiAudio } = require('./wAudio')
14
+ const { Utils } = require('../../utils')
15
+ const SolanaUtils = require('./utils')
16
+ const { TransactionHandler } = require('./transactionHandler')
17
+ const {
18
+ submitAttestations,
19
+ evaluateAttestations,
20
+ createSender,
21
+ deriveSolanaSenderFromEthAddress
22
+ } = require('./rewards')
23
+ const { AUDIO_DECMIALS, WAUDIO_DECMIALS } = require('../../constants')
24
+
25
+ const { PublicKey } = solanaWeb3
26
+
27
+ // Somewhat arbitrary close-to-zero number of Sol. For context, creating a UserBank costs ~0.002 SOL.
28
+ // Without this padding, we could reach some low non-zero number of SOL where transactions would fail
29
+ // despite a remaining balance.
30
+ const ZERO_SOL_EPSILON = 0.005
31
+ const SOL_PER_LAMPORT = 0.000000001
32
+
33
+ // Generous default connection confirmation timeout to better cope with RPC congestion
34
+ const DEFAULT_CONNECTION_CONFIRMATION_TIMEOUT_MS = 180 * 1000
35
+
36
+ /**
37
+ * @typedef {import("./rewards.js").AttestationMeta} AttestationMeta
38
+ */
39
+
40
+ /**
41
+ * SolanaWeb3Manager acts as the interface to solana contracts from a client.
42
+ * It wraps methods to create and lookup user banks, transfer balances, and
43
+ * interact with the @solana/web3 library.
44
+ *
45
+ * Note: Callers of this class should specify all $AUDIO amounts in units of wei.
46
+ * The internals of this class should handle the conversion from wei AUDIO to wormhole
47
+ * $AUDIO amounts.
48
+ */
49
+ class SolanaWeb3Manager {
50
+ /**
51
+ * @param {Object} solanaWeb3Config
52
+ * @param {string} solanaWeb3Config.solanaClusterEndpoint
53
+ * the solana cluster RPC endpoint
54
+ * @param {string} solanaWeb3Config.mintAddress
55
+ * address for the wAudio mint - Audius (Wormhole) token
56
+ * @param {string} solanaWeb3Config.solanaTokenAddress
57
+ * the SPL token program address
58
+ * @param {string} solanaWeb3Config.claimableTokenPDA
59
+ * the program derived address for the claimable token program (using the mint)
60
+ * @param {string} solanaWeb3Config.feePayerAddress
61
+ * the address for the specific fee payer to be used in relayed transactions
62
+ * @param {string} solanaWeb3Config.claimableTokenProgramAddress
63
+ * the address for the claimable token program used to create banks and transfer wAudio
64
+ * @param {string} solanaWeb3Config.rewardsManagerProgramId
65
+ * the ID of the rewards manager program
66
+ * @param {string} solanaWeb3Config.rewardsManagerProgramPDA
67
+ * the manager account of the rewards manager program
68
+ * @param {string} solanaWeb3Config.rewardsManagerTokenPDA
69
+ * the token holder account of the rewards manager program
70
+ * @param {boolean} solanaWeb3Config.useRelay
71
+ * whether to submit transactions via a relay, or locally
72
+ * @param {KeyPair} solanaWeb3Config.feePayerKepairs
73
+ * KeyPairs for feepayers
74
+ * @param {number} [solanaWeb3Config.confirmationTimeout] optional default confirmation timeout
75
+ * @param {PublicKey} [solanaWeb3Config.audiusDataProgramId]
76
+ * Program ID for audius-data anchor program
77
+ * @param {PublicKey} [solanaWeb3Config.audiusDataAdminStorageKeypairPublicKey]
78
+ * PK for audius-data admin storage keypair
79
+ * @param {anchor.Idl} [solanaWeb3Config.audiusDataIdl]
80
+ * IDL for audius-data program
81
+ * @param {IdentityService} identityService
82
+ * @param {Web3Manager} web3Manager
83
+ */
84
+ constructor (solanaWeb3Config, identityService, web3Manager) {
85
+ this.solanaWeb3Config = solanaWeb3Config
86
+ this.identityService = identityService
87
+ this.web3Manager = web3Manager
88
+
89
+ this.solanaWeb3 = solanaWeb3
90
+ this.splToken = splToken
91
+ }
92
+
93
+ async init () {
94
+ const {
95
+ solanaClusterEndpoint,
96
+ mintAddress,
97
+ solanaTokenAddress,
98
+ claimableTokenPDA,
99
+ feePayerAddress,
100
+ claimableTokenProgramAddress,
101
+ rewardsManagerProgramId,
102
+ rewardsManagerProgramPDA,
103
+ rewardsManagerTokenPDA,
104
+ useRelay,
105
+ feePayerKeypairs,
106
+ confirmationTimeout,
107
+ audiusDataProgramId,
108
+ audiusDataAdminStorageKeypairPublicKey,
109
+ audiusDataIdl
110
+ } = this.solanaWeb3Config
111
+
112
+ this.solanaClusterEndpoint = solanaClusterEndpoint
113
+ this.connection = new solanaWeb3.Connection(this.solanaClusterEndpoint, {
114
+ confirmTransactionInitialTimeout:
115
+ confirmationTimeout || DEFAULT_CONNECTION_CONFIRMATION_TIMEOUT_MS
116
+ })
117
+
118
+ this.transactionHandler = new TransactionHandler({
119
+ connection: this.connection,
120
+ useRelay,
121
+ identityService: this.identityService,
122
+ feePayerKeypairs
123
+ })
124
+
125
+ this.mintAddress = mintAddress
126
+ this.mintKey = SolanaUtils.newPublicKeyNullable(mintAddress)
127
+
128
+ this.solanaTokenAddress = solanaTokenAddress
129
+ this.solanaTokenKey = SolanaUtils.newPublicKeyNullable(solanaTokenAddress)
130
+
131
+ if (feePayerAddress) {
132
+ this.feePayerAddress = feePayerAddress
133
+ this.feePayerKey = SolanaUtils.newPublicKeyNullable(feePayerAddress)
134
+ } else if (feePayerKeypairs && feePayerKeypairs.length) {
135
+ this.feePayerAddress = feePayerKeypairs[0].publicKey
136
+ this.feePayerKey = SolanaUtils.newPublicKeyNullable(
137
+ feePayerKeypairs[0].publicKey
138
+ )
139
+ }
140
+
141
+ this.claimableTokenProgramKey = SolanaUtils.newPublicKeyNullable(
142
+ claimableTokenProgramAddress
143
+ )
144
+ this.claimableTokenPDA =
145
+ claimableTokenPDA ||
146
+ (this.claimableTokenProgramKey
147
+ ? (
148
+ await SolanaUtils.findProgramAddressFromPubkey(
149
+ this.claimableTokenProgramKey,
150
+ this.mintKey
151
+ )
152
+ )[0].toString()
153
+ : null)
154
+ this.claimableTokenPDAKey = SolanaUtils.newPublicKeyNullable(
155
+ this.claimableTokenPDA
156
+ )
157
+ this.rewardManagerProgramId = SolanaUtils.newPublicKeyNullable(
158
+ rewardsManagerProgramId
159
+ )
160
+ this.rewardManagerProgramPDA = SolanaUtils.newPublicKeyNullable(
161
+ rewardsManagerProgramPDA
162
+ )
163
+ this.rewardManagerTokenPDA = SolanaUtils.newPublicKeyNullable(
164
+ rewardsManagerTokenPDA
165
+ )
166
+ this.audiusDataProgramId = audiusDataProgramId
167
+ this.audiusDataAdminStorageKeypairPublicKey =
168
+ audiusDataAdminStorageKeypairPublicKey
169
+
170
+ this.audiusDataIdl = audiusDataIdl || idl
171
+
172
+ if (
173
+ this.audiusDataProgramId &&
174
+ this.audiusDataAdminStorageKeypairPublicKey &&
175
+ this.audiusDataIdl
176
+ ) {
177
+ const connection = new solanaWeb3.Connection(
178
+ this.solanaClusterEndpoint,
179
+ anchor.AnchorProvider.defaultOptions()
180
+ )
181
+ const anchorProvider = new anchor.AnchorProvider(
182
+ connection,
183
+ solanaWeb3.Keypair.generate(),
184
+ anchor.AnchorProvider.defaultOptions()
185
+ )
186
+ this.anchorProgram = new anchor.Program(
187
+ this.audiusDataIdl,
188
+ audiusDataProgramId,
189
+ anchorProvider
190
+ )
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Creates a solana bank account from the web3 provider's eth address
196
+ */
197
+ async createUserBank (feePayerOverride) {
198
+ if (!this.web3Manager) {
199
+ throw new Error(
200
+ 'A web3Manager is required for this solanaWeb3Manager method'
201
+ )
202
+ }
203
+
204
+ const ethAddress = this.web3Manager.getWalletAddress()
205
+ return createUserBankFrom({
206
+ ethAddress,
207
+ claimableTokenPDAKey: this.claimableTokenPDAKey,
208
+ feePayerKey:
209
+ SolanaUtils.newPublicKeyNullable(feePayerOverride) || this.feePayerKey,
210
+ mintKey: this.mintKey,
211
+ solanaTokenProgramKey: this.solanaTokenKey,
212
+ claimableTokenProgramKey: this.claimableTokenProgramKey,
213
+ connection: this.connection,
214
+ transactionHandler: this.transactionHandler
215
+ })
216
+ }
217
+
218
+ /**
219
+ * Creates a token account for the provided solana address (a wallet)
220
+ * See https://spl.solana.com/associated-token-account
221
+ * @param {string} solanaAddress
222
+ */
223
+ async createAssociatedTokenAccount (solanaAddress) {
224
+ await createAssociatedTokenAccount({
225
+ feePayerKey: this.feePayerKey,
226
+ solanaWalletKey: new PublicKey(solanaAddress),
227
+ mintKey: this.mintKey,
228
+ solanaTokenProgramKey: this.solanaTokenKey,
229
+ connection: this.connection,
230
+ identityService: this.identityService
231
+ })
232
+ }
233
+
234
+ /**
235
+ * Finds the wAudio token account for a provided solana address (a wallet)
236
+ * See https://spl.solana.com/associated-token-account
237
+ * @param {string} solanaAddress
238
+ */
239
+ async findAssociatedTokenAddress (solanaAddress) {
240
+ return findAssociatedTokenAddress({
241
+ solanaWalletKey: new PublicKey(solanaAddress),
242
+ mintKey: this.mintKey,
243
+ solanaTokenProgramKey: this.solanaTokenKey
244
+ })
245
+ }
246
+
247
+ /**
248
+ * Gets a solana bank account from the current we3 provider's eth address
249
+ * @returns {PublicKey} UserBank
250
+ */
251
+ async getUserBank () {
252
+ if (!this.web3Manager) {
253
+ throw new Error(
254
+ 'A web3Manager is required for this solanaWeb3Manager method'
255
+ )
256
+ }
257
+ const ethAddress = this.web3Manager.getWalletAddress()
258
+ const bank = await getBankAccountAddress(
259
+ ethAddress,
260
+ this.claimableTokenPDAKey,
261
+ this.solanaTokenKey
262
+ )
263
+ return bank
264
+ }
265
+
266
+ /**
267
+ * Gets the info for a user bank/wAudio token account given a solana address.
268
+ * If the solanaAddress is not a valid token account, returns `null`
269
+ * @returns {AccountInfo | null}
270
+ */
271
+ async getAssociatedTokenAccountInfo (solanaAddress) {
272
+ try {
273
+ const res = await getAssociatedTokenAccountInfo({
274
+ tokenAccountAddressKey: new PublicKey(solanaAddress),
275
+ mintKey: this.mintKey,
276
+ solanaTokenProgramKey: this.solanaTokenKey,
277
+ connection: this.connection
278
+ })
279
+ return res
280
+ } catch (e) {
281
+ return null
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Gets the SPL waudio balance for a solana address in wei with 18 decimals
287
+ * @returns {BN | null}
288
+ */
289
+ async getWAudioBalance (solanaAddress) {
290
+ try {
291
+ let tokenAccount = await this.getAssociatedTokenAccountInfo(solanaAddress)
292
+
293
+ // If the token account doesn't exist, check if solanaAddress is a root account
294
+ // if so, derive the associated token account & check that balance
295
+ if (!tokenAccount) {
296
+ const associatedTokenAccount = await this.findAssociatedTokenAddress(
297
+ solanaAddress
298
+ )
299
+ tokenAccount = await this.getAssociatedTokenAccountInfo(
300
+ associatedTokenAccount.toString()
301
+ )
302
+ if (!tokenAccount) {
303
+ return null
304
+ }
305
+ }
306
+
307
+ // Multiply by 10^10 to maintain same decimals as eth $AUDIO
308
+ const decimals = AUDIO_DECMIALS - WAUDIO_DECMIALS
309
+ return tokenAccount.amount.mul(Utils.toBN('1'.padEnd(decimals + 1, '0')))
310
+ } catch (e) {
311
+ return null
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Transfers audio from the web3 provider's eth address
317
+ * @param {string} recipientSolanaAddress
318
+ * Recipient solana address which is either a user bank, wAudio token account,
319
+ * or a solana account. In the last case, an associated token account is created
320
+ * if one does not already exist for the solana account
321
+ * @param {BN} amount the amount of $AUDIO to send in wei units of $AUDIO.
322
+ * **IMPORTANT NOTE**
323
+ * wAudio (Solana) does not support 10^-18 (wei) units of $AUDIO. The smallest
324
+ * demarcation on that side is 10^-8, so the $AUDIO amount must be >= 10^8 and have no
325
+ * remainder after a division with 10^8 or this method will throw.
326
+ *
327
+ * Generally speaking, callers into the solanaWeb3Manager should use BN.js representation
328
+ * of wei $AUDIO for all method calls
329
+ */
330
+ async transferWAudio (recipientSolanaAddress, amount) {
331
+ if (!this.web3Manager) {
332
+ throw new Error(
333
+ 'A web3Manager is required for this solanaWeb3Manager method'
334
+ )
335
+ }
336
+
337
+ // Check if the solana address is a token account
338
+ let tokenAccountInfo = await this.getAssociatedTokenAccountInfo(
339
+ recipientSolanaAddress
340
+ )
341
+ if (!tokenAccountInfo) {
342
+ console.info('Provided recipient solana address was not a token account')
343
+ // If not, check to see if it already has an associated token account.
344
+ const associatedTokenAccount = await this.findAssociatedTokenAddress(
345
+ recipientSolanaAddress
346
+ )
347
+ tokenAccountInfo = await this.getAssociatedTokenAccountInfo(
348
+ associatedTokenAccount.toString()
349
+ )
350
+
351
+ // If it's not a valid token account, we need to make one first
352
+ if (!tokenAccountInfo) {
353
+ console.info(
354
+ 'Provided recipient solana address has no associated token account, creating'
355
+ )
356
+ await this.createAssociatedTokenAccount(recipientSolanaAddress)
357
+ }
358
+ recipientSolanaAddress = associatedTokenAccount.toString()
359
+ }
360
+
361
+ console.info(
362
+ `Transfering ${amount.toString()} wei $AUDIO to ${recipientSolanaAddress}`
363
+ )
364
+
365
+ const wAudioAmount = wAudioFromWeiAudio(amount)
366
+
367
+ const ethAddress = this.web3Manager.getWalletAddress()
368
+ const senderSolanaAddress = await getBankAccountAddress(
369
+ ethAddress,
370
+ this.claimableTokenPDAKey,
371
+ this.solanaTokenKey
372
+ )
373
+ return transferWAudioBalance({
374
+ amount: wAudioAmount,
375
+ senderEthAddress: ethAddress,
376
+ feePayerKey: this.feePayerKey,
377
+ senderEthPrivateKey: this.web3Manager.getOwnerWalletPrivateKey(),
378
+ senderSolanaAddress,
379
+ recipientSolanaAddress,
380
+ claimableTokenPDA: this.claimableTokenPDAKey,
381
+ solanaTokenProgramKey: this.solanaTokenKey,
382
+ claimableTokenProgramKey: this.claimableTokenProgramKey,
383
+ connection: this.connection,
384
+ mintKey: this.mintKey,
385
+ transactionHandler: this.transactionHandler
386
+ })
387
+ }
388
+
389
+ /**
390
+ * Submits attestations for challenge completion to the RewardsManager program on Solana.
391
+ *
392
+ * @param {{
393
+ * attestations: AttestationMeta[],
394
+ * oracleAttestation: AttestationMeta,
395
+ * challengeId: string,
396
+ * specifier: string,
397
+ * recipientEthAddress: string,
398
+ * tokenAmount: BN,
399
+ * instructionsPerTransaction?: number,
400
+ * logger: any
401
+ * feePayerOverride: string | null
402
+ * }} {
403
+ * attestations,
404
+ * oracleAttestation,
405
+ * challengeId,
406
+ * specifier,
407
+ * recipientEthAddress,
408
+ * tokenAmount,
409
+ * instructionsPerTransaction,
410
+ * logger
411
+ * feePayerOverride
412
+ * }
413
+ * @memberof SolanaWeb3Manager
414
+ */
415
+ async submitChallengeAttestations ({
416
+ attestations,
417
+ oracleAttestation,
418
+ challengeId,
419
+ specifier,
420
+ recipientEthAddress,
421
+ tokenAmount,
422
+ instructionsPerTransaction,
423
+ logger = console,
424
+ feePayerOverride = null
425
+ }) {
426
+ return submitAttestations({
427
+ rewardManagerProgramId: this.rewardManagerProgramId,
428
+ rewardManagerAccount: this.rewardManagerProgramPDA,
429
+ attestations,
430
+ oracleAttestation,
431
+ challengeId,
432
+ specifier,
433
+ feePayer:
434
+ SolanaUtils.newPublicKeyNullable(feePayerOverride) || this.feePayerKey,
435
+ recipientEthAddress,
436
+ tokenAmount,
437
+ transactionHandler: this.transactionHandler,
438
+ instructionsPerTransaction,
439
+ logger
440
+ })
441
+ }
442
+
443
+ /**
444
+ * Evaluates existing submitted attestations, disbursing if successful.
445
+ *
446
+ * @param {{
447
+ * challengeId: string,
448
+ * specifier: string,
449
+ * recipientEthAddress: string
450
+ * oracleEthAddress: string
451
+ * logger: any
452
+ * feePayerOverride: string | null
453
+ * }} {
454
+ * challengeId,
455
+ * specifier,
456
+ * recipientEthAddress,
457
+ * oracleEthAddress,
458
+ * tokenAmount,
459
+ * logger
460
+ * feePayerOverride
461
+ * }
462
+ * @memberof SolanaWeb3Manager
463
+ */
464
+ async evaluateChallengeAttestations ({
465
+ challengeId,
466
+ specifier,
467
+ recipientEthAddress,
468
+ oracleEthAddress,
469
+ tokenAmount,
470
+ logger = console,
471
+ feePayerOverride = null
472
+ }) {
473
+ return evaluateAttestations({
474
+ rewardManagerProgramId: this.rewardManagerProgramId,
475
+ rewardManagerAccount: this.rewardManagerProgramPDA,
476
+ rewardManagerTokenSource: this.rewardManagerTokenPDA,
477
+ challengeId,
478
+ specifier,
479
+ recipientEthAddress,
480
+ userBankProgramAccount: this.claimableTokenPDAKey,
481
+ oracleEthAddress,
482
+ feePayer:
483
+ SolanaUtils.newPublicKeyNullable(feePayerOverride) || this.feePayerKey,
484
+ tokenAmount,
485
+ transactionHandler: this.transactionHandler,
486
+ logger
487
+ })
488
+ }
489
+
490
+ /**
491
+ * Creates a new rewards signer (one that can attest)
492
+ * @param {{
493
+ * senderEthAddress: string,
494
+ * operatorEthAddress: string,
495
+ * attestations: AttestationMeta[],
496
+ * feePayerOverride?: string
497
+ * }} {
498
+ * @memberof SolanaWeb3Manager
499
+ */
500
+ async createSender ({
501
+ senderEthAddress,
502
+ operatorEthAddress,
503
+ attestations,
504
+ feePayerOverride = null
505
+ }) {
506
+ return createSender({
507
+ rewardManagerProgramId: this.rewardManagerProgramId,
508
+ rewardManagerAccount: this.rewardManagerProgramPDA,
509
+ senderEthAddress,
510
+ feePayer:
511
+ SolanaUtils.newPublicKeyNullable(feePayerOverride) || this.feePayerKey,
512
+ operatorEthAddress,
513
+ attestations,
514
+ identityService: this.identityService,
515
+ connection: this.connection,
516
+ transactionHandler: this.transactionHandler
517
+ })
518
+ }
519
+
520
+ /**
521
+ * Gets the balance of a PublicKey, in SOL
522
+ *
523
+ * @param {{
524
+ * publicKey: PublicKey
525
+ * }} { publicKey }
526
+ * @return {Promise<number>}
527
+ * @memberof SolanaWeb3Manager
528
+ */
529
+ async getBalance ({ publicKey }) {
530
+ const lamports = await this.connection.getBalance(publicKey)
531
+ return lamports * SOL_PER_LAMPORT
532
+ }
533
+
534
+ /**
535
+ * Gets whether a PublicKey has a usable balance
536
+ *
537
+ * @param {{
538
+ * publicKey: PublicKey,
539
+ * epsilon?: number
540
+ * }} { publicKey }
541
+ * @return {Promise<boolean>}
542
+ * @memberof SolanaWeb3Manager
543
+ */
544
+ async hasBalance ({ publicKey, epsilon = ZERO_SOL_EPSILON }) {
545
+ const balance = await this.getBalance({ publicKey })
546
+ return balance > epsilon
547
+ }
548
+
549
+ async getSlot () {
550
+ return this.connection.getSlot('processed')
551
+ }
552
+
553
+ async getRandomFeePayer () {
554
+ return this.identityService.getRandomFeePayer()
555
+ }
556
+
557
+ /**
558
+ * Gets whether a given node registered on eth with `senderEthAddress` is registered on Solana
559
+ *
560
+ * @param {string} senderEthAddress
561
+ * @return {Promise<boolean>}
562
+ * @memberof SolanaWeb3Manager
563
+ */
564
+ async getIsDiscoveryNodeRegistered (senderEthAddress) {
565
+ const derivedSenderSolanaAddress = await deriveSolanaSenderFromEthAddress(
566
+ senderEthAddress,
567
+ this.rewardManagerProgramId,
568
+ this.rewardManagerProgramPDA
569
+ )
570
+
571
+ const res = await this.connection.getAccountInfo(derivedSenderSolanaAddress)
572
+ return !!res
573
+ }
574
+
575
+ async findProgramAddress (programId, pubkey) {
576
+ return PublicKey.findProgramAddress(
577
+ [pubkey.toBytes().slice(0, 32)],
578
+ programId
579
+ )
580
+ }
581
+
582
+ /**
583
+ * Finds a 'derived' address by finding a programAddress with
584
+ * seeds array as first 32 bytes of base + seeds
585
+ * Returns [derivedAddress, bumpSeed]
586
+ * @param {string} programId
587
+ * @param {string} base
588
+ * @param {Buffer | Uint8Array} seed
589
+ * @returns the program address
590
+ */
591
+ async findDerivedAddress (programId, base, seed) {
592
+ return PublicKey.findProgramAddress(
593
+ [base.toBytes().slice(0, 32), seed],
594
+ programId
595
+ )
596
+ }
597
+
598
+ /**
599
+ * Finds the target PDA with the base audius admin as the initial seed
600
+ * In conjunction with the secondary seed as the users id in bytes
601
+ * @param {PublicKey} programId
602
+ * @param {PublicKey} adminAccount
603
+ * @param {Buffer | Uint8Array} seed
604
+ */
605
+ async findDerivedPair (programId, adminAccount, seed) {
606
+ programId = SolanaUtils.newPublicKeyNullable(programId)
607
+ adminAccount = SolanaUtils.newPublicKeyNullable(adminAccount)
608
+
609
+ const [baseAuthorityAccount] = await this.findProgramAddress(
610
+ programId,
611
+ adminAccount
612
+ )
613
+ const derivedAddressInfo = await this.findDerivedAddress(
614
+ programId,
615
+ baseAuthorityAccount,
616
+ seed
617
+ )
618
+
619
+ const derivedAddress = derivedAddressInfo[0]
620
+ const bumpSeed = derivedAddressInfo[1]
621
+
622
+ return { baseAuthorityAccount, derivedAddress, bumpSeed }
623
+ }
624
+
625
+ /**
626
+ * Fetch account on Solana given the program derived address
627
+ * @param {PublicKey} pda the program derived address from findDerivedPair()
628
+ */
629
+ async fetchAccount (pda) {
630
+ let account
631
+ try {
632
+ account = await this.anchorProgram.account.user.fetch(pda)
633
+ return account
634
+ } catch (e) {
635
+ return null
636
+ }
637
+ }
638
+
639
+ /**
640
+ * Given the eth address buffer from the account, convert to hex
641
+ * @param {Buffer} accountEthAddress
642
+ * @returns hex string of input bytes
643
+ */
644
+ async deriveEthWalletFromAddress (accountEthAddress) {
645
+ let encodedEthAddress = Buffer.from(accountEthAddress).toString('hex')
646
+
647
+ if (!encodedEthAddress.startsWith('0x')) {
648
+ encodedEthAddress = '0x' + encodedEthAddress
649
+ }
650
+
651
+ return encodedEthAddress
652
+ }
653
+ }
654
+
655
+ module.exports = SolanaWeb3Manager
@@ -0,0 +1,7 @@
1
+ import type BN from 'bn.js'
2
+ /**
3
+ * Converts a BN to a Uint8Array of length 8, in little endian notation.
4
+ * Useful for when Rust wants a u64 (8 * 8) represented as a byte array.
5
+ * Ex: https://github.com/AudiusProject/audius-protocol/blob/master/solana-programs/reward-manager/program/src/processor.rs#L389
6
+ */
7
+ export const padBNToUint8Array = (bn: BN): number[] => bn.toArray('le', 8)