Check which tokens came to the contract - ethereum

Solidity. How do I check which tokens were sent to the contract? How do I check the USDT token?
contract DEX {
event Bought(uint256 amount);
event Sold(uint256 amount);
IERC20 public token;
constructor() public {
token = new ERC20Basic();
}
function buy() payable public {
uint256 amountTobuy = msg.value;
uint256 dexBalance = token.balanceOf(address(this));
require(amountTobuy > 0, "You need to send some Ether");
require(amountTobuy <= dexBalance, "Not enough tokens in the reserve");
token.transfer(msg.sender, amountTobuy);
emit Bought(amountTobuy);
}
function sell(uint256 amount) public {
require(amount > 0, "You need to sell at least some tokens");
uint256 allowance = token.allowance(msg.sender, address(this));
require(allowance >= amount, "Check the token allowance");
token.transferFrom(msg.sender, address(this), amount);
msg.sender.transfer(amount);
emit Sold(amount);
}
}

You're looking for the balanceOf function, you could use OpenZepplin's implementation of this as well.
uint balance = token.balanceOf(account);
For each token you want to check, you'll need the tokens address too. So for USDT, you'd need the token address of USDT. Then you could do something like (nodejs syntax):
pragma solidity ^0.6.0;
import "#openzeppelin/contracts/token/ERC20/IERC20.sol";
contract GetBalance{
constructor() public {
}
function getBalanceOfToken(address _USDT_ADDRESS) public returns (uint){
usdt = IERC20(_USDT_ADDRESS);
uint balance = usdt.balanceOf(address(this));
return balance;
}
}

Related

Transaction is getting reverted in the `refundToInsurer()` function call

The deployment of InsuranceProvider is working fine and the calling of newContract() with the required parameters is successfully creating/deploying the InsuranceConsumer contract. Even, the payOutContract() is working correctly in terms of transferring the ETH balance from the InsuranceConsumer to the client's wallet.
The issue is with the refundToInsurer() function, as it's expected to transfer the ETH balance from the InsuranceConsumer to the insurer's wallet, but it's transaction is getting failed/reverted.
Here's the code:
SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract InsuranceProvider {
address payable public insurer;
AggregatorV3Interface internal priceFeed;
modifier onlyOwner() {
require(insurer == msg.sender, "Only Insurance provider can do this");
_;
}
constructor() payable {
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
insurer = payable(msg.sender);
}
function newContract(
address payable _client,
uint256 _premium,
uint256 _payoutValue
) public payable onlyOwner returns (address) {
//create contract, send payout amount so contract is fully funded plus a small buffer
InsuranceConsumer i = (new InsuranceConsumer){
value: ((_payoutValue * 1 ether) / (uint256(getLatestPrice())))
}(_client, _premium, _payoutValue);
return address(i);
}
function getLatestPrice() public view returns (int256) {
(, int256 price, , uint256 timeStamp, ) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
function payOutContract(address _contract) public {
InsuranceConsumer i = InsuranceConsumer(_contract);
// Transfer agreed amount to client
i.payOutContract();
}
function refundToInsurer(address _contract) public onlyOwner {
InsuranceConsumer i = InsuranceConsumer(_contract);
// Transfer back the amount to insurer
i.refundToInsurer();
}
}
contract InsuranceConsumer {
AggregatorV3Interface internal priceFeed;
address payable public insurer;
address payable client;
uint256 startDate;
uint256 premium;
uint256 payoutValue;
constructor(
address payable _client,
uint256 _premium,
uint256 _payoutValue
) payable {
//set ETH/USD Price Feed
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
//first ensure insurer has fully funded the contract
require(
msg.value >= _payoutValue / uint256(getLatestPrice()),
"Not enough funds sent to contract"
);
//now initialize values for the contract
insurer = payable(msg.sender);
client = _client;
startDate = block.timestamp; //contract will be effective immediately on creation
premium = _premium;
payoutValue = _payoutValue;
}
function payOutContract() public {
//Transfer agreed amount to client
client.transfer(address(this).balance);
}
function refundToInsurer() public {
// Transfer back the amount to insurer
insurer.transfer(address(this).balance);
}
function getLatestPrice() public view returns (int256) {
(, int256 price, , uint256 timeStamp, ) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
}
Can anyone please help by pointing out the logical mistake that I'm doing in the refundToInsurer() function ?
As, we're creating the InsuranceConsumer using the newContract() function of InsuranceProvider. Therefore, the msg.sender of the InsuranceConsumer is going to be the InsuranceProvider itself, not the insurer's wallet.
So, when we're calling the refundInsurer() of InsuranceConsumer via InsuranceProvider, then it's doing:
insurer.transfer(address(this).balance);
It means to transfer the available ETH in the InsuranceConsumer to the InsuranceProvider (not the insurer's wallet), and since InsuranceProvider is not expected to be a receiver, that's why it's reverting the transaction.
So, the corrected code will be:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract InsuranceProvider {
address payable public insurer;
AggregatorV3Interface internal priceFeed;
modifier onlyOwner() {
require(insurer == msg.sender, "Only Insurance provider can do this");
_;
}
constructor() payable {
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
insurer = payable(msg.sender);
}
function newContract(
address payable _client,
uint256 _premium,
uint256 _payoutValue
) public payable onlyOwner returns (address) {
//create contract, send payout amount so contract is fully funded plus a small buffer
InsuranceConsumer i = (new InsuranceConsumer){
value: ((_payoutValue * 1 ether) / (uint256(getLatestPrice())))
}(_client, _premium, _payoutValue);
return address(i);
}
function getLatestPrice() public view returns (int256) {
(, int256 price, , uint256 timeStamp, ) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
function payOutContract(address _contract) public onlyOwner {
// Transfer agreed amount to client
InsuranceConsumer i = InsuranceConsumer(_contract);
i.payOutContract();
}
function refundToInsurer(address _contract) public onlyOwner {
// Transfer back the amount to insurer
InsuranceConsumer i = InsuranceConsumer(_contract);
i.refundToInsurer(insurer);
}
}
contract InsuranceConsumer {
AggregatorV3Interface internal priceFeed;
address payable public insurer;
address payable client;
uint256 startDate;
uint256 premium;
uint256 payoutValue;
constructor(
address payable _client,
uint256 _premium,
uint256 _payoutValue
) payable {
//set ETH/USD Price Feed
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
//first ensure insurer has fully funded the contract
require(
msg.value >= _payoutValue / uint256(getLatestPrice()),
"Not enough funds sent to contract"
);
//now initialize values for the contract
insurer = payable(msg.sender);
client = _client;
startDate = block.timestamp; //contract will be effective immediately on creation
premium = _premium;
payoutValue = _payoutValue;
}
function payOutContract() public {
//Transfer agreed amount to client
client.transfer(address(this).balance);
}
function refundToInsurer(address payable _insurer) public {
// Transfer back the amount to insurer
_insurer.transfer(address(this).balance);
}
function getLatestPrice() public view returns (int256) {
(, int256 price, , uint256 timeStamp, ) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
}
Now, while calling the refundInsurer(), we're explicitly passing the insurer as the parameter, and it's taking the value of msg.sender from InsuranceProvider, so the msg.sender is going to be the insurer's wallet (with which the InsuranceProvider is being deployed) in this case.
And now, when we're calling the refundInsurer() of InsuranceConsumer via InsuranceProvider, then it's doing:
_insurer.transfer(address(this).balance);
It means to transfer the available ETH in the InsuranceConsumer to the insurer's wallet. So, the transaction will be successful resulting in the withdrawal of the funds from the InsuranceConsumer to the insurer's wallet.

ERC721 Invalid token id

I am building a NFT Marketplace
I use 2 smart contracts to :
first, mint the token
then, call setApprovalForAll() to authorize the marketplace contract to transfer the token
strangely, the owner is address(0) when it should be the msg.sender when I created the token last
" The transaction has been reverted to the initial state.
Reason provided by the contract: "ERC721: invalid token ID". "
This the source code of the 2 smart contracts below :
smart contract : NFT
smart contract : NFTMarketplace
Thanks for the help
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "./#openzeppelin/contracts/utils/Counters.sol";
import "./#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "./#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "./#openzeppelin/contracts/security/ReentrancyGuard.sol";
contract NFT is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
address contractAddress;
constructor(address marketplaceAddress) ERC721("NFTMarketplace", "NFTM") {
contractAddress = marketplaceAddress;
}
event TokenMinted (
uint256 indexed tokenId,
string tokenURI
);
function createToken(string memory tokenURI) public returns (uint) {
uint256 currentTokenId = _tokenIds.current();
_safeMint(msg.sender, currentTokenId);
_setTokenURI(currentTokenId, tokenURI);
setApprovalForAll(contractAddress, true);
_tokenIds.increment();
emit TokenMinted(currentTokenId, tokenURI);
return currentTokenId;
}
function getCurrentToken() public view returns (uint256) {
return _tokenIds.current();
}
}
contract NFTMarketplace is ReentrancyGuard, ERC721 {
using Counters for Counters.Counter;
//_tokenIds variable has the most recent minted tokenId
//Keeps track of the number of items sold on the marketplace
Counters.Counter private _itemsSold;
//owner is the contract address that created the smart contract
address payable owner;
//The fee charged by the marketplace to be allowed to list an NFT
uint256 listPrice = 0.01 ether;
constructor() ERC721("NFTMarketplace", "NFTM") {}
//The structure to store info about a listed token
struct Token {
uint256 tokenId;
string tokenURI;
address nftContract;
string name;
address payable owner;
uint256 price;
bool isListed;
}
//the event emitted when a token is successfully listed
event TokenListedSuccess (
uint256 indexed tokenId,
address nftContract,
address owner,
uint256 price,
bool isListed
);
//This mapping maps tokenId to token info and is helpful when retrieving details about a tokenId
mapping(uint256 => Token) private idToToken;
function updateListPrice(uint256 _listPrice) public payable {
require(owner == msg.sender, "Only owner can update listing price");
listPrice = _listPrice;
}
//The first time a token is created, it is listed here
// make it payable with money -- add require
function listToken(address nftContract, uint256 currentTokenId, string memory tokenURI, string memory name, uint256 price) public payable {
require(msg.value > 0, "Price must be at least 1 wei");
require(msg.value == listPrice, "Price must be equal to listing price");
idToToken[currentTokenId] = Token(
currentTokenId,
tokenURI,
nftContract,
name,
payable(address(this)),
listPrice,
true
);
emit TokenListedSuccess(
currentTokenId,
nftContract,
msg.sender,
listPrice,
true
);
}
function buyNFT(address nftContract, uint256 itemId) public payable nonReentrant {
uint price = idToToken[itemId].price;
uint tokenId = idToToken[itemId].tokenId;
address seller = ERC721.ownerOf(tokenId);
address buyer = msg.sender;
require(msg.value > 0, "You need to send some ether");
require(buyer != seller,"You already own this nft");
require(msg.value == price, "Please submit the asking price in order to complete the purchase");
idToToken[itemId].isListed = false;
idToToken[itemId].owner = payable(buyer);
payable(seller).transfer(price);
_itemsSold.increment();
IERC721(nftContract).transferFrom(seller, buyer, tokenId);
}
/* ...rest of smart contract */
}
I think you forget to assign "owner" value.
Typically, we set it in constructor.
like
constructor() {
i_owner = msg.sender;
}

Despite using the receive() function, my contract is not receiving payment in Remix

I am writing a smart contract in Remix with Solidity. The purpose of the contract is to allow a user to mint an NFT for 1 ETH. At present, the user is able to mint and the contract accepts the payment (ie. the user's balance is properly subtracted). But when I check the address(this).balance of the contract with my accountBalance() function, the function returns 0. I have included the receive() function as per the Solidity docs:
event Received(address, uint);
receive() external payable {
emit Received(msg.sender, msg.value);
}
Can someone explain why this is happening and what I need to change about my contract? Here is my contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
// imports
import '#openzeppelin/contracts/token/ERC721/ERC721.sol';
import '#openzeppelin/contracts/access/Ownable.sol';
import '#openzeppelin/contracts/security/PullPayment.sol';
// contract
contract RobocopPoster is ERC721, Ownable, PullPayment {
// constants
uint256 public mintPrice;
uint256 public totalSupply;
uint256 public maxSupply;
uint256 public maxPerWallet;
bool public mintEnabled;
mapping (address => uint256) public walletMints;
// constructor
// initialize variables
constructor() payable ERC721('RobocopPoster', 'SFFPC') {
mintPrice = 1 ether;
totalSupply = 0;
maxSupply = 1000;
maxPerWallet = 3;
}
event Received(address, uint);
receive() external payable {
emit Received(msg.sender, msg.value);
}
// functions
function setMintEnabled(bool mintEnabled_) external onlyOwner {
mintEnabled = mintEnabled_;
}
function withdrawPayments(address payable payee) public override onlyOwner virtual {
super.withdrawPayments(payee);
}
function accountBalance() public view returns (uint256) {
return (address(this).balance);
}
function mint(uint256 quantity_) public payable {
require(mintEnabled, 'Minting not enabled.');
require(msg.value == quantity_ * mintPrice, 'wrong mint value');
require(totalSupply + quantity_ <= maxSupply, 'sold out');
require(walletMints[msg.sender] + quantity_ <= maxPerWallet, 'exceed max wallet');
walletMints[msg.sender] += quantity_;
_asyncTransfer(address(this), msg.value);
for (uint i = 0; i < quantity_; i++) {
uint256 newTokenId = totalSupply + 1;
totalSupply++;
_safeMint(msg.sender, newTokenId);
}
}
}
You need to call withdrawPayments to receive the fund, because _asyncTransfer from PullPayment in your contract minting sent the fund to the escrow contract. That's why you saw zero balance in ERC721 contract.

How to send correctly ETH from the manager's deposit to user if an event occurs?

I have this smart contract that I am trying to test. The manager deposits a certain amount of ether. Users can use the vault to earn extra ethers by locking own ether. Users deposit the amount of ether they want (ex 0.10 ETH) and set the seconds for locking. When users deposit, the price of ethereum is recorded via chainlink. If at the end of the locking period the price of ethereum is less than 2000$ the user receives the amount of locked ETH (0.10 ETH) + 2x (0.20ETH) the amount of locked ethers. The extra ethers are taken from the manager's deposit.
The code seems to work fine and the console returns no errors. I am testing the smart contract on the Kovan network. The problem is encountered when the user tries to withdraw the ethereums. When he withdraws, only the deposited ones are returned without the extra ethers being added.
I am new to Solidity so I appreciate any criticism or advice. If there is something already existing similar to what I am trying to create please let me know.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
interface EACAggregatorProxy {
function latestAnswer() external view returns (int256);
}
contract oracleLink {
address public manager;
uint256 public managerDeposit;
uint256[] public managerDeposits;
constructor() payable {
manager = msg.sender;
managerDeposit = msg.value;
managerDeposits.push(managerDeposit);
}
function depositVault() public payable {
require(msg.sender == manager);
}
address public user;
uint256 public userContribution;
uint256 public userCount;
uint256 deadline;
uint256 lockAmount = lockAmounts[msg.sender];
mapping(address => uint) lockAmounts;
uint256 startTime = startTimes[block.timestamp];
mapping(uint => uint) startTimes;
address public chainLinkETHUSDAddress = 0x9326BFA02ADD2366b30bacB125260Af641031331;
uint public ethPrice = 0;
uint256 public price = ethPrice;
function deposit(uint256 numberOfSeconds) public payable {
lockAmounts[msg.sender] = msg.value;
startTimes[block.timestamp] = block.timestamp;
user = msg.sender;
userContribution = msg.value;
userCount++;
deadline = block.timestamp + (numberOfSeconds * 1 seconds);
int256 chainLinkEthPrice = EACAggregatorProxy(chainLinkETHUSDAddress).latestAnswer();
ethPrice = uint(chainLinkEthPrice / 100000000);
}
function withdraw() public payable {
if (ethPrice <= 2000) {
uint256 toWithdraw = lockAmounts[msg.sender];
uint256 amountOfToken = toWithdraw * 2;
payable(manager).transfer(amountOfToken);
}
require(block.timestamp >= deadline);
uint256 amountToWithdraw = lockAmounts[msg.sender];
lockAmounts[msg.sender] = 0;
payable(msg.sender).transfer(amountToWithdraw);
}
}
So the one thing that I noticed is that when you try to send the additional ETH to the recipient's address you're actually trying to send it back to the manager and not the recipient. Also note that you should avoid using the transfer method and use the call method instead: call{value: amount}("") should now be used for transferring ether (Do not use send or transfer.) as of May 2021.
So your withdraw method should look something like this instead:
function withdraw() public payable {
address recipient = msg.sender;
uint256 additionalToken;
if (ethPrice <= 2000) {
additionalToken = lockAmounts[msg.sender] * 2;
}
require(block.timestamp >= deadline);
uint256 amountToWithdraw = lockAmounts[msg.sender] + additionalToken;
lockAmounts[msg.sender] = 0;
(bool success, ) = payable(recipient).call{value: amountToWithdraw}("");
require(success, "Transfer failed.");
}
Hopefully this helps.

Sending ether to a payable function in Solidity doesn't decrease the sender's Ether in Ganache

I have the following smart contract:
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./MyCoinSupply.sol";
contract MyCoinDEX
{
IERC20 public token;
event Bought(uint256 amount);
event Sold(uint256 amount);
constructor() public
{
token = new MyCoinSupply();
}
function getSenderAddress() public view returns (address) // for debugging purposes
{
return (msg.sender);
}
function getAddress() public view returns (address)
{
return address(this);
}
function getTokenAddress() public view returns (address)
{
return address(token);
}
function buy() payable public // send ether and get tokens in exchange; 1 token == 1 ether
{
uint256 amountTobuy = msg.value;
uint256 dexBalance = token.balanceOf(address(this));
require(amountTobuy > 0, "You need to send some ether");
require(amountTobuy <= dexBalance, "Not enough tokens in the reserve");
token.transfer(msg.sender, amountTobuy);
emit Bought(amountTobuy);
}
function sell(uint256 amount) public // send tokens to get ether back
{
require(amount > 0, "You need to sell at least some tokens");
uint256 allowance = token.allowance(msg.sender, address(this));
require(allowance >= amount, "Check the token allowance");
token.transferFrom(msg.sender, address(this), amount);
// https://stackoverflow.com/questions/67341914/error-send-and-transfer-are-only-available-for-objects-of-type-address-payable
payable(msg.sender).transfer(amount);
emit Sold(amount);
}
}
if I call the buy() method from truffle console, it executes without any exceptions:
truffle(development)> MyCoinDEX.buy({value: 1})
I verified that the account calling the buy() method receives the token. However, the balance of Ether in Ganache for the account calling the buy() method doesn't decrease. So essentially, the account is getting tokens for free.
What's going on here? How do I fix it?
I am not sure but it would be necessary to investigate about the balance of the contract account. The gas for token.transfer might be paid by the contract account balance, since the contract account is the transaction sender for token contract.
Or the balance decrement would be unnoticeable because it is too small.
I would be happy to know about the answer if you have found out.