How to ensure the winner of lottery smart contract doesn't pay the gas fee? - solidity

I have a lottery smart contract, essentially a coinflip between two participants. Players can deposit into the contract and once we have two players, anyone can call the bet() function. This means that the gas fee relies on the person who called the method. How do I get the gas fee of that instance of running the function and refund the person who won if they were the one to pay the gas fee (and place this cost on the loser). This is the codes basic structure currently, is it possible for me to see how much gas the transaction cost/will cost?
function bet() public isGame {
uint dice = diceRoll();
address winner;
if (dice == 1) {
// reward player 1
balance[players[0]] = some eth;
balance[players[1]] = less eth;
winner = players[0];
}
else {
// reward player 2
balance[players[0]] = less eth;
balance[players[1]] = some eth;
winner = players[1];
}
if (msg.sender == winner) {
// deduct gas fee from losers balance and give it to winner
}

Related

Synthetix Staking contract epochs lifecycle

I am trying to understand how to make a staking contract that blocks funds for a period of time and give rewards in epochs for the period that the funds are locked. I understand that synthetix contract is a very good starting point, but I have some trouble with understanding how their epochs works
How the Synthetix Staking Contract starts a new epoch? From what I am seeing, they have a function notifyRewardAmount which seems to add a reward duration and an amount for that period. But how they call this function with precision on each end of a period?
function notifyRewardAmount(uint256 reward) external onlyRewardsDistribution updateReward(address(0)) {
if (block.timestamp >= periodFinish) {
rewardRate = reward.div(rewardsDuration);
} else {
uint256 remaining = periodFinish.sub(block.timestamp);
uint256 leftover = remaining.mul(rewardRate);
rewardRate = reward.add(leftover).div(rewardsDuration);
}
// Ensure the provided reward amount is not more than the balance in the contract.
// This keeps the reward rate in the right range, preventing overflows due to
// very high values of rewardRate in the earned and rewardsPerToken functions;
// Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.
uint balance = rewardsToken.balanceOf(address(this));
require(rewardRate <= balance.div(rewardsDuration), "Provided reward too high");
lastUpdateTime = block.timestamp;
periodFinish = block.timestamp.add(rewardsDuration);
emit RewardAdded(reward);
}
I believe that they are using some sort of a script, but this is a single point of failure and sounds like it's a bad idea to do

Reverse Lotto Search has CRAZY fees (new to solidity): Gas estimation errored with the following message

I am new to solidity and for this project I am trying to do a reverse lottery drawing, where the losers are drawn and appended until only the winner remains.
I keep getting a gas estimation error:
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
gas required exceeds allowance (29970705)
I have tried upping my gas when I deploy on remix and all that does is up my cost when I run - it currently estimates 75000ethererum for running: drawLoser()
I use fulfullRandomWords which calls Chainlink VRF - which gives me a verified random seed, I then use this seed in drawLoser(). current_supply is hardcoded at 10000 for testing. I then use my random seed to make a random number and check if that number exists in my losers array, if it does not exist, I increment and generate a new number from the same seed and repeat until I find a new number. I am trying to do all of this without storing anything except my uint16 entry in my loser array, but I am guessing I am doing something stupid and storing more than I realize on the blockchain since the gas fee is absurd.
Thank you for any help!
function fulfillRandomWords(
uint256, /* requestId */
uint256[] memory randomWords
) internal override {
s_randomWords = randomWords;
}
function exists1(uint16 num) public view returns (bool) {
for (uint i = 0; i < losers.length; i++) {
if (losers[i] == num) {
return true;
}
}
return false;
}
//Right now I need to fulfill randomwords and then drawLoser - draw loser does not generate a new seed
function drawLoser() public {
//fulfillRandomWords;
uint16 drawing;
uint i = 0;
uint j = 1;
//generate 10% of total entrys as losers
while(i < 10*(current_supply-getCountLosers())/100) { //current_supply is entrys in lotto
drawing = uint16(uint256(keccak256(abi.encode(s_randomWords[0], j)))%(current_supply-losers.length)+1);
if (exists1(drawing) == true){
j++;
}
if (exists1(drawing) == false){
losers.push(drawing);
i++;
}
}
}
error: Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? gas required exceeds allowance (29970705)
This means that your transaction is going to fail to tripped require() or revert.

How can I update the price of Matic on realtime inside a smart contract

I'm working on a smart contract that allows users to pay for monthly subscriptions like Netflix, Amazon, etc...
Assuming that each subscription costs 20$ per month which is equivalent to 22 Matic at the time of writing this post.
During the time of the subscription, the user should pay 20$ per month with Matic, and its value will vary.
How can I update the monthly payment inside the smart contract so the subscriber will be able to pay each with the current value of MATIC not more not less? It's possible in solidity?
Or should I let the user pay his subscription manually each month based on the price of each subscription in dollars but with MATIC?
I tried to implement a solution with Tellor in my smart contract but I got stuck.
// smart contract subscription(part of it)
struct Subscription {
address payable subscriber;
uint start;
uint nextPayment;
bool activated;
}
/* nested mapping from address to id to Subscription */
mapping(address => mapping(uint => Subscription)) private AllSubscriptions;
/* Pay subcription every Month*/
function pay(uint256 planId)
external payable
onlyUsers()
{
Subscription storage submitSubscription = AllSubscriptions[msg.sender][planId];
require(block.timestamp > submitSubscription.nextPayment, " Payement not due yet");
Plan storage plan = idToPlan[planId];
require(msg.value >= plan.monthlyPayment, " Monthly payment not correct");
emit PaymentSent(
payable(msg.sender),
payable(address(this)),
plan.monthlyPayment,
planId,
block.timestamp);
totalPaymentsPerWallet[msg.sender] += 1;
submitSubscription.nextPayment = submitSubscription.nextPayment + 4 weeks;
}
// UsingTellor functionnalities
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
import "usingtellor/contracts/UsingTellor.sol";
contract PriceContract is UsingTellor {
uint256 public btcPrice;
//This Contract now has access to all functions in UsingTellor
constructor(address payable _tellorAddress) UsingTellor(_tellorAddress) public {}
function setBtcPrice() public {
bytes memory _b = abi.encode("SpotPrice",abi.encode("MATIC","USD"));
bytes32 _queryID = keccak256(_b);
bool _didGet;
uint256 _timestamp;
bytes _value;
(_didGet, _value, _timestamp) = getDataBefore(_queryID);
uint256 maticPrice = abi.decode(_value,(uint256));
require(token.transferFrom(subscriber,address(this),cost/maticPrice));
}
}
You can use any of the Chainlink data feeds that return the current price of MATIC in USD. It's a free service, there's no LINK payment for data feeds.
Docs and code example: https://docs.chain.link/docs/get-the-latest-price/

How to set msg.value in Remix IDE

This is probably an easy error I'm missing, but I cannot for the life of me figure out how to set the msg.value variable in this contract. I've read online that this value is the amount of wei associated with the transaction, but how do I, as a caller of the contract, specifically set that value. Here's the contract I'm struggling with.
pragma solidity 0.8.7;
contract VendingMachine {
// Declare state variables of the contract
address public owner;
mapping (address => uint) public cupcakeBalances;
// When 'VendingMachine' contract is deployed:
// 1. set the deploying address as the owner of the contract
// 2. set the deployed smart contract's cupcake balance to 100
constructor() {
owner = msg.sender;
cupcakeBalances[address(this)] = 100;
}
// Allow the owner to increase the smart contract's cupcake balance
function refill(uint amount) public {
require(msg.sender == owner, "Only the owner can refill.");
cupcakeBalances[address(this)] += amount;
}
// Allow anyone to purchase cupcakes
function purchase(uint amount) public payable {
require(msg.value >= amount * 1 ether, "You must pay at least 1 ETH per cupcake");
require(cupcakeBalances[address(this)] >= amount, "Not enough cupcakes in stock to complete this purchase");
cupcakeBalances[address(this)] -= amount;
cupcakeBalances[msg.sender] += amount;
}
}
Every time I enter an amount, I'm getting thrown the error that says "You must pay at least 1 ETH per cupcake"
There's nowhere for me to specifically enter in a value for how much I'm going to pay for this, any help would be great
here's what I'm able to input when I deploy the contract on Remix
Top of the Deploy Button you can see the Value Field :
when you want to call the purchase , first fill the value field and select Ether after that calls your function.
I try this way with your code and it works fine.

Smart contract Token distribution solution

I have a question regard to the token sale: How token distribution work?
An example:
10% for private sale
30% for public sale
20% for dev team
40% for rewards
The number of token will be transferred to these address at the time the token created or it will be transferred to these address after that?
It depends on the token contract implementation, can be both.
Example that mints 100 tokens to public sale available right after token creation, and reserves another 50 for later vesting by a dev team address:
pragma solidity ^0.8;
contract MyToken {
mapping (address => uint256) _balances;
mapping (address => Vesting) _vesting;
struct Vesting {
uint256 amount;
uint64 unlockTime;
}
constructor() {
address publicSaleAddress = address(0x123);
address devTeamAddress = address(0x456);
// set the `publicSaleAddress` balance right away
_balances[publicSaleAddress] = 100;
// don't set the `devTeamAddress` balance now
// instead, allow them to claim it after some time
uint64 deadline = uint64(block.timestamp) + 365 days;
_vesting[devTeamAddress] = Vesting(
50,
deadline
);
}
function unvest() external {
// check if they have something to unvest
require(_vesting[msg.sender].amount > 0, 'Nothing to unvest');
// check if they are allowed to unvest yet
require(_vesting[msg.sender].unlockTime >= block.timestamp, 'Not yet');
// increase their balance
_balances[msg.sender] += _vesting[msg.sender].amount;
// prevent them from claiming the balance again
_vesting[msg.sender] = Vesting(0, 0);
}
}