0

My use case is that I have to invoke a contract function when an API is called.

Now I have tried multiple ways, but I have issues with both. My function name is "transfer".

Method - I

In this method I first unlock the account of the user. Then invoke the contract function by contractInstance.methodName(). In the callback method, I lock the account again

Issue: The issue I see here is, when I get multiple calls to my api at the same time, it will cause an issue. As one call might lock the account just when one more thread is trying to invoke the function.

/ * Getting the contract Instance */

import Web3 from 'web3';
  const tokenABI = require('../ContractABI.json');

  if (typeof web3 !== 'undefined') {
    var web3 = new Web3(web3.currentProvider)
} else {
    var web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:8545'))
}

var TokenContract = web3.eth.contract(tokenABI.abi);
var tokenInstance = TokenContract.at(contractConfig.id);

/ * Getting the contract Instance */

router.post('/transferTokens',async (req,res,next)=>{
    let senderAddress = req.param("sender");
    let receiverAddress = req.param("receiver");
    let transferAmount = req.param("amount");

    let searchCriteria = {
        address:senderAddress
    }

    try{
        // Getting the private key of the user from DB.

        let senderDetails = await MongoHelper.findOneByCriteria('accounts',searchCriteria);
        console.log('senderDetails:',senderDetails);

        let chk = web3.personal.unlockAccount(senderDetails.address, senderDetails.pwd, 95000);

        // Unlocked the account and then invoke the transfer function with the necessary parameters.

        tokenInstance.transfer(receiverAddress, transferAmount, { from: senderDetails.address })
        .then(function (msg) {
            res.data = msg;
            let chk = web3.personal.lockAccount(senderDetails.address);
            next();

        }).catch(function (e) {
            console.log('Error %%%%%%%%%%%%%%%%%',e);
            let chk = web3.personal.lockAccount(senderDetails.address);
            next(e)

        });

    }catch(err){
        console.log(' Error err:',err);
        next(err);
    }

});

Method - II

**In this method, I am deriving the callData for my contract function. I am creating a Raw Transaction Object. I am signing it with the user's private key. Then I am using web3.eth.sendRawTransaction to send the transaction **

Issue: The issue i am facing is: I see a transaction is created. But it is not doing what it should do ideally. It is just a dummy transaction. The contract method is not getting invoked. I guess the call data is not proper or something.

I see the calldata something similar to below: 0xb7184b680000000000000000000000000000000000000000000000000000000000000578

router.post('/transferTokens2',async (req,res,next)=>{
    let senderAddress = req.param("sender");
    let receiverAddress = req.param("receiver");
    let transferAmount = req.param("amount");

    let searchCriteria = {
        address:senderAddress
    }

    try{
        let senderDetails = await MongoHelper.findOneByCriteria('accounts',searchCriteria);
        let callData = tokenInstance.transfer.getData(receiverAddress,transferAmount);

        let rawTx = {
            from:senderAddress,
            nonce: 93,
            gasPrice: '0x4a817c800', // eth_estimateGas rpc result
            gasLimit: '0x2fd618',
            to:receiverAddress,
            data:callData 
        }
        var privateKey = new Buffer(senderDetails.key, 'hex')

        var tx = new Tx(rawTx);
        tx.sign(privateKey);

        var serializedTx = tx.serialize();

        web3.eth.sendRawTransaction('0x'+ serializedTx.toString('hex'), function(err, hash) {
            if (!err) {
                console.log('$$$$$:',hash); 
                res.data = hash;
                next();
            }else{
                next(err);
            }   
        });

    }catch(err){
        next(err);
    }

});
1

For method 1) you have to serialize access to the account unlock/lock. You can use semaphore to limit to a single operation at any time.

For method 2) you have hardcoded the nonce. You have to calculate before each transaction var nonce = web3.eth.getTransactionCount(<address>). Beware that a nonce are consecutive numbers without repetitions. You also have to guarantee each nonce is used only once.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.