-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add util tests * Refactor to listener + more tests + ts tests * Refactor all commands + some more tests * Add all listener setup tests * Further unit tests * linkWallet tests * getWallet tests * All commands unit tested * link wallet with XUMM show link * got so bad with case rename * readd files * Update node.js.yml * Exclude dist from tests * lowercase util sleep * Add XLS-20 NFT Support * Add /richlist command * Update Readme * Add Farming & Richlist command (#7) Added farming for token values Added commands related to farming (Start farming & stop farming) Added unit tests for farming commands Added CRON web endpoint for farming progress tracker Added /richlist command * Fix import casing
- Loading branch information
1 parent
e10c8bb
commit 795a644
Showing
41 changed files
with
1,097 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import SETTINGS from '../settings'; | ||
import sleep from '../utils/sleep'; | ||
import { getFarmingWallets } from '../data/getFarmingWallets'; | ||
import { getUserByDiscordId } from '../data/getUserByDiscordId'; | ||
import { updateWalletFarming } from '../data/updateWalletFarming'; | ||
import { deleteWalletFarming } from '../data/deleteWalletFarming'; | ||
import { setWalletEarned } from '../data/setWalletEarned'; | ||
|
||
import { Client, TextChannel } from 'discord.js'; | ||
|
||
const scanFarmingWallets = async ( | ||
client: Client, | ||
LOGGER: any, | ||
forceRefreshHours: boolean | ||
) => { | ||
// Get all wallets | ||
const farmingWallets = await getFarmingWallets(); | ||
|
||
let changes = 0; | ||
let paused = 0; | ||
for (let i = 0; i < farmingWallets.length; i++) { | ||
const farmingProgress = farmingWallets[i]; | ||
const farmingUser = await getUserByDiscordId(farmingProgress?.discordId); | ||
|
||
if (!farmingProgress || !farmingUser) { | ||
continue; | ||
} | ||
|
||
await sleep(100); | ||
|
||
// Check holdings | ||
if (farmingUser.totalPoints < farmingProgress.rewardPointsRequired) { | ||
// They don't have enough anymore, pause their farming. | ||
paused += 1; | ||
await updateWalletFarming( | ||
farmingProgress.discordId, | ||
farmingProgress.rewardPointsRequired, | ||
farmingProgress.rewardGoalAmount, | ||
farmingProgress.rewardGoalHoursRequired, | ||
farmingProgress.hoursFarmed, | ||
false, // Pause this wallet farming | ||
farmingProgress.dateStarted | ||
); | ||
continue; | ||
} | ||
|
||
// All good for this farmer | ||
changes += 1; | ||
let hoursFarmed = farmingProgress.hoursFarmed + 1; | ||
|
||
// Check if we have to refresh wallets with enough points to continue farming | ||
if (forceRefreshHours) { | ||
// If so, credit them for all hours since date farming started | ||
// this is for if there are network issues for a long time and we | ||
// want to be nice to the community users. | ||
const startedAt = new Date(farmingProgress.dateStarted).getTime(); | ||
const now = new Date().getTime(); | ||
hoursFarmed = Math.floor(Math.abs(now - startedAt) / 36e5); | ||
} | ||
|
||
// Check if they can claim now and save to other table | ||
const completed = hoursFarmed >= farmingProgress.rewardGoalHoursRequired; | ||
|
||
if (completed) { | ||
// Completed farming, save to earned table | ||
await setWalletEarned( | ||
farmingProgress.discordId, | ||
farmingUser.discordUsername, | ||
farmingUser.discordDiscriminator, | ||
farmingProgress.rewardGoalAmount, | ||
hoursFarmed, | ||
farmingProgress.dateStarted, | ||
new Date().toISOString() | ||
); | ||
|
||
// Delete from farmed table | ||
await deleteWalletFarming(farmingProgress.discordId); | ||
|
||
// Post in payout channel | ||
const channel = client.channels.cache.get( | ||
SETTINGS.DISCORD.FARMING_DONE_CHANNEL_ID | ||
) as TextChannel; | ||
if (channel !== null) { | ||
channel.send( | ||
`🚨🚜 User finished farming: ${farmingUser.discordUsername}#${farmingUser.discordDiscriminator} with discord id ${farmingUser.discordId} has finished farming for ${farmingProgress.rewardGoalAmount} ${SETTINGS.FARMING.EARNINGS_NAME} with ${hoursFarmed} hours.` | ||
); | ||
} | ||
|
||
// DM user | ||
const walletUser = client.users.cache.get(farmingUser.discordId); | ||
|
||
if (walletUser) { | ||
await walletUser.send( | ||
`Congratulations! You have finished farming for ${farmingProgress.rewardGoalAmount} ${SETTINGS.FARMING.EARNINGS_NAME} at ${hoursFarmed} hours!` | ||
); | ||
} | ||
} else { | ||
// Didn't complete yet, save progress so far. | ||
await updateWalletFarming( | ||
farmingProgress.discordId, | ||
farmingProgress.rewardPointsRequired, | ||
farmingProgress.rewardGoalAmount, | ||
farmingProgress.rewardGoalHoursRequired, | ||
hoursFarmed, | ||
true, | ||
farmingProgress.dateStarted | ||
); | ||
} | ||
} | ||
|
||
if (LOGGER !== null) { | ||
LOGGER.trackMetric({ name: 'scanFarmers-changes', value: changes }); | ||
} | ||
|
||
return `All done for ${farmingWallets.length} farmers with ${changes} changes and ${paused} paused`; | ||
}; | ||
|
||
export { scanFarmingWallets }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { getTopHolders } from '../data/getTopHolders'; | ||
import richlist from './richlist'; | ||
import { CommandInteraction } from 'discord.js'; | ||
import { jest } from '@jest/globals'; | ||
|
||
jest.mock('../data/getTopHolders'); | ||
|
||
describe('richlist interaction logic', () => { | ||
let interaction: CommandInteraction; | ||
let payload: any; | ||
|
||
beforeEach(() => { | ||
interaction = { | ||
author: { id: '123' }, | ||
commandName: 'richlist', | ||
reply: jest.fn(), | ||
} as unknown as CommandInteraction; | ||
|
||
payload = { | ||
handled: false, | ||
interaction, | ||
}; | ||
}); | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
it('calls interaction.reply when payload.handled is false', async () => { | ||
payload.handled = false; | ||
|
||
await richlist(payload); | ||
|
||
expect(interaction.reply).toHaveBeenCalled(); | ||
}); | ||
|
||
it('does not call interaction.reply when payload.handled is true', async () => { | ||
payload.handled = true; | ||
|
||
await richlist(payload); | ||
|
||
expect(interaction.reply).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('calls interaction.reply with top members if all ok', async () => { | ||
const userName = 'User'; | ||
const discriminator = '123'; | ||
const points = 55; | ||
|
||
( | ||
getTopHolders as jest.MockedFunction<typeof getTopHolders> | ||
).mockReturnValue( | ||
Promise.resolve([ | ||
{ | ||
discordId: '123456', | ||
discordUsername: userName, | ||
discordDiscriminator: discriminator, | ||
previousDiscordUsername: 'Prev', | ||
previousDiscordDiscriminator: '333', | ||
totalPoints: points, | ||
wallets: [ | ||
{ address: 'wallet', points: 50, verified: false }, | ||
{ address: 'wallet2', points: 5, verified: true }, | ||
], | ||
}, | ||
]) | ||
); | ||
|
||
await richlist(payload); | ||
|
||
expect(interaction.reply).toHaveBeenCalledWith({ | ||
content: `Top 10 community holders:\n ${points}\t\t->\t\t${userName}#${discriminator}`, | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.