I am trying to make a Dapp which maintains the various versions of a trade(new versions are created when we update the data of trade). I am using javascript we3.js api to call my solidity functions through javascript. I have a function which displays the data when we search using a field called 'client'. When I am clicking the button to search on basis of client, it returns an error. I am using promises in javascript, but it seems to me that the javascript function is returning a promise which is undefined to solidity function. But after the error the javascript function is returning the expected values(I checked using console.log).
I have tried using async/await but that doesnt seems to do the trick.
My Javascript code:-
getVersion:async function(i){
var returnedLatestVersion;
App.contracts.Trades.deployed().then(async function(instance){
await instance.getLatestVersionOfTrade.call(i).then(function(a){
returnedLatestVersion = a;
console.log("test:"+returnedLatestVersion+",a:"+a);
}).catch(function(err){
console.log(err)
})
console.log("test2="+returnedLatestVersion);
return await returnedLatestVersion;
})
},
searchByClient: function(){
var tradesInstance;
var client = $('#clientSearch').val();
var tradeResults = $("#tradesResult");
tradeResults.empty();
App.contracts.Trades.deployed().then(function(instance){
tradesInstance = instance;
return tradesInstance.getClientData.call(client).then(async function(returnValues){
console.log("returnValues Array = "+returnValues);
var returnValuesLength = returnValues.length;
for(var i=0;i<returnValuesLength;i++){
var a = returnValues[i];
var c = returnValues[i];
var j;
j = await App.getVersion(a);
console.log("version ="+j);
console.log("tradeId="+a);
tradesInstance.trades(c,j).then(function(trade){
var secId = trade[0];
var notional = trade [1];
var price = trade[2];
var client = trade[3];
var tradeTemplate = "<tr><td>" + secId + "</td><td>" + notional + "</td><td>" + price + "</td><td>" + client +"</td></tr>"
tradeResults.append(tradeTemplate);
})
}
}).catch(function(err){
console.log(err);
})
}).catch(function(err){
console.warn(err);
})
}
};
My Smart Contract :-
pragma solidity 0.5.0;
contract Trades {
struct Trade {
string secId;
uint notional;
uint price;
string client;
uint version;
uint index;
uint tradeId;
}
mapping(uint =>mapping(uint => Trade)) public trades;
uint public tradeId;
uint[] tradeIndex;
uint[] tradeID;
uint[] public totalNum;
function updateTrade(uint _tradeId, string memory _secId,uint _notional,uint _price,string memory _client) public{
uint j;
j= (getLatestVersionOfTrade(_tradeId)) + 1;
trades[_tradeId][j].secId = _secId;
trades[_tradeId][j].notional = _notional;
trades[_tradeId][j].price = _price;
trades[_tradeId][j].client = _client;
trades[_tradeId][j].version = j;
trades[_tradeId][j].index = tradeIndex.push(tradeIndex[tradeIndex.length-1]+1);
}
function setTrade(string memory _secId,uint _notional,uint _price,string memory _client) public {
uint version = 0;
tradeId++;
trades[tradeId][version].secId = _secId;
trades[tradeId][version].notional = _notional;
trades[tradeId][version].price = _price;
trades[tradeId][version].client = _client;
trades[tradeId][version].version = version;
trades[tradeId][version].index = tradeIndex.push(tradeId);
tradeID.push(tradeId);
}
function getAllTradeData()view public returns(uint[] memory){
return tradeIndex;
}
function getAllTradeDataId()view public returns(uint[] memory){
return tradeID;
}
function getTradeById(uint _tradeId,uint version)view public returns(string memory, uint, uint, string memory, uint, uint){
return (trades[_tradeId][version].secId, trades[_tradeId][version].notional, trades[_tradeId][version].price,
trades[_tradeId][version].client,trades[_tradeId][version].version, trades[_tradeId][version].index);
}
function getLatestVersionOfTrade(uint _tradeId) view public returns (uint) {
uint max = 0;
for (uint i = 0; i < tradeIndex.length; i++) {
uint ver = trades[_tradeId][i].version;
if (ver > max) {
max = ver;
}
}
return max;
}
function getClientData(string memory _client) public returns (uint[] memory) {
if (totalNum.length > 0){
delete totalNum;
}
for(uint i=1; i <= tradeID.length;i++){
uint j;
j= (getLatestVersionOfTrade(i));
if(uint(keccak256(abi.encodePacked(trades[i][j].client))) == uint(keccak256(abi.encodePacked(_client)))){
totalNum.push(i);
}
}
return totalNum;
}
function getTotalNumLength() public returns (uint){
return totalNum.length;
}
}
The error shown on brower console : -
returnValues Array = 3,4,5
app.js:113 version =undefined
app.js:114 tradeId=3
app.js:113 version =undefined
app.js:114 tradeId=4
app.js:113 version =undefined
app.js:114 tradeId=5
3inpage.js:1 Uncaught (in promise) Error: Invalid number of arguments to
Solidity function
at Object.InvalidNumberOfSolidityArgs (inpage.js:1)
at u.validateArgs (inpage.js:1)
at u.toPayload (inpage.js:1)
at u.call (inpage.js:1)
at u.execute (inpage.js:1)
at truffle-contract.js:136
at new Promise (<anonymous>)
at truffle-contract.js:127
app.js:77 test:0,a:0
app.js:82 test2=0
app.js:77 test:0,a:0
app.js:82 test2=0
app.js:77 test:1,a:1
app.js:82 test2=1
The variable 'j' in searchByClient is returning an undefined value when it is passed in 'trades(c,j)'. But in the function getVersion the value returning seems to be fine. Please help me out as I have no other options left. Also I am extremly new to javascript, so please do tell me if I had make any mistakes. I was able to write this code with help of a tutorial.
Try to modify getVersion
like this:
getVersion:async function(i){
var returnedLatestVersion;
return new Promise((resolve, reject) => {
App.contracts.Trades.deployed().then(async function(instance){
await instance.getLatestVersionOfTrade.call(i).then(function(a){
returnedLatestVersion = a;
console.log("test:"+returnedLatestVersion+",a:"+a);
resolve(returnedLatestVersion); // here you return your result as a promise
}).catch(function(err){
console.log(err)
reject(err); // here you reject the promise in case of error
})
console.log("test2="+returnedLatestVersion);
})
})
}
You can also return the result of instance.getLatestVersionOfTrade.call(i)` and this will return a promise as well. But I think using resolve makes it a little more clear what exactly it is that you are returning.