exports.newWeb3Server = function newWeb3Server() { const MODULE = "Web3 Server" let thisObject = { getNetworkClientStatus: getNetworkClientStatus, createWalletAccount: createWalletAccount, getWalletBalances: getWalletBalances, signData: signData, recoverAddress: recoverAddress, mnemonicToPrivateKey: mnemonicToPrivateKey, payContributors: payContributors, initialize: initialize, finalize: finalize, run: run } const Web3 = SA.nodeModules.web3 let web3Map = new Map() return thisObject function finalize() { web3Map = undefined } function initialize() { } function run() { } async function getNetworkClientStatus(host, port, interface) { let key = 'host (' + host + ') at port (' + port + ') via interface (' + interface + ')' try { let web3 = web3Map.get(key) if (web3 === undefined) { /* This means that we never got connected to this client before */ let web3 = await connectToClient(key, host, port, interface) if (web3.error !== undefined) { return web3 } return await returnStatus(web3) } else { return await returnStatus(web3) } async function returnStatus(web3) { let status = {} status.isSyncing = await web3.eth.isSyncing() status.chainId = await web3.eth.getChainId() status.currentBlockNumber = await web3.eth.getBlockNumber() status.result = 'Ok' return status } } catch (err) { return { error: 'Could not connect to ' + key + '. ' + err.stack + '.' } } } async function createWalletAccount(entropy) { try { let web3 = new Web3() let account = web3.eth.accounts.create() return { address: account.address, privateKey: account.privateKey, result: 'Ok' } } catch (err) { return { error: 'Could not create the account. ' + err.stack } } } async function getWalletBalances(host, port, interface, walletDefinition) { let key = 'host (' + host + ') at port (' + port + ') via interface (' + interface + ')' try { let web3 = web3Map.get(key) if (web3 === undefined) { /* This means that we never got connected to this client before */ let web3 = await connectToClient(key, host, port, interface) if (web3.error !== undefined) { return web3 } return await returnAccountBalances(web3) } else { return await returnAccountBalances(web3) } async function returnAccountBalances(web3) { let responseData = {} for (let i = 0; i < walletDefinition.walletAccounts.length; i++) { let walletAccount = walletDefinition.walletAccounts[i] if (walletAccount.ethBalance !== undefined) { try { walletAccount.ethBalance.value = await web3.eth.getBalance(walletAccount.config.address) } catch (err) { if (err.message.indexOf('Provided address') >= 0) { walletAccount.error = 'Invalid configured address.' } else { walletAccount.error = err.message } } } for (let j = 0; j < walletAccount.tokenBalances.length; j++) { let tokenBalance = walletAccount.tokenBalances[j] if (tokenBalance.referenceParent === undefined) { continue } if (tokenBalance.referenceParent.parentNode === undefined) { continue } if (tokenBalance.referenceParent.smartContracts === undefined) { continue } if (tokenBalance.referenceParent.config.codeName === undefined) { tokenBalance.error = 'Reference Parent without config.codeName defined.' continue } if (tokenBalance.referenceParent.smartContracts.config.address === undefined) { tokenBalance.error = 'Reference Parent Smart Contract without config.address defined.' continue } let tokenContractAddress = tokenBalance.referenceParent.smartContracts.config.address // The minimum ABI to get ERC20 Token balance let minABI = [ // balanceOf { "constant": true, "inputs": [{ "name": "_owner", "type": "address" }], "name": "balanceOf", "outputs": [{ "name": "balance", "type": "uint256" }], "type": "function" }, // decimals { "constant": true, "inputs": [], "name": "decimals", "outputs": [{ "name": "", "type": "uint8" }], "type": "function" } ]; let contract = new web3.eth.Contract(minABI, tokenContractAddress); try { tokenBalance.value = await contract.methods.balanceOf(walletAccount.config.address).call() } catch (err) { if (err.message.indexOf('Provided address') >= 0) { walletAccount.error = 'Invalid configured address.' } else { walletAccount.error = err.message } } } } responseData.result = 'Ok' responseData.walletDefinition = walletDefinition return responseData } } catch (err) { return { error: 'Could not connect to ' + key + '. ' + err.stack + '.' } } } async function connectToClient(key, host, port, interface) { let web3 switch (interface) { case 'ws': { web3 = new Web3('ws://' + host + ':' + port + ''); break } case 'http': { web3 = new Web3('http://' + host + ':' + port + ''); break } default: { return { error: 'Interface parameter must be either ws or http. Received ' + interface } } } return await testConnection() async function testConnection() { let accounts = await web3.eth.getAccounts() if (web3.currentProvider.connected === false) { return { error: 'Connection to ' + key + ' could not be established.' } } else { web3Map.set(key, web3) return web3 } } } async function signData(privateKey, data) { try { let web3 = new Web3() let signature = web3.eth.accounts.sign(data, privateKey) return { signature: signature, result: 'Ok' } } catch (err) { return { error: 'Could not sign the data. ' + err.stack } } } async function recoverAddress(signature) { try { let signatureObject = JSON.parse(signature) let web3 = new Web3() let address = web3.eth.accounts.recover(signatureObject) return { address: address, result: 'Ok' } } catch (err) { return { error: 'Could not recover address. ' + err.stack } } } async function mnemonicToPrivateKey(mnemonic) { try { const ethers = SA.nodeModules.ethers let wallet = ethers.Wallet.fromMnemonic(mnemonic) if (wallet.privateKey !== undefined) { return { address: wallet.address, privateKey: wallet.privateKey, result: 'Ok' } } else { return { address: undefined, privateKey: undefined, result: 'Fail' } } } catch (err) { return { error: 'Could not convert to Private Key. ' + err.stack } } } async function payContributors(contractAddress, contractAbi, paymentsArray, mnemonic) { try { let response = await mnemonicToPrivateKey(mnemonic) let privateKey = response.privateKey for (let i = 0; i < paymentsArray.length; i++) { await CL.projects.foundations.utilities.asyncFunctions.sleep(10000) let payment = paymentsArray[i] sendTokens( i + 1, payment.userProfile, payment.from, payment.to, payment.amount ) } async function sendTokens(number, userProfile, fromAddress, toAddress, tokenAmount) { try { console.log('') console.log('---------------------------------------------------------------------------------------------------------------------------------------------------') console.log(' Payment # ' + number + ' - User Profile: ' + userProfile + ' - SA Tokens Amount: ' + tokenAmount / 1000000000000000000 + ' - Address: ' + toAddress) console.log('---------------------------------------------------------------------------------------------------------------------------------------------------') console.log('') const Tx = SA.nodeModules.ethereumjsTx.Transaction; const web3 = new Web3(new Web3.providers.HttpProvider('https://bsc-dataseed.binance.org/')) const amount = web3.utils.toHex(tokenAmount) privateKey = privateKey.replace('0x', '') const privateKeyBuffer = Buffer.from(privateKey, 'hex') const contractAbiObject = JSON.parse(contractAbi) const contract = new web3.eth.Contract(contractAbiObject, contractAddress, { from: fromAddress }) const Common = SA.nodeModules.ethereumjsCommon.default const BSC_FORK = Common.forCustomChain( 'mainnet', { name: 'Binance Smart Chain Mainnet', networkId: 56, chainId: 56, url: 'https://bsc-dataseed.binance.org/' }, 'istanbul', ); const nonce = await web3.eth.getTransactionCount(fromAddress); const rawTransaction = { "from": fromAddress, "gasPrice": web3.utils.toHex(5000000000), "gasLimit": web3.utils.toHex(210000), "to": contractAddress, "value": "0x0", "data": contract.methods.transfer(toAddress, amount).encodeABI(), "nonce": web3.utils.toHex(nonce) }; const transaction = new Tx(rawTransaction, { 'common': BSC_FORK }) transaction.sign(privateKeyBuffer) console.log('Transaction:', rawTransaction) const result = await web3.eth.sendSignedTransaction('0x' + transaction.serialize().toString('hex')) console.log('Result:', result) return result } catch (err) { console.log('[ERROR] web3Server -> sendTokens -> err.stack = ' + err.stack) } } return { address: wallet.address, privateKey: wallet.privateKey, result: 'Ok' } } catch (err) { return { error: 'Could not convert to Private Key. ' + err.stack } } } }