Why is .call() necessary when I want to see returned values from a smart contract function? - solidity

In my contract I have this function (solc 0.8.4):
function makeDecision(address person) external returns (string memory name, bool approved) {
require(msg.sender == loanOfficer, "Only the loan officer can initiate a decision.");
require(bytes(applicants[person].name).length != 0, "That person is not in the pool of applicants.");
if (applicants[person].credScore > 650 && applicants[person].credAge > 5) {
applicants[person].approved = true;
}
return (applicants[person].name, applicants[person].approved);
}
When I go into my truffle console and call my function this way loanContract.makeDecision(accounts[1]) everything works fine, but I get a tx receipt as the response.
When I call my function this way via truffle console loanContract.makeDecision.call(accounts[1]) I get the expected response from my function. I am wanting an explanation that tells me why this difference in response occurs so that I understand what is going on on a deeper level. I hate using things without understanding why they work.
If it helps, my contract (which is named LoanDisbursement) was initialized in the console like so: let loanContract = await LoanDisbursement.deployed() and my accounts variable: let accounts = await web3.eth.getAccounts()
any tips would help since I am still learning and diving into this ecosystem. I've not been able to find any decent documentation on this functionality as of yet. Thanks.

Truffle contract functions create a transaction - and return the transaction data.
The call function doesn't create a transaction, it just makes a call. So it cannot return transaction receipt and the authors of Truffle decided to return the function value instead.
Without transaction, the state of your contract is not changed. Which is probably not what you want, and you should always create a transaction when you need to save state changes to the blockchain.
Truffle doesn't return the function value when you're creating a transaction. Using Truffle, there are two approaches that they recommend:
Reading event logs that the transaction produced
Add an event to your function emit MadeDecision(applicants[person].name, applicants[person].approved);, and then access it in your JS code in result.logs.
Calling a getter in a subsequent call.
Tx setValue(5) and then call getValue(). Or in your case:
Tx makeDecision(0x123) and then call applicants[0x123] (assuming applicants is public).

Related

What is the input data on bsc scan?

I am developing NFT marketplace.
I have written a smart contract and passed tests using test scripts without any issue.
But when I tried to interact with my smart contract in Frontend code, I have met the error.
Here is my transaction on testnet.
https://testnet.bscscan.com/tx/0x7876b914f4417d89633a5a491bc3526e8d13a7595bb8679944b060f5b22e4a07
I have found some input data there.
Here is my contract.
function updatePrice(uint256 _elpisHeroId, uint256 _newPrice)
public
isApproved(_elpisHeroId)
{
require(_newPrice > 0, "Price should be greater than zero");
/// Identify elpisHero's index. It is the same as tokenId
uint256 elpisHeroIndex = _elpisHeroId;
/// Update metadata of a elpisHero
ElpisHeroData storage elpisHeroData = elpisHeroesData[elpisHeroIndex];
elpisHeroData.heroPrice = _newPrice;
}
As you can see in my contract, there are two parameters, _elpisHeroId, _newPrice, not _bnbPrice, _tokenPrice.
I wonder why this happens. Where do those parameters come from?

Just got scammed in a honeypot, which part of the code was it?

I just want to know which part of the code was the thing to look after next time to save my ass from getting scammed.
Code: https://bscscan.com/address/0x31d9bb2d2e971f0f2832b32f942828e1f5d82bf9#code
Only the owner of the token was able to sell, no one else. No liquidity pull.
Thank you so much.
Line 277:
require(balances1 || _balances1[sender] , "ERC20: transfer to the zero address");
balances1 is a bool
_balances1 is a mapping (address => bool)
Values of these properties are controllable only by the owner - in functions Renounce, Prize_Fund, and Reflections.
At least one of them needs to be true in order to pass the require() condition.
Without the state of the blockchain in the moment of your transaction (and your transaction details), I can't say it for sure - but it's likely that the balances1 was false, and _balances1[sender] was true only for an authorized (possibly scammer) address.
Which would effectively disallow transfers from anyone except this address.
Also, the transactions list supports my findings. Each of the Transfer events fail with this error message. And it's covered by many Approval events - possibly to not be suspicious (all transactions failed) at the first look.
Both burnAddress and charityAddress are the same address, defined early in the code sample:
address payable public charityAddress = payable(0x000000000000000000000000000000000000dEaD); // Marketing Address
address public immutable burnAddress = 0x000000000000000000000000000000000000dEaD;
The actual sending part can be found on the emit statement, that will emit the transaction to the blockchain:
emit Transfer(address(this), msg.sender, _totalSupply);
This is the constructor, so when the contract is loaded, the only path for it is by the sender, to "this" address, which is the hardcoded one, from any "sender" that bought in.

Difference between EnsureSuccessStatusCode and Assert.Equal(HttpStatusCode.OK, response.StatusCode) in XUnit ASP.Net Core WebAPI Tests

I read in a Book (ISBN 1838550313, 9781838550318 S.315) that they check a WEB-API Request with both EnsureSuccessStatusCode() and Assert.Equal(HttpStatusCode.OK, ..) in one validation Method. But is the second Assert call not unnecessary to check if the HTTP-Status is 200 or not? What is the difference and what is the best practice?
HttpResponseMessage.EnsureSuccessStatusCode is implemented like this:
public HttpResponseMessage EnsureSuccessStatusCode()
{
if (!IsSuccessStatusCode)
{
throw new HttpRequestException(…, inner: null, _statusCode);
}
return this;
}
So it just checks the value of IsSuccessStatusCode which is implemented like this:
public bool IsSuccessStatusCode
{
get { return ((int)_statusCode >= 200) && ((int)_statusCode <= 299); }
}
So a status code is considered to be successful, if it is in the range [200, 299]. This matches the definition of the HTTP status codes.
If the status code value is not a successful code, then the EnsureSuccessStatusCode method will throw an exception. So it is a quick way to stop the execution in cases where the request failed.
Asserting for equality with HttpStatusCode.OK checks if the status code is exactly 200. This also means that other successful codes would be rejected. Whether that is an appropriate thing to do depends on the API you are testing. Many RESTful APIs will often return different successful status codes depending on what happened. For example, an API might return “201 Created” to express that a resource has been created.
If the test wants to explicitly ensure that the response has a status code “200 OK”, then calling EnsureSuccessStatusCode is not needed. Otherwise, if you want to accept any successful status code, just calling EnsureSuccessStatusCode will be enough for the test since a thrown exception will usually fail the test.

How to test contract with multiple accounts / addresses in truffle?

I want to test my truffle contract with multiple msg.sender addresses. Like "the first user sell token, the second user buys this token". For one address I simply write something like contract.buy.value(10 wei)();. But where I could get another address and how to send money from him?
I write my tests on solidity, not on javascript.
as you can see in the Truffle docs, you can specify two different accounts to interact with your deployed smart contract like below (Metacoin example):
var account_one = "0x1234..."; // an address
var account_two = "0xabcd..."; // another address
var meta;
MetaCoin.deployed().then(function(instance) {
meta = instance;
return meta.sendCoin(account_two, 10, {from: account_one});
}).then(function(result) {
// If this callback is called, the transaction was successfully processed.
alert("Transaction successful!")
}).catch(function(e) {
// There was an error! Handle it.
})
This is about how you can do with your own created token.
If you want to transfer Ether between accounts, you can specify accounts in your truffle execution file (a javascript file). And these accounts may come from your configured local blockchain (Ganache, if you are using Truffle Suite to test your smart contract, it will provide you with several accounts and you can configure these by yourself).
Moreover, you may need javascript API to specify the sender and receiver: web3.eth.sendTransaction.
First time to answer a question, hope this will help.

Wit.ai seems to be jumping randomly between stories

I have two separate simple stories on my Wit.ai bot,
the first one takes in the word "Debug", sends "test" then runs a function that outputs context stuff to the console called test_context()
the second one takes in an address, runs a function that changes the context called new_session(), then sends a confirmation of the change to the user structured like "your location has been changed to {address}"
when I type directly into the wit.ai test console it seems to correctly detect the stories and run the corresponding functions, but when I try to use it through the Node.js API it seems to act completely randomly.
Sometimes when typing in an address it will run test_context() followed by new_session(), then output no text, sometimes it will just output the test text followed by the address text and run no functions, sometimes it will act correctly.
The same behavior happens when inputting "Debug" as well.
The back end is set up correctly, as 2 other stories seem to be working perfectly fine.
Both of these stories were working fine earlier today, I have made no changes to the wit stories themselves and no change to the back-end has even touched the debug function.
Is this a known issue?
I encountered this problem as well.
It appears to me as when you do not handle setting context variables in the story from wit.ai correctly (by setting them to null for example), it messes up the story. As a developer it is your own responsability to handle the story correctly "client side", so I can understand wit.ai lets weird stuff happen when you do not do this. Maybe wit.ai decided to jump stories to keep their bot from crashing, still remains a bit mysterious to me. Maybe your problem is of a different kind, just sharing a similair observation and my solution.
Exactly for reasons of testing I created three stories;
handle greetings
tell what the weather in city x is
identify when you want to plan a meeting
The bot is connected to facebook and I handle actions (like planning a meeting) on my nodejs express server.
I said to the bot "I want to plan a meeting tomorrow", resulting in a wit date/time. One timeslot by the way. This is going ok. Then I sent the message "I want to plan a meeting this morning". This resulted in TWO date/time variables in the wit.ai context. In turn, my code could not handle this; two timestamps resulted in null (probably json message getting more complicated and I try to get the wrong field). This in turn resulted in null for the context variable that had to be returned.
So what I did is to catch the error for when the context variable is not filled and just fill in [wit.js could not find date]. This fixed the problem, even though I now of course need to handle this error better.
Old code:
'createAppointment': ({sessionId, context, text, entities}) => {
return new Promise(function(resolve, reject) {
const myDateTime = firstEntityValue(entities, 'datetime');
console.log('the time trying to send ',myDateTime);
createAppointment(context, myDateTime)
context.appointmentText = myDateTime
return resolve(context);
},}
New, working code:
'createAppointment': ({sessionId, context, text, entities}) => {
return new Promise(function(resolve, reject) {
const myDateTime = firstEntityValue(entities, 'datetime');
console.log('the time trying to send ',myDateTime);
if(myDateTime){
createAppointment(context, myDateTime)
context.appointmentText = myDateTime
return resolve(context);
} else {
context.appointmentText = '[wit.js could not find date]'
return resolve(context);
}
});
},
Hope this helps