Initial commit
This commit is contained in:
commit
b956f48b62
|
@ -0,0 +1,2 @@
|
|||
.idea
|
||||
node_modules
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,379 @@
|
|||
{
|
||||
"abi": [
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "token0",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "token1",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "pair",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "PairCreated",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "allPairs",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "pair",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "allPairsLength",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenA",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenB",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "createPair",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "pair",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "feeTo",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "feeToSetter",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenA",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenB",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getPair",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "pair",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "setFeeTo",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "setFeeToSetter",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"evm": {
|
||||
"bytecode": {
|
||||
"linkReferences": {},
|
||||
"object": "",
|
||||
"opcodes": "",
|
||||
"sourceMap": ""
|
||||
},
|
||||
"deployedBytecode": {
|
||||
"linkReferences": {},
|
||||
"object": "",
|
||||
"opcodes": "",
|
||||
"sourceMap": ""
|
||||
}
|
||||
},
|
||||
"interface": [
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "token0",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "token1",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "pair",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "PairCreated",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "allPairs",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "pair",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "allPairsLength",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenA",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenB",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "createPair",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "pair",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "feeTo",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "feeToSetter",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenA",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenB",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getPair",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "pair",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "setFeeTo",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "setFeeToSetter",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"bytecode": ""
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,201 @@
|
|||
// SPHRc Liquidity Harvester Pro 2000
|
||||
// License: Proprietary
|
||||
|
||||
/**
|
||||
* INSTALL:
|
||||
* first install node.js and npm (they are usually together.)
|
||||
* navigate in terminal to the directory you unpacked this in.
|
||||
* type: npm install
|
||||
*
|
||||
* RUN:
|
||||
* navigate in terminal to the directory you unpacked this in.
|
||||
* type, putting a space before "export":
|
||||
* export MNEMONIC="your seed phrase goes here"
|
||||
* type: ./loop.sh
|
||||
* leave the terminal open. It will run forever. If you need to end it, exit
|
||||
* the terminal.
|
||||
*/
|
||||
|
||||
const account_number = 1; // Sparrow acct num, STARTS AT ZERO, CAN'T USE TREZOR
|
||||
const loop_delay = 7200 * 1000; // 2 hours
|
||||
|
||||
const router_address = '0xf3ce4655a44146c8eefbf45651f6479f9d67a77a';
|
||||
|
||||
const sphr_token_address = '0x20e3dD746DdF519B23Ffbbb6Da7a5d33eA6349D6';
|
||||
const sphrc_token_address = '0x402C2C3aceeb52b8654A0631012ceD49cbc9bDc4';
|
||||
const slpt_token_address = '0x596430dF1662B39d481265752A0c694f72C99AD3';
|
||||
|
||||
const grans_sphr_pool_address = '0xcc22E95B1926F48acF17852582F14B22AB4cF0b9';
|
||||
const ubiq_sphr_pool_address = '0x5130bc430Ed7cD252a18B724fBa40cd1078F8C75';
|
||||
const ricks_sphr_pool_address = '0xB934A32F065a9db4B2Df565b901276c88dc31F3E';
|
||||
const sphrc_sphr_pool_address = '0x93CdC7AF7fa7CfA9E603Cf4406acD81171A7Cfaa';
|
||||
|
||||
const pool_addresses = [
|
||||
grans_sphr_pool_address,
|
||||
ubiq_sphr_pool_address,
|
||||
ricks_sphr_pool_address,
|
||||
sphrc_sphr_pool_address
|
||||
];
|
||||
|
||||
const deadline_seconds = 600;
|
||||
slippage_pct = .995;
|
||||
|
||||
const HDWalletProvider = require('@truffle/hdwallet-provider');
|
||||
const Web3 = require("web3");
|
||||
const Contract = require('web3-eth-contract');
|
||||
const BigNumber = require('bignumber.js');
|
||||
BigNumber.set({ DECIMAL_PLACES: 18, ROUNDING_MODE: BigNumber.ROUND_FLOOR })
|
||||
|
||||
const mnemonic = process.env.MNEMONIC;
|
||||
|
||||
const provider = new HDWalletProvider({
|
||||
mnemonic: {
|
||||
phrase: mnemonic
|
||||
},
|
||||
providerOrUrl: "https://rpc.octano.dev"
|
||||
});
|
||||
|
||||
Contract.setProvider(provider);
|
||||
let web3 = new Web3(provider);
|
||||
|
||||
const erc20_abi = require('./IERC20.json').abi;
|
||||
|
||||
const router_abi = require('./IUniswapV2Router02.json').abi;
|
||||
const router = new Contract(router_abi, router_address);
|
||||
|
||||
console.log("Starting loop");
|
||||
(async () => {
|
||||
const account = (await web3.eth.getAccounts())[account_number];
|
||||
console.log(`account: ${account}`);
|
||||
|
||||
const factory_address = await router.methods.factory().call();
|
||||
console.log(`factory address: ${factory_address}`);
|
||||
|
||||
const factory_abi = require('./IUniswapV2Factory.json').abi;
|
||||
const factory = new Contract(factory_abi, factory_address);
|
||||
|
||||
const pool_abi = require('./ShinobiPool.json').abi;
|
||||
|
||||
while (true) {
|
||||
const reward_promises = [];
|
||||
for (const pool_address of pool_addresses) {
|
||||
reward_promises.push(
|
||||
new Promise(resolve => {
|
||||
const pool = new Contract(pool_abi, pool_address);
|
||||
console.log(`Calling harvest for ${pool_address}`);
|
||||
pool.methods.getReward().send({ from: account }).then(() => {
|
||||
console.log(`Harvested rewards for ${pool_address}`);
|
||||
resolve();
|
||||
})
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`There are ${reward_promises.length} pools to harvest.`);
|
||||
|
||||
console.log("Getting rewards from all pools.")
|
||||
await Promise.all(reward_promises);
|
||||
console.log("Done harvesting.")
|
||||
|
||||
|
||||
const sphr = new Contract(erc20_abi, sphr_token_address);
|
||||
const sphr_balance = await sphr.methods.balanceOf(account).call();
|
||||
const sphr_balance_pretty = new BigNumber(sphr_balance).div('1e+8');
|
||||
console.log(`sphere balance: ${sphr_balance_pretty}`);
|
||||
|
||||
const sphrc = new Contract(erc20_abi, sphrc_token_address);
|
||||
const sphrc_balance = await sphrc.methods.balanceOf(account).call();
|
||||
const sphrc_balance_pretty = new BigNumber(sphrc_balance).div('1e+18');
|
||||
console.log(`spherec balance: ${sphrc_balance_pretty}`);
|
||||
|
||||
if (new BigNumber(sphr_balance).isZero() || new BigNumber(sphrc_balance).lt('1000000000000000000')) {
|
||||
console.log("sphere or spherec balance too low, skipping this step.")
|
||||
}
|
||||
else {
|
||||
const pair_address = await factory.methods.getPair(sphr_token_address, sphrc_token_address).call();
|
||||
const pair_abi = require('./IUniswapV2Pair.json').abi;
|
||||
const pair = new Contract(pair_abi, pair_address);
|
||||
const reserves = await pair.methods.getReserves().call();
|
||||
console.log(`reserve0: ${reserves.reserve0}, reserve1: ${reserves.reserve1}`);
|
||||
|
||||
const sphr_sphrc_ratio = new BigNumber(reserves.reserve0).div(reserves.reserve1);
|
||||
console.log(`ratio of sphr to sphrc: ${sphr_sphrc_ratio}`);
|
||||
const needed_sphr = new BigNumber(sphrc_balance).times(sphr_sphrc_ratio).integerValue().toString();
|
||||
console.log(`needed sphere: ${new BigNumber(needed_sphr).div('1e+8')}`);
|
||||
|
||||
if (new BigNumber(needed_sphr).gt(sphr_balance)) {
|
||||
console.log("Not enough sphr, skipping this step.");
|
||||
}
|
||||
else {
|
||||
// account for slippage
|
||||
const sphr_min_desired = new BigNumber(needed_sphr).times(slippage_pct).integerValue().toString();
|
||||
const sphrc_min_desired = new BigNumber(sphrc_balance).times(slippage_pct).integerValue().toString()
|
||||
console.log(`desired: ${new BigNumber(sphr_min_desired).div('1e+8')} ${new BigNumber(sphrc_min_desired).div('1e+18')}`);
|
||||
|
||||
// make sure both tokens are approved for the amounts
|
||||
const approval_promises = [];
|
||||
|
||||
const sphr_allowance = await sphr.methods.allowance(account, router_address).call();
|
||||
if (new BigNumber(sphr_allowance).lt(needed_sphr)) {
|
||||
console.log("Sphere allowance isn't big enough, approving now.");
|
||||
approval_promises.push( sphr.methods.approve(router_address, needed_sphr).send({ from: account }) );
|
||||
}
|
||||
|
||||
const sphrc_allowance = await sphrc.methods.allowance(account, router_address).call()
|
||||
if (new BigNumber(sphrc_allowance).lt(sphrc_balance)) {
|
||||
console.log("Sphere Cubed allowance isn't big enough, approving now.");
|
||||
approval_promises.push( sphrc.methods.approve(router_address, sphrc_balance).send({ from: account }) );
|
||||
}
|
||||
|
||||
if (approval_promises.length) {
|
||||
await Promise.all(approval_promises);
|
||||
}
|
||||
|
||||
const deadline = Math.floor(Date.now() / 1000) + deadline_seconds;
|
||||
|
||||
console.log('Adding liquidity to Shinobi.');
|
||||
await router.methods.addLiquidity(
|
||||
sphr_token_address,
|
||||
sphrc_token_address,
|
||||
needed_sphr,
|
||||
sphrc_balance,
|
||||
sphr_min_desired,
|
||||
sphrc_min_desired,
|
||||
account,
|
||||
deadline
|
||||
).send({ from: account });
|
||||
}
|
||||
}
|
||||
|
||||
const slpt = new Contract(erc20_abi, slpt_token_address);
|
||||
const slpt_balance = await slpt.methods.balanceOf(account).call();
|
||||
|
||||
if ( new BigNumber(slpt_balance).isZero() ) {
|
||||
console.log("No new SLPT to stake.")
|
||||
}
|
||||
else {
|
||||
console.log(`SLPT balance: ${new BigNumber(slpt_balance).div('1e+18')}`);
|
||||
const sphr_sphrc_pool = new Contract(pool_abi, sphrc_sphr_pool_address);
|
||||
|
||||
const slpt_allowance = await slpt.methods.allowance(account, sphrc_sphr_pool_address).call();
|
||||
|
||||
if (new BigNumber(slpt_allowance).lt(slpt_balance)) {
|
||||
console.log("SLPT Allowance for yield farm is not enough, approving now.");
|
||||
await slpt.methods.approve(sphrc_sphr_pool_address, slpt_balance).send({ from: account });
|
||||
}
|
||||
|
||||
console.log("Staking SLPT tokens.");
|
||||
await sphr_sphrc_pool.methods.stake(slpt_balance).send({ from: account });
|
||||
}
|
||||
|
||||
console.log("Waiting for a while...");
|
||||
await new Promise(resolve => setTimeout(resolve, loop_delay));
|
||||
console.log("Done waiting, resuming.");
|
||||
}
|
||||
|
||||
})().catch(e => {
|
||||
console.error('oh shit', e);
|
||||
|
||||
try { provider.engine.stop(); } catch(e) {}
|
||||
process.exit(1);
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
while :
|
||||
do
|
||||
node index.js || continue
|
||||
sleep 5
|
||||
done
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "auto-farmer",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@truffle/hdwallet-provider": "^1.2.2",
|
||||
"bignumber.js": "^9.0.1",
|
||||
"web3": "^1.3.4",
|
||||
"web3-eth-contract": "^1.3.4"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue