How to Pass NFT Trait Property Securely To Smart Contract - ethereum

I have an NFT staking contract that issues rewards based on the property rarity of the NFT staked. The four property tiers are 1,2,3 and 4.
When a user clicks stakeNFT(tokenId, nftTier), I use the tokenId to pull the metadata json property from IPFS and send the NFT tier to the smart contract.
The issue here is while this works on the user interface of our website, anyone can use Etherscan directly and input an tier that isn’t in their NFT so as to earn more rewards.
How do I verify the NFT tier based on the tokenId onchain?

Related

How to check whether user has any ERC1155 of specific contract in solidity?

I'm writing a staking smart-contract for ERC1155 contract (https://etherscan.io/address/0x2013ff029f9d3d31169f4fdc673c8b9fa0ce1fbd#code). When user wants to claim his reward, I need to check whether he owns any token of another ERC721 contract (https://etherscan.io/address/0x50add0f8541df53765848f6c73fecdc794fff985#code) to reward him with extra 10% of earned tokens. I can easily do it, using balanceOf of ERC721. If it returns 0, then user doesn't have any NFTs, so he won't get any extra tokens.
What would I do if bonus contract wasn't ERC721, but ERC1155? balanceOf of ERC1155 works in other way, it shows how many tokens of given id user has, when ERC721 shows total amount of tokens user owns. How could I check whether user has any ERC1155 of given contract?
You can do a loop with balanceOf and increment the id or use balanceOfBatch. But I see on the contract you only have one collection => TOKEN_ID == 0, so u can use balanceOf.

How do Ethereum ERC-20 Contracts for Tokens Interact

Learning Solidity along with token development.
I'm having a hard time understanding how tokens with multiple smart contracts interact with each other.
I've read through other tokens with multiple contracts on GitHub and reviewed contracts on OpenZeppelin but they all appear somewhat orphaned.
Let's say we developed a token that has a supply and tracks wallet address to amount using a map. The contract is released and is given an address. Admin or privilege methods are protected via owner address validation. Then we release a second contract that needs to make apply a fee for transactions.
How does the second (token transaction fees) contract interact with the data stored on the first (token contract)? Does the second contract need to also verify ownership?
Any contract on Ethereum can interact with any other contract by using Interfaces. You can call methods from the second contract on the first contract for an ERC20 token as below:
Define ERC20 Interface
interface ERC20 {
function balanceOf(address account) external view returns (uint256);
}
Use the interface and token contract address to call methods on the first contract:
ERC20(tokenContractAddress).balanceOf(0xabcd....);
The similar approach can be used for any contracts

staking existing ERC20 token

How do I make a existing running erc20 to prevent some holders from transacting?
I am trying to do a staking feature. Can I write a new contract to control the existing erc20 contract?
Logic that would affect a token holder's ability to transfer (or have a party transferFrom on the holders behalf) must be written into the contract if you want token transfers to be halted within the contract itself. Therefore, if you already have a contract deployed you would have to deploy a new ERC20 contract that has the logic - if you want the staking mechanism to be within the same contract. Then you would have to transfer balances from the previous version of the contract to the newly deployed contract. While possible, it would incur a gas expense to replicate the contract state. You could have your token holders pay this gas cost by having some sort of mint or recover function that would read the old contract balance for an address, create the balance on the new contract, and then mark the balance as transferred.
Alternatively, to your second question, you could facilitate the staking with an additional contract that users would set an allowance to within the ERC20 contract. Then, users could interact with something like a stake function on this new staking contract. The staking contract would use the transferFrom ERC20 function to transfer tokens from the owner to the staking contract's address after incrementing the user's staked token amount within the staking contract. This would record the holder's staking "credit" and tie the tokens up by transferring their ownership to the staking contract. Users could then unstake which would decrement the user's staked token amount and transfer the tokens back from the staking contract's address to the token holder's address. This type of approach has more moving pieces but could be a more flexible step while developing the mechanism as you can deploy new versions of the staking contract without having to redeploy the ERC20 contract or transfer balances. Users would be able to transfer like normal throughout multiple versions of the staking contract and extracting tokens from previous versions of the staking contracts would be gas-efficient.

Pushing an ERC721 token into a wallet after auction completion

I'm trying to develop a set of contracts in where an ERC721 token is auctioned off, then the winner gets the token placed into their wallet. I'm not entirely sure how to structure this. These are the contracts I was thinking would be needed.
WALLET
Contains the mapping of addresses to tokens owned
Upon deployment, creates deploys an AuctionFactory contract and saves the address
AUCTIONFACTORY
Deploys an Auction contract upon command, with the item being the ERC721 token specified
AUCTION
Contains all the logic for an auction
Inherits from Wallet, allowing manipulation of the mapping state variable found in the contract, placing ERC721 tokens won into the winners wallet
The problem is that Auction can't inherit from Wallet. The compiler will throw an error when AuctionFactory tries to deploy an auction - cannot create instance of derived or same contract. And that makes sense to me, since Wallet deploys the factory, and if the factory deploys an Auction that inherits from Wallet, it's technically deploying its parent contract.
So my question is, how can I structure this set of contracts? How can I allow an instance of an auction contract to communicate and manipulate with a store on another contract?
Here is an example contract which can deposit tokens and then auction them off. This is a basic auction model which shows the control flow for transferring possession of the token.
Here is the setup. First we have to import the ERC-721 headers. I am using the reference implementation for ERC-721 for this:
pragma solidity 0.5.1;
import "https://github.com/0xcert/ethereum-erc721/src/contracts/tokens/erc721.sol";
import "https://github.com/0xcert/ethereum-erc721/src/contracts/tokens/erc721-token-receiver.sol";
Here is the contract and the main data structure:
// This implements an ERC-721 auction by taking ownership of tokens
contract CollectableAuction is ERC721TokenReceiver {
mapping (uint256 => AuctionDetails) auctionDetails;
struct AuctionDetails {
ERC721 nftContract;
bool bidIsComplete;
address seller;
address winningBidder;
uint256 tokenId;
}
}
We add in the deposit mechanism. This works by allowing people to send tokens directly to the auction contract. You may implement a different mechanism to start auctions, but this one works just as well.
// Deposit an asset and start an auction
function onERC721Received(
address,
address from,
uint256 tokenId,
bytes calldata
)
external
returns(bytes4)
{
uint256 auctionId = uint256(keccak256(abi.encode(uint256(msg.sender), tokenId)));
auctionDetails[auctionId] = AuctionDetails({
nftContract: ERC721(msg.sender),
bidIsComplete: false,
seller: from,
winningBidder: address(0),
tokenId: tokenId
});
return 0x150b7a02;
}
Here is a mock implementation for your auction process. Your actual auction will certainly be more complicated.
function completeAuction(uint256 auctionId) external {
auctionDetails[auctionId].bidIsComplete = true;
}
Lastly, when the auction is done then the winning bidder needs to take the token.
function withdraw(uint256 auctionId) external {
AuctionDetails storage details = auctionDetails[auctionId];
require(details.bidIsComplete);
require(msg.sender == details.winningBidder);
// Collect money from winning bidder
details.nftContract.safeTransferFrom(address(this), details.winningBidder, details.tokenId);
// Send money to seller
// Do event logging
delete auctionDetails[auctionId];
}
The above is a fully-functioning starting point for this project.
I'm not sure why you need to inherit from a Wallet contract. The Auction structure should be something like:
Owner of token X calls a function createAuction from your contract to create an auction
createAuction(tokenId, minPrice, duration) will:
Store the owner address, token id and some other information (minimum price, duration, etc.) into a mapping. You'll probably use your token id as the mapping key.
Use the transferFrom function from your ERC721 contract to transfer the ownership from current owner to the Auction contract itself, something like: erc721.transferFrom(owner, this, tokenId). This is required later when you have to transfer the ownership to the buyer.
A buyer joins the game, and bid on this auction by calling a bidOnAuction(tokenId). Check the parameters (msg.value > minPrice, duration, etc.). And if these are bid winning conditions, then you transfer the money to the seller (owner) and you transfer the token owrnership from your contract to the buyer, again by calling the erc721 method: erc721.transferFrom(this, msg.sender, tokenId).
The Auction contract works as an escrow, it keeps the ERC721 token ownership until the auction is finished (bought or cancelled). You don't have to "manipulate ownership", you only have to let the owner transfer the token to your contract and then, your contract transfer the ownership back to the previous owner if the auction was cancelled or to the buyer if the auction was completed.

How does a User account own an ERC20 Token

This question is a little conceptual, so hopefully this picture will help clear up my misunderstanding.
Image there is a crowdsale smart contract deployed on address 0x2. A User at address 0x01 buys a token.
Here is my understanding of what happens:
The crowdsale contract (# address: 0x2) accepts ether from the user account (# address: 0x1)
The crowdsale contract stores 0x1 as having purchased a token (important: this information is stored in the smart contract #address 0x2)
Now my Question: If 0x1 is a user account (and not a smart contract) there is no code at address 0x1. I thought a user account just consisted of an address + ether associated with the address, how can it also store the fact that 0x1 owns an ERC20 token? For example, I can login to MetaMask and (before clicking the "add token" option) MetaMask can see that I have a token... how is this possible?
Every ERC20 contract has the following function:
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
Your wallet just calls this function from the known token contracts with your address. Since it's a view function it doesn't cost any gas.
I recon most ERC20 token get added rather quickly to a wallet like Metamask or MEW. But if your balance doesn't automatically show, you can add the contract address manually (in MEW at least, not sure about Metamask) and it will show up afterwards.
In solidity there are two ways to get the address of the person who sent the transaction
tx.origin
msg.sender
In your example, in the method inside ERC20 Token.sol, the value tx.origin will be 0x1 and msg.sender will be 0x2
So to answer your question, how does the ERC20 token know about 0x2 is: it depends on how the token contract is written and whether it uses tx.origin or msg.sender. I would imagine it uses msg.sender, because that is the more prevalent one.
If it does use msg.sender you can still make the crowdsale contract work by first buying the tokens and then immediatelly transfering the tokens from the crowdsale contract to the caller.
For more information, refer to What's the difference between 'msg.sender' and 'tx.origin'?
how can it also store the fact that 0x1 owns an ERC20 token?
Token transfers, or transfers in accounting in general, are kept in a ledger. In this case, the ledger is ERC-20 smart contract that internally keeps balances who owns and what in its balances mapping. Or, the smart contract manage the storage (EVM SSTORE instructions) where the records of ownership are kept.
Note that some other blockchains, like Telos and EOS (and mayne Solana) might be opposite and there the storage is maintained on the user account (user account has associated RAM and tables for any token user owns).