@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,682 @@
|
|
|
1
|
+
const axios = require('axios')
|
|
2
|
+
const { sampleSize } = require('lodash')
|
|
3
|
+
|
|
4
|
+
const { Base, Services } = require('./base')
|
|
5
|
+
const BN = require('bn.js')
|
|
6
|
+
const { RewardsManagerError } = require('../services/solanaWeb3Manager/errors')
|
|
7
|
+
const { WAUDIO_DECMIALS } = require('../constants')
|
|
8
|
+
const { Utils } = require('../utils/utils')
|
|
9
|
+
|
|
10
|
+
const { decodeHashId } = Utils
|
|
11
|
+
|
|
12
|
+
const GetAttestationError = Object.freeze({
|
|
13
|
+
CHALLENGE_INCOMPLETE: 'CHALLENGE_INCOMPLETE',
|
|
14
|
+
ALREADY_DISBURSED: 'ALREADY_DISBURSED',
|
|
15
|
+
INVALID_ORACLE: 'INVALID_ORACLE',
|
|
16
|
+
MISSING_CHALLENGES: 'MISSING_CHALLENGES',
|
|
17
|
+
INVALID_INPUT: 'INVALID_INPUT',
|
|
18
|
+
USER_NOT_FOUND: 'USER_NOT_FOUND',
|
|
19
|
+
HCAPTCHA: 'HCAPTCHA',
|
|
20
|
+
COGNITO_FLOW: 'COGNITO_FLOW',
|
|
21
|
+
DISCOVERY_NODE_ATTESTATION_ERROR: 'DISCOVERY_NODE_ATTESTATION_ERROR',
|
|
22
|
+
DISCOVERY_NODE_UNKNOWN_RESPONSE: 'DISCOVERY_NODE_UNKNOWN_RESPONSE',
|
|
23
|
+
AAO_ATTESTATION_ERROR: 'AAO_ATTESTATION_ERROR',
|
|
24
|
+
AAO_ATTESTATION_REJECTION: 'AAO_ATTESTATION_REJECTION',
|
|
25
|
+
AAO_ATTESTATION_UNKNOWN_RESPONSE: 'AAO_ATTESTATION_UNKNOWN_RESPONSE',
|
|
26
|
+
UNKNOWN_ERROR: 'UNKNOWN_ERROR'
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const AggregateAttestationError = Object.freeze(
|
|
30
|
+
{
|
|
31
|
+
INSUFFICIENT_DISCOVERY_NODE_COUNT: 'INSUFFICIENT_DISCOVERY_NODE_COUNT',
|
|
32
|
+
UNKNOWN_ERROR: 'UNKNOWN_ERROR'
|
|
33
|
+
}
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const GetSenderAttestationError = Object.freeze({
|
|
37
|
+
REQUEST_FOR_ATTESTATION_FAILED: 'REQUEST_FOR_ATTESTATION_FAILED'
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Combined error type for `SubmitAndEvaluate`
|
|
42
|
+
*/
|
|
43
|
+
const SubmitAndEvaluateError = Object.freeze({
|
|
44
|
+
...GetAttestationError,
|
|
45
|
+
...AggregateAttestationError,
|
|
46
|
+
...RewardsManagerError
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const AttestationPhases = Object.freeze({
|
|
50
|
+
SANITY_CHECKS: 'SANITY_CHECKS',
|
|
51
|
+
AGGREGATE_ATTESTATIONS: 'AGGREGATE_ATTESTATIONS',
|
|
52
|
+
SUBMIT_ATTESTATIONS: 'SUBMIT_ATTESTATIONS',
|
|
53
|
+
EVALUATE_ATTESTATIONS: 'EVALUATE_ATTESTATIONS'
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const AAO_REQUEST_TIMEOUT_MS = 15 * 1000
|
|
57
|
+
const WRAPPED_AUDIO_PRECISION = 10 ** WAUDIO_DECMIALS
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @typedef {import("../services/solanaWeb3Manager/rewards.js").AttestationMeta} AttestationMeta
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
class Rewards extends Base {
|
|
64
|
+
constructor (ServiceProvider, ...args) {
|
|
65
|
+
super(...args)
|
|
66
|
+
this.ServiceProvider = ServiceProvider
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
*
|
|
71
|
+
* Top level method to aggregate attestations, submit them to RewardsManager, and evalute the result.
|
|
72
|
+
*
|
|
73
|
+
* @typedef {Object} GetSubmitAndEvaluateAttestationsReturn
|
|
74
|
+
* @property {Boolean} success
|
|
75
|
+
* @property {GetAttestationError} error
|
|
76
|
+
*
|
|
77
|
+
* @param {{
|
|
78
|
+
* challengeId: string,
|
|
79
|
+
* encodedUserId: string,
|
|
80
|
+
* handle: string,
|
|
81
|
+
* recipientEthAddress: string,
|
|
82
|
+
* specifier: string,
|
|
83
|
+
* oracleEthAddress: string,
|
|
84
|
+
* amount: number,
|
|
85
|
+
* quorumSize: number,
|
|
86
|
+
* AAOEndpoint: string,
|
|
87
|
+
* endpoints: Array<string>,
|
|
88
|
+
* instructionsPerTransaction?: number,
|
|
89
|
+
* maxAggregationAttempts?: number
|
|
90
|
+
* logger: any
|
|
91
|
+
* feePayerOverride: string | null
|
|
92
|
+
* }} {
|
|
93
|
+
* challengeId,
|
|
94
|
+
* encodedUserId,
|
|
95
|
+
* handle,
|
|
96
|
+
* recipientEthAddress,
|
|
97
|
+
* specifier,
|
|
98
|
+
* oracleEthAddress,
|
|
99
|
+
* amount,
|
|
100
|
+
* quorumSize,
|
|
101
|
+
* AAOEndpoint,
|
|
102
|
+
* endpoints,
|
|
103
|
+
* maxAggregationAttempts,
|
|
104
|
+
* instructionsPerTransaction,
|
|
105
|
+
* logger,
|
|
106
|
+
* feePayerOverride
|
|
107
|
+
* }
|
|
108
|
+
* @returns {Promise<GetSubmitAndEvaluateAttestationsReturn>}
|
|
109
|
+
* @memberof Challenge
|
|
110
|
+
*/
|
|
111
|
+
async submitAndEvaluate ({
|
|
112
|
+
challengeId, encodedUserId, handle, recipientEthAddress, specifier, oracleEthAddress, amount, quorumSize, AAOEndpoint, instructionsPerTransaction, maxAggregationAttempts = 20, endpoints = null, logger = console, feePayerOverride = null
|
|
113
|
+
}) {
|
|
114
|
+
let phase
|
|
115
|
+
let nodesToReselect = null
|
|
116
|
+
try {
|
|
117
|
+
phase = AttestationPhases.SANITY_CHECKS
|
|
118
|
+
|
|
119
|
+
// fail if amount is a decimal
|
|
120
|
+
if ((Number(amount) !== amount) || (amount % 1 !== 0)) {
|
|
121
|
+
throw new Error('Invalid amount')
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Aggregate
|
|
125
|
+
|
|
126
|
+
logger.info(`submitAndEvaluate: aggregating attestations for userId [${decodeHashId(encodedUserId)}], challengeId [${challengeId}]`)
|
|
127
|
+
phase = AttestationPhases.AGGREGATE_ATTESTATIONS
|
|
128
|
+
const { discoveryNodeAttestations, aaoAttestation, error: aggregateError, erroringNodes } = await this.aggregateAttestations({
|
|
129
|
+
challengeId, encodedUserId, handle, specifier, oracleEthAddress, amount, quorumSize, AAOEndpoint, endpoints, logger, maxAttempts: maxAggregationAttempts
|
|
130
|
+
})
|
|
131
|
+
if (aggregateError) {
|
|
132
|
+
nodesToReselect = erroringNodes
|
|
133
|
+
throw new Error(aggregateError)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Submit
|
|
137
|
+
|
|
138
|
+
logger.info(`submitAndEvaluate: submitting for challenge [${challengeId}], userId: [${decodeHashId(encodedUserId)}] with [${discoveryNodeAttestations.length}] DN and [${aaoAttestation ? 1 : 0}] oracle attestations.`)
|
|
139
|
+
const fullTokenAmount = new BN(amount * WRAPPED_AUDIO_PRECISION)
|
|
140
|
+
phase = AttestationPhases.SUBMIT_ATTESTATIONS
|
|
141
|
+
const { errorCode: submitErrorCode, error: submitError } = await this.solanaWeb3Manager.submitChallengeAttestations({
|
|
142
|
+
attestations: discoveryNodeAttestations,
|
|
143
|
+
oracleAttestation: aaoAttestation,
|
|
144
|
+
challengeId,
|
|
145
|
+
specifier,
|
|
146
|
+
recipientEthAddress,
|
|
147
|
+
tokenAmount: fullTokenAmount,
|
|
148
|
+
instructionsPerTransaction,
|
|
149
|
+
logger,
|
|
150
|
+
feePayerOverride
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
// In the case of an unparseable error,
|
|
154
|
+
// we'll only have the error, not the code.
|
|
155
|
+
if (submitErrorCode || submitError) {
|
|
156
|
+
const shouldRetryInSeperateTransactions = (
|
|
157
|
+
submitErrorCode === RewardsManagerError.REPEATED_SENDERS ||
|
|
158
|
+
submitErrorCode === RewardsManagerError.SIGN_COLLISION ||
|
|
159
|
+
submitErrorCode === RewardsManagerError.OPERATOR_COLLISION
|
|
160
|
+
)
|
|
161
|
+
// If we have sender collisions, we should
|
|
162
|
+
// submit one attestation per transaction and try to get
|
|
163
|
+
// into a good state.
|
|
164
|
+
// TODO: in the case this retry fails, we still proceed
|
|
165
|
+
// to evaluate phase and will error there (not ideal)
|
|
166
|
+
if (shouldRetryInSeperateTransactions) {
|
|
167
|
+
logger.warn(`submitAndEvaluate: saw repeat senders for userId [${decodeHashId(encodedUserId)}] challengeId: [${challengeId}] with err: ${submitErrorCode}, breaking up into individual transactions`)
|
|
168
|
+
await this.solanaWeb3Manager.submitChallengeAttestations({
|
|
169
|
+
attestations: discoveryNodeAttestations,
|
|
170
|
+
oracleAttestation: aaoAttestation,
|
|
171
|
+
challengeId,
|
|
172
|
+
specifier,
|
|
173
|
+
recipientEthAddress,
|
|
174
|
+
tokenAmount: fullTokenAmount,
|
|
175
|
+
instructionsPerTransaction: 2, // SECP + Attestation
|
|
176
|
+
logger,
|
|
177
|
+
feePayerOverride
|
|
178
|
+
})
|
|
179
|
+
} else {
|
|
180
|
+
throw new Error(submitErrorCode || submitError)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Evaluate
|
|
185
|
+
|
|
186
|
+
logger.info(`submitAndEvaluate: evaluating for challenge [${challengeId}], userId: [${decodeHashId(encodedUserId)}]`)
|
|
187
|
+
phase = AttestationPhases.EVALUATE_ATTESTATIONS
|
|
188
|
+
const { errorCode: evaluateErrorCode, error: evaluateError } = await this.solanaWeb3Manager.evaluateChallengeAttestations({
|
|
189
|
+
challengeId,
|
|
190
|
+
specifier,
|
|
191
|
+
recipientEthAddress,
|
|
192
|
+
oracleEthAddress,
|
|
193
|
+
tokenAmount: fullTokenAmount,
|
|
194
|
+
logger,
|
|
195
|
+
feePayerOverride
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
if (evaluateErrorCode || evaluateError) {
|
|
199
|
+
throw new Error(evaluateErrorCode || evaluateError)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return { success: true, error: null, phase: null, nodesToReselect: null }
|
|
203
|
+
} catch (e) {
|
|
204
|
+
const err = e.message
|
|
205
|
+
const log = (err === GetAttestationError.COGNITO_FLOW || err === GetAttestationError.HCAPTCHA) ? logger.info : logger.error
|
|
206
|
+
log(`submitAndEvaluate: failed for userId: [${decodeHashId(encodedUserId)}] challenge-id [${challengeId}] at phase [${phase}] with err: ${err}`)
|
|
207
|
+
return { success: false, error: err, phase, nodesToReselect }
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
*
|
|
213
|
+
* Aggregates attestations from Discovery Nodes and AAO.
|
|
214
|
+
*
|
|
215
|
+
* @typedef {Object} AttestationsReturn
|
|
216
|
+
* @property {Array<AttestationMeta>} discoveryNodeAttestations
|
|
217
|
+
* @property {AttestationMeta} aaoAttestation
|
|
218
|
+
* @property {GetAttestationError} error
|
|
219
|
+
*
|
|
220
|
+
* @param {{
|
|
221
|
+
* challengeId: string,
|
|
222
|
+
* encodedUserId: string,
|
|
223
|
+
* handle: string,
|
|
224
|
+
* specifier: string,
|
|
225
|
+
* oracleEthAddress: string,
|
|
226
|
+
* amount: number,
|
|
227
|
+
* quorumSize: number,
|
|
228
|
+
* AAOEndpoint: string,
|
|
229
|
+
* maxAttempts: number
|
|
230
|
+
* endpoints = null
|
|
231
|
+
* logger: any
|
|
232
|
+
* }} {
|
|
233
|
+
* challengeId,
|
|
234
|
+
* encodedUserId,
|
|
235
|
+
* handle,
|
|
236
|
+
* specifier,
|
|
237
|
+
* oracleEthAddress,
|
|
238
|
+
* amount,
|
|
239
|
+
* quorumSize,
|
|
240
|
+
* AAOEndpoint,
|
|
241
|
+
* maxAttempts
|
|
242
|
+
* endpoints = null,
|
|
243
|
+
* logger
|
|
244
|
+
* }
|
|
245
|
+
* @returns {Promise<AttestationsReturn>}
|
|
246
|
+
* @memberof Rewards
|
|
247
|
+
*/
|
|
248
|
+
async aggregateAttestations ({ challengeId, encodedUserId, handle, specifier, oracleEthAddress, amount, quorumSize, AAOEndpoint, maxAttempts, endpoints = null, logger = console }) {
|
|
249
|
+
this.REQUIRES(Services.DISCOVERY_PROVIDER)
|
|
250
|
+
|
|
251
|
+
if (endpoints) {
|
|
252
|
+
endpoints = sampleSize(endpoints, quorumSize)
|
|
253
|
+
} else {
|
|
254
|
+
// If no endpoints array provided, select here
|
|
255
|
+
endpoints = await this.ServiceProvider.getUniquelyOwnedDiscoveryNodes(quorumSize)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (endpoints.length < quorumSize) {
|
|
259
|
+
logger.error(`Tried to fetch [${quorumSize}] attestations, but only found [${endpoints.length}] registered nodes.`)
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
discoveryNodeAttestations: null,
|
|
263
|
+
aaoAttestation: null,
|
|
264
|
+
error: AggregateAttestationError.INSUFFICIENT_DISCOVERY_NODE_COUNT,
|
|
265
|
+
erroringNodes: null
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// First attempt AAO
|
|
270
|
+
|
|
271
|
+
let aaoAttestation = null
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
const { success, error: aaoAttestationError } = await this.getAAOAttestation({
|
|
275
|
+
challengeId,
|
|
276
|
+
specifier,
|
|
277
|
+
handle,
|
|
278
|
+
amount,
|
|
279
|
+
AAOEndpoint,
|
|
280
|
+
oracleEthAddress
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
if (aaoAttestationError) {
|
|
284
|
+
return {
|
|
285
|
+
discoveryNodeAttestations: null,
|
|
286
|
+
aaoAttestation: null,
|
|
287
|
+
error: aaoAttestationError,
|
|
288
|
+
erroringNodes: null
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
aaoAttestation = success
|
|
292
|
+
} catch (e) {
|
|
293
|
+
const err = e.message
|
|
294
|
+
logger.error(`Failed to aggregate attestations for user [${decodeHashId(encodedUserId)}], challenge-id: [${challengeId}] with err: ${err}`)
|
|
295
|
+
return {
|
|
296
|
+
discoveryNodeAttestations: null,
|
|
297
|
+
aaoAttestation: null,
|
|
298
|
+
error: GetAttestationError.AAO_ATTESTATION_ERROR,
|
|
299
|
+
erroringNodes: null
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Then attempt DNs
|
|
304
|
+
|
|
305
|
+
try {
|
|
306
|
+
const discoveryNodeAttestationResults = await this._getDiscoveryAttestationsWithRetries({
|
|
307
|
+
endpoints,
|
|
308
|
+
challengeId,
|
|
309
|
+
encodedUserId,
|
|
310
|
+
specifier,
|
|
311
|
+
oracleEthAddress,
|
|
312
|
+
logger,
|
|
313
|
+
maxAttempts
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
const discoveryNodeSuccesses = discoveryNodeAttestationResults.map(r => r.success)
|
|
317
|
+
const discoveryNodeErrors = discoveryNodeAttestationResults.map(r => r.error)
|
|
318
|
+
const error = discoveryNodeErrors.find(Boolean)
|
|
319
|
+
if (error) {
|
|
320
|
+
// Propagate out the specific nodes that errored
|
|
321
|
+
const erroringNodes = discoveryNodeAttestationResults.filter(r => r.error).map(r => r.endpoint)
|
|
322
|
+
return {
|
|
323
|
+
discoveryNodeAttestations: null,
|
|
324
|
+
aaoAttestation: null,
|
|
325
|
+
error,
|
|
326
|
+
erroringNodes
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
discoveryNodeAttestations: discoveryNodeSuccesses,
|
|
332
|
+
aaoAttestation,
|
|
333
|
+
error: null,
|
|
334
|
+
erroringNodes: null
|
|
335
|
+
}
|
|
336
|
+
} catch (e) {
|
|
337
|
+
const err = e.message
|
|
338
|
+
logger.error(`Failed to aggregate attestations for user [${decodeHashId(encodedUserId)}], challenge-id: [${challengeId}] with err: ${err}`)
|
|
339
|
+
return {
|
|
340
|
+
discoveryNodeAttestations: null,
|
|
341
|
+
aaoAttestation: null,
|
|
342
|
+
error: GetAttestationError.DISCOVERY_NODE_ATTESTATION_ERROR,
|
|
343
|
+
erroringNodes: null
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
*
|
|
350
|
+
* Retrieves a Discovery Node attestation for a given userId.
|
|
351
|
+
*
|
|
352
|
+
* @typedef {Object} GetAttestationReturn
|
|
353
|
+
* @property {AttestationMeta} success
|
|
354
|
+
* @property {GetAttestationError} error
|
|
355
|
+
*
|
|
356
|
+
* @param {{
|
|
357
|
+
* challengeId: string,
|
|
358
|
+
* encodedUserId: string,
|
|
359
|
+
* specifier: string,
|
|
360
|
+
* oracleEthAddress: string,
|
|
361
|
+
* discoveryProviderEndpoint: string
|
|
362
|
+
* logger: any
|
|
363
|
+
* }} {
|
|
364
|
+
* challengeId,
|
|
365
|
+
* encodedUserId,
|
|
366
|
+
* specifier,
|
|
367
|
+
* oracleEthAddress,
|
|
368
|
+
* discoveryProviderEndpoint
|
|
369
|
+
* logger
|
|
370
|
+
* }
|
|
371
|
+
* @returns {Promise<GetAttestationReturn>}
|
|
372
|
+
* @memberof Challenge
|
|
373
|
+
*/
|
|
374
|
+
async getChallengeAttestation ({ challengeId, encodedUserId, specifier, oracleEthAddress, discoveryProviderEndpoint, logger = console }) {
|
|
375
|
+
this.REQUIRES(Services.DISCOVERY_PROVIDER)
|
|
376
|
+
try {
|
|
377
|
+
const res = await this.discoveryProvider.getChallengeAttestation(
|
|
378
|
+
challengeId,
|
|
379
|
+
encodedUserId,
|
|
380
|
+
specifier,
|
|
381
|
+
oracleEthAddress,
|
|
382
|
+
discoveryProviderEndpoint
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
const meta = {
|
|
386
|
+
ethAddress: res.owner_wallet,
|
|
387
|
+
signature: res.attestation
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return { success: meta, error: null }
|
|
391
|
+
} catch (e) {
|
|
392
|
+
const err = e.message
|
|
393
|
+
logger.error(`Failed to get challenge attestation for userId [${decodeHashId(encodedUserId)}] challengeId [${challengeId}]from ${discoveryProviderEndpoint} with ${err}`)
|
|
394
|
+
const mappedErr = GetAttestationError[err] || GetAttestationError.DISCOVERY_NODE_UNKNOWN_RESPONSE
|
|
395
|
+
return {
|
|
396
|
+
success: null,
|
|
397
|
+
error: mappedErr
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
async getUndisbursedChallenges ({ limit, offset, completedBlockNumber, encodedUserId, logger = console } = { logger: console }) {
|
|
403
|
+
this.REQUIRES(Services.DISCOVERY_PROVIDER)
|
|
404
|
+
try {
|
|
405
|
+
const res = await this.discoveryProvider.getUndisbursedChallenges(
|
|
406
|
+
limit,
|
|
407
|
+
offset,
|
|
408
|
+
completedBlockNumber,
|
|
409
|
+
encodedUserId
|
|
410
|
+
)
|
|
411
|
+
return { success: res, error: null }
|
|
412
|
+
} catch (e) {
|
|
413
|
+
const error = e.message
|
|
414
|
+
logger.error(`Failed to get undisbursed challenges with error: ${error}`)
|
|
415
|
+
return {
|
|
416
|
+
success: null,
|
|
417
|
+
error
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
*
|
|
424
|
+
* Retrieves an AAO attestation for a given user handle.
|
|
425
|
+
*
|
|
426
|
+
* @typedef {Object} GetAAOAttestationReturn
|
|
427
|
+
* @property {AttestationMeta} success
|
|
428
|
+
* @property {GetAttestationError} error
|
|
429
|
+
*
|
|
430
|
+
* @param {{
|
|
431
|
+
* challengeId: string,
|
|
432
|
+
* specifier: string,
|
|
433
|
+
* handle: string,
|
|
434
|
+
* amount: number,
|
|
435
|
+
* AAOEndpoint: string,
|
|
436
|
+
* oracleEthAddress: string
|
|
437
|
+
* logger: any
|
|
438
|
+
* }} {
|
|
439
|
+
* challengeId,
|
|
440
|
+
* specifier,
|
|
441
|
+
* handle,
|
|
442
|
+
* amount,
|
|
443
|
+
* AAOEndpoint,
|
|
444
|
+
* oracleEthAddress,
|
|
445
|
+
* logger
|
|
446
|
+
* }
|
|
447
|
+
* @returns {Promise<GetAAOAttestationReturn>}
|
|
448
|
+
* @memberof Challenge
|
|
449
|
+
*/
|
|
450
|
+
async getAAOAttestation ({ challengeId, specifier, handle, amount, AAOEndpoint, oracleEthAddress, logger = console }) {
|
|
451
|
+
const data = {
|
|
452
|
+
challengeId,
|
|
453
|
+
challengeSpecifier: specifier,
|
|
454
|
+
amount
|
|
455
|
+
}
|
|
456
|
+
const request = {
|
|
457
|
+
method: 'post',
|
|
458
|
+
headers: {
|
|
459
|
+
'Content-Type': 'application/json'
|
|
460
|
+
},
|
|
461
|
+
url: `${AAOEndpoint}/attestation/${handle}`,
|
|
462
|
+
timeout: AAO_REQUEST_TIMEOUT_MS,
|
|
463
|
+
data
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
try {
|
|
467
|
+
const response = await axios(request)
|
|
468
|
+
// if attestation is successful, 'result' represents a signature
|
|
469
|
+
// otherwise, 'result' is false
|
|
470
|
+
// - there may or may not be a value for `needs` if the attestation fails
|
|
471
|
+
// - depending on whether the user can take an action to attempt remediation
|
|
472
|
+
const { result, needs } = response.data
|
|
473
|
+
|
|
474
|
+
if (!result) {
|
|
475
|
+
logger.error(`Failed to get AAO attestation${needs ? `: needs ${needs}` : ''}`)
|
|
476
|
+
const mappedErr = needs
|
|
477
|
+
? GetAttestationError[needs] || GetAttestationError.AAO_ATTESTATION_UNKNOWN_RESPONSE
|
|
478
|
+
: GetAttestationError.AAO_ATTESTATION_REJECTION
|
|
479
|
+
return {
|
|
480
|
+
success: null,
|
|
481
|
+
error: mappedErr
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return {
|
|
486
|
+
success: {
|
|
487
|
+
signature: result,
|
|
488
|
+
ethAddress: oracleEthAddress
|
|
489
|
+
},
|
|
490
|
+
error: null
|
|
491
|
+
}
|
|
492
|
+
} catch (e) {
|
|
493
|
+
const err = e.message
|
|
494
|
+
logger.error(`Failed to get AAO attestation: ${err}`)
|
|
495
|
+
return {
|
|
496
|
+
success: null,
|
|
497
|
+
error: GetAttestationError.AAO_ATTESTATION_ERROR
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
async _getDiscoveryAttestationsWithRetries ({
|
|
503
|
+
endpoints,
|
|
504
|
+
challengeId,
|
|
505
|
+
encodedUserId,
|
|
506
|
+
specifier,
|
|
507
|
+
oracleEthAddress,
|
|
508
|
+
logger,
|
|
509
|
+
maxAttempts
|
|
510
|
+
}) {
|
|
511
|
+
let retryCount = 0
|
|
512
|
+
let unrecoverableError = false
|
|
513
|
+
const completedAttestations = []
|
|
514
|
+
let needsAttestations = endpoints
|
|
515
|
+
|
|
516
|
+
do {
|
|
517
|
+
logger.info(`Aggregating attestations with retries challenge: ${challengeId}, userId: ${encodedUserId}, endpoints: ${needsAttestations}, attempt ${retryCount}`)
|
|
518
|
+
if (retryCount > 0) {
|
|
519
|
+
await (new Promise(resolve => setTimeout(resolve, 2000)))
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const attestations = await Promise.all(needsAttestations.map(async endpoint => {
|
|
523
|
+
const res = await this.getChallengeAttestation({
|
|
524
|
+
challengeId,
|
|
525
|
+
encodedUserId,
|
|
526
|
+
specifier,
|
|
527
|
+
oracleEthAddress,
|
|
528
|
+
discoveryProviderEndpoint: endpoint,
|
|
529
|
+
logger
|
|
530
|
+
})
|
|
531
|
+
return { endpoint, res }
|
|
532
|
+
}))
|
|
533
|
+
|
|
534
|
+
needsAttestations = []
|
|
535
|
+
attestations.forEach(a => {
|
|
536
|
+
// If it's a retryable error
|
|
537
|
+
const isRetryable = a.res.error === GetAttestationError.CHALLENGE_INCOMPLETE ||
|
|
538
|
+
a.res.error === GetAttestationError.MISSING_CHALLENGES
|
|
539
|
+
|
|
540
|
+
if (isRetryable) {
|
|
541
|
+
needsAttestations.push(a.endpoint)
|
|
542
|
+
logger.info(`Node ${a.endpoint} challenge still incomplete for challenge [${challengeId}], userId: ${encodedUserId}`)
|
|
543
|
+
// If final attempt, make sure we return the result
|
|
544
|
+
if (retryCount === maxAttempts) {
|
|
545
|
+
completedAttestations.push({ ...a.res, endpoint: a.endpoint })
|
|
546
|
+
}
|
|
547
|
+
} else {
|
|
548
|
+
completedAttestations.push({ ...a.res, endpoint: a.endpoint })
|
|
549
|
+
if (a.res.error) {
|
|
550
|
+
unrecoverableError = true
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
retryCount++
|
|
556
|
+
}
|
|
557
|
+
while (needsAttestations.length && retryCount <= maxAttempts)
|
|
558
|
+
|
|
559
|
+
if (needsAttestations.length || unrecoverableError) {
|
|
560
|
+
logger.info(`Failed to aggregate attestations for challenge [${challengeId}], userId: [${decodeHashId(encodedUserId)}]`)
|
|
561
|
+
} else {
|
|
562
|
+
logger.info(`Successfully aggregated attestations for challenge [${challengeId}], userId: [${decodeHashId(encodedUserId)}]`)
|
|
563
|
+
}
|
|
564
|
+
return completedAttestations
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
*
|
|
569
|
+
* Creates a new discovery node sender for rewards. A sender may
|
|
570
|
+
* attest in user challenge completion to issue rewards.
|
|
571
|
+
*
|
|
572
|
+
* This method queries other discovery nodes asking for attestation of
|
|
573
|
+
* a given new senderEthAddress (delegate wallet) and operatorEthAddress (owner wallet).
|
|
574
|
+
* Those attestations are bundled
|
|
575
|
+
*
|
|
576
|
+
* @param {{
|
|
577
|
+
* senderEthAddress: string
|
|
578
|
+
* operatorEthAddress: string
|
|
579
|
+
* senderEndpoint: string
|
|
580
|
+
* endpoints?: string[]
|
|
581
|
+
* numAttestations?: number
|
|
582
|
+
* feePayerOverride?: string
|
|
583
|
+
* }} {
|
|
584
|
+
* senderEthAddress: the new sender eth address to add. The delegate wallet.
|
|
585
|
+
* operatorEthAddress: the unique address of the operator that runs this service
|
|
586
|
+
* senderEndpoint: the new sender's service endpoint
|
|
587
|
+
* endpoints: optional endpoints from other nodes. If not provided, nodes are selected from chain.
|
|
588
|
+
* numAttestations: optional number of attestations to get from other nodes, default 3
|
|
589
|
+
* feePayerOverride: optional override feepayer
|
|
590
|
+
* }
|
|
591
|
+
* @memberof Rewards
|
|
592
|
+
*/
|
|
593
|
+
async createSenderPublic ({
|
|
594
|
+
senderEthAddress,
|
|
595
|
+
operatorEthAddress,
|
|
596
|
+
senderEndpoint,
|
|
597
|
+
endpoints,
|
|
598
|
+
numAttestations = 3,
|
|
599
|
+
feePayerOverride
|
|
600
|
+
}) {
|
|
601
|
+
let attestEndpoints
|
|
602
|
+
if (endpoints) {
|
|
603
|
+
attestEndpoints = sampleSize(endpoints, numAttestations)
|
|
604
|
+
} else {
|
|
605
|
+
attestEndpoints = await this.ServiceProvider.getUniquelyOwnedDiscoveryNodes(numAttestations, [], async (node) => {
|
|
606
|
+
const isRegistered = await this.solanaWeb3Manager.getIsDiscoveryNodeRegistered(node.delegateOwnerWallet)
|
|
607
|
+
return isRegistered
|
|
608
|
+
})
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
if (attestEndpoints.length < numAttestations) {
|
|
612
|
+
throw new Error(`Not enough other nodes found, need ${numAttestations}, found ${attestEndpoints.length}`)
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
let error = null
|
|
616
|
+
const attestations = await Promise.all(attestEndpoints.map(async attestEndpoint => {
|
|
617
|
+
try {
|
|
618
|
+
const res = await this.discoveryProvider.getCreateSenderAttestation(
|
|
619
|
+
senderEthAddress,
|
|
620
|
+
attestEndpoint
|
|
621
|
+
)
|
|
622
|
+
return {
|
|
623
|
+
ethAddress: res.owner_wallet,
|
|
624
|
+
signature: res.attestation
|
|
625
|
+
}
|
|
626
|
+
} catch (e) {
|
|
627
|
+
console.error(e)
|
|
628
|
+
error = true
|
|
629
|
+
}
|
|
630
|
+
}))
|
|
631
|
+
if (error) {
|
|
632
|
+
console.error(`Failed to get attestations from other nodes ${attestEndpoints}`)
|
|
633
|
+
return {
|
|
634
|
+
success: null,
|
|
635
|
+
error: GetSenderAttestationError.REQUEST_FOR_ATTESTATION_FAILED
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Register the server as a sender on the rewards manager
|
|
640
|
+
const receipt = await this.solanaWeb3Manager.createSender({
|
|
641
|
+
senderEthAddress,
|
|
642
|
+
operatorEthAddress,
|
|
643
|
+
attestations,
|
|
644
|
+
feePayerOverride
|
|
645
|
+
})
|
|
646
|
+
return receipt
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Logs results of an attestation to identity.
|
|
651
|
+
*
|
|
652
|
+
* @param {{
|
|
653
|
+
* status: string,
|
|
654
|
+
* userId: string,
|
|
655
|
+
* challengeId: string,
|
|
656
|
+
* amount: number,
|
|
657
|
+
* source: string
|
|
658
|
+
* specifier: string
|
|
659
|
+
* error?: string,
|
|
660
|
+
* phase?: string,
|
|
661
|
+
* reason?: string
|
|
662
|
+
* }} { status, userId, challengeId, amount, error, phase, specifier, reason }
|
|
663
|
+
* @memberof IdentityService
|
|
664
|
+
*/
|
|
665
|
+
async sendAttestationResult ({ status, userId, challengeId, amount, error, phase, source, specifier, reason }) {
|
|
666
|
+
await this.identityService.sendAttestationResult({
|
|
667
|
+
status,
|
|
668
|
+
userId,
|
|
669
|
+
challengeId,
|
|
670
|
+
amount,
|
|
671
|
+
error,
|
|
672
|
+
phase,
|
|
673
|
+
source,
|
|
674
|
+
specifier,
|
|
675
|
+
reason
|
|
676
|
+
})
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
module.exports = Rewards
|
|
681
|
+
module.exports.SubmitAndEvaluateError = SubmitAndEvaluateError
|
|
682
|
+
module.exports.AttestationPhases = AttestationPhases
|