├── keep_alive.js ├── response_models ├── SteamTradeOffer.js └── SteamInventoryItem.js ├── utils └── SteamAccountCredentials.js ├── package.json ├── config.js ├── .gitignore ├── README.md ├── managers └── SteamBotAccountManager.js └── index.js /keep_alive.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | 3 | http.createServer(function (req, res) { 4 | res.write("I'm alive"); 5 | res.end(); 6 | }).listen(8080); 7 | -------------------------------------------------------------------------------- /response_models/SteamTradeOffer.js: -------------------------------------------------------------------------------- 1 | class SteamTradeOffer { 2 | constructor(incomingOffer, securityCode) { 3 | this.offer = incomingOffer; 4 | this.SECURITY_CODE = securityCode; 5 | } 6 | 7 | getMessage() { 8 | return this.offer.message; 9 | } 10 | 11 | getItemsToGive() { 12 | return this.offer.itemsToGive; 13 | } 14 | 15 | isSafeTrade() { 16 | return this.getMessage() == this.SECURITY_CODE.toString() && this.getItemsToGive().length == 0; 17 | } 18 | 19 | } 20 | 21 | module.exports = SteamTradeOffer; -------------------------------------------------------------------------------- /response_models/SteamInventoryItem.js: -------------------------------------------------------------------------------- 1 | class SteamInventoryItem { 2 | constructor(response) { 3 | this.steamInventoryItemResponse = response; 4 | } 5 | // Add more names and things here on an as needed basis 6 | getName() { 7 | return this.steamInventoryItemResponse.market_hash_name; 8 | } 9 | 10 | 11 | /* 12 | * In the future we may want to start checking to see if we can get the lowest valued item and send that item instead. 13 | */ 14 | getMarketPrice() { 15 | return null; 16 | } 17 | 18 | getRawData() { 19 | return this.steamInventoryItemResponse; 20 | } 21 | } 22 | 23 | module.exports = SteamInventoryItem; -------------------------------------------------------------------------------- /utils/SteamAccountCredentials.js: -------------------------------------------------------------------------------- 1 | class SteamAccountCredentials { 2 | constructor (identitySecret, sharedSecret, username, password, tradelink) { 3 | this.identitySecret = identitySecret 4 | this.sharedSecret = sharedSecret; 5 | this.username = username; 6 | this.password = password; 7 | this.tradelink = tradelink; 8 | } 9 | 10 | getIdentitySecret() { 11 | return this.identitySecret; 12 | } 13 | 14 | getSharedSecret() { 15 | return this.sharedSecret; 16 | } 17 | 18 | getUsername() { 19 | return this.username; 20 | } 21 | 22 | getPassword() { 23 | return this.password; 24 | } 25 | 26 | getTradelink() { 27 | return this.tradelink; 28 | } 29 | } 30 | 31 | module.exports = SteamAccountCredentials; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-steam-trade-farm", 3 | "version": "1.0.0", 4 | "description": "Steam bot written in NodeJS/JS that will send trades between 2 bots in order to increase \"Amount of trades done\"", 5 | "main": "index.js", 6 | "dependencies": { 7 | "steam-totp": "^2.1.1", 8 | "steam-tradeoffer-manager": "^2.10.2", 9 | "steam-user": "^4.19.3", 10 | "steamcommunity": "^3.42.0" 11 | }, 12 | "devDependencies": {}, 13 | "scripts": { 14 | "test": "node index" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/Gunthersuper/node-steam-trade-farm-replit.git" 19 | }, 20 | "author": "", 21 | "license": "ISC", 22 | "bugs": { 23 | "url": "https://github.com/Gunthersuper/node-steam-trade-farm-replit/issues" 24 | }, 25 | "homepage": "https://github.com/Gunthersuper/node-steam-trade-farm-replit#readme" 26 | } 27 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Please Read. 3 | * Google on how to get your shared_secret and identity secret. (You may have to use Steam SDA to get these codes.) 4 | * gameCode is the appId of the game. You can use any appId that you have current tradable items in. Please see below examples (YOU CANNOT USE CSGO) 5 | * TF2 = 440 6 | * Witch It = 559650 7 | * Use google to find more appIds. 8 | 9 | */ 10 | 11 | module.exports = { 12 | account1: { 13 | shared_secret: "randomStringOfChars418=", 14 | identity_secret: "randomStringOfChars21w=", 15 | username: "Robbie", 16 | password: "Password", 17 | tradelink: "https://steamcommunity.com/tradeoffer/new/?partner=202877252&token=04S9nN_6" 18 | }, 19 | account2: { 20 | shared_secret: "randomStringOfChars418=", 21 | identity_secret: "randomStringOfChars21w=", 22 | username: "Robbie", 23 | password: "Password", 24 | tradelink: "https://steamcommunity.com/tradeoffer/new/?partner=202877252&token=04S9nN_6" 25 | }, 26 | gameCode : 559650, 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | .DS_Store 61 | 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node.Js Steam Trade Farm for Replit 2 | 3 | ## Increase amount of "Trades Made" 4 | 5 | It's fork of https://github.com/RobertSkonieczny/node-steam-trade-farm 6 | 7 | ## Starting amount. 8 | ![Trades Made Example](https://gyazo.com/c90de4cbb61d720b458170475399728e.png) 9 | 10 | ## 8 hours later 11 | ![Trade Made Result Example](https://gyazo.com/f251d419d5eb64efa55791e9b8f17570.png) 12 | 13 | ## Features 14 | - Increase amount of trades made. (500+ Trades an hour!) 15 | - Automatically send trades from your main account and bot account. 16 | - Message security to ensure all trades accepted are secure and is from the other bot account. 17 | 18 | ## Installation Guide 19 | 20 | - Register repl.it account 21 | - Run on replit https://replit.com/new/github/Gunthersuper/node-steam-trade-farm-replit 22 | - You will be redirected to Replit, you might have to create an account (you can Register with Google). 23 | - Replit is a website, and does not run off your computer! 24 | - Edit this config for your accs: 25 | ``` 26 | "shared_secret1": "randomStringOfChars418=", 27 | "identity_secret1": "randomStringOfChars21w=", 28 | "username1": "Robbie", 29 | "password1": "Password", 30 | "tradelink1": "https://steamcommunity.com/tradeoffer/new/?partner=202877252&token=04S9nN_6", 31 | 32 | "shared_secret2": "randomStringOfChars418=", 33 | "identity_secret2": "randomStringOfChars21w=", 34 | "username2": "Robbie", 35 | "password2": "Password", 36 | "tradelink2": "https://steamcommunity.com/tradeoffer/new/?partner=202877252&token=04S9nN_6", 37 | 38 | "gameCode" : "440" 39 | ``` 40 | - `440` - Team Fortress 2, `304930` - Unturned (You must have some items in the inventory) 41 | 42 | - Go to secrets, Edit raw JSON. Paste your config. 43 | - Run the bot 44 | -------------------------------------------------------------------------------- /managers/SteamBotAccountManager.js: -------------------------------------------------------------------------------- 1 | const SteamInventoryItem = require('../response_models/SteamInventoryItem.js'); 2 | 3 | const GAME_CODE = process.env['gameCode']; 4 | 5 | class SteamBotAccountManager { 6 | constructor(client, community, tradeOfferManager ,credentials) { 7 | this.tradeOfferBot = tradeOfferManager; 8 | this.client = client; // Steam User 9 | this.community = community; 10 | this.inventory = []; 11 | this.credentials = credentials; 12 | } 13 | 14 | async getAndFetchInventory() { 15 | await this.#fetchInventory(); 16 | return this.inventory; 17 | } 18 | 19 | getTradeOfferBot() { 20 | return this.tradeOfferBot; 21 | } 22 | 23 | getSteamCommunity() { 24 | return this.community; 25 | } 26 | 27 | getClient() { 28 | return this.client; 29 | } 30 | 31 | async getFirstItemInInventory() { 32 | var inventoryItems = await this.getAndFetchInventory(); 33 | 34 | if (inventoryItems.length == 0) { 35 | throw new Error("Inventory for " + GAME_CODE + " appId is empty."); 36 | } 37 | 38 | return inventoryItems[0]; 39 | } 40 | 41 | async sendTradeOffer(tradelink, message, steamInventoryItemList, maxRetries) { 42 | return new Promise(async (resolve, reject) => { 43 | let offer = this.tradeOfferBot.createOffer(tradelink); 44 | offer.setMessage(message); 45 | 46 | // Add all items to the trade offer. 47 | steamInventoryItemList.forEach(item => offer.addMyItem(item.getRawData())); 48 | 49 | offer.send(async (err, status) => { 50 | if (err) { 51 | // Servers are non-consistant. Some trade offers can fail even though nothing is wrong with the trade offer. 52 | // So we cna use simple recursion to try to resend the offer. It will retry N amount of times before fully crashing. 53 | if (maxRetries <= 0) { 54 | this.printMessage('Error in the sendTradeOffer Function'); 55 | this.printMessage(err); 56 | return reject(err) 57 | } 58 | this.sendTradeOffer(tradelink, message, steamInventoryItemList, maxRetries-1) 59 | } else if (status == 'pending') { 60 | await this.#acceptConfirmation(offer); 61 | return resolve(1); 62 | } 63 | }); 64 | }); 65 | } 66 | 67 | async acceptIncomingSafeTradeOffer(offer, maxRetries) { 68 | return new Promise(async (resolve, reject) => { 69 | offer.accept((acceptanceErr) => { 70 | if (acceptanceErr) { 71 | if (maxRetries <= 0) { 72 | this.printMessage('Error in the sendTradeOffer Function'); 73 | this.printMessage(acceptanceErr); 74 | return reject(acceptanceErr) 75 | } 76 | this.acceptIncomingSafeTradeOffer(offer,maxRetries-1); 77 | } else { 78 | this.printMessage('Accepted trade'); 79 | return resolve(1); 80 | } 81 | }); 82 | }); 83 | } 84 | 85 | printMessage(message) { 86 | console.log("[" + this.credentials.getUsername() + "] " + message); 87 | } 88 | 89 | 90 | /* 91 | * Private Function 92 | */ 93 | async #fetchInventory() { 94 | this.inventory = await new Promise(async (resolve, reject) => { 95 | this.tradeOfferBot.getInventoryContents(GAME_CODE, 2, true, (err, inventory) => { 96 | if (err) { 97 | this.printMessage('Error in fetchInventory'); 98 | this.printMessage(err); 99 | return reject(err) 100 | } 101 | return resolve(inventory.map(item => new SteamInventoryItem(item))); 102 | }); 103 | }); 104 | } 105 | 106 | async #acceptConfirmation(offer) { 107 | return await new Promise(async (resolve, reject) => { 108 | this.community.acceptConfirmationForObject(this.credentials.getIdentitySecret(), offer.id, (err) => { 109 | this.printMessage(err); 110 | if (err) { 111 | this.printMessage('Error in acceptConfirmation'); 112 | this.printMessage(err); 113 | return reject(err); 114 | } else { 115 | return resolve(1); 116 | } 117 | }); 118 | }); 119 | } 120 | } 121 | 122 | module.exports = SteamBotAccountManager; 123 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const SteamUser = require('steam-user'); 2 | const SteamCommunity = require('steamcommunity'); 3 | const SteamTotp = require('steam-totp'); 4 | const keep_alive = require('./keep_alive.js') 5 | const SteamBotAccountManager = require('./managers/SteamBotAccountManager.js'); 6 | const SteamAccountCredentials = require('./utils/SteamAccountCredentials.js'); 7 | const SteamTradeOffer = require('./response_models/SteamTradeOffer.js'); 8 | const TradeOfferManager = require('steam-tradeoffer-manager'); 9 | 10 | const mainClient = new SteamUser(); 11 | const botClient = new SteamUser(); 12 | 13 | const account1Credentials = new SteamAccountCredentials(process.env['identity_secret1'], 14 | process.env['shared_secret1'], 15 | process.env['username1'], 16 | process.env['password1'], 17 | process.env['tradelink1'] 18 | ); 19 | 20 | const account2Credentials = new SteamAccountCredentials(process.env['identity_secret2'], 21 | process.env['shared_secret2'], 22 | process.env['username2'], 23 | process.env['password2'], 24 | process.env['tradelink2'] 25 | ); 26 | 27 | 28 | var mainCommunity = new SteamCommunity(); 29 | var botCommunity = new SteamCommunity(); 30 | 31 | const MAX_RETRIES = 5; 32 | 33 | var mainManager = new TradeOfferManager({ 34 | "steam": mainClient, // Polling every 30 seconds is fine since we get notifications from Steam 35 | "domain": "example.com", // Our domain is example.com 36 | "language": "en" // We want English item descriptions 37 | }); 38 | 39 | var botManager = new TradeOfferManager({ 40 | "steam": botClient, // Polling every 30 seconds is fine since we get notifications from Steam 41 | "domain": "example.com", // Our domain is example.com 42 | "language": "en" // We want English item descriptions 43 | }); 44 | 45 | const SECURITY_CODE = Math.floor((Math.random() * 99999) + 1); 46 | 47 | var account1 = new SteamBotAccountManager(mainClient, mainCommunity, mainManager, account1Credentials); 48 | var account2 = new SteamBotAccountManager(botClient, botCommunity, botManager, account2Credentials); 49 | 50 | try { 51 | account1.getClient().logOn({ 52 | "accountName": account1Credentials.getUsername(), 53 | "password": account1Credentials.getPassword(), 54 | "twoFactorCode": SteamTotp.generateAuthCode(account1Credentials.getSharedSecret()) 55 | }); 56 | 57 | account2.getClient().logOn({ 58 | "accountName": account2Credentials.getUsername(), 59 | "password": account2Credentials.getPassword(), 60 | "twoFactorCode": SteamTotp.generateAuthCode(account2Credentials.getSharedSecret()) 61 | }); 62 | } catch { 63 | console.log('Something went wrong with the signon process. If a steam guard message appeared try again in 1 minute If not ' + 64 | 'Your username, password, shared secret, or identity secret is incorrect and you need to update it in your config file (Please check for both account1 and account2)' 65 | ) 66 | } 67 | 68 | 69 | account1.getClient().on('loggedOn', () => { 70 | account1.printMessage('Logged in!'); 71 | }); 72 | 73 | account2.getClient().on('loggedOn', () => { 74 | account2.printMessage('Logged in!'); 75 | }); 76 | 77 | account2.getClient().on('webSession', async function(sessionID, cookies) { 78 | account2.getTradeOfferBot().setCookies(cookies); 79 | await account2.getSteamCommunity().setCookies(cookies); 80 | }); 81 | 82 | account1.getClient().on('webSession', async function(sessionID, cookies) { 83 | account1.getTradeOfferBot().setCookies(cookies); 84 | await account1.getSteamCommunity().setCookies(cookies); 85 | // Get the Item we want to trade. 86 | var targetItem = await account1.getFirstItemInInventory(); 87 | 88 | // Log the item we will be sending/receiving 89 | account1.printMessage("The item in which we are using is/an " + targetItem.getName()); 90 | 91 | // Send the trade offer. 92 | await account1.sendTradeOffer(account2Credentials.getTradelink(), SECURITY_CODE.toString(), [targetItem], MAX_RETRIES); 93 | }); 94 | 95 | account1.getTradeOfferBot().on('newOffer', async (offerResponse) => { 96 | account1.printMessage('RECEIVED TRADE OFFER'); 97 | var offer = new SteamTradeOffer(offerResponse, SECURITY_CODE); 98 | if (offer.isSafeTrade()) { 99 | account1.printMessage('Confirmed this is a safe trade, accepting the offer.'); 100 | await account1.acceptIncomingSafeTradeOffer(offerResponse,MAX_RETRIES); 101 | 102 | var newItem = await account1.getFirstItemInInventory(); 103 | 104 | account1.printMessage('Sending the offer with a ' + newItem.getName()); 105 | await account1.sendTradeOffer(account2Credentials.getTradelink(), SECURITY_CODE.toString(), [newItem], MAX_RETRIES); 106 | 107 | } else { 108 | account2.printMessage('Found unsafe trade'); 109 | } 110 | 111 | }); 112 | 113 | account2.getTradeOfferBot().on('newOffer', async (offerResponse) => { 114 | account2.printMessage('RECEIVED TRADE OFFER'); 115 | var offer = new SteamTradeOffer(offerResponse, SECURITY_CODE); 116 | if (offer.isSafeTrade()) { 117 | account2.printMessage('Confirmed this is a safe trade, accepting the offer.'); 118 | await account2.acceptIncomingSafeTradeOffer(offerResponse,MAX_RETRIES); 119 | 120 | var newItem = await account2.getFirstItemInInventory(); 121 | 122 | account1.printMessage('Sending the offer with a ' + newItem.getName()); 123 | await account2.sendTradeOffer(account1Credentials.getTradelink(), SECURITY_CODE.toString(), [newItem], MAX_RETRIES); 124 | } else { 125 | account2.printMessage('Found unsafe trade'); 126 | } 127 | }); 128 | --------------------------------------------------------------------------------