Large amount of wei not being processed by Solidity on Remix - ethereum

U am trying to implement liquidity pools with Solidity, and had written two functions : addLiquidity() and withdraw() for it. However, the withdraw function doesn't seem to work with Remix when I try to withdraw large sums (like 0.001 ether), but works with sums like 150000 wei or something.
It doesn't seem to be an issue with Remix's IDE (i read somehere it has a problem working with large numbers), because even when I pass the 149999998499999985165 wei in double quotes (e.g. "149999998499999985165") the same error appears.
The error states: "Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
execution reverted { "originalError": { "code": 3, "data": "0x4e487b710000000000000000000000000000000000000000000000000000000000000011", "message": "execution reverted" } }"
Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface linkStandardToken {
function transferFrom(address _from, address _to, uint256 _value) external returns (bool) ;
function balanceOf(address _owner) external returns (uint256) ;
function transfer(address to, uint tokens) external returns (bool success);
}
contract Uniswap
{
using SafeMath for uint256;
uint public totalLiquidity;
uint public balance;
address public owner;
address public tokenAddress = 0xaFF4481D10270F50f203E0763e2597776068CBc5; // REPLACE WITH ACTUAL TOKEN
linkStandardToken token;
bool public poolInit = false;
uint public protocolFees = 30; //in basis points i.e. divide by 10,000
uint public tempTokenPrice = 0;
mapping(address => uint) public liquidityBalances;
constructor()
{
owner = msg.sender;
token = linkStandardToken(tokenAddress);
}
function init(uint _tokenAmount) public payable
{
require(totalLiquidity == 0, "Already initialized");
require(_tokenAmount > 0, "Token amount must be > 0");
require(msg.value > 0, "Eth amount must be > 0");
totalLiquidity = totalLiquidity.add(_tokenAmount);
balance = balance.add(msg.value);
poolInit = true;
require(token.transferFrom(msg.sender, address(this), _tokenAmount), "Can't transfer tokens to contract");
setTokenToEthPrice();
}
fallback() payable external{}
receive() payable external{}
// _amount - input token amount, X - input token reserve, Y- output token reserve
function _swap(uint _amount, uint X , uint Y) public view returns (uint)
{
// code omitted
}
function swapEthToToken(/*uint _inputEthAmount*/) public payable
{
// code omitted
}
function swapTokenToEth(uint _tokenAmount) public payable
{
// code omitted
}
function setTokenToEthPrice() public // set to internal later
{
tempTokenPrice = _swap(1, balance , token.balanceOf(address(this))) ;
}
function addLiquidity(uint maxTokens) payable public returns (uint)
{
require(msg.value > 0, "msg.val <= 0");
require(totalLiquidity > 0, "totalLiquidity <= 0");
uint tokensBalance = getTokenBalance(address(this));
uint tokensToAdd = msg.value.mul(tokensBalance)/balance;
require(tokensToAdd <= maxTokens , "tokensToAdd > maxTokens");
balance= balance.add(msg.value);
uint mintedLiquidity = msg.value.mul(totalLiquidity)/balance;
liquidityBalances[msg.sender] = liquidityBalances[msg.sender].add(mintedLiquidity);
totalLiquidity = totalLiquidity.add(mintedLiquidity);
require(linkStandardToken(
0xaFF4481D10270F50f203E0763e2597776068CBc5)
.transferFrom(msg.sender, address(this), tokensToAdd));
return mintedLiquidity;
}
function withdraw9(uint256 amount, uint minimumEth, uint minimumTokens) public
{
require(liquidityBalances[msg.sender] >= amount, "Liquidity Balance of msg send < amount");
require(totalLiquidity > 0, "totalLiquidity <= 0");
uint tokenBalance = getTokenBalance(address(this));
uint temp = amount.mul(totalLiquidity);
uint etherToTransfer = temp.div(balance);
uint temp1 = amount.mul(totalLiquidity);
uint tokensToTransfer = temp1.div(tokenBalance);
require(minimumEth < etherToTransfer, "minimumEth >= etherToTransfer");
require(minimumTokens < tokensToTransfer, "minimumTokens >= tokensToTransfer");
balance = balance - etherToTransfer;
totalLiquidity = totalLiquidity.sub(amount);
liquidityBalances[msg.sender] = liquidityBalances[msg.sender].sub(amount);
address payable addr = payable(msg.sender);
addr.transfer(etherToTransfer);
require(linkStandardToken(
0xaFF4481D10270F50f203E0763e2597776068CBc5)
.transfer(msg.sender, tokensToTransfer), "Token transfer unsuccesful");
}
}
library SafeMath {
....// code emitted for compactness
}

As i can see in the last line of widthdraw9 function you use .transfer in order to send ether to some contract. I guess this contract have some code in receive function, so .transfer is not your choose. This function has a gas limitation and any code in receive can break it. If i correctly saw the problem then you should use .call function with enough amount of gas. More about these functions.

The "Gas estimation errored" message doesn't necessarily mean that the problem is with the amount of gas given, just that it hit some error while estimating the amount of gas needed.
The originalError.data has "0x4e487b71...". Looking up those high order 4 bytes on 4byte.directory shows that it's the signature for Panic(uint256), and the code in the low order bytes is "...00011" so the error code is 0x11 (17 decimal). The Solidity doc lists these codes, indicating:
0x11: If an arithmetic operation results in underflow or overflow outside of an unchecked { ... } block.
In the code, balance is not declared in uint etherToTransfer = temp.div(balance). If it's a state variable, could it be 0? Or is there a missing uint256 balance = liquidityBalances[msg.sender]?

Related

Transaction is getting reverted in the `refundToInsurer()` function call

The deployment of InsuranceProvider is working fine and the calling of newContract() with the required parameters is successfully creating/deploying the InsuranceConsumer contract. Even, the payOutContract() is working correctly in terms of transferring the ETH balance from the InsuranceConsumer to the client's wallet.
The issue is with the refundToInsurer() function, as it's expected to transfer the ETH balance from the InsuranceConsumer to the insurer's wallet, but it's transaction is getting failed/reverted.
Here's the code:
SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract InsuranceProvider {
address payable public insurer;
AggregatorV3Interface internal priceFeed;
modifier onlyOwner() {
require(insurer == msg.sender, "Only Insurance provider can do this");
_;
}
constructor() payable {
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
insurer = payable(msg.sender);
}
function newContract(
address payable _client,
uint256 _premium,
uint256 _payoutValue
) public payable onlyOwner returns (address) {
//create contract, send payout amount so contract is fully funded plus a small buffer
InsuranceConsumer i = (new InsuranceConsumer){
value: ((_payoutValue * 1 ether) / (uint256(getLatestPrice())))
}(_client, _premium, _payoutValue);
return address(i);
}
function getLatestPrice() public view returns (int256) {
(, int256 price, , uint256 timeStamp, ) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
function payOutContract(address _contract) public {
InsuranceConsumer i = InsuranceConsumer(_contract);
// Transfer agreed amount to client
i.payOutContract();
}
function refundToInsurer(address _contract) public onlyOwner {
InsuranceConsumer i = InsuranceConsumer(_contract);
// Transfer back the amount to insurer
i.refundToInsurer();
}
}
contract InsuranceConsumer {
AggregatorV3Interface internal priceFeed;
address payable public insurer;
address payable client;
uint256 startDate;
uint256 premium;
uint256 payoutValue;
constructor(
address payable _client,
uint256 _premium,
uint256 _payoutValue
) payable {
//set ETH/USD Price Feed
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
//first ensure insurer has fully funded the contract
require(
msg.value >= _payoutValue / uint256(getLatestPrice()),
"Not enough funds sent to contract"
);
//now initialize values for the contract
insurer = payable(msg.sender);
client = _client;
startDate = block.timestamp; //contract will be effective immediately on creation
premium = _premium;
payoutValue = _payoutValue;
}
function payOutContract() public {
//Transfer agreed amount to client
client.transfer(address(this).balance);
}
function refundToInsurer() public {
// Transfer back the amount to insurer
insurer.transfer(address(this).balance);
}
function getLatestPrice() public view returns (int256) {
(, int256 price, , uint256 timeStamp, ) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
}
Can anyone please help by pointing out the logical mistake that I'm doing in the refundToInsurer() function ?
As, we're creating the InsuranceConsumer using the newContract() function of InsuranceProvider. Therefore, the msg.sender of the InsuranceConsumer is going to be the InsuranceProvider itself, not the insurer's wallet.
So, when we're calling the refundInsurer() of InsuranceConsumer via InsuranceProvider, then it's doing:
insurer.transfer(address(this).balance);
It means to transfer the available ETH in the InsuranceConsumer to the InsuranceProvider (not the insurer's wallet), and since InsuranceProvider is not expected to be a receiver, that's why it's reverting the transaction.
So, the corrected code will be:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract InsuranceProvider {
address payable public insurer;
AggregatorV3Interface internal priceFeed;
modifier onlyOwner() {
require(insurer == msg.sender, "Only Insurance provider can do this");
_;
}
constructor() payable {
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
insurer = payable(msg.sender);
}
function newContract(
address payable _client,
uint256 _premium,
uint256 _payoutValue
) public payable onlyOwner returns (address) {
//create contract, send payout amount so contract is fully funded plus a small buffer
InsuranceConsumer i = (new InsuranceConsumer){
value: ((_payoutValue * 1 ether) / (uint256(getLatestPrice())))
}(_client, _premium, _payoutValue);
return address(i);
}
function getLatestPrice() public view returns (int256) {
(, int256 price, , uint256 timeStamp, ) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
function payOutContract(address _contract) public onlyOwner {
// Transfer agreed amount to client
InsuranceConsumer i = InsuranceConsumer(_contract);
i.payOutContract();
}
function refundToInsurer(address _contract) public onlyOwner {
// Transfer back the amount to insurer
InsuranceConsumer i = InsuranceConsumer(_contract);
i.refundToInsurer(insurer);
}
}
contract InsuranceConsumer {
AggregatorV3Interface internal priceFeed;
address payable public insurer;
address payable client;
uint256 startDate;
uint256 premium;
uint256 payoutValue;
constructor(
address payable _client,
uint256 _premium,
uint256 _payoutValue
) payable {
//set ETH/USD Price Feed
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
//first ensure insurer has fully funded the contract
require(
msg.value >= _payoutValue / uint256(getLatestPrice()),
"Not enough funds sent to contract"
);
//now initialize values for the contract
insurer = payable(msg.sender);
client = _client;
startDate = block.timestamp; //contract will be effective immediately on creation
premium = _premium;
payoutValue = _payoutValue;
}
function payOutContract() public {
//Transfer agreed amount to client
client.transfer(address(this).balance);
}
function refundToInsurer(address payable _insurer) public {
// Transfer back the amount to insurer
_insurer.transfer(address(this).balance);
}
function getLatestPrice() public view returns (int256) {
(, int256 price, , uint256 timeStamp, ) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
}
Now, while calling the refundInsurer(), we're explicitly passing the insurer as the parameter, and it's taking the value of msg.sender from InsuranceProvider, so the msg.sender is going to be the insurer's wallet (with which the InsuranceProvider is being deployed) in this case.
And now, when we're calling the refundInsurer() of InsuranceConsumer via InsuranceProvider, then it's doing:
_insurer.transfer(address(this).balance);
It means to transfer the available ETH in the InsuranceConsumer to the insurer's wallet. So, the transaction will be successful resulting in the withdrawal of the funds from the InsuranceConsumer to the insurer's wallet.

How to send correctly ETH from the manager's deposit to user if an event occurs?

I have this smart contract that I am trying to test. The manager deposits a certain amount of ether. Users can use the vault to earn extra ethers by locking own ether. Users deposit the amount of ether they want (ex 0.10 ETH) and set the seconds for locking. When users deposit, the price of ethereum is recorded via chainlink. If at the end of the locking period the price of ethereum is less than 2000$ the user receives the amount of locked ETH (0.10 ETH) + 2x (0.20ETH) the amount of locked ethers. The extra ethers are taken from the manager's deposit.
The code seems to work fine and the console returns no errors. I am testing the smart contract on the Kovan network. The problem is encountered when the user tries to withdraw the ethereums. When he withdraws, only the deposited ones are returned without the extra ethers being added.
I am new to Solidity so I appreciate any criticism or advice. If there is something already existing similar to what I am trying to create please let me know.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
interface EACAggregatorProxy {
function latestAnswer() external view returns (int256);
}
contract oracleLink {
address public manager;
uint256 public managerDeposit;
uint256[] public managerDeposits;
constructor() payable {
manager = msg.sender;
managerDeposit = msg.value;
managerDeposits.push(managerDeposit);
}
function depositVault() public payable {
require(msg.sender == manager);
}
address public user;
uint256 public userContribution;
uint256 public userCount;
uint256 deadline;
uint256 lockAmount = lockAmounts[msg.sender];
mapping(address => uint) lockAmounts;
uint256 startTime = startTimes[block.timestamp];
mapping(uint => uint) startTimes;
address public chainLinkETHUSDAddress = 0x9326BFA02ADD2366b30bacB125260Af641031331;
uint public ethPrice = 0;
uint256 public price = ethPrice;
function deposit(uint256 numberOfSeconds) public payable {
lockAmounts[msg.sender] = msg.value;
startTimes[block.timestamp] = block.timestamp;
user = msg.sender;
userContribution = msg.value;
userCount++;
deadline = block.timestamp + (numberOfSeconds * 1 seconds);
int256 chainLinkEthPrice = EACAggregatorProxy(chainLinkETHUSDAddress).latestAnswer();
ethPrice = uint(chainLinkEthPrice / 100000000);
}
function withdraw() public payable {
if (ethPrice <= 2000) {
uint256 toWithdraw = lockAmounts[msg.sender];
uint256 amountOfToken = toWithdraw * 2;
payable(manager).transfer(amountOfToken);
}
require(block.timestamp >= deadline);
uint256 amountToWithdraw = lockAmounts[msg.sender];
lockAmounts[msg.sender] = 0;
payable(msg.sender).transfer(amountToWithdraw);
}
}
So the one thing that I noticed is that when you try to send the additional ETH to the recipient's address you're actually trying to send it back to the manager and not the recipient. Also note that you should avoid using the transfer method and use the call method instead: call{value: amount}("") should now be used for transferring ether (Do not use send or transfer.) as of May 2021.
So your withdraw method should look something like this instead:
function withdraw() public payable {
address recipient = msg.sender;
uint256 additionalToken;
if (ethPrice <= 2000) {
additionalToken = lockAmounts[msg.sender] * 2;
}
require(block.timestamp >= deadline);
uint256 amountToWithdraw = lockAmounts[msg.sender] + additionalToken;
lockAmounts[msg.sender] = 0;
(bool success, ) = payable(recipient).call{value: amountToWithdraw}("");
require(success, "Transfer failed.");
}
Hopefully this helps.

How to add a uint T in constructor that will be a time constant inside my smart contract?

I need a time constant to calculate timestamps for deposit, withdrawal, and reward sub-pools. this time constant called T will start from contract deployment and will not be specific to one address/user. I.e rewards(R) are divided into 3 sub-pools: R1 = 20% available after 2T has passed since contract deployment, R2 = 30% available after 3T has passed since contract deployment, R3= 50% available after 4T has passed since contract deployment. I need this variable to be in minutes, for example, sender inputs 3 I want the time between each timestamp to be 3, like deposit in the first T, withdrawal after 3T. How to set it in minutes?
Here is the state variable
uint256 public T;
Here is the constructor
constructor(address stakingToken, address rewardsToken, uint256 timeConstant) {
s_stakingToken = IERC20(stakingToken);
s_rewardsToken = IERC20(rewardsToken);
initialTime = block.timestamp;
T = timeConstant;
}
My full code
error TransferFailed();
error NeedsMoreThanZero();
contract Staking is ReentrancyGuard {
IERC20 public s_rewardsToken;
IERC20 public s_stakingToken;
// This is the reward token per seco
nd
// Which will be multiplied by the tokens the user staked divided by the total
// This ensures a steady reward rate of the platform
// So the more users stake, the less for everyone who is staking.
uint256 public constant REWARD_RATE = 100;
uint256 public s_lastUpdateTime;
uint256 public s_rewardPerTokenStored;
//uint256 public constant T = 3;
uint256 public initialTime;
uint256 public T;
mapping(address => uint256) public s_userRewardPerTokenPaid;
mapping(address => uint256) public s_rewards;
uint256 private s_totalSupply;
mapping(address => uint256) public s_balances; // someones address => how much he staked
event Staked(address indexed user, uint256 indexed amount);
event WithdrewStake(address indexed user, uint256 indexed amount);
event RewardsClaimed(address indexed user, uint256 indexed amount);
constructor(address stakingToken, address rewardsToken, uint256 timeConstant) {
s_stakingToken = IERC20(stakingToken);
s_rewardsToken = IERC20(rewardsToken);
initialTime = block.timestamp;
T = timeConstant;
}
/**
* #notice How much reward a token gets based on how long it's been in and during which "snapshots"
*/
function rewardPerToken() public view returns (uint256) {
if (s_totalSupply == 0) {
return s_rewardPerTokenStored;
}
return
s_rewardPerTokenStored +
(((block.timestamp - s_lastUpdateTime) * REWARD_RATE * 1e18) / s_totalSupply);
}
/**
* #notice How much reward a user has earned
*/
function earned(address account) public view returns (uint256) {
uint256 nowTime = block.timestamp-initialTime;
require(nowTime > 2*T);
if (nowTime > 2*T && nowTime <= 3*T) {
return
((((s_balances[account] * (rewardPerToken() - s_userRewardPerTokenPaid[account])) /
1e18) + s_rewards[account]) / 5 );
} else if
(nowTime > 3*T && nowTime <= 4*T) {
return
((((s_balances[account] * (rewardPerToken() - s_userRewardPerTokenPaid[account])) /
1e18) + s_rewards[account]) / 2 );
} else {
return
(((s_balances[account] * (rewardPerToken() - s_userRewardPerTokenPaid[account])) /
1e18) + s_rewards[account]);
}
}
/**
* #notice Deposit tokens into this contract
* #param amount | How much to stake
*/
function stake(uint256 amount)
external
updateReward(msg.sender)
nonReentrant
moreThanZero(amount)
{
//from T0 to T deposit is available
uint256 nowTime = block.timestamp-initialTime; // time between deployment of contract and now.
require(nowTime < T);
s_totalSupply += amount;
// increasing how much they are staking for how much they staked each time.
s_balances[msg.sender] += amount;
emit Staked(msg.sender, amount);
// sending an amount of token from an address to this contract
bool success = s_stakingToken.transferFrom(msg.sender, address(this), amount);
// if not successfully sent, return an error.
// using the below code instead of "require(success, "Failed")" reduces gas fees, since it doesn't output a string.
if (!success) {
revert TransferFailed(); // revert resets everything done in a failed transaction.
}
}
/**
* #notice Withdraw tokens from this contract
* #param amount | How much to withdraw
*/
function withdraw(uint256 amount) external updateReward(msg.sender) nonReentrant {
// from 2T the user can reward his tokens
uint256 nowTime = block.timestamp-initialTime; // time between deployment of contract and now.
require(nowTime > 2* T);
s_totalSupply -= amount;
s_balances[msg.sender] -= amount;
emit WithdrewStake(msg.sender, amount);
// transfer: send tokens from contract back to msg.sender.
bool success = s_stakingToken.transfer(msg.sender, amount);
if (!success) {
revert TransferFailed(); // revert resets everything done in a failed transaction.
}
}
/**
* #notice User claims their tokens
*/
function claimReward() external updateReward(msg.sender) nonReentrant {
uint256 reward = s_rewards[msg.sender];
s_rewards[msg.sender] = 0;
emit RewardsClaimed(msg.sender, reward);
bool success = s_rewardsToken.transfer(msg.sender, reward);
if (!success) {
revert TransferFailed(); // revert resets everything done in a failed transaction.
}
}
/********************/
/* Modifiers Functions */
/********************/
modifier updateReward(address account) {
s_rewardPerTokenStored = rewardPerToken();
s_lastUpdateTime = block.timestamp;
s_rewards[account] = earned(account);
s_userRewardPerTokenPaid[account] = s_rewardPerTokenStored;
_;
}
modifier moreThanZero(uint256 amount) {
if (amount == 0) {
revert NeedsMoreThanZero();
}
_;
}
/********************/
/* Getter Functions */
/********************/
// Ideally, we'd have getter functions for all our s_ variables we want exposed, and set them all to private.
// But, for the purpose of this demo, we've left them public for simplicity.
function getStaked(address account) public view returns (uint256) {
return s_balances[account];
}
}
Firstly maintain a map for storing the time for each user. Then make functions like depositTimeSet , withdrawalTimeSet for storing different time for different user. While despositing update the variable and while withdraw check the time has exceed or not.
struct Users {
uint dipositTime;
uint withDrawTime;
uint lastDepositTime;
}
mapping(address => Users ) users;
function depositeTimeSet(uint t) {
users[msg.sender].dipositTime = t minutes;
withdrawalTimeSet(t);
}
function withdrawalTimeSet(uint t) {
users[msg.sender].withDrawTime = 3 * t minutes
}
function deposite() {
transferFrom(msg.sender,address(this));
depositeTimeSet(3); // considering sender send 3
users[msg.sender].lastDepositTime = now;
}
function withdraw() {
if(
now > users[msg.sender].lastDepositTime +
users[msg.sender].withDrawTime,"too early for withdraw
request"
)
transferFrom(address(this),msg.sender);
}
You can see THIS one might be helpful
You can see THIS resource for time unit in solidity

Does Solidity function with payable modifier allow to perform msg.sender.call{}

Found out that there are error in my own code. Answered my own question
I am beginner of Solidity programming, and came across with reentrancy risk. I have tested script below in remix and it works per expectation.
https://solidity-by-example.org/hacks/re-entrancy/
contract EtherStore {
// Withdrawal limit = 1 ether / week
uint constant public WITHDRAWAL_LIMIT = 1 ether;
mapping(address => uint) public lastWithdrawTime;
mapping(address => uint) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint _amount) public {
require(balances[msg.sender] >= _amount);
require(_amount <= WITHDRAWAL_LIMIT);
require(block.timestamp >= lastWithdrawTime[msg.sender] + 1 weeks);
(bool sent, ) = msg.sender.call{value: _amount}("");
require(sent, "Failed to send Ether");
balances[msg.sender] -= _amount;
lastWithdrawTime[msg.sender] = block.timestamp;
}
// Helper function to check the balance of this contract
function getBalance() public view returns (uint) {
return address(this).balance;
}
}
The attack contract stop working (return false) the moment msg.sender.call function is included at the end of deposit function (see below code)
However, if the new deposit function is called directly via remix, the msg.sender.call function will go through smoothly without any exceptions
contract EtherStore {
// Withdrawal limit = 1 ether / week
uint constant public WITHDRAWAL_LIMIT = 1 ether;
mapping(address => uint) public lastWithdrawTime;
mapping(address => uint) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
(bool sent, ) = msg.sender.call{value: 1 ether}("");
require(sent, "Failed to send Ether");
}
function withdraw(uint _amount) public {
require(balances[msg.sender] >= _amount);
require(_amount <= WITHDRAWAL_LIMIT);
require(block.timestamp >= lastWithdrawTime[msg.sender] + 1 weeks);
(bool sent, ) = msg.sender.call{value: _amount}("");
require(sent, "Failed to send Ether");
balances[msg.sender] -= _amount;
lastWithdrawTime[msg.sender] = block.timestamp;
}
// Helper function to check the balance of this contract
function getBalance() public view returns (uint) {
return address(this).balance;
}
}
May i check if anyone know what is causing the behavioural differences in both function call.
My objective of testing the new deposit() function is to check if attacker can launch direct attack using single deposit() call, with the assumption that deposit() function will transfer small balance back to msg.sender.
According to my understanding, the expected behavior should be calling the msg.sender fallback() function. But this doesnt happen in the test (remix), instead it returns false straight away
Thanks in advance
**Found out that there are bugs in my logic, thanks for the answe
The two deposit functions are
old
function deposit() public payable {
balances[msg.sender] += msg.value;
}
new
function deposit() public payable {
balances[msg.sender] += msg.value;
(bool sent, ) = msg.sender.call{value: 1 ether}("");
require(sent, "Failed to send Ether");
}
In the second function you add a check which prevents against re-entrancy attacks with custom fallback function on msg.sender.
{value: 1 ether}("");
https://ethereum.stackexchange.com/questions/42521/what-does-msg-sender-call-do-in-solidity
https://consensys.github.io/smart-contract-best-practices/known_attacks/
https://quantstamp.com/blog/what-is-a-re-entrancy-attack

Ethereum, crowdsale returns 0.00 tokens to the wallet

I'm trying to set up a basic crowdsale at ethereum testnet and the solidity code I'm using is the basic examples found at
https://ethereum.org/crowdsale#the-code
with steps followed as described in that guide.
The issue first was that the ethereum wallet doesn't accept the code as is to compile due to the first line:
contract token { function transfer(address receiver, uint amount){ } }
Specifically, its function returns a warning of an unused local variable and won't compile. Is there a way around this other than defining empty variables inside the function?
The second issue is after it's deployed with the modification as mentioned above, it works. But when it sends tokens to the wallet that sent the ether, the amount is always locked at 0.00 tokens.
FULL CODE:
pragma solidity ^0.4.2;
contract token { function transfer(address receiver, uint amount){ receiver; amount; } }
contract Crowdsale {
address public beneficiary;
uint public fundingGoal; uint public amountRaised; uint public deadline; uint public price;
token public tokenReward;
mapping(address => uint256) public balanceOf;
bool fundingGoalReached = false;
event GoalReached(address beneficiary, uint amountRaised);
event FundTransfer(address backer, uint amount, bool isContribution);
bool crowdsaleClosed = false;
/* data structure to hold information about campaign contributors */
/* at initialization, setup the owner */
function Crowdsale(
address ifSuccessfulSendTo,
uint fundingGoalInEthers,
uint durationInMinutes,
uint etherCostOfEachToken,
token addressOfTokenUsedAsReward
) {
beneficiary = ifSuccessfulSendTo;
fundingGoal = fundingGoalInEthers * 1 ether;
deadline = now + durationInMinutes * 1 minutes;
price = etherCostOfEachToken * 1 ether;
tokenReward = token(addressOfTokenUsedAsReward);
}
/* The function without a name is the default function that is called whenever anyone sends funds to a contract */
function () payable {
if (crowdsaleClosed) throw;
uint amount = msg.value;
balanceOf[msg.sender] = amount;
amountRaised += amount;
tokenReward.transfer(msg.sender, amount / price);
FundTransfer(msg.sender, amount, true);
}
modifier afterDeadline() { if (now >= deadline) _; }
/* checks if the goal or time limit has been reached and ends the campaign */
function checkGoalReached() afterDeadline {
if (amountRaised >= fundingGoal){
fundingGoalReached = true;
GoalReached(beneficiary, amountRaised);
}
crowdsaleClosed = true;
}
function safeWithdrawal() afterDeadline {
if (!fundingGoalReached) {
uint amount = balanceOf[msg.sender];
balanceOf[msg.sender] = 0;
if (amount > 0) {
if (msg.sender.send(amount)) {
FundTransfer(msg.sender, amount, false);
} else {
balanceOf[msg.sender] = amount;
}
}
}
if (fundingGoalReached && beneficiary == msg.sender) {
if (beneficiary.send(amountRaised)) {
FundTransfer(beneficiary, amountRaised, false);
} else {
//If we fail to send the funds to beneficiary, unlock funders balance
fundingGoalReached = false;
}
}
}
}
EDIT: I forgot to mention the steps leading to this point aka Token creation / shareholder association work with the code as is provided in the guide.
I came across the same issue. I solved it by actually defining the transfer function as the example from ethereum.org provides an empty one.
I replaced this:
contract token { function transfer(address receiver, uint amount){ } }
By this:
contract token {
event Transfer(address indexed from, address indexed to, uint256 value);
function transfer(address _to, uint256 _value) {
if (_to == 0x0) throw;
Transfer(msg.sender, _to, _value);
}
}
For your second problem, do you actually have a confirmation that the token created were actually sent? How many ether did you send to the crowd-sale contract? It seems that you are using two decimals for your token and if you defined "Ether cost of each token" of 5 like in the example, you shouldn't send less than 0.05 ether to the crowd-sale contract.
Hope it helps!