Solidity Chainlink keepers with PriceFeeds - solidity

I'm trying to integrate Pricefeeds in the chain keepers to automate a sell order when the price goes under certain value.
Separately both work but when adding the Price feed function inside the checkUpkeep() it doesn't trigger the performUpkeep().
Does checkUpkeep() function can call the priceFeed function or is not even praepared for this?
how should I implement it then?
Here is the code:
function checkUpkeep(bytes memory /* checkData */) public view override returns (//,bytes memory value
bool upkeepNeeded,
bytes memory num
){
uint256 EthPrice = 0;
// uint256 i = 2;
EthPrice = getPrice();
num = abi.encodePacked(EthPrice);
if (EthPrice > 0){
upkeepNeeded = true;
}
return (upkeepNeeded, num);//, value
}
function performUpkeep(bytes calldata num) external override {//, bytes calldata value
(bool upkeepNeeded, ) = checkUpkeep("");
if (!upkeepNeeded) {
revert Order__UpkeepNotNeeded(
address(this).balance,
s_Wallets.length
);
}
//Byte conversion to uint
uint256 number;
number = abi.decode(num, (uint256));
// for(uint i=0;i<num.length;i++){
// number = number + uint(uint8(num[i]))*(2**(8*(num.length-(i+1))));
// }
s_nombre = number;
}

Related

How to create a withdraw function

I created a basic contract for crowdfunding. But cannot figure out how to create a withdraw function.
Withdraw function will transfer a campaign's collected funds to the campaign's owner. This is my full crowdfunding contract:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
contract CrowdFunding {
event testConditon(
uint256 deadline,
uint256 currentTimeInMs,
uint256 diff,
bool condition
);
struct Campaign {
address payable owner;
string title;
string description;
uint256 target;
uint256 deadline;
uint256 amountCollected;
string image;
address[] donators;
uint256[] donations;
}
mapping(uint256 => Campaign) public campaigns;
uint256 public numberOfCampaigns = 0;
function createCampaign(
address _owner,
string memory _title,
string memory _description,
uint256 _target,
uint256 _deadline,
string memory _image
) public returns (uint256) {
Campaign storage campaign = campaigns[numberOfCampaigns];
uint256 currentTimeInMs = block.timestamp * 1000;
emit testConditon(
_deadline,
currentTimeInMs,
_deadline - currentTimeInMs,
_deadline > currentTimeInMs
);
require(
_deadline > currentTimeInMs,
"The deadline must be in the future"
);
campaign.owner = payable(_owner);
campaign.title = _title;
campaign.description = _description;
campaign.target = _target;
campaign.deadline = _deadline;
campaign.image = _image;
campaign.amountCollected = 0;
numberOfCampaigns++;
return numberOfCampaigns - 1;
}
function donateToCampaign(uint256 _id) public payable {
uint256 amount = msg.value;
Campaign storage campaign = campaigns[_id];
campaign.donators.push(msg.sender);
campaign.donations.push(amount);
(bool sent, ) = payable(campaign.owner).call{value: amount}("");
if (sent) {
campaign.amountCollected += amount;
}
}
function getDonators(uint256 _id)
public
view
returns (address[] memory, uint256[] memory)
{
return (campaigns[_id].donators, campaigns[_id].donations);
}
function getCampaigns() public view returns (Campaign[] memory) {
Campaign[] memory allCampaigns = new Campaign[](numberOfCampaigns);
for (uint256 i = 0; i < numberOfCampaigns; i++) {
Campaign storage item = campaigns[i];
allCampaigns[i] = item;
}
return allCampaigns;
}
function withdraw(uint256 _id) public {
Campaign storage campaign = campaigns[_id];
require(
campaign.amountCollected >= campaign.target,
"The campaign has not reached its target"
);
//deadline has passed
// require(
// campaign.deadline < block.timestamp * 1000,
// "The deadline has not passed yet"
// );
require(
campaign.owner == msg.sender,
"Only the owner of the campaign can withdraw the funds"
);
campaign.owner.transfer(campaign.amountCollected);
campaign.amountCollected = 0;
}
}
I have no idea how to solve this issue.
Looks like you are missing the payable keyword to trigger the token transfer. Try this:
function withdraw(uint256 _id) public {
Campaign storage campaign = campaigns[_id];
(bool success, ) = payable(campaign.owner).call{value: campaign.amountCollected}("");
require(success, "Withdrawal failure");
campaign.amountCollected = 0;
}
Warning: this function and your function are having a reentrency vulnerability.

TypeError: Explicit type conversion not allowed from "uint256" to "address"

i make simple code, but have error "TypeError: Explicit type conversion not allowed from "uint256" to "address"." Can you help me? I even asked the gpt bot about this error, but it confused me even more)))
in the beginning there was a simple idea - 10k nft, 30 of them immediately after the deposit, the minimum price is indicated and everyone can buy without restriction
`pragma solidity ^0.8.4;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
contract Sptzrawef is ERC721 {
// Define the token name, symbol, and maximum supply
uint256 public totalSupply = 10000;
string public tokenURI;
// Define the owner of the contract
address public owner;
// Define the minimum price of the token
uint256 public minPrice;
// Define the mapping for the token ownership
mapping(address => mapping(uint256 => bool)) public tokenOwnership;
// The constructor function
constructor() ERC721("Sptzrawef", "SP") {
tokenURI = "https://nftstorage.link/ipfs/ba.................q3oq/";
owner = msg.sender;
minPrice = 0.025 ether;
totalSupply = 10000;
// Mint 30 tokens immediately upon deployment
for (uint256 i = 1; i <= 30; i++) {
tokenOwnership[msg.sender][i] = true;
}
}
// Function to mint new tokens
function mint(address _to, uint256 _tokenId) public {
require(msg.sender == owner);
require(_tokenId <= totalSupply);
require(tokenOwnership[_to][_tokenId] == false);
tokenOwnership[_to][_tokenId] = true;
totalSupply++;
}
// Function to buy the token
function buy(uint256 _tokenId) public payable {
require(msg.value >= minPrice);
require(tokenOwnership[msg.sender][_tokenId] == false);
require(_tokenId <= totalSupply);
tokenOwnership[msg.sender][_tokenId] = true;
}
function balanceOf() public view returns (uint256) {
return totalSupply;
}
function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256) {
uint256 count = 0;
for (uint256 i = 1; i <= totalSupply; i++) {
if (tokenOwnership[_owner][i]) {
if (count == _index) {
return i;
}
count++;
}
}
return 0;
}
function ownerOf(uint256 _tokenId) public view override returns (address) {
require(_tokenId <= totalSupply);
for (uint256 i = 0; i < totalSupply; i++) {
address wallet = address(i); - error at this line
if (tokenOwnership[wallet][_tokenId]) {
return wallet;
}
}
return address(0);
}
}`
I think you are using ownerOf function in the wrong way.
try to create a new "getWalletAddress" function, for example, and use it in this way:
function getWalletAddress(uint256 _tokenId) public view returns (address) {
require(_tokenId <= totalSupply);
for (uint256 i = 0; i < totalSupply; i++) {
address wallet = ownerOf(i);
if (tokenOwnership[wallet][_tokenId]) {
return wallet;
}
}
return address(0);
}
}
Or if you want to override the "ownerOf" function then you should go for this code:
function ownerOf(uint256 _tokenId) public view overrides returns (address) {
require(_tokenId <= totalSupply);
for (uint256 i = 0; i < totalSupply; i++) {
address wallet = _ownerOf(i);
if (tokenOwnership[wallet][_tokenId]) {
return wallet;
}
}
return address(0);
}
}
I hope this help resolve your issue
address is 20bytes and uint256 is 32bytes.
Therefore, you need to use uint160 for the type of i to convert it to address.
Or please convert i into uint160 before converting it to address
address wallet = address(uint160(i));

Transfer ether to smart contract user SOLIDITY

I am coding a coin flip contract. I have an issue with the amount sent by the smart contract to a player who wins the game.
What I want to do is: when you loose the coin flip, you loose your bet and when you win, you get 2 x the bet amount - our royalty. Yet, when I deploy the contract on Remix and test the PayWinner() function, I do not get 2x what I bet - royalty.
Thanks for your help!
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
contract CoinFlip {
uint roundId;
uint betAmount;
uint royalty;
address owner;
address payable[] players;
struct round {
address payable player;
uint betAmount;
bool playerChoice; // 0 = heads; 1 = tails
bool draw;
bool win;
uint winAmount;
}
round public myRound;
mapping (uint => round) public flipHistory; // map the roundId with the round data
constructor() {
owner = msg.sender;
betAmount = 0;
roundId = 0;
}
function setRoyalty(uint _royalty) public onlyOwner returns (uint) {
return royalty = _royalty / 100;
}
function getRandomNumber(uint _bet, bool _playerChoice) public payable {
// minimum amount to be bet
require(msg.value > .001 ether);
// update the array players with the latest player
players.push(payable(msg.sender));
// update roundId
roundId = roundId+1;
// update player in Struct
myRound.player = payable(msg.sender);
// update betAmount in Struct
myRound.betAmount = _bet;
// update playerChoice in Struct
myRound.playerChoice = _playerChoice;
myRound.draw = uint256(keccak256(abi.encodePacked(
msg.sender,
)
)
)
% 2 == 1;
payWinner();
}
function payWinner() private {
if (myRound.draw == myRound.playerChoice) { // if else statement
myRound.win = true;
// compute amount to be transferred to winner
myRound.winAmount = myRound.betAmount * (2 - royalty);
// update mapping
flipHistory[roundId] = myRound;
payable(myRound.player).transfer(myRound.winAmount);
}
else {
myRound.win = false;
// update mapping
flipHistory[roundId] = myRound;
}
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
}

Change the state of a variable of a contract B from a Keeper

The purpose is to use this variable from the B contract
Im trying with delegate call but doesnt work,only works with event
ContractB.sol
// SPDX-License-Identifier: MIT
pragma solidity >0.8.0;
contract ContractB {
uint256 public tokenName = uint256(2);
event SetToken(uint256 _tokenName);
function setTokenName(uint256 _newName) external returns (uint256) {
setInternal(_newName);
}
function setInternal (uint256 _newName) public returns (uint256)
{
tokenName = _newName;
emit SetToken(tokenName);
return tokenName;
}
function getTokenName() public view returns (uint256)
{
return tokenName;
}
}
Counter.sol
//Begin
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
interface KeeperCompatibleInterface {
function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData);
function performUpkeep(bytes calldata performData) external;
}
contract Counter is KeeperCompatibleInterface {
uint256 public counter; // Public counter variable
// Use an interval in seconds and a timestamp to slow execution of Upkeep
//60 seconds
uint public immutable interval;
uint public lastTimeStamp; //My counter was updated
//**
address contractBAddress;
uint256 public tokenName = uint256(2);
//**
constructor(uint updateInterval,address _contractBAddress) {
interval = updateInterval;
lastTimeStamp = block.timestamp;
counter = 0;
contractBAddress=_contractBAddress;
}
function checkUpkeep(bytes calldata checkData) external view override returns (bool upkeepNeeded, bytes memory performData) {
upkeepNeeded = (block.timestamp - lastTimeStamp) > interval;
performData = checkData;
}
//When checkUpKeep its already to launch, this task is executed
function performUpkeep(bytes calldata) external override {
lastTimeStamp = block.timestamp;
counter=0;
counter = counter + 1;
(bool success, bytes memory returndata) = contractBAddress.delegatecall(
abi.encodeWithSignature("setTokenName(uint256)", counter)
);
// if the function call reverted
if (success == false) {
// if there is a return reason string
if (returndata.length > 0) {
// bubble up any reason for revert
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert("Function call reverted");
}
}
}
function getTokenName() public view returns (uint256)
{
return tokenName;
}
}
The event works perfect, but i cant change the state in ContractB.sol ...
https://kovan.etherscan.io/tx/0x7fbacd6fa79d73b3b3233e955c9b95ae83efe2149002d1561c696061f6b1695e#eventlog
The fact that the event worked perfectly is proof that Keeper did its job properly. The problem here is the delegatecall itself.
When contract A executes delegatecall to contract B, B's code is executed with contract A's storage, msg.sender and msg.value. Storage, current address and balance still refer to the calling contract (contract A), only the code is taken from the called address (contract B).
In your case, setTokenName updates ContractB's tokenName , ergo ContractB's storage slot 0. The same storage slot at Counter smart contract is uint256 public counter. When you executed delegatecall you updated the Counter’s storage (counter variable) with ContractB’s setTokenName function logic.
Since you know the ContractB’s ABI why don’t you do something like this?
pragma solidity ^0.8.0;
import "./ContractB.sol";
contract Counter is KeeperCompatibleInterface {
ContractB public contractB;
uint256 public counter;
constructor(ContractB _contractBAddress) {
contractB = _contractBAddress;
}
function performUpkeep(bytes calldata) external override {
counter = counter + 1;
contractB.setTokenName(counter);
}
}
You should use this:
ContractB contractB = ContractB(contractBAddress);
contractB.setTokenName(counter);
Documentation:
https://solidity-by-example.org/calling-contract/
Counter.sol
//Begin
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
interface KeeperCompatibleInterface {
function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData);
function performUpkeep(bytes calldata performData) external;
}
contract Counter is KeeperCompatibleInterface {
uint256 public counter; // Public counter variable
// Use an interval in seconds and a timestamp to slow execution of Upkeep
//60 seconds
uint public immutable interval;
uint public lastTimeStamp; //My counter was updated
//**
address public contractBAddress;
//**
constructor(uint updateInterval,address _contractBAddress) {
interval = updateInterval;
lastTimeStamp = block.timestamp;
counter = 0;
contractBAddress=_contractBAddress;
}
function checkUpkeep(bytes calldata checkData) external view override returns (bool upkeepNeeded, bytes memory performData) {
upkeepNeeded = (block.timestamp - lastTimeStamp) > interval;
performData = checkData;
}
//When checkUpKeep its already to launch, this task is executed
function performUpkeep(bytes calldata) external override {
lastTimeStamp = block.timestamp;
counter = counter + 1;
ContractB contractB = ContractB(contractBAddress);
contractB.setTokenName(counter);
}
}
ContractB.sol
contract ContractB {
uint256 public tokenName = uint256(2);
function setTokenName(uint256 _newName) external {
tokenName=_newName;
}
function getTokenName() public view returns (uint256)
{
return tokenName;
}
}

ChainLink Price Fee using Keepers

I am trying to use the keepers chainlink service to get the eth/usd on the Kovan test net. I deployed my contract and registered it with keepers and funded with link token. Still I am not seeing the getLatestPrice() update.
contract address: 0xA29196C270cC15cb5D758Ae3613285720e6DEEb9
Upkeep address: 0xA29196C270cC15cb5D758Ae3613285720e6DEEb9
// SPDX-License-Identifier: MIT
pragma solidity 0.8.6;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
interface KeeperCompatibleInterface {
function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData);
function performUpkeep(bytes calldata performData) external;
}
contract Counter is KeeperCompatibleInterface {
AggregatorV3Interface internal priceFeed;
uint public counter; // Public counter variable
// Use an interval in seconds and a timestamp to slow execution of Upkeep
uint public immutable interval;
uint public lastTimeStamp;
constructor(uint updateInterval) {
interval = updateInterval;
lastTimeStamp = block.timestamp;
counter = 0;
priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);
}
function getLatestPrice() public view returns (int) {
(
uint80 roundID,
int price,
uint startedAt,
uint timeStamp,
uint80 answeredInRound
) = priceFeed.latestRoundData();
return price;
}
function checkUpkeep(bytes calldata checkData) external view override returns (bool upkeepNeeded, bytes memory performData) {
upkeepNeeded = (block.timestamp - lastTimeStamp) > interval;
performData = checkData;
}
function performUpkeep(bytes calldata performData) external override {
lastTimeStamp = block.timestamp;
counter = counter + 1;
performData;
getLatestPrice();
}
}
your upkeep job would be getting called, but the problem is you're not doing anything with the getLatestPrice function. This is a view function that just returns the current feed price. If you were to add a line in your performUpkeep function to actually store the result of getLatestPrice() in a variable in the contract, then you would see that it is getting called