@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,424 @@
1
+ const bs58 = require('bs58')
2
+ const { toBuffer } = require('ethereumjs-util')
3
+ const { zeroPad } = require('ethers/lib/utils')
4
+ const { providers } = require('ethers/lib/index')
5
+ const wormholeSDK = require('@certusone/wormhole-sdk')
6
+
7
+ const SolanaUtils = require('../solanaWeb3Manager/utils')
8
+ const { Utils } = require('../../utils')
9
+ const { wAudioFromWeiAudio } = require('../solanaWeb3Manager/wAudio')
10
+ const { sign, getTransferTokensDigest } = require('../../utils/signatures')
11
+ /** Singleton state-manager for Audius Eth Contracts */
12
+
13
+ class Wormhole {
14
+ /**
15
+ * Wormhole constructor
16
+ * @param {object} hedgehog
17
+ * @param {object} ethWeb3Manager
18
+ * @param {object} ethContracts
19
+ * @param {object} identityService
20
+ * @param {object} solanaWeb3Manager
21
+ * @param {Array<string>} rpcHosts
22
+ * @param {string} solBridgeAddress
23
+ * @param {string} solTokenBridgeAddress
24
+ * @param {string} ethBridgeAddress
25
+ * @param {string} ethTokenBridgeAddress
26
+ * @param {boolean} isServer
27
+ */
28
+ constructor (
29
+ hedgehog,
30
+ ethWeb3Manager,
31
+ ethContracts,
32
+ identityService,
33
+ solanaWeb3Manager,
34
+ rpcHosts,
35
+ solBridgeAddress,
36
+ solTokenBridgeAddress,
37
+ ethBridgeAddress,
38
+ ethTokenBridgeAddress,
39
+ isServer
40
+ ) {
41
+ // Wormhole service dependecies
42
+ this.hedgehog = hedgehog
43
+ this.ethWeb3Manager = ethWeb3Manager
44
+ this.ethContracts = ethContracts
45
+ this.identityService = identityService
46
+ this.solanaWeb3Manager = solanaWeb3Manager
47
+
48
+ // Wormhole config
49
+ this.rpcHosts = rpcHosts
50
+ this.solBridgeAddress = solBridgeAddress
51
+ this.solTokenBridgeAddress = solTokenBridgeAddress
52
+ this.ethBridgeAddress = ethBridgeAddress
53
+ this.ethTokenBridgeAddress = ethTokenBridgeAddress
54
+ this.wormholeSDK = wormholeSDK
55
+ }
56
+
57
+ async getSignedVAAWithRetry (
58
+ hosts,
59
+ emitterChain,
60
+ emitterAddress,
61
+ sequence,
62
+ extraGrpcOpts = {},
63
+ retryTimeout = 5000,
64
+ retryAttempts = 60
65
+ ) {
66
+ let currentWormholeRpcHost = -1
67
+ const getNextRpcHost = () => ++currentWormholeRpcHost % hosts.length
68
+ let result
69
+ let attempts = 0
70
+ while (!result) {
71
+ attempts++
72
+ await new Promise((resolve) => setTimeout(resolve, retryTimeout))
73
+ try {
74
+ result = await this.wormholeSDK.getSignedVAA(
75
+ hosts[getNextRpcHost()],
76
+ emitterChain,
77
+ emitterAddress,
78
+ sequence,
79
+ extraGrpcOpts
80
+ )
81
+ } catch (e) {
82
+ if (retryAttempts !== undefined && attempts > retryAttempts) {
83
+ throw e
84
+ }
85
+ }
86
+ }
87
+ return result
88
+ }
89
+
90
+ /**
91
+ * Sends `amount` tokens to `solanaAccount` by way of the wormhole
92
+ * @param {string} ethTxReceipt The tx receipt
93
+ * @param {function} [customSignTransaction] Optional custom sign transaction parameter
94
+ * @param {Object?} options The grpc options passed to get signed VAA for different transport
95
+ *
96
+ * else will attempt to relay
97
+ * @returns {Promise} Promise object of {
98
+ transactionSignature: string,
99
+ error: Error,
100
+ phase: string,
101
+ logs: Array<string>
102
+ }
103
+ */
104
+ async attestAndCompleteTransferEthToSol (ethTxReceipt, customSignTransaction, options = {}) {
105
+ const phases = {
106
+ GET_RECEIPT: 'GET_RECEIPT',
107
+ GET_SIGNED_VAA: 'GET_SIGNED_VAA',
108
+ POST_VAA_SOLANA: 'POST_VAA_SOLANA',
109
+ REDEEM_ON_SOLANA: 'REDEEM_ON_SOLANA'
110
+ }
111
+ let phase = phases.GET_RECEIPT
112
+ const logs = [`Attest and complete transfer for eth to sol for reciept ${ethTxReceipt}`]
113
+ try {
114
+ const receipt = await this.ethWeb3Manager.web3.eth.getTransactionReceipt(ethTxReceipt)
115
+ const sequence = this.wormholeSDK.parseSequenceFromLogEth(receipt, this.ethBridgeAddress)
116
+ const emitterAddress = this.wormholeSDK.getEmitterAddressEth(this.ethTokenBridgeAddress)
117
+ phase = phases.GET_SIGNED_VAA
118
+ const { vaaBytes } = await this.getSignedVAAWithRetry(
119
+ this.rpcHosts,
120
+ this.wormholeSDK.CHAIN_ID_ETH,
121
+ emitterAddress,
122
+ sequence,
123
+ options
124
+ )
125
+
126
+ const connection = this.solanaWeb3Manager.connection
127
+ let signTransaction
128
+ if (customSignTransaction) {
129
+ signTransaction = customSignTransaction
130
+ } else {
131
+ signTransaction = async (transaction) => {
132
+ const { blockhash } = await connection.getLatestBlockhash()
133
+ // Must call serialize message to set the correct signatures on the transaction
134
+ transaction.serializeMessage()
135
+ const transactionData = {
136
+ recentBlockhash: blockhash,
137
+ instructions: transaction.instructions.map(SolanaUtils.prepareInstructionForRelay),
138
+ signatures: transaction.signatures.map(sig => ({
139
+ publicKey: sig.publicKey.toString(),
140
+ signature: sig.signature
141
+ }))
142
+ }
143
+
144
+ const { transactionSignature } = await this.identityService.solanaRelayRaw(transactionData)
145
+ logs.push(`Relay sol tx for postVAA with signature ${transactionSignature}`)
146
+ return {
147
+ serialize: () => {}
148
+ }
149
+ }
150
+ connection.sendRawTransaction = async () => ''
151
+ connection.confirmTransaction = async () => ''
152
+ }
153
+ phase = phases.POST_VAA_SOLANA
154
+ await this.wormholeSDK.postVaaSolana(
155
+ connection,
156
+ signTransaction,
157
+ this.solBridgeAddress,
158
+ this.solanaWeb3Manager.feePayerAddress.toString(), // payerAddress
159
+ vaaBytes
160
+ )
161
+
162
+ // Finally, redeem on Solana
163
+ phase = phases.REDEEM_ON_SOLANA
164
+ const transaction = await this.wormholeSDK.redeemOnSolana(
165
+ connection,
166
+ this.solBridgeAddress,
167
+ this.solTokenBridgeAddress,
168
+ this.solanaWeb3Manager.feePayerAddress.toString(), // payerAddress,
169
+ vaaBytes
170
+ )
171
+
172
+ let finalTxSignature
173
+ // Must call serialize message to set the correct signatures on the transaction
174
+ if (customSignTransaction) {
175
+ const signedTransaction = await signTransaction(transaction)
176
+ const txid = await connection.sendRawTransaction(signedTransaction.serialize())
177
+ finalTxSignature = txid
178
+
179
+ await connection.confirmTransaction(txid)
180
+ } else {
181
+ transaction.serializeMessage()
182
+
183
+ const { blockhash } = await connection.getLatestBlockhash()
184
+ const transactionData = {
185
+ recentBlockhash: blockhash,
186
+ instructions: transaction.instructions.map(SolanaUtils.prepareInstructionForRelay),
187
+ signatures: transaction.signatures.map(sig => ({
188
+ publicKey: sig.publicKey.toString(),
189
+ signature: sig.signature
190
+ }))
191
+ }
192
+
193
+ const { transactionSignature } = await this.identityService.solanaRelayRaw(transactionData)
194
+ finalTxSignature = transactionSignature
195
+ }
196
+ logs.push(`Complete redeem on sol with signature ${finalTxSignature}`)
197
+ return {
198
+ transactionSignature: finalTxSignature,
199
+ error: null,
200
+ phase,
201
+ logs
202
+ }
203
+ } catch (error) {
204
+ return {
205
+ error: error.message,
206
+ phase,
207
+ logs
208
+ }
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Sends `amount` tokens to `solanaAccount` by way of the wormhole
214
+ * @param {BN} amount The amount of AUDIO to send in Wrapped Audio (8 decimals)
215
+ * @param {string} ethTargetAddress The eth address to transfer AUDIO
216
+ * @param {Object?} options The grpc options passed to get signed VAA for different transport
217
+ */
218
+ async sendTokensFromSolToEthViaWormhole (amount, ethTargetAddress, options = {}) {
219
+ const phases = {
220
+ GENERATE_SOL_ROOT_ACCT: 'GENERATE_SOL_ROOT_ACCT',
221
+ TRANSFER_WAUDIO_TO_ROOT: 'TRANSFER_WAUDIO_TO_ROOT',
222
+ TRANFER_FROM_SOL: 'TRANFER_FROM_SOL',
223
+ GET_SIGNED_VAA: 'GET_SIGNED_VAA',
224
+ GET_EMITTER_ADDR: 'GET_EMITTER_ADDR',
225
+ REDEEM_ON_ETH: 'REDEEM_ON_ETH'
226
+ }
227
+ let phase = phases.GENERATE_SOL_ROOT_ACCT
228
+ const logs = [`Transferring ${amount} WAUDIO to ${ethTargetAddress}`]
229
+ try {
230
+ const wAudioAmount = wAudioFromWeiAudio(amount)
231
+ // Generate a solana keypair derived from the hedgehog private key
232
+ // NOTE: The into to fromSeed is a 32 bytes Uint8Array
233
+ const rootSolanaAccount = this.solanaWeb3Manager.solanaWeb3.Keypair.fromSeed(
234
+ this.hedgehog.wallet.getPrivateKey()
235
+ )
236
+
237
+ const solanaAddress = rootSolanaAccount.publicKey.toString()
238
+ logs.push(`Root Solana Account: ${solanaAddress}`)
239
+
240
+ // Find the token account owned by the root solana account and get the token account's info
241
+ const associatedTokenAccount = await this.solanaWeb3Manager.findAssociatedTokenAddress(solanaAddress)
242
+ const tokenAccountInfo = await this.solanaWeb3Manager.getAssociatedTokenAccountInfo(associatedTokenAccount.toString())
243
+
244
+ // If it's not a valid token account, create the token account
245
+ if (!tokenAccountInfo) {
246
+ logs.push(`Creating Associated Token Account: ${associatedTokenAccount.toString()}`)
247
+ await this.solanaWeb3Manager.createAssociatedTokenAccount(solanaAddress)
248
+ } else {
249
+ logs.push(`Associated Token Account Exits: ${associatedTokenAccount.toString()}`)
250
+ }
251
+
252
+ phase = phases.TRANSFER_WAUDIO_TO_ROOT
253
+ // Move wrapped audio from then user bank account to the user's token wallet
254
+ await this.solanaWeb3Manager.transferWAudio(tokenAccountInfo.address.toString(), amount)
255
+ logs.push(`Transferred waudio ${wAudioAmount.toString()} balance to associated token account`)
256
+ phase = phases.TRANFER_FROM_SOL
257
+
258
+ const connection = this.solanaWeb3Manager.connection
259
+
260
+ // Submit transaction - results in a Wormhole message being published
261
+ const tx = await this.wormholeSDK.transferFromSolana(
262
+ connection, // solana web3 Connection
263
+ this.solBridgeAddress, // bridge address
264
+ this.solTokenBridgeAddress, // token bridge address
265
+ this.solanaWeb3Manager.feePayerAddress, // payerAddress
266
+ tokenAccountInfo.address.toString(), // fromAddress
267
+ this.solanaWeb3Manager.mintAddress, // mintAddress
268
+ wAudioAmount, // BigInt
269
+ zeroPad(toBuffer(ethTargetAddress), 32), // Uint8Array of length 32 targetAddress
270
+ this.wormholeSDK.CHAIN_ID_ETH, // ChainId targetChain
271
+ zeroPad(toBuffer(this.ethContracts.AudiusTokenClient.contractAddress), 32), // Uint8Array of length 32 originAddress
272
+ this.wormholeSDK.CHAIN_ID_ETH, // ChainId originChain
273
+ solanaAddress // from owner address
274
+ )
275
+
276
+ // Must call serialize message to set the correct signatures on the transaction
277
+ tx.serializeMessage()
278
+ tx.partialSign(rootSolanaAccount)
279
+
280
+ const { blockhash } = await connection.getLatestBlockhash()
281
+ const transactionData = {
282
+ recentBlockhash: blockhash,
283
+ instructions: tx.instructions.map(SolanaUtils.prepareInstructionForRelay),
284
+ signatures: tx.signatures.map(sig => ({
285
+ publicKey: sig.publicKey.toString(),
286
+ signature: sig.signature
287
+ }))
288
+ }
289
+ const { transactionSignature } = await this.identityService.solanaRelayRaw(transactionData)
290
+ logs.push(`Transferred to wormhole with signature: ${transactionSignature}`)
291
+ phase = phases.GET_EMITTER_ADDR
292
+
293
+ // Get the sequence number and emitter address required to fetch the signedVAA of our message
294
+ const info = await connection.getTransaction(transactionSignature)
295
+ const sequence = this.wormholeSDK.parseSequenceFromLogSolana(info)
296
+ const emitterAddress = await this.wormholeSDK.getEmitterAddressSolana(this.solTokenBridgeAddress)
297
+ // Fetch the signedVAA from the Wormhole Network (this may require retries while you wait for confirmation)
298
+ phase = phases.GET_SIGNED_VAA
299
+ const { vaaBytes } = await this.getSignedVAAWithRetry(
300
+ this.rpcHosts,
301
+ this.wormholeSDK.CHAIN_ID_SOLANA,
302
+ emitterAddress,
303
+ sequence,
304
+ options
305
+ )
306
+
307
+ // Redeem on Ethereum
308
+ // NOTE: The signer should be the user's personal wallet
309
+ phase = phases.REDEEM_ON_ETH
310
+ const signer = (new providers.Web3Provider(window.ethereum)).getSigner()
311
+ await this.wormholeSDK.redeemOnEth(this.ethTokenBridgeAddress, signer, vaaBytes)
312
+ logs.push('Redeemed on eth')
313
+ return { phase, logs, error: null }
314
+ } catch (error) {
315
+ return {
316
+ error: error.message,
317
+ phase,
318
+ logs
319
+ }
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Locks assets owned by `fromAccount` into the Solana wormhole with a target
325
+ * solanaAccount destination via the provided relayer wallet.
326
+ * @param {string} fromAccount the account holding the ETH AUDIO to transfer
327
+ * @param {BN} amount The amount of AUDIO to send in WEI (18 decimals)
328
+ * @param {string} solanaAccount The solana token account
329
+ */
330
+ async _getTransferTokensToEthWormholeParams (fromAccount, amount, solanaAccount) {
331
+ const web3 = this.ethWeb3Manager.getWeb3()
332
+ const wormholeClientAddress = this.ethContracts.WormholeClient.contractAddress
333
+
334
+ const chainId = await web3.eth.getChainId()
335
+
336
+ const currentBlockNumber = await web3.eth.getBlockNumber()
337
+ const currentBlock = await web3.eth.getBlock(currentBlockNumber)
338
+
339
+ // 1 hour, sufficiently far in future
340
+ const deadline = currentBlock.timestamp + (60 * 60 * 1)
341
+ const solanaB58 = bs58.decode(solanaAccount).toString('hex')
342
+ const recipient = toBuffer(`0x${solanaB58}`)
343
+ const nonce = await this.ethContracts.WormholeClient.nonces(fromAccount)
344
+ const arbiterFee = Utils.toBN('0')
345
+
346
+ const digest = getTransferTokensDigest(
347
+ web3,
348
+ 'AudiusWormholeClient',
349
+ wormholeClientAddress,
350
+ chainId,
351
+ {
352
+ from: fromAccount,
353
+ amount,
354
+ recipientChain: chainId,
355
+ recipient,
356
+ arbiterFee
357
+ },
358
+ nonce,
359
+ deadline
360
+ )
361
+ const myPrivateKey = this.hedgehog.wallet._privKey
362
+ const signedDigest = sign(digest, myPrivateKey)
363
+ return {
364
+ chainId,
365
+ deadline,
366
+ recipient,
367
+ arbiterFee,
368
+ signedDigest
369
+ }
370
+ }
371
+
372
+ /**
373
+ * Locks assets owned by `fromAccount` into the Solana wormhole with a target
374
+ * solanaAccount destination via the provided relayer wallet.
375
+ * @param {string} fromAccount the account holding the ETH AUDIO to transfer
376
+ * @param {BN} amount The amount of AUDIO to send in WEI (18 decimals)
377
+ * @param {string} solanaAccount The solana token account
378
+ * @param {string} relayer The eth relayer to permission to aprrove and transfer
379
+ */
380
+ async transferTokensToEthWormhole (fromAccount, amount, solanaAccount, relayer) {
381
+ const {
382
+ chainId,
383
+ deadline,
384
+ recipient,
385
+ arbiterFee,
386
+ signedDigest
387
+ } = await this._getTransferTokensToEthWormholeParams(fromAccount, amount, solanaAccount)
388
+ const tx = await this.ethContracts.WormholeClient.transferTokens(
389
+ fromAccount,
390
+ amount,
391
+ chainId,
392
+ recipient,
393
+ arbiterFee,
394
+ deadline,
395
+ signedDigest,
396
+ relayer
397
+ )
398
+ return tx
399
+ }
400
+
401
+ async getTransferTokensToEthWormholeMethod (fromAccount, amount, solanaAccount, relayer) {
402
+ const {
403
+ chainId,
404
+ deadline,
405
+ recipient,
406
+ arbiterFee,
407
+ signedDigest
408
+ } = await this._getTransferTokensToEthWormholeParams(fromAccount, amount, solanaAccount)
409
+ const method = await this.ethContracts.WormholeClient.WormholeContract.methods.transferTokens(
410
+ fromAccount,
411
+ amount,
412
+ chainId,
413
+ recipient,
414
+ arbiterFee,
415
+ deadline,
416
+ signedDigest.v,
417
+ signedDigest.r,
418
+ signedDigest.s
419
+ )
420
+ return method
421
+ }
422
+ }
423
+
424
+ module.exports = Wormhole
package/src/types.ts ADDED
@@ -0,0 +1,8 @@
1
+ import AudiusLibs from './libs'
2
+
3
+ export { sdk } from './sdk'
4
+
5
+ export const libs: any = AudiusLibs
6
+ export { Utils } from './utils'
7
+ export { CreatorNode } from './services/creatorNode'
8
+ export * from './sanityChecks'
@@ -0,0 +1,53 @@
1
+ import { CURRENT_USER_EXISTS_LOCAL_STORAGE_KEY } from './constants'
2
+
3
+ const supportsLocalStorage = () =>
4
+ typeof window !== 'undefined' && window && window.localStorage
5
+
6
+ export type CurrentUser = {
7
+ user_id: string
8
+ wallet: string
9
+ blocknumber: number
10
+ track_blocknumber: number
11
+ creator_node_endpoint: string
12
+ is_creator: boolean
13
+ }
14
+
15
+ /**
16
+ * Singleton class to store the current user if initialized.
17
+ * Some instances of AudiusLibs and services require a current user to
18
+ * return valid queries, e.g. requesting the a discprov to return a reposted track.
19
+ */
20
+ export class UserStateManager {
21
+ currentUser: CurrentUser | null
22
+
23
+ constructor() {
24
+ // Should reflect the same fields as discovery node's /users?handle=<handle>
25
+ this.currentUser = null
26
+ }
27
+
28
+ /**
29
+ * Sets this.currentUser with currentUser
30
+ * @param {Object} currentUser fields to override this.currentUser with
31
+ */
32
+ setCurrentUser(currentUser: CurrentUser) {
33
+ this.currentUser = currentUser
34
+ if (supportsLocalStorage()) {
35
+ window.localStorage.setItem(CURRENT_USER_EXISTS_LOCAL_STORAGE_KEY, 'true')
36
+ }
37
+ }
38
+
39
+ getCurrentUser() {
40
+ return this.currentUser
41
+ }
42
+
43
+ getCurrentUserId() {
44
+ return this.currentUser ? this.currentUser.user_id : null
45
+ }
46
+
47
+ clearUser() {
48
+ this.currentUser = null
49
+ if (supportsLocalStorage()) {
50
+ window.localStorage.removeItem(CURRENT_USER_EXISTS_LOCAL_STORAGE_KEY)
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,51 @@
1
+ import assert from 'assert'
2
+ import type Web3 from 'web3'
3
+
4
+ interface WalletResponse {
5
+ signature: string
6
+ signer: string
7
+ }
8
+
9
+ /**
10
+ * Recover the public wallet address given the response contains the signature and timestamp
11
+ * @param {object} response entire service provider response (not axios)
12
+ */
13
+ export function recoverWallet(web3: Web3, response: WalletResponse) {
14
+ let recoveredDelegateWallet = null
15
+
16
+ const dataForRecovery = JSON.parse(JSON.stringify(response))
17
+ delete dataForRecovery.signature
18
+ const dataForRecoveryStr = JSON.stringify(sortObjectKeys(dataForRecovery))
19
+
20
+ try {
21
+ const hashedData = web3.utils.keccak256(dataForRecoveryStr)
22
+ recoveredDelegateWallet = web3.eth.accounts.recover(
23
+ hashedData,
24
+ response.signature
25
+ )
26
+
27
+ assert.strictEqual(response.signer, recoveredDelegateWallet)
28
+ } catch (e) {
29
+ console.error(`Issue with recovering public wallet address: ${e}`)
30
+ }
31
+
32
+ return recoveredDelegateWallet
33
+ }
34
+
35
+ type ValueOrArray<T> = undefined | string | T | Array<ValueOrArray<T>>
36
+ type SortObject = ValueOrArray<Record<string, string>>
37
+
38
+ /**
39
+ * Recursively sorts object keys alphabetically
40
+ */
41
+ export function sortObjectKeys(x: SortObject): SortObject {
42
+ if (typeof x !== 'object' || !x) {
43
+ return x
44
+ }
45
+ if (Array.isArray(x)) {
46
+ return x.map(sortObjectKeys)
47
+ }
48
+ return Object.keys(x)
49
+ .sort()
50
+ .reduce((o, k) => ({ ...o, [k]: sortObjectKeys(x[k]) }), {})
51
+ }
@@ -0,0 +1,97 @@
1
+ import FormData from 'form-data'
2
+ import axios from 'axios'
3
+
4
+ declare global {
5
+ interface Window {
6
+ grecaptcha: {
7
+ ready: (callback: () => void) => Promise<void>
8
+ execute: (siteKey: string, config: { action: string }) => Promise<string>
9
+ }
10
+ }
11
+ }
12
+
13
+ const VERIFY_ENDPOINT = 'https://www.google.com/recaptcha/api/siteverify'
14
+ const IS_BROWSER = typeof window !== 'undefined' && window !== null
15
+
16
+ interface CaptchaConfig {
17
+ siteKey: string
18
+ serviceKey: string
19
+ }
20
+
21
+ export class Captcha {
22
+ siteKey: string
23
+ serviceKey: string
24
+ constructor({ siteKey, serviceKey }: CaptchaConfig) {
25
+ this.siteKey = siteKey
26
+ this.serviceKey = serviceKey
27
+
28
+ this.generate = this.generate.bind(this)
29
+ this.verify = this.verify.bind(this)
30
+ }
31
+
32
+ /**
33
+ * Intended to be called by clients. Will generate a token used to calculate recaptcha score.
34
+ * @param action name for this "action" for grouping
35
+ */
36
+ async generate(action: string) {
37
+ if (!this.siteKey) {
38
+ throw new Error('No siteKey provided')
39
+ }
40
+
41
+ if (!IS_BROWSER) {
42
+ throw new Error('Expected a browser/client context')
43
+ }
44
+
45
+ if (!window.grecaptcha) {
46
+ throw new Error('No captcha found, did you forget to import it?')
47
+ }
48
+
49
+ return await new Promise<string>((resolve) => {
50
+ window.grecaptcha.ready(() => {
51
+ window.grecaptcha.execute(this.siteKey, { action }).then((token) => {
52
+ resolve(token)
53
+ })
54
+ })
55
+ })
56
+ }
57
+
58
+ /**
59
+ * Intended to be called by services. According to recaptcha v3 docs:
60
+ * A score of 1.0 is very likely a good interaction, 0.0 is very likely a bot
61
+ * @param token
62
+ * @param minScore score must be >= minScore to be ok
63
+ * @returns
64
+ * {boolean | null} ok - whether score > minScore (false if something went wrong)
65
+ * {number | null} score - the raw score [0, 1] (or null if a score was not computed)
66
+ */
67
+ async verify(token: string, minScore = 0.5) {
68
+ if (!this.serviceKey) {
69
+ throw new Error('No serviceKey provided')
70
+ }
71
+
72
+ let score, ok, hostname
73
+
74
+ const formData = new FormData()
75
+ formData.append('response', token)
76
+ formData.append('secret', this.serviceKey)
77
+
78
+ try {
79
+ const resp = await axios.post(VERIFY_ENDPOINT, formData, {
80
+ headers: formData.getHeaders(),
81
+ adapter: IS_BROWSER
82
+ ? require('axios/lib/adapters/xhr')
83
+ : require('axios/lib/adapters/http')
84
+ })
85
+
86
+ score = resp.data.score
87
+ ok = score >= minScore
88
+ hostname = resp.data.hostname
89
+ } catch (e) {
90
+ console.error('Error with verifying captcha request', e)
91
+ score = null
92
+ ok = true
93
+ hostname = null
94
+ }
95
+ return { score, ok, hostname }
96
+ }
97
+ }
@@ -0,0 +1,64 @@
1
+ import type Wallet from 'ethereumjs-wallet'
2
+
3
+ // Default multiplier on top of gas estimate to be extra safe that txns
4
+ // will go through
5
+ const GAS_LIMIT_MULTIPLIER = 1.05
6
+
7
+ export interface ContractMethod {
8
+ arguments: string[]
9
+ estimateGas: (config: {
10
+ from: Wallet | string | undefined
11
+ gas: number | undefined
12
+ }) => Promise<number>
13
+ _method: {
14
+ name: string
15
+ inputs: Array<{ type: string }>
16
+ }
17
+ encodeABI: () => string
18
+ send: <Tx>(config: {
19
+ from: Wallet | string | undefined
20
+ gas: number
21
+ gasPrice?: number
22
+ }) => Tx
23
+ }
24
+
25
+ interface EstimateGasConfig {
26
+ method: ContractMethod
27
+ from?: Wallet | string
28
+ gasLimitMaximum: number
29
+ multiplier?: number
30
+ }
31
+
32
+ /**
33
+ * Returns estimated gas use for a txn for a contract method
34
+ * @param options
35
+ * @param options.method the contract method
36
+ * @param options.from address the method will be sent from (required if the contract requires a certain sender, e.g. guardian)
37
+ * @param options.gasLimitMaximum the maximum amount of gas we will allow
38
+ * (likely will return a number much smaller than this)
39
+ * @param options.multipler the multiplier to safe-guard against estimates that are too low
40
+ */
41
+ export const estimateGas = async ({
42
+ method,
43
+ from,
44
+ gasLimitMaximum,
45
+ multiplier = GAS_LIMIT_MULTIPLIER
46
+ }: EstimateGasConfig) => {
47
+ try {
48
+ const estimatedGas = await method.estimateGas({
49
+ from,
50
+ gas: gasLimitMaximum
51
+ })
52
+ // Rounding is necessary here as fractional gas limits will break
53
+ const safeEstimatedGas = Math.ceil(estimatedGas * multiplier)
54
+ console.info(
55
+ `Estimated gas limit ${safeEstimatedGas} for method ${method._method.name}`
56
+ )
57
+ return safeEstimatedGas
58
+ } catch (e) {
59
+ console.error(
60
+ `Unable to estimate gas for transaction ${method._method.name}, using ${gasLimitMaximum}`
61
+ )
62
+ return gasLimitMaximum
63
+ }
64
+ }