@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,308 @@
1
+ import axios, {
2
+ AxiosRequestConfig,
3
+ AxiosResponse,
4
+ CancelTokenSource
5
+ } from 'axios'
6
+ import semver from 'semver'
7
+
8
+ import { Utils } from './utils'
9
+ import { promiseFight } from './promiseFight'
10
+
11
+ export type ServiceName = string
12
+ export interface ServiceWithEndpoint {
13
+ endpoint: string
14
+ spID?: string
15
+ }
16
+ export type Service = ServiceName | ServiceWithEndpoint
17
+
18
+ interface Request {
19
+ id?: string
20
+ url: string
21
+ }
22
+
23
+ interface TimingConfig {
24
+ timeout?: number
25
+ }
26
+
27
+ export interface Timing {
28
+ request: Request
29
+ response: AxiosResponse | null
30
+ millis: number | null
31
+ }
32
+
33
+ /**
34
+ * Fetches a url and times how long it took the request to complete.
35
+ */
36
+ async function timeRequest(
37
+ request: Request,
38
+ timeout?: number | null
39
+ ): Promise<Timing> {
40
+ // This is non-perfect because of the js event loop, but enough
41
+ // of a proximation. Don't use for mission-critical timing.
42
+ const startTime = new Date().getTime()
43
+ const config: TimingConfig = {}
44
+ if (timeout !== null && timeout !== undefined) {
45
+ config.timeout = timeout
46
+ }
47
+ let response
48
+ try {
49
+ response = await axios.get(request.url, config)
50
+ } catch (e) {
51
+ console.debug(`Error with request for ${request.url}: ${e}`)
52
+ return { request, response: null, millis: null }
53
+ }
54
+ const millis = new Date().getTime() - startTime
55
+ return { request, response, millis }
56
+ }
57
+
58
+ interface SortServiceTimingsConfig {
59
+ serviceTimings: Timing[]
60
+ sortByVersion: boolean
61
+ currentVersion?: string | null
62
+ /*
63
+ * the number of milliseconds at which we consider services to be equally as fast
64
+ * and pick randomly between them. Default of null implies that the faster service
65
+ * (even if by 1ms) will be picked always.
66
+ */
67
+ equivalencyDelta?: number | null
68
+ }
69
+
70
+ /**
71
+ * Custom sort for `serviceTimings`, the response from `timeRequest()` function above
72
+ */
73
+ function sortServiceTimings({
74
+ serviceTimings,
75
+ sortByVersion,
76
+ currentVersion = null, // only required if `sortByVersion` = false
77
+ equivalencyDelta = null
78
+ }: SortServiceTimingsConfig) {
79
+ return serviceTimings.sort((a, b) => {
80
+ // If health check failed, send to back of timings
81
+ if (a.response == null) return 1
82
+ if (b.response == null) return -1
83
+
84
+ const aVersion = a.response.data.data.version
85
+ const bVersion = b.response.data.data.version
86
+
87
+ if (sortByVersion) {
88
+ // Always sort by version desc
89
+ if (semver.gt(aVersion, bVersion)) return -1
90
+ if (semver.lt(aVersion, bVersion)) return 1
91
+ } else if (!sortByVersion && currentVersion) {
92
+ // Only sort by version if behind current on-chain version
93
+ if (
94
+ semver.gt(currentVersion, aVersion) &&
95
+ semver.gt(currentVersion, bVersion)
96
+ ) {
97
+ if (semver.gt(aVersion, bVersion)) return -1
98
+ if (semver.lt(aVersion, bVersion)) return 1
99
+ } else if (semver.gt(currentVersion, aVersion)) {
100
+ return 1
101
+ } else if (semver.gt(currentVersion, bVersion)) {
102
+ return -1
103
+ }
104
+ }
105
+
106
+ // If same version and transcode queue load, do a tie breaker on the response time
107
+ // If the requests are near eachother (delta < equivalencyDelta), pick randomly
108
+
109
+ const delta = (a.millis ?? 0) - (b.millis ?? 0)
110
+ if (equivalencyDelta !== null && delta < equivalencyDelta) {
111
+ return 1 - 2 * Math.random() // [-1, 1]
112
+ }
113
+ return delta
114
+ })
115
+ }
116
+
117
+ interface TimeRequestsConfig {
118
+ requests: Request[]
119
+ sortByVersion?: boolean
120
+ filterNonResponsive?: boolean
121
+ // current on-chain service version - only required if `sortByVersion` = false
122
+ currentVersion?: string | null
123
+ // ms applied to each individual request
124
+ timeout?: number | null
125
+ /*
126
+ * the number of milliseconds at which we consider services to be equally as fast
127
+ * and pick randomly between them. Default of null implies that the faster service
128
+ * (even if by 1ms) will be picked always.
129
+ */
130
+ equivalencyDelta?: number | null
131
+ }
132
+
133
+ /**
134
+ * Fetches multiple urls and times each request and returns the results sorted
135
+ * first by version and then by lowest-latency.
136
+ */
137
+ async function timeRequests({
138
+ requests,
139
+ sortByVersion = false,
140
+ currentVersion = null, // only required if `sortByVersion` = false
141
+ filterNonResponsive = false,
142
+ timeout = null,
143
+ equivalencyDelta = null
144
+ }: TimeRequestsConfig) {
145
+ let serviceTimings = await Promise.all(
146
+ requests.map(async (request) => await timeRequest(request, timeout))
147
+ )
148
+
149
+ if (filterNonResponsive) {
150
+ serviceTimings = serviceTimings.filter((timing) => timing.response !== null)
151
+ }
152
+
153
+ return sortServiceTimings({
154
+ serviceTimings,
155
+ currentVersion,
156
+ sortByVersion,
157
+ equivalencyDelta
158
+ })
159
+ }
160
+
161
+ type RequestResponses =
162
+ | { blob: AxiosResponse; url: string }
163
+ | AxiosResponse
164
+ // eslint-disable-next-line @typescript-eslint/no-invalid-void-type -- this is a return type
165
+ | void
166
+
167
+ /**
168
+ * Races multiple requests
169
+ * @param urls
170
+ * @param callback invoked with the first successful url
171
+ * @param axiosConfig extra axios config for each request
172
+ * @param timeout timeout for any requests to be considered bad
173
+ * @param timeBetweenRequests time between requests being dispatched to free up client network interface
174
+ */
175
+ async function raceRequests(
176
+ urls: string[],
177
+ callback: (url: string) => void,
178
+ axiosConfig: AxiosRequestConfig,
179
+ timeout = 3000,
180
+ timeBetweenRequests = 100,
181
+ validationCheck = (_: AxiosResponse) => true
182
+ ) {
183
+ const CancelToken = axios.CancelToken
184
+
185
+ const sources: CancelTokenSource[] = []
186
+ let hasFinished = false
187
+ const requests = urls.map(async (url, i) => {
188
+ const source = CancelToken.source()
189
+ sources.push(source)
190
+
191
+ // Slightly offset requests by their order, so:
192
+ // 1. We try creator node gateways first
193
+ // 2. We give requests the opportunity to get canceled if other's are very fast
194
+ await Utils.wait(timeBetweenRequests * i)
195
+ if (hasFinished) return
196
+ return await new Promise<RequestResponses>((resolve, reject) => {
197
+ axios({
198
+ method: 'get',
199
+ url,
200
+ cancelToken: source.token,
201
+ ...axiosConfig
202
+ })
203
+ .then((response) => {
204
+ const isValid = validationCheck(response)
205
+ if (isValid) {
206
+ hasFinished = true
207
+ resolve({
208
+ blob: response,
209
+ url
210
+ })
211
+ } else {
212
+ // Invalid because of validity check
213
+ reject(response)
214
+ }
215
+ })
216
+ .catch((thrown) => {
217
+ reject(thrown)
218
+ // no-op.
219
+ // If debugging `axios.isCancel(thrown)`
220
+ // can be used to check if the throw was from a cancel.
221
+ })
222
+ })
223
+ })
224
+ if (timeout !== null) {
225
+ requests.push(Utils.wait(timeout))
226
+ }
227
+ let response
228
+ let errored: AxiosResponse[]
229
+ try {
230
+ const { val, errored: e } = await promiseFight<
231
+ RequestResponses,
232
+ AxiosResponse
233
+ >(requests, true)
234
+ response = val
235
+ errored = e
236
+ } catch (e: any) {
237
+ response = null
238
+ errored = e
239
+ }
240
+ sources.forEach((source) => {
241
+ source.cancel('Fetch already succeeded')
242
+ })
243
+
244
+ if (response && 'url' in response && 'blob' in response) {
245
+ callback(response.url)
246
+ return { response: response.blob, errored }
247
+ }
248
+
249
+ return { response: null, errored }
250
+ }
251
+
252
+ interface AllRequestsConfig {
253
+ /*
254
+ * map of actual URL to hit (e.g. https://resource/endpoint)
255
+ * and identifying value (e.g. https://resource)
256
+ */
257
+ urlMap: Record<string, Service>
258
+ /*
259
+ * timeout for any request to be considered bad
260
+ */
261
+ timeout: number
262
+ /* a check invoked for each response.
263
+ * If invalid, the response is filtered out.
264
+ * (response: any) => boolean
265
+ */
266
+ validationCheck: (_: AxiosResponse) => boolean
267
+ }
268
+
269
+ /**
270
+ * Gets the response for many requests with a timeout to each
271
+ */
272
+ async function allRequests({
273
+ urlMap,
274
+ timeout,
275
+ validationCheck
276
+ }: AllRequestsConfig) {
277
+ const urls = Object.keys(urlMap)
278
+ const requests = urls.map(async (url) => {
279
+ return await new Promise<Service | null>((resolve) => {
280
+ axios({
281
+ method: 'get',
282
+ timeout,
283
+ url
284
+ })
285
+ .then((response) => {
286
+ const isValid = validationCheck(response)
287
+ if (isValid) {
288
+ resolve(urlMap[url] as Service)
289
+ } else {
290
+ resolve(null)
291
+ }
292
+ })
293
+ .catch(() => {
294
+ resolve(null)
295
+ })
296
+ })
297
+ })
298
+ const responses = (await Promise.all(requests)).filter(Boolean)
299
+ return responses
300
+ }
301
+
302
+ export {
303
+ timeRequest,
304
+ timeRequests,
305
+ raceRequests,
306
+ allRequests,
307
+ sortServiceTimings
308
+ }
@@ -0,0 +1,87 @@
1
+ import { promiseFight } from './promiseFight'
2
+ import assert from 'assert'
3
+
4
+ /**
5
+ * A promise that either resolves or rejects. If it resolves,
6
+ * resolves with the provided id.
7
+ * @param id identifier for this promise
8
+ * @param resolveTimeout resolves after this timeout
9
+ * @param rejectTimeout rejects after this timeout
10
+ */
11
+ const p = async (
12
+ id: string,
13
+ resolveTimeout: null | number,
14
+ rejectTimeout?: number
15
+ ) =>
16
+ await new Promise((resolve, reject) => {
17
+ if (resolveTimeout) {
18
+ setTimeout(() => resolve(id), resolveTimeout)
19
+ }
20
+ if (rejectTimeout) {
21
+ setTimeout(() => reject(id), rejectTimeout)
22
+ }
23
+ })
24
+
25
+ describe('promiseFight', () => {
26
+ it('should pick the first', async () => {
27
+ const res = await promiseFight([p('first', 1), p('second', 100)])
28
+ assert.strictEqual(res, 'first')
29
+ })
30
+
31
+ it('should pick the first of many', async () => {
32
+ const res = await promiseFight([
33
+ p('first', 1),
34
+ p('second', 100),
35
+ p('third', 101),
36
+ p('fourth', 102),
37
+ p('fifth', 103)
38
+ ])
39
+ assert.strictEqual(res, 'first')
40
+ })
41
+
42
+ it('should pick the first that succeeds', async () => {
43
+ const res = await promiseFight([
44
+ p('first', 100),
45
+ p('second', null, 10),
46
+ p('third', null, 20)
47
+ ])
48
+ assert.strictEqual(res, 'first')
49
+ })
50
+
51
+ it('should pick the first that succeeds and capture the failed', async () => {
52
+ const res = await promiseFight(
53
+ [p('first', 100), p('second', null, 10), p('third', null, 20)],
54
+ true
55
+ )
56
+ assert.deepStrictEqual(res, { val: 'first', errored: ['second', 'third'] })
57
+ })
58
+
59
+ it('should pick the first that succeeds and capture the failed that finished', async () => {
60
+ const res = await promiseFight(
61
+ [
62
+ p('first', 100),
63
+ p('second', null, 10),
64
+ p('third', null, 20),
65
+ p('fourth', null, 200)
66
+ ],
67
+ true
68
+ )
69
+ assert.deepStrictEqual(res, { val: 'first', errored: ['second', 'third'] })
70
+ })
71
+
72
+ it('should fail if all of the promises fail', async () => {
73
+ try {
74
+ await promiseFight(
75
+ [
76
+ p('first', null, 100),
77
+ p('second', null, 10),
78
+ p('third', null, 20),
79
+ p('fourth', null, 200)
80
+ ],
81
+ true
82
+ )
83
+ } catch (e) {
84
+ assert.deepStrictEqual(e, ['first', 'second', 'third', 'fourth'])
85
+ }
86
+ })
87
+ })
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Given an array of promises, it returns the first resolved promise as soon as it finishes
3
+ * @param promises
4
+ * @param captureErrored optional capture errored promises
5
+ * @return A promise that resolves with the first promise that resolves
6
+ */
7
+ export async function promiseFight<T1, T2>(
8
+ promises: Array<Promise<T1>>
9
+ ): Promise<T1 | T2>
10
+ export async function promiseFight<T1, T2>(
11
+ promises: Array<Promise<T1>>,
12
+ captureErrored: boolean
13
+ ): Promise<{ val: T1; errored: T2[] }>
14
+ export async function promiseFight<T1, T2>(
15
+ promises: Array<Promise<T1>>,
16
+ captureErrored?: boolean
17
+ ) {
18
+ const errored: T2[] = []
19
+ return await Promise.all<Array<Promise<T1 | T2>>>(
20
+ promises.map(async (p) => {
21
+ return await p.then<T1, T2>(
22
+ async (val) => await Promise.reject(val),
23
+ async (err) => {
24
+ if (captureErrored) errored.push(err)
25
+ return await Promise.resolve(err)
26
+ }
27
+ )
28
+ })
29
+ ).then(
30
+ async (errors) => await Promise.reject(errors),
31
+ async (val) => {
32
+ if (captureErrored) return await Promise.resolve({ val, errored })
33
+ else return await Promise.resolve(val)
34
+ }
35
+ )
36
+ }
@@ -0,0 +1,139 @@
1
+ import { Utils } from './utils'
2
+ import { ecsign, toBuffer } from 'ethereumjs-util'
3
+ import { pack } from '@ethersproject/solidity'
4
+ import type Web3 from 'web3'
5
+
6
+ export const sign = (digest: any, privateKey: Buffer) => {
7
+ const buffer = toBuffer(digest)
8
+ const signature = ecsign(buffer, privateKey)
9
+ return signature
10
+ }
11
+
12
+ // lazyload permitTypehash to avoid a web3 race
13
+ let _permitTypehash: null | string = null
14
+ const getPermitTypehash = () => {
15
+ if (!_permitTypehash) {
16
+ _permitTypehash = Utils.keccak256(
17
+ 'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)'
18
+ )
19
+ }
20
+ return _permitTypehash
21
+ }
22
+
23
+ let _transferTokensTypehash: null | string = null
24
+ const getTransferTokensTypeHash = () => {
25
+ if (!_transferTokensTypehash) {
26
+ _transferTokensTypehash = Utils.keccak256(
27
+ 'TransferTokens(address from,uint256 amount,uint16 recipientChain,bytes32 recipient,uint256 artbiterFee,uint32 nonce,uint256 deadline)'
28
+ )
29
+ }
30
+ return _transferTokensTypehash
31
+ }
32
+
33
+ export interface ApproveTokens {
34
+ owner: string
35
+ spender: string
36
+ value: string
37
+ }
38
+
39
+ // Returns the EIP712 hash which should be signed by the user
40
+ // in order to make a call to `permit`
41
+ export function getPermitDigest(
42
+ web3: Web3,
43
+ name: string,
44
+ address: string,
45
+ chainId: string,
46
+ approve: ApproveTokens,
47
+ nonce: boolean,
48
+ deadline: string
49
+ ) {
50
+ const DOMAIN_SEPARATOR = getDomainSeparator(web3, name, address, chainId)
51
+
52
+ const innerEncoded = web3.eth.abi.encodeParameters(
53
+ ['bytes32', 'address', 'address', 'uint256', 'uint256', 'uint256'],
54
+ [
55
+ getPermitTypehash(),
56
+ approve.owner,
57
+ approve.spender,
58
+ approve.value,
59
+ nonce,
60
+ deadline
61
+ ]
62
+ )
63
+ const encoded = pack(
64
+ ['bytes1', 'bytes1', 'bytes32', 'bytes32'],
65
+ ['0x19', '0x01', DOMAIN_SEPARATOR, Utils.keccak256(innerEncoded)]
66
+ )
67
+ return Utils.keccak256(encoded)
68
+ }
69
+
70
+ export interface TransferTokens {
71
+ from: string
72
+ amount: string
73
+ recipientChain: string
74
+ recipient: string
75
+ arbiterFee: string
76
+ }
77
+
78
+ // Returns the EIP712 hash which should be signed by the user
79
+ // in order to make a call to `transferTokens`
80
+ export function getTransferTokensDigest(
81
+ web3: Web3,
82
+ name: string,
83
+ address: string,
84
+ chainId: string,
85
+ transferTokens: TransferTokens,
86
+ nonce: boolean,
87
+ deadline: string
88
+ ) {
89
+ const DOMAIN_SEPARATOR = getDomainSeparator(web3, name, address, chainId)
90
+ const innerEncoded = web3.eth.abi.encodeParameters(
91
+ [
92
+ 'bytes32',
93
+ 'address',
94
+ 'uint256',
95
+ 'uint16',
96
+ 'bytes32',
97
+ 'uint256',
98
+ 'uint32',
99
+ 'uint256'
100
+ ],
101
+ [
102
+ getTransferTokensTypeHash(),
103
+ transferTokens.from,
104
+ transferTokens.amount,
105
+ transferTokens.recipientChain,
106
+ transferTokens.recipient,
107
+ transferTokens.arbiterFee,
108
+ nonce,
109
+ deadline
110
+ ]
111
+ )
112
+ const encoded = pack(
113
+ ['bytes1', 'bytes1', 'bytes32', 'bytes32'],
114
+ ['0x19', '0x01', DOMAIN_SEPARATOR, Utils.keccak256(innerEncoded)]
115
+ )
116
+ return Utils.keccak256(encoded)
117
+ }
118
+
119
+ // Gets the EIP712 domain separator
120
+ function getDomainSeparator(
121
+ web3: Web3,
122
+ name: string,
123
+ contractAddress: string,
124
+ chainId: string
125
+ ) {
126
+ const encoded = web3.eth.abi.encodeParameters(
127
+ ['bytes32', 'bytes32', 'bytes32', 'uint256', 'address'],
128
+ [
129
+ Utils.keccak256(
130
+ 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
131
+ ),
132
+ Utils.keccak256(name),
133
+ Utils.keccak256('1'),
134
+ chainId,
135
+ contractAddress
136
+ ]
137
+ )
138
+ return Utils.keccak256(encoded)
139
+ }
@@ -0,0 +1,34 @@
1
+ export type Maybe<T> = T | undefined
2
+ export type Nullable<T> = T | null
3
+
4
+ export interface Logger {
5
+ /**
6
+ * Write a 'log' level log.
7
+ */
8
+ log: (message: any, ...optionalParams: any[]) => any
9
+
10
+ /**
11
+ * Write a 'info' level log.
12
+ */
13
+ info: (message: any, ...optionalParams: any[]) => any
14
+
15
+ /**
16
+ * Write an 'error' level log.
17
+ */
18
+ error: (message: any, ...optionalParams: any[]) => any
19
+
20
+ /**
21
+ * Write a 'warn' level log.
22
+ */
23
+ warn: (message: any, ...optionalParams: any[]) => any
24
+
25
+ /**
26
+ * Write a 'debug' level log.
27
+ */
28
+ debug?: (message: any, ...optionalParams: any[]) => any
29
+
30
+ /**
31
+ * Write a 'verbose' level log.
32
+ */
33
+ verbose?: (message: any, ...optionalParams: any[]) => any
34
+ }
@@ -0,0 +1,36 @@
1
+ import assert from 'assert'
2
+ import { Utils } from './utils'
3
+
4
+ describe('utils', () => {
5
+ it('should decodeMethod correctly', async () => {
6
+ const decoded = Utils.decodeMultihash(
7
+ 'QmWAoBkJzA1Ffur3aiVPr8h5YSV5aBxRFNeZDPmB7vnBQP'
8
+ )
9
+ assert.strictEqual(
10
+ decoded.digest,
11
+ '0x74574595073a25aaac18f1089239a26f8bceaf76cc29973d2be13352d2abca4c'
12
+ )
13
+ assert.strictEqual(decoded.hashFn, 18) // constant
14
+ assert.strictEqual(decoded.size, 32) // constant
15
+ })
16
+
17
+ it('should encodeMethod correctly with 0x prefix', async () => {
18
+ const encoded = Utils.encodeMultihash(
19
+ '0x74574595073a25aaac18f1089239a26f8bceaf76cc29973d2be13352d2abca4c'
20
+ )
21
+ assert.strictEqual(
22
+ encoded,
23
+ 'QmWAoBkJzA1Ffur3aiVPr8h5YSV5aBxRFNeZDPmB7vnBQP'
24
+ )
25
+ })
26
+
27
+ it('should encodeMethod correctly without 0x prefix', async () => {
28
+ const encoded = Utils.encodeMultihash(
29
+ '74574595073a25aaac18f1089239a26f8bceaf76cc29973d2be13352d2abca4c'
30
+ )
31
+ assert.strictEqual(
32
+ encoded,
33
+ 'QmWAoBkJzA1Ffur3aiVPr8h5YSV5aBxRFNeZDPmB7vnBQP'
34
+ )
35
+ })
36
+ })