const axios = require('axios'); //used for getting api data, install with "yarn add axios"
const Web3 = require('web3'); //used for web3 functions, install with "yarn add web3"
const Common = require('ethereumjs-common').default;//used for creating custom chains, install with "yarn add '@ethereumjs/common@v2.2.0'"
let Tx = require('ethereumjs-tx').Transaction;
let ETHprovider = new Web3.providers.WebsocketProvider('wss://mainnet.infura.io/ws/v3/projectID')
let web3 = new Web3(ETHprovider);
let privateKey = Buffer.from('PRIVATE_KEY', 'hex');
const ADDRESS = 'ADDRESS';//your address
let callURL = 'https://api.1inch.exchange/v3.0/137/swap?fromTokenAddress=0x8f3cf7ad23cd3cadbd9735aff958023239c6a063&' +
'toTokenAddress=0x27f8d03b3a2196956ed754badc28d73be8830a6e&' +
'amount=10000000000000000000&fromAddress=' +
ADDRESS +
'&slippage=1';
let approveURL = 'https://api.1inch.exchange/v3.0/137/approve/calldata';
const ethereumMainnet = { 'chain': 'mainnet' }
async function driver() {
web3.eth.getBalance(ADDRESS)
.then(console.log);
globalData = await approveApiCaller(approveURL, 10000000000000000000, "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", "0xfe");
console.log(globalData);
console.log('Global Data done')
transaction = signTx(globalData); //sign the transaction with
console.log(transaction); //print the serialized transaction
console.log('Sign global data')
sendTransaction(transaction); //send the transaction
console.log('Send Transaction')
globalData = await apiCaller(callURL, '0xff'); //call the api to get the data, and wait until it returns
console.log('apiCaller')
console.log(globalData["tx"]); //log the data
transaction = signTx(globalData["tx"]); //sign the transaction
console.log(transaction);
console.log('send transaction');
sendTransaction(transaction); //send the transaction
console.log("transaction success");
}
/**
* Sends a transaction based on serialized data
* @param {the serialized transaction you want to send} tx
*/
function sendTransaction(tx) {
let temp = '0x' + tx.toString('hex'); //make the transaction into a hexadecimal string
web3.eth.sendSignedTransaction(temp)
.on('transactionHash', async function(hash){
console.log('transactionHash')
const status = await waitTransaction(hash);
console.log(hash)
})
.on('receipt', function(receipt){
console.log('transactionHash')
console.log(receipt)
})
.on('confirmation', function(confirmationNumber, receipt){
console.log('confirmation')
console.log(confirmationNumber)
console.log(receipt)
})
.on('error', function(error, receipt) {
console.log('error');
console.log(error);
console.log(receipt);
}); // If a out of gas error, the second parameter is the receipt.
}
/**
* Will sign a transaction with a private key based on the transaction data provided
* @param {the transaction you'd like signed} tx
* @returns serialized transaction
*/
function signTx(tx) {
let temp = new Tx(tx, ethereumMainnet);
//let temp = new Tx(tx, { common: ethereumMainnet });
temp.sign(privateKey);
console.log(temp);
return temp.serialize();
}
/**
* This will call the api to get an approve transaction, some tokens need to be approved to 0 before increasing again later
* @param {the url used to access the } url
* @param {the number of tokens that are requested to be unlocked, if "null" infinite will be unlocked } value
* @param {the token address of what tokens needs to be unlocked} tokenAddress
* @param {the nonce of the transaction} nonce
* @returns approve transaction
*/
async function approveApiCaller(url, value, tokenAddress, nonce) {
url += (value > -1 || value != null ? "?amount=" + value + "&" : "") //tack on the value if it's greater than -1
+ "tokenAddress=" + tokenAddress //complete the called URL
console.log(url);
let temp = await axios.get(url); //wait for the request to be complete
temp = temp.data; //we only want the data object from the api call
//we need to convert the gas price to hex
let gasPrice = parseInt(temp["gasPrice"]);
console.log(gasPrice)
gasPrice = '0x' + gasPrice.toString(16); //convert to hexadecimal string
temp["value"] = "0x" + temp["value"]; //convert value to hecadecimal
temp["gasPrice"] = gasPrice; //change the gas price in the tx object
temp["gas"] = "0xc350"; //gas limit of 50,000, may need to be higher for certain tokens
temp["from"] = ADDRESS;
temp["nonce"] = nonce;
console.log(temp);
return temp;
}
/**
* Will call the api and return the data needed
* @param {the url of what api call you want} url
* @param {the nonce of the transaction, the user must keep track of this} nonce
* @returns swap transaction
*/
async function apiCaller(url, nonce) {
let temp = await axios.get(url); //get the api call
temp = temp.data; //we only want the data object from the api call
//we need to convert the gasPrice to hex
let gasPrice = parseInt(temp.tx["gasPrice"]); //get the gasPrice from the tx
gasPrice = '0x' + gasPrice.toString(16); //add a leading 0x after converting from decimal to hexadecimal
temp.tx["gasPrice"] = gasPrice; //set the value of gasPrice in the transaction object
//we also need value in the form of hex
let value = parseInt(temp.tx["value"]); //get the value from the transaction
value = '0x' + value.toString(16); //add a leading 0x after converting from decimal to hexadecimal
temp.tx["value"] = value; //set the value of value in the transaction object
temp.tx["nonce"] = nonce;
console.log(temp); //it's the users responsibility to keep track of the nonce
return temp; //return the data
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function waitTransaction(txHash) {
let tx = null;
while (tx == null) {
tx = await web3.eth.getTransactionReceipt(txHash);
await sleep(2000);
}
console.log("Transaction " + txHash + " was mined.");
return (tx.status);
}
driver();
Sorry guys, I needed some help badly. With the provided code, I am getting Transaction was not mined within 50 blocks, please make sure your transaction was properly sent. Be aware that it might still be mined! Sometime I get transaction underpriced. Can someone help me on this issue?