Skip to content

Commit

Permalink
feat: KEEPER_PREAUTHORIZE env variable and logic (#269)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben authored May 25, 2022
1 parent 372c3c0 commit 3d958ed
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 37 deletions.
1 change: 1 addition & 0 deletions bot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ $ npm run start
- `KEEPER_*`: (optional) set of env variables to enable keeper bot:
- `KEEPER_WALLET_PRIVATE_KEY`: (required) The wallet private key (https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key)
- `KEEPER_MINIMUM_NET_PROFIT_DAI`: (required) The minimum net profit an auction must yield before the keeper automatically bids on it. Can be negative if one is willing to spend ETH on transaction fees to keep DAI stable
- `KEEPER_PREAUTHORIZE`: (optional, default `false`) if set to `true`, the wallet will execute all required authorizations (for DAI and collateralals) on start. Default behaviour is to wait until specific auction is profitable and then execute authorizations only required for the particular auction. Note that it's recommended to set this to `true` only in combination with `WHITELISTED_COLLATERALS`
- `TWITTER_*`: (optional) set of env variables to enable twitter bot. Created via twitter developer account
with `OAuth 1.0a` `Elevated` access and `Read and Write` permissions:
- `TWITTER_API_KEY`: (required)
Expand Down
3 changes: 2 additions & 1 deletion bot/src/auctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export const getNewAuctionsFromActiveAuctions = function (activeActions: Auction
};

export const getAllAuctions = async function (network: string): Promise<AuctionInitialInfo[]> {
const auctions = await fetchAllInitialAuctions(network, getWhitelistedCollaterals());
const collaterals = await getWhitelistedCollaterals();
const auctions = await fetchAllInitialAuctions(network, collaterals);

const auctionIds = auctions.map(auction => `"${auction.id}"`).join(', ');
console.info(`auctions: found "${auctions.length}" auctions (${auctionIds}) on "${network}" network`);
Expand Down
69 changes: 69 additions & 0 deletions bot/src/authorisation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import getSigner from 'auctions-core/src/signer';
import {
authorizeCollateral,
authorizeWallet,
getCollateralAuthorizationStatus,
getWalletAuthorizationStatus,
} from 'auctions-core/src/authorizations';
import { ETHEREUM_NETWORK, KEEPER_PREAUTHORIZE } from './variables';
import { getWhitelistedCollaterals } from './whitelist';

export async function checkAndAuthorizeWallet(walletAddress: string): Promise<boolean> {
const isWalletAuth = await getWalletAuthorizationStatus(ETHEREUM_NETWORK, walletAddress);

if (isWalletAuth) {
console.info(`keeper: wallet "${walletAddress}" has already been authorized`);
return false;
}

console.info(`keeper: wallet "${walletAddress}" has not been authorized yet. Attempting authorization now...`);
const transactionHash = await authorizeWallet(ETHEREUM_NETWORK, walletAddress, false);
console.info(`keeper: wallet "${walletAddress}" successfully authorized via "${transactionHash}" transaction`);
return true;
}

export async function checkAndAuthorizeCollateral(walletAddress: string, collateralType: string): Promise<boolean> {
// get collateral authorization status
const isCollateralAuth = await getCollateralAuthorizationStatus(ETHEREUM_NETWORK, collateralType, walletAddress);

// try to authorize the collateral then return
if (isCollateralAuth) {
console.info(
`keeper: collateral "${collateralType}" has already been authorized on wallet "${walletAddress}"`
);
return false;
}

console.info(
`keeper: collateral "${collateralType}" has not been authorized on wallet "${walletAddress}" yet. Attempting authorization now...`
);
const collateralTransactionHash = await authorizeCollateral(
ETHEREUM_NETWORK,
walletAddress,
collateralType,
false
);
console.info(
`keeper: collateral "${collateralType}" successfully authorized on wallet "${walletAddress}" via "${collateralTransactionHash}" transaction`
);
return true;
}

export async function executePreAuthorizationsIfRequested() {
if (KEEPER_PREAUTHORIZE !== true) {
return;
}

const collaterals = await getWhitelistedCollaterals();
console.info(
`keeper: "KEEPER_PREAUTHORIZE" is true. Attempting to authorize wallet and collaterals: "${collaterals.join(
', '
)}"`
);
const signer = await getSigner(ETHEREUM_NETWORK);
const walletAddress = await signer.getAddress();
await checkAndAuthorizeWallet(walletAddress);
for (const collateral of collaterals) {
await checkAndAuthorizeCollateral(walletAddress, collateral);
}
}
2 changes: 2 additions & 0 deletions bot/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import participate, { setupKeeper } from './keeper';
import { ETHEREUM_NETWORK } from './variables';
import { setupTwitter } from './twitter';
import { setupWhitelist } from './whitelist';
import { executePreAuthorizationsIfRequested } from './authorisation';

const DEFAULT_REFETCH_INTERVAL = 60 * 1000;
const SETUP_DELAY = 3 * 1000;
Expand All @@ -31,6 +32,7 @@ const start = async function (): Promise<void> {
setupWhitelist();
await setupTwitter();
await setupKeeper();
await executePreAuthorizationsIfRequested();
loop();
setInterval(loop, REFETCH_INTERVAL);
};
Expand Down
42 changes: 10 additions & 32 deletions bot/src/keeper.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import { AuctionInitialInfo } from 'auctions-core/src/types';
import getSigner, { createSigner, setSigner } from 'auctions-core/src/signer';
import { bidWithCallee, enrichAuction } from 'auctions-core/src/auctions';
import {
authorizeCollateral,
authorizeWallet,
getCollateralAuthorizationStatus,
getWalletAuthorizationStatus,
} from 'auctions-core/src/authorizations';
import { ETHEREUM_NETWORK, KEEPER_MINIMUM_NET_PROFIT_DAI, KEEPER_WALLET_PRIVATE_KEY } from './variables';
import { checkAndAuthorizeCollateral, checkAndAuthorizeWallet } from './authorisation';

let isSetupCompleted = false;
const currentlyExecutedAuctions = new Set();
Expand Down Expand Up @@ -87,40 +82,23 @@ const checkAndParticipateIfPossible = async function (auction: AuctionInitialInf
);
}

// get wallet authorization status
const walletAddress = await signer.getAddress();
const isWalletAuth = await getWalletAuthorizationStatus(ETHEREUM_NETWORK, walletAddress);

// try to authorize the wallet then return
if (!isWalletAuth) {
console.info(`keeper: wallet "${walletAddress}" has not been authorized yet. Attempting authorization now...`);
const transactionHash = await authorizeWallet(ETHEREUM_NETWORK, walletAddress, false);
console.info(`keeper: wallet "${walletAddress}" successfully authorized via "${transactionHash}" transaction`);
const wasWalletNewlyAuthorized = await checkAndAuthorizeWallet(walletAddress);
if (wasWalletNewlyAuthorized) {
// restart auction evaluation in case authorization was executed
await checkAndParticipateIfPossible(auction);
return;
}

// get collateral authorization status
const isCollateralAuth = await getCollateralAuthorizationStatus(
ETHEREUM_NETWORK,
auctionTransaction.collateralType,
walletAddress
// check the collateral authorization status and authorize if needed
const wasCollateralNewlyAuthorized = await checkAndAuthorizeCollateral(
walletAddress,
auctionTransaction.collateralType
);

// try to authorize the collateral then return
if (!isCollateralAuth) {
console.info(
`keeper: collateral "${auctionTransaction.collateralType}" has not been authorized on wallet "${walletAddress}" yet. Attempting authorization now...`
);
const collateralTransactionHash = await authorizeCollateral(
ETHEREUM_NETWORK,
walletAddress,
auctionTransaction.collateralType,
false
);
console.info(
`keeper: collateral "${auctionTransaction.collateralType}" successfully authorized on wallet "${walletAddress}" via "${collateralTransactionHash}" transaction`
);
if (wasCollateralNewlyAuthorized) {
// restart auction evaluation in case authorization was executed
await checkAndParticipateIfPossible(auction);
return;
}
Expand Down
1 change: 1 addition & 0 deletions bot/src/variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export const ETHEREUM_NETWORK = process.env.ETHEREUM_NETWORK || 'kovan';
export const KEEPER_MINIMUM_NET_PROFIT_DAI = parseInt(process.env.KEEPER_MINIMUM_NET_PROFIT_DAI || '');
export const KEEPER_WALLET_PRIVATE_KEY = process.env.KEEPER_WALLET_PRIVATE_KEY;
export const WHITELISTED_COLLATERALS = process.env.WHITELISTED_COLLATERALS;
export const KEEPER_PREAUTHORIZE = process.env.KEEPER_PREAUTHORIZE?.toLowerCase().trim() === 'true' || false;
9 changes: 5 additions & 4 deletions bot/src/whitelist.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getCollateralConfigByType } from 'auctions-core/src/constants/COLLATERALS';
import { WHITELISTED_COLLATERALS } from './variables';
import { getSupportedCollateralTypes } from 'auctions-core/dist/src/addresses';
import { ETHEREUM_NETWORK, WHITELISTED_COLLATERALS } from './variables';

const validateWhitelist = function (whitelist: string[]) {
const unsupportedCollateralTypes: string[] = [];
Expand All @@ -17,15 +18,15 @@ const validateWhitelist = function (whitelist: string[]) {
}
};

export const parseCollateralWhitelist = function (whitelist: string): string[] {
const parseCollateralWhitelist = function (whitelist: string): string[] {
return whitelist.split(',').map(item => item.trim());
};

export const getWhitelistedCollaterals = function () {
export const getWhitelistedCollaterals = async function () {
if (WHITELISTED_COLLATERALS) {
return parseCollateralWhitelist(WHITELISTED_COLLATERALS);
}
return undefined;
return await getSupportedCollateralTypes(ETHEREUM_NETWORK);
};

export const setupWhitelist = function () {
Expand Down

0 comments on commit 3d958ed

Please sign in to comment.