Skip to content

Commit

Permalink
Starting the trade logic
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurfiorette committed Mar 18, 2021
1 parent 07485e5 commit 44f66a6
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 8 deletions.
18 changes: 14 additions & 4 deletions app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import SteamCommunity from 'steamcommunity';
import SteamTotp from 'steam-totp';
import TradeOfferManager from 'steam-tradeoffer-manager';
import { info, Ad } from './logger';
import { Offer } from './trade/types';
import { process } from './trade/processor';

Ad.startup();

Expand All @@ -18,8 +20,8 @@ const manager = new TradeOfferManager({

info('TradeOfferManager is ready');

const { username, sharedSecret, password } = config.steam;
const { gameId } = config.info;
const { username, sharedSecret, password, identitySecret } = config.steam;
const { gameId: statusGameId } = config.status;

client.logOn({
accountName: username,
Expand All @@ -28,9 +30,17 @@ client.logOn({
});

client.on('loggedOn', () => {
info(`Logged into steam with username ${username}`);
client.setPersona(1);
client.gamesPlayed(gameId);
client.gamesPlayed(statusGameId);
info(`Logged into steam with username: '${username}'. Playing game id: '${statusGameId}'`);
});

client.on('webSession', (sessionId: number, cookies: string[]) => {
manager.setCookies(cookies);
community.setCookies(cookies);
community.startConfirmationChecker(2000, identitySecret);
});

manager.on('newOffer', (offer: Offer) => process(offer, community).then(() => info('Offer processed.')));

info('App initialized');
13 changes: 9 additions & 4 deletions app/src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ import { enable } from 'colors';

enable();

function printAll(prefix: string, color: string | undefined, ...message: string[]) {
message.forEach((msg) => console.log(`[${prefix}]`.blue, color ? msg[color] : msg));
}

export function info(...message: string[]) {
printAll('INFO', 'green', ...message);
}
Expand All @@ -22,6 +18,15 @@ export function log(...message: string[]) {
printAll('#', undefined, ...message);
}

function printAll(prefix: string, color: string | undefined, ...message: string[]) {
write(...message);
message.forEach((msg) => console.log(`[${prefix}]`.blue, color ? msg[color] : msg));
}

export function write(...message: string[]) {
//TODO: write in the logs only
}

export namespace Ad {
export function startup() {
log(
Expand Down
18 changes: 18 additions & 0 deletions app/src/trade/analyzer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { trading } from '../../../config.json';
import { Item, ItemPrice } from './types';

export function isTrash(item: ItemPrice): boolean {
return calculatePrice(item) <= trading.trashValue;
}

export function containsUnmarketable(items: Item[], callback: (items: Item[]) => void): boolean {
const unmarketable = items.filter((item) => !item.marketable);
if (unmarketable.length > 0) {
callback(unmarketable);
return true;
} else return false;
}

export function calculatePrice({ median_price, lowest_price }: ItemPrice): number {
return lowest_price > median_price ? lowest_price : median_price + lowest_price / 2;
}
39 changes: 39 additions & 0 deletions app/src/trade/market.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import axios from 'axios';
import { error, info } from '../logger';
import { ItemPrice, Item } from './types';
import { calculatePrice, isTrash } from './analyzer';

export async function getItemPrice({ appid, market_hash_name }: Item): Promise<ItemPrice> {
return new Promise<ItemPrice>(async (resolve, reject) => {
const params = { appid, currency: 1, market_hash_name };
try {
const data = await axios.get('http://steamcommunity.com/market/priceoverview', { params });
info('Received a response for the request on steamcommunity');
return resolve(parseData(data));
} catch (err) {
error('Received and error when getting steam price overview:');
return reject(err);
}
});
}

export async function getAllItemsPrice(items: Item[]) {
const prices: ItemPrice[] = [];
for(let item of items) {
prices.push(await getItemPrice(item))
}
return prices;
}

function parseData({ success, lowest_price, volume, median_price }: any): ItemPrice {
return {
success,
volume: Number(volume),
lowest_price: cleanPrice(lowest_price),
median_price: cleanPrice(median_price)
};
}

function cleanPrice(price: string): number {
return Number(price.substring(1));
}
85 changes: 85 additions & 0 deletions app/src/trade/processor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { info, warn } from '../logger';
import config from '../../../config.json';
import { getAllItemsPrice } from './market';
import { Offer, Community } from './types';
import { containsUnmarketable, isTrash, calculatePrice } from './analyzer';
import { acceptOffer, declineOffer, Reason } from './trader';

const { ownerIds, tradeWith0Profit } = config.trading;

export async function process(offer: Offer, community: Community): Promise<void> {
info('Received an offer');

const { partner, message, itemsToGive, itemsToReceive } = offer;

if (message && message.length > 0) {
info('This offer came with a message:', message);
}

if (offer.isGlitched()) {
warn('Received glitched offer, declining...');
return declineOffer(offer, Reason.GLITCHED);
}

if (ownerIds.includes(partner.getSteamID64())) {
info('Trade partner is owner');
return acceptOffer(offer);
}

info(`All our items are: ${itemsToGive.map((item) => item.name)}`);

info(`Their items are: ${itemsToReceive.map((item) => item.name)}`);

if (itemsToReceive.length < 1) {
info('Their item list are empty. declining...');
return declineOffer(offer, Reason.NEGATIVE_PROFIT);
} else {
if (containsUnmarketable(itemsToReceive, (items) => info(`There's unmarketable itens in the trade: ${items}`))) {
info('Declining trade');
return declineOffer(offer, Reason.UNMARKETABLE_ITEM);
}

const isGift = itemsToGive.length < 1;

info(isGift ? 'Our item list are empty. Accepting gift...' : 'They have items to trade. Analyzing...');
info('Getting market prices.');

const receiveItemsPrices = await getAllItemsPrice(itemsToReceive);

if (receiveItemsPrices.some(isTrash)) {
warn('Trade received with in the trash limit. Declining offer');
return declineOffer(offer, Reason.TRASH_LIMIT);
}

const receivePrice = receiveItemsPrices.map(calculatePrice).reduce((a, b) => a + b);

const givePrice = (await getAllItemsPrice(itemsToGive)).map(calculatePrice).reduce((a, b) => a + b);

info(`Our price are: '$${givePrice}' and their price are: '$${receivePrice}'`);

if (isGift) {
info('Accepting gift');
return acceptOffer(offer, receivePrice);
} else {
if (givePrice >= receivePrice) {
info('We are overpaying. Declining offer...');
return declineOffer(offer, Reason.NEGATIVE_PROFIT);
} else {
if (givePrice == receivePrice) {
info('This trade profit equal to 0');
if (!tradeWith0Profit) {
info(`The flag 'tradeWith0Profit' is false. Declining offer...`);
return declineOffer(offer, Reason.ZERO_PROFIT);
} else {
info(`Trading in the same way as the flag 'tradeWith0Profit' is true`);
}
}

const profit = receivePrice - givePrice;

info(`Our profit is ${profit}. Accepting offer...`);
return acceptOffer(offer, profit);
}
}
}
}
30 changes: 30 additions & 0 deletions app/src/trade/trader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Offer } from './types';
import { info, warn, error } from '../logger';

export enum Reason {
TRASH_LIMIT = 'Exists one or more itens with an value lower than the trash limit',
GLITCHED = 'This trade was glitched',
NEGATIVE_PROFIT = 'He proposed an offer that our profit is negative',
UNMARKETABLE_ITEM = 'Exists one or more itens that are unmarketable',
ZERO_PROFIT = `This trade have both sides at the same price and the flag 'tradeWith0Profit' is false`
}

export async function declineOffer(offer: Offer, reason: Reason) {
await offer.decline((err) => {
if (err) {
error('Was thrown an error while declining this offer.', err);
return;
}
warn(`Declined the offer. Reason: '${reason}'`);
});
}

export async function acceptOffer(offer: Offer, profit?: number) {
await offer.accept((err) => {
if (err) {
error('Was thrown an error while accepting this offer.', err);
return;
}
info(`Accepted the offer with the profit of ${profit}`);
});
}
33 changes: 33 additions & 0 deletions app/src/trade/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export interface Partner {
getSteamID64(): number;
}

export interface Item {
market_hash_name: string;
name: string;
appid: number;
amount: number;
marketable: boolean;
tradeable: boolean;
commodity: boolean;
}

export interface ItemPrice {
success: boolean;
lowest_price: number;
volume: number;
median_price: number;
}

export interface Offer {
isGlitched: () => boolean;
accept: (err: (err: any) => void) => void;
decline: (err: (err: any) => void) => void;
partner: Partner;
itemsToGive: Item[];
itemsToReceive: Item[];
message: string;
isOurOffer: boolean;
}

export interface Community {}

0 comments on commit 44f66a6

Please sign in to comment.