Reputation: 2741
I'm trying to create a simple smart contract to learn solidity and how ethereum works.
From what I understand, using the modify payable on a method will make it accept a value. We then deduct from the sender and add that somewhere else, in this code I'm trying to send it to the owner of the contract.
contract AcceptEth {
address public owner;
uint public bal;
uint public price;
mapping (address => uint) balance;
function AcceptEth() {
// set owner as the address of the one who created the contract
owner = msg.sender;
// set the price to 2 ether
price = 2 ether;
}
function accept() payable returns(bool success) {
// deduct 2 ether from the one person who executed the contract
balance[msg.sender] -= price;
// send 2 ether to the owner of this contract
balance[owner] += price;
return true;
}
}
When I interact with this contract through remix, I get an error of "VM Exception while processing transaction: out of gas" it creates a transaction and the gas price was 21000000000 and the value was 0.00 ETH when I'm trying to get 2 ether from anyone who executes this method.
What's wrong with the code? Alternatively I can add a a variable for one to input the value they want to send, along with a withdraw method, right? but for the sake of learning, I wanted to keep it simple. but even this code feels a bit simple and feels like something is missing.
Upvotes: 5
Views: 7163
Reputation: 11001
I think where you're getting lost is that contracts have built in mechanisms for receiving and holding ether. For example, if you wanted to make it so your accept()
method receives exactly 2 ether (or whatever you set price
to), you would do something like this:
contract AcceptEth {
address public owner;
uint public price;
mapping (address => uint) balance;
function AcceptEth() {
// set owner as the address of the one who created the contract
owner = msg.sender;
// set the price to 2 ether
price = 2 ether;
}
function accept() payable {
// Error out if anything other than 2 ether is sent
require(msg.value == price);
// Track that calling account deposited ether
balance[msg.sender] += msg.value;
}
}
Now, say you have two accounts with the following balances:
0x01 = 50 ether
0x02 = 20 ether
And this contract is deployed and has the address of 0xc0. All addresses can hold ether, so even the contract itself has a balance. Since it was just deployed (and wasn't deployed with any initial ether), it's balance is 0.
Now say 0x01 calls accept()
sending in 2 ether. The transaction will execute and the 3 addresses in our example will have the following balances:
0x01 = 48 ether
0x02 = 20 ether
0xc0 = 2 ether
Now, say 0x02 calls accept()
TWICE, passing 2 ether both times:
0x01 = 48 ether
0x02 = 16 ether
0xc0 = 6 ether
The contract holds all of the ether sent to it. But, your contract also holds state (the balance
map which you defined in code) which is tracking who deposited what. So, you know from that mapping that 0x01 deposited 2 ether and 0x02 deposited 4 ether. If you wanted to introduce a refund()
method that sends the ether back, you would write it like this
function refund(uint amountRequested) public {
require(amountRequested > 0 && amountRequested <= balance[msg.sender]);
balance[msg.sender] -= amountRequested;
msg.sender.transfer(amountRequested); // contract transfers ether to msg.sender's address
}
Upvotes: 13