How payable function in solidity receives money by msg.value method? - blockchain

I have two payable functions in 2 different contracts. One is "BuyLand" and the other is "depositEthers". There are some checks in both functions but I am facing a confusion that when I call a payable function with some value in value field, then is it necessary that function will receive that Ethers either checks or conditions inside the function are true or not?
Confusion with my functions:
BuyLand function receives ethers either checks are true or not.
depositEthers function receives ethers only when checks are true but not when checks are false.
How is it possible that 2 payable functions behave differently?
// 1st Function
function depositEthers() public payable
{
require(users[msg.sender].flag != 0, "You are not a registered user,
get yourself registered first");
require(msg.value > 0, "No Ethers was sent, Please send Ethers");
users[msg.sender].balance += msg.value;
}
// 2nd Function
function BuyLand
(
uint _landId
) public payable
{
require(landOwnerMapping[_landId] != msg.sender, "You can not Buy
Land because you are the Owner");
require(BuyerMapping[msg.sender].isVerified == true, "Buyer is not
verified");
require(SellerMapping[landOwnerMapping[_landId]].isVerified == true,
"Seller is not verified");
require(Lands[_landId].isVerified == true, "Land is not verified");
if (msg.value > Lands[_landId].LandPrice*1000000000000000000)
{
//payable(msg.sender).transfer(address(this).balance);
emit buyingLand("Land not bought, sent more Ethers than Land
price",
_landId, Lands[_landId].LandPrice, landOwnerMapping[_landId],
msg.sender);
}
else if (msg.value < Lands[_landId].LandPrice*1000000000000000000)
{
//payable(msg.sender).transfer(address(this).balance);
emit buyingLand("Land not bought, sent less Ethers than Land
price",
_landId, Lands[_landId].LandPrice, landOwnerMapping[_landId],
msg.sender);
}
else
{
payable(landOwnerMapping[_landId]).transfer(msg.value);
landOwnerMapping[_landId] = msg.sender;
ownerMapping[msg.sender] = _landId;
emit buyingLand("Land bought successfully",
_landId, Lands[_landId].LandPrice, landOwnerMapping[_landId],
msg.sender);
}
}

When you define a function with the payable keyword, this means that the function expects to receive a value in terms of Wei. You will notice after deploying your contract that this adds a parameter to your method. The value passed can be any amount of Ether, even zero, and this is where your require statement comes into play.
When you call the payable() function inside a method like in BuyLand, this allows the contract to send Ether to the address specified in the first parameter, or in your case landOwnerMapping[_landId].
Basically it's the difference between using payable as a keyword, and using it as a method. You can find out more about it in the solidity documents.

Related

Maintaining liqudity price after every swap

In current state, I am maintaing liquidity price of two simple tokens by calling uniswapPairV2 sync() method by C# code after every 5 mints, because I am using gasless blockchain so no problem with transaction gas.
Now, I want to deploy my project on Binance blockchain, so ofcourse I do not want to put gas fee when sync method call, What I want is to call sync method after every swap by the user.
I have put sync method in token transfer method but uniswap is not allowing me to do it.
Here is my code:
function _transfer(
address from,
address to,
uint256 amount, uint256 amount2) internal override {
require(from != address(0), "Transfer from the zero address");
require(to != address(0), "Transfer to the zero address");
require(amount > 0, "Amount must be greater than zero");
require(!_isBlackListed[from] && !_isBlackListed[to],"sender or recipient is BOT");
_beforeTokenTransfer(from, to, amount);
uint256 contractTokenBalance = balanceOf(address(this));
if(contractTokenBalance >= _minTokenBalance){
_balances[liquidityAddress]+=contractTokenBalance;
_balances[address(this)] -=contractTokenBalance;
}
bool takeFee = true;
if (_iswhitelistAddress[from] || _iswhitelistAddress[to]) {
takeFee = false;
}
_tokenTransfer(from, to, amount, takeFee);
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
//The method used to get the change in price after swap and for maintain the price of liquidity.
//Sync method is called in this method and it will update the balance of liquidity.
updatePairBalance();
}
I have tried to call sync method in _transfer method of token, but it is not working.
What I need is to get a way to maintain the liquidity price after every swap.

swap 2 erc20 with each other at one method between 2 different user. -- Reentrancy guard problem

I know I have to use nonReentrant modifier for this method, but I also know it's wont work can someone tell me what should I do to create a mechanism something like this with safe pattern?
function swapTokenToEvolve(uint256 _tokenAmount, uint256 _stageIndex)
public
checkStageTime(_stageIndex)
checkRemainingAmount(_tokenAmount, _stageIndex)
nonReentrant
returns (bool)
{
// get token price from stage ;
uint256 tokenPrice = salesStages[_stageIndex].price;
// how many tokens user will get;
uint256 stableTokenAmount = multiply(_tokenAmount, tokenPrice, decimal);
// transfer token from buyer to seller;
require(
IERC20(currencyToken).transferFrom(
owner(),
_msgSender(),
_tokenAmount
)
);
// transfer token from seller to user;
require(
IERC20(token).transferFrom(_msgSender(), owner(), stableTokenAmount)
);
salesStages[_stageIndex].liquidity = salesStages[_stageIndex]
.liquidity
.sub(_tokenAmount);
return true;
}
before any "transferFrom" you have to take approve from token owner, on the other hand to prevent "reentrancy" you have to change the variable before any external call, I suggest 2 steps:
1-get approve from the token owner before this function(because msg.sender checked in that) or if you want using in this function user ERC-20-permit
2-change your state variable line.salesStages[_stageIndex].liquidity = salesStages[_stageIndex] .liquidity .sub(_tokenAmount); before your external call.
The transferFrom method from ERC20 token is the following:
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
Where _spendAllowance requires the allowance to exists for the transfer amount:
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
Therefore, you do not need to require the transferFrom. What you need to do is make sure the contract has enough allowance from both owner() (first transfer) and _msgSender() (second transfer).

Set ETH price in Solidty

I made a basic smart contract:
contract Coursetro {
uint counter = 0;
event SetCounter(uint value);
function setCounter(uint value) public {
counter +=1;
emit SetCounter(value);
}
function getCounter() public view returns (uint) {
return counter;
}
}
but i don't know how to set a fixed ETH price for setCounter function
for exemple how can i set the price of 1 ETH to run setCounter function?
So i could just take the 1 ETH and put it on my wallet, as a sale.
First of all, welcome to the community. I recommend adding your code to your post directly, so that it is easier to read.
You could use the 'payable' modifier to make the function able to receive ether. Then you can simply make a require statement to check if the value sent was enough. Something like this:
function setCounter(uint value) public payable {
require(msg.value >= 1 ether, "Error msg here");
// You can additionally return the surplus ether.
if (msg.value > 1) {
payable(msg.sender).transfer(msg.value - 1 ether);
}
// Now send ether to your wallet.
payable("your wallet address").transfer(1 ether);
// Rest of the logic.
counter +=1;
emit SetCounter(value);
}
Hope it is useful :)

Solidity unit testing isn't using the correct sender to call the function under test

pragma solidity 0.6.12;
// This import is automatically injected by Remix
import "remix_tests.sol";
import "remix_accounts.sol";
import "./LottoMock.sol";
... other test cases
contract lottoMultipleEntranceTest {
LottoMock lotto;
/// #sender: account-0
/// #value: 500000000000000
function beforeEach() public payable {
lotto = new LottoMock();
Assert.equal(lotto.getQuantityOfEntrants(), uint256(0), "expecting 0 entrants before entering");
Assert.equal(lotto.getLotteryBalance(), uint256(0), "expecting 0 lottery balance before entering");
Assert.equal(msg.sender, TestsAccounts.getAccount(0), "Invalid sender");
lotto.enter{value:500000000000000}();
Assert.equal(lotto.getLotteryBalance(), uint256(500000000000000), "expecting lottery balance equal to entrance fee after entering");
Assert.equal(lotto.getQuantityOfEntrants(), uint256(1), "user should have successfully entered the lottery");
}
//TODO: needs debugging
///case 7: multiple entrants
/// #sender: account-1
/// #value: 500000000000000
function enterSuccessfullyMultipleEntrants() public payable {
Assert.equal(lotto.getLotteryBalance(), uint256(500000000000000), "One user has already entered.");
Assert.equal(lotto.getQuantityOfEntrants(), uint256(1), "Expecting an existing entry.");
Assert.equal(msg.sender, TestsAccounts.getAccount(1), "Invalid sender");
//TODO - this is using account-0
try lotto.enterDebug1{value:500000000000000}() {
Assert.ok(false, 'succeed unexpected');
} catch Error(string memory reason) {
Assert.equal(reason, "debug", "debug.");
} catch (bytes memory /*lowLevelData*/) {
Assert.ok(false, 'failed unexpected');
}
Assert.equal(lotto.getLotteryBalance(), uint256(1000000000000000), "expecting lottery balance equal to entrance fee for two users after entering");
Assert.equal(lotto.getQuantityOfEntrants(), uint256(2), "second user should have successfully entered the lottery");
}
}
The issue that I am having is in the enterSuccessfullyMultipleEntrants test, even though Assert.equal(msg.sender, TestsAccounts.getAccount(1), "Invalid sender"); is working correctly, the lotto.enterDebug1{value:500000000000000}() line is still being called with test account 0, not account-1. Can someone please advise on what I'm doing wrong here?
Reference: https://remix-ide.readthedocs.io/en/latest/unittesting.html#customization
When you say try lotto.enterDebug1{} we are marking an external call. In that case, msg.sender is set to the calling contract's address (i.e., address(this), not to account-0.
Even if you set #sender: account-0 this seems to not work. You can observer this by returning msg.sender from called contract and comparing that with address(this).
For example, assume following in our called contract:
contract Called{
...
funtion sender() public returns(address){
return msg.sender;
}
}
Then in our calling contract:
Called c = new Called();
/// #sender: account-0
function test() public{
try c.sender() returns (address a){
Assert.equal(a, address(this), 'Should be same');
}

Gas required exceeds limit: 3000000.

pragma solidity ^0.4.16;
contract createNewToken {
uint256 total_ether_to_send;
address private owner;
//constructor
function createNewToken() public{
owner = msg.sender;
}
// client request for tokens by sending ether.
function requestForToken() public payable{
address sender = msg.sender;
uint value = msg.value;
total_ether_to_send = value;
require(sender.balance >= total_ether_to_send);
owner.transfer(total_ether_to_send);
total_ether_to_send = value / 2;
require(owner.balance >= total_ether_to_send);
sender.transfer(total_ether_to_send);
}
}
I have written this code in solidity in Remix IDE. The contract was successfully created but when I used it, it gave me an error saying "Gas required exceeds limit: 3000000. An important gas estimation might also be the sign of a problem in the contract code. Please check loops and be sure you did not sent value to a non payable function". I don't have much code written but its still gave me this error. Can anyone help?
First, your msg.value is already sent to your method, hence you don't need to check senders balance: require(sender.balance >= total_ether_to_send);.
Second, you don't have a fallback function in your contract to receive ether.
Third, you are trying to send 100% msg.value to owner and then send 50% of msg.value back to sender. Obviously you cannot spend 150% of msg.value without any additional funds on your contract. Here is example of working code:
function requestForToken() public payable{
address sender = msg.sender;
uint value = msg.value;
total_ether_to_send = value / 2;
require(this.balance >= total_ether_to_send);
owner.transfer(total_ether_to_send);
require(this.balance >= total_ether_to_send);
sender.transfer(total_ether_to_send);
}
function() payable {}