Skip to content

Added all functionality needed to get total fees adjusted based on value of eth at the time for tax purposes #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14,916 changes: 14,916 additions & 0 deletions data.html

Large diffs are not rendered by default.

1,245 changes: 1,235 additions & 10 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
"author": "CXBW",
"license": "ISC",
"dependencies": {
"cheerio": "^1.0.0-rc.10",
"ethers": "^5.5.2",
"form-data": "^4.0.0",
"got": "^11.8.3",
"prompt": "^1.2.0"
"mathjs": "^10.0.0",
"prompt": "^1.2.0",
"request": "^2.88.2"
}
}
8 changes: 6 additions & 2 deletions util/accounts/accountFns.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import got from 'got';
import got from 'got'

function parseData(data){
return JSON.parse(data.body)
Expand All @@ -7,7 +7,11 @@ function parseData(data){
export const getBalance = async (address, _config) => {
let balanceReq = await got.get(`${_config.baseUrl}?module=account&action=balance&address=${address}&tag=latest&apikey=${_config.apiKey}`);
let balance = parseData(balanceReq).result;
console.log(balance);
return balance;
}

export const getHistory = async (address, _config, options={}) => {
let historyReq = await got.get(`${_config.baseUrl}?module=account&action=txlist&address=${address}&startblock=${options?.startblock || 0}&endblock=${options?.endblock || 99999999}&sort=asc&apikey=${_config.apiKey}`);
let history = parseData(historyReq).result;
return history;
}
1 change: 1 addition & 0 deletions util/commandConfig/commandImports.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import '../commands/help.js';
import '../commands/getConfig.js';
import '../commands/scan.js';
import '../commands/getGasHistory.js';
let a;
export default a;

72 changes: 72 additions & 0 deletions util/commands/getGasHistory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Command from '../commandConfig/commandClass.js';
import globals from '../../index.js';
import {evaluate} from 'mathjs';
import * as accountFns from '../accounts/accountFns.js';
import * as dateFns from '../dates/dateFns.js';
import * as gasFns from '../gas/gasFns.js';
import * as ethPriceFns from '../marketPrices/ethPriceFns.js';

new Command("getGasUsed",
`Returns a sum of gas spent on transactions \n
Usage: escan getGasHistory <address> \n
Options:
From a start date
-start=<start-date>
\n

To an end date
-end=<end-date>,
\n

Exclude gas from failed transactions
-excludeFailed,
\n

Only use gas from failed transactions
-failedOnly
\n

Only return outgoing transactions
-outgoing`
,

async (address, options)=>{
//Get a list of address transaction history
let history = await accountFns.getHistory(address, globals._config);
let gasHistory = history.map((item)=> {
return {
gasPaid: gasFns.calcGasPaid(item.gasUsed, item.gasPrice), //in ETH
date: dateFns.unixToDateString(item.timeStamp),
isError: item.isError,
}
});

let startDate = gasHistory[0].date;
let endDate = gasHistory[gasHistory.length-1].date;
//For date range, get eth prices for each date
let pastPrices = await ethPriceFns.getHistoricalETH(startDate, endDate);
//Convert ETH to USD using each price
gasHistory = gasHistory.map(row=>{
console.log(row);
let histIndex = Math.floor(ethPriceFns.getHistIndex(row.date, endDate));
let price = parseFloat(pastPrices[histIndex].Price.replace(",",""));
//console.log(`Calc: ${parseFloat(row.gasPaid)} * ${price}`);
row.gasPaid = "$" + evaluate((row.gasPaid) * price).toFixed(2);
return row;
});

console.log("Gas History (based on value of ETH on day of each txn)");
console.log(gasHistory);
console.log("Totals: ");

//Sum and return gas used in USD
let totalFees = 0;
for(let i = 0; i < gasHistory.length; i++){
let decimalFee = parseFloat(gasHistory[i].gasPaid.replace("$",""));
totalFees += decimalFee;
}
totalFees = totalFees.toFixed(2);
console.log("$" + totalFees);
});


4 changes: 4 additions & 0 deletions util/dates/dateFns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

export const unixToDateString = (unixDate, format="en-US")=>{
return new Date(unixDate * 1000).toLocaleDateString(format);
}
8 changes: 8 additions & 0 deletions util/gas/gasFns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ethers } from "ethers"

//returns gas paid in ETH
//Note: gasPrice is a string representing WEI
export const calcGasPaid = (gasUsed, gasPrice)=>{
gasPrice = ethers.utils.formatEther(gasPrice);
return gasPrice * gasUsed;
}
77 changes: 77 additions & 0 deletions util/marketPrices/ethPriceFns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import request from 'request';
import cheerio from 'cheerio';


//Returns an array of objects containing Date, Price, Open, High, and Low
export const getHistoricalETH = (start, end) => {
try{
var headers = {
'authority': 'www.investing.com',
'pragma': 'no-cache',
'cache-control': 'no-cache',
'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"',
'accept': 'text/plain, */*; q=0.01',
'content-type': 'application/x-www-form-urlencoded',
'x-requested-with': 'XMLHttpRequest',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36',
'sec-ch-ua-platform': '"macOS"',
'origin': 'https://www.investing.com',
'sec-fetch-site': 'same-origin',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
'referer': 'https://www.investing.com/crypto/ethereum/historical-data',
'accept-language': 'en-US,en;q=0.9'
};
var dataString = `curr_id=1061443&smlID=25674078&header=null&st_date=${start}&end_date=${end}&interval_sec=Daily&sort_col=date&sort_ord=DESC&action=historical_data`;

var options = {
url: 'https://www.investing.com/instruments/HistoricalDataAjax',
method: 'POST',
headers: headers,
body: dataString
};

let p = new Promise((resolve, reject)=>{
request(options, (err, res, body)=>{
if(err){reject(err)}
body = formatHistData(body);
resolve(body);
});
}).catch(err=>{console.log(err)});

return p;
}catch(err){console.log(err);}
}

function formatHistData(data){
const $ = cheerio.load(data);
let parsed = ($('table tr').text());
let split = parsed.split(/\n\n|\n \n/g);
let arr = [];
split.forEach(elem=>{
let newElem = elem.split('\n');
arr.push(newElem);
});
let keys = arr[0];
keys.shift();
arr.shift();
arr = arr.map((elem)=>{return mapObject(keys, elem);});
return arr;

}

function mapObject(keys, arr){
let newObj = {};
keys.forEach((key, i)=>{ newObj[key] = arr[i]});
return newObj;
}


export const getHistIndex = (date, startDate)=>{
date = new Date(date);
startDate = new Date(startDate);
console.log(`StartDate: ${startDate} - Date:${date}`);
let index = (startDate - date)/(24*3600*1000);
return index;
}
31 changes: 31 additions & 0 deletions util/marketPrices/temp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import cheerio from 'cheerio';
import fs from 'fs';


function parseData(data){
const $ = cheerio.load(data);
let parsed = ($('table tr').text());
let split = parsed.split(/\n\n|\n \n/g);
let arr = [];
split.forEach(elem=>{
let newElem = elem.split('\n');
arr.push(newElem);
});
let keys = arr[0];
keys.shift();
arr.shift();
arr = arr.map((elem)=>{return mapObject(keys, elem);});
console.log(arr);
console.log(keys);

}

function mapObject(keys, arr){
let newObj = {};
keys.forEach((key, i)=>{ newObj[key] = arr[i]});
return newObj;
}
fs.readFile('./data.html', 'utf8', (err, data)=>{
if(err){console.log(err);}
else{parseData(data);}
});