@audius/sp-actions 1.0.1
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/CHANGELOG.md +11 -0
- package/README.md +61 -0
- package/claim.js +165 -0
- package/package.json +29 -0
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
## Automatic claims
|
|
2
|
+
|
|
3
|
+
This utility enables Audius Service Providers to automatically run claim operations whenever a new round is initiated.
|
|
4
|
+
|
|
5
|
+
This script can run on a recurring basis via cron and takes in two command line arguments: `spOwnerWallet` and `privateKey`.
|
|
6
|
+
|
|
7
|
+
`spOwnerWallet` - The wallet address used to register the nodes
|
|
8
|
+
|
|
9
|
+
`privateKey` - Not the private key of the `spOwnerWallet`. Should be a throwaway wallet used exclusively to claim with just enough ETH to make claims, no more than 1 ETH at any given time with an alert to top up.
|
|
10
|
+
|
|
11
|
+
Any wallet can make a claim on behalf of any node operator and their delegators and the rewards will be distributed to the node operator and the delegators inside the staking system and not to the wallet performing the claim. In order to access the claim, the node operator or delegator would have to request to undelegate.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
# 1. Ensure npm is installed on your system
|
|
15
|
+
|
|
16
|
+
# 2. Install the actions utility
|
|
17
|
+
npm install -g @audius/sp-actions
|
|
18
|
+
|
|
19
|
+
# 3. Setup a cron job with the following command: (NOTE: replace <npm_prefix> with the output from 'npm config get prefix')
|
|
20
|
+
(crontab -l 2>/dev/null; echo "0 */6 * * * <npm_prefix>/bin/claim claim-rewards <spOwnerWallet> <privateKey>") | crontab -
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
Usage: claim [options] [command]
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
-h, --help display help for command
|
|
28
|
+
|
|
29
|
+
Commands:
|
|
30
|
+
initiate-round [options] <privateKey> Initiates new round for claiming rewards
|
|
31
|
+
claim-rewards [options] <spOwnerWallet> <privateKey> Claim rewards for given spOwnerWallet
|
|
32
|
+
help [command] display help for command
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Usage: claim initiate-round [options] <privateKey>
|
|
37
|
+
|
|
38
|
+
Initiates new round for claiming rewards
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
--eth-registry-address <ethRegistryAddress> Registry contract address (default: "0xd976d3b4f4e22a238c1A736b6612D22f17b6f64C")
|
|
42
|
+
--eth-token-address <ethTokenAddress> Token contract address (default: "0x18aAA7115705e8be94bfFEBDE57Af9BFc265B998")
|
|
43
|
+
--web3-provider <web3Provider> Web3 provider to use
|
|
44
|
+
--gas <gas> ammount of gas to use (default: 100000)
|
|
45
|
+
--gas-price <gasPrice> gas price in gwei
|
|
46
|
+
-h, --help display help for command
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
Usage: claim claim-rewards [options] <spOwnerWallet> <privateKey>
|
|
51
|
+
|
|
52
|
+
Claim rewards for given spOwnerWallet
|
|
53
|
+
|
|
54
|
+
Options:
|
|
55
|
+
--eth-registry-address <ethRegistryAddress> Registry contract address (default: "0xd976d3b4f4e22a238c1A736b6612D22f17b6f64C")
|
|
56
|
+
--eth-token-address <ethTokenAddress> Token contract address (default: "0x18aAA7115705e8be94bfFEBDE57Af9BFc265B998")
|
|
57
|
+
--web3-provider <web3Provider> Web3 provider to use
|
|
58
|
+
--gas <gas> ammount of gas to use (default: 1000000)
|
|
59
|
+
--gas-price <gasPrice> gas price in gwei
|
|
60
|
+
-h, --help display help for command
|
|
61
|
+
```
|
package/claim.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const axios = require('axios')
|
|
4
|
+
const Web3 = require('web3')
|
|
5
|
+
const HDWalletProvider = require('@truffle/hdwallet-provider')
|
|
6
|
+
const { program } = require('commander')
|
|
7
|
+
|
|
8
|
+
const { AudiusLibs } = require('@audius/sdk')
|
|
9
|
+
|
|
10
|
+
const defaultRegistryAddress = '0xd976d3b4f4e22a238c1A736b6612D22f17b6f64C'
|
|
11
|
+
const defaultTokenAddress = '0x18aAA7115705e8be94bfFEBDE57Af9BFc265B998'
|
|
12
|
+
const defaultWeb3Provider = 'https://eth-mainnet.g.alchemy.com/v2/4hFRA61i6OFXz2UmkyFsSvgXBQBBOGgW'
|
|
13
|
+
|
|
14
|
+
async function configureLibs(ethRegistryAddress, ethTokenAddress, web3Provider) {
|
|
15
|
+
const configuredWeb3 = await AudiusLibs.Utils.configureWeb3(web3Provider, null, false)
|
|
16
|
+
|
|
17
|
+
const audiusLibsConfig = {
|
|
18
|
+
ethWeb3Config: AudiusLibs.configEthWeb3(ethTokenAddress, ethRegistryAddress, configuredWeb3, '0x0'),
|
|
19
|
+
isServer: true,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const libs = new AudiusLibs(audiusLibsConfig)
|
|
23
|
+
await libs.init()
|
|
24
|
+
|
|
25
|
+
return libs
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function getClaimsManagerContract(ethRegistryAddress, ethTokenAddress, web3) {
|
|
29
|
+
const audiusLibs = await configureLibs(ethRegistryAddress, ethTokenAddress, web3.eth.currentProvider)
|
|
30
|
+
await audiusLibs.ethContracts.ClaimsManagerClient.init()
|
|
31
|
+
return new web3.eth.Contract(
|
|
32
|
+
audiusLibs.ethContracts.ClaimsManagerClient._contract.options.jsonInterface,
|
|
33
|
+
audiusLibs.ethContracts.ClaimsManagerClient._contract.options.address
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function getDelegateManagerContract(ethRegistryAddress, ethTokenAddress, web3) {
|
|
38
|
+
const audiusLibs = await configureLibs(ethRegistryAddress, ethTokenAddress, web3.eth.currentProvider)
|
|
39
|
+
await audiusLibs.ethContracts.DelegateManagerClient.init()
|
|
40
|
+
return new web3.eth.Contract(
|
|
41
|
+
audiusLibs.ethContracts.DelegateManagerClient._contract.options.jsonInterface,
|
|
42
|
+
audiusLibs.ethContracts.DelegateManagerClient._contract.options.address
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function initiateRound(privateKey, { ethRegistryAddress, ethTokenAddress, web3Provider, gas, gasPrice, transferRewardsToSolana }) {
|
|
47
|
+
const web3 = new Web3(
|
|
48
|
+
new HDWalletProvider({
|
|
49
|
+
privateKeys: [privateKey],
|
|
50
|
+
providerOrUrl: web3Provider,
|
|
51
|
+
})
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
web3.eth.transactionPollingTimeout = 3600
|
|
55
|
+
const accountAddress = web3.eth.accounts.privateKeyToAccount(privateKey).address
|
|
56
|
+
|
|
57
|
+
const claimsManagerContract = await getClaimsManagerContract(ethRegistryAddress, ethTokenAddress, web3)
|
|
58
|
+
|
|
59
|
+
const lastFundedBlock = await claimsManagerContract.methods.getLastFundedBlock().call()
|
|
60
|
+
const requiredBlockDiff = await claimsManagerContract.methods.getFundingRoundBlockDiff().call()
|
|
61
|
+
|
|
62
|
+
const currentBlock = await web3.eth.getBlockNumber()
|
|
63
|
+
const blockDiff = currentBlock - lastFundedBlock - 12
|
|
64
|
+
|
|
65
|
+
if (blockDiff <= requiredBlockDiff) {
|
|
66
|
+
console.log(`Block difference of ${requiredBlockDiff} not met, ${requiredBlockDiff - blockDiff} blocks remaining`)
|
|
67
|
+
process.exit(1)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (gas === undefined) {
|
|
71
|
+
console.log('Estimating Gas')
|
|
72
|
+
gas = await claimsManagerContract.methods.initiateRound().estimateGas()
|
|
73
|
+
console.log('Calculated Gas:', gas)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log('Initializing Round')
|
|
77
|
+
await claimsManagerContract.methods.initiateRound().send({
|
|
78
|
+
from: accountAddress,
|
|
79
|
+
gas
|
|
80
|
+
})
|
|
81
|
+
console.log('Successfully initiated Round')
|
|
82
|
+
|
|
83
|
+
if (transferRewardsToSolana) {
|
|
84
|
+
const { transferCommunityRewardsToSolana } = require('@audius/sdk/scripts/communityRewards/transferCommunityRewardsToSolana')
|
|
85
|
+
console.log('Running rewards manager transfer')
|
|
86
|
+
await transferCommunityRewardsToSolana()
|
|
87
|
+
console.log('Successfully transferred rewards to solana')
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function claimRewards(
|
|
92
|
+
spOwnerWallet,
|
|
93
|
+
privateKey,
|
|
94
|
+
{ ethRegistryAddress, ethTokenAddress, web3Provider, gas, gasPrice }
|
|
95
|
+
) {
|
|
96
|
+
const web3 = new Web3(
|
|
97
|
+
new HDWalletProvider({
|
|
98
|
+
privateKeys: [privateKey],
|
|
99
|
+
providerOrUrl: web3Provider,
|
|
100
|
+
})
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
web3.eth.transactionPollingTimeout = 3600
|
|
104
|
+
const accountAddress = web3.eth.accounts.privateKeyToAccount(privateKey).address
|
|
105
|
+
|
|
106
|
+
const claimsManagerContract = await getClaimsManagerContract(ethRegistryAddress, ethTokenAddress, web3)
|
|
107
|
+
const delegateManagerContract = await getDelegateManagerContract(ethRegistryAddress, ethTokenAddress, web3)
|
|
108
|
+
|
|
109
|
+
const claimPending = await claimsManagerContract.methods.claimPending(spOwnerWallet).call()
|
|
110
|
+
|
|
111
|
+
if (claimPending) {
|
|
112
|
+
if (gas === undefined) {
|
|
113
|
+
console.log('Estimating Gas')
|
|
114
|
+
gas = await delegateManagerContract.methods.claimRewards(spOwnerWallet).estimateGas()
|
|
115
|
+
console.log('Calculated Gas:', gas)
|
|
116
|
+
|
|
117
|
+
const gasPrice = await web3.eth.getGasPrice()
|
|
118
|
+
const estimatedFee = gas * gasPrice
|
|
119
|
+
console.log('Estimated Fee:', web3.utils.fromWei(estimatedFee.toString(), 'ether'), 'ETH')
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log('Claiming Rewards')
|
|
123
|
+
await delegateManagerContract.methods.claimRewards(spOwnerWallet).send({
|
|
124
|
+
from: accountAddress,
|
|
125
|
+
gas,
|
|
126
|
+
gasPrice: gasPrice ? web3.utils.toWei(gasPrice, 'gwei') : (await web3.eth.getGasPrice()),
|
|
127
|
+
})
|
|
128
|
+
console.log('Claimed Rewards successfully')
|
|
129
|
+
} else {
|
|
130
|
+
console.log('No claims pending')
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function main() {
|
|
135
|
+
program
|
|
136
|
+
.command('initiate-round <privateKey>')
|
|
137
|
+
.description('Initiates new round for claiming rewards')
|
|
138
|
+
.option('--eth-registry-address <ethRegistryAddress>', 'Registry contract address', defaultRegistryAddress)
|
|
139
|
+
.option('--eth-token-address <ethTokenAddress>', 'Token contract address', defaultTokenAddress)
|
|
140
|
+
.option('--web3-provider <web3Provider>', 'Web3 provider to use', defaultWeb3Provider)
|
|
141
|
+
.option('--gas <gas>', 'amount of gas to use')
|
|
142
|
+
.option('--gas-price <gasPrice>', 'gas price in gwei')
|
|
143
|
+
.option('--transfer-rewards-to-solana', 'whether to also transfer rewards to solana rewards manager on success. Requires env vars to be set.', false)
|
|
144
|
+
.action(initiateRound)
|
|
145
|
+
|
|
146
|
+
program
|
|
147
|
+
.command('claim-rewards <spOwnerWallet> <privateKey>')
|
|
148
|
+
.description('Claim rewards for given spOwnerWallet')
|
|
149
|
+
.option('--eth-registry-address <ethRegistryAddress>', 'Registry contract address', defaultRegistryAddress)
|
|
150
|
+
.option('--eth-token-address <ethTokenAddress>', 'Token contract address', defaultTokenAddress)
|
|
151
|
+
.option('--web3-provider <web3Provider>', 'Web3 provider to use', defaultWeb3Provider)
|
|
152
|
+
.option('--gas <gas>', 'ammount of gas to use')
|
|
153
|
+
.option('--gas-price <gasPrice>', 'gas price in gwei')
|
|
154
|
+
.action(claimRewards)
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
await program.parseAsync(process.argv)
|
|
158
|
+
process.exit(0)
|
|
159
|
+
} catch (e) {
|
|
160
|
+
console.error(e)
|
|
161
|
+
process.exit(1)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
main()
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@audius/sp-actions",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "A utility for audius service providers to claim token rewards.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"claim": "claim.js"
|
|
7
|
+
},
|
|
8
|
+
"author": "Audius",
|
|
9
|
+
"license": "Apache-2.0",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@audius/sdk": "4.2.0",
|
|
12
|
+
"@truffle/hdwallet-provider": "^1.2.2",
|
|
13
|
+
"axios": "^0.21.0",
|
|
14
|
+
"commander": "^6.2.1",
|
|
15
|
+
"web3": "^1.3.4"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/AudiusProject/audius-protocol/issues"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/AudiusProject/audius-protocol.git#main"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/AudiusProject/audius-protocol/tree/main/packages/sp-actions",
|
|
25
|
+
"prettier": {
|
|
26
|
+
"semi": false,
|
|
27
|
+
"singleQuote": true
|
|
28
|
+
}
|
|
29
|
+
}
|