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
const MIN_PROFIT_USD = 0.1; // $0.10 per prize claimed | |
const FEE_TOKEN_ASSET_RATE_USD = 0.6; // $0.60 for prize token (likely POOL) | |
const FEE_TOKEN_DECIMALS = 18; | |
const GAS_ONE_CLAIM_USD = 0.08; // $0.08 gas cost for one claim | |
const GAS_EACH_FOLLOWING_CLAIM_USD = 0.02; // $0.02 extra gas cost for each following claim | |
interface ClaimInfo { | |
claimCount: number; | |
minVrgdaFeePerClaim: string; |
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
const loopUnclaimedGroups = async (unclaimedClaimsGrouped, claimerContract: Contract) => { | |
for (let vaultTier of Object.entries(unclaimedClaimsGrouped)) { | |
const [key, value] = vaultTier; | |
const [vault, tier] = key.split(','); | |
const groupedClaims: any = value; | |
console.log(`Vault: ${vault}`); | |
console.log(`Tier Index: #${tier}`); | |
console.log(`# prizes: ${groupedClaims.length}`); |
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
const getClaims = async (): Promise<Claim[]> { => { | |
const contracts: ContractsBlob = await downloadContractsBlob(CHAIN_ID); | |
// We have found this to be too heavy to use in our OpenZeppelin Defender autotasks. | |
// Depending on the number of winners you may need to cache the results of this for | |
// every draw in flat files that your bot then fetches later | |
const claims: Claim[] = await computeDrawWinners(readProvider, contracts, CHAIN_ID); | |
return claims; | |
} |
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
const findAndGroupUnclaimed = async (claims: Claim[]) => { | |
// Cross-reference claimed prizes to flag if a prize has been claimed or not | |
claims = await flagClaimedRpc(readProvider, contracts, claims); | |
let unclaimedClaims = claims.filter((claim) => !claim.claimed); | |
console.log(`${unclaimedClaims.length} prizes remaining to be claimed...`); | |
if (unclaimedClaims.length === 0) { | |
console.log(`No prizes left to claim. Exiting ...`); | |
return; |
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
const executeTransaction = async (claimPrizesParams, claimerContract: Contract) => { | |
// It's profitable if there is at least 1 claim to claim | |
if (claimPrizesParams.winners.length > 0) { | |
const populatedTx = await claimerContract.populateTransaction.claimPrizes( | |
...Object.values(claimPrizesParams), | |
); | |
const tx = await relayer.sendTransaction({ | |
data: populatedTx.data, | |
to: populatedTx.to, |
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
const calculateProfit = async ( | |
vault: string, | |
tierIndex: number, | |
claimerContract: Contract, | |
groupedClaims: any, | |
): Promise<ClaimPrizesParams> => { | |
const { claimCount, claimFeesUsd, totalCostUsd, minVrgdaFeePerClaim } = | |
await getClaimInfo( | |
claimerContract, | |
tierIndex, |
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
import { Contract, BigNumber } from 'ethers'; | |
import { JsonRpcProvider } from '@ethersproject/providers' | |
import { formatUnits } from '@ethersproject/units'; | |
import { | |
computeDrawWinners, | |
downloadContractsBlob, | |
flagClaimedRpc, | |
Claim, | |
ContractsBlob, | |
} from '@generationsoftware/pt-v5-utils-js'; |
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
if (profitable) { | |
const transactionPopulated = await | |
liquidationRouterContract.populateTransaction.swapExactAmountOut( | |
liquidationPair.address, | |
swapRecipient, | |
wantedAmountsOut[selectedIndex], | |
amountInMin, | |
Math.floor(Date.now() / 1000) + 100 // deadline | |
); |
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
// Get allowance approval | |
const allowance = await tokenInContract.allowance( | |
relayerAddress, | |
liquidationRouterContract.address | |
); | |
// Note that we're setting it to the max allowance as we trust the security | |
// audits of the LiquidationRouter contract | |
if (allowance.lt(exactAmountIn)) { | |
const tx = await tokenInContract.approve( |
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
// Your Relayer (the EOA or "externally owned account") will be swapping POOL | |
// tokens, so it will need to have a POOL balance. | |
const relayerAddress = '0x49ca801A80e31B1ef929eAB13Ab3FBbAe7A55e8F'; | |
// Check if tokenIn balance for relayer (bot) account is sufficient | |
const tokenInContract = new ethers.Contract(tokenInAddress, ERC20Abi, writeProvider); | |
const tokenInBalance = await tokenInContract.balanceOf(relayerAddress); | |
const sufficientBalance = tokenInBalance.gt(exactAmountIn); | |
if (!sufficientBalance) { |