@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.
- package/.eslintrc +38 -0
- package/.prettierrc.js +1 -0
- package/.python-version +1 -0
- package/Dockerfile +15 -0
- package/README.md +3 -0
- package/babel.config.js +3 -0
- package/data-contracts/ABIs/AdminUpgradeabilityProxy.json +132 -0
- package/data-contracts/ABIs/BaseAdminUpgradeabilityProxy.json +113 -0
- package/data-contracts/ABIs/BaseUpgradeabilityProxy.json +22 -0
- package/data-contracts/ABIs/DiscoveryProviderFactory.json +189 -0
- package/data-contracts/ABIs/DiscoveryProviderFactoryInterface.json +61 -0
- package/data-contracts/ABIs/DiscoveryProviderStorage.json +205 -0
- package/data-contracts/ABIs/DiscoveryProviderStorageInterface.json +65 -0
- package/data-contracts/ABIs/ECDSA.json +4 -0
- package/data-contracts/ABIs/IPLDBlacklistFactory.json +168 -0
- package/data-contracts/ABIs/Initializable.json +4 -0
- package/data-contracts/ABIs/Migrations.json +67 -0
- package/data-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
- package/data-contracts/ABIs/Ownable.json +79 -0
- package/data-contracts/ABIs/PlaylistFactory.json +669 -0
- package/data-contracts/ABIs/PlaylistFactoryInterface.json +42 -0
- package/data-contracts/ABIs/PlaylistStorage.json +250 -0
- package/data-contracts/ABIs/PlaylistStorageInterface.json +129 -0
- package/data-contracts/ABIs/Proxy.json +10 -0
- package/data-contracts/ABIs/Registry.json +240 -0
- package/data-contracts/ABIs/RegistryContract.json +102 -0
- package/data-contracts/ABIs/RegistryContractInterface.json +28 -0
- package/data-contracts/ABIs/RegistryInterface.json +66 -0
- package/data-contracts/ABIs/SigningLogic.json +43 -0
- package/data-contracts/ABIs/SigningLogicInitializable.json +46 -0
- package/data-contracts/ABIs/SocialFeatureFactory.json +460 -0
- package/data-contracts/ABIs/SocialFeatureStorage.json +225 -0
- package/data-contracts/ABIs/SocialFeatureStorageInterface.json +123 -0
- package/data-contracts/ABIs/TestContract.json +135 -0
- package/data-contracts/ABIs/TestContractInterface.json +19 -0
- package/data-contracts/ABIs/TestContractWithStorage.json +165 -0
- package/data-contracts/ABIs/TestContractWithStorageInterface.json +24 -0
- package/data-contracts/ABIs/TestStorage.json +144 -0
- package/data-contracts/ABIs/TestStorageInterface.json +42 -0
- package/data-contracts/ABIs/TestUserReplicaSetManager.json +432 -0
- package/data-contracts/ABIs/TrackFactory.json +391 -0
- package/data-contracts/ABIs/TrackFactoryInterface.json +73 -0
- package/data-contracts/ABIs/TrackStorage.json +223 -0
- package/data-contracts/ABIs/TrackStorageInterface.json +121 -0
- package/data-contracts/ABIs/UpgradeabilityProxy.json +37 -0
- package/data-contracts/ABIs/UserFactory.json +657 -0
- package/data-contracts/ABIs/UserFactoryInterface.json +65 -0
- package/data-contracts/ABIs/UserLibraryFactory.json +334 -0
- package/data-contracts/ABIs/UserReplicaSetManager.json +418 -0
- package/data-contracts/ABIs/UserStorage.json +233 -0
- package/data-contracts/ABIs/UserStorageInterface.json +93 -0
- package/data-contracts/signatureSchemas.ts +1236 -0
- package/dist/core.d.ts +446 -0
- package/dist/core.js +769 -0
- package/dist/core.js.map +1 -0
- package/dist/index.d.ts +689 -0
- package/dist/index.js +72850 -0
- package/dist/index.js.map +1 -0
- package/eth-contracts/ABIs/Address.json +4 -0
- package/eth-contracts/ABIs/AudiusAdminUpgradeabilityProxy.json +105 -0
- package/eth-contracts/ABIs/AudiusClaimDistributor.json +4968 -0
- package/eth-contracts/ABIs/AudiusToken.json +724 -0
- package/eth-contracts/ABIs/BaseUpgradeabilityProxy.json +23 -0
- package/eth-contracts/ABIs/Checkpointing.json +4 -0
- package/eth-contracts/ABIs/ClaimsManager.json +539 -0
- package/eth-contracts/ABIs/Context.json +11 -0
- package/eth-contracts/ABIs/DelegateManager.json +989 -0
- package/eth-contracts/ABIs/DelegateManagerV2.json +1049 -0
- package/eth-contracts/ABIs/DelegateManagerV2Bad.json +1049 -0
- package/eth-contracts/ABIs/ERC20.json +252 -0
- package/eth-contracts/ABIs/ERC20Burnable.json +287 -0
- package/eth-contracts/ABIs/ERC20Detailed.json +270 -0
- package/eth-contracts/ABIs/ERC20Mintable.json +364 -0
- package/eth-contracts/ABIs/ERC20Pausable.json +397 -0
- package/eth-contracts/ABIs/EthRewardsManager.json +174 -0
- package/eth-contracts/ABIs/Governance.json +938 -0
- package/eth-contracts/ABIs/GovernanceUpgraded.json +953 -0
- package/eth-contracts/ABIs/GovernanceV2.json +938 -0
- package/eth-contracts/ABIs/IERC20.json +200 -0
- package/eth-contracts/ABIs/Initializable.json +4 -0
- package/eth-contracts/ABIs/InitializableV2.json +14 -0
- package/eth-contracts/ABIs/Migrations.json +71 -0
- package/eth-contracts/ABIs/MinterRole.json +91 -0
- package/eth-contracts/ABIs/MockAccount.json +62 -0
- package/eth-contracts/ABIs/MockDelegateManager.json +55 -0
- package/eth-contracts/ABIs/MockStakingCaller.json +259 -0
- package/eth-contracts/ABIs/MockWormhole.json +106 -0
- package/eth-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
- package/eth-contracts/ABIs/Ownable.json +93 -0
- package/eth-contracts/ABIs/Pausable.json +150 -0
- package/eth-contracts/ABIs/PauserRole.json +91 -0
- package/eth-contracts/ABIs/Proxy.json +10 -0
- package/eth-contracts/ABIs/Registry.json +288 -0
- package/eth-contracts/ABIs/Roles.json +4 -0
- package/eth-contracts/ABIs/SafeERC20.json +4 -0
- package/eth-contracts/ABIs/SafeMath.json +4 -0
- package/eth-contracts/ABIs/ServiceProviderFactory.json +1153 -0
- package/eth-contracts/ABIs/ServiceTypeManager.json +337 -0
- package/eth-contracts/ABIs/Staking.json +555 -0
- package/eth-contracts/ABIs/StakingUpgraded.json +570 -0
- package/eth-contracts/ABIs/TestContract.json +44 -0
- package/eth-contracts/ABIs/TrustedNotifierManager.json +265 -0
- package/eth-contracts/ABIs/Uint256Helpers.json +4 -0
- package/eth-contracts/ABIs/UpgradeabilityProxy.json +40 -0
- package/eth-contracts/ABIs/Wormhole.json +45 -0
- package/eth-contracts/ABIs/WormholeClient.json +155 -0
- package/examples/file.mp3 +0 -0
- package/examples/initAudiusLibs.js +86 -0
- package/examples/initializeVersions.js +95 -0
- package/examples/pic.jpg +0 -0
- package/initScripts/configureLocalDiscProv.js +167 -0
- package/initScripts/helpers/claim.js +43 -0
- package/initScripts/helpers/distributeTokens.js +24 -0
- package/initScripts/helpers/spRegistration.js +138 -0
- package/initScripts/helpers/utils.js +34 -0
- package/initScripts/helpers/version.js +93 -0
- package/initScripts/local.js +617 -0
- package/initScripts/mainnet.js +131 -0
- package/initScripts/manageProdRelayerWallets.js +191 -0
- package/package.json +125 -0
- package/rollup.config.js +164 -0
- package/scripts/AudiusClaimDistributor.json +4968 -0
- package/scripts/Wormhole.json +155 -0
- package/scripts/addCIDToIpldBlacklist.js +124 -0
- package/scripts/circleci-test.sh +53 -0
- package/scripts/communityRewards/transferCommunityRewardsToSolana.js +222 -0
- package/scripts/ipfs.sh +58 -0
- package/scripts/migrate_contracts.sh +25 -0
- package/scripts/reset.sh +65 -0
- package/scripts/test.sh +77 -0
- package/src/api/account.js +670 -0
- package/src/api/base.js +122 -0
- package/src/api/file.js +168 -0
- package/src/api/playlist.js +328 -0
- package/src/api/rewards.d.ts +4 -0
- package/src/api/rewards.js +682 -0
- package/src/api/serviceProvider.js +154 -0
- package/src/api/track.js +604 -0
- package/src/api/user.js +888 -0
- package/src/api/user.test.js +172 -0
- package/src/constants.ts +7 -0
- package/src/core.ts +3 -0
- package/src/index.js +6 -0
- package/src/libs.d.ts +3 -0
- package/src/libs.js +619 -0
- package/src/sanityChecks/addSecondaries.js +40 -0
- package/src/sanityChecks/assignReplicaSetIfNecessary.js +10 -0
- package/src/sanityChecks/index.d.ts +9 -0
- package/src/sanityChecks/index.js +31 -0
- package/src/sanityChecks/isCreator.js +73 -0
- package/src/sanityChecks/needsRecoveryEmail.js +20 -0
- package/src/sanityChecks/rolloverNodes.js +74 -0
- package/src/sanityChecks/sanitizeNodes.js +24 -0
- package/src/sanityChecks/syncNodes.js +28 -0
- package/src/sdk/constants.ts +10 -0
- package/src/sdk/index.ts +1 -0
- package/src/sdk/oauth/Oauth.ts +265 -0
- package/src/sdk/oauth/index.ts +1 -0
- package/src/sdk/sdk.ts +102 -0
- package/src/service-selection/ServiceSelection.test.ts +320 -0
- package/src/service-selection/ServiceSelection.ts +460 -0
- package/src/service-selection/constants.ts +14 -0
- package/src/service-selection/index.ts +1 -0
- package/src/services/ABIDecoder/AudiusABIDecoder.ts +71 -0
- package/src/services/ABIDecoder/index.ts +1 -0
- package/src/services/comstock/Comstock.ts +39 -0
- package/src/services/comstock/index.ts +1 -0
- package/src/services/contracts/ContractClient.ts +227 -0
- package/src/services/contracts/GovernedContractClient.ts +53 -0
- package/src/services/contracts/ProviderSelection.ts +42 -0
- package/src/services/creatorNode/CreatorNode.ts +1065 -0
- package/src/services/creatorNode/CreatorNodeSelection.test.ts +997 -0
- package/src/services/creatorNode/CreatorNodeSelection.ts +488 -0
- package/src/services/creatorNode/constants.ts +10 -0
- package/src/services/creatorNode/index.ts +2 -0
- package/src/services/dataContracts/AudiusContracts.ts +234 -0
- package/src/services/dataContracts/IPLDBlacklistFactoryClient.ts +73 -0
- package/src/services/dataContracts/PlaylistFactoryClient.ts +370 -0
- package/src/services/dataContracts/RegistryClient.ts +95 -0
- package/src/services/dataContracts/SocialFeatureFactoryClient.ts +196 -0
- package/src/services/dataContracts/TrackFactoryClient.ts +131 -0
- package/src/services/dataContracts/UserFactoryClient.ts +351 -0
- package/src/services/dataContracts/UserLibraryFactoryClient.ts +115 -0
- package/src/services/dataContracts/UserReplicaSetManagerClient.ts +206 -0
- package/src/services/dataContracts/index.ts +1 -0
- package/src/services/discoveryProvider/DiscoveryProvider.ts +1168 -0
- package/src/services/discoveryProvider/DiscoveryProviderSelection.test.ts +536 -0
- package/src/services/discoveryProvider/DiscoveryProviderSelection.ts +383 -0
- package/src/services/discoveryProvider/constants.ts +13 -0
- package/src/services/discoveryProvider/index.ts +1 -0
- package/src/services/discoveryProvider/requests.ts +629 -0
- package/src/services/ethContracts/AudiusTokenClient.ts +163 -0
- package/src/services/ethContracts/ClaimDistributionClient.ts +45 -0
- package/src/services/ethContracts/ClaimsManagerClient.ts +102 -0
- package/src/services/ethContracts/DelegateManagerClient.ts +480 -0
- package/src/services/ethContracts/EthContracts.ts +359 -0
- package/src/services/ethContracts/EthRewardsManagerClient.ts +33 -0
- package/src/services/ethContracts/GovernanceClient.ts +451 -0
- package/src/services/ethContracts/RegistryClient.ts +33 -0
- package/src/services/ethContracts/ServiceProviderFactoryClient.ts +691 -0
- package/src/services/ethContracts/ServiceTypeManagerClient.ts +112 -0
- package/src/services/ethContracts/StakingProxyClient.ts +97 -0
- package/src/services/ethContracts/TrustedNotifierManagerClient.ts +101 -0
- package/src/services/ethContracts/WormholeClient.ts +97 -0
- package/src/services/ethContracts/index.ts +1 -0
- package/src/services/ethWeb3Manager/EthWeb3Manager.ts +239 -0
- package/src/services/ethWeb3Manager/index.ts +1 -0
- package/src/services/hedgehog/Hedgehog.ts +96 -0
- package/src/services/hedgehog/index.ts +1 -0
- package/src/services/identity/IdentityService.ts +551 -0
- package/src/services/identity/index.ts +1 -0
- package/src/services/identity/requests.ts +65 -0
- package/src/services/schemaValidator/SchemaValidator.ts +105 -0
- package/src/services/schemaValidator/index.ts +1 -0
- package/src/services/schemaValidator/schemas/trackSchema.json +267 -0
- package/src/services/schemaValidator/schemas/userSchema.json +230 -0
- package/src/services/solanaAudiusData/errors.ts +20 -0
- package/src/services/solanaAudiusData/index.ts +1189 -0
- package/src/services/solanaWeb3Manager/errors.js +101 -0
- package/src/services/solanaWeb3Manager/index.d.ts +46 -0
- package/src/services/solanaWeb3Manager/index.js +655 -0
- package/src/services/solanaWeb3Manager/padBNToUint8Array.ts +7 -0
- package/src/services/solanaWeb3Manager/rewards.js +941 -0
- package/src/services/solanaWeb3Manager/rewardsAttester.ts +1093 -0
- package/src/services/solanaWeb3Manager/tokenAccount.js +149 -0
- package/src/services/solanaWeb3Manager/transactionHandler.js +345 -0
- package/src/services/solanaWeb3Manager/transfer.js +272 -0
- package/src/services/solanaWeb3Manager/userBank.js +160 -0
- package/src/services/solanaWeb3Manager/utils.d.ts +31 -0
- package/src/services/solanaWeb3Manager/utils.js +163 -0
- package/src/services/solanaWeb3Manager/wAudio.js +28 -0
- package/src/services/solanaWeb3Manager/wAudio.test.js +30 -0
- package/src/services/web3Manager/Web3Config.ts +14 -0
- package/src/services/web3Manager/Web3Manager.ts +360 -0
- package/src/services/web3Manager/XMLHttpRequest.ts +11 -0
- package/src/services/web3Manager/index.ts +2 -0
- package/src/services/wormhole/index.js +424 -0
- package/src/types.ts +8 -0
- package/src/userStateManager.ts +53 -0
- package/src/utils/apiSigning.ts +51 -0
- package/src/utils/captcha.ts +97 -0
- package/src/utils/estimateGas.ts +64 -0
- package/src/utils/fileHasher.ts +278 -0
- package/src/utils/importContractABI.d.ts +9 -0
- package/src/utils/importContractABI.js +19 -0
- package/src/utils/index.ts +11 -0
- package/src/utils/multiProvider.ts +72 -0
- package/src/utils/network.test.ts +127 -0
- package/src/utils/network.ts +308 -0
- package/src/utils/promiseFight.test.ts +87 -0
- package/src/utils/promiseFight.ts +36 -0
- package/src/utils/signatures.ts +139 -0
- package/src/utils/types.ts +34 -0
- package/src/utils/utils.test.ts +36 -0
- package/src/utils/utils.ts +235 -0
- package/src/utils/uuid.ts +14 -0
- package/src/web3.d.ts +9 -0
- package/src/web3.js +8 -0
- package/tests/assets/static_image.png +0 -0
- package/tests/assets/static_text.txt +1 -0
- package/tests/audiusTokenClientTest.js +37 -0
- package/tests/creatorNodeTest.js +19 -0
- package/tests/fileHasherTest.js +125 -0
- package/tests/governanceTest.js +382 -0
- package/tests/helpers.js +105 -0
- package/tests/index.js +14 -0
- package/tests/playlistClientTest.js +157 -0
- package/tests/providerSelectionTest.js +241 -0
- package/tests/registryClientTest.js +19 -0
- package/tests/rewardsAttesterTest.js +373 -0
- package/tests/serviceTypeManagerClientTest.js +33 -0
- package/tests/socialFeatureClientTest.js +79 -0
- package/tests/stakingTest.js +302 -0
- package/tests/trackClientTest.js +86 -0
- package/tests/userClientTest.js +121 -0
- package/tsconfig.json +10 -0
- package/types/@audius-hedgehog/index.d.ts +39 -0
- 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
|
+
})
|