@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,941 @@
|
|
|
1
|
+
const { TOKEN_PROGRAM_ID } = require('@solana/spl-token')
|
|
2
|
+
const {
|
|
3
|
+
Secp256k1Program,
|
|
4
|
+
SystemProgram,
|
|
5
|
+
SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
6
|
+
SYSVAR_RENT_PUBKEY,
|
|
7
|
+
TransactionInstruction
|
|
8
|
+
} = require('@solana/web3.js')
|
|
9
|
+
const borsh = require('borsh')
|
|
10
|
+
const { getBankAccountAddress } = require('./userBank')
|
|
11
|
+
const BN = require('bn.js')
|
|
12
|
+
const SolanaUtils = require('./utils')
|
|
13
|
+
const { RewardsManagerError } = require('./errors')
|
|
14
|
+
|
|
15
|
+
// Various prefixes used for rewards
|
|
16
|
+
const SENDER_SEED_PREFIX = 'S_'
|
|
17
|
+
const VERIFY_TRANSFER_SEED_PREFIX = 'V_'
|
|
18
|
+
const TRANSFER_PREFIX = 'T_'
|
|
19
|
+
const ADD_SENDER_MESSAGE_PREFIX = 'add'
|
|
20
|
+
|
|
21
|
+
// Enum cases for instructions
|
|
22
|
+
const CREATE_SENDER_PUBLIC_ENUM_VALUE = 4
|
|
23
|
+
const SUBMIT_INSTRUCTION_ENUM_VALUE = 6
|
|
24
|
+
const EVALUATE_INSTRUCTION_ENUM_VALUE = 7
|
|
25
|
+
|
|
26
|
+
const ATTESTATION_INSTRUCTIONS_PER_TRANSACTION = 4
|
|
27
|
+
|
|
28
|
+
const encoder = new TextEncoder()
|
|
29
|
+
|
|
30
|
+
class SubmitAttestationInstructionData {
|
|
31
|
+
/**
|
|
32
|
+
* Creates an instance of SubmitAttestationInstructionData.
|
|
33
|
+
* @param {{transferId: string}} {
|
|
34
|
+
* transferId
|
|
35
|
+
* }
|
|
36
|
+
* @memberof SubmitAttestationInstructionData
|
|
37
|
+
*/
|
|
38
|
+
constructor ({ transferId }) {
|
|
39
|
+
this.id = transferId
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const submitAttestationInstructionSchema = new Map([
|
|
44
|
+
[
|
|
45
|
+
SubmitAttestationInstructionData,
|
|
46
|
+
{
|
|
47
|
+
kind: 'struct',
|
|
48
|
+
fields: [['id', 'string']]
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
])
|
|
52
|
+
|
|
53
|
+
class ValidateAttestationsInstructionData {
|
|
54
|
+
/**
|
|
55
|
+
* Creates an instance of ValidateAttestationsInstructionData.
|
|
56
|
+
* @param {{
|
|
57
|
+
* amount: number,
|
|
58
|
+
* id: string,
|
|
59
|
+
* ethRecipient: Uint8Array
|
|
60
|
+
* }} {
|
|
61
|
+
* amount,
|
|
62
|
+
* id,
|
|
63
|
+
* ethRecipient
|
|
64
|
+
* }
|
|
65
|
+
* @memberof ValidateAttestationsInstructionData
|
|
66
|
+
*/
|
|
67
|
+
constructor ({ amount, id, ethRecipient }) {
|
|
68
|
+
this.amount = amount
|
|
69
|
+
this.id = id
|
|
70
|
+
this.eth_recipient = ethRecipient
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const validateAttestationsInstructionSchema = new Map([
|
|
75
|
+
[
|
|
76
|
+
ValidateAttestationsInstructionData,
|
|
77
|
+
{
|
|
78
|
+
kind: 'struct',
|
|
79
|
+
fields: [
|
|
80
|
+
['amount', 'u64'],
|
|
81
|
+
['id', 'string'],
|
|
82
|
+
['eth_recipient', [20]]
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
])
|
|
87
|
+
|
|
88
|
+
class CreateSenderPublicInstructionData {
|
|
89
|
+
/**
|
|
90
|
+
* Creates an instance of CreateSenderPublicInstructionData
|
|
91
|
+
* @param {{
|
|
92
|
+
* ethAddress: Uint8Array
|
|
93
|
+
* operator: Uint8Array
|
|
94
|
+
* }} {
|
|
95
|
+
* ethAddress,
|
|
96
|
+
* operator
|
|
97
|
+
* }
|
|
98
|
+
*/
|
|
99
|
+
constructor ({
|
|
100
|
+
ethAddress,
|
|
101
|
+
operator
|
|
102
|
+
}) {
|
|
103
|
+
this.eth_address = ethAddress
|
|
104
|
+
this.operator = operator
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const createSenderPublicInstructionSchema = new Map(
|
|
109
|
+
[
|
|
110
|
+
[
|
|
111
|
+
CreateSenderPublicInstructionData,
|
|
112
|
+
{
|
|
113
|
+
kind: 'struct',
|
|
114
|
+
fields: [
|
|
115
|
+
['eth_address', [20]],
|
|
116
|
+
['operator', [20]]
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
]
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @typedef {Object} AttestationMeta
|
|
125
|
+
* @property {string} ethAddress
|
|
126
|
+
* @property {string} signature
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Submits attestations from Discovery Nodes and AAO that a user has completed a challenge.
|
|
131
|
+
*
|
|
132
|
+
*
|
|
133
|
+
* @param {{
|
|
134
|
+
* rewardManagerProgramId: PublicKey,
|
|
135
|
+
* rewardManagerAccount: PublicKey,
|
|
136
|
+
* attestations: AttestationMeta[]
|
|
137
|
+
* oracleAttestation: AttestationMeta
|
|
138
|
+
* challengeId: string,
|
|
139
|
+
* specifier: string,
|
|
140
|
+
* feePayer: PublicKey,
|
|
141
|
+
* attestationSignature: string,
|
|
142
|
+
* recipientEthAddress: string,
|
|
143
|
+
* tokenAmount: BN,
|
|
144
|
+
* transactionHandler: TransactionHandler,
|
|
145
|
+
* instructionsPerTransaction?: number,
|
|
146
|
+
* logger: any
|
|
147
|
+
* }} {
|
|
148
|
+
* rewardManagerProgramId,
|
|
149
|
+
* rewardManagerAccount,
|
|
150
|
+
* attestations,
|
|
151
|
+
* oracleAttestation,
|
|
152
|
+
* challengeId,
|
|
153
|
+
* specifier,
|
|
154
|
+
* feePayer,
|
|
155
|
+
* recipientEthAddress,
|
|
156
|
+
* tokenAmount,
|
|
157
|
+
* transactionHandler,
|
|
158
|
+
* instructionsPerTransaction,
|
|
159
|
+
* logger
|
|
160
|
+
* }
|
|
161
|
+
*/
|
|
162
|
+
async function submitAttestations ({
|
|
163
|
+
rewardManagerProgramId,
|
|
164
|
+
rewardManagerAccount,
|
|
165
|
+
attestations,
|
|
166
|
+
oracleAttestation,
|
|
167
|
+
challengeId,
|
|
168
|
+
specifier,
|
|
169
|
+
feePayer,
|
|
170
|
+
recipientEthAddress,
|
|
171
|
+
tokenAmount,
|
|
172
|
+
transactionHandler,
|
|
173
|
+
instructionsPerTransaction = ATTESTATION_INSTRUCTIONS_PER_TRANSACTION,
|
|
174
|
+
logger = console
|
|
175
|
+
}) {
|
|
176
|
+
// Construct combined transfer ID
|
|
177
|
+
const transferId = SolanaUtils.constructTransferId(challengeId, specifier)
|
|
178
|
+
|
|
179
|
+
// Derive the message account we'll use to store the attestations
|
|
180
|
+
const [
|
|
181
|
+
rewardManagerAuthority,
|
|
182
|
+
derivedMessageAccount
|
|
183
|
+
] = await deriveMessageAccount(
|
|
184
|
+
transferId,
|
|
185
|
+
rewardManagerProgramId,
|
|
186
|
+
rewardManagerAccount
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
const encodedSenderMessage = SolanaUtils.constructAttestation(
|
|
190
|
+
recipientEthAddress,
|
|
191
|
+
tokenAmount,
|
|
192
|
+
transferId,
|
|
193
|
+
oracleAttestation.ethAddress
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
// Add instructions from DN attestations - each attestation
|
|
197
|
+
// needs a pairing of SECP recovery instruction and submit
|
|
198
|
+
// attestation instruction.
|
|
199
|
+
let instructions = await Promise.all(
|
|
200
|
+
attestations.reduce((instructions, meta, i) => {
|
|
201
|
+
const secpInstruction = Promise.resolve(
|
|
202
|
+
generateAttestationSecpInstruction({
|
|
203
|
+
attestationMeta: meta,
|
|
204
|
+
recipientEthAddress,
|
|
205
|
+
tokenAmount,
|
|
206
|
+
transferId,
|
|
207
|
+
instructionIndex: (2 * i) % instructionsPerTransaction,
|
|
208
|
+
encodedSenderMessage
|
|
209
|
+
})
|
|
210
|
+
)
|
|
211
|
+
const verifyInstruction = generateSubmitAttestationInstruction({
|
|
212
|
+
attestationMeta: meta,
|
|
213
|
+
derivedMessageAccount,
|
|
214
|
+
rewardManagerAccount,
|
|
215
|
+
rewardManagerProgramId,
|
|
216
|
+
rewardManagerAuthority,
|
|
217
|
+
transferId,
|
|
218
|
+
feePayer
|
|
219
|
+
})
|
|
220
|
+
return [...instructions, secpInstruction, verifyInstruction]
|
|
221
|
+
}, [])
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
const encodedOracleMessage = SolanaUtils.constructAttestation(
|
|
225
|
+
recipientEthAddress,
|
|
226
|
+
tokenAmount,
|
|
227
|
+
transferId
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
// Add instructions from oracle attestation
|
|
231
|
+
const oracleSecp = await generateAttestationSecpInstruction({
|
|
232
|
+
attestationMeta: oracleAttestation,
|
|
233
|
+
recipientEthAddress,
|
|
234
|
+
instructionIndex: instructions.length % instructionsPerTransaction,
|
|
235
|
+
tokenAmount,
|
|
236
|
+
transferId,
|
|
237
|
+
encodedSenderMessage: encodedOracleMessage
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
const oracleTransfer = await generateSubmitAttestationInstruction({
|
|
241
|
+
attestationMeta: oracleAttestation,
|
|
242
|
+
derivedMessageAccount,
|
|
243
|
+
rewardManagerAccount,
|
|
244
|
+
rewardManagerProgramId,
|
|
245
|
+
rewardManagerAuthority,
|
|
246
|
+
transferId,
|
|
247
|
+
feePayer
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
// Break the instructions up into multiple transactions as per `instructionsPerTransaction`
|
|
251
|
+
instructions = [...instructions, oracleSecp, oracleTransfer]
|
|
252
|
+
const bucketedInstructions = instructions.reduce((acc, cur) => {
|
|
253
|
+
if (acc[acc.length - 1].length < instructionsPerTransaction) {
|
|
254
|
+
acc[acc.length - 1].push(cur)
|
|
255
|
+
} else {
|
|
256
|
+
acc.push([cur])
|
|
257
|
+
}
|
|
258
|
+
return acc
|
|
259
|
+
}, [[]])
|
|
260
|
+
|
|
261
|
+
const results = await Promise.all(bucketedInstructions.map(i => transactionHandler.handleTransaction({
|
|
262
|
+
instructions: i,
|
|
263
|
+
errorMapping: RewardsManagerError,
|
|
264
|
+
logger,
|
|
265
|
+
skipPreflight: false,
|
|
266
|
+
feePayerOverride: feePayer,
|
|
267
|
+
sendBlockhash: false
|
|
268
|
+
})))
|
|
269
|
+
logger.info(`submitAttestations: submitted attestations with results: ${JSON.stringify(results)}`)
|
|
270
|
+
|
|
271
|
+
// If there's any error in any of the transactions, just return that one
|
|
272
|
+
for (const res of results) {
|
|
273
|
+
if (res.error || res.errorCode) {
|
|
274
|
+
return res
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return results[0]
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Creates a new rewards signer (one that can attest)
|
|
282
|
+
*
|
|
283
|
+
* @param {{
|
|
284
|
+
* rewardManagerProgramId: PublicKey,
|
|
285
|
+
* rewardManagerAccount: PublicKey,
|
|
286
|
+
* senderEthAddress: string,
|
|
287
|
+
* feePayer: PublicKey,
|
|
288
|
+
* operatorEthAddress: string,
|
|
289
|
+
* attestations: AttestationMeta[],
|
|
290
|
+
* identityService: any
|
|
291
|
+
* connection: Connection
|
|
292
|
+
* }} {
|
|
293
|
+
* rewardManagerProgramId,
|
|
294
|
+
* rewardManagerAccount,
|
|
295
|
+
* senderEthAddress,
|
|
296
|
+
* feePayer,
|
|
297
|
+
* operatorEthAddress,
|
|
298
|
+
* attestations,
|
|
299
|
+
* identityService,
|
|
300
|
+
* connection
|
|
301
|
+
* }
|
|
302
|
+
*/
|
|
303
|
+
async function createSender ({
|
|
304
|
+
rewardManagerProgramId,
|
|
305
|
+
rewardManagerAccount,
|
|
306
|
+
senderEthAddress,
|
|
307
|
+
feePayer,
|
|
308
|
+
operatorEthAddress,
|
|
309
|
+
attestations,
|
|
310
|
+
transactionHandler
|
|
311
|
+
}) {
|
|
312
|
+
const [rewardManagerAuthority] = await SolanaUtils.findProgramAddressFromPubkey(
|
|
313
|
+
rewardManagerProgramId,
|
|
314
|
+
rewardManagerAccount
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
const encodedSenderMessage = constructCreateSenderMessage(
|
|
318
|
+
senderEthAddress,
|
|
319
|
+
rewardManagerAccount
|
|
320
|
+
)
|
|
321
|
+
const signerEthAddresses = attestations.map(meta => meta.ethAddress)
|
|
322
|
+
const signerInstructions = attestations.map((meta, i) => {
|
|
323
|
+
return generateCreateSenderSecpInstruction({
|
|
324
|
+
ethAddress: senderEthAddress,
|
|
325
|
+
attestationMeta: meta,
|
|
326
|
+
instructionIndex: i,
|
|
327
|
+
encodedSenderMessage
|
|
328
|
+
})
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
const createSenderInstruction = await generateCreateSenderInstruction({
|
|
332
|
+
senderEthAddress,
|
|
333
|
+
operatorEthAddress,
|
|
334
|
+
rewardManagerAccount,
|
|
335
|
+
rewardManagerAuthority,
|
|
336
|
+
rewardManagerProgramId,
|
|
337
|
+
feePayer,
|
|
338
|
+
signerEthAddresses
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
const instructions = [...signerInstructions, createSenderInstruction]
|
|
342
|
+
return transactionHandler.handleTransaction({ instructions, errorMapping: RewardsManagerError, feePayerOverride: feePayer })
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Evaluates previously submitted attestations, disbursing if successful.
|
|
347
|
+
*
|
|
348
|
+
* @param {{
|
|
349
|
+
* rewardManagerProgramId: PublicKey
|
|
350
|
+
* rewardManagerAccount: PublicKey
|
|
351
|
+
* rewardManagerTokenSource: PublicKey
|
|
352
|
+
* challengeId: string
|
|
353
|
+
* specifier: string
|
|
354
|
+
* recipientEthAddress: string
|
|
355
|
+
* userBankProgramAccount: PublicKey,
|
|
356
|
+
* oracleEthAddress: string
|
|
357
|
+
* feePayer: PublicKey
|
|
358
|
+
* tokenAmount: BN
|
|
359
|
+
* tokenAmount: BN,
|
|
360
|
+
* transactionHandler: TransactionHandler,
|
|
361
|
+
* logger: any
|
|
362
|
+
* }} {
|
|
363
|
+
* rewardManagerProgramId,
|
|
364
|
+
* rewardManagerAccount,
|
|
365
|
+
* rewardManagerTokenSource,
|
|
366
|
+
* challengeId,
|
|
367
|
+
* specifier,
|
|
368
|
+
* recipientEthAddress,
|
|
369
|
+
* userBankProgramAccount,
|
|
370
|
+
* oracleEthAddress,
|
|
371
|
+
* feePayer,
|
|
372
|
+
* tokenAmount,
|
|
373
|
+
* transactionHandler,
|
|
374
|
+
* logger
|
|
375
|
+
* }
|
|
376
|
+
*/
|
|
377
|
+
const evaluateAttestations = async ({
|
|
378
|
+
rewardManagerProgramId,
|
|
379
|
+
rewardManagerAccount,
|
|
380
|
+
rewardManagerTokenSource,
|
|
381
|
+
challengeId,
|
|
382
|
+
specifier,
|
|
383
|
+
recipientEthAddress,
|
|
384
|
+
userBankProgramAccount,
|
|
385
|
+
oracleEthAddress,
|
|
386
|
+
feePayer,
|
|
387
|
+
tokenAmount,
|
|
388
|
+
transactionHandler,
|
|
389
|
+
logger = console
|
|
390
|
+
}) => {
|
|
391
|
+
// Get transfer ID
|
|
392
|
+
const transferId = SolanaUtils.constructTransferId(challengeId, specifier)
|
|
393
|
+
|
|
394
|
+
// Derive the messages account we previously stored attestations in
|
|
395
|
+
const [
|
|
396
|
+
rewardManagerAuthority,
|
|
397
|
+
verifiedMessagesAccount
|
|
398
|
+
] = await deriveMessageAccount(
|
|
399
|
+
transferId,
|
|
400
|
+
rewardManagerProgramId,
|
|
401
|
+
rewardManagerAccount
|
|
402
|
+
)
|
|
403
|
+
// Derive the transfer account we'll use to represent + dedupe
|
|
404
|
+
// the disbursement.
|
|
405
|
+
const transferAccount = await deriveTransferAccount(
|
|
406
|
+
transferId,
|
|
407
|
+
rewardManagerProgramId,
|
|
408
|
+
rewardManagerAccount
|
|
409
|
+
)
|
|
410
|
+
// Derive the recipient's Solana Userbank account
|
|
411
|
+
// from their eth key
|
|
412
|
+
const recipientBankAccount = await getBankAccountAddress(
|
|
413
|
+
recipientEthAddress,
|
|
414
|
+
userBankProgramAccount,
|
|
415
|
+
TOKEN_PROGRAM_ID
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
// Derive the AAO's Solana pubkey from it's eth address
|
|
419
|
+
const derivedAAOAddress = await deriveSolanaSenderFromEthAddress(
|
|
420
|
+
oracleEthAddress,
|
|
421
|
+
rewardManagerProgramId,
|
|
422
|
+
rewardManagerAccount
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
// Construct the requried accounts
|
|
426
|
+
|
|
427
|
+
/// 0. `[]` Verified messages
|
|
428
|
+
/// 1. `[]` Reward manager
|
|
429
|
+
/// 2. `[]` Reward manager authority
|
|
430
|
+
/// 3. `[]` Reward token source
|
|
431
|
+
/// 4. `[]` Reward token recipient
|
|
432
|
+
/// 5. `[]` Transfer account
|
|
433
|
+
/// 6. `[]` Bot oracle
|
|
434
|
+
/// 7. `[]` Payer
|
|
435
|
+
/// 8. `[]` Sysvar rent
|
|
436
|
+
/// 9. `[]` Token program id
|
|
437
|
+
/// 10. `[]` System program id
|
|
438
|
+
const accounts = [
|
|
439
|
+
{
|
|
440
|
+
pubkey: verifiedMessagesAccount,
|
|
441
|
+
isSigner: false,
|
|
442
|
+
isWritable: true
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
pubkey: rewardManagerAccount,
|
|
446
|
+
isSigner: false,
|
|
447
|
+
isWritable: false
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
pubkey: rewardManagerAuthority,
|
|
451
|
+
isSigner: false,
|
|
452
|
+
isWritable: false
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
pubkey: rewardManagerTokenSource,
|
|
456
|
+
isSigner: false,
|
|
457
|
+
isWritable: true
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
pubkey: recipientBankAccount,
|
|
461
|
+
isSigner: false,
|
|
462
|
+
isWritable: true
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
pubkey: transferAccount,
|
|
466
|
+
isSigner: false,
|
|
467
|
+
isWritable: true
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
pubkey: derivedAAOAddress,
|
|
471
|
+
isSigner: false,
|
|
472
|
+
isWritable: false
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
pubkey: feePayer,
|
|
476
|
+
isSigner: true,
|
|
477
|
+
isWritable: true
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
pubkey: SYSVAR_RENT_PUBKEY,
|
|
481
|
+
isSigner: false,
|
|
482
|
+
isWritable: false
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
pubkey: TOKEN_PROGRAM_ID,
|
|
486
|
+
isSigner: false,
|
|
487
|
+
isWritable: false
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
pubkey: SystemProgram.programId,
|
|
491
|
+
isSigner: false,
|
|
492
|
+
isWritable: false
|
|
493
|
+
}
|
|
494
|
+
]
|
|
495
|
+
|
|
496
|
+
// Construct the instruction data
|
|
497
|
+
const instructionData = new ValidateAttestationsInstructionData({
|
|
498
|
+
amount: tokenAmount.toNumber(),
|
|
499
|
+
id: transferId,
|
|
500
|
+
ethRecipient: SolanaUtils.ethAddressToArray(recipientEthAddress)
|
|
501
|
+
})
|
|
502
|
+
const serializedInstructionData = borsh.serialize(
|
|
503
|
+
validateAttestationsInstructionSchema,
|
|
504
|
+
instructionData
|
|
505
|
+
)
|
|
506
|
+
const serializedInstructionEnum = Buffer.from(
|
|
507
|
+
Uint8Array.of(EVALUATE_INSTRUCTION_ENUM_VALUE, ...serializedInstructionData)
|
|
508
|
+
)
|
|
509
|
+
const transferInstruction = new TransactionInstruction({
|
|
510
|
+
keys: accounts,
|
|
511
|
+
programId: rewardManagerProgramId,
|
|
512
|
+
data: serializedInstructionEnum
|
|
513
|
+
})
|
|
514
|
+
|
|
515
|
+
return transactionHandler.handleTransaction({
|
|
516
|
+
instructions: [transferInstruction],
|
|
517
|
+
errorMapping: RewardsManagerError,
|
|
518
|
+
logger,
|
|
519
|
+
skipPreflight: false,
|
|
520
|
+
feePayerOverride: feePayer,
|
|
521
|
+
sendBlockhash: false
|
|
522
|
+
})
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Helpers
|
|
526
|
+
|
|
527
|
+
// Generate particular instructions
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
*
|
|
531
|
+
* Helper function to generate a submit attestation instruction.
|
|
532
|
+
* @param {{
|
|
533
|
+
* attestationMeta: AttestationMeta,
|
|
534
|
+
* derivedMessageAccount: PublicKey
|
|
535
|
+
* rewardManagerAccount: PublicKey
|
|
536
|
+
* rewardManagerAuthority: PublicKey
|
|
537
|
+
* rewardManagerProgramId: PublicKey
|
|
538
|
+
* feePayer: PublicKey
|
|
539
|
+
* transferId: string
|
|
540
|
+
* }} {
|
|
541
|
+
* attestationMeta,
|
|
542
|
+
* derivedMessageAccount,
|
|
543
|
+
* rewardManagerAccount,
|
|
544
|
+
* rewardManagerAuthority,
|
|
545
|
+
* rewardManagerProgramId,
|
|
546
|
+
* feePayer,
|
|
547
|
+
* transferId
|
|
548
|
+
* }
|
|
549
|
+
* @returns {Promise<TransactionInstruction>}
|
|
550
|
+
*/
|
|
551
|
+
const generateSubmitAttestationInstruction = async ({
|
|
552
|
+
attestationMeta,
|
|
553
|
+
derivedMessageAccount,
|
|
554
|
+
rewardManagerAccount,
|
|
555
|
+
rewardManagerAuthority,
|
|
556
|
+
rewardManagerProgramId,
|
|
557
|
+
feePayer,
|
|
558
|
+
transferId
|
|
559
|
+
}) => {
|
|
560
|
+
// Get the DN's derived Solana address from the eth pubkey
|
|
561
|
+
const derivedSender = await deriveSolanaSenderFromEthAddress(
|
|
562
|
+
attestationMeta.ethAddress,
|
|
563
|
+
rewardManagerProgramId,
|
|
564
|
+
rewardManagerAccount
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
/// Submit attestations
|
|
568
|
+
/// 0. `[writable]` Verified messages - New or existing account PDA storing verified messages
|
|
569
|
+
/// 1. `[]` Reward manager
|
|
570
|
+
/// 2. `[]` Reward manager authority
|
|
571
|
+
/// 3. `[signer]` Funder
|
|
572
|
+
/// 4. `[]` Sender
|
|
573
|
+
/// 5. `[]` Sysvar rent
|
|
574
|
+
/// 6. `[]` Instruction info
|
|
575
|
+
/// 7. `[]` System program id
|
|
576
|
+
const verifyInstructionAccounts = [
|
|
577
|
+
{
|
|
578
|
+
pubkey: derivedMessageAccount,
|
|
579
|
+
isSigner: false,
|
|
580
|
+
isWritable: true
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
pubkey: rewardManagerAccount,
|
|
584
|
+
isSigner: false,
|
|
585
|
+
isWritable: false
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
pubkey: rewardManagerAuthority,
|
|
589
|
+
isSigner: false,
|
|
590
|
+
isWritable: false
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
pubkey: feePayer,
|
|
594
|
+
isSigner: true,
|
|
595
|
+
isWritable: true
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
pubkey: derivedSender,
|
|
599
|
+
isSigner: false,
|
|
600
|
+
isWritable: false
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
pubkey: SYSVAR_RENT_PUBKEY,
|
|
604
|
+
isSigner: false,
|
|
605
|
+
isWritable: false
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
pubkey: SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
609
|
+
isSigner: false,
|
|
610
|
+
isWritable: false
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
pubkey: SystemProgram.programId,
|
|
614
|
+
isSigner: false,
|
|
615
|
+
isWritable: false
|
|
616
|
+
}
|
|
617
|
+
]
|
|
618
|
+
|
|
619
|
+
const instructionData = new SubmitAttestationInstructionData({ transferId })
|
|
620
|
+
const serializedInstructionData = borsh.serialize(
|
|
621
|
+
submitAttestationInstructionSchema,
|
|
622
|
+
instructionData
|
|
623
|
+
)
|
|
624
|
+
const serializedInstructionEnum = Buffer.from(
|
|
625
|
+
Uint8Array.of(SUBMIT_INSTRUCTION_ENUM_VALUE, ...serializedInstructionData)
|
|
626
|
+
)
|
|
627
|
+
|
|
628
|
+
return new TransactionInstruction({
|
|
629
|
+
keys: verifyInstructionAccounts,
|
|
630
|
+
programId: rewardManagerProgramId,
|
|
631
|
+
data: serializedInstructionEnum
|
|
632
|
+
})
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Encodes a given signature to a 64 byte array for SECP recovery
|
|
637
|
+
* @param {string} signature
|
|
638
|
+
* @returns {{encodedSignature: string, recoveryId: number}} encodedSignature
|
|
639
|
+
*/
|
|
640
|
+
const encodeSignature = (signature) => {
|
|
641
|
+
// Perform signature manipulations:
|
|
642
|
+
// - remove the 0x prefix for BN
|
|
643
|
+
// - lose the final byte / recovery ID: the secp instruction constructor
|
|
644
|
+
// requires only 'r', 's' from the signature, while 'v', the recovery ID,
|
|
645
|
+
// is passed as a separate argument.
|
|
646
|
+
// https://medium.com/mycrypto/the-magic-of-digital-signatures-on-ethereum-98fe184dc9c7
|
|
647
|
+
//
|
|
648
|
+
let strippedSignature = signature.replace('0x', '')
|
|
649
|
+
const recoveryIdStr = strippedSignature.slice(strippedSignature.length - 2)
|
|
650
|
+
const recoveryId = new BN(recoveryIdStr, 'hex').toNumber()
|
|
651
|
+
strippedSignature = strippedSignature.slice(0, strippedSignature.length - 2)
|
|
652
|
+
// Pad to 64 bytes - otherwise, signatures starting with '0' would result
|
|
653
|
+
// in < 64 byte arrays
|
|
654
|
+
const encodedSignature = Uint8Array.of(
|
|
655
|
+
...new BN(strippedSignature, 'hex').toArray('be', 64)
|
|
656
|
+
)
|
|
657
|
+
return { encodedSignature, recoveryId }
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
*
|
|
662
|
+
* @param {{
|
|
663
|
+
* attestationMeta: AttestationMeta
|
|
664
|
+
* recipientEthAddress: string
|
|
665
|
+
* tokenAmount: BN
|
|
666
|
+
* transferId: string
|
|
667
|
+
* instructionIndex: number
|
|
668
|
+
* encodedSenderMessage: string
|
|
669
|
+
* }} {
|
|
670
|
+
* attestationMeta,
|
|
671
|
+
* recipientEthAddress,
|
|
672
|
+
* tokenAmount,
|
|
673
|
+
* transferId,
|
|
674
|
+
* instructionIndex,
|
|
675
|
+
* encodedSenderMessage
|
|
676
|
+
* }
|
|
677
|
+
* @returns {TransactionInstruction}
|
|
678
|
+
*/
|
|
679
|
+
const generateAttestationSecpInstruction = ({
|
|
680
|
+
attestationMeta,
|
|
681
|
+
recipientEthAddress,
|
|
682
|
+
tokenAmount,
|
|
683
|
+
transferId,
|
|
684
|
+
instructionIndex,
|
|
685
|
+
encodedSenderMessage
|
|
686
|
+
}) => {
|
|
687
|
+
const { encodedSignature, recoveryId } = encodeSignature(attestationMeta.signature)
|
|
688
|
+
|
|
689
|
+
return Secp256k1Program.createInstructionWithEthAddress({
|
|
690
|
+
ethAddress: SolanaUtils.ethAddressToArray(attestationMeta.ethAddress),
|
|
691
|
+
message: encodedSenderMessage,
|
|
692
|
+
signature: encodedSignature,
|
|
693
|
+
recoveryId,
|
|
694
|
+
instructionIndex
|
|
695
|
+
})
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
*
|
|
700
|
+
* @param {{
|
|
701
|
+
* ethAddress: string
|
|
702
|
+
* attestationMeta: AttestationMeta
|
|
703
|
+
* instructionIndex: number
|
|
704
|
+
* encodedSenderMessage: string
|
|
705
|
+
* }} {
|
|
706
|
+
* ethAddress,
|
|
707
|
+
* attestationMeta,
|
|
708
|
+
* instructionIndex,
|
|
709
|
+
* encodedSenderMessage
|
|
710
|
+
* }
|
|
711
|
+
* @returns {TransactionInstruction}
|
|
712
|
+
*/
|
|
713
|
+
const generateCreateSenderSecpInstruction = ({
|
|
714
|
+
ethAddress,
|
|
715
|
+
attestationMeta,
|
|
716
|
+
instructionIndex,
|
|
717
|
+
encodedSenderMessage
|
|
718
|
+
}) => {
|
|
719
|
+
const { encodedSignature, recoveryId } = encodeSignature(attestationMeta.signature)
|
|
720
|
+
return Secp256k1Program.createInstructionWithEthAddress({
|
|
721
|
+
ethAddress: attestationMeta.ethAddress,
|
|
722
|
+
message: encodedSenderMessage,
|
|
723
|
+
signature: encodedSignature,
|
|
724
|
+
recoveryId,
|
|
725
|
+
instructionIndex
|
|
726
|
+
})
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
*
|
|
731
|
+
* Helper function generate a create sender instruction.
|
|
732
|
+
* @param {{
|
|
733
|
+
* senderEthAddress: string,
|
|
734
|
+
* operatorEthAddress: string,
|
|
735
|
+
* rewardManagerAccount: PublicKey,
|
|
736
|
+
* rewardManagerAuthority: PublicKey,
|
|
737
|
+
* rewardManagerProgramId: PublicKey,
|
|
738
|
+
* feePayer: PublicKey,
|
|
739
|
+
* signerEthAddresses: string[]
|
|
740
|
+
* }} {
|
|
741
|
+
* senderEthAddress,
|
|
742
|
+
* operatorEthAddress,
|
|
743
|
+
* rewardManagerAccount,
|
|
744
|
+
* rewardManagerAuthority,
|
|
745
|
+
* rewardManagerProgramId,
|
|
746
|
+
* feePayer,
|
|
747
|
+
* signerEthAddresses
|
|
748
|
+
* }
|
|
749
|
+
* @returns {TransactionInstruction}
|
|
750
|
+
*/
|
|
751
|
+
const generateCreateSenderInstruction = async ({
|
|
752
|
+
senderEthAddress,
|
|
753
|
+
operatorEthAddress,
|
|
754
|
+
rewardManagerAccount,
|
|
755
|
+
rewardManagerAuthority,
|
|
756
|
+
rewardManagerProgramId,
|
|
757
|
+
feePayer,
|
|
758
|
+
signerEthAddresses
|
|
759
|
+
}) => {
|
|
760
|
+
// Get the DN's derived Solana address from the eth pubkey
|
|
761
|
+
const derivedSenderSolanaAddress = await deriveSolanaSenderFromEthAddress(
|
|
762
|
+
senderEthAddress,
|
|
763
|
+
rewardManagerProgramId,
|
|
764
|
+
rewardManagerAccount
|
|
765
|
+
)
|
|
766
|
+
|
|
767
|
+
const signerSolanaPubKeys = await Promise.all(signerEthAddresses.map(async signerEthAddress =>
|
|
768
|
+
deriveSolanaSenderFromEthAddress(
|
|
769
|
+
signerEthAddress,
|
|
770
|
+
rewardManagerProgramId,
|
|
771
|
+
rewardManagerAccount
|
|
772
|
+
)
|
|
773
|
+
))
|
|
774
|
+
|
|
775
|
+
/// 0. `[]` Reward manager
|
|
776
|
+
/// 1. `[]` Reward manager authority
|
|
777
|
+
/// 2. `[signer]` Funder
|
|
778
|
+
/// 3. `[writable]` new_sender
|
|
779
|
+
/// 4. `[]` Bunch of senders which prove creating another one
|
|
780
|
+
const createSenderInstructionAccounts = [
|
|
781
|
+
{
|
|
782
|
+
pubkey: rewardManagerAccount,
|
|
783
|
+
isSigner: false,
|
|
784
|
+
isWritable: false
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
pubkey: rewardManagerAuthority,
|
|
788
|
+
isSigner: false,
|
|
789
|
+
isWritable: false
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
pubkey: feePayer,
|
|
793
|
+
isSigner: true,
|
|
794
|
+
isWritable: true
|
|
795
|
+
},
|
|
796
|
+
{
|
|
797
|
+
pubkey: derivedSenderSolanaAddress,
|
|
798
|
+
isSigner: false,
|
|
799
|
+
isWritable: true
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
pubkey: SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
803
|
+
isSigner: false,
|
|
804
|
+
isWritable: false
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
pubkey: SYSVAR_RENT_PUBKEY,
|
|
808
|
+
isSigner: false,
|
|
809
|
+
isWritable: false
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
pubkey: SystemProgram.programId,
|
|
813
|
+
isSigner: false,
|
|
814
|
+
isWritable: false
|
|
815
|
+
},
|
|
816
|
+
...signerSolanaPubKeys.map(pubkey =>
|
|
817
|
+
({
|
|
818
|
+
pubkey,
|
|
819
|
+
isSigner: false,
|
|
820
|
+
isWritable: false
|
|
821
|
+
})
|
|
822
|
+
)
|
|
823
|
+
]
|
|
824
|
+
|
|
825
|
+
const createSenderPublicInstructionData = new CreateSenderPublicInstructionData({
|
|
826
|
+
ethAddress: SolanaUtils.ethAddressToArray(senderEthAddress),
|
|
827
|
+
operator: SolanaUtils.ethAddressToArray(operatorEthAddress)
|
|
828
|
+
})
|
|
829
|
+
const serializedInstructionData = borsh.serialize(
|
|
830
|
+
createSenderPublicInstructionSchema,
|
|
831
|
+
createSenderPublicInstructionData
|
|
832
|
+
)
|
|
833
|
+
const serializedInstructionEnum = Buffer.from(Uint8Array.of(
|
|
834
|
+
CREATE_SENDER_PUBLIC_ENUM_VALUE,
|
|
835
|
+
...serializedInstructionData
|
|
836
|
+
))
|
|
837
|
+
|
|
838
|
+
return new TransactionInstruction({
|
|
839
|
+
keys: createSenderInstructionAccounts,
|
|
840
|
+
programId: rewardManagerProgramId,
|
|
841
|
+
data: serializedInstructionEnum
|
|
842
|
+
})
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Misc
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Derives the Solana account associated with a given sender Eth address.
|
|
849
|
+
*
|
|
850
|
+
* @param {string} ethAddress
|
|
851
|
+
* @param {PublicKey} rewardManagerProgramId
|
|
852
|
+
* @param {PublicKey} rewardManagerAccount
|
|
853
|
+
* @returns {Promise<PublicKey>}
|
|
854
|
+
*/
|
|
855
|
+
const deriveSolanaSenderFromEthAddress = async (
|
|
856
|
+
ethAddress,
|
|
857
|
+
rewardManagerProgramId,
|
|
858
|
+
rewardManagerAccount
|
|
859
|
+
) => {
|
|
860
|
+
const ethAddressArr = SolanaUtils.ethAddressToArray(ethAddress)
|
|
861
|
+
const encodedPrefix = encoder.encode(SENDER_SEED_PREFIX)
|
|
862
|
+
|
|
863
|
+
const [, derivedSender] = await SolanaUtils.findProgramAddressWithAuthority(
|
|
864
|
+
rewardManagerProgramId,
|
|
865
|
+
rewardManagerAccount,
|
|
866
|
+
new Uint8Array([...encodedPrefix, ...ethAddressArr])
|
|
867
|
+
)
|
|
868
|
+
return derivedSender
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
/**
|
|
872
|
+
* Constructs a create signer message for an existing "signer" eth address
|
|
873
|
+
* @param {string} ethAddress
|
|
874
|
+
* @returns {Uint8Array}
|
|
875
|
+
*/
|
|
876
|
+
const constructCreateSenderMessage = (
|
|
877
|
+
ethAddress,
|
|
878
|
+
rewardManagerAccount
|
|
879
|
+
) => {
|
|
880
|
+
const encodedPrefix = encoder.encode(ADD_SENDER_MESSAGE_PREFIX)
|
|
881
|
+
const ethAddressArr = SolanaUtils.ethAddressToArray(ethAddress)
|
|
882
|
+
const rewardManagerAccountArr = rewardManagerAccount.toBytes()
|
|
883
|
+
|
|
884
|
+
const items = [encodedPrefix, rewardManagerAccountArr, ethAddressArr]
|
|
885
|
+
const res = items.slice(1).reduce((prev, cur, i) => {
|
|
886
|
+
return Uint8Array.of(...prev, ...cur)
|
|
887
|
+
}, Uint8Array.from(items[0]))
|
|
888
|
+
return res
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Derives the 'transfer account' - the account which represents a single successful disbursement
|
|
893
|
+
* and is used to dedupe - from the transferId and other info
|
|
894
|
+
*
|
|
895
|
+
* @param {string} transferId
|
|
896
|
+
* @param {PublicKey} rewardProgramId
|
|
897
|
+
* @param {PublicKey} rewardManager
|
|
898
|
+
* @returns {Promise<PublicKey>}
|
|
899
|
+
*/
|
|
900
|
+
const deriveTransferAccount = async (
|
|
901
|
+
transferId,
|
|
902
|
+
rewardProgramId,
|
|
903
|
+
rewardManager
|
|
904
|
+
) => {
|
|
905
|
+
const seed = Uint8Array.from([
|
|
906
|
+
...encoder.encode(TRANSFER_PREFIX),
|
|
907
|
+
...encoder.encode(transferId)
|
|
908
|
+
])
|
|
909
|
+
const [, derivedAddress] = await SolanaUtils.findProgramAddressWithAuthority(
|
|
910
|
+
rewardProgramId,
|
|
911
|
+
rewardManager,
|
|
912
|
+
seed
|
|
913
|
+
)
|
|
914
|
+
return derivedAddress
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
/**
|
|
918
|
+
* Derives the account to store messages for a single challenge
|
|
919
|
+
*
|
|
920
|
+
* @param {string} transferId
|
|
921
|
+
* @param {PublicKey} rewardsProgramId
|
|
922
|
+
* @param {PublicKey} rewardManager
|
|
923
|
+
* @returns {Promise<[PublicKey, PublicKey, number]>}
|
|
924
|
+
*/
|
|
925
|
+
const deriveMessageAccount = async (
|
|
926
|
+
transferId,
|
|
927
|
+
rewardsProgramId,
|
|
928
|
+
rewardManager
|
|
929
|
+
) => {
|
|
930
|
+
const encodedPrefix = encoder.encode(VERIFY_TRANSFER_SEED_PREFIX)
|
|
931
|
+
const encodedTransferId = encoder.encode(transferId)
|
|
932
|
+
const seeds = Uint8Array.from([...encodedPrefix, ...encodedTransferId])
|
|
933
|
+
return SolanaUtils.findProgramAddressWithAuthority(rewardsProgramId, rewardManager, seeds)
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
module.exports = {
|
|
937
|
+
submitAttestations,
|
|
938
|
+
evaluateAttestations,
|
|
939
|
+
createSender,
|
|
940
|
+
deriveSolanaSenderFromEthAddress
|
|
941
|
+
}
|