@audius/sdk 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/.eslintrc +38 -0
  2. package/.prettierrc.js +1 -0
  3. package/.python-version +1 -0
  4. package/Dockerfile +15 -0
  5. package/README.md +3 -0
  6. package/babel.config.js +3 -0
  7. package/data-contracts/ABIs/AdminUpgradeabilityProxy.json +132 -0
  8. package/data-contracts/ABIs/BaseAdminUpgradeabilityProxy.json +113 -0
  9. package/data-contracts/ABIs/BaseUpgradeabilityProxy.json +22 -0
  10. package/data-contracts/ABIs/DiscoveryProviderFactory.json +189 -0
  11. package/data-contracts/ABIs/DiscoveryProviderFactoryInterface.json +61 -0
  12. package/data-contracts/ABIs/DiscoveryProviderStorage.json +205 -0
  13. package/data-contracts/ABIs/DiscoveryProviderStorageInterface.json +65 -0
  14. package/data-contracts/ABIs/ECDSA.json +4 -0
  15. package/data-contracts/ABIs/IPLDBlacklistFactory.json +168 -0
  16. package/data-contracts/ABIs/Initializable.json +4 -0
  17. package/data-contracts/ABIs/Migrations.json +67 -0
  18. package/data-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
  19. package/data-contracts/ABIs/Ownable.json +79 -0
  20. package/data-contracts/ABIs/PlaylistFactory.json +669 -0
  21. package/data-contracts/ABIs/PlaylistFactoryInterface.json +42 -0
  22. package/data-contracts/ABIs/PlaylistStorage.json +250 -0
  23. package/data-contracts/ABIs/PlaylistStorageInterface.json +129 -0
  24. package/data-contracts/ABIs/Proxy.json +10 -0
  25. package/data-contracts/ABIs/Registry.json +240 -0
  26. package/data-contracts/ABIs/RegistryContract.json +102 -0
  27. package/data-contracts/ABIs/RegistryContractInterface.json +28 -0
  28. package/data-contracts/ABIs/RegistryInterface.json +66 -0
  29. package/data-contracts/ABIs/SigningLogic.json +43 -0
  30. package/data-contracts/ABIs/SigningLogicInitializable.json +46 -0
  31. package/data-contracts/ABIs/SocialFeatureFactory.json +460 -0
  32. package/data-contracts/ABIs/SocialFeatureStorage.json +225 -0
  33. package/data-contracts/ABIs/SocialFeatureStorageInterface.json +123 -0
  34. package/data-contracts/ABIs/TestContract.json +135 -0
  35. package/data-contracts/ABIs/TestContractInterface.json +19 -0
  36. package/data-contracts/ABIs/TestContractWithStorage.json +165 -0
  37. package/data-contracts/ABIs/TestContractWithStorageInterface.json +24 -0
  38. package/data-contracts/ABIs/TestStorage.json +144 -0
  39. package/data-contracts/ABIs/TestStorageInterface.json +42 -0
  40. package/data-contracts/ABIs/TestUserReplicaSetManager.json +432 -0
  41. package/data-contracts/ABIs/TrackFactory.json +391 -0
  42. package/data-contracts/ABIs/TrackFactoryInterface.json +73 -0
  43. package/data-contracts/ABIs/TrackStorage.json +223 -0
  44. package/data-contracts/ABIs/TrackStorageInterface.json +121 -0
  45. package/data-contracts/ABIs/UpgradeabilityProxy.json +37 -0
  46. package/data-contracts/ABIs/UserFactory.json +657 -0
  47. package/data-contracts/ABIs/UserFactoryInterface.json +65 -0
  48. package/data-contracts/ABIs/UserLibraryFactory.json +334 -0
  49. package/data-contracts/ABIs/UserReplicaSetManager.json +418 -0
  50. package/data-contracts/ABIs/UserStorage.json +233 -0
  51. package/data-contracts/ABIs/UserStorageInterface.json +93 -0
  52. package/data-contracts/signatureSchemas.ts +1236 -0
  53. package/dist/core.d.ts +446 -0
  54. package/dist/core.js +769 -0
  55. package/dist/core.js.map +1 -0
  56. package/dist/index.d.ts +689 -0
  57. package/dist/index.js +72850 -0
  58. package/dist/index.js.map +1 -0
  59. package/eth-contracts/ABIs/Address.json +4 -0
  60. package/eth-contracts/ABIs/AudiusAdminUpgradeabilityProxy.json +105 -0
  61. package/eth-contracts/ABIs/AudiusClaimDistributor.json +4968 -0
  62. package/eth-contracts/ABIs/AudiusToken.json +724 -0
  63. package/eth-contracts/ABIs/BaseUpgradeabilityProxy.json +23 -0
  64. package/eth-contracts/ABIs/Checkpointing.json +4 -0
  65. package/eth-contracts/ABIs/ClaimsManager.json +539 -0
  66. package/eth-contracts/ABIs/Context.json +11 -0
  67. package/eth-contracts/ABIs/DelegateManager.json +989 -0
  68. package/eth-contracts/ABIs/DelegateManagerV2.json +1049 -0
  69. package/eth-contracts/ABIs/DelegateManagerV2Bad.json +1049 -0
  70. package/eth-contracts/ABIs/ERC20.json +252 -0
  71. package/eth-contracts/ABIs/ERC20Burnable.json +287 -0
  72. package/eth-contracts/ABIs/ERC20Detailed.json +270 -0
  73. package/eth-contracts/ABIs/ERC20Mintable.json +364 -0
  74. package/eth-contracts/ABIs/ERC20Pausable.json +397 -0
  75. package/eth-contracts/ABIs/EthRewardsManager.json +174 -0
  76. package/eth-contracts/ABIs/Governance.json +938 -0
  77. package/eth-contracts/ABIs/GovernanceUpgraded.json +953 -0
  78. package/eth-contracts/ABIs/GovernanceV2.json +938 -0
  79. package/eth-contracts/ABIs/IERC20.json +200 -0
  80. package/eth-contracts/ABIs/Initializable.json +4 -0
  81. package/eth-contracts/ABIs/InitializableV2.json +14 -0
  82. package/eth-contracts/ABIs/Migrations.json +71 -0
  83. package/eth-contracts/ABIs/MinterRole.json +91 -0
  84. package/eth-contracts/ABIs/MockAccount.json +62 -0
  85. package/eth-contracts/ABIs/MockDelegateManager.json +55 -0
  86. package/eth-contracts/ABIs/MockStakingCaller.json +259 -0
  87. package/eth-contracts/ABIs/MockWormhole.json +106 -0
  88. package/eth-contracts/ABIs/OpenZeppelinUpgradesAddress.json +4 -0
  89. package/eth-contracts/ABIs/Ownable.json +93 -0
  90. package/eth-contracts/ABIs/Pausable.json +150 -0
  91. package/eth-contracts/ABIs/PauserRole.json +91 -0
  92. package/eth-contracts/ABIs/Proxy.json +10 -0
  93. package/eth-contracts/ABIs/Registry.json +288 -0
  94. package/eth-contracts/ABIs/Roles.json +4 -0
  95. package/eth-contracts/ABIs/SafeERC20.json +4 -0
  96. package/eth-contracts/ABIs/SafeMath.json +4 -0
  97. package/eth-contracts/ABIs/ServiceProviderFactory.json +1153 -0
  98. package/eth-contracts/ABIs/ServiceTypeManager.json +337 -0
  99. package/eth-contracts/ABIs/Staking.json +555 -0
  100. package/eth-contracts/ABIs/StakingUpgraded.json +570 -0
  101. package/eth-contracts/ABIs/TestContract.json +44 -0
  102. package/eth-contracts/ABIs/TrustedNotifierManager.json +265 -0
  103. package/eth-contracts/ABIs/Uint256Helpers.json +4 -0
  104. package/eth-contracts/ABIs/UpgradeabilityProxy.json +40 -0
  105. package/eth-contracts/ABIs/Wormhole.json +45 -0
  106. package/eth-contracts/ABIs/WormholeClient.json +155 -0
  107. package/examples/file.mp3 +0 -0
  108. package/examples/initAudiusLibs.js +86 -0
  109. package/examples/initializeVersions.js +95 -0
  110. package/examples/pic.jpg +0 -0
  111. package/initScripts/configureLocalDiscProv.js +167 -0
  112. package/initScripts/helpers/claim.js +43 -0
  113. package/initScripts/helpers/distributeTokens.js +24 -0
  114. package/initScripts/helpers/spRegistration.js +138 -0
  115. package/initScripts/helpers/utils.js +34 -0
  116. package/initScripts/helpers/version.js +93 -0
  117. package/initScripts/local.js +617 -0
  118. package/initScripts/mainnet.js +131 -0
  119. package/initScripts/manageProdRelayerWallets.js +191 -0
  120. package/package.json +125 -0
  121. package/rollup.config.js +164 -0
  122. package/scripts/AudiusClaimDistributor.json +4968 -0
  123. package/scripts/Wormhole.json +155 -0
  124. package/scripts/addCIDToIpldBlacklist.js +124 -0
  125. package/scripts/circleci-test.sh +53 -0
  126. package/scripts/communityRewards/transferCommunityRewardsToSolana.js +222 -0
  127. package/scripts/ipfs.sh +58 -0
  128. package/scripts/migrate_contracts.sh +25 -0
  129. package/scripts/reset.sh +65 -0
  130. package/scripts/test.sh +77 -0
  131. package/src/api/account.js +670 -0
  132. package/src/api/base.js +122 -0
  133. package/src/api/file.js +168 -0
  134. package/src/api/playlist.js +328 -0
  135. package/src/api/rewards.d.ts +4 -0
  136. package/src/api/rewards.js +682 -0
  137. package/src/api/serviceProvider.js +154 -0
  138. package/src/api/track.js +604 -0
  139. package/src/api/user.js +888 -0
  140. package/src/api/user.test.js +172 -0
  141. package/src/constants.ts +7 -0
  142. package/src/core.ts +3 -0
  143. package/src/index.js +6 -0
  144. package/src/libs.d.ts +3 -0
  145. package/src/libs.js +619 -0
  146. package/src/sanityChecks/addSecondaries.js +40 -0
  147. package/src/sanityChecks/assignReplicaSetIfNecessary.js +10 -0
  148. package/src/sanityChecks/index.d.ts +9 -0
  149. package/src/sanityChecks/index.js +31 -0
  150. package/src/sanityChecks/isCreator.js +73 -0
  151. package/src/sanityChecks/needsRecoveryEmail.js +20 -0
  152. package/src/sanityChecks/rolloverNodes.js +74 -0
  153. package/src/sanityChecks/sanitizeNodes.js +24 -0
  154. package/src/sanityChecks/syncNodes.js +28 -0
  155. package/src/sdk/constants.ts +10 -0
  156. package/src/sdk/index.ts +1 -0
  157. package/src/sdk/oauth/Oauth.ts +265 -0
  158. package/src/sdk/oauth/index.ts +1 -0
  159. package/src/sdk/sdk.ts +102 -0
  160. package/src/service-selection/ServiceSelection.test.ts +320 -0
  161. package/src/service-selection/ServiceSelection.ts +460 -0
  162. package/src/service-selection/constants.ts +14 -0
  163. package/src/service-selection/index.ts +1 -0
  164. package/src/services/ABIDecoder/AudiusABIDecoder.ts +71 -0
  165. package/src/services/ABIDecoder/index.ts +1 -0
  166. package/src/services/comstock/Comstock.ts +39 -0
  167. package/src/services/comstock/index.ts +1 -0
  168. package/src/services/contracts/ContractClient.ts +227 -0
  169. package/src/services/contracts/GovernedContractClient.ts +53 -0
  170. package/src/services/contracts/ProviderSelection.ts +42 -0
  171. package/src/services/creatorNode/CreatorNode.ts +1065 -0
  172. package/src/services/creatorNode/CreatorNodeSelection.test.ts +997 -0
  173. package/src/services/creatorNode/CreatorNodeSelection.ts +488 -0
  174. package/src/services/creatorNode/constants.ts +10 -0
  175. package/src/services/creatorNode/index.ts +2 -0
  176. package/src/services/dataContracts/AudiusContracts.ts +234 -0
  177. package/src/services/dataContracts/IPLDBlacklistFactoryClient.ts +73 -0
  178. package/src/services/dataContracts/PlaylistFactoryClient.ts +370 -0
  179. package/src/services/dataContracts/RegistryClient.ts +95 -0
  180. package/src/services/dataContracts/SocialFeatureFactoryClient.ts +196 -0
  181. package/src/services/dataContracts/TrackFactoryClient.ts +131 -0
  182. package/src/services/dataContracts/UserFactoryClient.ts +351 -0
  183. package/src/services/dataContracts/UserLibraryFactoryClient.ts +115 -0
  184. package/src/services/dataContracts/UserReplicaSetManagerClient.ts +206 -0
  185. package/src/services/dataContracts/index.ts +1 -0
  186. package/src/services/discoveryProvider/DiscoveryProvider.ts +1168 -0
  187. package/src/services/discoveryProvider/DiscoveryProviderSelection.test.ts +536 -0
  188. package/src/services/discoveryProvider/DiscoveryProviderSelection.ts +383 -0
  189. package/src/services/discoveryProvider/constants.ts +13 -0
  190. package/src/services/discoveryProvider/index.ts +1 -0
  191. package/src/services/discoveryProvider/requests.ts +629 -0
  192. package/src/services/ethContracts/AudiusTokenClient.ts +163 -0
  193. package/src/services/ethContracts/ClaimDistributionClient.ts +45 -0
  194. package/src/services/ethContracts/ClaimsManagerClient.ts +102 -0
  195. package/src/services/ethContracts/DelegateManagerClient.ts +480 -0
  196. package/src/services/ethContracts/EthContracts.ts +359 -0
  197. package/src/services/ethContracts/EthRewardsManagerClient.ts +33 -0
  198. package/src/services/ethContracts/GovernanceClient.ts +451 -0
  199. package/src/services/ethContracts/RegistryClient.ts +33 -0
  200. package/src/services/ethContracts/ServiceProviderFactoryClient.ts +691 -0
  201. package/src/services/ethContracts/ServiceTypeManagerClient.ts +112 -0
  202. package/src/services/ethContracts/StakingProxyClient.ts +97 -0
  203. package/src/services/ethContracts/TrustedNotifierManagerClient.ts +101 -0
  204. package/src/services/ethContracts/WormholeClient.ts +97 -0
  205. package/src/services/ethContracts/index.ts +1 -0
  206. package/src/services/ethWeb3Manager/EthWeb3Manager.ts +239 -0
  207. package/src/services/ethWeb3Manager/index.ts +1 -0
  208. package/src/services/hedgehog/Hedgehog.ts +96 -0
  209. package/src/services/hedgehog/index.ts +1 -0
  210. package/src/services/identity/IdentityService.ts +551 -0
  211. package/src/services/identity/index.ts +1 -0
  212. package/src/services/identity/requests.ts +65 -0
  213. package/src/services/schemaValidator/SchemaValidator.ts +105 -0
  214. package/src/services/schemaValidator/index.ts +1 -0
  215. package/src/services/schemaValidator/schemas/trackSchema.json +267 -0
  216. package/src/services/schemaValidator/schemas/userSchema.json +230 -0
  217. package/src/services/solanaAudiusData/errors.ts +20 -0
  218. package/src/services/solanaAudiusData/index.ts +1189 -0
  219. package/src/services/solanaWeb3Manager/errors.js +101 -0
  220. package/src/services/solanaWeb3Manager/index.d.ts +46 -0
  221. package/src/services/solanaWeb3Manager/index.js +655 -0
  222. package/src/services/solanaWeb3Manager/padBNToUint8Array.ts +7 -0
  223. package/src/services/solanaWeb3Manager/rewards.js +941 -0
  224. package/src/services/solanaWeb3Manager/rewardsAttester.ts +1093 -0
  225. package/src/services/solanaWeb3Manager/tokenAccount.js +149 -0
  226. package/src/services/solanaWeb3Manager/transactionHandler.js +345 -0
  227. package/src/services/solanaWeb3Manager/transfer.js +272 -0
  228. package/src/services/solanaWeb3Manager/userBank.js +160 -0
  229. package/src/services/solanaWeb3Manager/utils.d.ts +31 -0
  230. package/src/services/solanaWeb3Manager/utils.js +163 -0
  231. package/src/services/solanaWeb3Manager/wAudio.js +28 -0
  232. package/src/services/solanaWeb3Manager/wAudio.test.js +30 -0
  233. package/src/services/web3Manager/Web3Config.ts +14 -0
  234. package/src/services/web3Manager/Web3Manager.ts +360 -0
  235. package/src/services/web3Manager/XMLHttpRequest.ts +11 -0
  236. package/src/services/web3Manager/index.ts +2 -0
  237. package/src/services/wormhole/index.js +424 -0
  238. package/src/types.ts +8 -0
  239. package/src/userStateManager.ts +53 -0
  240. package/src/utils/apiSigning.ts +51 -0
  241. package/src/utils/captcha.ts +97 -0
  242. package/src/utils/estimateGas.ts +64 -0
  243. package/src/utils/fileHasher.ts +278 -0
  244. package/src/utils/importContractABI.d.ts +9 -0
  245. package/src/utils/importContractABI.js +19 -0
  246. package/src/utils/index.ts +11 -0
  247. package/src/utils/multiProvider.ts +72 -0
  248. package/src/utils/network.test.ts +127 -0
  249. package/src/utils/network.ts +308 -0
  250. package/src/utils/promiseFight.test.ts +87 -0
  251. package/src/utils/promiseFight.ts +36 -0
  252. package/src/utils/signatures.ts +139 -0
  253. package/src/utils/types.ts +34 -0
  254. package/src/utils/utils.test.ts +36 -0
  255. package/src/utils/utils.ts +235 -0
  256. package/src/utils/uuid.ts +14 -0
  257. package/src/web3.d.ts +9 -0
  258. package/src/web3.js +8 -0
  259. package/tests/assets/static_image.png +0 -0
  260. package/tests/assets/static_text.txt +1 -0
  261. package/tests/audiusTokenClientTest.js +37 -0
  262. package/tests/creatorNodeTest.js +19 -0
  263. package/tests/fileHasherTest.js +125 -0
  264. package/tests/governanceTest.js +382 -0
  265. package/tests/helpers.js +105 -0
  266. package/tests/index.js +14 -0
  267. package/tests/playlistClientTest.js +157 -0
  268. package/tests/providerSelectionTest.js +241 -0
  269. package/tests/registryClientTest.js +19 -0
  270. package/tests/rewardsAttesterTest.js +373 -0
  271. package/tests/serviceTypeManagerClientTest.js +33 -0
  272. package/tests/socialFeatureClientTest.js +79 -0
  273. package/tests/stakingTest.js +302 -0
  274. package/tests/trackClientTest.js +86 -0
  275. package/tests/userClientTest.js +121 -0
  276. package/tsconfig.json +10 -0
  277. package/types/@audius-hedgehog/index.d.ts +39 -0
  278. package/types/abi-decoder/index.d.ts +41 -0
@@ -0,0 +1,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
+ }