Is it safe to read the ethereum smart contract balance directly to calculate the transfer of assets to users? - ethereum

I have contract, through which users can trade on DEX.
Like this:
// transfer asset A from msg.sender
ERC20(AToken).transferFrom(msg.sender, address(this), amount);
// do trade A to B
... trade logic here
// get balance of asset B after trade
// asset B after trade gets to this contract address
uint256 returnAmount = ERC20(BToken).balanceOf(address(this));
// transfer asset B to msg.sender
ERC20(BToken).transfer(msg.sender, returnAmount);
I wonder about returnAmount, is this logic safe?
Transactions in ethereum are performed either completely or not performed at all, and also in order of priority.
But I’m still wondering if there could be such a case when returnAmount shows incorrectly, for example, contract get the balance after the transaction of another user?

Transactions in ETH are executed one by one, other transactions can not interfere to execution of a transaction when it's running by EVM.

Related

Allowance failed when attempting to transfer LINK tokens

I'm creating a smart contract where users can create NFT raffles. I will be using Chainlink VRF for getting provably fair results. For this, the user who creates the raffle needs to supply the contract with LINK tokens. I'm attempting to transfer these tokens using an allowance.
function initRaffle(address _tokenContract, uint256 _tokenId, uint256 _ticketPrice) external {
require(_ticketPrice > 0, "Ticket price must be bigger than 0");
require(LINKToken.balanceOf(msg.sender) >= ChainlinkFee, "Insufficient LINK supplied");
require(LINKToken.allowance(msg.sender, address(this)) >= ChainlinkFee, "Allowance failed");
Running initRaffle results in Allowance failed. I've checked and the LINKToken.balanceOf(msg.sender) is bigger than the fee, so that shouldn't be the problem. The LINKToken.balanceOf(address(this)) is 0.
What's going wrong? And how do I create a working function for having the user transfer (fee amount) link tokens to the contract.
The user needs to invoke approve(yourContractAddress, feeAmount) directly on the LINKToken contract (not through your contract). This sets the allowance.
You can then use transferFrom() to pull tokens (up to the allowed amount) from the user's wallet.
bool success = LINKToken.transferFrom(msg.sender, address(this), ChainlinkFee);

Block OpenSea trading

Is there a way to avoid trading NFTs on standard marketplaces like OpenSea without breaking the erc721 standard?
If so, how would you go about it?
It is about an NFT that is something like a voucher that can be used 5 times. Over 5 years, once per year. I would like to prevent that someone unknowingly buys a redeemed voucher (for the current year).
You can include checks in your transfer function.
Keep a global map counter with token IDs pointing to the number of transactions per token
mapping(uint256=> uint256) private _tokenTx;
Now, in your transfer function you can use the NFT id, check in the map to see if it's lower than 5, if it is, you fail the tx, otherwise you continue and increase the number
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
require(to != address(0), "ERC721: transfer to the zero address");
**require(_tokenTx[tokenId] <6, "ERC721: can\'t transfer more than 5 times");**
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
**_tokenTx[tokenId] = _tokenTx[tokenId]+1;**
emit Transfer(from, to, tokenId);
}
As for filtering exchanges transfers, you can either keep a dynamic list with the addresses they use, or block the approval processes altogether.
The first keeps the standard better but is harder and more expensive to keep up, the second one is a bit more aggressive but will work for all popular exchanges out there
Or, if you're using an external link to redirect buyers/traders to the text file that lists the voucher code, all you have to do is replace the voucher code(s) with a message saying that all the vouchers have been redeemed and then save the file. That way, the next time the NFT gets traded and they unlock the link, they'll see the message.
I sure as hell ain't going to waste my time trying to figure out all that coding nonesense...lol.

Best way to register for a vote in solidity

Hi I'm creating a voting smart contract for a DAO and I have a security question. The voting system works like this:
You send your tokens to the smart contract then the smart contract registers how much tokens you have and assignes you "Power" which you use when you vote. Then the smart contract sends the funds back immidiately.
My question is if there is more secure way to do this. Without funds leaving usere's wallet.
Here is the code I have so far.
function getPower() payable public {
require(msg.value > 0, "The amount can't be 0");
require(election_state == ELECTION_STATE.OPEN);
require(votingPeriod > block.timestamp);
uint amountSent = msg.value;
// This function will take their money and assign power to the voter
// The power is equal to their deposit in eth * 10 so for each eth they get 10 power
voters[msg.sender].power = msg.value * 10;
payable(msg.sender).transfer(amountSent);
}
Thanks in advance.
Based on the provided code and question, I'm assuming you want to calculate the voting power based on the users' ETH balance - not based on their balance of the DAO token.
You can get the current ETH balance of an address, using the .balance member of an address type. So you could simplify your function as this:
function getPower() public {
require(election_state == ELECTION_STATE.OPEN);
require(votingPeriod > block.timestamp);
voters[msg.sender].power = msg.sender.balance * 10;
}
After performing the validations, it assigns the value based on the msg.sender ETH balance at the moment of the getPower() function being invoked. Without them needing to send ETH to the contract.
Note that this approach is not common and can be misused for example by users loaning a large amount of ETH just before executing the getPower() function. I'd recommend you to use a more common pattern of calculating the voting power based on their current holdings of the token representing their stake in the DAO.

Transfer money between accounts in solidity

I am writing a contract where I want to transfer money (present in the contract owners account and not the contract) to an account address passed to a function in the contract.
for some reason this code won't work
function payBill(uint value, address account) payable public {
account.transfer(value);
transactionCount += 1;
transactionAmount += value;
}
Your problem can be related to any frontend code, not only this.
You've got two options.
get that other user address from the contract and then run a direct transaction between two accounts (example here https://web3js.readthedocs.io/en/v1.2.6/web3-eth.html#id80)
send a value (see here https://web3js.readthedocs.io/en/v1.2.6/web3-eth-contract.html#id33) when you are calling the payBill method. If you don't do it, the default value is zero, and you don't see any transfer.
Also, please consider having a look at this https://diligence.consensys.net/blog/2019/09/stop-using-soliditys-transfer-now/
EDIT:
what you are trying to do here, is also not doable. This requires the contract to have the number of funds that you want to transfer. That is because, with the payable method, you are sending funds to the contract, but the funds will only be in the contract, once the transaction is accepted. On the other hand, you are trying to send that number of funds to another user, without having them on the contract. That is why you never see any balance.

Can one contract own tokens of another one

if I got it right smart contracts do not have a private key, so they can not sign transactions. The first transaction is signed buy the user and if a contract calls another contract and so on, those transactions are also signed buy the user. So, what if we have two ERC20 contracts A and B and B holds some A tokens.
contract A{
....
//balance of contract B
balanceOf[0xE4e5a16C8fx207a07f7df98e3a85e2067feacB9w]=500;
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}
....
}
contract B{
//address this=0xE4e5a16C8fx207a07f7df98e3a85e2067feacB9w
}
What if some user pretend to to be a contract B calling contract A?
I mean he will sign the sequence of transactions where the last one would not come from the contract B, but contract A will think so.
It will look like this:
{
data: "0xa9059cbb000000000000000000000000cf2ee9c0dccd39aac2fd44b744270f50f8af13b00000000000000000000000000000000000000000000000000000000000000064",
from: "0xE4e5a16C8fx207a07f7df98e3a85e2067feacB9w ",//address B
gas: 210000,
gasPrice: 1,
nonce: "24",
to: "0xa6d90569018967c5esc7d056f74eg4hc3j8ae93" //address A
}
If he do so, it is possible for him, using function transfer in contract A and passing in it his own address to steal tokens from contract B balance in contract A.
So am I right and this is really possible or I made a mistake somewhere? And if it is possible, how in this case a contract can own tokens of other contracts?
Yes, contracts can own tokens.
The transaction you specified won't work; you can't just pick a from address. A transaction is sent from an externally owned account (EOA), meaning an account that has a private key. And only the person with that private key can sign such a transaction. See if this blog post helps: https://programtheblockchain.com/posts/2017/12/29/how-ethereum-transactions-work/.
I think I found an answer to my question.
A first person, who signs a sequence of messages can not cheat and substitute the second message, because when nodes will validate his actions they will all run this sequence of messages on their EVM and if the second message is not valid(i.e it is not coming from the contract) the state will not change.