This repository has been archived by the owner on Apr 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
206 lines (186 loc) · 5.9 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
const { ethers, providers, Wallet } = require('ethers')
const fetch = require('node-fetch')
const TelegramBot = require('node-telegram-bot-api');
const graphQLNode = 'https://grateful-sink-production.up.railway.app/'
const contractAddress = '0x0e22B5f3E11944578b37ED04F5312Dfc246f443C'
const petQuery = (owner) => `
{
pets(
where:{
owner_in: "${owner}"
}
) {
id
score
lastAttackUsed
}
}
`
const petQueryById = (id) => `
{
pet(id: ${id}) {
id
score
lastAttackUsed
}
}
`
const itemOwnedQuery = (id) => `
{
pet(id: ${id}) {
itemsOwned
}
}
`
const leaderboardQuery = () => `
{
pets (
first: 1000,
where: {
owner_not: "0x0000000000000000000000000000000000000000"
},
orderBy: "level",
orderDirection: "desc"
) {
name
id
owner
score
timeUntilStarving
status
lastAttackUsed
lastAttacked
level
}
}
`
const sleep = async (ms) => {
return new Promise(resolve => setTimeout(resolve, ms));
}
const getLeaderboard = async () => {
const leaderboardResponse = await fetch(graphQLNode, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: leaderboardQuery() }),
})
const leaderboardJson = await leaderboardResponse.json()
const leaderboard = leaderboardJson.data.pets
return leaderboard
}
require('dotenv').config()
const env = process.env
const main = async () => {
const telegramToken = env.TELEGRAM_TOKEN
const telegramChatId = env.TELEGRAM_CHAT_ID
let bot
if (telegramToken && telegramChatId) {
bot = new TelegramBot(telegramToken, {polling: true});
console.log(`Telegram bot started`)
}
const lastAttachedTimestamp = {}
const web3 = new ethers.providers.JsonRpcProvider(env.NODE_URL)
const wallet = new Wallet(env.PRIVATE_KEY, web3)
console.log(`Wallet address: ${wallet.address}`)
while (true) {
let pets = []
try {
const petsResponse = await fetch(graphQLNode, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: petQuery(wallet.address) }),
})
const petsJson = await petsResponse.json()
pets = petsJson.data.pets
} catch (e) {
console.log(`Error fetching pets: ${e}`)
}
if (pets.length === 0) {
console.log(`!!! No pets found`)
await sleep(5000)
continue
}
for (let i = 0; i < pets.length; i++) {
const pet = pets[i]
const petId = pet.id
const petScore = pet.score
const lastAttackUsed = pet.lastAttackUsed
// we can attack if last attack was more than 15 minutes ago
const now = Math.floor(Date.now() / 1000)
const canAttack = (now - lastAttackUsed) > 15 * 60
// -----------------------------------------------------------------------------
if (!canAttack) {
console.log(`-> Pet ${petId} cannot attack yet waiting ${15 * 60 - (now - lastAttackUsed)} seconds`)
continue
}
if (typeof lastAttachedTimestamp[petId] === 'undefined') {
lastAttachedTimestamp[petId] = 0
}
if (lastAttachedTimestamp[petId] + 15 * 60 > now) {
console.log(`-> Pet ${petId} already attacked in the last 15 minutes`)
continue
}
console.log(`Pet ${petId} can attack!`)
const leaderboard = await getLeaderboard()
for (const leaderboardPet of leaderboard) {
const lastAttacked = leaderboardPet.lastAttacked
const leaderboardScore = leaderboardPet.score
if (ethers.BigNumber.from(leaderboardScore).lte(
ethers.BigNumber.from(petScore).mul(ethers.BigNumber.from(15)).div(ethers.BigNumber.from(10))
)) {
continue
}
const status = leaderboardPet.status
const now = Math.floor(Date.now() / 1000)
if (lastAttacked + 60 * 60 < now && status === 0) {
const itemsOwnedResponse = await fetch(graphQLNode, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: itemOwnedQuery(leaderboardPet.id) }),
})
const itemsOwnedJson = await itemsOwnedResponse.json()
const itemsOwned = itemsOwnedJson.data.pet.itemsOwned
if (!itemsOwned.includes(6)) {
console.log(`Attacking pet ${leaderboardPet.id}`)
const contract = new ethers.Contract(contractAddress, [
'function attack(uint256 fromId, uint256 toId) external',
], wallet)
try {
const tx = await contract.attack(petId, leaderboardPet.id)
console.log(`-> Transaction hash: ${tx.hash}`)
const receipt = await tx.wait()
console.log(`-> Transaction confirmed in block ${receipt.blockNumber}`)
const updatedPetResponse = await fetch(graphQLNode, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: petQueryById(petId) }),
})
const updatedPetJson = await updatedPetResponse.json()
const updatedPet = updatedPetJson.data.pet
const updatedPetScore = updatedPet.score
const updatedScore = ethers.BigNumber.from(updatedPetScore).sub(ethers.BigNumber.from(petScore))
const formatedScore = ethers.utils.formatUnits(updatedScore, 12)
console.log(`-> Pet ${petId} won score: ${formatedScore.toString()}`)
if (bot) {
bot.sendMessage(telegramChatId, `Pet ${petId} won score: ${formatedScore.toString()}`)
}
lastAttachedTimestamp[petId] = now
break
} catch (e) {
console.log(`-> !!!Error attacking pet ${leaderboardPet.id}: ${e}`)
}
}
}
}
}
await sleep(5000)
}
}
main()