Skip to content

Commit

Permalink
feat: bump package and refactor scripts (#3)
Browse files Browse the repository at this point in the history
* fix: added try catch in workable fn

* feat: slow mode

* fix: using alchemy provider only for logs

* refactor: newAutomatedVault without restart

* fix: added some logs

* fix: yearn batch strategies

* style: lint

* fix: reduced batch size to 80

* feat: increased gas limit on factory-harvest-v1

* feat: added multiple builders

* feat: upgraded scripting utils version

* fix: reduced strategies batch to half

* fix: reduced to 30 now

* feat: upgraded scriptings version for better logs

* fix: reduce gas limit to 10M

* chore: cleanup package

* fix: reducing gas limit to 10m

* feat: upgrade to newest canary

* fix: env example

* feat: bump keeper utils

---------

Co-authored-by: 0xGorilla <[email protected]>
Co-authored-by: 0xGorilla <[email protected]>
  • Loading branch information
3 people authored Aug 6, 2024
1 parent 5791b9a commit 2af8c08
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 122 deletions.
3 changes: 1 addition & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
RPC_HTTP_MAINNET_URI=
RPC_WSS_MAINNET_URI=
RPC_HTTP_MAINNET_URI_FOR_LOGS=
TX_SIGNER_PRIVATE_KEY=
BUNDLE_SIGNER_PRIVATE_KEY=
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@
"*.ts": "yarn lint"
},
"dependencies": {
"@flashbots/ethers-provider-bundle": "0.5.0",
"@keep3r-network/keeper-scripting-utils": "1.0.0",
"@keep3r-network/keeper-scripting-utils": "1.1.1",
"dotenv": "16.0.3",
"ethers": "5.6.9",
"lodash.isequal": "4.5.0",
Expand Down
15 changes: 7 additions & 8 deletions src/factory-harvest-v1.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import {getMainnetSdk} from '@dethcrypto/eth-sdk-client';
import {providers, Wallet} from 'ethers';
import {FlashbotsBundleProvider} from '@flashbots/ethers-provider-bundle';
import {FlashbotsBroadcastor, getEnvVariable} from '@keep3r-network/keeper-scripting-utils';
import {PrivateBroadcastor, getEnvVariable} from '@keep3r-network/keeper-scripting-utils';
import {factoryHarvestV1Run} from './shared/factory-harvest-v1-run';

// SETUP
const WORK_FUNCTION = 'work';
const GAS_LIMIT = 10_000_000;
const PRIORITY_FEE = 1.5e9;
const PRIORITY_FEE = 2e9;
const builders = ['https://rpc.titanbuilder.xyz/', 'https://rpc.beaverbuild.org/'];

(async () => {
// ENVIRONMENT
const provider = new providers.JsonRpcProvider(getEnvVariable('RPC_HTTP_MAINNET_URI'));
const providerForLogs = new providers.JsonRpcProvider(getEnvVariable('RPC_HTTP_MAINNET_URI_FOR_LOGS'));
const txSigner = new Wallet(getEnvVariable('TX_SIGNER_PRIVATE_KEY'), provider);
const bundleSigner = new Wallet(getEnvVariable('BUNDLE_SIGNER_PRIVATE_KEY'), provider);
const chainId = 1;

// CONTRACTS
const job = getMainnetSdk(txSigner).publicKeeperJob;

// PROVIDERS
const flashbotsProvider = await FlashbotsBundleProvider.create(provider, bundleSigner);

const flashbotBroadcastor = new FlashbotsBroadcastor(flashbotsProvider, PRIORITY_FEE, GAS_LIMIT);
const broadcastor = new PrivateBroadcastor(builders, PRIORITY_FEE, GAS_LIMIT, true, chainId);

// INITIALIZE
await factoryHarvestV1Run(job, provider, WORK_FUNCTION, flashbotBroadcastor.tryToWorkOnFlashbots.bind(flashbotBroadcastor));
await factoryHarvestV1Run(job, provider, providerForLogs, WORK_FUNCTION, broadcastor.tryToWork.bind(broadcastor));
})();
14 changes: 6 additions & 8 deletions src/harvest-v2.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
import {getMainnetSdk} from '@dethcrypto/eth-sdk-client';
import {providers, Wallet} from 'ethers';
import {FlashbotsBundleProvider} from '@flashbots/ethers-provider-bundle';
import {getEnvVariable, StealthBroadcastor} from '@keep3r-network/keeper-scripting-utils/';
import {testV2Keep3rRun} from './shared/v2-keeper-run';
import {v2Keep3rRun} from './shared/v2-keeper-run';

// SETUP
const WORK_FUNCTION = 'work';
const GAS_LIMIT = 10_000_000;
const PRIORITY_FEE = 2e9;
const GAS_LIMIT = 5_000_000;
const BURST_SIZE = 2;
const builders = ['https://rpc.titanbuilder.xyz/', 'https://rpc.beaverbuild.org/'];

(async () => {
// ENVIRONMENT
const provider = new providers.JsonRpcProvider(getEnvVariable('RPC_HTTP_MAINNET_URI'));
const txSigner = new Wallet(getEnvVariable('TX_SIGNER_PRIVATE_KEY'), provider);
const bundleSigner = new Wallet(getEnvVariable('BUNDLE_SIGNER_PRIVATE_KEY'), provider);
const chainId = 1;

// CONTRACTS
const harvestJob = getMainnetSdk(txSigner).harvestV2Keep3rV2;
const stealthRelayer = getMainnetSdk(txSigner).stealthRelayer;

// PROVIDERS
const flashbotsProvider = await FlashbotsBundleProvider.create(provider, bundleSigner);
const rpcStealthBroacastor = new StealthBroadcastor(flashbotsProvider, stealthRelayer, PRIORITY_FEE, GAS_LIMIT, BURST_SIZE);
const broadcastor = new StealthBroadcastor(builders, stealthRelayer, PRIORITY_FEE, GAS_LIMIT, true, chainId);

// INITIALIZE
await testV2Keep3rRun(harvestJob, provider, WORK_FUNCTION, rpcStealthBroacastor.tryToWorkOnStealthRelayer.bind(rpcStealthBroacastor));
await v2Keep3rRun(harvestJob, provider, WORK_FUNCTION, broadcastor.tryToWork.bind(broadcastor));
})();
31 changes: 27 additions & 4 deletions src/shared/batch-requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,32 @@ import {ethers} from 'ethers';
import * as BatchWorkable from '../../solidity/artifacts/contracts/BatchWorkable.sol/BatchWorkable.json';

export async function getStrategies(job: Contract, strategies: string[]): Promise<string[]> {
const inputData = ethers.utils.defaultAbiCoder.encode(['address', 'address[]'], [job.address, strategies]);
const contractCreationCode = BatchWorkable.bytecode.concat(inputData.slice(2));
const encodedStrategies = await job.provider.call({data: contractCreationCode});
const [workableStrategies] = ethers.utils.defaultAbiCoder.decode(['address[]'], encodedStrategies) as [string[]];
let workableStrategies: string[] = [];

const batches = chunkArray(strategies, 30);
for (const batch of batches) {
const inputData = ethers.utils.defaultAbiCoder.encode(['address', 'address[]'], [job.address, batch]);
const contractCreationCode = BatchWorkable.bytecode.concat(inputData.slice(2));
const encodedStrategies = await job.provider.call({data: contractCreationCode});
const [batchWorkableStrategies] = ethers.utils.defaultAbiCoder.decode(['address[]'], encodedStrategies) as [string[]];
workableStrategies = workableStrategies.concat(batchWorkableStrategies);
}

return workableStrategies;
}

/**
* Splits an array into smaller chunks of a specified maximum size.
*
* @param array The array to be split.
* @param chunkSize The maximum size of each chunk.
* @returns An array of arrays, each of which is a chunk of the original array.
*/
function chunkArray<T>(array: T[], chunkSize: number): T[][] {
const chunks: T[][] = [];
for (let i = 0; i < array.length; i += chunkSize) {
chunks.push(array.slice(i, i + chunkSize));
}

return chunks;
}
86 changes: 40 additions & 46 deletions src/shared/factory-harvest-v1-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,55 +27,16 @@ const TOPICS = [
export async function factoryHarvestV1Run(
jobContract: Contract,
provider: providers.WebSocketProvider | providers.JsonRpcProvider,
providerForLogs: providers.WebSocketProvider | providers.JsonRpcProvider,
workMethod: string,
broadcastMethod: (props: BroadcastorProps) => Promise<void>,
): Promise<void> {
const vaultFactory = new Contract(VAULT_FACTORY_ADDRESS, VaultFactoryABI, provider);

const allVaults: string[] = await vaultFactory.allDeployedVaults();

const logsByTopic: Record<string, Event[]> = {};

for (const topic of TOPICS) {
const filter = {
address: allVaults,
topics: [topic],
fromBlock: VAULT_FACTORY_DEPLOYMENT_BLOCK,
};
logsByTopic[topic] = await provider.send('eth_getLogs', [filter]);
}

const strategyAdded = logsByTopic[TOPIC_STRATEGY_ADDED].map((event) => {
return event.topics[1];
});

const strategyAddedToQueue = logsByTopic[TOPIC_STRATEGY_ADDED_TO_QUEUE].map((event) => {
return event.topics[1];
});

const strategyMigratedFrom = logsByTopic[TOPIC_STRATEGY_MIGRATED].map((event) => {
return event.topics[1];
});

const strategyMigratedTo = logsByTopic[TOPIC_STRATEGY_MIGRATED].map((event) => {
return event.topics[2];
});

const strategyRemovedFromQueue = logsByTopic[TOPIC_STRATEGY_REMOVED_FROM_QUEUE].map((event) => {
return event.topics[1];
});

const strategyRevoked = logsByTopic[TOPIC_STRATEGY_REVOKED].map((event) => {
return event.topics[1];
});

const blockListener = new BlockListener(provider);

const allAddedStrategies = strategyAdded.concat(strategyMigratedTo).concat(strategyAddedToQueue);
const allRemovedStrategies = new Set(strategyRevoked.concat(strategyMigratedFrom).concat(strategyRemovedFromQueue));
const currentStrategies = allAddedStrategies.filter((x) => !allRemovedStrategies.has(x)).map((x) => '0x'.concat(x.slice(26, 256)));
const vaultFactory = new Contract(VAULT_FACTORY_ADDRESS, VaultFactoryABI, provider);
let currentStrategies: string[] = await getCurrentStrategies(vaultFactory, providerForLogs);

const blockSubscription = blockListener.stream(async (block: Block) => {
blockListener.stream(async (block: Block) => {
const workableStrategies = await getStrategies(jobContract, currentStrategies);

for (const strategy of workableStrategies) {
Expand Down Expand Up @@ -124,9 +85,9 @@ export async function factoryHarvestV1Run(
});

provider.on(vaultFactory.filters.NewAutomatedVault(), async () => {
// When a new vault is deployed, the script resets and re loads the strategies to work
blockSubscription();
await factoryHarvestV1Run(jobContract, provider, workMethod, broadcastMethod);
console.log('^^^^^^^^^^^^^^^^^ NEW AUTOMATED VAULT ^^^^^^^^^^^^^^^^^');
// When a new vault is deployed, reload the strategies to work
currentStrategies = await getCurrentStrategies(vaultFactory, providerForLogs);
});
}

Expand All @@ -142,3 +103,36 @@ function removeStrategy(strategiesArray: string[], strategy: string) {

strategiesArray.splice(indexOfStrategyToRemove, 1);
}

async function getCurrentStrategies(
vaultFactory: Contract,
providerForLogs: providers.WebSocketProvider | providers.JsonRpcProvider,
): Promise<string[]> {
const allVaults: string[] = await vaultFactory.allDeployedVaults();
console.log(`Fetching current strategies from ${allVaults.length} vaults`);

const logsByTopic: Record<string, Event[]> = {};
for (const topic of TOPICS) {
const filter = {
address: allVaults,
topics: [topic],
fromBlock: VAULT_FACTORY_DEPLOYMENT_BLOCK,
};
logsByTopic[topic] = await providerForLogs.send('eth_getLogs', [filter]);
}

const strategyAdded = logsByTopic[TOPIC_STRATEGY_ADDED].map((event) => event.topics[1]);
const strategyAddedToQueue = logsByTopic[TOPIC_STRATEGY_ADDED_TO_QUEUE].map((event) => event.topics[1]);
const strategyMigratedFrom = logsByTopic[TOPIC_STRATEGY_MIGRATED].map((event) => event.topics[1]);
const strategyMigratedTo = logsByTopic[TOPIC_STRATEGY_MIGRATED].map((event) => event.topics[2]);
const strategyRemovedFromQueue = logsByTopic[TOPIC_STRATEGY_REMOVED_FROM_QUEUE].map((event) => event.topics[1]);
const strategyRevoked = logsByTopic[TOPIC_STRATEGY_REVOKED].map((event) => event.topics[1]);

const allAddedStrategies = strategyAdded.concat(strategyMigratedTo).concat(strategyAddedToQueue);
const allRemovedStrategies = new Set(strategyRevoked.concat(strategyMigratedFrom).concat(strategyRemovedFromQueue));
const currentStrategies = allAddedStrategies.filter((x) => !allRemovedStrategies.has(x)).map((x) => '0x'.concat(x.slice(26, 256)));

console.log(`Found ${currentStrategies.length} strategies`);

return currentStrategies;
}
2 changes: 1 addition & 1 deletion src/shared/v2-keeper-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type {BroadcastorProps} from '@keep3r-network/keeper-scripting-utils';
import {BlockListener} from '@keep3r-network/keeper-scripting-utils';
import {getStrategies} from './batch-requests';

export async function testV2Keep3rRun(
export async function v2Keep3rRun(
jobContract: Contract,
provider: providers.WebSocketProvider | providers.JsonRpcProvider,
workMethod: string,
Expand Down
15 changes: 7 additions & 8 deletions src/tend-v2.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
import {getMainnetSdk} from '@dethcrypto/eth-sdk-client';
import {providers, Wallet} from 'ethers';
import {FlashbotsBundleProvider} from '@flashbots/ethers-provider-bundle';
import {FlashbotsBroadcastor, getEnvVariable} from '@keep3r-network/keeper-scripting-utils';
import {testV2Keep3rRun} from './shared/v2-keeper-run';
import {getEnvVariable, PrivateBroadcastor} from '@keep3r-network/keeper-scripting-utils';
import {v2Keep3rRun} from './shared/v2-keeper-run';

// SETUP
const WORK_FUNCTION = 'work';
const GAS_LIMIT = 10_000_000;
const PRIORITY_FEE = 1.5e9;
const PRIORITY_FEE = 2e9;
const builders = ['https://rpc.titanbuilder.xyz/', 'https://rpc.beaverbuild.org/'];

(async () => {
// ENVIRONMENT
const provider = new providers.JsonRpcProvider(getEnvVariable('RPC_HTTP_MAINNET_URI'));
const txSigner = new Wallet(getEnvVariable('TX_SIGNER_PRIVATE_KEY'), provider);
const bundleSigner = new Wallet(getEnvVariable('BUNDLE_SIGNER_PRIVATE_KEY'), provider);
const chainId = 1;

// CONTRACTS
const tendJob = getMainnetSdk(txSigner).tendV2Keep3rV2;

// PROVIDERS
const flashbotsProvider = await FlashbotsBundleProvider.create(provider, bundleSigner);
const flashbotBroadcastor = new FlashbotsBroadcastor(flashbotsProvider, PRIORITY_FEE, GAS_LIMIT);
const broadcastor = new PrivateBroadcastor(builders, PRIORITY_FEE, GAS_LIMIT, true, chainId);

// INITIALIZE
await testV2Keep3rRun(tendJob, provider, WORK_FUNCTION, flashbotBroadcastor.tryToWorkOnFlashbots.bind(flashbotBroadcastor));
await v2Keep3rRun(tendJob, provider, WORK_FUNCTION, broadcastor.tryToWork.bind(broadcastor));
})();
Loading

0 comments on commit 2af8c08

Please sign in to comment.