I wrote a solidity that pays ERC-20 tokens for ERC-721 NFT transaction, but it doesn't work - solidity

I wrote a solidity that pays ERC-20 tokens for ERC-721 NFT transactions, but it doesn't work. On purchase, you trigger the purchaseToken method. But I get an unknown error. I'm testing it on ropsten. Can you find the problem with my solidity file? I can't solve it and I'm on the verge of dying. Please advice from seniors. please.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
import "./saleNFT.sol";
contract MintNFT is ERC721Enumerable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
address owner;
// constructor
constructor() ERC721("NAME", "SYMBOL") {
owner = msg.sender;
}
SaleNFT public saleNFT;
// struct
struct tokenData {
uint256 tokenId;
string tokenURI;
uint256 tokenPrice;
}
// modifier
modifier onlyOwner {
require(msg.sender == owner, "Caller not owner");
_;
}
// mapping
mapping(uint256 => string) private _tokenURIs;
// variable
uint256 balanceLength;
function mintNftToken(string memory _tokenURI) public onlyOwner returns (uint256) {
_tokenIds.increment();
uint256 nftTokenId = _tokenIds.current();
_mint(msg.sender, nftTokenId);
_setTokenURI(nftTokenId, _tokenURI);
return nftTokenId;
}
function _setTokenURI(uint256 _tokenId, string memory _tokenURI) internal {
require(_exists(_tokenId), "ERC721Metadata: URI set of nonexistent token");
_tokenURIs[_tokenId] = _tokenURI;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
import "./mintNFT.sol";
contract SaleNFT {
MintNFT public mintNftTokenAddress;
IERC20 public currencyTokenAddress;
uint256 feePercent;
address payable feeAddress;
address owner;
// constructor
constructor(address _mintNftTokenAddress, IERC20 _currencyTokenAddress, address payable _feeAddress, uint256 _feePercent) {
mintNftTokenAddress = MintNFT(_mintNftTokenAddress);
currencyTokenAddress = _currencyTokenAddress;
feeAddress = _feeAddress;
feePercent = _feePercent;
owner = msg.sender;
}
// struct
struct Trade {
uint256 item;
uint256 price;
}
// modifier
modifier onlyOwner {
require(msg.sender == owner, "Caller not owner");
_;
}
// mapping
mapping(uint256 => Trade) public trades;
// array
uint256[] public onSaleTokenArray;
function changeFee(uint256 _feePercent , address payable _feeAddress) onlyOwner external returns (bool) {
feePercent = _feePercent;
feeAddress = _feeAddress;
return true;
}
function _pay(address from, address to, uint256 amount) internal returns (bool) {
return IERC20(currencyTokenAddress).transferFrom(from, to, amount);
}
function setForSaleNft(uint256 _tokenId, uint256 _price) public {
address tokenOwner = mintNftTokenAddress.ownerOf(_tokenId);
require(tokenOwner == msg.sender, "Caller is not token owner.");
require(_price > 0, "Price is zero or lower.");
require(trades[_tokenId].price == 0, "This token is already on sale.");
require(mintNftTokenAddress.isApprovedForAll(tokenOwner, address(this)), "token owner did not approve token.");
trades[_tokenId] = Trade({
item: _tokenId,
price: _price
});
onSaleTokenArray.push(_tokenId);
}
function purchaseToken(uint256 _tokenId) external {
uint256 price = trades[_tokenId].price;
address tokenOwner = mintNftTokenAddress.ownerOf(_tokenId);
uint256 balance = currencyTokenAddress.balanceOf(msg.sender);
uint256 premium = price * feePercent / 10000;
require(price > 0, "token not sale");
require(tokenOwner != msg.sender, "Caller is token owner.");
require((balance + premium) >= price, "Lack of balance");
require(balance >= (premium + price), "Caller sent lower than price.");
require(_pay(msg.sender, tokenOwner, price), "token transfer error for owner");
mintNftTokenAddress.safeTransferFrom(tokenOwner, msg.sender, _tokenId);
require(_pay(msg.sender, feeAddress, premium), "token transfer error for feeaddress");
trades[_tokenId].price = 0;
for(uint256 i = 0; i < onSaleTokenArray.length; i++) {
if (trades[onSaleTokenArray[i]].price == 0) {
if ((onSaleTokenArray.length - 1) != i) {
onSaleTokenArray[i] = onSaleTokenArray[onSaleTokenArray.length - 1];
}
onSaleTokenArray.pop();
}
}
}
}

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.

Require statement reverting transaction everytime

something strange is going on. I'm testing some contracts on remix EVM. I have some pretty basic NFT staking contracts that works fine when comes to staking and transfering the token. However, if I try to execute the unstake function, the transaction gets reverted saying that the the require conditions are not passing. However, and more strange is that if I call the functions inside the require separately the condition is true!
I don't know whats going on at this point, so please any advice or help would be much appreciated. Currently I have three contracts (ERC20, ERC721, ERC721staking) with all functions working just right except for the unstake function.
These are my contracts:
Energy.sol (ERC20):
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
/* Simple ERC20 token contract to issue rewards */
contract Energy is ERC20, Ownable {
mapping(address => bool) minters;
constructor() ERC20("ENERGY", "NRG") {
_mint(msg.sender, 100 * 10**decimals());
}
modifier isMinter() {
require(minters[msg.sender], "Caller is not authorized to mint!");
_;
}
function mintRewards(address to, uint256 amount) external isMinter {
_mint(to, amount * 10**decimals());
}
function addMinter(address account) public onlyOwner {
minters[account] = true;
}
}
Fuel.sol (ERC721)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
contract Fuel is ERC721, ERC721Burnable, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("Fuel", "FUEL") {}
function safeMint(address to) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
}
}
Generator.sol (staking):
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import "#openzeppelin/contracts/security/ReentrancyGuard.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "./Energy.sol";
import "./Fuel.sol";
struct Loader {
uint256[] fuelIds;
mapping(uint256 => uint256) loadBlock;
}
contract Generator is Ownable, ReentrancyGuard, IERC721Receiver {
Fuel fuel;
Energy energy;
uint256 rewardsPerBlock = 5;
mapping(address => Loader) loaders;
// Enumeration of fuelIds staked indexes of a loader
mapping(address => mapping(uint256 => uint256)) public fuelIdIndex;
// tracks owner of a fuelId
mapping(uint256 => address) public loaderOf;
constructor(address _fuel, address _energy) {
fuel = Fuel(_fuel);
energy = Energy(_energy);
}
function stake(uint256 fuelId) public nonReentrant {
// safe checks
require(
fuel.ownerOf(fuelId) == msg.sender,
"You're not the owner of this NFT"
);
// push new token to staking collection
loaders[msg.sender].fuelIds.push(fuelId);
// updates index reference of fuelId
uint256 totalFuel = loaders[msg.sender].fuelIds.length;
fuelIdIndex[msg.sender][fuelId] = totalFuel - 1;
// inits staking block
loaders[msg.sender].loadBlock[fuelId] = block.number;
// add it to reference
loaderOf[fuelId] = msg.sender;
fuel.safeTransferFrom(address(msg.sender), address(this), fuelId);
}
function unstake(uint256 fuelId) public nonReentrant {
// safe checks
require(ownedByThis(fuelId), "This fuel is not being loaded here!");
require(
_loaderOf(fuelId) == address(msg.sender),
"You haven't loaded this fuel here!"
);
uint256 lastFuelIndex = loaders[msg.sender].fuelIds.length - 1;
uint256 fuelIndex = fuelIdIndex[msg.sender][fuelId];
// swap current fuelId to last position
if (lastFuelIndex != fuelIndex) {
uint256 lastFuelId = loaders[msg.sender].fuelIds[lastFuelIndex];
loaders[msg.sender].fuelIds[fuelIndex] = lastFuelIndex; // Move the last token to the slot of the to-delete token
fuelIdIndex[msg.sender][lastFuelId] = fuelIndex; // Update the moved token's index
}
// remove the last element from mapping and array
delete fuelIdIndex[msg.sender][fuelId];
delete loaders[msg.sender].fuelIds[lastFuelIndex];
delete loaders[msg.sender].loadBlock[fuelId];
delete loaderOf[fuelId];
// Transfer back to the owner
fuel.safeTransferFrom(address(this), address(msg.sender), fuelId);
claim(fuelId);
}
function claim(uint256 fuelId) public {
// safe checks
require(ownedByThis(fuelId), "This fuel is not being loaded here!");
require(
_loaderOf(fuelId) == address(msg.sender),
"You haven't loaded this fuel here!"
);
uint256 rewardsToClaim = getPendingRewards(msg.sender, fuelId);
energy.mintRewards(msg.sender, rewardsToClaim);
loaders[msg.sender].loadBlock[fuelId] = block.number;
}
function claimAll() public nonReentrant {
// safe checks
require(
loaders[msg.sender].fuelIds.length > 0,
"You have no fuel loaded here!"
);
uint256 totalFuelLoaded = totalFuelLoadedBy(msg.sender);
for (uint256 i = 0; i < totalFuelLoaded; i++) {
uint256 fuelId = loaders[msg.sender].fuelIds[i];
claim(fuelId);
}
}
function getPendingRewards(address account, uint256 fuelId)
public
view
returns (uint256)
{
uint256 loadBlock = loaders[account].loadBlock[fuelId];
uint256 blocksElapsed = block.number - loadBlock;
return blocksElapsed * rewardsPerBlock;
}
function getAllPendingRewards() public view returns (uint256) {
uint256 totalFuelLoaded = totalFuelLoadedBy(msg.sender);
uint256 totalRewards = 0;
for (uint256 i = 0; i < totalFuelLoaded; i++) {
uint256 fuelId = loaders[msg.sender].fuelIds[i];
totalRewards += getPendingRewards(msg.sender, fuelId);
}
return totalRewards;
}
function _loaderOf(uint256 fuelId) public view returns (address) {
return loaderOf[fuelId];
}
function totalFuelLoadedBy(address account) public view returns (uint256) {
return loaders[account].fuelIds.length;
}
function generatorAddress() public view returns (address) {
return address(this);
}
function ownedByThis(uint256 fuelId) public view returns (bool) {
return address(fuel.ownerOf(fuelId)) == address(this);
}
function onERC721Received(
address operator,
address from,
uint256 fuelId,
bytes calldata data
) external override returns (bytes4) {
return this.onERC721Received.selector;
}
}
If you want to test the flow (and I hope you do) be sure to deploy first the Fuel and Energy contracts, then use the address of the contracts as constructor arguments when deploying the Generator contract. Then approveForAll the generator address in the fuel instance, mint some nfts, stake in the generator contract and try to unstake. Every function will work just fine but the unstake function.
Thanks again for any help!
Function ownedByThis takes address ownerOf(fuelId) from you Fuel contract, but after you staked your NFT in Generator.sol, now Generator.sol is owner of this NFT, and your require statement with function ownedByThis is not working. Also i added (delete loaderOf[fuelId];) to the very bottom of your Claim function. Before unstake your nft dont forget to use AddMinter funtion for address of Generator.sol contract. Hope i was useful.
Updated code below
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "#openzeppelin/contracts/security/ReentrancyGuard.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "./Energy.sol";
import "./Fuel.sol";
contract Generator is Ownable, ReentrancyGuard, ERC721Holder {
Fuel fuel;
Energy energy;
struct Loader {
uint256[] fuelIds;
mapping(uint256 => uint256) loadBlock;
}
uint256 rewardsPerBlock = 5;
mapping(address => Loader) loaders;
// Enumeration of fuelIds staked indexes of a loader
mapping(address => mapping(uint256 => uint256)) public fuelIdIndex;
// tracks owner of a fuelId
mapping(uint256 => address) public loaderOf;
constructor(address _fuel, address _energy) {
fuel = Fuel(_fuel);
energy = Energy(_energy);
}
function stake(uint256 fuelId) public nonReentrant {
// safe checks
require(
fuel.ownerOf(fuelId) == msg.sender,
"You're not the owner of this NFT"
);
// push new token to staking collection
loaders[msg.sender].fuelIds.push(fuelId);
// updates index reference of fuelId
uint256 totalFuel = loaders[msg.sender].fuelIds.length;
fuelIdIndex[msg.sender][fuelId] = totalFuel - 1;
// inits staking block
loaders[msg.sender].loadBlock[fuelId] = block.number;
// add it to reference
loaderOf[fuelId] = msg.sender;
fuel.safeTransferFrom(address(msg.sender), address(this), fuelId);
}
function unstake(uint256 fuelId) public nonReentrant {
// safe checks
require(msg.sender == loaderOf[fuelId], "You are not the owner");
//require(ownedByThis(fuelId), "This fuel is not being loaded here!");
// require(
// _loaderOf(fuelId) == address(msg.sender),
// "You haven't loaded this fuel here!"
// );
uint256 lastFuelIndex = loaders[msg.sender].fuelIds.length - 1;
uint256 fuelIndex = fuelIdIndex[msg.sender][fuelId];
// swap current fuelId to last position
if (lastFuelIndex != fuelIndex) {
uint256 lastFuelId = loaders[msg.sender].fuelIds[lastFuelIndex];
loaders[msg.sender].fuelIds[fuelIndex] = lastFuelIndex; // Move the
last token to the slot of the to-delete token
fuelIdIndex[msg.sender][lastFuelId] = fuelIndex; // Update the
moved token's index
}
// remove the last element from mapping and array
delete fuelIdIndex[msg.sender][fuelId];
delete loaders[msg.sender].fuelIds[lastFuelIndex];
delete loaders[msg.sender].loadBlock[fuelId];
// Transfer back to the owner
fuel.safeTransferFrom(address(this), address(msg.sender), fuelId);
claim(fuelId);
}
function claim(uint256 fuelId) public {
// safe checks
//require(ownedByThis(fuelId), "This fuel is not being loaded here!");
require(msg.sender == loaderOf[fuelId], "You are not the owner");
// require(
// _loaderOf(fuelId) == address(msg.sender),
// "You haven't loaded this fuel here!"
// );
uint256 rewardsToClaim = getPendingRewards(msg.sender, fuelId);
energy.mintRewards(msg.sender, rewardsToClaim);
loaders[msg.sender].loadBlock[fuelId] = block.number;
delete loaderOf[fuelId];
}
function claimAll() public nonReentrant {
// safe checks
require(
loaders[msg.sender].fuelIds.length > 0,
"You have no fuel loaded here!"
);
uint256 totalFuelLoaded = totalFuelLoadedBy(msg.sender);
for (uint256 i = 0; i < totalFuelLoaded; i++) {
uint256 fuelId = loaders[msg.sender].fuelIds[i];
claim(fuelId);
}
}
function getPendingRewards(address account, uint256 fuelId) public view
returns (uint256) {
uint256 loadBlock = loaders[account].loadBlock[fuelId];
uint256 blocksElapsed = block.number - loadBlock;
return blocksElapsed * rewardsPerBlock;
}
function getAllPendingRewards() public view returns (uint256) {
uint256 totalFuelLoaded = totalFuelLoadedBy(msg.sender);
uint256 totalRewards = 0;
for (uint256 i = 0; i < totalFuelLoaded; i++) {
uint256 fuelId = loaders[msg.sender].fuelIds[i];
totalRewards += getPendingRewards(msg.sender, fuelId);
}
return totalRewards;
}
function _loaderOf(uint256 fuelId) public view returns (address) {
return loaderOf[fuelId];
}
function totalFuelLoadedBy(address account) public view returns (uint256) {
return loaders[account].fuelIds.length;
}
function generatorAddress() public view returns (address) {
return address(this);
}
// function ownedByThis(uint256 fuelId) public view returns (bool) {
// return address(fuel.ownerOf(fuelId)) == address(this);
// }
function onERC721Received(address, address, uint256, bytes memory) public
virtual override returns (bytes4) {
return this.onERC721Received.selector;
}
}

'Gas Estimation Failed' Error when trying to deploy a contract on remix to the Ganache test net

This is what the error reads:
Gas estimation errored with the following message (see below). The
transaction execution will likely fail. Do you want to force sending?
Internal JSON-RPC error. { "message": "Returned error: project ID does
not have access to archive state", "code": -32000, "data": { "stack":
"Error: Returned error: project ID does not have access to archive
state\n at Object.ErrorResponse
(/usr/local/lib/node_modules/ganache-cli/build/ganache-core.node.cli.js:55:2110625)\n
at a
(/usr/local/lib/node_modules/ganache-cli/build/ganache-core.node.cli.js:55:2108932)\n
at
/usr/local/lib/node_modules/ganache-cli/build/ganache-core.node.cli.js:55:2093154\n
at runMicrotasks ()\n at processTicksAndRejections
(internal/process/task_queues.js:95:5)", "name": "Error" } }
I have made the settings for deployment on remix:
Injected Web 3
pragma solidity ^0.5.0;
pragma experimental ABIEncoderV2;
interface Structs {
struct Val {
uint256 value;
}
enum ActionType {
Deposit, // supply tokens
Withdraw, // borrow tokens
Transfer, // transfer balance between accounts
Buy, // buy an amount of some token (externally)
Sell, // sell an amount of some token (externally)
Trade, // trade tokens against another account
Liquidate, // liquidate an undercollateralized or expiring account
Vaporize, // use excess tokens to zero-out a completely negative account
Call // send arbitrary data to an address
}
enum AssetDenomination {
Wei // the amount is denominated in wei
}
enum AssetReference {
Delta // the amount is given as a delta from the current value
}
struct AssetAmount {
bool sign; // true if positive
AssetDenomination denomination;
AssetReference ref;
uint256 value;
}
struct ActionArgs {
ActionType actionType;
uint256 accountId;
AssetAmount amount;
uint256 primaryMarketId;
uint256 secondaryMarketId;
address otherAddress;
uint256 otherAccountId;
bytes data;
}
struct Info {
address owner; // The address that owns the account
uint256 number; // A nonce that allows a single address to control many accounts
}
struct Wei {
bool sign; // true if positive
uint256 value;
}
}
contract DyDxPool is Structs {
function getAccountWei(Info memory account, uint256 marketId) public view returns (Wei memory);
function operate(Info[] memory, ActionArgs[] memory) public;
}
/**
* #dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see `ERC20Detailed`.
*/
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
}
contract DyDxFlashLoan is Structs {
DyDxPool pool = DyDxPool(0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e);
address public WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
mapping(address => uint256) public currencies;
constructor() public {
currencies[WETH] = 1;
}
modifier onlyPool() {
require(
msg.sender == address(pool),
"FlashLoan: could be called by DyDx pool only"
);
_;
}
function tokenToMarketId(address token) public view returns (uint256) {
uint256 marketId = currencies[token];
require(marketId != 0, "FlashLoan: Unsupported token");
return marketId - 1;
}
// the DyDx will call `callFunction(address sender, Info memory accountInfo, bytes memory data) public` after during `operate` call
function flashloan(address token, uint256 amount, bytes memory data)
internal
{
IERC20(token).approve(address(pool), amount + 1);
Info[] memory infos = new Info[](1);
ActionArgs[] memory args = new ActionArgs[](3);
infos[0] = Info(address(this), 0);
AssetAmount memory wamt = AssetAmount(
false,
AssetDenomination.Wei,
AssetReference.Delta,
amount
);
ActionArgs memory withdraw;
withdraw.actionType = ActionType.Withdraw;
withdraw.accountId = 0;
withdraw.amount = wamt;
withdraw.primaryMarketId = tokenToMarketId(token);
withdraw.otherAddress = address(this);
args[0] = withdraw;
ActionArgs memory call;
call.actionType = ActionType.Call;
call.accountId = 0;
call.otherAddress = address(this);
call.data = data;
args[1] = call;
ActionArgs memory deposit;
AssetAmount memory damt = AssetAmount(
true,
AssetDenomination.Wei,
AssetReference.Delta,
amount + 1
);
deposit.actionType = ActionType.Deposit;
deposit.accountId = 0;
deposit.amount = damt;
deposit.primaryMarketId = tokenToMarketId(token);
deposit.otherAddress = address(this);
args[2] = deposit;
pool.operate(infos, args);
}
}
contract Flashloan is DyDxFlashLoan {
uint256 public loan;
constructor() public payable {
(bool success, ) = WETH.call.value(msg.value)("");
require(success, "fail to get weth");
}
function getFlashloan(address flashToken, uint256 flashAmount) external {
uint256 balanceBefore = IERC20(flashToken).balanceOf(address(this));
bytes memory data = abi.encode(flashToken, flashAmount, balanceBefore);
flashloan(flashToken, flashAmount, data); // execution goes to `callFunction`
}
function callFunction(
address, /* sender */
Info calldata, /* accountInfo */
bytes calldata data
) external onlyPool {
(address flashToken, uint256 flashAmount, uint256 balanceBefore) = abi
.decode(data, (address, uint256, uint256));
uint256 balanceAfter = IERC20(flashToken).balanceOf(address(this));
require(
balanceAfter - balanceBefore == flashAmount,
"contract did not get the loan"
);
loan = balanceAfter;
// Use the money here!
}
}

How can I implement chainlink vrf with giving reward to a RANDOM owner of my nft when someone mints it?

I am creating a nft collection and I want the random owner to receive a percentage of the mint price with each mint. But since I need to wait for the VRF response, can't figure out how to implement randomness function and function that will send the percentage to the vrf response (random owner).
pragma solidity >=0.7.0 <0.9.0;
import "#chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
contract Sofb is ERC721Enumerable, Ownable, VRFConsumerBase {
using Strings for uint256;
string baseURI;
string public baseExtension = ".json";
uint256 public cost = 0.015 ether;
uint256 public maxSupply = 7070;
uint256 public tokenCounter;
bool public paused = false;
bool public revealed = false;
string public notRevealedUri;
bytes32 internal keyHash;
uint256 internal fee;
uint256 public randomResult = 0;
address payable giftAddress = payable(msg.sender);
uint256 giftValue = 0;
mapping(bytes32 => uint256) public requestIdToRandomNumber;
mapping(bytes32 => address) public requestIdToAddress;
mapping(bytes32 => uint256) public requestIdToRequestNumberIndex;
uint256 public requestCounter;
constructor(string memory _name, string memory _symbol, string memory _initBaseURI, string memory _initNotRevealedUri, address _vrfCoordinator, address _linkToken, bytes32 _keyHash, uint256 _fee)
VRFConsumerBase(_vrfCoordinator, _linkToken)
ERC721(_name, _symbol) {
setBaseURI(_initBaseURI);
setNotRevealedURI(_initNotRevealedUri);
keyHash = _keyHash;
fee = _fee;
}
// internal
function _baseURI() internal view virtual override returns (string memory) {
return baseURI;
}
// public
function getRandomNumber() public returns (bytes32 requestId) {
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");
requestIdToAddress[requestId] = msg.sender;
requestIdToRequestNumberIndex[requestId] = requestCounter;
requestCounter += 1;
return requestRandomness(keyHash, fee);
}
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
requestIdToRandomNumber[requestId] = randomness;
uint256 requestNumber = requestIdToRequestNumberIndex[requestId];
}
function mint() public payable {
uint256 supply = totalSupply();
require(!paused);
require(supply + 1 <= maxSupply);
require(msg.value >= cost);
if (msg.sender != owner()) {
require(msg.value >= cost);
}
if (supply > 0) {
require(randomResult > 0);
giftAddress = payable(ownerOf(randomResult));
giftValue = ((supply + 1 == 5) || (supply + 1 == 10)) ? address(this).balance * 1 / 100 : msg.value * 10 / 100;
(bool success, ) = payable(giftAddress).call{value: giftValue}("");
require(success);
}
_safeMint(msg.sender, supply + 1);
getRandomNumber();
}
...
}
you should mint the token and put the mint logic inside the fulfillRandomness function, to access the data you will need i will recommend you to have an array of structs with the data you need, remember that random returns a requestId, use the request id as an index to get the stored data and then mint it, it's on you if you want to delete the data after mint the nft

Ethereum Remix: gas required exceeds allowance (30000000) issue

I'm trying to deploy a smart contract on BSC Testnet but the Remix IDE throws me error below:
I've got more than 3 BMB in my Metamask BinanceSmartChain Testnet wallet.
creation of ContractName errored: Internal JSON-RPC error. { "code": -32000, "message": "gas required exceeds allowance (30000000) or always failing transaction" }
My creating code:
Full code is at: https://www.codepile.net/pile/ObGN8kry
//SPDX-License-Identifier: Unlicensed
pragma solidity ^0.6.12;
contract ContractName is Context, IERC20, Ownable {
using SafeMath for uint256;
using Address for address;
mapping (address => uint256) private _rOwned;
mapping (address => uint256) private _tOwned;
mapping (address => mapping (address => uint256)) private _allowances;
mapping (address => bool) private _isExcludedFromFee;
mapping (address => bool) private _isExcluded;
address[] private _excluded;
uint256 private constant MAX = ~uint256(0);
uint256 private _tTotal = 100000000000 * 10**6 * 10**9;
uint256 private _rTotal = (MAX - (MAX % _tTotal));
uint256 private _tFeeTotal;
string private _name = "PENGUIN MOON";
string private _symbol = "PEGM";
uint8 private _decimals = 9;
uint256 public _taxFee = 3;
uint256 private _previousTaxFee = _taxFee;
uint256 public _liquidityFee = 5;
uint256 private _previousLiquidityFee = _liquidityFee;
IUniswapV2Router02 public immutable uniswapV2Router;
address public immutable uniswapV2Pair;
bool inSwapAndLiquify;
bool public swapAndLiquifyEnabled = true;
uint256 public _maxTxAmount = 500000000 * 10**6 * 10**9;
uint256 private numTokensSellToAddToLiquidity = 25000000 * 10**6 * 10**9;
event MinTokensBeforeSwapUpdated(uint256 minTokensBeforeSwap);
event SwapAndLiquifyEnabledUpdated(bool enabled);
event SwapAndLiquify(
uint256 tokensSwapped,
uint256 ethReceived,
uint256 tokensIntoLiqudity
);
modifier lockTheSwap {
inSwapAndLiquify = true;
_;
inSwapAndLiquify = false;
}
constructor () public {
_rOwned[_msgSender()] = _rTotal;
IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x10ED43C718714eb63d5aA57B78B54704E256024E);
// Create a uniswap pair for this new token
uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
.createPair(address(this), _uniswapV2Router.WETH());
// set the rest of the contract variables
uniswapV2Router = _uniswapV2Router;
//exclude owner and this contract from fee
_isExcludedFromFee[owner()] = true;
_isExcludedFromFee[address(this)] = true;
emit Transfer(address(0), _msgSender(), _tTotal);
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view returns (uint8) {
return _decimals;
}
function totalSupply() public view override returns (uint256) {
return _tTotal;
}
function balanceOf(address account) public view override returns (uint256) {
if (_isExcluded[account]) return _tOwned[account];
return tokenFromReflection(_rOwned[account]);
}
function transfer(address recipient, uint256 amount) public override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
function allowance(address owner, address spender) public view override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
function isExcludedFromReward(address account) public view returns (bool) {
return _isExcluded[account];
}
function totalFees() public view returns (uint256) {
return _tFeeTotal;
}
function deliver(uint256 tAmount) public {
address sender = _msgSender();
require(!_isExcluded[sender], "Excluded addresses cannot call this function");
(uint256 rAmount,,,,,) = _getValues(tAmount);
_rOwned[sender] = _rOwned[sender].sub(rAmount);
_rTotal = _rTotal.sub(rAmount);
_tFeeTotal = _tFeeTotal.add(tAmount);
}
function reflectionFromToken(uint256 tAmount, bool deductTransferFee) public view returns(uint256) {
require(tAmount <= _tTotal, "Amount must be less than supply");
if (!deductTransferFee) {
(uint256 rAmount,,,,,) = _getValues(tAmount);
return rAmount;
} else {
(,uint256 rTransferAmount,,,,) = _getValues(tAmount);
return rTransferAmount;
}
}
function tokenFromReflection(uint256 rAmount) public view returns(uint256) {
require(rAmount <= _rTotal, "Amount must be less than total reflections");
uint256 currentRate = _getRate();
return rAmount.div(currentRate);
}
function excludeFromReward(address account) public onlyOwner() {
// require(account != 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D, 'We can not exclude Uniswap router.');
require(!_isExcluded[account], "Account is already excluded");
if(_rOwned[account] > 0) {
_tOwned[account] = tokenFromReflection(_rOwned[account]);
}
_isExcluded[account] = true;
_excluded.push(account);
}
function includeInReward(address account) external onlyOwner() {
require(_isExcluded[account], "Account is already excluded");
for (uint256 i = 0; i < _excluded.length; i++) {
if (_excluded[i] == account) {
_excluded[i] = _excluded[_excluded.length - 1];
_tOwned[account] = 0;
_isExcluded[account] = false;
_excluded.pop();
break;
}
}
}
function _transferBothExcluded(address sender, address recipient, uint256 tAmount) private {
(uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee, uint256 tLiquidity) = _getValues(tAmount);
_tOwned[sender] = _tOwned[sender].sub(tAmount);
_rOwned[sender] = _rOwned[sender].sub(rAmount);
_tOwned[recipient] = _tOwned[recipient].add(tTransferAmount);
_rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);
_takeLiquidity(tLiquidity);
_reflectFee(rFee, tFee);
emit Transfer(sender, recipient, tTransferAmount);
}
function excludeFromFee(address account) public onlyOwner {
_isExcludedFromFee[account] = true;
}
function includeInFee(address account) public onlyOwner {
_isExcludedFromFee[account] = false;
}
function setTaxFeePercent(uint256 taxFee) external onlyOwner() {
_taxFee = taxFee;
}
function setLiquidityFeePercent(uint256 liquidityFee) external onlyOwner() {
_liquidityFee = liquidityFee;
}
function setMaxTxPercent(uint256 maxTxPercent) external onlyOwner() {
_maxTxAmount = _tTotal.mul(maxTxPercent).div(
10**2
);
}
function setSwapAndLiquifyEnabled(bool _enabled) public onlyOwner {
swapAndLiquifyEnabled = _enabled;
emit SwapAndLiquifyEnabledUpdated(_enabled);
}
//to recieve ETH from uniswapV2Router when swaping
receive() external payable {}
function _reflectFee(uint256 rFee, uint256 tFee) private {
_rTotal = _rTotal.sub(rFee);
_tFeeTotal = _tFeeTotal.add(tFee);
}
function _getValues(uint256 tAmount) private view returns (uint256, uint256, uint256, uint256, uint256, uint256) {
(uint256 tTransferAmount, uint256 tFee, uint256 tLiquidity) = _getTValues(tAmount);
(uint256 rAmount, uint256 rTransferAmount, uint256 rFee) = _getRValues(tAmount, tFee, tLiquidity, _getRate());
return (rAmount, rTransferAmount, rFee, tTransferAmount, tFee, tLiquidity);
}
function _getTValues(uint256 tAmount) private view returns (uint256, uint256, uint256) {
uint256 tFee = calculateTaxFee(tAmount);
uint256 tLiquidity = calculateLiquidityFee(tAmount);
uint256 tTransferAmount = tAmount.sub(tFee).sub(tLiquidity);
return (tTransferAmount, tFee, tLiquidity);
}
function _getRValues(uint256 tAmount, uint256 tFee, uint256 tLiquidity, uint256 currentRate) private pure returns (uint256, uint256, uint256) {
uint256 rAmount = tAmount.mul(currentRate);
uint256 rFee = tFee.mul(currentRate);
uint256 rLiquidity = tLiquidity.mul(currentRate);
uint256 rTransferAmount = rAmount.sub(rFee).sub(rLiquidity);
return (rAmount, rTransferAmount, rFee);
}
function _getRate() private view returns(uint256) {
(uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
return rSupply.div(tSupply);
}
function _getCurrentSupply() private view returns(uint256, uint256) {
uint256 rSupply = _rTotal;
uint256 tSupply = _tTotal;
for (uint256 i = 0; i < _excluded.length; i++) {
if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply) return (_rTotal, _tTotal);
rSupply = rSupply.sub(_rOwned[_excluded[i]]);
tSupply = tSupply.sub(_tOwned[_excluded[i]]);
}
if (rSupply < _rTotal.div(_tTotal)) return (_rTotal, _tTotal);
return (rSupply, tSupply);
}
function _takeLiquidity(uint256 tLiquidity) private {
uint256 currentRate = _getRate();
uint256 rLiquidity = tLiquidity.mul(currentRate);
_rOwned[address(this)] = _rOwned[address(this)].add(rLiquidity);
if(_isExcluded[address(this)])
_tOwned[address(this)] = _tOwned[address(this)].add(tLiquidity);
}
function calculateTaxFee(uint256 _amount) private view returns (uint256) {
return _amount.mul(_taxFee).div(
10**2
);
}
function calculateLiquidityFee(uint256 _amount) private view returns (uint256) {
return _amount.mul(_liquidityFee).div(
10**2
);
}
function removeAllFee() private {
if(_taxFee == 0 && _liquidityFee == 0) return;
_previousTaxFee = _taxFee;
_previousLiquidityFee = _liquidityFee;
_taxFee = 0;
_liquidityFee = 0;
}
function restoreAllFee() private {
_taxFee = _previousTaxFee;
_liquidityFee = _previousLiquidityFee;
}
function isExcludedFromFee(address account) public view returns(bool) {
return _isExcludedFromFee[account];
}
function _approve(address owner, address spender, uint256 amount) private {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _transfer(
address from,
address to,
uint256 amount
) private {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
require(amount > 0, "Transfer amount must be greater than zero");
if(from != owner() && to != owner())
require(amount <= _maxTxAmount, "Transfer amount exceeds the maxTxAmount.");
// is the token balance of this contract address over the min number of
// tokens that we need to initiate a swap + liquidity lock?
// also, don't get caught in a circular liquidity event.
// also, don't swap & liquify if sender is uniswap pair.
uint256 contractTokenBalance = balanceOf(address(this));
if(contractTokenBalance >= _maxTxAmount)
{
contractTokenBalance = _maxTxAmount;
}
bool overMinTokenBalance = contractTokenBalance >= numTokensSellToAddToLiquidity;
if (
overMinTokenBalance &&
!inSwapAndLiquify &&
from != uniswapV2Pair &&
swapAndLiquifyEnabled
) {
contractTokenBalance = numTokensSellToAddToLiquidity;
//add liquidity
swapAndLiquify(contractTokenBalance);
}
//indicates if fee should be deducted from transfer
bool takeFee = true;
//if any account belongs to _isExcludedFromFee account then remove the fee
if(_isExcludedFromFee[from] || _isExcludedFromFee[to]){
takeFee = false;
}
//transfer amount, it will take tax, burn, liquidity fee
_tokenTransfer(from,to,amount,takeFee);
}
function swapAndLiquify(uint256 contractTokenBalance) private lockTheSwap {
// split the contract balance into halves
uint256 half = contractTokenBalance.div(2);
uint256 otherHalf = contractTokenBalance.sub(half);
// capture the contract's current ETH balance.
// this is so that we can capture exactly the amount of ETH that the
// swap creates, and not make the liquidity event include any ETH that
// has been manually sent to the contract
uint256 initialBalance = address(this).balance;
// swap tokens for ETH
swapTokensForEth(half); // <- this breaks the ETH -> HATE swap when swap+liquify is triggered
// how much ETH did we just swap into?
uint256 newBalance = address(this).balance.sub(initialBalance);
// add liquidity to uniswap
addLiquidity(otherHalf, newBalance);
emit SwapAndLiquify(half, newBalance, otherHalf);
}
function swapTokensForEth(uint256 tokenAmount) private {
// generate the uniswap pair path of token -> weth
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = uniswapV2Router.WETH();
_approve(address(this), address(uniswapV2Router), tokenAmount);
// make the swap
uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
tokenAmount,
0, // accept any amount of ETH
path,
address(this),
block.timestamp
);
}
function addLiquidity(uint256 tokenAmount, uint256 ethAmount) private {
// approve token transfer to cover all possible scenarios
_approve(address(this), address(uniswapV2Router), tokenAmount);
// add the liquidity
uniswapV2Router.addLiquidityETH{value: ethAmount}(
address(this),
tokenAmount,
0, // slippage is unavoidable
0, // slippage is unavoidable
owner(),
block.timestamp
);
}
//this method is responsible for taking all fee, if takeFee is true
function _tokenTransfer(address sender, address recipient, uint256 amount,bool takeFee) private {
if(!takeFee)
removeAllFee();
if (_isExcluded[sender] && !_isExcluded[recipient]) {
_transferFromExcluded(sender, recipient, amount);
} else if (!_isExcluded[sender] && _isExcluded[recipient]) {
_transferToExcluded(sender, recipient, amount);
} else if (!_isExcluded[sender] && !_isExcluded[recipient]) {
_transferStandard(sender, recipient, amount);
} else if (_isExcluded[sender] && _isExcluded[recipient]) {
_transferBothExcluded(sender, recipient, amount);
} else {
_transferStandard(sender, recipient, amount);
}
if(!takeFee)
restoreAllFee();
}
function _transferStandard(address sender, address recipient, uint256 tAmount) private {
(uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee, uint256 tLiquidity) = _getValues(tAmount);
_rOwned[sender] = _rOwned[sender].sub(rAmount);
_rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);
_takeLiquidity(tLiquidity);
_reflectFee(rFee, tFee);
emit Transfer(sender, recipient, tTransferAmount);
}
function _transferToExcluded(address sender, address recipient, uint256 tAmount) private {
(uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee, uint256 tLiquidity) = _getValues(tAmount);
_rOwned[sender] = _rOwned[sender].sub(rAmount);
_tOwned[recipient] = _tOwned[recipient].add(tTransferAmount);
_rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);
_takeLiquidity(tLiquidity);
_reflectFee(rFee, tFee);
emit Transfer(sender, recipient, tTransferAmount);
}
function _transferFromExcluded(address sender, address recipient, uint256 tAmount) private {
(uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee, uint256 tLiquidity) = _getValues(tAmount);
_tOwned[sender] = _tOwned[sender].sub(tAmount);
_rOwned[sender] = _rOwned[sender].sub(rAmount);
_rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);
_takeLiquidity(tLiquidity);
_reflectFee(rFee, tFee);
emit Transfer(sender, recipient, tTransferAmount);
}
}
``
IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x10ED43C718714eb63d5aA57B78B54704E256024E);
// Create a uniswap pair for this new token
uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
.createPair(address(this), _uniswapV2Router.WETH());
These lines in your constructor are trying to interact with a contract that exists on the mainnet. But you're on the testnet, where there's no contract on this address.
As stated in this post, the Pancake testnet router address is 0xD99D1c33F9fC3444f8101754aBC46c52416550D1. So you need to replace the hardcoded address to this one.