Search code examples
javascriptweb3jsthundercore

How do I send transactions and transfer TT on ThunderCore mainnet?


Without using ThunderCore Hub or any Web3 wallet which supports Thunder Token, how could I programmatically send transactions or transfer Thunder Tokens?


Solution

  • To send a transaction on Thundercore, set these fields in the transaction:

    See the submitTx method in the following code:

    transfer.js

    const fs = require('fs');
    const path = require('path');
    
    const Accounts = require('web3-eth-accounts');
    const Eth = require('web3-eth');
    const Web3 = require('web3');
    const BN = Web3.utils.BN;
    
    const pretty = require('./pretty');
    const erc20Abi = require('./ERC20.abi.json');
    
    const web3Provider = () => {
      return Eth.giveProvider || 'https://mainnet-rpc.thundercore.com';
    }
    
    const signTx = async (fromAccount, tx) => {
      const signedTx = await fromAccount.signTransaction(tx)
      return signedTx.rawTransaction // hex string
    }
    
    class ChainHelper {
      constructor(eth, chainId, fromAccount) {
        this.eth = eth;
        this.chainId = chainId;
        this.fromAccount = fromAccount;
        this.fromAddress = fromAccount.address;
      }
      async submitTx(toAddress, value, txData) {
        const eth = this.eth;
        const promiseResults = await Promise.all([
          eth.getTransactionCount(this.fromAccount.address),
          eth.getGasPrice(),
        ]);
        const nonce = promiseResults[0];
        const gasPrice = promiseResults[1];
        const fromAddress = this.fromAddress;
        const tx = {
          'gasLimit': 0,
          'chainId': this.chainId,
          'gasPrice': gasPrice,
          'nonce': nonce,
          'from': fromAddress,
          'to': toAddress,
          'value': value,
          'data': txData,
        }
        const gasMultiple = new BN(1.0);
        tx.gasLimit = '0x' + (new BN(await eth.estimateGas(tx))).mul(gasMultiple).toString(16);
        console.log('tx:', pretty.format(tx));
        const rawTxStr = await signTx(this.fromAccount, tx);
        return eth.sendSignedTransaction(rawTxStr);
      }
      async transferToken (contractAddress, toAddress, value) {
        const eth = this.eth;
        const contractAbi = erc20Abi;
        const contract = new eth.Contract(contractAbi, contractAddress);
        const txData = contract.methods.transfer(toAddress, value).encodeABI();
        return this.submitTx(contractAddress, 0, txData);
      }
    }
    
    const create = async (privateKey) => {
      const accounts = new Accounts();
      if (!privateKey.startsWith('0x')) {
        privateKey = '0x' + privateKey;
      }
      const account = accounts.privateKeyToAccount(privateKey);
      const eth = new Eth(web3Provider());
      const networkId = await eth.net.getId();
      return new ChainHelper(eth, networkId, account);
    }
    
    const readKeys = () => {
      const privateKeys = fs.readFileSync(path.join(__dirname, '..', '.private-keys'),
      {encoding: 'ascii'}).split('\n').filter(x => x.length > 0);
      return privateKeys;
    }
    
    module.exports = {
      create: create,
      readKeys: readKeys,
    };
    

    testTransfer.js

    const fs = require('fs');
    const path = require('path');
    const ChainHelper = require('../src/transfer.js');
    
    const toAddress = '0x6f0d809e0fa6650460324f26df239bde6c004ecf';
    
    describe('transfer', () => {
      it('transfer TT', async() => {
        const privateKey = ChainHelper.readKeys()[0]
        const c = await ChainHelper.create(privateKey);
        c.submitTx(toAddress, 1, '');
      });
      it('tokenTransfer', async() => {
        const privateKey = ChainHelper.readKeys()[0]
        const c = await ChainHelper.create(privateKey);
        /* Token.issue() */
        const jsonBuf = fs.readFileSync(path.join(__dirname, '..', 'build', 'contracts', 'Token.json'));
        const contractData = JSON.parse(jsonBuf);
        const contractAbi = contractData['abi'];
        const contractAddress = contractData['networks'][c.chainId]['address'];
        const contract = new c.eth.Contract(contractAbi, contractAddress);
        const toAddress = c.fromAddress;
        const tokenAmount = 2;
        let txData = contract.methods.issue(tokenAmount, c.fromAddress).encodeABI();
        let r = await c.submitTx(toAddress, 0, txData);
        console.log('Token.issue receipt:', r);
        /* Token.transfer() */
        r = await c.transferToken(contractAddress, toAddress, tokenAmount)
        console.log('Token.transfer receipt:', r);
      });
    });
    

    The code above targets the command line or server-side node.js, to send transactions from a browser replace signTx and eth.sendSignedTransaction with web3.eth.sendTransaction

    The complete example is in the transfer branch of this field-support repo.