If i have a function like this:
function sendToAuthor (uint tokenId) public payable{
//here I want to get some ether from the msg.sender, store it in a
mapping and send it to another address (author).
}
What I don't understand is how to check if the msg.sender gave the smart contract the money or not. If I can check that, I can take the msg.value from the mapping and send it to the author, but how do I check that the sender actually made the eth transfer to the contract?
The msg.value variable contains how much ETH was deposited in payable function. You check that the value is above zero or matches the any payment amount you are expecting.
psuedocode:
contract someContract {
address author = "0x00...";
mapping (address => uint) public sentToAuthor;
function sendToAuthor () public payable {
sentToAuthor[msg.sender] = msg.value;
author.call{value: msg.value}("");
}
}
Your question doesn't really make sense.
What I don't understand is how to check if the msg.sender gave the smart contract the money or not.
You just look at the value of msg.value. If the transaction doesn't revert, and the function is payable, and you don't send it anywhere else, then your contract receives those funds. Period. No "checking" needed. If you do want to check, you could on the client side, but just looking at the contract balance (e.g., ethers.utils.balanceOf(contractAddress), or something). You could also just look at the mapping here, it will be correct and show you.
If I can check that, I can take the msg.value from the mapping and send it to the author, but how do I check that the sender actually made the eth transfer to the contract?
The "msg.value" won't actually be "in" the mapping, mappings can't actually hold eth, they can only hold a uint. It just tells you how much was sent to the contract.
Btw, as written here, it sends it straight to the author, so it won't stay in the contract. If you remove the last line of "sendToAuthor" (the author.call line), then the eth will just stay in the contract itself, instead.
(btw, there's an ethereum stackoverflow, you should be asking there.)
Related
I was wondering what information are publicly visible and intelligible when an EOA (external ownable address) calls a payable function on a smart contract, with some parameters and a return value.
Let us say I have the smart contract function below, the question is: 'is the return value visible somewhere on the blockchain?'. I am using Solidity 0.8.12.
function askForSecretCode(uint time) external payable returns (bytes32) {
require(msg.value == 42, 'Need to pay 42 wei.');
secretCodes[secretCodesNum] = keccak256(abi.encodePacked(msg.sender, time);
return keccak256(abi.encodePacked(msg.sender, time);
}
Anyone can see the input time param value as a part of a transaction invoking the askForSecretCode function.
Even though if you don't publish the contract source code, the bytecode is public, and there are decompilers that can (with some error rate) help generate source code back from the bytecode. So let's assume that the source code is available as well.
From the source code (or usually even from the pseudocode generated by the decompiler), anyone can determine the storage slot of secretCodesNum (which from the context seems to be a property of the contract) and retrieve its value using the eth_getStorageAt RPC method, including historical values.
Using these secretCodesNum values, they can use the same method to determine storage slots of any secretCodes[secretCodesNum] and their values.
TLDR: Never ever store private data on the blockchain.
I'm trying to create a "real" transaction from inside a smart contract to an EOA. This is so that I can attach data/input_data to send to it.
I've read several resources on this but I've come to contradictory information: some say it's impossible, some say that call() can achieve this. I've been testing multiple methods and have not come to see that it is possible.
Here's a simple example of what I'm trying to achieve:
pragma solidity 0.8.6;
contract Simple {
uint32 value;
constructor() payable {
// Contract is initialized with 0.5 ether
value = 22;
}
function foo() public {
require(address(this).balance >= 0.1 ether);
// Along with transfering ether, I want to send some data to the EOA,
// for example, whichever value is in the variable "value"
payable(msg.sender).transfer(0.1 ether);
}
}
On a "normal" transaction, it is possible to set the field "input data" (normally used to make function calls when sending a transaction to a smart contract), which allows us to send data on a transaction from an EOA to another EOA. I was able to achieve this already.
But, from my understanding, contracts "can't" create transactions; they only create "internal transactions" (informal name) that are associated with the "parent transaction" (transaction that called the contract in the first place) and therefore don't have the data field. But they're able to call another contract on the network, so I assume they're able to send some data along the network, right?
Furthermore, this question seems to imply that the low level call() method is able to achieve this. I've tried multiple approaches but have not been able to reproduce the wanted behaviour.
msg.sender.call{value: 0.1 ether}("data", value); // Doesn't work
msg.sender.call{value: 0.1 ether}(value); // Doesn't work
msg.sender.call{value: 0.1 ether}(abi.encodeWithSignature(value)) // Doesn't work
At some point, I did find my message on a block's "extra data", but from my understanding, this was written there by the miner for some reason.
So, to sum it up, is it possible to, from a contract, send ether + message to an EOA account? How would I achieve this?
Edit: Fixed the function name, which was a reserved keyword.
function msg() public {
This function name is a bit problematic, because you're overriding the global msg variable, and can't use the msg.sender.
So I changed the function name to generic foo().
function foo() public {
msg.sender.call{value: 0.1 ether}
Since Solidity 0.8, an address is not payable by default (source: docs). So if you want to send them the native currency (in case of Ethereum, that's ETH), you need to cast the address to payable first.
payable(msg.sender).call{value: 0.1 ether}
Finally to the data sending part.
At some point, I did find my message on a block's "extra data", but from my understanding, this was written there by the miner for some reason.
I'm not exactly sure, but it seems like you stumbled upon the correct field, which is simply the data field of the raw transaction, and the blockchain explorer probably named it "extra data". The data field is not filled by the miner, but by the transaction creator.
Since you're sending an integer, and the data field is bytes (array of bytes), you need to encode it to bytes. In your case:
abi.encode(value)
To you put it all together:
pragma solidity 0.8.6;
contract Simple {
uint value;
constructor() payable {
value = 22;
}
function foo() public {
require(address(this).balance >= 0.1 ether);
payable(msg.sender).call{value: 0.1 ether}(abi.encode(value));
}
}
When you execute the foo() function (and the contract has enough funds), it will create an internal transaction (some blockchain explorers might use a different name) to the msg.sender with value 0.1 ether and the decimal 22 encoded as hex 16 in the data field.
I'm a rookie working with solidity and blockchain technologies and I was reading some good practices to improve my code.
And I have a question about a code that I'm not quite understanding very well:
Source: https://github.com/ConsenSys/smart-contract-best-practices/blob/master/docs/known_attacks.md
// INSECURE
mapping (address => uint) private userBalances;
function withdrawBalance() public {
uint amountToWithdraw = userBalances[msg.sender];
require(msg.sender.call.value(amountToWithdraw)()); // At this point, the caller's code is executed, and can call withdrawBalance again
userBalances[msg.sender] = 0;
}
In the above code is said to be insecure because a malicious agent can call the step 2 require the amount of times we wants. My question regarding this is, how the malicious agent can call misuse this and call that line of code more than 1 time. I'm clearly missing something here.
This is known as a reentrancy attack.
This is insecure because the user's balance is set to 0 only after the withdrawal has been processed. Moreover, the withdrawal is processed by using evm's CALL opcode, which passes control to the receiving address.
If the receiving address is a contract, it can hijack this transfer using the fallback function. Inside this fallback function, it can check to see if the balance of the sending contract exceeds the amount that was transferred. If it does, it will call withdrawBalance again, until the withdrawal contract's balance has been depleted.
A simple attacker contract may look something like:
contract Attacker {
function startattack() {
victim.withdrawBalance();
}
function() payable {
if (victim.balance > msg.value) {
victim.withdrawBalance();
}
}
}
By calling startattack, you initiate a withdrawal. When the require(msg.sender.call.value(amountToWithdraw)()); line is executed, it runs the code in the fallback function. At this point, msg.value is userBalances[msg.sender]. The attacker can check if the victim's contract still has more ether available than userBalances[msg.sender], and run a withdrawal again (which will result in this process looping until the balance drops below userBalances[msg.sender]).
This can be avoided by switching the order of lines to:
function withdrawBalance() public {
uint amountToWithdraw = userBalances[msg.sender];
userBalances[msg.sender] = 0;
require(msg.sender.call.value(amountToWithdraw)());
}
Now, even if the attacker calls withdrawBalance again, the user's balance has already been set to 0, and further withdrawal will not be possible.
Newbie.
There is a go-ethereum method:
eth.estimateGas({from:'firstAccount', to:'secondAccount'})
that works well,
but same method with contract address like:
eth.estimateGas({from:'firstAccount', to:'contractAddr'})
fails with error
gas required exceeds allowance or always failing transaction
I have looked into go-ethereum source code and it has the line, that contains proposal to use contract address as second parameter:
https://github.com/ethereum/go-ethereum/blob/master/accounts/abi/bind/base.go#L221
The question is: is there any possibily to use eth.estimateGas with contract address as second parameter and how to avoid above error?
Thank you.
You're not specifying what you're executing in the contract, so there's nothing to estimate. When you estimateGas for a transfer to an EOA account, there is no contract code to execute, so there is no message data to be sent as part of the transaction object. If you're estimating gas on a contract call, you need to include the data for the contract.
For example, if you want to estimate gas to setValue(2) method in this contract
pragma solidity ^0.4.19;
contract SimpleContract {
uint256 _value;
function setValue(uint256 value) public {
_value = value;
}
}
your call would be
var data = '552410770000000000000000000000000000000000000000000000000000000000000002';
eth.estimateGas({from: fromAccount, to: contractAddress, data});
The value for data comes from encoding the function signature and the parameter value(s). You can use a simple tool (like https://abi.hashex.org) to generate this. You just enter the function name along with the parameter argument types and their values, and it will generate the message data for you. You can also do this using web3js.
EDIT - I neglected to consider contracts with fallback functions. Executing estimateGas on a contract without passing in message data provide the estimate for contracts that have a fallback function. If the contract does not have a fallback function, the call will fail.
How can I write a smart contract to give role based permission for a transaction to take place.
Say there are five people A, B, C, D and E. A wants to send some ethers to B. But the transaction will not take place until and unless C, D and E give confirmation/approve.
Is it possible to do with ethereum smart contracts? Can someone give me sample code for the same?
Thanks in advance.
you can create such smart contract although using a multisig account would be better for this case.
you could write a simple contract which validate a transaction after receiving the different needed signatures.
e..g :
contract C{
address A;
address B;
address C;
mapping (address=>bool) permission;
function send_permission(address _to, uint value)
{
if(permission[A]&&permission[A]&&permission[A])
_to.transfer(value);
}
function set_permission(bool state)
{
permission[msg.sender]=state;
}
}
For a dynamic solution you will need to create 2 mappings one for the user who can approve transactions (lets call them moderator for simplicity) and one for the permissions
the logic will be when a user sends a transaction we see if he is approved in the approval mapping if yes go though with the transaction otherwise revert.
you will need to make a function for a user to get approved.
and a function which allows a moderator to approve an address in which we will check if a moderator is present in the moderators mapping. if yes he can add the non-approved user to the approved mapping.
remember in this solution once an address is approved that address can send multiple transactions with no checks but if you want to limit what address can send which transaction you'll have to modify the second mapping to a nested one in which youll keep a track of the address, the transaction number and a bool value